Merge remote-tracking branch 'dev/msm-4.9-sched' into msm-4.9

* origin/dev/msm-4.9-sched:
  ARM: dts: msm: Update silver CPUs's idle cost data for SDM845v2
  sched/fair: prevent possible infinite loop in sched_group_energy
  sched: Update WALT stats also in boosted_cpu_util()
  sched/fair: Add provision to control the spreading on SMP
  sched/fair: Add EAS_USE_NEED_IDLE feature
  sched/fair: Turn off FBT_STRICT_ORDER feature
  sched/fair: fix incorrect CPU selection for non latency sensitive tasks
  sched: Add task placement snapshot
  sched/fair: select the most energy-efficient CPU candidate on wake-up
  sched/fair: fix array out of bounds access in select_energy_cpu_idx()
  sched/fair: use min capacity when evaluating active cpus
  sched/fair: use min capacity when evaluating idle backup cpus
  sched/fair: use min capacity when evaluating placement energy costs
  sched/fair: introduce minimum capacity capping sched feature
  arm/topology: link arch_scale_min_freq_capacity to cpufreq
  arm64/topology: link arch_scale_min_freq_capacity to cpufreq
  sched: add arch_scale_min_freq_capacity to track minimum capacity caps
  cpufreq: add scaled minimum capacity tracking for policy changes
  arm64: enable max frequency capping
  arm: enable max frequency capping
  cpufreq: implement max frequency capping
  sched/fair: introduce an arch scaling function for max frequency capping
  cpufreq: remove max frequency capping from scale_freq_capacity()
  Revert "ANDROID: cpufreq: Max freq invariant scheduler load-tracking and cpu capacity support"
  Revert "ANDROID: arm: Enable max freq invariant scheduler load-tracking and capacity support"
  Revert "ANDROID: arm64: Enable max freq invariant scheduler load-tracking and capacity support"
  sched/fair: reduce rounding errors in energy computations
  sched/fair: re-factor energy_diff to use a single (extensible) energy_env
  sched/fair: cleanup select_energy_cpu_brute to be more consistent
  sched/fair: remove capacity tracking from energy_diff
  sched/fair: remove energy_diff tracepoint in preparation to re-factoring
  sched/fair: use *p to reference task_structs
  sched: EAS: Fix the calculation of group util in group_idle_state()
  cpufreq: Drop schedfreq governor
  sched: Sync EAS codebase to android-4.9
  sched: Move core_ctl callback from tick to WALT IRQ work
  sched: fair: Always use energy aware wakeups
  sched: Introduce new workload differentiation
  sched: Introduce a different version of freq aggregation
  sched: report group load to the cpufreq
  sched: Start reporting top task load to cpufreq
  sched: Introduce scheduler boost related placement changes
  sched: Port boost setting mechanisms to EAS
  sched: integrate core_ctl with EAS
  sched: EAS: add infrastructure for core_ctl
  sched: EAS: add core isolation support
  sched: Introduce an irq_work to report WALT load
  sched: introduce small wakee task on waker
  sched: fair: Ignore energy-diff calculations for colocated tasks
  sched: change default group upmigrate and downmigrate values
  sched: EAS: colocate related threads
  sched: cpufreq: Use per_cpu_ptr instead of this_cpu_ptr when reporting load
  sched: cpufreq: Use sched_clock instead of rq_clock when updating schedutil
  sched: cpufreq: Update cpufreq once in a WALT window
  ARM: dts: msm: Add an energy model for the SDM845 CPUs

Conflicts:
	kernel/sched/fair.c

Change-Id: Ieaeecb28e57955db3b13d6d9c1d81b204caf0fcf
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index d11af52..ac9489f 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -54,6 +54,7 @@
 | ARM            | Cortex-A57      | #852523         | N/A                         |
 | ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220        |
 | ARM            | Cortex-A72      | #853709         | N/A                         |
+| ARM            | Cortex-A55      | #1024718        | ARM64_ERRATUM_1024718       |
 | ARM            | MMU-500         | #841119,#826419 | N/A                         |
 |                |                 |                 |                             |
 | Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375        |
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 9a9a6d0..bda03f0 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -1,12 +1,222 @@
 * CoreSight Components:
 
 CoreSight components are compliant with the ARM CoreSight architecture
-specification and can be connected in various topologies to suit a particular
-SoCs tracing needs. These trace components can generally be classified as
-sinks, links and sources. Trace data produced by one or more sources flows
-through the intermediate links connecting the source to the currently selected
-sink. Each CoreSight component device should use these properties to describe
-its hardware characteristcs.
+specification and can be connected in various topologies to suite a particular
+SoCs tracing needs. These trace components can generally be classified as sinks,
+links and sources. Trace data produced by one or more sources flows through the
+intermediate links connecting the source to the currently selected sink. Each
+CoreSight component device should use these properties to describe its hardware
+characteristcs.
+
+Required properties:
+
+- compatible : name of the component used for driver matching, should be one of
+	the following:
+	"arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
+	"arm,coresight-tpiu" for coresight tpiu device,
+	"qcom,coresight-replicator" for coresight replicator device,
+	"arm,coresight-funnel" for coresight funnel devices,
+	"qcom,coresight-tpda" for coresight tpda device,
+	"qcom,coresight-tpdm" for coresight tpdm device,
+	"qcom,coresight-dbgui" for coresight dbgui device
+	"arm,coresight-stm" for coresight stm trace device,
+	"arm,coresight-etm" for coresight etm trace devices,
+	"arm,coresight-etmv4" for coresight etmv4 trace devices,
+	"qcom,coresight-csr" for coresight csr device,
+	"arm,coresight-cti" for coresight cti devices,
+	"qcom,coresight-hwevent" for coresight hardware event devices
+	"arm,coresight-fuse" for coresight fuse v1 device,
+	"arm,coresight-fuse-v2" for coresight fuse v2 device,
+	"arm,coresight-fuse-v3" for coresight fuse v3 device,
+	"qcom,coresight-remote-etm" for coresight remote processor etm trace device,
+	"qcom,coresight-qpdi" for coresight qpdi device
+- reg : physical base address and length of the register set(s) of the component.
+	Not required for the following compatible string:
+	- "qcom,coresight-remote-etm"
+- reg-names : names corresponding to each reg property value.
+	Not required for the following compatible string:
+	- "qcom,coresight-remote-etm"
+	The reg-names that need to be used with corresponding compatible string
+	for a coresight device are:
+	- for coresight tmc-etr or tmc-etf device:
+		compatible : should be "arm,coresight-tmc"
+		reg-names  : should be:
+			"tmc-base" - physical base address of tmc configuration
+				registers
+			"bam-base" - physical base address of tmc-etr bam registers
+	- for coresight tpiu device:
+		compatible : should be "arm,coresight-tpiu"
+		reg-names  : should be:
+			"tpiu-base" - physical base address of tpiu registers
+	- for coresight replicator device
+		compatible : should be "qcom,coresight-replicator"
+		reg-names  : should be:
+			"replicator-base" - physical base address of replicator
+				registers
+	- for coresight funnel devices
+		compatible : should be "arm,coresight-funnel"
+		reg-names  : should be:
+			"funnel-base" - physical base address of funnel registers
+	- for coresight tpda trace device
+		compatible : should be "qcom,coresight-tpda"
+		reg-names  : should be:
+			"tpda-base" - physical base address of tpda registers
+	- for coresight tpdm trace device
+		compatible : should be "qcom,coresight-tpdm"
+		reg-names  : should be:
+			"tpdm-base" - physical base address of tpdm registers
+	- for coresight dbgui device:
+		compatible : should be "qcom,coresight-dbgui"
+		reg-names  : should be:
+			"dbgui-base" - physical base address of dbgui registers
+	- for coresight stm trace device
+		compatible : should be "arm,coresight-stm"
+		reg-names  : should be:
+			"stm-base" - physical base address of stm configuration
+				registers
+			"stm-data-base" - physical base address of stm data registers
+	- for coresight etm trace devices
+		compatible : should be "arm,coresight-etm"
+		reg-names  : should be:
+			"etm-base" - physical base address of etm registers
+	- for coresight etmv4 trace devices
+		compatible : should be "arm,coresight-etmv4"
+		reg-names  : should be:
+			"etm-base" - physical base address of etmv4 registers
+	- for coresight csr device:
+		compatible : should be "qcom,coresight-csr"
+		reg-names  : should be:
+			"csr-base" - physical base address of csr registers
+	- for coresight cti devices:
+		compatible : should be "arm,coresight-cti"
+		reg-names  : should be:
+			"cti<num>-base" - physical base address of cti registers
+	- for coresight hardware event devices:
+		compatible : should be "qcom,coresight-hwevent"
+		reg-names  : should be:
+			"<ss-mux>" - physical base address of hardware event mux
+				control registers where <ss-mux> is subsystem mux it
+				represents
+	- for coresight fuse device:
+		compatible : should be "arm,coresight-fuse"
+		reg-names  : should be:
+			"fuse-base" - physical base address of fuse registers
+			"nidnt-fuse-base" - physical base address of nidnt fuse registers
+			"qpdi-fuse-base" - physical base address of qpdi fuse registers
+	- for coresight qpdi device:
+		compatible : should be "qcom,coresight-qpdi"
+		reg-names  : should be:
+			"qpdi-base" - physical base address of qpdi registers
+- coresight-id : unique integer identifier for the component
+- coresight-name : unique descriptive name of the component
+- coresight-nr-inports : number of input ports on the component
+
+Optional properties:
+
+- coresight-outports : list of output port numbers of this component
+- 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-default-sink : represents the default compile time CoreSight sink
+- coresight-ctis : list of ctis that this component interacts with
+- qcom,cti-save : boolean, indicating cti context needs to be saved and restored
+- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti
+		   registers to be saved and restored
+- qcom,cti-gpio-trigin : cti trigger input driven by gpio
+- qcom,cti-gpio-trigout : cti trigger output sent to gpio
+- qcom,pc-save : program counter save implemented
+- qcom,blk-size : block size for tmc-etr to usb transfers
+- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer
+- qcom,round-robin : indicates if per core etms are allowed round-robin access
+		     by the funnel
+- qcom,write-64bit : only 64bit data writes supported by stm
+- qcom,data-barrier : barrier required for every stm data write to channel space
+- <supply-name>-supply: phandle to the regulator device tree node. The required
+			<supply-name> is "vdd" for SD card and "vdd-io" for SD
+			I/O supply. Used for tpiu component
+- qcom,<supply>-voltage-level : specifies voltage level for vdd supply. Should
+				be specified in pairs (min, max) with units
+				being uV. Here <supply> can be "vdd" for SD card
+				vdd supply or "vdd-io" for SD I/O vdd supply.
+- qcom,<supply>-current-level : specifies current load levels for vdd supply.
+				Should be specified in pairs (lpm, hpm) with
+				units being uA. Here <supply> can be "vdd" for
+				SD card vdd supply or "vdd-io" for SD I/O vdd
+				supply.
+- qcom,hwevent-clks : list of clocks required by hardware event driver
+- qcom,hwevent-regs : list of regulators required by hardware event driver
+- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
+			  the device. Only relevant in case of tmc-etr device.
+- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
+		spi/ppi, b is the interrupt number and c is the mask,
+- interrupt-names : a list of strings that map in order to the list of
+		    interrupts specified in the 'interrupts' property.
+- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC
+		   ETR configuration.
+- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped.
+			Used for TMC component
+- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support
+		 present. Used for tpiu component
+- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present.
+		 Used for tpiu component
+  qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of
+  these may specified for tpiu component
+- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used
+		       for tpiu component
+- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used
+		      for tpiu component
+- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used
+		    for tpiu component
+- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used
+		    for tpiu component
+- nidnt-gpio : specifies gpio for NIDnT hardware detection
+- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection
+- pinctrl-names : names corresponding to the numbered pinctrl. The allowed
+		  names are subset of the following: cti-trigin-pctrl,
+		  cti-trigout-pctrl. Used for cti component
+- pinctrl-<n>: list of pinctrl phandles for the different pinctrl states. Refer
+	       to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt".
+- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled
+			     for the ETM whose CPU is being powered down. The port
+			     state is restored when CPU is powered up. Used for
+			     funnel component.
+- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before
+			     powering down CPU. Used for TMC component.
+- qcom,bc-elem-size : specifies the BC element size supported by each monitor
+		      connected to the aggregator on each port. Should be specified
+		      in pairs (port, bc element size).
+- qcom,tc-elem-size : specifies the TC element size supported by each monitor
+		      connected to the aggregator on each port. Should be specified
+		      in pairs (port, tc element size).
+- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor
+		       connected to the aggregator on each port. Should be specified
+		       in pairs (port, dsb element size).
+- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor
+		       connected to the aggregator on each port. Should be specified
+		       in pairs (port, cmb element size).
+- qcom,clk-enable: specifies whether additional clock bit needs to be set for
+		   M4M TPDM.
+- qcom,tpda-atid : specifies the ATID for TPDA.
+- qcom,inst-id : QMI instance id for remote ETMs.
+- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be
+			 set in ETM stall control register.
+- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true
+- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device
+- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers
+- qcom,dbgui-data-offset : indicates the offset of dbgui data registers
+- qcom,dbgui-size : indicates the size of dbgui address and data registers
+- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver
+- qcom,cpuss-debug-cgc: debug clock gating phandle for etm
+	reg : the clock gating register for each cluster
+	cluster : indicate the cluster number
+
+coresight-outports, coresight-child-list and coresight-child-ports lists will
+be of the same length and will have a one to one correspondence among the
+elements at the same list index.
+
+coresight-default-sink must be specified for one of the sink devices that is
+intended to be made the default sink. Other sink devices must not have this
+specified. Not specifying this property on any of the sinks is invalid.
 
 * Required properties for all components *except* non-configurable replicators:
 
@@ -190,6 +400,20 @@
 	* reg-names: funnel-base-real: actual register space for the
 	  duplicate funnel.
 
+* Optional properties for CSRs:
+
+	* qcom,usb-bam-support: boolean, indicates CSR has the ability to operate on
+	  usb bam, include enable,disable and flush.
+
+	* qcom,hwctrl-set-support: boolean, indicates CSR has the ability to operate on
+	  to "HWCTRL" register.
+
+	* qcom,set-byte-cntr-support:boolean, indicates CSR has the ability to operate on
+	  to "BYTECNT" register.
+
+	* qcom,timestamp-support:boolean, indicates CSR support sys interface to read
+	  timestamp value.
+
 Example:
 
 1. Sinks
diff --git a/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
new file mode 100644
index 0000000..dc7966a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/acpuclock/clock-a7.txt
@@ -0,0 +1,43 @@
+* Qualcomm Application CPU clock driver
+
+clock-a7 is the driver for the Root Clock Generator (rcg) hw which controls
+the cpu rate. RCGs support selecting one of several clock inputs, as well as
+a configurable divider. This hw is different than normal rcgs in that it may
+optionally have a register which encodes the maximum rate supported by hw.
+
+Required properties:
+- compatible: "qcom,clock-a53-8916", "qcom,clock-a7-9650",
+		"qcom,clock-a7-mdm9607", "qcom,clock-a7-sdx20"
+- reg: pairs of physical address and region size
+- reg-names: "rcg-base" is expected
+- clock-names: list of names of clock inputs
+- qcom,speedX-bin-vZ:
+		A table of CPU frequency (Hz) to regulator voltage (uV) mapping.
+		Format: <freq uV>
+		This represents the max frequency possible for each possible
+		power configuration for a CPU that's binned as speed bin X,
+		speed bin revision Z. Speed bin values can be between [0-7]
+		and the version can be between [0-3].
+
+- cpu-vdd-supply: regulator phandle for cpu power domain.
+
+Optional properties:
+- reg-names: "efuse", "efuse1"
+- qcom,safe-freq: Frequency in HZ
+	     When switching rates from A to B, the mux div clock will
+             instead switch from A -> safe_freq -> B.
+- qcom,enable-opp: This will allow to register the cpu clock with OPP
+	     framework.
+
+Example:
+	qcom,acpuclk@f9011050 {
+		compatible = "qcom,clock-a7-8226";
+		reg = <0xf9011050 0x8>;
+		reg-names = "rcg_base";
+		cpu-vdd-supply = <&apc_vreg_corner>;
+
+		clock-names = "clk-4", "clk-5";
+		qcom,speed0-bin-v0 =
+			<384000000 1150000>,
+			<600000000 1200000>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
new file mode 100644
index 0000000..ef40b72
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -0,0 +1,28 @@
+Qualcomm Technologies, Inc. BAM Data Multiplexer Driver
+
+Required properties:
+- compatible : should be "qcom,bam_dmux"
+- reg : the location and size of the BAM hardware
+- interrupts : the BAM hardware to apps processor interrupt line
+
+Optional properties:
+-qcom,satellite-mode: the hardware needs to be configured in satellite mode
+-qcom,rx-ring-size: the size of the receive ring buffer pool, default is 32
+-qcom,max-rx-mtu: the maximum receive MTU that can be negotiated, in bytes.
+	Default is 2048.  Other possible values are 4096, 8192, and 16384.
+-qcom,no-cpu-affinity: boolean value indicating that workqueue CPU affinity
+	is not required.
+-qcom,fast-shutdown: boolean value to support fast shutdown time.
+
+Example:
+
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
+		qcom,satellite-mode;
+		qcom,rx-ring-size = <64>;
+		qcom,max-rx-mtu = <8192>;
+		qcom,no-cpu-affinity;
+		qcom,fast-shutdown;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
index 4cc49a59..37718e1 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
@@ -1,6 +1,6 @@
-Qualcomm Technologies MSM Clock controller
+Qualcomm Technologies, Inc. MSM Clock controller
 
-Qualcomm Technologies MSM Clock controller devices contain PLLs, root clock
+Qualcomm Technologies, Inc. MSM Clock controller devices contain PLLs, root clock
 generators and other clocking hardware blocks that provide stable, low power
 clocking to hardware blocks on Qualcomm Technologies SOCs. The clock controller
 device node lists the power supplies needed to be scaled using the vdd_*-supply
@@ -12,10 +12,46 @@
 Required properties:
 - compatible:           Must be one of following,
 			"qcom,gcc-8953"
+			"qcom,gcc-8909"
+			"qcom,gcc-sdm632"
 			"qcom,cc-debug-8953"
+			"qcom,cc-debug-8909"
+			"qcom,cc-debug-sdm632"
 			"qcom,gcc-mdss-8953"
+			"qcom,gcc-mdss-sdm632"
                         "qcom,gcc-gfx-8953"
                         "qcom,gcc-gfx-sdm450"
+                        "qcom,gcc-gfx-sdm632"
+			"qcom,gcc-8992"
+			"qcom,gcc-8952"
+			"qcom,gcc-8937"
+			"qcom,gcc-8917"
+			"qcom,gcc-8940"
+			"qcom,gcc-8920"
+			"qcom,gcc-spm-8952"
+			"qcom,gcc-spm-8937"
+			"qcom,rpmcc-8909"
+			"qcom,rpmcc-8909-pm660"
+			"qcom,cc-debug-8952"
+			"qcom,cc-debug-8953"
+			"qcom,cc-debug-8937"
+			"qcom,cc-debug-8917"
+			"qcom,cc-debug-8940"
+			"qcom,cc-debug-8920"
+			"qcom,gcc-mdss-8953"
+			"qcom,gcc-mdss-8952"
+			"qcom,gcc-mdss-8909"
+			"qcom,gcc-mdss-8937"
+			"qcom,gcc-mdss-8917"
+			"qcom,gcc-mdss-8940"
+			"qcom,gcc-mdss-8920"
+			"qcom,gcc-gfx-8953"
+			"qcom,gcc-gfx-sdm450"
+			"qcom,gcc-mdm9607"
+			"qcom,cc-debug-mdm9607"
+			"qcom,gcc-9650"
+			"qcom,cc-debug-9650"
+			"qcom,gcc-sdx20"
 
 - reg:                  Pairs of physical base addresses and region sizes of
                         memory mapped registers.
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
new file mode 100644
index 0000000..5d570d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
@@ -0,0 +1,78 @@
+Qualcomm Technologies, Inc. MSM8939 CPU clock tree
+
+clock-cpu-8939 is a device that represents the MSM8939 or MSM8952 CPU
+subsystem clock tree. It lists the various power supplies that need to be
+scaled when the clocks are scaled and also other HW specific parameters like
+fmax tables, avs settings table, etc.
+
+Required properties:
+- compatible:		Must be one of "qcom,clock-cpu-8939" or
+			"qcom,cpu-clock-8952", "qcom,cpu-clock-8917".
+- reg:			Pairs of physical base addresses and region sizes of
+			memory mapped registers.
+- reg-names:		Names of the bases for the above registers. Expected
+			bases are:
+			"apcs-c0-rcg-base", "apcs-c1-rcg-base",
+			"apcs-cci-rcg-base", "efuse", "efuse1", "efuse2"
+- vdd-c0-supply:	The regulator powering the little cluster
+- vdd-c1-supply:	The regulator powering the big cluster
+- vdd-cci-supply:	The regulator powering the CCI cluster
+- qcom,speedX-bin-vY-ZZZ:
+			A table of CPU frequency (Hz) to voltage (corner)
+			mapping that represents the max frequency possible
+			for each supported voltage level for a CPU. 'X' is
+			the speed bin into which the device falls into - a
+			bin will have unique frequency-voltage relationships.
+			'Y' is the characterization version, implying that
+			characterization (deciding what speed bin a device
+			falls into) methods and/or encoding may change. The
+			values 'X' and 'Y' are read from efuse registers, and
+			the right table is picked from multiple possible tables.
+			'ZZZ' can be c1, c0 or cci depending on whether the table
+			is for the big cluster, little cluster or cci.
+Optional properties:
+- qcom,cpu-pcnoc-vote:  Boolean to indicate cpu clocks would need to keep
+			active pcnoc vote.
+- qcom,num-cluster:     Boolean to indicate cpu clock code is used for single
+			cluster.
+Example:
+	clock_cpu: qcom,cpu-clock-8939@f9015000 {
+		compatible = "qcom,cpu-clock-8939";
+		reg = <0xf9015000 0x1000>,
+		      <0xf9016000 0x1000>,
+		      <0xf9011000 0x1000>,
+		      <0xf900d000 0x1000>,
+		      <0xf900f000 0x1000>,
+		      <0xf9112000 0x1000>;
+		reg-names = "apcs-c0-rcg-base", "apcs-c1-rcg-base",
+			     "apcs-cci-rcg-base", "efuse", "efuse1",
+				"efuse2";
+                vdd-c0-supply = <&apc_vreg_corner>;
+		vdd-c1-supply = <&apc_vreg_corner>;
+		vdd-cci-supply = <&apc_vreg_corner>;
+		qcom,speed0-bin-v0-c0 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1286400000 3>;
+		qcom,speed0-bin-v0-c1 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1785600000 3>;
+		qcom,speed0-bin-v0-cci =
+			<         0 0>,
+			< 150000000 1>,
+			< 300000000 2>,
+			< 600000000 3>;
+		clocks = <&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_c0_pll>,
+			<&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_c1_pll>,
+			<&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_cci_pll>;
+			clock-names = "clk-c0-4", "clk-c0-5",
+			"clk-c1-4", "clk-c1-5",
+			"clk-cci-4", "clk-cci-5";
+		#clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt
new file mode 100644
index 0000000..2d89614
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-sdm632.txt
@@ -0,0 +1,94 @@
+Qualcomm Technologies, Inc SDM632 CPU clock driver
+
+clock-cpu-sdm632 is a device that represents the SDM632 CPU subystem clock
+tree. It lists the various power supplies that need to be scaled when the
+clocks are scaled and also other HW specific parameters like fmax tables etc.
+
+The root clock generator could have the ramp controller in built.
+Ramp control will allow programming the sequence ID for pulse swallowing,
+enable sequence and for linking sequence IDs.
+
+Required properties:
+- compatible:		Must be "qcom,clock-cpu-sdm632".
+
+- reg:			Pairs of physical base addresses and region sizes of
+			memory mapped registers.
+- reg-names:		Names of the bases for the above registers. Expected
+			bases are:
+			"apcs-c1-pll-base", "apcs-c0-pll-base",
+			"apcs-cci-pll-base", "apcs-c1-rcg-base",
+			"apcs-c0-rcg-base", "apcs-cci-rcg-base",
+			"efuse", "rcgwr-c0-base(optional)",
+			"rcgwr-c1-base(optional)".
+- clocks:		The clocks sources used by the cluster/cci mux.
+- clock-names:		Name of the clocks for the above clocks.
+- vdd-mx-supply:	The regulator powering all the PLLs of clusters & cci.
+- vdd-c0-supply:	The regulator powering the cluster 0.
+- vdd-c1-supply:	The regulator powering the cluster 1.
+- vdd-cci-supply:	The regulator powering the CCI cluster.
+
+- qcom,speedX-bin-vY-ZZZ:
+			A table of CPU frequency (Hz) to voltage (corner)
+			mapping that represents the max frequency possible
+			for each supported voltage level for a CPU. 'X' is
+			the speed bin into which the device falls into - a
+			bin will have unique frequency-voltage relationships.
+			'Y' is the characterization version, implying that
+			characterization (deciding what speed bin a device
+			falls into) methods and/or encoding may change. The
+			values 'X' and 'Y' are read from efuse registers, and
+			the right table is picked from multiple possible tables.
+			'ZZZ' can be cl for(c0 & c1) or cci depending on whether
+			the table for the clusters or cci.
+
+Example:
+	clock_cpu {
+		compatible = "qcom,cpu-clock-sdm632";
+		reg =   <0xb114000  0x68>,
+			<0xb014000  0x68>,
+			<0xb016000  0x8>,
+			<0xb116000  0x8>,
+			<0xb1d0000  0x8>,
+			<0xb011050  0x8>,
+			<0xb111050  0x8>,
+			<0xb1d1050  0x8>,
+			<0x00a412c  0x8>;
+		reg-names = "rcgwr-c0-base", "rcgwr-c1-base",
+			    "apcs-c1-pll-base", "apcs-c0-pll-base",
+			    "apcs-cci-pll-base", "apcs-c1-rcg-base",
+			    "apcs-c0-rcg-base", "apcs-cci-rcg-base",
+			    "efuse";
+		qcom,num-clusters = <2>;
+		vdd-mx-supply = <&pm8953_s7_level_ao>;
+		vdd-c0-supply = <&apc_vreg_corner>;
+		vdd-c1-supply = <&apc_vreg_corner>;
+		vdd-cci-supply = <&apc_vreg_corner>;
+		clocks = <&clock_gcc clk_xo_a_clk_src>;
+		clock-names = "xo_a";
+		qcom,speed0-bin-v0-c0 =
+			<          0 0>,
+			<   614400000 1>,
+			<   883200000 2>,
+			<  1036200000 3>,
+			<  1363200000 4>,
+			<  1563000000 5>,
+			<  1670400000 6>,
+			<  1785600000 7>;
+		qcom,speed0-bin-v0-c1 =
+			<          0 0>,
+			<   633600000 1>,
+			<   902400000 2>,
+			<  1094400000 3>,
+			<  1401600000 4>,
+			<  1555200000 5>,
+			<  1785600000 6>;
+		qcom,speed0-bin-v0-cci =
+			<          0 0>,
+			<  307200000 1>,
+			<  403200000 2>,
+			<  499200000 3>,
+			<  691200000 4>,
+			<  768000000 5>,
+			<  787200000 6>;
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
new file mode 100644
index 0000000..56fa470
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -0,0 +1,49 @@
+* MSM Sleep status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+The required properties of core sleep status node are:
+- compatible: qcom,cpu-sleep-status
+
+The required properties of sleep status node are:
+- reg: physical address of the sleep status register for the cpus
+- qcom,cpu-sleep-status-mask - The bit mask within the status register that
+	indicates the Core's sleep state.
+
+Example:
+	qcom,cpu-sleep-status {
+		compatible = "qcom,cpu-sleep-status";
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		CPU0: cpu@0 {
+			device_type = "cpu";
+			compatible = "qcom,kryo";
+
+			qcom,sleep-status = <&cpu0_slp_sts>;
+		};
+
+		CPU1: cpu@1 {
+			device_type = "cpu";
+			compatible = "qcom,kryo";
+
+			qcom,sleep-status = <&cpu1_slp_sts>;
+		};
+	};
+
+	cpu0_slp_sts: cpu-sleep-status@9981058 {
+		reg = <0x9981058 0x100>;
+		qcom,sleep-status-mask = <0xc00000>;
+	};
+
+	cpu1_slp_sts: cpu-sleep-status@9991058 {
+		reg = <0x9991058 0x100>;
+		qcom,sleep-status-mask = <0xc00000>;
+	}
diff --git a/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt b/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt
new file mode 100644
index 0000000..d034bb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/glink_bgcom_xprt.txt
@@ -0,0 +1,33 @@
+Qualcomm Technologies, Inc. G-link bgcom Transport
+
+Required properties:
+-compatible : should be "qcom,glink-bgcom-xprt".
+-label : the name of the subsystem this link connects to.
+
+Optional properties:
+-qcom,qos-config: Reference to the qos configuration elements.It depends on
+		ramp-time.
+-qcom,ramp-time: Worst case time in microseconds to transition to this power
+		state. Power states are numbered by array index position.
+
+Example:
+
+	qcom,glink-bgcom-xprt-bg {
+		compatible = "qcom,glink-bgcom-xprt";
+		label = "bg";
+		qcom,qos-config = <&glink_qos_bg>;
+		qcom,ramp-time = <0x10>,
+				     <0x20>,
+				     <0x30>,
+				     <0x40>;
+	};
+
+	glink_qos_bg: qcom,glink-qos-config-bg {
+		compatible = "qcom,glink-qos-config";
+		qcom,flow-info = <0x80 0x0>,
+				 <0x70 0x1>,
+				 <0x60 0x2>,
+				 <0x50 0x3>;
+		qcom,mtu-size = <0x800>;
+		qcom,tput-stats-cycle = <0xa>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
new file mode 100644
index 0000000..9fc2031
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/jtag-fuse.txt
@@ -0,0 +1,22 @@
+* JTAG-FUSE
+
+The jtag-fuse entry specifies the memory mapped addresses for the fuse
+registers. The jtag-fuse driver uses these to provide api(s) that can be used
+by jtag save and restore driver(s) to query whether the Hardware they manage
+is functionally disabled or not and take corresponding steps.
+
+Required Properties:
+compatible: component name used for driver matching, should be one of the
+	following:
+	"qcom,jtag-fuse" for jtag fuse device
+	"qcom,jtag-fuse-v2" for jtag fuse v2 device
+	"qcom,jtag-fuse-v3" for jtag fuse v3 device
+reg: physical base address and length of the register set
+reg-names: should be "fuse-base"
+
+Example:
+	jtag_fuse: jtagfuse@fc4be024 {
+		compatible = "qcom,jtag-fuse";
+		reg = <0xfc4be024 0x8>;
+		reg-names = "fuse-base";
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
new file mode 100644
index 0000000..0304035
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
@@ -0,0 +1,55 @@
+* LPM Workarounds
+
+The required properties are:
+
+- compatible: "qcom,lpm-workarounds"
+
+The optional properties are:
+- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts
+	regitsters of performance cluster.
+
+- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address.
+	     "l1_l2_gcc" - string to identify l1_l2_gcc physical address.
+
+- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo
+	vote when system is coming out of rpm assisted power collaspe.
+	lpm-cx-supply is required if this is present.
+
+- lpm-cx-supply:  will hold handle for CX regulator supply which is used
+	to unvote.
+
+- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure
+	world needs to disable and enable L2 SPM to get the proper context
+	in secure watchdog bite cases. With this workaround there is a race
+	in programming L2 SPM between HLOS and secure world. This leads to
+	stability issues. To avoid this program L2 SPM only in secure world
+	based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this
+	is required.
+
+- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic
+	clock gating needs to be enabled by software for performance cluster
+	cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is
+	required.
+
+- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is
+	in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM
+	driver.
+
+- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu.
+
+- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure.
+
+Example:
+
+qcom,lpm-workarounds {
+	compatible = "qcom,lpm-workarounds";
+	reg = <0x0B011018 0x4>,
+	      <0x0B011088 0x4>;
+	reg-names = "l2-pwr-sts", "l1-l2-gcc";
+	lpm-cx-supply = <&pm8916_s2_corner>;
+	qcom,lpm-wa-cx-turbo-unvote;
+	qcom,lpm-wa-skip-l2-spm;
+	qcom,lpm-wa-dynamic-clock-gating;
+	qcom,cpu-offline-mask = "0xF";
+	qcom,non-boot-cpu-index = <4>;
+}
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm.txt b/Documentation/devicetree/bindings/arm/msm/mpm.txt
new file mode 100644
index 0000000..c3535cb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/mpm.txt
@@ -0,0 +1,77 @@
+* MSM Sleep Power Manager (mpm-v2)
+
+The MPM acts a sleep power manager to shutdown the clock source and put the
+device into a retention mode to save power. The MPM is also responsible for
+waking up and bringing up the resources from sleep. The MPM driver configures
+interrupts monitored by the MPM hardware before entering sleep through a
+RPM interface.
+
+The required nodes for the MPM driver are:
+
+- compatible: "qcom, mpm-v2"
+- reg: Specifies the base physical address(s) and the size of the MPM
+	registers. The MPM driver access two memory regions for confifure the
+	virtual MPM driver on the RPM. The first region is the memory space
+	shared with the virtual MPM driver. The second region is the address
+	to the register that triggers a interrupt to the RPM.
+- reg-names: "vmpm" - string to identify the shared memory space region
+	     "ipc" - string to identify the register that triggers a interrupt
+- clocks: clock identifers used by clock driver while looking up mpm clocks.
+- clock-names: name of the clock used by mpm driver.
+- qcom,ipc-bit-offset: The bit to set in the ipc register that triggers a interrupt
+	to the RPM
+- qcom,gic-parent: phandle to the gic interrupt controller
+- qcom,gic-map: Provides a mapping of how a GIC interrupt is connect to a MPM. The
+	mapping is presented in tuples. Each tuple represents a MPM pin and
+	which GIC interrupt is routed to it. Since MPM monitors interrupts
+	only during system wide low power mode, system interrupts originating
+	from other processors can be ignored and assigned an MPM pin mapping
+	of 0xff.
+- qcom,gpio-parent: phandle to the GPIO interrupt controller
+- qcom,gpio-map: Provides a mapping of how a GPIO interrupt is connect to a MPM. The
+	mapping is presented in tuples. Each tuple represents a MPM pin and
+	which GIC interrupt is routed to it. Since MPM monitors interrupts
+	only during system wide low power mode, system interrupts originating
+	from other processors can be ignored and assigned an MPM pin mapping
+	of 0xff.
+
+Optional Properties:
+
+- qcom,num-mpm-irqs : Specifies the number of mpm interrupts supported on a
+	target. If the property isn't present, 64 interrupts are
+	considered for the target by default.
+
+Example:
+	qcom,mpm@fc4281d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K*/
+		    <0xfa006000 0x1000>;   /* MSM_APCS_GCC_BASE 4K*/
+		reg-names = "vmpm", "ipc"
+			interrupts = <0 171 1>;
+		clocks = <&clock_rpm clk_xo_lpm_clk>;
+		clock-names = "xo";
+
+		qcom,ipc-bit-offset = <0>;
+
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <25 132>,
+			<27 111>,
+			<0xff 48>,
+			<0xff 51>,
+			<0xff 52>,
+			<0xff 53>,
+			<0xff 54>,
+			<0xff 55>;
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <1  46>,
+			<2 150>,
+			<4 103>,
+			<5 104>,
+			<6 105>,
+			<7 106>,
+			<8 107>,
+			<53 37>,
+			<54 24>,
+			<55 14>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index 9bc8168..47aabfd 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -119,6 +119,12 @@
 - MSM8937
   compatible = "qcom,msm8937"
 
+- SDM439
+  compatible = "qcom,sdm439"
+
+- SDM429
+  compatible = "qcom,sdm429"
+
 - MDM9640
   compatible = "qcom,mdm9640"
 
@@ -175,6 +181,9 @@
 - VR device:
   compatible = "qcom,qvr"
 
+- SVR device:
+  compatible = "qcom,svr"
+
 - HDK device:
   compatible = "qcom,hdk"
 
@@ -295,6 +304,7 @@
 compatible = "qcom,sda845-mtp"
 compatible = "qcom,sda845-qrd"
 compatible = "qcom,sda845-hdk"
+compatible = "qcom,sda845-svr"
 compatible = "qcom,sdm670-rumi"
 compatible = "qcom,sdm670-cdp"
 compatible = "qcom,sdm670-mtp"
@@ -317,6 +327,12 @@
 compatible = "qcom,msm8937-qrd"
 compatible = "qcom,msm8937-pmi8950-qrd-sku1"
 compatible = "qcom,msm8937-pmi8937-qrd-sku2"
+compatible = "qcom,sdm429-cdp"
+compatible = "qcom,sdm429-mtp"
+compatible = "qcom,sdm429-qrd"
+compatible = "qcom,sdm439-cdp"
+compatible = "qcom,sdm439-mtp"
+compatible = "qcom,sdm439-qrd"
 compatible = "qcom,msm8953-rumi"
 compatible = "qcom,msm8953-sim"
 compatible = "qcom,msm8953-cdp"
@@ -328,6 +344,9 @@
 compatible = "qcom,sdm450-cdp"
 compatible = "qcom,sdm450-qrd"
 compatible = "qcom,sdm632-rumi"
+compatible = "qcom,sdm632-cdp"
+compatible = "qcom,sdm632-mtp"
+compatible = "qcom,sdm632-qrd"
 compatible = "qcom,mdm9640-cdp"
 compatible = "qcom,mdm9640-mtp"
 compatible = "qcom,mdm9640-rumi"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
new file mode 100644
index 0000000..de66152
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -0,0 +1,448 @@
+MSM thermal driver (MSM_THERMAL)
+
+MSM_THERMAL is a kernel platform driver which regulates thermal conditions
+on the device during kernel boot. The goal of MSM_THERMAL is to prevent the
+temperature of the system from exceeding a thermal limit at which it cannot
+operate. Examples are CPU junction thermal limit, or POP memory thermal limit.
+The MSM_THERMAL driver polls the TSENS sensor hardware during boot, and
+reduces the maximum CPU frequency allowed in steps, to limit power/thermal
+output when a threshold temperature is crossed. It restores the maximum CPU
+frequency allowed in the same stepwise fashion when the threshold temperature
+(with hysteresis gap) is cleared.
+
+The devicetree representation of the MSM_THERMAL block should be:
+
+Required properties
+
+- compatible: "qcom,msm-thermal"
+- qcom,sensor-id: The id of the TSENS sensor polled for temperature.
+			Typically the sensor closest to CPU0.
+- qcom,poll-ms: Sampling interval to read sensor, in ms.
+- qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC.
+- qcom,temp-hysteresis: Degrees C below threshold temperature to step CPU up.
+- qcom,freq-step: Number of frequency steps to take on each CPU mitigation.
+
+Optional properties
+
+- reg:                  Physical address for uio mapping
+- qcom,core-limit-temp: Threshold temperature to start shutting down cores
+			in degC
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
+			online in sequence.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+			in degC. This will be used when polling based
+			core control is disabled. The difference between hotplug-temp
+			and core-limit-temp is that core-limit-temp is used during
+			early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+			cores to be offlined. Cores can be brought online if needed.
+- qcom,freq-mitigation-temp: Threshold temperature to mitigate
+			the CPU max frequency in degC. This will be
+			used when polling based frequency control is disabled.
+			The difference between freq-mitigation-temp
+			and limit-temp is that limit-temp is used during
+			early boot prior to thermal_sys being available for registering
+			temperature thresholds. Also, this emergency frequency
+			mitigation is a single step frequency mitigation to a predefined value
+			as opposed to the step by step frequency mitigation during boot-up.
+- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
+			cpu max frequency.
+- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
+			should mitigate the CPU, when the freq-mitigation-temp
+			threshold is reached.
+- qcom,vdd-restriction-temp: When temperature is below this threshold, will
+			enable vdd restriction which will set higher voltage on
+			key voltage rails, in degC.
+- qcom,vdd-restriction-temp-hysteresis: When temperature is above this threshold
+			will disable vdd restriction on key rails, in degC.
+- qcom,pmic-sw-mode-temp: Threshold temperature to disable auto mode on the
+			rail, in degC. If this property exists,
+			qcom,pmic-sw-mode-temp-hysteresis and
+			qcom,pmic-sw-mode-regs need to exist, otherwise return error.
+- qcom,pmic-sw-mode-temp-hysteresis: Degree below threshold temperature to
+			enable auto mode on the rail, in degC. If this property exists,
+			qcom,pmic-sw-mode-temp and qcom,pmic-sw-mode-regs need to
+			exist, otherwise return error.
+- qcom,pmic-sw-mode-regs: Array of the regulator names that will want to
+			disable/enable automode based on the threshold. If this
+			property exists, qcom,pmic-sw-mode-temp and
+			qcom,pmic-sw-mode-temp-hysteresis need to exist, otherwise
+			return error. Also, if this property is defined, will have to
+			define <consumer_supply_name>-supply = <&phandle_of_regulator>
+- <consumer_supply_name>-supply = <&phandle_of_regulator>: consumer_supply_name
+			is the name that's defined in thermal driver.
+			phandle_of_regulator is defined by reuglator device tree.
+- qcom,online-hotplug-core: This property should be defined in targets where
+			KTM should online cores, which are hotplugged due to
+			thermal condition.
+- qcom,synchronous-cluster-id: This property specifies an array of synchronous cluster-ID's.
+			This property will be used by KTM to optimize the synchronous
+			cluster frequency update.
+- qcom,synchronous-cluster-map: This property specifies an array of cluster-ID,
+			number of cpus in that cluster and their corresponding cpu
+			phandles. This property should be defined in targets where
+			the kernel topology module is not present.
+			In the older kernel version, where the kernel topology module is
+			not available, KTM gets the mapping information from this property.
+- qcom,disable-vdd-mx:  If this property is defined, the feature VDD MX
+			restriction will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-vdd-rstr: If this property is defined, the feature VDD
+			restriction will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-sensor-info: If this property is defined, the feature sensor
+			alias info will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-ocr:     If this property is defined, the feature optimum current
+			request will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-psm:     If this property is defined, the feature PMIC software
+			mode will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-gfx-phase-ctrl: If this property is defined, the feature graphics
+			phase control will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,disable-cx-phase-ctrl: If this property is defined, the feature
+			cx phase control will be disabled. All other properties
+			corresponding to this feature will be ignored.
+- qcom,therm-ddr-lm-info: If this optional property is defined, it enables
+			DDR frequency restriction feature. It expects array of
+			sensor id to be monitored, high threshold  and low threshold
+			for that sensor respectively.
+
+Optional child nodes
+- qcom,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
+			dual phase) for rails with PMIC, in degC. If this property exists,
+			then the properties, qcom,pmic-opt-curr-temp-hysteresis and
+			qcom,pmic-opt-curr-regs should also be defined to enable this
+			feature.
+- qcom,pmic-opt-curr-temp-hysteresis: Degree below the threshold to disable the optimum
+			current request for a rail, in degC. If this property exists,
+			then the properties, qcom,pmic-opt-curr-temp and
+			qcom,pmic-opt-curr-regs should also be defined to enable
+			this feature.
+- qcom,pmic-opt-curr-regs: Name of the rails for which the optimum current should be
+			requested. If this property exists, then the properties,
+			qcom,pmic-opt-curr-temp and qcom,pmic-opt-curr-temp-hysteresis
+			should also be defined to enable this feature.
+- qcom,pmic-opt-curr-sensor-id: Sensor, which needs to be monitored for requesting OCR
+			when qcom,pmic-opt-curr-temp threshold is reached.
+			It is an optional property, if it is configured, msm_thermal will
+			monitor only this sensor, otherwise it will monitor all TSENS for
+			this feature. If this property exists, then the properties,
+			qcom,pmic-opt-curr-temp, qcom,pmic-opt-curr-temp-hysteresis and
+			qcom,pmic-opt-curr-regs should also be defined to enable this feature.
+- qcom,<vdd restriction child node name>: Define the name of the child node.
+			If this property exisits, qcom,vdd-rstr-reg, qcom,levels
+			need to exist. qcom,min-level is optional if qcom,freq-req
+			exists, otherwise it's required.
+- qcom,vdd-rstr-reg: Name of the rail
+- qcom,levels: Array of the level values. Unit is corner voltage for voltage request
+			or kHz for frequency request.
+- qcom,min-level: Request this level as minimum level when disabling voltage
+			restriction. Unit is corner voltage for voltage request.
+			This will not be required if qcom,freq-req exists.
+- qcom,freq-req: Flag to determine if we should restrict frequency on this rail
+			instead of voltage.
+- qcom,max-freq-level: Request this frequency as scaling maximum level when
+			enabling vdd restriction feature for a rail. This is
+			an optional property which is only applicable to the rail
+			with "qcom,freq-req" property set.
+- qcom,cx-phase-hot-crit-temp: Threshold temperature for sending the 'HOT_CRITICAL'
+			temperature band to RPM, in degC. This will aid RPM
+			in deciding the number of phases required for CX rail.
+			If this property exists, then the property,
+			qcom,cx-phase-hot-crit-temp-hyst should also be defined to
+			enable this feature.
+- qcom,cx-phase-hot-crit-temp-hyst: Degree below the threshold to send the 'WARM'
+			temperature band to RPM, in degC. This will aid RPM
+			in deciding the number of phases required for CX.
+			If this property exists, then the property,
+			qcom,cx-phase-hot-crit-temp should also be defined to enable
+			this feature.
+- qcom,cx-phase-resource-key: The key name to be used for sending the CX
+			temperature band message to RPM. This property should
+			be defined along with the other properties required for
+			CX phase selection feature.
+- qcom,gfx-phase-hot-crit-temp: Threshold temperature for sending the 'HOT_CRITICAL'
+			temperature band to RPM, in degC. This will aid RPM in
+			deciding the number of phases required for GFX rail.
+			If this property exists, then the properties,
+			qcom,gfx-phase-hot-crit-temp-hyst and qcom,gfx-sensor-id
+			should also be defined to enable this feature.
+- qcom,gfx-phase-hot-crit-temp-hyst: Degree below the threshold to clear the 'HOT_CRITICAL'
+			band and send the 'WARM' temperature band to RPM, in degC.
+			This will aid RPM in deciding the number of phases required
+			for GFX rail. If this property exists, then the properties,
+			qcom,gfx-phase-hot-crit-temp and qcom,gfx-sensor-id
+			should also be defined to enable this feature.
+- qcom,gfx-phase-warm-temp: Threshold temperature for sending the 'WARM' temperature
+			band to RPM, in degC. This will aid RPM in deciding the
+			number of phases required for GFX rail. If this property
+			exists, then the properties, qcom,gfx-sensor-id and
+			qcom,gfx-phase-warm-temp-hyst should also be defined to
+			enable this feature.
+- qcom,gfx-phase-warm-temp-hyst: Degree below the threshold to clear the 'WARM'
+			band and send the 'NORMAL' temperature band to RPM, in degC.
+			This will aid RPM in deciding the number of phases required
+			for GFX rail. If this property exists, then the property,
+			qcom,gfx-sensor-id and qcom,gfx-phase-warm-temp should also
+			be defined to enable this feature.
+-qcom,gfx-sensor-id:     The ID of the TSENS sensor, which is closest to graphics
+			processor, monitoring the GPU temperature. If this property
+			exists, then the property, qcom,gfx-phase-hot-crit-temp and
+			qcom,gfx-phase-hot-crit-temp-hyst or/and qcom,gfx-phase-warm-temp
+			and qcom,gfx-phase-warm-temp-hyst should also be defined to
+			enable this feature.
+- qcom,gfx-phase-resource-key: The key name to be used for sending the GFX temperature
+			band message to RPM. This property should be defined along
+			with the other properties required for GFX phase selection
+			feature.
+- qcom,rpm-phase-resource-type: The RPM resource type name to be used for sending
+			temperature bands for CX and GFX phase selection. This
+			property should be defined along with the other properties
+			required for CX and GFX phase selection feature.
+- qcom,rpm-phase-resource-id: The RPM resource ID to be used for sending temperature
+			bands for CX and GFX phase selection. This property should
+			be defined along with the other properties required for CX
+			and GFX phase selection feature.
+- qcom,mx-restriction-temp: Threshold temperature below which the module votes for
+			higher data retention voltage of MX and CX supply. If and only if this
+			property exists, then the property qcom,mx-restriction-temp-hysteresis,
+			qcom,mx-retention-min should also be present. Also, if this
+			property is defined, will have to define vdd-mx-supply =
+			<&phandle_of_regulator>
+- qcom,mx-restriction-temp-hysteresis: Degree above the threshold to remove MX and CX vote.
+			If this property exists, then the property qcom,mx-restriction-temp,
+			qcom,mx-retention-min should also be present.Also, if this
+			property is defined, will have to define vdd-mx-supply =
+			<&phandle_of_regulator>
+- qcom,mx-retention-min: Minimum data retention voltage to be applied to MX rail if
+			the low threshold is crossed. If this property exists, then the
+			property qcom,mx-restriction-temp and
+			qcom,mx-restriction-temp-hysteresis should also be present.
+			Also, if this property is defined, will have to define
+			vdd-mx-supply = <&phandle_of_regulator>
+- qcom,cx-retention-min: Minimum data retention voltage to be applied to CX rail if the low
+			threshold is crossed. If this property exists, then the property
+			qcom,mx-restriction-temp and qcom,mx-restriction-temp-hysteresis
+			should also be present. Also, if this property is defined, will
+			have to define vdd-cx-supply = <&phandle_of_regulator>.
+- qcom,mx-restriction-sensor_id: sensor id, which needs to be monitored for requesting MX/CX
+			retention voltage. If this optional property is defined, msm_thermal
+			will monitor only this sensor, otherwise by default it will monitor
+			all TSENS for this feature. If this property exists, then the properties,
+			qcom,mx-restriction-temp, qcom,mx-restriction-temp-hysteresis and
+			qcom,mx-retention-min should also be defined to enable this feature.
+- qcom,therm-reset-temp: Degree above which the KTM will initiate a secure watchdog reset.
+			When this property is defined, KTM will monitor all the tsens from
+			boot time and will initiate a secure watchdog reset if any of the
+			tsens temperature reaches this threshold. This reset helps in
+			generating more informative crash dumps opposed to the crash dump
+			generated by the hardware reset.
+
+Example:
+
+	qcom,msm-thermal {
+		compatible = "qcom,msm-thermal";
+		reg = <0x70000 0x1000>;
+		qcom,sensor-id = <0>;
+		qcom,poll-ms = <250>;
+		qcom,limit-temp = <60>;
+		qcom,temp-hysteresis = <10>;
+		qcom,freq-step = <2>;
+		qcom,therm-reset-temp = <115>;
+		qcom,core-limit-temp = <90>;
+		qcom,core-temp-hysteresis = <10>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,freq-mitigation-temp = <110>;
+		qcom,freq-mitigation-temp-hysteresis = <20>;
+		qcom,freq-mitigation-value = <960000>;
+		qcom,rpm-phase-resource-type = "misc";
+		qcom,rpm-phase-resource-id = <0>;
+		qcom,cx-phase-resource-key = "tmpc";
+		qcom,cx-phase-hot-crit-temp = <75>;
+		qcom,cx-phase-hot-crit-temp-hyst = <15>;
+		qcom,gfx-phase-warm-temp = <60>;
+		qcom,gfx-phase-warm-temp-hyst = <10>;
+		qcom,gfx-phase-hot-crit-temp = <85>;
+		qcom,gfx-phase-hot-crit-temp-hyst = <15>;
+		qcom,gfx-sensor-id = <4>;
+		qcom,gfx-phase-resource-key = "tmpg";
+		qcom,pmic-sw-mode-temp = <90>;
+		qcom,pmic-sw-mode-temp-hysteresis = <80>;
+		qcom,pmic-sw-mode-regs = "vdd-dig";
+		qcom,vdd-restriction-temp = <5>;
+		qcom,vdd-restriction-temp-hysteresis = <10>;
+		vdd-dig-supply=<&pm8841_s2_floor_corner>
+		qcom,mx-restriction-temp = <5>;
+		qcom,mx-restriction-temp-hysteresis = <10>;
+		qcom,mx-retention-min = <710000>;
+		qcom,mx-restriction-sensor_id = <2>;
+		vdd-mx-supply = <&pma8084_s1>;
+		qcom,cx-retention-min = <RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS>;
+		vdd-cx-supply = <&pmd9635_s5_level>;
+		qcom,online-hotplug-core;
+		qcom,therm-ddr-lm-info = <1 90 75>;
+		qcom,synchronous-cluster-id = <0 1>; /* Indicates cluster 0 and 1 are synchronous */
+		qcom,synchronous-cluster-map =  <0 2 &CPU0 &CPU1>,
+						<1 2 &CPU2 &CPU3>;
+		/* <cluster-ID, number of cores in cluster, cpu phandles>.
+		** In the above case, the cluster with ID 0 & 1 has 2 cores
+		** and their phandles are mentioned.
+		*/
+
+		qcom,vdd-dig-rstr{
+			qcom,vdd-rstr-reg = "vdd-dig";
+			qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+			qcom,min-level = <1>; /* No Request */
+		};
+
+		qcom,vdd-apps-rstr{
+			qcom,vdd-rstr-reg = "vdd-apps";
+			qcom,levels = <1881600 1958400 2265600>;
+			qcom,freq-req;
+			qcom,max-freq-level = <1958400>;
+		};
+	};
+
+
+
+The sensor information node is an optional node that holds information
+about thermal sensors on a target. The information includes sensor type,
+sensor name, sensor alias and sensor scaling factor. The parent node
+name is qcom,sensor-information. It has a list of optional child
+nodes, each representing a sensor. The child node is named as
+qcom,sensor-information-<id>. The id takes values sequentially
+from 0 to N-1 where N is the number of sensors. This id doesn't
+relate to zone id or sensor id.
+
+The devicetree representation of sensor information node should be:
+
+1.0 Required properties:
+
+- compatible: "qcom,sensor-information"
+
+1.1 Optional nodes:
+
+qcom,sensor-information-<id>
+
+The below properties belong to the child node qcom,sensor-information-<id>.
+Following are the required and optional properties of a child node.
+
+1.1.a Required properties:
+
+- qcom,sensor-type: Type of a sensor. A sensor can be of type tsens,
+			alarm or adc.
+			tsens: 	Sensors that are on MSM die.
+			alarm: 	Sensors that are on PMIC die.
+			adc:   	Sensors that are usually thermistors
+				placed out of the die.
+- qcom,sensor-name: Name of a sensor as defined by low level sensor driver.
+
+1.1.b Optional properties:
+
+- qcom,alias-name: Alias name for a sensor. The alias name corresponds
+			to a device such as gpu/pop-mem whose temperature
+			is relative to the sensor temperature defined in the
+			child node. This node can not be used for providing
+			alias name for cpu devices. Thermal driver assigns the
+			cpu device alias, based on the sensor defined in the
+			cpu mitigation profile.
+- qcom,scaling-factor: The unit that needs to be multiplied to the
+			sensor temperature to get temperature unit in
+			degree centigrade. If this property is not
+			present, a default scaling factor of 1 is assigned
+			to a sensor.
+
+Example:
+
+	qcom,sensor-information {
+		compatible = "qcom,sensor-information";
+		sensor_information0: qcom,sensor-information-0 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor0";
+		};
+
+		sensor_information1: qcom,sensor-information-1 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor1";
+		};
+
+		sensor_information2: qcom,sensor-information-2 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor2";
+		};
+
+		sensor_information3: qcom,sensor-information-3 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor3";
+		};
+
+		sensor_information4: qcom,sensor-information-4 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor4";
+		};
+
+		sensor_information5: qcom,sensor-information-5 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor5";
+		};
+
+		sensor_information6: qcom,sensor-information-6 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor6";
+			qcom,alias-name = "cpu7";
+		}
+
+		sensor_information7: qcom,sensor-information-7 {
+			qcom,sensor-type =  "alarm";
+			qcom,sensor-name = "pm8994_tz";
+			qcom,scaling-factor = <1000>;
+                };
+
+	};
+
+===============================================================================
+Mitigation Profile:
+===============================================================================
+Thermal driver allows users to specify various mitigation profiles and
+associate a profile to a device. The device should have a phandle, to associate
+itself with a mitigation profile, using a "qcom,limits-info" property.
+This profile can specify whether to mitigate the device during various
+limiting conditions.
+
+Required Node:
+- qcom,limit_info-#: This is a mitigation profile node. A profile should
+			normally have a sensor(s) to monitor and a list
+			of properties enabling or disabling a mitigation.
+
+Required properties:
+
+- qcom,temperature-sensor: Array of phandle(s) to the temperature sensor(s) that
+			need(s) to be used for monitoring the device associated
+			with this mitigation profile. Right now the first
+			sensor will be used for KTM CPU monitoring. Alias
+			name of multiple sensors monitoring a same device will
+			be differentiated by appending an index like, "cpu0_0"
+			and "cpu0_1". A single sensor monitoring multiple
+			devices will have an alias name like "cpu0-cpu1-cpu2".
+
+Optional properties:
+
+- qcom,boot-frequency-mitigate: Enable thermal frequency mitigation
+			during boot.
+- qcom,emergency-frequency-mitigate: Enable emergency frequency mitigation.
+- qcom,hotplug-mitigation-enable: Enable hotplug mitigation. This enables
+			hotplug mitigation both during boot and emergency
+			condition.
+
+Example:
+	mitigation_profile7: qcom,limit_info-7 {
+		qcom,temperature-sensor =
+			<&sensor_information6 &sensor_information8>;
+		qcom,boot-frequency-mitigate;
+		qcom,emergency-frequency-mitigate;
+		qcom,hotplug-mitigation-enable;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/proxy-client.txt b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt
new file mode 100644
index 0000000..29cfaf9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt
@@ -0,0 +1,34 @@
+Bus Proxy Client Bindings
+
+Bus proxy client provides means to cast proxy bandwidth votes during bootup
+which is removed at the end of boot. This feature can be used in situations
+where a shared resource can be scaled between several possible perfomance
+levels and hardware requires that it be at a high level at the beginning of
+boot before the client has probed and voted for required bandwidth.
+
+Required properties:
+- compatible:			Must be "qcom,bus-proxy-client".
+
+Optional properties:
+- qcom,msm-bus,name:		String representing the client-name.
+- qcom,msm-bus,num-cases:	Total number of usecases.
+- qcom,msm-bus,active-only:	Boolean 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-KBps:	Arrays of unsigned integers representing:
+				master-id, slave-id, arbitrated bandwidth
+				in KBps, instantaneous bandwidth in KBps.
+
+Example:
+
+	qcom,proxy-client {
+		compatible = "qcom,bus-proxy-client";
+		qcom,msm-bus,name = "proxy_client";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>, <23 512 0 0>,
+			<22 512 0 6400000>, <23 512 0 6400000>,
+			<22 512 0 6400000>, <23 512 0 6400000>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
index 36e1a69..a53eba5 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -4,15 +4,28 @@
 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
-show to the user using the debugfs interface of the kernel.
+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: "qcom,rpmh-master-stats".
+- 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/clock/qcom,debugcc.txt b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt
new file mode 100644
index 0000000..a4452a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt
@@ -0,0 +1,20 @@
+Qualcomm Technologies, Inc. Debug Clock Controller Binding
+----------------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+			"qcom,debugcc-sdm845"
+			"qcom,debugcc-sdxpoorwills"
+
+- clock-names: Shall contain "xo_clk_src"
+- clocks: phandle + clock reference to the CXO clock.
+- #clock-cells : Shall contain 1.
+
+Example:
+	clock_debug: qcom,cc-debug {
+		compatible = "qcom,sdxpoorwills";
+		qcom,gcc = <&clock_gcc>;
+		clock-names = "xo_clk_src";
+		clocks = <&clock_rpmh RPMH_CXO_CLK>;
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 7330db4..ba29471 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -20,7 +20,6 @@
 			"qcom,gcc-sdm845-v2"
 			"qcom,gcc-sdm845-v2.1"
 			"qcom,gcc-sdm670"
-			"qcom,debugcc-sdm845"
 			"qcom,gcc-sdxpoorwills"
 
 - reg : shall contain base register location and length
diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
new file mode 100644
index 0000000..0149ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
@@ -0,0 +1,57 @@
+* Qualcomm Technologies, Inc. Connectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for SDIO
+based Wi-Fi devices. It also adds support to manage two 1.8V voltage
+regulators and WLAN power enable 3.3V regulators. The main purpose of this
+device tree entry below is to invoke the CNSS SDIO platform driver
+and provide handle to the WLAN power enable 3.3V pmic GPIO and two 1.8V
+PMIC voltage regulator resources.
+
+Required properties:
+  - compatible: "qcom,cnss_sdio"
+  - reg: memory resource to save firmware dump, optional.
+  - reg-names: memory resource name.
+  - subsys-name: cnss sdio subsytem device name, required.
+  - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node.
+  - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node.
+  - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node.
+  - vdd-wlan-xtal-supply: phandle to the WLAM XTAL regulator device tree node.
+
+Optional properties:
+  - pinctrl-names: Names corresponding to the numbered pinctrl states
+  - pinctrl-<n>: Pinctrl states as described in
+                bindings/pinctrl/pinctrl-bindings.txt
+  - qcom,is-antenna-shared: Enabled for Platforms with both sdio and pcie QCA
+                           Chipsets are attached.
+  - qcom,cnss-enable-bus-bandwidth: Boolean - Define this property when target
+					support to vote for bus bandwidth.
+  - qcom,msm-bus,name: client name for msm bus register.
+  - qcom,msm-bus,num-cases: number of cases for bus scaling.
+  - qcom,msm-bus,num-paths: number of paths for bus scale vector.
+  - qcom,msm-bus,vectors-KBps: bus scale vector table.
+  - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where
+                           wlan_en toggling is not supported.
+Example:
+	qcom,cnss-sdio {
+		compatible = "qcom,cnss_sdio";
+		reg = <0x87a00000, 0x200000>;
+		reg-names = "ramdump";
+		subsys-name = "AR6320";
+		vdd-wlan-supply = <&rome_vreg>;
+		vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>;
+		vdd-wlan-io-supply = <&mdm9607_l11>;
+		vdd-wlan-xtal-supply = <&mdm9607_l2>;
+		qcom,is-antenna-shared;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&cnss_sdio_active>;
+		pinctrl-1 = <&cnss_sdio_sleep>;
+		qcom,cnss-enable-bus-bandwidth;
+		qcom,msm-bus,name = "msm-cnss";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<79 512 0 0>,			/* No vote */
+				<79 512 6250 200000>,		/* 50 Mbps */
+				<79 512 25000 200000>,		/* 200 Mbps */
+				<79 512 2048000 4096000>;	/* MAX */
+	};
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index ad9d190..e70109d 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -30,6 +30,7 @@
   - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
   - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory
   - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal.
+  - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert.
 
 Example:
 
@@ -61,4 +62,5 @@
 	vdd-0.8-cx-mx-supply = <&pm8998_l5>;
 	qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
 	qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+	qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
     };
diff --git a/Documentation/devicetree/bindings/display/bridge/lt9611.txt b/Documentation/devicetree/bindings/display/bridge/lt9611.txt
new file mode 100644
index 0000000..61688b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/lt9611.txt
@@ -0,0 +1,125 @@
+LT9611 DSI to HDMI bridge
+
+
+Required properties:
+	- compatible:				Must be "lt,lt9611"
+	- reg:					Main I2C slave ID (for I2C host driver)
+	- lt,irq-gpio:				Main IRQ gpio mapping
+	- lt,reset-gpio				Main reset gpio mapping
+
+
+	Optional properties:
+	- lt,hdmi-ps-gpio:			gpio mapping for HDMI PS
+	- lt,hdmi-en-gpio:			gpio mapping for HDMI EN
+
+	- lt,supply-entries:			A node that lists the elements of the supply used to
+						power the bridge. There can be more than one instance
+						of this binding, in which case the entry would be
+						appended with the supply entry index.
+	e.g. lt,supply-entry@0
+	-- lt,supply-name: name of the supply (vdd/vcc)
+	-- lt,supply-min-voltage: minimum voltage level (uV)
+	-- lt,supply-max-voltage: maximum voltage level (uV)
+	-- lt,supply-enable-load: load drawn (uA) from enabled supply
+	-- lt,supply-disable-load: load drawn (uA) from disabled supply
+	-- lt,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode
+	-- lt,supply-pre-on-sleep: time to sleep (ms) before turning on
+	-- lt,supply-post-on-sleep: time to sleep (ms) after turning on
+	-- lt,supply-pre-off-sleep: time to sleep (ms) before turning off
+	-- lt,supply-post-off-sleep: time to sleep (ms) after turning off
+
+	- lt,non-pluggable: Boolean to indicate if display is non pluggable.
+	- lt,customize-modes: Customized modes when it's non-pluggable display.
+	e.g. lt,customize-mode-id@0
+	-- lt,mode-h-active: Horizontal active pixels for this mode.
+	-- lt,mode-h-front-porch: Horizontal front porch in pixels for this mode.
+	-- lt,mode-h-pulse-width: Horizontal sync width in pixels for this mode.
+	-- lt,mode-h-back-porch: Horizontal back porch in pixels for this mode.
+	-- lt,mode-h-active-high: Boolean to indicate if mode horizontal polarity is active high.
+	-- lt,mode-v-active: Vertical active lines for this mode.
+	-- lt,mode-v-front-porch: Vertical front porch in lines for this mode.
+	-- lt,mode-v-pulse-width: Vertical sync width in lines for this mode.
+	-- lt,mode-v-back-porch: Vertical back porch in lines for this mode.
+	-- lt,mode-v-active-high: Boolean to indicate if mode vertical polarity is active high.
+	-- lt,mode-refersh-rate: Mode refresh rate in hertz.
+	-- lt,mode-clock-in-khz: Mode pclk in KHz.
+
+Required nodes:
+
+The LT9611 has one video port. Its connection is modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+Video port 0 is for the DSI input. The remote endpoint phandle should
+be a reference to a valid mipi_dsi_host device node.
+
+
+Example:
+
+&qupv3_se9_i2c {
+	status = "okay";
+	lt9611@3b {
+		compatible = "lt,lt9611";
+		reg = <0x3b>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <125 0>;
+		interrupt-names = "lt_irq";
+		lt,irq-gpio = <&tlmm 125 0x0>;
+		lt,reset-gpio = <&tlmm 134 0x0>;
+		lt,hdmi-ps-gpio = <&tlmm 136 0x0>;
+		lt,hdmi-en-gpio = <&tlmm 137 0x0>;
+
+		vcc-supply = <&pm660l_l6>;
+		vdd-supply = <&pm660_l11>;
+		lt,supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			lt,supply-entry@0 {
+				reg = <0>;
+				lt,supply-name = "vcc";
+				lt,supply-min-voltage = <3300000>;
+				lt,supply-max-voltage = <3300000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+
+			lt,supply-entry@1 {
+				reg = <1>;
+				lt,supply-name = "vdd";
+				lt,supply-min-voltage = <1800000>;
+				lt,supply-max-voltage = <1800000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+		};
+
+		lt,customize-modes {
+			lt,customize-mode-id@0 {
+				lt,mode-h-active = <1920>;
+				lt,mode-h-front-porch = <88>;
+				lt,mode-h-pulse-width = <44>;
+				lt,mode-h-back-porch = <148>;
+				lt,mode-h-active-high;
+				lt,mode-v-active = <1080>;
+				lt,mode-v-front-porch = <4>;
+				lt,mode-v-pulse-width = <5>;
+				lt,mode-v-back-porch = <36>;
+				lt,mode-v-active-high;
+				lt,mode-refresh-rate = <60>;
+				lt,mode-clock-in-khz = <148500>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lt9611_in: endpoint {
+				remote-endpoint = <&ext_dsi_out>;
+				};
+			};
+		};
+	};
+};
+
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index a89b834..0f40cbce 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -66,6 +66,10 @@
 - qcom,dsi-display:       Specifies dsi display is present
 - qcom,hdmi-display:      Specifies hdmi is present
 - qcom,dp-display:        Specified dp is present
+- ports:                  This video port is used when external bridge is present. The connection is modelled
+                          using the OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+                          Video port 0 is for the bridge output. The remote endpoint phandle should be
+                          mipi_dsi_device device node.
 - qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the
 					a particular "type" of DSI module. The module "types"
 					can be "core", "ctrl", and "phy". Within the same type,
diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
index 35383adb..91a49af 100644
--- a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
+++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt
@@ -8,7 +8,7 @@
 - compatible:
     Usage: required
     Value type: <string>
-    Definition: Should contain "qcom,pm8941-misc";
+    Definition: Should contain "qcom,pm8941-misc" or "qcom,pmd-vbus-det";
 
 - reg:
     Usage: required
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 493a1aa..7bcb2dc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi-panel
+Qualcomm Technologies, Inc. mdss-dsi-panel
 
 mdss-dsi-panel is a dsi panel device which supports panels that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 2f74f7f..8b593a9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi
+Qualcomm Technologies, Inc. mdss-dsi
 
 mdss-dsi is the master DSI device which supports multiple DSI host controllers that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index c474b88..3d649e5 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS EDP
+Qualcomm Technologies, Inc. MDSS EDP
 
 MDSS EDP is a edp driver which supports panels that are compatible with
 VESA EDP display interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index e33d358..3661221 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS MDP
+Qualcomm Technologies, Inc. MDSS MDP
 
 MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
 drive user interface to different panel interfaces. MDP driver is the core of
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index d746a52..6b9238c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -1,8 +1,7 @@
-Qualcomm MDSS pll for DSI/EDP/HDMI
+Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI
 
-mdss-pll is a pll controller device which supports pll devices that
-are compatiable with MIPI display serial interface specification,
-HDMI and edp.
+mdss-pll is a pll controller device which supports pll devices that are
+compatiable with MIPI display serial interface specification, HDMI and edp.
 
 Required properties:
 - compatible:		Compatible name used in the driver. Should be one of:
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index 7f95ed4..285a14f 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -1,4 +1,4 @@
-* Qualcomm HDMI Tx
+* Qualcomm Technologies, Inc. HDMI Tx
 
 Required properties:
 - cell-index: hdmi tx controller index
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
index b399145..c679fe6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -42,6 +42,7 @@
   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"
@@ -83,4 +84,9 @@
 			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
index aece6ac..747e0b6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -17,6 +17,10 @@
 
 - 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)
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 55cd383..7976a87 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -130,6 +130,13 @@
 				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
@@ -160,6 +167,15 @@
 				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
@@ -200,6 +216,9 @@
 - 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
@@ -230,7 +249,7 @@
 		Defines a SOC hardware revision.
 
 Properties:
-- reg:
+-  qcom,soc-hw-revision:
 		Identifier for the hardware revision - must match the value read
 		from the hardware.
 - qcom,chipid:
@@ -313,6 +332,15 @@
 		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>;
@@ -379,6 +407,7 @@
 				#size-cells = <0>;
 
 				qcom,speed-bin = <0>;
+				qcom,ca-target-pwrlevel = <1>;
 
 				qcom,gpu-pwrlevel@0 {
 					reg = <0>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
index 7dece8e..c33daab 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
@@ -11,6 +11,8 @@
  - reg			               : i2c slave address of the device.
  - interrupt-parent	           : parent of interrupt.
  - synaptics,irq-gpio	       : irq gpio.
+ - synaptics,reset-gpio	       : reset gpio.
+ - synaptics,power-gpio	       : power switch gpio.
  - synaptics,irq-flags         : irq flags.
 
 Optional property:
@@ -18,13 +20,23 @@
  - vcc_i2c-supply			   : analog voltage power supply needed to power device.
  - synaptics,pwr-reg-name	   : power reg name of digital voltage.
  - synaptics,bus-reg-name	   : bus reg name of analog voltage.
- - synaptics,irq-on-state      : status of irq gpio.
+ - synaptics,irq-on-state	 : irq gpio active state.
+ - synaptics,reset-on-state      : reset gpio active state.
+ - synaptics,power-on-state      : power switch active state.
+ - synaptics,ub-i2c-addr	 : microbootloader mode I2C slave address.
  - synaptics,cap-button-codes  : virtual key code mappings to be used.
  - synaptics,vir-button-codes  : virtual key code and the response region on panel.
  - synaptics,x-flip		       : modify orientation of the x axis.
  - synaptics,y-flip		       : modify orientation of the y axis.
  - synaptics,reset-delay-ms	   : reset delay for controller (ms), default 100.
+ - synaptics,reset-active-ms	   : reset active duration for controller (ms), default 100.
+ - synaptics,power-delay-ms	   : power delay for controller (ms), default 100.
  - synaptics,max-y-for-2d	   : maximal y value of the panel.
+ - synaptics,swap-axes		   : specify whether to swap axes.
+ - synaptics,resume-in-workqueue	: specify whether to defer the resume to workqueue.
+ - clock-names			: Clock names used for secure touch. They are: "iface_clk", "core_clk"
+ - clocks			: Defined if 'clock-names' DT property is defined. These clocks
+				  are associated with the underlying I2C bus.
 
 Example:
 	i2c@78b7000 {
@@ -34,8 +46,8 @@
 			reg = <0x4b>;
 			interrupt-parent = <&tlmm>;
 			interrupts = <65 0x2008>;
-			vdd_ana-supply = <&pmtitanium_l17>;
-			vcc_i2c-supply = <&pmtitanium_l6>;
+			vdd_ana-supply = <&pm8953_l17>;
+			vcc_i2c-supply = <&pm8953_l6>;
 			synaptics,pwr-reg-name = "vdd_ana";
 			synaptics,bus-reg-name = "vcc_i2c";
 			synaptics,irq-gpio = <&tlmm 65 0x2008>;
@@ -46,5 +58,9 @@
 			synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */
 			synaptics,cap-button-codes = <139 172 158>;
 			synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>;
+			/* Underlying clocks used by secure touch */
+			clock-names = "iface_clk", "core_clk";
+			clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+				<&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt
new file mode 100644
index 0000000..833b108
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,mpm.txt
@@ -0,0 +1,92 @@
+QTI MPM interrupt controller
+
+MPM (MSM sleep Power Manager) is QTI's platform parent interrupt controller.
+It manages subsystem wakeups and resources during sleep. This driver marks
+the wakeup interrupts in APSS such that it monitors the interrupts when the
+system is asleep, wakes up the APSS when one of these interrupts occur and
+replays it to the subsystem interrupt controller after it becomes operational.
+
+Platform interrupt controller MPM is next in hierarchy, followed by others.
+
+This defines 2 interrupt controllers to monitor the interrupts when the system is asleep:
+
+One for to monitor the wakeup capable gic interrupts called wakegic.
+
+Properties:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should contain "qcom,mpm-gic" and the respective target compatible flag.
+
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: should specify the IRQ used by remote processor to wakeup APSS.
+
+- interrupt-parent:
+	Usage: required
+	Value type: <phandle>
+	Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <bool>
+	Definition: Identifies the node as an interrupt controller.
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Specifies the base physical address to trigger an interrupt into remote processor.
+
+-reg-names:
+	Usage: required
+	Value type: <string>, <string>
+	Definition: Specifies the address field names.
+
+- qcom,num-mpm-irqs:
+	Usage: optional
+	Value type: <value>
+	Defination: Specifies the number of interrupts supported.
+
+Example:
+
+wakegic: wake-gic@7781b8 {
+	compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953", "qcom,mpm-gic-msm8937";
+	interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+	reg = <0x601d4 0x1000>,
+	    <0xb011008 0x4>;  /* MSM_APCS_GCC_BASE 4K */
+	reg-names = "vmpm", "ipc";
+	interrupt-controller;
+	interrupt-parent = <&intc>;
+	#interrupt-cells = <3>;
+};
+
+
+One for to monitor the wakeup capable gpio interrupts called wakegpio.
+
+properties:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should contain "qcom,mpm-gpio" and the respective target compatible flag.
+
+- interrupt-parent:
+	Usage: required
+	Value type: <phandle>
+	Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <bool>
+	Definition: Identifies the node as an interrupt controller.
+
+Example:
+
+wakegpio: wake-gpio {
+	compatible = "qcom,mpm-gpio", "qcom,mpm-gpio-msm8953", "qcom,mpm-gpio-msm8937";
+	interrupt-controller;
+	interrupt-parent = <&tlmm>;
+	#interrupt-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
index 07667a4..8d6fad0 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
@@ -31,6 +31,7 @@
 	* "qcom,pdc-sdm845": For sdm845 pin data
 	* "qcom,pdc-sdm845-v2": For sdm845 v2 pin data
 	* "qcom,pdc-sdm670": For sdm670 pin data
+	* "qcom,pdc-sdxpoorwills": For sdxpoorwills pin data
 
 - reg:
 	Usage: required
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
index 176f9e1..54ff110 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -119,6 +119,8 @@
 			  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.
+- qcom,bst-pwm-ovrhd-uv		: Charger flash VPH overhead. Applicable for PMI632 only.
+				  Supported values (in mV) are: 300, 400, 500, 600. Default is 300.
 
 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.
@@ -182,6 +184,10 @@
 				  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";
@@ -302,6 +308,7 @@
 			qcom,led-mask = <3>;
 			qcom,default-led-trigger =
 						"switch0_trigger";
+			qcom,symmetry-en;
 		};
 
 		pmi8998_switch1: qcom,led_switch_1 {
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
index b7ce662..1a76d5d 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
@@ -118,6 +118,18 @@
 
 Following properties are specific only to LRA vibrators.
 
+- qcom,lra-auto-mode
+  Usage:      optional
+  Value type: <empty>
+  Definition: If specified, a set of pre-configured settings will be applied
+		based on the pattern duration. For example, for a duration of
+		< 20 ms (short duration), one set of settings will be applied
+		and for a duration of >= 20 ms (long duration), another set of
+		settings will be applied. The parameters configured in the
+		driver when this property is specified is based on the LRA
+		tested internally. Those parameters should be fine-tuned or
+		adjusted based on the LRA used on different hardware platforms.
+
 - qcom,lra-auto-res-mode
   Usage:      optional
   Value type: <string>
@@ -200,9 +212,13 @@
 - qcom,wave-samples
   Usage:      optional
   Value type: <prop-encoded-array>
-  Definition: Wave samples in an array of 8 elements. Each element takes the
+  Definition: Wave samples in an array of 32 elements. Each element takes the
 		following representation, bit 0: unused, bits[5:1] : amplitude,
 		bit 6: overdrive, bit 7: sign. Default sample value is 0x3E.
+		Since the hardware supports configuring upto 8 samples, a set
+		of 8 samples will be configured initially and the next set will
+		be configured upon the play interrupt until all the samples are
+		configured and played.
 
 Following properties are applicable only when "qcom,play-mode" is set to
 "pwm".
diff --git a/Documentation/devicetree/bindings/mcd/mcd.txt b/Documentation/devicetree/bindings/mcd/mcd.txt
new file mode 100644
index 0000000..4077ee2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mcd/mcd.txt
@@ -0,0 +1,29 @@
+* MCD (MobiCore Driver)
+
+t-base is an operating system running in the secure world (TrustZone).
+The t-base implementation consists of several components in the
+secure world and the non-secure world (kernel and user space). The
+MobiCore driver communicates with the t-base operating system that
+exists in TrustZone.
+
+Required properties:
+  - compatible: Should be "qcom,mcd"
+  - qcom,ce-hw-instance: should contain crypto HW instance
+  - qcom,ce-device: Device number
+  - clocks: Array of <clock_controller_phandle clock_reference> listing
+            all the clocks that are accesed by this subsystem.
+  - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target.
+
+Example:
+	mcd {
+		compatible = "qcom,mcd";
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		qcom,ce-opp-freq = <100000000>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/laser-sensor.txt b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
new file mode 100644
index 0000000..0003f20
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
@@ -0,0 +1,29 @@
+Laser Sensor Device Tree Bindings.
+========================================
+
+Boards with the Laser Sensor connected to CCI shall have the following
+properties:
+
+Required node properties:
+	- cell-index: cci hardware core index
+    - compatible:
+		- "st,stmvl53l0" : STMiecroelectronics VL53L0 Laser sensor.
+	- reg : offset and length of the register set for the device
+	- qcom, cci-master: cci master the sensor connected to
+	- cam_cci-supply : cci voltage regulator used
+	- cam_laser-supply: laser sensor voltage regulator
+	- qcom,cam-vreg-name: voltage regulators name
+	- qcom, cam-vreg-min-voltage: specify minimum voltage level for
+		regulators used
+	- qcom, cam-vreg-max-voltage: specify maximum voltage level for
+		regulators used
+	- pinctrl-names : should specify the pin control groups followed by
+		the definition of each group
+		stm,irq-gpio : irq gpio which is to provide interrupts to host.
+	- gpios : should contain phandle to gpio controller node and array of
+		#gpio-cells specifying specific gpio (controller specific)
+	- qcom,gpio-req-tbl-num : contains index to gpios specific to the sensor
+	- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+		qcom,gpio-req-tbl-num property (in the same order)
+	- qcom,gpio-req-tbl-label : should contain name of gpios present in
+		qcom,gpio-req-tbl-num property (in the same order)
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
index 4b16103..66eaae1 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
@@ -108,6 +108,23 @@
   Definition: List of strings corresponds clock-rates levels.
   Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo.
 
+- control-camnoc-axi-clk
+  Usage: optional
+  Value type: <empty>
+  Definition: Bool property specifying whether to control camnoc axi
+              clock from cpas driver.
+
+- camnoc-bus-width
+  Usage: required if control-camnoc-axi-clk is enabled
+  Value type: <u32>
+  Definition: camnoc bus width.
+
+- camnoc-axi-clk-bw-margin-perc
+  Usage: optional
+  Value type: <u32>
+  Definition: Percentage value to be added to camnoc bw while calculating
+              camnoc axi clock frequency.
+
 - qcom,msm-bus,name
 - qcom,msm-bus,num-cases
 - qcom,msm-bus,num-paths
@@ -147,6 +164,13 @@
   Definition: Bool property specifying whether Clients are connected
               through CAMNOC for AXI access.
 
+- nvmem-cells
+  Usage: optional
+  Definition: nvmem cell node
+
+- nvmem-cell-names
+  Usage: required
+  Definition: If nvmem node is present, cell name is required
 ===================================================================
 Third Level Node - CAM AXI Port properties
 ===================================================================
@@ -204,6 +228,9 @@
 		src-clock-name = "slow_ahb_clk_src";
 		clock-rates = <0 0 0 0 80000000 0>;
 		clock-cntl-level = "turbo";
+		control-camnoc-axi-clk;
+		camnoc-bus-width = <32>;
+		camnoc-axi-clk-bw-margin-perc = <10>;
 		qcom,msm-bus,name = "cam_ahb";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,num-paths = <1>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
index cf551f6..c47cb34 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
@@ -49,7 +49,7 @@
 - compatible
   Usage: required
   Value type: <string>
-  Definition: Should be "qcom,fd41".
+  Definition: Should be one of "qcom,fd41", "qcom,fd501".
 
 - reg-names
   Usage: optional
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-soc.txt b/Documentation/devicetree/bindings/media/video/msm-cam-soc.txt
new file mode 100644
index 0000000..382395f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-soc.txt
@@ -0,0 +1,41 @@
+* Qualcomm Technologies, Inc. MSM Camera SOC
+
+The below set of properties need to be defined by all the camera
+modules in their respective dtsi to adapt to SOC layer
+
+Required properties:
+  - clock-names: name of the clocks required for the device
+  - qcom,clock-rates: clock rate in Hz
+    - 0 if appropriate clock is required but doesn't have to apply the rate
+  - qcom,vdd-names: names of all the regulators for the device
+  - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+    below optional properties:
+      - qcom,msm-bus,name
+      - qcom,msm-bus,num-cases
+      - qcom,msm-bus,num-paths
+      - qcom,msm-bus,vectors-KBps
+  - qcom,msm-bus-vector-dyn-vote: indicated dynamic or static voting
+  - qcom,clock-cntl-support: indicates if further control supported for clocks
+  - Refer to "Documentation/devicetree/bindings/media/video/msm-ispif.txt" for
+    below optional property:
+      - qcom,clock-control
+
+Example:
+
+   cpp: qcom,cpp@a04000 {
+       mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+       camss-vdd-supply = <&gdsc_camss_top>;
+       vdd-supply = <&gdsc_cpp>;
+       qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+       clock-names = "camss_top_ahb_clk",
+                "ispif_ahb_clk", "csiphy_timer_src_clk",
+                "csiphy_timer_clk";
+       qcom,clock-rates = <0 0 200000000 0>;
+       qcom,msm-bus,name = "msm_camera_cpp";
+       qcom,msm-bus,num-cases = <2>;
+       qcom,msm-bus,num-paths = <1>;
+       qcom,msm-bus,vectors-KBps =
+               <106 512 0 0>,
+               <106 512 0 0>;
+       qcom,msm-bus-vector-dyn-vote;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam.txt b/Documentation/devicetree/bindings/media/video/msm-cam.txt
new file mode 100644
index 0000000..371447c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam.txt
@@ -0,0 +1,19 @@
+* Qualcomm Technologies, Inc. MSM Camera
+
+Required properties:
+- compatible :
+    - "qcom,msm-cam"
+- reg : offset and length of msm camera device registers.
+- reg-names : should specify relevant names for each reg property defined.
+
+Optional properties:
+- qcom,gpu-limit : valid kgsl frequency.
+
+Example:
+
+   qcom,msm-cam@fd8c0000 {
+       compatible = "qcom,msm-cam";
+       reg = <0xfd8C0000 0x10000>;
+       reg-names = "msm-cam";
+       qcom,gpu-limit = <700000000>;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
new file mode 100644
index 0000000..b43b295
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -0,0 +1,398 @@
+* Qualcomm Technologies, Inc. MSM CCI
+
+[First level nodes]
+Required properties:
+- cell-index: cci hardware core index
+- compatible :
+    - "qcom,cci"
+- reg : offset and length of the register set for the device
+    for the cci operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the cci interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- gpios : should contain phandle to gpio controller node and array of
+    #gpio-cells specifying specific gpio (controller specific)
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- clock-names: name of the clocks required for the device
+- clock-rates: clock rate in Hz
+
+Optional properties:
+- qcom,cam-vreg-name : name of the voltage regulators required for the device.
+- gdscr-supply : should contain gdsr regulator used for cci clocks.
+- mmagic-supply : should contain mmagic regulator used for mmagic clocks.
+
+- I2c speed settings (*)
+	- i2c_freq_100Khz: qcom,i2c_standard_mode - node should contain clock settings for
+	    100Khz
+	- i2c_freq_400Khz: qcom,i2c_fast_mode - node should contain clock settings for
+	    400Khz
+	- i2c_freq_custom: qcom,i2c_custom_mode - node can contain clock settings for
+	    frequencies other than 100Khz and 400Khz which is specific to usecase.
+	    Currently it has settings for 375Khz.
+	- i2c_freq_1Mhz: qcom,i2c_fast_plus_mode - node should contain clock
+	    settings for 1Mhz
+	* if speed settings is not defined the low level driver can use "i2c_freq_custom"
+	  like default
+
+[Second level nodes]
+* Qualcomm Technologies, Inc. CCI clock settings
+
+Optional properties:
+- qcom,hw-thigh : should contain high period of the SCL clock in terms of CCI
+    clock cycle
+- qcom,hw-tlow : should contain high period of the SCL clock in terms of CCI
+    clock cycle
+- qcom,hw-tsu-sto : should contain setup time for STOP condition
+- qcom,hw-tsu-sta : should contain setup time for Repeated START condition
+- qcom,hw-thd-dat : should contain hold time for the data
+- qcom,hw-thd-sta : should contain hold time for START condition
+- qcom,hw-tbuf : should contain free time between a STOP and a START condition
+- qcom,hw-scl-stretch-en : should contain enable or disable clock stretching
+- qcom,hw-trdhld : should contain internal hold time for SDA
+- qcom,hw-tsp : should contain filtering of glitches
+
+* Qualcomm Technologies, Inc. MSM Sensor
+
+MSM sensor node contains properties of camera sensor
+
+Required properties:
+- compatible : should be manufacturer name followed by sensor name
+    - "qcom,camera"
+    - "shinetech,gc0310"
+- reg : should contain i2c slave address of the device
+- qcom,csiphy-sd-index : should contain csiphy instance that will used to
+    receive sensor data
+    - 0, 1, 2
+- qcom,csid-sd-index : should contain csid core instance that will used to
+    receive sensor data
+    - 0, 1, 2, 3
+- cam_vdig-supply : should contain regulator from which digital voltage is
+    supplied
+- cam_vana-supply : should contain regulator from which analog voltage is
+    supplied
+- cam_vio-supply : should contain regulator from which IO voltage is supplied
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    sensor
+    - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
+    mentioned in qcom,cam-vreg-name property (in the same order)
+
+Optional properties:
+- qcom,slave-id : should contain i2c slave address, device id address
+    ,expected id read value and device id mask
+- qcom,sensor-name : should contain unique sensor name to differentiate from
+    other sensor
+    - "s5k3l1yx"
+- qcom,sensor-mode : should contain sensor mode supported
+    - 0 -> back camera 2D
+    - 1 -> front camera 2D
+    - 2 -> back camera 3D
+    - 3 -> back camera int 3D
+- qcom,sensor-type : should contain format of data that sensor streams
+    - 0 -> bayer format
+    - 1 -> yuv format
+- qcom,is-vpe : should be enabled if VPE module is required for post processing
+    of this sensor
+    - 1 if required, 0 otherwise
+- qcom,mount-angle : should contain the physical mount angle of the sensor on
+    the target
+    - 0, 90, 180, 360
+- qcom,secure : should be enabled to operate the camera in secure mode
+    - 0, 1
+- qcom,mclk-23880000 : should be enabled if the supported mclk is 23.88Mhz and
+    not 24 Mhz.
+- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
+    available
+    - 1 if gpio mux is not available, 0 otherwise
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+- gpios : should contain phandle to gpio controller node and array of
+    #gpio-cells specifying specific gpio (controller specific)
+- qcom,gpio-reset : should contain index to gpio used by sensors reset_n
+- qcom,gpio-standby : should contain index to gpio used by sensors standby_n
+- qcom,gpio-vio : should contain index to gpio used by sensors io vreg enable
+- qcom,gpio-vana : should contain index to gpio used by sensors analog vreg enable
+- qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable
+- qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable
+- qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
+    configured by msm
+- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
+    present in qcom,gpio-set-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
+    gpios as specified in gpio_set_tbl_flags property (in the same order)
+- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
+    lanes to CSID lanes
+    - 0x4320
+- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
+    be enabled
+- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
+    receive data
+- qcom,actuator-cam-name : should contain actuator cam name associated with
+    this sensor
+    - If actuator does not exist, this property should not be initialized
+    - If actuator exist, this field should indicate the index of actuator to
+      be used
+- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
+    for actuator
+- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
+    gpio
+- qcom,sensor-position : should contain the mount angle of the camera sensor
+    - 0 -> back camera
+    - 1 -> front camera
+- qcom,cci-master : should contain i2c master id to be used for this camera
+    sensor
+    - 0 -> MASTER 0
+    - 1 -> MASTER 1
+- qcom,actuator-src : if auto focus is supported by this sensor, this
+   property should contain phandle of respective actuator node
+- qcom,led-flash-src : if LED flash is supported by this sensor, this
+   property should contain phandle of respective LED flash node
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+    supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
+- qcom,eeprom-src : if eeprom memory is supported by this sensor, this
+   property should contain phandle of respective eeprom nodes
+- qcom,ois-src : if optical image stabilization is supported by this sensor,
+   this property should contain phandle of respective ois node
+- qcom,ir-led-src : if ir led is supported by this sensor, this property
+   should contain phandle of respective ir-led node
+- qcom,ir-cut-src : if ir cut is supported by this sensor, this property
+   should contain phandle of respective ir-cut node
+- qcom,special-support-sensors: if only some special sensors are supported
+   on this board, add sensor name in this property.
+
+* Qualcomm Technologies, Inc. MSM ACTUATOR
+
+Required properties:
+- cell-index : should contain unique identifier to differentiate
+    between multiple actuators
+- reg : should contain i2c slave address of the actuator and length of
+    data field which is 0x0
+- compatible :
+    - "qcom,actuator"
+- qcom,cci-master : should contain i2c master id to be used for this camera
+    sensor
+    - 0 -> MASTER 0
+    - 1 -> MASTER 1
+
+Optional properties:
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    actuator
+    - "cam_vaf"
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain the maximum current in microamps
+   required from the regulators mentioned in the qcom,cam-vreg-name property
+   (in the same order).
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+
+* Qualcomm Technologies, Inc. MSM LASER LED
+
+Required properties:
+- cell-index : should contain unique identifier to differentiate
+    between multiple laser led modules
+- reg : should contain i2c slave address of the laser led and length of
+    data field which is 0x0
+- compatible :
+    - "qcom,laser-led"
+- qcom,cci-master : should contain i2c master id to be used for this camera
+    sensor
+    - 0 -> MASTER 0
+    - 1 -> MASTER 1
+
+Optional properties:
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+   laser led
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level in microvolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level in microvolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain the maximum current in microamps
+   required from the regulators mentioned in the qcom,cam-vreg-name property
+   (in the same order).
+
+* Qualcomm Technologies, Inc. MSM OIS
+
+Required properties:
+- cell-index : should contain unique identifier to differentiate
+    between multiple ois drivers
+- reg : should contain i2c slave address of the ois and length of
+    data field which is 0x0
+- compatible :
+    - "qcom,ois"
+- qcom,cci-master : should contain i2c master id to be used for this camera
+    sensor
+    - 0 -> MASTER 0
+    - 1 -> MASTER 1
+
+Optional properties:
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    ois
+    - "cam_vaf"
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts
+   for regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain the maximum current in microamps
+   required from the regulators mentioned in the qcom,cam-vreg-name property
+   (in the same order).
+- cam_vaf-supply : should contain regulator from which ois voltage is supplied
+
+Example:
+
+   qcom,cci@0xfda0c000 {
+       cell-index = <0>;
+       compatible = "qcom,cci";
+       reg = <0xfda0c000 0x300>;
+       reg-names = "cci";
+       interrupts = <0 50 0>;
+       interrupt-names = "cci";
+	clock-names = "camss_top_ahb_clk", "vfe_clk_src",
+			"camss_vfe_vfe_clk", "iface_clk", "cpp_core_clk",
+			"cpp_iface_clk", "cpp_bus_clk", "micro_iface_clk";
+	qcom,clock-rates = <0 266670000 0 0 266670000 0 0 0>;
+       gpios = <&msmgpio 19 0>,
+               <&msmgpio 20 0>,
+               <&msmgpio 21 0>,
+               <&msmgpio 22 0>;
+       qcom,gpio-tbl-num = <0 1 2 3>;
+       qcom,gpio-tbl-flags = <1 1 1 1>;
+       qcom,gpio-tbl-label = "CCI_I2C_DATA0",
+                             "CCI_I2C_CLK0",
+                             "CCI_I2C_DATA1",
+                             "CCI_I2C_CLK1";
+		i2c_freq_100Khz: qcom,i2c_standard_mode {
+			status = "disabled";
+		};
+		i2c_freq_400Khz: qcom,i2c_fast_mode {
+			status = "disabled";
+		};
+		i2c_freq_custom: qcom,i2c_custom_mode {
+			status = "disabled";
+		};
+
+        actuator0: qcom,actuator@18 {
+                cell-index = <0>;
+                reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8941_l23>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <3000000>;
+		qcom,cam-vreg-max-voltage = <3000000>;
+		qcom,cam-vreg-op-mode = <100000>;
+        };
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,secure = <1>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,eeprom-src = <&eeprom0>;
+		cam_vdig-supply = <&pm8994_s3>;
+		cam_vio-supply = <&pm8994_lvs1>;
+		cam_vana-supply = <&pm8994_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-min-voltage = <1300000 0 2500000>;
+		qcom,cam-vreg-max-voltage = <1300000 0 2500000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 30 0>,
+			<&tlmm 29 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_mmss clk_mclk0_clk_src>,
+				<&clock_mmss clk_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+	};
+
+&i2c_freq_100Khz {
+	qcom,hw-thigh = <78>;
+	qcom,hw-tlow = <114>;
+	qcom,hw-tsu-sto = <28>;
+	qcom,hw-tsu-sta = <28>;
+	qcom,hw-thd-dat = <10>;
+	qcom,hw-thd-sta = <77>;
+	qcom,hw-tbuf = <118>;
+	qcom,hw-scl-stretch-en = <0>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <1>;
+	status = "ok";
+};
+
+&i2c_freq_400Khz {
+	qcom,hw-thigh = <20>;
+	qcom,hw-tlow = <28>;
+	qcom,hw-tsu-sto = <21>;
+	qcom,hw-tsu-sta = <21>;
+	qcom,hw-thd-dat = <13>;
+	qcom,hw-thd-sta = <18>;
+	qcom,hw-tbuf = <25>;
+	qcom,hw-scl-stretch-en = <0>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <3>;
+	status = "ok";
+};
+
+&i2c_freq_custom {
+	qcom,hw-thigh = <15>;
+	qcom,hw-tlow = <28>;
+	qcom,hw-tsu-sto = <21>;
+	qcom,hw-tsu-sta = <21>;
+	qcom,hw-thd-dat = <13>;
+	qcom,hw-thd-sta = <18>;
+	qcom,hw-tbuf = <25>;
+	qcom,hw-scl-stretch-en = <1>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <3>;
+	status = "ok";
+};
+
+&i2c_freq_1Mhz {
+	qcom,hw-thigh = <16>;
+	qcom,hw-tlow = <22>;
+	qcom,hw-tsu-sto = <17>;
+	qcom,hw-tsu-sta = <18>;
+	qcom,hw-thd-dat = <16>;
+	qcom,hw-thd-sta = <15>;
+	qcom,hw-tbuf = <19>;
+	qcom,hw-scl-stretch-en = <1>;
+	qcom,hw-trdhld = <3>;
+	qcom,hw-tsp = <3>;
+	qcom,cci-clk-src = <37500000>;
+	status = "ok";
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
new file mode 100644
index 0000000..450e4d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -0,0 +1,145 @@
+* Qualcomm Technologies, Inc. MSM CPP
+
+Required properties:
+- cell-index: cpp hardware core index
+- compatible :
+    - "qcom,cpp"
+- reg : offset and length of the register set for the device
+    for the cpp operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+  - cpp - has CPP MICRO register set.
+  - cpp_vbif - has VBIF core register set used by CPP.
+  - cpp_hw - has CPP hardware register set.
+- interrupts : should contain the cpp interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- vdd-supply: phandle to GDSC regulator controlling VFE & CPP core.
+- clocks: list of phandles to the clock controller device and coresponding
+  clock names.
+- clock-names: name of the clocks required for the device used by the consumer.
+- qcom,clock-rates: clock rate in Hz.
+- qcom,min-clock-rate: minimum clock rate in Hz, to be set to CPP hardware in
+  case dynamic clock scaling based on prevalent streams need lower clock rate.
+- qcom,cpp-fw-payload-info: Child node for cpp node having infomration on
+  cpp firmware payload offsets. This is mandatory node.
+- resets: reset specifier pair consists of phandle for the reset controller
+  and reset lines used by this controller.
+- reset-names: reset signal name strings sorted in the same order as the resets
+  property.
+- qcom,src-clock-rates =  This is an array which holds clock rates for cpp src
+  clocks. The maximum size for the array is 10.
+
+Required properties of the child node:
+- qcom,stripe-base = Base offset of stripes in cpp payload.
+- qcom,plane-base = Base offset of planes in cpp payload.
+- qcom,stripe-size = size of each stripe in payload.
+- qcom,plane-size = size of each plane in payload.
+- qcom,fe-ptr-off = offset from stripe base to fetch engine address
+  location in payload.
+- qcom,we-ptr-off = offset from stripe base to write engine address
+  location in payload.
+
+Optional properties of the child node:
+- qcom,ref-fe-ptr-off =  offset from stripe base to reference fetch engine
+  address location in payload.
+- qcom,ref-we-ptr-off = offset from stripe base to reference write engine
+  address location in payload.
+- qcom,we-meta-ptr-off = offset from stripe base to metadata address
+  location in payload.
+- qcom,fe-mmu-pf-ptr-off = offset from plane base to fetch engine mmu prefetch
+  address min location in payload.
+- qcom,ref-fe-mmu-pf-ptr-off = offset from plane base to reference fetch engine
+  mmu prefetch address min location in payload.
+- qcom,we-mmu-pf-ptr-off = offset from plane base to write engine mmu prefetch
+  address min location in payload.
+- qcom,dup-we-mmu-pf-ptr-off = offset from plane base to duplicate write engine
+   mmu prefetch address min location in payload.
+- qcom,ref-we-mmu-pf-ptr-off =  offset from plane base to reference write engine
+   mmu prefetch address min location in payload.
+- qcom,set-group-buffer-len = length/size of set group buffer command used for
+  hfr.
+- qcom,dup-frame-indicator-off =  offset for duplicate frame indicator in a
+  batch for frames
+
+Optional properties:
+- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic.
+- camss-vdd-supply: phandle to GDSC regulator controlling camss.
+- qcom,bus-master: Flag for presence of CPP bus master. It has to be set only for
+  platforms that support such feature.
+- qcom,vbif-setting: The offset and value for vbif core qos registers.
+  The first entry is register offset and second entry is register value.
+- qcom,micro-reset: Boolean flag indicating if micro reset need to be enabled.
+  This needs to present on platforms that support this feature.
+- qcom,cpp-cx-ipeak: To handle Cx peak current limit.
+                     <phandle bit>
+                     phandle - phandle of cx ipeak device node
+                     bit     - bit number of client in relevant register
+  This is used to access Cx ipeak HW module to limit the current drawn by
+  various subsystem blocks on Cx power rail. CPP set their bit in tcsr register
+  if it is going to cross its own threshold.
+
+Example:
+
+	qcom,cpp@fda04000 {
+		cell-index = <0>;
+		compatible = "qcom,cpp";
+		reg = <0xfda04000 0x100>,
+			<0xfda80000 0x200>,
+			<0xfda18000 0x008>,
+			<0xfd8c36D4 0x4>;
+		reg-names = "cpp", "cpp_vbif", "cpp_hw", "camss_cpp";
+		interrupts = <0 49 0>;
+		interrupt-names = "cpp";
+		mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+		camss-vdd-supply = <&gdsc_camss_top>;
+		vdd-supply = <&gdsc_cpp>;
+		clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+			<&clock_gcc  clk_mmssnoc_axi_clk>,
+			<&clock_mmss clk_mmagic_camss_axi_clk>,
+			<&clock_mmss clk_camss_top_ahb_clk>,
+			<&clock_mmss clk_cpp_clk_src>,
+			<&clock_mmss clk_camss_cpp_ahb_clk>,
+			<&clock_mmss clk_camss_cpp_axi_clk>,
+			<&clock_mmss clk_camss_cpp_clk>,
+			<&clock_mmss clk_camss_micro_ahb_clk>,
+			<&clock_mmss clk_camss_ahb_clk>;
+			<&clock_mmss clk_smmu_cpp_axi_clk>,
+			<&clock_mmss clk_camss_cpp_vbif_ahb_clk>,
+		clock-names = "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk",
+			"mmagic_camss_axi_clk", "camss_top_ahb_clk",
+			"cpp_core_clk",	"camss_cpp_ahb_clk",
+			"camss_cpp_axi_clk", "camss_cpp_clk",
+			"micro_iface_clk", "camss_ahb_clk";
+			"smmu_cpp_axi_clk", "cpp_vbif_ahb_clk";
+		qcom,clock-rates = <0 0 0 0 465000000 0 0 465000000 0 0 0 0>;
+		qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>;
+		qcom,min-clock-rate = <320000000>;
+		qcom,bus-master = <1>;
+		qcom,vbif-qos-setting = <0x20 0x10000000>,
+			<0x24 0x10000000>,
+			<0x28 0x10000000>,
+			<0x2C 0x10000000>;
+		qcom,src-clock-rates = <100000000 200000000 384000000 404000000
+			480000000 576000000 600000000>;
+		qcom,micro-reset;
+		qcom,cpp-fw-payload-info {
+			qcom,stripe-base = <553>;
+			qcom,plane-base = <481>;
+			qcom,stripe-size = <61>;
+			qcom,plane-size = <24>;
+			qcom,fe-ptr-off = <11>;
+			qcom,we-ptr-off = <23>;
+			qcom,ref-fe-ptr-off = <17>;
+			qcom,ref-we-ptr-off = <36>;
+			qcom,we-meta-ptr-off = <42>;
+			qcom,fe-mmu-pf-ptr-off = <6>;
+			qcom,ref-fe-mmu-pf-ptr-off = <9>;
+			qcom,we-mmu-pf-ptr-off = <12>;
+			qcom,dup-we-mmu-pf-ptr-off = <17>;
+			qcom,ref-we-mmu-pf-ptr-off = <22>;
+			qcom,set-group-buffer-len = <135>;
+			qcom,dup-frame-indicator-off = <70>;
+		resets = <&clock_mmss MMSS_CAMSS_MICRO_BCR>;
+		reset-names = "micro_iface_reset";
+		};
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
new file mode 100644
index 0000000..8a6b3c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
@@ -0,0 +1,40 @@
+* Qualcomm Technologies, Inc. MSM CSI Phy
+
+Required properties:
+- cell-index: csi phy hardware core index
+- compatible :
+    - "qcom,csiphy"
+    - "qcom,csiphy-v2.0"
+    - "qcom,csiphy-v2.2"
+    - "qcom,csiphy-v3.0"
+    - "qcom,csiphy-v3.1"
+    - "qcom,csiphy-v3.1.1"
+    - "qcom,csiphy-v3.2"
+    - "qcom,csiphy-v3.4.2"
+    - "qcom,csiphy-v3.5"
+    - "qcom,csiphy-v5.0"
+    - "qcom,csiphy-v5.01"
+- reg : offset and length of the register set for the device
+    for the csiphy operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csiphy interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- clock-names: name of the clocks required for the device
+- qcom,clock-rates: clock rate in Hz
+	- 0 if appropriate clock is required but doesn't have to apply the rate
+
+Example:
+
+   qcom,csiphy@fda0ac00 {
+       cell-index = <0>;
+       compatible = "qcom,csiphy-v2.0", "qcom,csiphy";
+       reg = <0xfda0ac00 0x200>;
+       reg-names = "csiphy";
+       interrupts = <0 78 0>;
+       interrupt-names = "csiphy";
+       clock-names = "camss_top_ahb_clk",
+                "ispif_ahb_clk", "csiphy_timer_src_clk",
+                "csiphy_timer_clk";
+       qcom,clock-rates = <0 0 200000000 0>;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-csid.txt b/Documentation/devicetree/bindings/media/video/msm-csid.txt
new file mode 100644
index 0000000..340d986
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csid.txt
@@ -0,0 +1,52 @@
+* Qualcomm Technologies, Inc. MSM CSID
+
+Required properties:
+- cell-index: csid hardware core index
+- compatible :
+    - "qcom,csid"
+    - "qcom,csid-v2.0"
+    - "qcom,csid-v2.2"
+    - "qcom,csid-v3.0"
+    - "qcom,csid-v3.1"
+    - "qcom,csid-v3.2"
+    - "qcom,csid-v3.5"
+    - "qcom,csid-v4.0"
+    - "qcom,csid-v3.4.2"
+    - "qcom,csid-v3.5.1"
+    - "qcom,csid-v3.4.3"
+    - "qcom,csid-v5.0"
+- reg : offset and length of the register set for the device
+    for the csid operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csid interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- qcom,csi-vdd-voltage : should specify voltage level
+    for mipi csi in uV.
+- qcom,mipi-csi-vdd-supply : should contain regulator to be used for
+    this csid core
+- clock-names: name of the clocks required for the device
+- qcom,clock-rates: clock rate in Hz
+	- 0 if appropriate clock is required but doesn't have to apply the rate
+
+Optional properties:
+- qcom,cam-vreg-name : name of the voltage regulators required for the device.
+- gdscr-supply : should contain regulator used for csid clocks.
+- mmagic-supply : should contain mmagic regulator used for mmagic clocks.
+
+Example:
+
+   qcom,csid@fda08000 {
+       cell-index = <0>;
+       compatible = "qcom,csid-v2.0", "qcom,csid";
+       reg = <0xfda08000 0x200>;
+       reg-names = "csid";
+       interrupts = <0 51 0>;
+       interrupt-names = "csiphy";
+       qcom,csi-vdd-voltage = <1800000>;
+       qcom,mipi-csi-vdd-supply = <&pm8941_l12>;
+       clock-names = "camss_top_ahb_clk", "ispif_ahb_clk",
+                "csi_ahb_clk", "csi_src_clk", "csi_clk",
+                "csi_phy_clk", "csi_pix_clk", "csi_rdi_clk";
+       qcom,clock-rates = <0 0 0 200000000 0 0 0 0>;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
new file mode 100644
index 0000000..f951b21
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -0,0 +1,199 @@
+* Qualcomm Technologies, Inc. MSM EEPROM
+
+EEPROM is an one time programmed(OTP) device that stores the calibration data
+use for camera sensor. It may either be integrated in the sensor module or in
+the sensor itself. As a result, the power, clock and GPIOs may be the same as
+the camera sensor. The following describes the page block map, power supply,
+clock, GPIO and power on sequence properties of the EEPROM device.
+
+Required properties if probe happens from camera daemon:
+- cell-index: eeprom hardware core index
+- compatible :
+    - "qcom,eeprom"
+- reg : offset of eeprom device registers.
+- qcom,cci-master : should specify the cci core index that eeprom use.
+- cam_vio-supply : should contain regulator to be used for the IO vdd.
+- qcom,cam-vreg-name : should specify the regulator name to be used for
+    this eeprom.
+- qcom,cam-vreg-type : should specify the regulator type to be used for
+    this eeprom.
+- qcom,cam-vreg-min-voltage : should specify minimum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-max-voltage : should specify maximum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA.
+- qcom,gpio-no-mux : should specify the gpio mux type.
+- gpios : should specify the gpios to be used for the eeprom.
+- qcom,gpio-reset : should specify the reset gpio index.
+- qcom,gpio-standby : should specify the standby gpio index.
+- qcom,gpio-req-tbl-num : should specify the gpio table index.
+- qcom,gpio-req-tbl-flags : should specify the gpio functions.
+- qcom,gpio-req-tbl-label : should specify the gpio labels.
+- qcom,cam-power-seq-type : should specify the power on sequence types.
+- qcom,cam-power-seq-val : should specify the power on sequence values.
+- qcom,cam-power-seq-cfg-val : should specify the power on sequence config
+    values.
+- qcom,cam-power-seq-delay : should specify the power on sequence delay
+    time in ms.
+
+Optional properties:
+- cam_vdig-supply : should contain regulator to be used for the digital vdd.
+
+
+
+Example:
+
+    eeprom0: qcom,eeprom@60 {
+        cell-index = <0>;
+        reg = <0x60 0x0>;
+        compatible = "qcom,eeprom";
+        qcom,cci-master = <0>;
+        cam_vdig-supply = <&pm8226_l5>;
+        cam_vio-supply = <&pm8226_lvs1>;
+        qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+        qcom,cam-vreg-type = <0 1>;
+        qcom,cam-vreg-min-voltage = <1200000 0>;
+        qcom,cam-vreg-max-voltage = <1200000 0>;
+        qcom,cam-vreg-op-mode = <200000 0>;
+        qcom,gpio-no-mux = <0>;
+        gpios = <&msmgpio 26 0>,
+            <&msmgpio 37 0>,
+            <&msmgpio 36 0>;
+        qcom,gpio-reset = <1>;
+        qcom,gpio-standby = <2>;
+        qcom,gpio-req-tbl-num = <0 1 2>;
+        qcom,gpio-req-tbl-flags = <1 0 0>;
+        qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+            "CAM_RESET1",
+            "CAM_STANDBY";
+        qcom,cam-power-seq-type = "sensor_vreg",
+            "sensor_vreg", "sensor_clk",
+            "sensor_gpio", "sensor_gpio";
+        qcom,cam-power-seq-val = "cam_vdig",
+            "cam_vio", "sensor_cam_mclk",
+            "sensor_gpio_reset",
+            "sensor_gpio_standby";
+        qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+        qcom,cam-power-seq-delay = <1 1 5 5 10>;
+    };
+
+
+
+Required properties if eeprom probe is kernel probe:
+- cell-index: eeprom hardware core index
+- compatible :
+    - "qcom,eeprom"
+- reg : offset of eeprom device registers.
+- qcom,eeprom-name : should specify relevant names of the eeprom module
+    library.
+- qcom,slave-addr : should specify the slave address of the eeprom.
+- qcom,cci-master : should specify the cci core index that eeprom use.
+- qcom,num-blocks : should specify the total block number that eeprom contains,
+    every block should contains page poll and mem.
+- qcom,page%d : number %d page size, start address, address type, data,
+    data type, delay in ms. size 0 stand for non-paged.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,poll%d : number %d poll size, poll reg address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,mem%d : number %d memory size, start address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- cam_vio-supply : should contain regulator to be used for the IO vdd.
+- qcom,cam-vreg-name : should specify the regulator name to be used for
+    this eeprom.
+- qcom,cam-vreg-type : should specify the regulator type to be used for
+    this eeprom.
+- qcom,cam-vreg-min-voltage : should specify minimum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-max-voltage : should specify maximum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA.
+- pinctrl-names : should specify the pin control groups followed by
+    the definition of each group
+- qcom,gpio-no-mux : should specify the gpio mux type.
+- gpios : should specify the gpios to be used for the eeprom.
+- qcom,gpio-reset : should specify the reset gpio index.
+- qcom,gpio-standby : should specify the standby gpio index.
+- qcom,gpio-req-tbl-num : should specify the gpio table index.
+- qcom,gpio-req-tbl-flags : should specify the gpio functions.
+- qcom,gpio-req-tbl-label : should specify the gpio labels.
+- qcom,cam-power-seq-type : should specify the power on sequence types.
+- qcom,cam-power-seq-val : should specify the power on sequence values.
+- qcom,cam-power-seq-cfg-val : should specify the power on sequence config
+    values.
+- qcom,cam-power-seq-delay : should specify the power on sequence delay
+    time in ms.
+
+Optional properties:
+- qcom,pageen%d : number %d page enable reg size, start address, address type,
+    data, data type, delay in ms. size 0 stand for not used.
+- cam_vdig-supply : should contain regulator to be used for the digital vdd.
+- qcom,saddr%d : property should specify the slave address for block (%d).
+- qcom,i2c-freq-mode : property should specify the I2C speed mode.
+
+Optional properties -EEPROM Camera Multimodule
+- qcom,cmm-data-support - Camera MultiModule data capability flag.
+- qcom,cmm-data-compressed - Camera MultiModule data compression flag.
+- qcom,cmm-data-offset - Camera MultiModule data start offset.
+- qcom,cmm-data-size - Camera MultiModule data size.
+
+
+
+Example:
+
+    eeprom0: qcom,eeprom@60 {
+        cell-index = <0>;
+        reg = <0x60 0x0>;
+        qcom,eeprom-name = "msm_eeprom";
+        compatible = "qcom,eeprom";
+        qcom,slave-addr = <0x60>;
+        qcom,cci-master = <0>;
+        qcom,num-blocks = <2>;
+        qcom,page0 = <1 0x0100 2 0x01 1 1>;
+        qcom,poll0 = <0 0x0 2 0 1 1>;
+        qcom,mem0 = <0 0x0 2 0 1 0>;
+        qcom,page1 = <1 0x0200 2 0x8 1 1>;
+        qcom,pageen1 = <1 0x0202 2 0x01 1 10>;
+        qcom,poll1 = <0 0x0 2 0 1 1>;
+        qcom,mem1 = <32 0x3000 2 0 1 0>;
+        qcom,saddr1 = <0x62>;
+
+		qcom,cmm-data-support;
+		qcom,cmm-data-compressed;
+		qcom,cmm-data-offset = <0>;
+		qcom,cmm-data-size = <0>;
+
+        cam_vdig-supply = <&pm8226_l5>;
+        cam_vio-supply = <&pm8226_lvs1>;
+        qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+        qcom,cam-vreg-type = <0 1>;
+        qcom,cam-vreg-min-voltage = <1200000 0>;
+        qcom,cam-vreg-max-voltage = <1200000 0>;
+        qcom,cam-vreg-op-mode = <200000 0>;
+        qcom,gpio-no-mux = <0>;
+        gpios = <&msmgpio 26 0>,
+            <&msmgpio 37 0>,
+            <&msmgpio 36 0>;
+        qcom,gpio-reset = <1>;
+        qcom,gpio-standby = <2>;
+        qcom,gpio-req-tbl-num = <0 1 2>;
+        qcom,gpio-req-tbl-flags = <1 0 0>;
+        qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+            "CAM_RESET1",
+            "CAM_STANDBY";
+        qcom,cam-power-seq-type = "sensor_vreg",
+            "sensor_vreg", "sensor_clk",
+            "sensor_gpio", "sensor_gpio";
+        qcom,cam-power-seq-val = "cam_vdig",
+            "cam_vio", "sensor_cam_mclk",
+            "sensor_gpio_reset",
+            "sensor_gpio_standby";
+        qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+        qcom,cam-power-seq-delay = <1 1 5 5 10>;
+    };
+
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-fd.txt b/Documentation/devicetree/bindings/media/video/msm-fd.txt
new file mode 100644
index 0000000..0563599
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-fd.txt
@@ -0,0 +1,99 @@
+* Qualcomm Technologies, Inc. MSM FD
+
+Face detection hardware block.
+The Face Detection Hardware Block will offload processing
+on the host and also reduce power consumption.
+Supports:
+Front and back camera face detection concurrently.
+Sizes: QVGA, VGA, WQVGA, WVGA at 20 pix minimum face size.
+
+Required properties:
+
+- compatible:
+    - "qcom,face-detection"
+- reg: offset and length of the register set for the device.
+- reg-names: should specify relevant names to each reg property defined.
+    - "fd_core" - FD CORE hardware register set.
+    - "fd_misc" - FD MISC hardware register set.
+    - "fd_vbif" - FD VBIF hardware register set.
+- interrupts: should contain the fd interrupts. From fd cores with
+  revisions 0x10010000 and higher, power collapse sequence is required.
+  Face detection misc irq is needed to perform power collapse.
+- interrupt-names: should specify relevant names to each interrupts
+  property defined.
+- vdd-supply: phandle to GDSC regulator controlling face detection hw.
+- clocks: list of entries each of which contains:
+    - phandle to the clock controller.
+    - macro containing clock's name in hardware.
+- clock-names: should specify relevant names to each clocks
+  property defined.
+
+Optional properties:
+
+- clock-rates: should specify clock rates in Hz to each clocks
+  property defined.
+  If we want to have different operating clock frequencies we can define
+  rate levels. They should be defined in incremental order.
+- qcom,bus-bandwidth-vectors: Specifies instant and average bus bandwidth
+  vectors per clock rate.
+  Each of entries contains:
+  - ab. Average bus bandwidth (Bps).
+  - ib. Instantaneous bus bandwidth (Bps).
+- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic.
+- camss-vdd-supply: phandle to GDSC regulator controlling camss.
+- qcom,fd-core-reg-settings: relative address offsets and value pairs for
+  FD CORE registers and bit mask.
+  Format: <reg_addr_offset reg_value reg_mask>
+- qcom,fd-misc-reg-settings: relative address offsets and value pairs for
+  FD MISC registers and bit mask.
+  Format: <reg_addr_offset reg_value reg_mask>
+- qcom,fd-vbif-reg-settings: relative address offsets and value pairs for
+  FD VBIF registers and bit mask.
+  Format: <reg_addr_offset reg_value reg_mask>
+
+Example:
+
+    qcom,fd@fd878000 {
+        compatible = "qcom,face-detection";
+        reg = <0xfd878000 0x800>,
+              <0xfd87c000 0x800>,
+              <0xfd860000 0x1000>;
+        reg-names = "fd_core", "fd_misc", "fd_vbif";
+        interrupts = <0 316 0>;
+        interrupt-names = "fd";
+        mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+        camss-vdd-supply = <&gdsc_camss_top>;
+        vdd-supply = <&gdsc_fd>;
+        qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+        clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+                <&clock_gcc  clk_mmssnoc_axi_clk>,
+                <&clock_mmss clk_mmagic_camss_axi_clk>,
+                <&clock_mmss clk_camss_top_ahb_clk>,
+                <&clock_mmss clk_fd_core_clk_src>,
+                <&clock_mmss clk_fd_core_clk>,
+                <&clock_mmss clk_fd_core_uar_clk>,
+                <&clock_mmss clk_fd_ahb_clk>,
+                <&clock_mmss clk_smmu_cpp_axi_clk>,
+                <&clock_mmss clk_camss_ahb_clk>,
+                <&clock_mmss clk_camss_cpp_axi_clk>,
+                <&clock_mmss clk_camss_cpp_vbif_ahb_clk>,
+                <&clock_mmss clk_smmu_cpp_ahb_clk>;
+        clock-names = "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk" ,
+                        "mmagic_camss_axi_clk", "camss_top_ahb_clk",
+                        "fd_core_clk_src", "fd_core_clk",
+                        "fd_core_uar_clk", "fd_ahb_clk",
+                        "smmu_cpp_axi_clk", "camss_ahb_clk",
+                        "camss_cpp_axi_clk", "cpp_vbif_ahb_clk",
+                         "smmu_cpp_ahb_clk";
+        clock-rates = <0 0 0 0 400000000 400000000 400000000 80000000 0 0 0 0 0>;
+        qcom,bus-bandwidth-vectors = <13000000 13000000>,
+            <45000000 45000000>,
+            <90000000 90000000>;
+        qcom,fd-vbif-reg-settings = <0x20 0x10000000 0x30000000>,
+            <0x24 0x10000000 0x30000000>,
+            <0x28 0x10000000 0x30000000>,
+            <0x2c 0x10000000 0x30000000>;
+        qcom,fd-misc-reg-settings = <0x20 0x2 0x3>,
+            <0x24 0x2 0x3>;
+        qcom,fd-core-reg-settings = <0x8 0x20 0xffffffff>;
+    };
diff --git a/Documentation/devicetree/bindings/media/video/msm-ir-cut.txt b/Documentation/devicetree/bindings/media/video/msm-ir-cut.txt
new file mode 100644
index 0000000..96cb28d
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-ir-cut.txt
@@ -0,0 +1,26 @@
+* QTI MSM IR CUT
+
+Required properties:
+- cell-index : ir cut filter hardware core index
+- compatible :
+    - "qcom,ir-cut"
+
+Optional properties:
+- gpios : should specify the gpios to be used for the ir cut filter.
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to ir cut filter
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- label : should contain unique ir cut filter name
+Example:
+
+qcom,ir-cut@60 {
+		cell-index = <0>;
+		compatible = "qcom,ir-cut";
+		label = "led-ir-label";
+		gpios = <&tlmm 60 0>;
+		qcom,gpio-req-tbl-num = <0>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "LED_IR_EN";
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-ir-led.txt b/Documentation/devicetree/bindings/media/video/msm-ir-led.txt
new file mode 100644
index 0000000..7e66fa0
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-ir-led.txt
@@ -0,0 +1,26 @@
+* QTI MSM IR LED
+
+Required properties:
+- cell-index : ir led hardware core index
+- compatible :
+    - "qcom,ir-led"
+
+Optional properties:
+- gpios : should specify the gpios to be used for the ir led.
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to ir led
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- label : should contain unique ir led name
+Example:
+
+qcom,ir-led {
+		cell-index = <0>;
+		compatible = "qcom,ir-led";
+		label = "led-ir-label";
+		gpios = <&tlmm 60 0>;
+		qcom,gpio-req-tbl-num = <0>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "LED_IR_EN";
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
new file mode 100644
index 0000000..fbcb74d
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
@@ -0,0 +1,18 @@
+* Qualcomm Technologies, Inc. MSM IRQ Router
+
+Required properties:
+- cell-index: irq router hardware core index
+- compatible :
+    - "qcom,irqrouter"
+- reg : offset and length of the register set for the device
+    for the irqrouter operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+
+Example:
+
+   qcom,irqrouter@0xfda0c000 {
+       cell-index = <0>;
+       compatible = "qcom,irqrouter";
+       reg = <0xfda00000 0x100>;
+       reg-names = "irqrouter";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-ispif.txt b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
new file mode 100644
index 0000000..d635a4e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
@@ -0,0 +1,159 @@
+* Qualcomm Technologies, Inc. MSM ISPIF
+
+Required properties:
+- cell-index: ispif hardware core index
+- compatible :
+    - "qcom,ispif"
+    - "qcom,ispif-v3.0"
+- reg : offset and length of the register set for the device
+    for the ispif operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the ispif interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- camss-vdd-supply: phandle to GDSC regulator.
+- mmagic-vdd-supply: phandle to mmagic regulator.
+- vfe0-vdd-supply: phandle to vfe0 regulator.
+- vfe1-vdd-supply: phandle to vfe1 regulator.
+- clocks: list of phandles to the clock controller device and coresponding
+  clock names.
+- clock-names: name of the clocks required for the device used by the consumer.
+- qcom,clock-rates: clock rate in Hz.
+- qcom,clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and
+  "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting
+  the rate assuming some other driver has already set it to appropriate rate.
+  "INIT_RATE" clock rate is not queried assuming some other driver has set
+  the clock rate and ispif will set the the clock to this rate.
+  "SET_RATE" clock is enabled and the rate is set to the value specified
+  in the property qcom,clock-rates.
+
+Optional properties:
+- qcom,num-isps: The number of ISPs the ISPIF module is connected to. If not set
+  the default value used is 1
+
+Example:
+
+	qcom,ispif@fda0a000 {
+	cell-index = <0>;
+	compatible = "qcom,ispif";
+	reg = <0xfda0a000 0x300>;
+	reg-names = "ispif";
+	interrupts = <0 55 0>;
+	interrupt-names = "ispif";
+	camss-vdd-supply = <&gdsc_camss_top>;
+	mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+	vfe0-vdd-supply = <&gdsc_vfe0>;
+	vfe1-vdd-supply = <&gdsc_vfe1>;
+	clocks = <&clock_mmss clk_camss_ispif_ahb_clk>,
+		<&clock_mmss clk_csi0_clk_src>,
+		<&clock_mmss clk_camss_csi0_clk>,
+		<&clock_mmss clk_camss_csi0rdi_clk>,
+		<&clock_mmss clk_camss_csi0pix_clk>,
+		<&clock_mmss clk_csi1_clk_src>,
+		<&clock_mmss clk_camss_csi1_clk>,
+		<&clock_mmss clk_camss_csi1rdi_clk>,
+		<&clock_mmss clk_camss_csi1pix_clk>,
+		<&clock_mmss clk_csi2_clk_src>,
+		<&clock_mmss clk_camss_csi2_clk>,
+		<&clock_mmss clk_camss_csi2rdi_clk>,
+		<&clock_mmss clk_camss_csi2pix_clk>,
+		<&clock_mmss clk_csi3_clk_src>,
+		<&clock_mmss clk_camss_csi3_clk>,
+		<&clock_mmss clk_camss_csi3rdi_clk>,
+		<&clock_mmss clk_camss_csi3pix_clk>,
+		<&clock_mmss clk_vfe0_clk_src>,
+		<&clock_mmss clk_camss_vfe0_clk>,
+		<&clock_mmss clk_camss_csi_vfe0_clk>,
+		<&clock_mmss clk_vfe1_clk_src>,
+		<&clock_mmss clk_camss_vfe1_clk>,
+		<&clock_mmss clk_camss_csi_vfe1_clk>;
+	clock-names = "ispif_ahb_clk",
+		"csi0_src_clk", "csi0_clk",
+		"csi0_pix_clk", "csi0_rdi_clk",
+		"csi1_src_clk", "csi1_clk",
+		"csi1_pix_clk", "csi1_rdi_clk",
+		"csi2_src_clk", "csi2_clk",
+		"csi2_pix_clk", "csi2_rdi_clk",
+		"csi3_src_clk", "csi3_clk",
+		"csi3_pix_clk", "csi3_rdi_clk",
+		"vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk",
+		"vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk";
+	qcom,clock-rates = <0
+		200000000 0 0 0
+		200000000 0 0 0
+		200000000 0 0 0
+		200000000 0 0 0
+		0 0 0
+		0 0 0>;
+	qcom,clock-control = "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"INIT_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"INIT_RATE", "NO_SET_RATE", "NO_SET_RATE";
+
+	};
+
+or
+
+	qcom,ispif@fda0a000 {
+	cell-index = <0>;
+	compatible = "qcom,ispif-v3.0", "qcom,ispif";
+	reg = <0xfda0a000 0x300>;
+	reg-names = "ispif";
+	interrupts = <0 55 0>;
+	interrupt-names = "ispif";
+	qcom,num-isps = <2>
+	vdd-supply = <&gdsc_camss_top>;
+	clocks = <&clock_mmss clk_camss_ispif_ahb_clk>,
+		<&clock_mmss clk_csi0_clk_src>,
+		<&clock_mmss clk_camss_csi0_clk>,
+		<&clock_mmss clk_camss_csi0rdi_clk>,
+		<&clock_mmss clk_camss_csi0pix_clk>,
+		<&clock_mmss clk_csi1_clk_src>,
+		<&clock_mmss clk_camss_csi1_clk>,
+		<&clock_mmss clk_camss_csi1rdi_clk>,
+		<&clock_mmss clk_camss_csi1pix_clk>,
+		<&clock_mmss clk_csi2_clk_src>,
+		<&clock_mmss clk_camss_csi2_clk>,
+		<&clock_mmss clk_camss_csi2rdi_clk>,
+		<&clock_mmss clk_camss_csi2pix_clk>,
+		<&clock_mmss clk_csi3_clk_src>,
+		<&clock_mmss clk_camss_csi3_clk>,
+		<&clock_mmss clk_camss_csi3rdi_clk>,
+		<&clock_mmss clk_camss_csi3pix_clk>,
+		<&clock_mmss clk_vfe0_clk_src>,
+		<&clock_mmss clk_camss_vfe0_clk>,
+		<&clock_mmss clk_camss_csi_vfe0_clk>,
+		<&clock_mmss clk_vfe1_clk_src>,
+		<&clock_mmss clk_camss_vfe1_clk>,
+		<&clock_mmss clk_camss_csi_vfe1_clk>;
+	clock-names = "ispif_ahb_clk",
+		"csi0_src_clk", "csi0_clk",
+		"csi0_pix_clk", "csi0_rdi_clk",
+		"csi1_src_clk", "csi1_clk",
+		"csi1_pix_clk", "csi1_rdi_clk",
+		"csi2_src_clk", "csi2_clk",
+		"csi2_pix_clk", "csi2_rdi_clk",
+		"csi3_src_clk", "csi3_clk",
+		"csi3_pix_clk", "csi3_rdi_clk",
+		"vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk",
+		"vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk";
+	qcom,clock-rates = <0
+		200000000 0 0 0
+		200000000 0 0 0
+		200000000 0 0 0
+		200000000 0 0 0
+		0 0 0
+		0 0 0>;
+	qcom,clock-control = "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"INIT_RATE", "NO_SET_RATE", "NO_SET_RATE",
+		"INIT_RATE", "NO_SET_RATE", "NO_SET_RATE";
+
+	};
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-jpeg.txt b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
new file mode 100644
index 0000000..5aed7c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
@@ -0,0 +1,140 @@
+* Qualcomm Technologies, Inc. MSM JPEG
+
+Required properties:
+- cell-index: jpeg hardware core index
+- compatible :
+    - "qcom,jpeg"
+    - "qcom,jpeg_dma"
+- reg : offset and length of the register set of jpeg device and vbif device
+    for the jpeg operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the jpeg interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- clock-names : names of clocks required for the device.
+- clocks : clocks required for the device.
+- qcom, clock-rates: rates of the required clocks.
+- vdd-supply: phandle to GDSC regulator controlling JPEG core.
+- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic.
+- camss-vdd-supply: phandle to GDSC regulator controlling camss.
+
+Optional properties:
+- qcom,vbif-reg-settings: relative address offsets and value pairs for VBIF registers.
+- qcom,qos-reg-settings: relative address offsets and value pairs for QoS registers.
+- qcom,prefetch-reg-settings: relative address offsets and value pairs for
+  MMU prefetch registers.
+
+Example:
+
+	qcom,jpeg@a1c000 {
+		cell-index = <0>;
+		compatible = "qcom,jpeg";
+		reg = <0xa1c000 0x4000>,
+			<0xa60000 0x3000>;
+		reg-names = "jpeg";
+		interrupts = <0 316 0>;
+		interrupt-names = "jpeg";
+                mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+                camss-vdd-supply = <&gdsc_camss_top>;
+                vdd-supply = <&gdsc_jpeg>;
+                qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+		clock-names =  "core_clk", "iface_clk", "bus_clk0",
+			       "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk",
+                               "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk",
+                               "mmagic_camss_axi_clk";
+		clocks = <&clock_mmss clk_camss_jpeg0_clk>,
+			<&clock_mmss clk_camss_jpeg_ahb_clk>,
+			<&clock_mmss clk_camss_jpeg_axi_clk>,
+			<&clock_mmss clk_camss_top_ahb_clk>,
+			<&clock_mmss clk_camss_ahb_clk>,
+			<&clock_mmss clk_smmu_jpeg_axi_clk>,
+                        <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+                        <&clock_gcc  clk_mmssnoc_axi_clk>,
+                        <&clock_mmss clk_mmagic_camss_axi_clk>;
+		qcom,clock-rates = <320000000 0 0 0 0 0 0 0 0>;
+		qcom,vbif-reg-settings = <0x4 0x1>,
+			<0xb0 0x00100010>,
+			<0xc0 0x10001000>;
+		qcom,qos-reg-settings = <0x28 0x00000008>;
+		qcom,prefetch-reg-settings = <0x30c 0x1111>,
+			<0x318 0x31>,
+			<0x324 0x31>,
+			<0x330 0x31>,
+			<0x33c 0x0>;
+		status = "ok";
+	};
+
+	qcom,jpeg@a24000 {
+		cell-index = <2>;
+		compatible = "qcom,jpeg";
+		reg = <0xa24000 0x4000>,
+			<0xa60000 0x3000>;
+		reg-names = "jpeg";
+		interrupts = <0 318 0>;
+		interrupt-names = "jpeg";
+                mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+                camss-vdd-supply = <&gdsc_camss_top>;
+                vdd-supply = <&gdsc_jpeg>;
+                qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+		clock-names =  "core_clk", "iface_clk", "bus_clk0",
+                               "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk",
+                               "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk",
+                               "mmagic_camss_axi_clk";
+		clocks = <&clock_mmss clk_camss_jpeg2_clk>,
+		       <&clock_mmss clk_camss_jpeg_ahb_clk>,
+		       <&clock_mmss clk_camss_jpeg_axi_clk>,
+		       <&clock_mmss clk_camss_top_ahb_clk>,
+		       <&clock_mmss clk_camss_ahb_clk>,
+		       <&clock_mmss clk_smmu_jpeg_axi_clk>,
+                       <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+                       <&clock_gcc  clk_mmssnoc_axi_clk>,
+                       <&clock_mmss clk_mmagic_camss_axi_clk>;
+		qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>;
+		qcom,vbif-reg-settings = <0x4 0x1>,
+			<0xb0 0x00100010>,
+			<0xc0 0x10001000>;
+		qcom,qos-reg-settings = <0x28 0x00000008>;
+		qcom,prefetch-reg-settings = <0x30c 0x1111>,
+			<0x318 0x0>,
+			<0x324 0x31>,
+			<0x330 0x31>,
+			<0x33c 0x31>;
+		status = "ok";
+	};
+
+	qcom,jpeg@aa0000 {
+		cell-index = <3>;
+		compatible = "qcom,jpeg_dma";
+		reg = <0xaa0000 0x4000>,
+			<0xa60000 0x3000>;
+		reg-names = "jpeg";
+		interrupts = <0 304 0>;
+		interrupt-names = "jpeg";
+                mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+                camss-vdd-supply = <&gdsc_camss_top>;
+                vdd-supply = <&gdsc_jpeg>;
+                qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+		clock-names =  "core_clk", "iface_clk", "bus_clk0",
+                               "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk",
+                               "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk",
+                               "mmagic_camss_axi_clk";
+		clocks = <&clock_mmss clk_camss_jpeg_dma_clk>,
+			<&clock_mmss clk_camss_jpeg_ahb_clk>,
+			<&clock_mmss clk_camss_jpeg_axi_clk>,
+			<&clock_mmss clk_camss_top_ahb_clk>,
+			<&clock_mmss clk_camss_ahb_clk>,
+			<&clock_mmss clk_smmu_jpeg_axi_clk>,
+                        <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+                        <&clock_gcc  clk_mmssnoc_axi_clk>,
+                        <&clock_mmss clk_mmagic_camss_axi_clk>;
+		qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>;
+		qcom,vbif-reg-settings = <0x4 0x1>,
+			<0xb0 0x00100010>,
+			<0xc0 0x10001000>;
+		qcom,qos-reg-settings = <0x28 0x00000008>;
+		qcom,prefetch-reg-settings = <0x18c 0x11>,
+			<0x1a0 0x31>,
+			<0x1b0 0x31>;
+		status = "ok";
+	};
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt b/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt
new file mode 100644
index 0000000..a1d6042
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-jpegdma.txt
@@ -0,0 +1,74 @@
+* Qualcomm Technologies, Inc. MSM JPEG DMA
+
+Jpeg dma hardware block.
+
+Jpeg dma can replicate and downscale yuv frames.
+Supported formats: Monochrome, NV12 and NV21.
+
+Required properties:
+- compatible : "qcom,jpegdma".
+- reg : offset and length of the register set of jpeg dma device and
+    vbif device for the jpeg dma operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the jpeg interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic.
+- camss-vdd-supply: phandle to GDSC regulator controlling camss.
+- clock-names : names of clocks required for the device.
+- clocks : clocks required for the device.
+- qcom,clock-rates: should specify clock rates in Hz to each clocks
+    property defined.
+- qcom,max-ds-factor: should specify the max dma downscale factor,
+    supported by HW.
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+	below optional properties:
+	- qcom,msm-bus,name
+	- qcom,msm-bus,num-cases
+	- qcom,msm-bus,num-paths
+	- qcom,msm-bus,vectors-KBps
+
+Optional properties:
+- qcom,vbif-reg-settings: relative address offsets and value pairs for VBIF registers.
+- qcom,qos-reg-settings: relative address offsets and value pairs for QoS registers.
+- qcom,prefetch-reg-settings: relative address offsets and value pairs for
+  MMU prefetch registers.
+
+Example:
+	qcom,jpegdma@aa0000 {
+		compatible = "qcom,jpegdma";
+		reg = <0xaa0000 0x4000>,
+			<0xa60000 0x3000>;
+		reg-names = "jpegdma_core", "jpeg_vbif";
+		interrupts = <0 304 0>;
+		interrupt-names = "jpeg";
+		mmagic-vdd-supply = <&gdsc_mmagic_camss>;
+		camss-vdd-supply = <&gdsc_camss_top>;
+		vdd-supply = <&gdsc_jpeg>;
+		qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd";
+		clock-names =  "core_clk", "iface_clk", "bus_clk0",
+				"camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk",
+				"mmss_mmagic_ahb_clk", "mmssnoc_axi_clk",
+				"mmagic_camss_axi_clk";
+		clocks = <&clock_mmss clk_camss_jpeg_dma_clk>,
+			<&clock_mmss clk_camss_jpeg_ahb_clk>,
+			<&clock_mmss clk_camss_jpeg_axi_clk>,
+			<&clock_mmss clk_camss_top_ahb_clk>,
+			<&clock_mmss clk_camss_ahb_clk>,
+			<&clock_mmss clk_smmu_jpeg_axi_clk>,
+			<&clock_mmss clk_mmss_mmagic_ahb_clk>,
+			<&clock_gcc  clk_mmssnoc_axi_clk>,
+			<&clock_mmss clk_mmagic_camss_axi_clk>;
+		qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>,
+		qcom,vbif-reg-settings = <0x4 0x1>;
+		qcom,prefetch-reg-settings = <0x18c 0x11>,
+			<0x1a0 0x31>,
+			<0x1b0 0x31>;
+		qcom,msm-bus,name = "msm_camera_jpeg_dma";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <62 512 0 0>,
+			<62 512 666675 666675>;
+		qcom,max-ds-factor = <128>;
+		status = "ok";
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
new file mode 100644
index 0000000..aaf1344
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -0,0 +1,208 @@
+* Qualcomm Technologies, Inc. MSM VFE
+
+Required properties for parent node:
+- compatible :
+    - "qcom,vfe"
+- #address-cells : Number of address related values in the reg field
+- #size-cells : Number of size related values in the reg field
+- ranges: How the register offsets for child translate to parent.
+
+Required properties for child node:
+- cell-index: vfe hardware core index
+- compatible :
+    - "qcom,vfe32"
+    - "qcom,vfe40"
+    - "qcom,vfe44"
+    - "qcom,vfe46"
+    - "qcom,vfe47"
+    - "qcom,vfe48"
+- reg : offset and length of the register set for the device
+    for the vfe operating in compatible mode. For parent node, add union of
+    all registers for both vfe.
+- reg-names : should specify relevant names to each reg property defined.
+    Only needed for child node.
+    - "vfe" - Required.
+    - "vfe_vbif" - Optional for "vfe32". Required for "vfe40".
+    - "vfe_fuse" - Optional.
+- interrupts : should contain the vfe interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+    - "vfe" - Required.
+- vdd-supply: phandle to GDSC regulator controlling VFE core.
+- qos-entries: number of QoS registers to program
+- qos-regs: relative address offsets of QoS registers
+- qos-settings: QoS values to be written to QoS registers
+- vbif-entries - number of VBIF registers to program (optional)
+- vbif-regs: relative address offsets of VBIF registers (optional)
+- vbif-settings: VBIF values to be written to VBIF registers (optional)
+- ds-entries: number danger/safe registers to program (optional)
+- ds-regs: relative address offsets of danger/safe registers (optional)
+- ds-settings: danger/safe values to be written to registers (optional)
+  NOTE: For all qos*, vbif*, ds* parameters, same SoC can have different
+  hardware versions with different entries/registers/settings. They can be
+  specified by adding version to the string e.g. qos-v2-settings. Also
+  different SoC can have same hardware version and still different QOS, VBIF,
+  and DS parameters. In this case they are exported if separate SoC version
+  specific dts files.
+- max-svs-clk: svs rate of the VFE clock in Hertz.
+- max-nominal-clk: nominal rate of the VFE clock in Hertz.
+- max-turbo-clk: turbo/high rate of the VFE clock in Hertz.
+
+Example:
+
+vfe0: qcom,vfe0@fda10000 {
+	cell-index = <0>;
+	compatible = "qcom,vfe44";
+	reg = <0xfda10000 0x1000>,
+		<0xfda40000 0x200>,
+		<0x7801a4 0x8>;
+	reg-names = "vfe", "vfe_vbif", "vfe_fuse";
+	interrupts = <0 57 0>;
+	interrupt-names = "vfe";
+	vdd-supply = <&gdsc_vfe>;
+	qos-entries = <8>;
+	qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8
+		0x2dc 0x2e0>;
+	qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa
+		0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa
+		0xaaaaaaaa 0x0002aaaa>;
+	qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0x0001aaa9>;
+	qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0x0001aaa9>;
+	vbif-entries = <17>;
+	vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0
+		0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160
+		0x164>;
+	vbif-settings = <0x1 0x01010101 0x01010101 0x10010110
+		0x10101010 0x10101010 0x10101010 0x00001010
+		0x00001010 0x00000707 0x00000707 0x00000030
+		0x00000fff 0x0fff0fff 0x00000001 0x22222222
+		0x00002222>;
+	vbif-v2-entries = <16>;
+	vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0
+		0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160
+		0x164>;
+	vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010
+		0x10101010 0x10101010 0x10101010 0x00000010
+		0x00000010 0x00000707 0x00000010 0x00000fff
+		0x0fff0fff 0x00000003 0x22222222 0x00002222>;
+	ds-entries = <17>;
+	ds-regs = <0x988 0x98c 0x990 0x994 0x998
+		0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0
+		0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>;
+	ds-settings = <0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x00000103>;
+	max-clk-svs = <300000000>;
+	max-clk-nominal = <465000000>;
+	max-clk-turbo = <600000000>;
+};
+
+vfe1: qcom,vfe1@fda14000 {
+	cell-index = <1>;
+	compatible = "qcom,vfe44";
+	reg = <0xfda14000 0x1000>,
+		<0xfda40000 0x200>,
+		<0x7801a4 0x8>;
+	reg-names = "vfe", "vfe_vbif", "vfe_fuse";
+	interrupts = <0 58 0>;
+	interrupt-names = "vfe";
+	vdd-supply = <&gdsc_vfe>;
+	qos-entries = <8>;
+	qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8
+		0x2dc 0x2e0>;
+	qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa
+		0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa
+		0xaaaaaaaa 0x0002aaaa>;
+	qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0x0001aaa9>;
+	qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9
+		0xaaa9aaa9 0x0001aaa9>;
+	vbif-entries = <17>;
+	vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0
+		0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160
+		0x164>;
+	vbif-settings = <0x1 0x01010101 0x01010101 0x10010110
+		0x10101010 0x10101010 0x10101010 0x00001010
+		0x00001010 0x00000707 0x00000707 0x00000030
+		0x00000fff 0x0fff0fff 0x00000001 0x22222222
+		0x00002222>;
+	vbif-v2-entries = <16>;
+	vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0
+		0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160
+		0x164>;
+	vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010
+		0x10101010 0x10101010 0x10101010 0x00000010
+		0x00000010 0x00000707 0x00000010 0x00000fff
+		0x0fff0fff 0x00000003 0x22222222 0x00002222>;
+	ds-entries = <17>;
+	ds-regs = <0x988 0x98c 0x990 0x994 0x998
+		0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0
+		0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>;
+	ds-settings = <0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x44441111 0x44441111
+		0x44441111 0x00000103>;
+	max-clk-svs = <300000000>;
+	max-clk-nominal = <465000000>;
+	max-clk-turbo = <600000000>;
+};
+
+qcom,vfe {
+	compatible = "qcom,vfe";
+	num_child = <2>;
+};
+
+In version specific file one needs to move only entries that differ between
+SoC versions with same VFE HW version:
+
+	&vfe0 {
+		qos-entries = <8>;
+		qos-regs = <0x378 0x37C 0x380 0x384 0x388 0x38C
+				0x390 0x394>;
+		qos-settings = <0xAAA9AAA9
+			0xAAA9AAA9
+			0xAAA9AAA9
+			0xAAA9AAA9
+			0xAAA9AAA9
+			0xAAA9AAA9
+			0xAAA9AAA9
+			0x0001AAA9>;
+		vbif-entries = <1>;
+		vbif-regs = <0x124>;
+		vbif-settings = <0x3>;
+		ds-entries = <17>;
+		ds-regs = <0xBD8 0xBDC 0xBE0 0xBE4 0xBE8
+			0xBEC 0xBF0 0xBF4 0xBF8 0xBFC 0xC00
+			0xC04 0xC08 0xC0C 0xC10 0xC14 0xC18>;
+		ds-settings = <0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x44441111
+			0x00000103>;
+		max-clk-svs = <300000000>;
+		max-clk-nominal = <465000000>;
+		max-clk-turbo = <600000000>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt b/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt
new file mode 100644
index 0000000..5b5323e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt
@@ -0,0 +1,42 @@
+* Qualcomm Technologies Inc MSM VIDC VMEM
+
+Required properties:
+- compatible : "qcom,msm-vmem"
+- interrupts : Contains the interrupt that maps to the VMEM module
+- reg : A set of 2 start address and size pairs that describe the hardware
+register address space and mappable memory address space.
+- reg-names : Strings that describe the pairs in "reg".  The register address
+space should be called "reg-base" and the memory space should be called "mem-base".
+- clocks : A set of clocks that correspond to the AHB and MAXI clocks that the
+hardware uses.
+- clock-names : A string that describes the "clocks" property.  The AHB clock
+should be named "ahb" and the MAXI clock should be named "maxi".
+- qcom,bank-size : The size of each memory bank, in bytes.
+- vdd-supply: phandle to a regulator that is considered to be the footswitch for vmem.
+- qcom,msm-bus,(name|num-cases,num-paths,vectors-KBps) - Bus to be voted for prior to
+  issuing any IO transactions to vmem.  Refer to Documentation/devicetree/bindings/arm/\
+  msm/msm_bus_adhoc.txt for further details.
+
+Example:
+
+qcom,vmem@880000 {
+	compatible = "qcom,msm-vmem";
+	interrupts = <0 429 0>;
+	reg = <0x880000 0x800>,
+	    <0x6800000 0x100000>;
+	reg-names = "reg-base", "mem-base";
+
+	vdd-supply = <&gdsc_mmagic_video>;
+	clocks = <&clock_mmss clk_vmem_ahb_clk>,
+	       <&clock_mmss clk_vmem_maxi_clk>;
+	clock-names = "ahb", "maxi";
+
+	qcom,bank-size = <131072>;
+
+	qcom,msm-bus,name = "vmem";
+	qcom,msm-bus,num-cases = <2>;
+	qcom,msm-bus,num-paths = <1>;
+	qcom,msm-bus,vectors-KBps =
+	        <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_VMEM_CFG   0   0>,
+	        <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_VMEM_CFG 500 800>;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vpu.txt b/Documentation/devicetree/bindings/media/video/msm-vpu.txt
new file mode 100644
index 0000000..6aea66b
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vpu.txt
@@ -0,0 +1,60 @@
+* Qualcomm Technologies, Inc. MSM VPU
+
+VPU (Video Processing Unit) applies high quality video post-processing
+functions like noise reduction, deinterlacing, scaling, etc in real-time
+on streaming video.
+
+
+Required properties:
+- compatible:
+    - "qcom,vpu"
+- reg: Specify offset and length of the device register sets.
+- reg-names: Names corresponding to the defined register sets.
+    - "vpu_csr": CSR registers
+    - "vpu_smem": Shared memory
+    - "vpu_vbif": VBIF registers (optional)
+- interrupts: Specify the vpu interrupts.
+- interrupt-names: Names corresponding to the defined interrupts list.
+    - "vpu_wdog": Watchdog interrupt
+    - "vpu_hfi": Firmware to Host interrupt
+- clock-names: Array of clocks that the driver requires for the device.
+  The names here correspond to the clock names used in clk_get(<name>).
+- qcom,bus-load-vector-tbl: Vectors of <load, ab, ib>. The (ab,ib) pairs are
+  ddr bus bandwidths to be requested at corresponding video processing load.
+  Vectors should be in ascending order of load, and their number is variable.
+- vdd-supply: regulator that supplies the vpu.
+
+Optional properties:
+- qcom,enabled-iommu-maps: List of IOMMU maps to be enabled, defined by name.
+  If this property is not defined or invalid, then device assumes contiguous
+  buffers. Valid iommu names are:
+    - "vpu_nonsecure": IOMMU for accessing non-secure video buffers.
+    - "vpu_secure":    IOMMU for accessing secure video buffers.
+    - "vpu_firmware":  IOMMU for loading firmware image.
+- qcom,vbif-reg-presets: List of offset-value pairs for VBIF registers to be
+  programmed. The offsets are from the base register specified in 'vpu_vbif'.
+  This is used to program default register values for QoS settings, etc.
+
+Example:
+	qcom,vpu@fdc00000 {
+		compatible = "qcom,vpu";
+		reg = <0xfdc00000 0xff000>,
+			<0xbfe00000 0x100000>;
+		reg-names = "vpu_csr", "vpu_smem";
+		interrupts = <0 44 0>, <0 45 0>;
+		interrupt-names = "vpu_wdog", "vpu_hfi";
+		clock-names = "core_clk", "bus_clock", "iface_clk";
+		qcom,maple-clk-load-freq-tbl = <100000 50000000>,
+			<500000 400000000>;
+		qcom,vdp-clk-load-freq-tbl = <200000 100000000>,
+			<400000 320000000>;
+		qcom,bus-clk-load-freq-tbl = <100000 40000000>,
+			<200000 80000000>;
+		qcom,bus-load-vector-tbl = <0 0 0>,
+			<489600 536000 1600000>,
+			<979200 2024000 1600000>;
+		qcom,enabled-iommu-maps = "vpu_nonsecure", "vpu_secure";
+		qcom,vbif-reg-presets = <0xb0138 0x43ff>,
+			<0xb0178 0xff12350e>;
+		vdd-supply = <&gdsc_vpu>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
new file mode 100644
index 0000000..cef9cf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
@@ -0,0 +1,9 @@
+OmniVision Image Sensor Device Tree Bindings.
+========================================
+
+Boards with the OmniVision Image Sensor shall have the following properties:
+
+Required root node properties:
+    - compatible:
+    - "ovti,ov8865" : OmniVision OV8865 8 megapixel Image Sensor.
+    - "ovti,ov5648" : OmniVision OV5648 5 megapixel Image Sensor.
diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
index 49d33a3..3017468 100644
--- a/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
+++ b/Documentation/devicetree/bindings/mhi/msm_mhi_dev.txt
@@ -19,6 +19,18 @@
   - qcom,mhi-ep-msi: End point MSI number.
   - qcom,mhi-version: MHI specification version supported by the device.
 
+Optional property:
+  - qcom,use-ipa-software-channel: If property is present use IPA hardware
+		accelerated path for MHI software channel data transfers
+		between host and device.
+  - qcom,mhi-config-iatu: If property is present map the control and data region
+		between host and device using iatu.
+  - qcom,mhi-interrupt: If property is present register for mhi interrupt.
+  - qcom,mhi-local-pa-base: The physical base address on the device used by the
+		MHI device driver to map the control and data region with the
+		MHI driver on the host. This property is required if iatu
+		property qcom,mhi-config-iatu is present.
+
 Example:
 
 	mhi: qcom,msm-mhi-dev {
diff --git a/Documentation/devicetree/bindings/net/qcom-ssdk.txt b/Documentation/devicetree/bindings/net/qcom-ssdk.txt
new file mode 100644
index 0000000..b72215d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/qcom-ssdk.txt
@@ -0,0 +1,35 @@
+
+* Qualcomm Technologies Inc. SSDK Driver.
+
+Add missing DT bindings documentation for 8337 ethernet switch.
+
+Required properties:
+- compatible: Should be "qcom,ess-switch-qca83xx"
+- qcom,switch-access-mode: Should be "mdio" or "local bus"
+- qcom,link-intr-gpio: Link interrupt number used by switch
+- qcom,switch-cpu-bmp: Switch cpu port bitmap
+- qcom,switch-lan-bmp: Switch lan port bitmap
+- qcom,switch-wan-bmp: Switch wan port bitmap
+- qcom,ar8327-initvals: Initial qca83xx configuration
+
+Optional:
+- qcom,link-polling-required: Boolean- Present if using polling for link check
+
+Example:
+
+ess-switch@0 {
+	compatible = "qcom,ess-switch-qca83xx";
+	qcom,switch-access-mode = "mdio";
+	qcom,ar8327-initvals = <
+		0x0000c 0x7600000   /* PAD6_MODE */
+		0x00008 0x0         /* PAD5_MODE */
+		0x000e4 0xaa545     /* MAC_POWER_SEL */
+		0x000e0 0xc74164de  /* SGMII_CTRL */
+		0x0007c 0x4e        /* PORT0_STATUS */
+		0x00094 0x4e        /* PORT6_STATUS */
+	>;
+	qcom,link-intr-gpio = <2>;
+	qcom,switch-cpu-bmp = <0x40>;    /* cpu port bitmap */
+	qcom,switch-lan-bmp = <0x3e>;    /* lan port bitmap */
+	qcom,switch-wan-bmp = <0x0>;     /* wan port bitmap */
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/msm.txt b/Documentation/devicetree/bindings/pinctrl/msm.txt
new file mode 100644
index 0000000..839bd05
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/msm.txt
@@ -0,0 +1,17 @@
+MSM Pinctrl Bindings
+
+Required properties:
+- compatible: "qcom,msm8996-pinctrl"
+              "qcom,mdm9640-pinctrl"
+	      "qcom,msm8909-pinctrl"
+- reg: Should be the base address and length of the TLMM block.
+- interrupts: Should be the parent IRQ of the TLMM block.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Should be two.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells : Should be two.
+                 The first cell is the gpio pin number and the
+                 second cell is used for optional parameters.
+
+Optional properties:
+- qcom,tlmm-emmc-boot-select : Should be the bit-field position to set.
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt
new file mode 100644
index 0000000..d2327a257
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8917-pinctrl.txt
@@ -0,0 +1,204 @@
+Qualcomm Technologies, Inc. MSM8917 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8917 platform.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,msm8917-pinctrl"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+	Usage: required
+	Value type: <string-array>
+	Definition: List of gpio pins affected by the properties specified in
+		    this subnode.
+		    Valid pins are:
+		    gpio0-gpio133,
+		    sdc1_clk,
+		    sdc1_cmd,
+		    sdc1_data,
+		    sdc1_rclk,
+		    sdc2_clk,
+		    sdc2_cmd,
+		    sdc2_data,
+		    qdsd_clk,
+		    qdsd_cmd,
+		    qdsd_data0,
+		    qdsd_data1,
+		    qdsd_data2,
+		    qdsd_data3,
+
+- function:
+	Usage: required
+	Value type: <string>
+	Definition: Specify the alternative function to be configured for the
+		    specified pins. Functions are only valid for gpio pins.
+		    Valid values are:
+        qdss_tracedata_b, blsp_uart1, gpio, blsp_spi1, adsp_ext, blsp_i2c1, prng_rosc,
+        qdss_cti_trig_out_b0, blsp_spi2, blsp_uart2, blsp_uart3, pbs0, pbs1,
+        pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, ldo_update,
+        atest_combodac_to_gpio_native, ldo_en, blsp_i2c2, gcc_gp1_clk_b, pbs2,
+        atest_gpsadc_dtest0_native, blsp_spi3, gcc_gp3_clk_b, blsp_spi4, blsp_uart4,
+        sec_mi2s, pwr_nav_enabled_b, codec_mad, pwr_crypto_enabled_b, blsp_i2c4,
+        blsp_spi5, blsp_uart5, qdss_traceclk_a, atest_bbrx1, m_voc,
+        qdss_cti_trig_in_a0, qdss_cti_trig_in_b0, blsp_i2c6, qdss_traceclk_b,
+        atest_wlan0, atest_wlan1, atest_bbrx0, blsp_i2c5, qdss_tracectl_a,
+        atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6,
+        qdss_tracectl_b, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, cam_mclk,
+        cci_i2c, pwr_modem_enabled_a, cci_timer0, cci_timer1, cam1_standby,
+        pwr_nav_enabled_a, cam1_rst, pwr_crypto_enabled_a, forced_usb,
+        qdss_cti_trig_out_b1, cam2_rst, webcam_standby, cci_async, webcam_rst,
+        ov_ldo, sd_write, accel_int, gcc_gp1_clk_a, alsp_int, gcc_gp2_clk_a,
+        mag_int, gcc_gp3_clk_a, blsp6_spi, fp_int, qdss_cti_trig_in_b1, uim_batt,
+        cam2_standby, uim1_data, uim1_clk, uim1_reset, uim1_present, uim2_data,
+        uim2_clk, uim2_reset, uim2_present, sensor_rst, mipi_dsi0, smb_int,
+        cam0_ldo, us_euro, atest_char3, dbg_out, bimc_dte0, ts_resout, ts_sample,
+        sec_mi2s_mclk_b, pri_mi2s, sdcard_det, atest_char1, ebi_cdc, audio_reset,
+        atest_char0, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, lpass_slimbus,
+        lpass_slimbus0, lpass_slimbus1, codec_int1, codec_int2, wcss_bt,
+        atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1, wcss_wlan0, wcss_wlan,
+        wcss_fm, ext_lpass, cri_trng, cri_trng1, cri_trng0, blsp_spi7, blsp_uart7,
+        pri_mi2s_ws, blsp_i2c7, gcc_tlmm, dmic0_clk, dmic0_data, key_volp,
+        qdss_cti_trig_in_a1, us_emitter, wsa_irq, wsa_io, wsa_reset, blsp_spi8,
+        blsp_uart8, blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, modem_tsync,
+        nav_tsync, nav_pps_in_b, nav_pps, gsm0_tx, atest_char, atest_tsens,
+        bimc_dte1, ssbi_wtr1, fp_gpio, coex_uart, key_snapshot, key_focus, nfc_pwr,
+        blsp8_spi, qdss_cti_trig_out_a0, qdss_cti_trig_out_a1
+
+- bias-disable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull up.
+
+- output-high:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    high.
+		    Not valid for sdc pins.
+
+- output-low:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    low.
+		    Not valid for sdc pins.
+
+- drive-strength:
+	Usage: optional
+	Value type: <u32>
+	Definition: Selects the drive strength for the specified pins, in mA.
+		    Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8917-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt
new file mode 100644
index 0000000..f697704
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt
@@ -0,0 +1,204 @@
+Qualcomm Technologies, Inc. MSM8937 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8937 platform.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,msm8937-pinctrl"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+	Usage: required
+	Value type: <string-array>
+	Definition: List of gpio pins affected by the properties specified in
+		    this subnode.
+		    Valid pins are:
+		    gpio0-gpio133,
+		    sdc1_clk,
+		    sdc1_cmd,
+		    sdc1_data,
+		    sdc1_rclk,
+		    sdc2_clk,
+		    sdc2_cmd,
+		    sdc2_data,
+		    qdsd_clk,
+		    qdsd_cmd,
+		    qdsd_data0,
+		    qdsd_data1,
+		    qdsd_data2,
+		    qdsd_data3,
+
+- function:
+	Usage: required
+	Value type: <string>
+	Definition: Specify the alternative function to be configured for the
+		    specified pins. Functions are only valid for gpio pins.
+		    Valid values are:
+        qdss_tracedata_b, blsp_uart1, gpio, blsp_spi1, adsp_ext, blsp_i2c1, prng_rosc,
+        qdss_cti_trig_out_b0, blsp_spi2, blsp_uart2, blsp_uart3, pbs0, pbs1,
+        pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, ldo_update,
+        atest_combodac_to_gpio_native, ldo_en, blsp_i2c2, gcc_gp1_clk_b, pbs2,
+        atest_gpsadc_dtest0_native, blsp_spi3, gcc_gp3_clk_b, blsp_spi4, blsp_uart4,
+        sec_mi2s, pwr_nav_enabled_b, codec_mad, pwr_crypto_enabled_b, blsp_i2c4,
+        blsp_spi5, blsp_uart5, qdss_traceclk_a, atest_bbrx1, m_voc,
+        qdss_cti_trig_in_a0, qdss_cti_trig_in_b0, blsp_i2c6, qdss_traceclk_b,
+        atest_wlan0, atest_wlan1, atest_bbrx0, blsp_i2c5, qdss_tracectl_a,
+        atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6,
+        qdss_tracectl_b, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, cam_mclk,
+        cci_i2c, pwr_modem_enabled_a, cci_timer0, cci_timer1, cam1_standby,
+        pwr_nav_enabled_a, cam1_rst, pwr_crypto_enabled_a, forced_usb,
+        qdss_cti_trig_out_b1, cam2_rst, webcam_standby, cci_async, webcam_rst,
+        ov_ldo, sd_write, accel_int, gcc_gp1_clk_a, alsp_int, gcc_gp2_clk_a,
+        mag_int, gcc_gp3_clk_a, blsp6_spi, fp_int, qdss_cti_trig_in_b1, uim_batt,
+        cam2_standby, uim1_data, uim1_clk, uim1_reset, uim1_present, uim2_data,
+        uim2_clk, uim2_reset, uim2_present, sensor_rst, mipi_dsi0, smb_int,
+        cam0_ldo, us_euro, atest_char3, dbg_out, bimc_dte0, ts_resout, ts_sample,
+        sec_mi2s_mclk_b, pri_mi2s, sdcard_det, atest_char1, ebi_cdc, audio_reset,
+        atest_char0, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, lpass_slimbus,
+        lpass_slimbus0, lpass_slimbus1, codec_int1, codec_int2, wcss_bt,
+        atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1, wcss_wlan0, wcss_wlan,
+        wcss_fm, ext_lpass, cri_trng, cri_trng1, cri_trng0, blsp_spi7, blsp_uart7,
+        pri_mi2s_ws, blsp_i2c7, gcc_tlmm, dmic0_clk, dmic0_data, key_volp,
+        qdss_cti_trig_in_a1, us_emitter, wsa_irq, wsa_io, wsa_reset, blsp_spi8,
+        blsp_uart8, blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, modem_tsync,
+        nav_tsync, nav_pps_in_b, nav_pps, gsm0_tx, atest_char, atest_tsens,
+        bimc_dte1, ssbi_wtr1, fp_gpio, coex_uart, key_snapshot, key_focus, nfc_pwr,
+        blsp8_spi, qdss_cti_trig_out_a0, qdss_cti_trig_out_a1
+
+- bias-disable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull up.
+
+- output-high:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    high.
+		    Not valid for sdc pins.
+
+- output-low:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    low.
+		    Not valid for sdc pins.
+
+- drive-strength:
+	Usage: optional
+	Value type: <u32>
+	Definition: Selects the drive strength for the specified pins, in mA.
+		    Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8937-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+	};
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index d272b7f..73cd1db 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -135,6 +135,8 @@
 - qcom,additional-mapping: specifies any addtional mapping needed for this
 				context bank. The format is <iova pa size>
 
+- qcom,ipa-q6-smem-size: specifies the Q6 SMEM partition size
+
 IPA SMP2P sub nodes
 
 -compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index f50fd88..75996a5 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -104,6 +104,13 @@
 		    this property is not specified, then the default value used
 		    will be 75mA.
 
+- qcom,fg-cutoff-current
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum Battery current (in mA) used for cutoff SOC
+		    estimate. If this property is not specified, then a default
+		    value of 500 mA will be applied.
+
 - qcom,fg-delta-soc-thr
 	Usage:      optional
 	Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
new file mode 100644
index 0000000..f87f7db
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -0,0 +1,221 @@
+Qualcomm Techonologies, Inc. QPNP PMIC QGAUGE (QG) Device
+
+QPNP PMIC QGAUGE device provides the ability to gauge the State-of-Charge
+of the battery. It provides an interface to the clients to read various
+battery related parameters.
+
+=======================
+Required Node Structure
+=======================
+
+Qgauge device must be described in two level of nodes. The first level
+describes the properties of the Qgauge device and the second level
+describes the peripherals managed/used of the module.
+
+====================================
+First Level Node - QGAUGE device
+====================================
+
+- compatible
+	Usage:      required
+	Value type: <string>
+	Definition: Should be "qcom,qpnp-qg".
+
+- qcom,pmic-revid
+	Usage:      required
+	Value type: <phandle>
+	Definition: Should specify the phandle of PMIC revid module. This is
+		    used to identify the PMIC subtype.
+
+- qcom,qg-vadc
+	Usage:      required
+	Value type: <phandle>
+	Definition: Phandle for the VADC node, it is used for BATT_ID and
+		    BATT_THERM readings.
+
+- qcom,vbatt-empty-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    vbatt-empty interrupt fires. The SOC is forced to 0
+		    when this interrupt fires. If not specified, the
+		    default value is 3200 mV.
+
+- qcom,vbatt-cutoff-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    the Qgauge algorithm converges to 0 SOC. If not specified
+		    the default value is 3400 mV.
+
+- qcom,vbatt-low-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    the VBAT_LOW interrupt fires. Software can take necessary
+		    the action when this interrupt fires. If not specified
+		    the default value is 3500 mV.
+
+- qcom,qg-iterm-ma
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in mA) at which the the QG algorithm
+		    converges the SOC to 100% during charging and can be used to
+		    terminate charging. If not specified, the default value is
+		    100mA.
+
+- qcom,delta-soc
+	Usage:      optional
+	Value type: <u32>
+	Definition: The SOC percentage increase at which the SOC is
+		    periodically reported to the userspace. If not specified,
+		    the value defaults to 1%.
+
+- qcom,s2-fifo-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The total number if FIFO samples which need to be filled up
+		    in S2 state of QG to fire the FIFO DONE interrupt.
+		    Minimum value = 1 Maximum Value = 8. If not specified,
+		    the default value is 5.
+
+- qcom,s2-acc-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The number of distinct V & I samples to be accumulated
+		    in each FIFO in the S2 state of QG.
+		    Minimum Value = 0 Maximum Value = 256. If not specified,
+		    the default value is 128.
+
+- qcom,s2-acc-interval-ms
+	Usage:      optional
+	Value type: <u32>
+	Definition: The time (in ms) between each of the V & I samples being
+		    accumulated in FIFO.
+		    Minimum Value = 0 ms Maximum Value = 2550 ms. If not
+		    specified the default value is 100 ms.
+
+- qcom,ocv-timer-expiry-min
+	Usage:      optional
+	Value type: <u32>
+	Definition: The maximum time (in minutes) for the QG to transition from
+		    S3 to S2 state.
+		    Minimum Value = 2 min Maximum Value = 30 min. If not
+		    specified the hardware default is set to 14 min.
+
+- qcom,ocv-tol-threshold-uv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The OCV detection error tolerance (in uV). The maximum
+		    voltage allowed between 2 VBATT readings in the S3 state
+		    to qualify for a valid OCV.
+		    Minimum Value = 0 uV Maximum Value = 12262 uV  Step = 195 uV
+
+- qcom,s3-entry-fifo-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The minimum number if FIFO samples which have to qualify the
+		    S3 IBAT entry threshold (qcom,s3-entry-ibat-ua) for QG
+		    to enter into S3 state.
+		    Minimum Value = 1 Maximum Value = 8. The hardware default
+		    is configured to 3.
+
+- qcom,s3-entry-ibat-ua
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in uA) for the QG to enter into the S3
+		    state. The QG algorithm enters into S3 if the battery
+		    current is lower than this threshold consecutive for
+		    the FIFO length specified in 'qcom,s3-entry-fifo-length'.
+		    Minimum Value = 0 uA Maximum Value = 155550 uA
+		    Step = 610 uA.
+
+- qcom,s3-exit-ibat-ua
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in uA) for the QG to exit S3 state.
+		    If the battery current is higher than this threshold QG
+		    exists S3 state.
+		    Minimum Value = 0 uA Maximum Value = 155550 uA
+		    Step = 610 uA.
+
+- qcom,rbat-conn-mohm
+	Usage:      optional
+	Value type: <u32>
+	Definition: Resistance of the battery connectors in mOhms.
+
+- qcom,ignore-shutdown-soc-secs
+	Usage:      optional
+	Value type: <u32>
+	Definition: Time in seconds beyond which shutdown SOC is ignored.
+		    If not specified the default value is 360 secs.
+
+- qcom,hold-soc-while-full
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property that when defined holds SOC at 100% when
+		    the battery is full until recharge starts.
+
+- qcom,linearize-soc
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property that when defined linearizes SOC when
+		    the SOC drops after charge termination monotonically to
+		    improve the user experience. This is applicable only if
+		    "qcom,hold-soc-while-full" is specified.
+
+==========================================================
+Second Level Nodes - Peripherals managed by QGAUGE driver
+==========================================================
+- reg
+	Usage:      required
+	Value type: <prop-encoded-array>
+	Definition: Addresses and sizes for the specified peripheral
+
+- interrupts
+	Usage:      optional
+	Value type: <prop-encoded-array>
+	Definition: Interrupt mapping as per the interrupt encoding
+
+- interrupt-names
+	Usage:      optional
+	Value type: <stringlist>
+	Definition: Interrupt names.  This list must match up 1-to-1 with the
+		    interrupts specified in the 'interrupts' property.
+
+========
+Example
+========
+
+pmi632_qg: qpnp,qg {
+	compatible = "qcom,qpnp-qg";
+	qcom,pmic-revid = <&pmi632_revid>;
+	qcom,qg-vadc = <&pmi632_vadc>;
+	qcom,vbatt-empty-mv = <3200>;
+	qcom,vbatt-low-mv = <3500>;
+	qcom,vbatt-cutoff-mv = <3400>;
+	qcom,qg-iterm-ma = <100>;
+
+	qcom,qgauge@4800 {
+		status = "okay";
+		reg = <0x4800 0x100>;
+		interrupts = <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x2 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x4 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x5 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x6 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "qg-batt-missing",
+				  "qg-vbat-low",
+				  "qg-vbat-empty",
+				  "qg-fifo-done",
+				  "qg-good-ocv",
+				  "qg-fsm-state-chg",
+				  "qg-event";
+	};
+
+	qcom,qg-sdam@b000 {
+		status = "okay";
+		reg = <0xb000 0x100>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
new file mode 100644
index 0000000..b7e6a31b
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -0,0 +1,359 @@
+Qualcomm Technologies, Inc. SMB5 Charger Specific Bindings
+
+SMB5 Charger is an efficient programmable battery charger capable of charging a
+high-capacity lithium-ion battery over micro-USB or USB Type-C ultrafast with
+Quick Charge 2.0, Quick Charge 3.0, and USB Power Delivery support. Wireless
+charging features full A4WP Rezence 1.2, WPC 1.2, and PMA support.
+
+=======================
+Required Node Structure
+=======================
+
+SMB5 Charger must be described in two levels of devices nodes.
+
+===============================
+First Level Node - SMB5 Charger
+===============================
+
+Charger specific properties:
+- compatible
+  Usage:      required
+  Value type: <string>
+  Definition: "qcom,qpnp-smb5".
+
+- qcom,pmic-revid
+  Usage:      required
+  Value type: phandle
+  Definition: Should specify the phandle of PMI's revid module. This is used to
+		identify the PMI subtype.
+
+- qcom,batteryless-platform
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which indicates that the platform does not have a
+		battery, and therefore charging should be disabled. In
+		addition battery properties will be faked such that the device
+		assumes normal operation.
+
+- qcom,fcc-max-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum fast charge current in micro-amps.
+		If the value is not present, 1Amp is used as default.
+
+- qcom,fv-max-uv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum float voltage in micro-volts.
+		If the value is not present, 4.35V is used as default.
+
+- qcom,usb-icl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the USB input current limit in micro-amps.
+		 If the value is not present, 1.5Amps is used as default.
+
+- qcom,usb-ocl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the OTG output current limit in micro-amps.
+		If the value is not present, 1.5Amps is used as default.
+
+- qcom,dc-icl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the DC input current limit in micro-amps.
+
+- qcom,boost-threshold-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the boost current threshold in micro-amps.
+		If the value is not present, 100mA is used as default.
+
+- qcom,thermal-mitigation
+  Usage:      optional
+  Value type: Array of <u32>
+  Definition: Array of fast charge current limit values for
+		different system thermal mitigation levels.
+		This should be a flat array that denotes the
+		maximum charge current in mA for each thermal
+		level.
+
+- qcom,float-option
+  Usage:      optional
+  Value type: <u32>
+  Definition: Configures how the charger behaves when a float charger is
+	      detected by APSD.
+	        1 - Treat as a DCP.
+	        2 - Treat as a SDP.
+	        3 - Disable charging.
+	        4 - Suspend USB input.
+
+- qcom,hvdcp-disable
+  Usage:      optional
+  Value type: <empty>
+  Definition: Specifies if hvdcp charging is to be enabled or not.
+		If this property is not specified hvdcp will be enabled.
+		If this property is specified, hvdcp 2.0 detection will still
+		happen but the adapter won't be asked to switch to a higher
+		voltage point.
+
+- qcom,chg-inhibit-threshold-mv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Charge inhibit threshold in milli-volts. Charging will be
+		inhibited when the battery voltage is within this threshold
+		from Vfloat at charger insertion. If this is not specified
+		then charge inhibit will be disabled by default.
+		Allowed values are: 50, 100, 200, 300.
+
+- qcom,auto-recharge-soc
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the SOC threshold at which the charger will
+		restart charging after termination. The value specified
+		ranges from 0 - 100. The feature is enabled if this
+		property is specified with a valid SOC value.
+
+- qcom,auto-recharge-vbat-mv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the battery voltage threshold at which the charger
+		will restart charging after termination. The value specified
+		is in milli-volts.
+
+- qcom,suspend-input-on-debug-batt
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which when present enables input suspend for
+		debug battery.
+
+- qcom,min-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the minimum charger buck/boost switching frequency
+		in KHz. It overrides the min frequency defined for the charger.
+
+- qcom,max-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum charger buck/boost switching frequency in
+		 KHz. It overrides the max frequency defined for the charger.
+
+- qcom,otg-deglitch-time-ms
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the deglitch interval for OTG detection.
+		If the value is not present, 50 msec is used as default.
+
+- qcom,step-charging-enable
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present enables step-charging.
+
+- qcom,wd-bark-time-secs
+  Usage:      optional
+  Value type: <u32>
+  Definition: WD bark-timeout in seconds. The possible values are
+		16, 32, 64, 128. If not defined it defaults to 64.
+
+- qcom,sw-jeita-enable
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present enables sw compensation for
+		jeita.
+
+- qcom,battery-data
+  Usage:      optional
+  Value type: <phandle>
+  Definition: Specifies the phandle of the node which contains the battery
+		profiles supported on the device. This is only specified
+		when step charging and sw-jeita configurations are desired
+		to be get from these properties defined in battery profile:
+		qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.
+
+- qcom,flash-derating-soc
+  Usage:      optional
+  Value type: <u32>
+  Definition: SOC threshold in percentage below which hardware will start
+		derating flash. This is only applicable to certain PMICs like
+		PMI632 which has SCHGM_FLASH peripheral.
+
+- qcom,flash-disable-soc
+  Usage:      optional
+  Value type: <u32>
+  Definition: SOC threshold in percentage below which hardware will disable
+		flash. This is only applicable to certain PMICs like PMI632
+		which has SCHGM_FLASH peripheral.
+
+- qcom,headroom-mode
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies flash hardware headroom management policy. The
+		possible values are:
+		<0>: Fixed mode, constant 5V at flash input.
+		<1>: Adaptive mode allows charger output voltage to be
+		dynamically controlled by the flash module based on the
+		required flash headroom.
+		This is only applicable to certain PMICs like PMI632 which
+		has SCHGM_FLASH peripheral.
+
+=============================================
+Second Level Nodes - SMB5 Charger Peripherals
+=============================================
+
+Peripheral specific properties:
+- reg
+  Usage:      required
+  Value type: <prop-encoded-array>
+  Definition: Address and size of the peripheral's register block.
+
+- interrupts
+  Usage:      required
+  Value type: <prop-encoded-array>
+  Definition: Peripheral interrupt specifier.
+
+- interrupt-names
+  Usage:      required
+  Value type: <stringlist>
+  Definition: Interrupt names.  This list must match up 1-to-1 with the
+	      interrupts specified in the 'interrupts' property.
+
+=======
+Example
+=======
+
+pmi8998_charger: qcom,qpnp-smb5 {
+	compatible = "qcom,qpnp-smb5";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	dpdm-supply = <&qusb_phy0>;
+
+	qcom,chgr@1000 {
+		reg = <0x1000 0x100>;
+		interrupts =	<0x2 0x10 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x10 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x10 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x10 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x10 0x4 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"chg-error",
+					"chg-state-change",
+					"step-chg-state-change",
+					"step-chg-soc-update-fail",
+					"step-chg-soc-update-request";
+	};
+
+	qcom,otg@1100 {
+		reg = <0x1100 0x100>;
+		interrupts =	<0x2 0x11 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x3 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"otg-fail",
+					"otg-overcurrent",
+					"otg-oc-dis-sw-sts",
+					"testmode-change-detect";
+	};
+
+	qcom,bat-if@1200 {
+		reg = <0x1200 0x100>;
+		interrupts =	<0x2 0x12 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x12 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x12 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x12 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x12 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x12 0x5 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"bat-temp",
+					"bat-ocp",
+					"bat-ov",
+					"bat-low",
+					"bat-therm-or-id-missing",
+					"bat-terminal-missing";
+	};
+
+	qcom,usb-chgpth@1300 {
+		reg = <0x1300 0x100>;
+		interrupts =	<0x2 0x13 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x5 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x6 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x7 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"usbin-collapse",
+					"usbin-lt-3p6v",
+					"usbin-uv",
+					"usbin-ov",
+					"usbin-plugin",
+					"usbin-src-change",
+					"usbin-icl-change",
+					"type-c-change";
+	};
+
+	qcom,dc-chgpth@1400 {
+		reg = <0x1400 0x100>;
+		interrupts =	<0x2 0x14 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x5 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x6 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"dcin-collapse",
+					"dcin-lt-3p6v",
+					"dcin-uv",
+					"dcin-ov",
+					"dcin-plugin",
+					"div2-en-dg",
+					"dcin-icl-change";
+	};
+
+	qcom,chgr-misc@1600 {
+		reg = <0x1600 0x100>;
+		interrupts =	<0x2 0x16 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x5 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x6 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x7 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"wdog-snarl",
+					"wdog-bark",
+					"aicl-fail",
+					"aicl-done",
+					"high-duty-cycle",
+					"input-current-limiting",
+					"temperature-change",
+					"switcher-power-ok";
+	};
+
+	qcom,schgm-flash@a600 {
+		reg = <0xa600 0x100>;
+		interrupts =	<0x2 0xa6 0x0 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x1 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x2 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x3 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x4 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x5 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x6 IRQ_TYPE_NONE>,
+				<0x2 0xa6 0x7 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"flash-en",
+					"torch-req",
+					"flash-state-change",
+					"vout-up",
+					"vout-down",
+					"ilim1-s1",
+					"ilim2-s2",
+					"vreg-ok";
+	};
+};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
index be8c2f0..de40a7c 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -47,36 +47,39 @@
 Legacy SMMU v1/v2:
 
 Required properties:
-- compatible : Must be "qcom,msm-fastprc-legacy-compute-cb"
+- compatible : Must be "qcom,msm-fastrpc-legacy-compute"
 
 Required subnode:
 - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context
                                 banks
 
 Required subnode properties:
-- qcom,adsp-shared-phandle: phandle that describe the context bank handle
-- qcom,adsp-shared-sids : A list of SID associated with the context bank
-- qcom,virtual-addr-pool : Virtual address range that the context bank
-                           will be using
+- compatible : Must be "qcom,msm-fastrpc-legacy-compute-cb"
+- label	     : Label describing the channel this context bank belongs to
+- iommus     : A list of phandle and IOMMU specifier pairs that describe the
+			IOMMU master interfaces of the device
+- sids       : A list of SID associated with the context bank
 
 Example:
-        qcom,adsprpc_domains {
-                compatible = "qcom,msm-fastrpc-legacy-compute-cb";
-                qcom,msm_fastrpc_compute_cb {
-                       qcom,adsp-shared-phandle = <&adsp_shared>;
-                       qcom,adsp-shared-sids = <0x8 0x9>;
-                       qcom,virtual-addr-pool = <0x80000000 0x7FFFFFFF>;
-                };
-        };
-
+	qcom,msm_fastrpc {
+		compatible = "qcom,msm-fastrpc-legacy-compute";
+		qcom,msm_fastrpc_compute_cb {
+			compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_iommu 0x2408 0x7>;
+			sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+		};
+	};
 Remote Heap:
 
 Required properties:
 - compatible : Must be "qcom,msm-adsprpc-mem-region"
 - memory-region : CMA region which is owned by this device
+- restrict-access : Blocking vote for hyp_assign_phys function call
 
 Example:
        qcom,adsprpc-mem {
                compatible = "qcom,msm-adsprpc-mem-region";
                memory-region = <&adsp_mem>;
+               restrict-access;
        };
diff --git a/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt
new file mode 100644
index 0000000..2a5fc0f
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-mdsprpc-mem.txt
@@ -0,0 +1,24 @@
+Qualcomm Technologies, Inc. FastRPC MDSP CMA Heap
+
+The MSM MDSPRPC memory device allocates CMA memory, for sharing memory
+of FastRPC buffers to remote processor(MDSP).
+
+Required properties:
+-compatible: Must be "qcom,msm-mdsprpc-mem-region"
+-memory-region: A phandle that points to a memory heap where the
+heap memory is allocated
+
+Example:
+	qcom,mdsprpc-mem {
+		compatible = "qcom,msm-mdsprpc-mem-region";
+		memory-region = <&mdsp_mem>;
+	};
+
+Ion Heap:
+
+Ion heap allows for sharing of buffers between different processors
+and between user space and kernel space.
+(see Documentation/devicetree/bindings/arm/msm/msm_ion.txt).
+
+Required properties for Ion heap:
+- compatible : "qcom,msm-ion"
diff --git a/Documentation/devicetree/bindings/regulator/cpr-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
index 1c4dfbf..0f5e27a 100644
--- a/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
@@ -709,19 +709,6 @@
 				The number of quadruples should be equal to the number of values specified in
 				the qcom,cpr-aging-sensor-id property. This property is required if
 				the qcom,cpr-aging-sensor-id property has been specified.
-- qcom,cpr-thermal-sensor-id:	TSENS hardware sensor-id of the sensor which
-				needs to be monitored.
-- qcom,cpr-disable-temp-threshold:	The TSENS temperature threshold in degrees Celsius at which CPR
-				closed-loop is disabled. CPR closed-loop will stay disabled as long as the
-				temperature is below this threshold. This property is required
-				only if 'qcom,cpr-thermal-sensor-id' is present.
-- qcom,cpr-enable-temp-threshold:	The TSENS temperature threshold in degrees Celsius at which CPR
-				closed-loop is enabled. CPR closed-loop will stay enabled above this
-				temperature threshold. This property is required only if
-				'qcom,cpr-thermal-sensor-id' is present.
-- qcom,disable-closed-loop-in-pc:	Bool property to disable closed-loop CPR during
-				power-collapse. This can be enabled only for single core
-				designs. The property 'qcom,cpr-cpus' is required to enable this logic.
 Example:
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
@@ -971,8 +958,4 @@
 		qcom,cpr-fuse-aging-init-quot-diff =
 				<101 0 8 0>,
 				<101 8 8 0>;
-
-		qcom,cpr-thermal-sensor-id = <9>;
-		qcom,cpr-disable-temp-threshold = <5>;
-		qcom,cpr-enable-temp-threshold = <10>;
 	};
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt
new file mode 100644
index 0000000..149a01a
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt
@@ -0,0 +1,14 @@
+Qualcomm Technologies Inc. bg-daemon
+
+BG-Daemon : When Modem goes down, to re-establish the connections,
+BG-Daemon toggles the bg-reset gpio to reset BG.
+
+Required properties:
+- compatible : should be "qcom,bg-daemon"
+- qcom,bg-reset-gpio : gpio for the apps processor use to soft reset BG
+
+Example:
+	qcom,bg-daemon {
+		compatible = "qcom,bg-daemon";
+		qcom,bg-reset-gpio = <&pm660_gpios 5 0>;
+	};
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt
new file mode 100644
index 0000000..26a13cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt
@@ -0,0 +1,19 @@
+Qualcomm technologies Inc bg-rsb
+
+BG-RSB : bg-rsb is used to communicate with BG over Glink to
+configure the RSB events. bg-rsb enable/disable LDO11 and LDO15
+before making any communication to BG regarding RSB.
+It also provides an input device, which is used to send the RSB/Button
+events to input framework.
+
+Required properties:
+- compatible : should be "qcom,bg-rsb"
+- vdd-ldo1-supply : pm660_l11 regulator
+- vdd-ldo2-supply : for pm660_l15 regulator
+
+Example:
+	qcom,bg-rsb {
+		compatible = "qcom,bg-rsb";
+		vdd-ldo1-supply = <&pm660_l11>;
+		vdd-ldo2-supply = <&pm660_l15>;
+	};
diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt
new file mode 100644
index 0000000..e9a28a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt
@@ -0,0 +1,24 @@
+Qualcomm technologies Inc bg-spi
+
+BG-COM SPI : bg-spi is used for the  communication with Blackghost
+chipset. It uses SPI protocol for communication.
+BG-COM: bgcome is a thin transport layer over glink which provides
+the read/write APIs to communicate with Blackghost chipset.
+
+Required properties:
+- compatible : should be "qcom,bg-spi"
+- spi-max-frequency : Maximum SPI clocking speed of device in Hz
+- qcom,irq-gpio : GPIO pin
+- reg : Register set
+
+Example:
+	spi@78b6000 { /* BLSP1 QUP2 */
+		status = "ok";
+		qcom,bg-spi {
+			compatible = "qcom,bg-spi";
+			reg = <0>;
+			spi-max-frequency = <19200000>;
+			interrupt-parent = <&msm_gpio>;
+			qcom,irq-gpio = <&msm_gpio 110 1>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 58c9bf8..33dc684 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -293,16 +293,17 @@
 
  - compatible : "qcom,msm-pcm-hostless"
 
-* audio-load-mod
+* msm-audio-apr
 
 Required properties:
 
- - compatible : "qcom,audio-load-mod"
+ - compatible : "qcom,msm-audio-apr"
+		This device is added to represent APR module.
 
 Optional properties:
 
- - compatible : "qcom,audio-test-mod"
-		Add this compatible as child device to load-module device.
+ - compatible : "qcom,msm-audio-apr-dummy"
+		Add this compatible as child device to msm-audio-apr device.
 		This child device is added after lpass is up to invoke
 		deferred probe devices.
 
@@ -655,10 +656,10 @@
                 compatible = "qcom,msm-pcm-hostless";
         };
 
-	audio_load_mod {
-		compatible = "qcom,audio-load-mod";
-		audio_test_mod {
-			compatible = "qcom,audio-test-mod";
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
 		};
 	};
 
@@ -1871,6 +1872,128 @@
 		asoc-wsa-codec-prefixes = "SpkrLeft";
 	};
 
+* MSM8909 BG ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm-bg-audio-codec"
+- qcom,model : The user-visible name of this sound card.
+- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets
+	mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs,
+	this would list all the 2^N combinations.
+- pinctrl-names : The combinations of gpio sets from above that are supported in
+	the flavor. This can be sometimes same as qcom,pinctrl-names i.e with 2^N
+	combinations or will have less incase if some combination is not supported.
+- pinctrl-# : Pinctrl states as mentioned in pinctrl-names.
+- qcom,audio-routing : A list of the connections between audio components.
+	Each entry is a pair of strings, the first being the connection's sink,
+	the second being the connection's source.
+
+Optional properties:
+- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+- 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".
+- vdd-spkr-supply: BG codec supply's speaker regulator device tree node.
+
+Example:
+	sound {
+		status = "disabled";
+		compatible = "qcom,msm-bg-audio-codec";
+		qcom,model = "msm-bg-snd-card";
+		reg = <0x7702000 0x4>,
+		      <0x7702004 0x4>,
+		      <0x7702008 0x4>,
+		      <0x770200c 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			    "csr_gp_io_mux_spkr_ctl",
+			    "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			    "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel";
+		qcom,msm-snd-card-id = <0>;
+		qcom,msm-ext-pa = "primary";
+		qcom,tdm-audio-intf;
+		qcom,msm-afe-clk-ver = <1>;
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&lpa>,
+				<&voice_svc>;
+		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-pcm-lpa",
+				      "msm-voice-svc";
+		asoc-cpu = <&dai_pri_auxpcm>,
+				<&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+				<&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+				<&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+				<&int_fm_rx>, <&int_fm_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>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+				<&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>,
+				<&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>,
+				<&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>;
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+				"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+				"msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+				"msm-dai-q6-dev.12293", "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-tdm.36864",
+				"msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866",
+				"msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868",
+				"msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870",
+				"msm-dai-q6-tdm.36871";
+		asoc-codec = <&stub_codec>;
+		asoc-codec-names = "msm-stub-codec.1";
+	};
+
+* BG Codec Driver.
+
+Required properties:
+- compatible : "qcom,bg-codec"
+- qcom,bg-glink : Glink component required for the BG codec communication.
+	- compatible :"qcom,bg-cdc-glink"
+- qcom,msm-glink-channels: Number of glink channels available to communicate
+			   with the glink client
+- vdd-spkr-supply: BG codec supply's speaker regulator device tree node.
+
+Optional properties:
+- qcom,bg-speaker-connected: This flag will notify BG codec driver that speaker
+			is connected to target or not. Based on this flag BG
+			codec driver will send smart pa init params to BG.
+
+Example:
+
+        bg_cdc: bg_codec {
+                status = "disabled";
+                compatible = "qcom,bg-codec";
+                qcom,bg-glink {
+                        compatible = "qcom,bg-cdc-glink";
+                        qcom,msm-glink-channels = <4>;
+                };
+        };
+
 * MDM9607 ASoC Machine driver
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt b/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
index 757ca9a..8a67d6d 100644
--- a/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
+++ b/Documentation/devicetree/bindings/soundwire/swr-wcd-ctrl.txt
@@ -8,6 +8,7 @@
 	 which the swr-devid is <0x0 0x032000> where 0x03 represents
 	 device Unique_ID, 0x20 represents Part_Id1 and 0x00
 	 represents part_Id2.
+- qcom,swr-num-dev : Maximum number of possible slave devices.
 - #address-cells = <2>;
 - #size-cells = <0>;
 
@@ -16,6 +17,7 @@
  Example:
 	swr_master {
 		compatible = "qcom,swr-wcd";
+		qcom,swr-num-dev = <2>;
 		#address-cells = <2>;
 		#size-cells = <0>;
 
diff --git a/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt
new file mode 100644
index 0000000..ab21954
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-bcl-pmic5.txt
@@ -0,0 +1,43 @@
+===============================================================================
+BCL Peripheral driver for PMIC5:
+===============================================================================
+Qualcomm Technologies, Inc's PMIC has battery current limiting peripheral,
+which can monitor for high battery current and low battery voltage in the
+hardware. The BCL peripheral driver interacts with the PMIC peripheral using
+the SPMI driver interface. The hardware can take threshold for notifying for
+high battery current or low battery voltage events. This driver works only
+with PMIC version 5, where the same BCL peripheral can be found in multiple
+PMIC's that are used in a device, with limited functionalities. For example,
+one PMIC can have only vbat monitoring, while the other PMIC can have both
+vbat and ibat monitoring. This is a common driver, that can interact
+with the multiple BCL peripherals.
+
+Required Parameters:
+- compatible: must be
+	'qcom,bcl-v5' for bcl peripheral in PMIC version 5.
+- reg: <a b> where 'a' is the starting register address of the PMIC
+	peripheral and 'b' is the size of the peripheral address space.
+- interrupts: <a b c d> Where,
+		'a' is the SLAVE ID of the PMIC,
+		'b' is the peripheral ID,
+		'c' is the interrupt number in PMIC and
+		'd' is the interrupt type.
+- interrupt-names: user defined names for the interrupts. These
+		interrupt names will be used by the drivers to identify the
+		interrupts, instead of specifying the ID's. bcl driver will
+		accept these standard interrupts.
+		"bcl-ibat-lvl0",
+		"bcl-ibat-lvl1",
+		"bcl-vbat-lvl0",
+		"bcl-vbat-lvl1",
+		"bcl-vbat-lvl2",
+
+Example:
+	bcl@4200 {
+		compatible = "qcom,bcl-v5";
+		reg = <0x4200 0x100>;
+		interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x42 0x1 IRQ_TYPE_NONE>;
+		interrupt-names = "bcl-ibat-lvl0",
+					"bcl-vbat-lvl0";
+	};
diff --git a/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt b/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt
new file mode 100644
index 0000000..00be6de
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-bcl-soc.txt
@@ -0,0 +1,13 @@
+===============================================================================
+PMIC state of charge driver:
+===============================================================================
+Battery state of charge driver can monitor for change in battery charge and
+notify thermal framework, when the value goes below a certain threshold.
+
+Required Parameters:
+- compatible: must be 'qcom,msm-bcl-soc' for battery state of charge driver.
+
+Example:
+	bcl-soc {
+		compatible = "qcom,msm-bcl-soc";
+	};
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67ffaed..6ff6e9b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -19,6 +19,7 @@
 	       should be "qcom,sdm630-tsens" for 630 TSENS driver.
 	       should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
 	       should be "qcom,tsens24xx" for 2.4 TSENS controller.
+	       should be "qcom,msm8937-tsens" for 8937 TSENS driver.
 	       The compatible property is used to identify the respective controller to use
 	       for the corresponding SoC.
 - reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/Documentation/devicetree/bindings/usb/msm-android-usb.txt b/Documentation/devicetree/bindings/usb/msm-android-usb.txt
new file mode 100644
index 0000000..4422a18
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/msm-android-usb.txt
@@ -0,0 +1,36 @@
+ANDROID USB:
+
+This describes the device tree node for the Android USB gadget device.
+This works in conjunction with a USB Device Controller (UDC) to provide
+a dynamically configurable composition of functions to be exposed when
+connected to a USB host.
+
+Required properties:
+- compatible: should be "qcom,android-usb"
+
+Optional properties :
+- reg  : offset and length of memory region that is used by device to
+  update USB PID and serial numbers used by bootloader in DLOAD mode.
+- qcom,pm-qos-latency : This property must be a list of three integer values
+  (perf, normal, sleep) where each value respresents DMA latency in microsecs.
+  First value represents DMA latency to vote with pm_qos when back to back USB
+  transfers are happening and it requires USB thoughput to be maximum.
+  Second value represents value to vote when not many USB transfers are
+  happening and it is OK to have higher DMA latency to save power.
+  Third value represents DMA latency to vote when USB BUS is IDLE and absolutely
+  no transfers are happening. It should allow transition to lowest power state.
+- qcom,usb-core-id: Index to refer USB hardware core to bind android gadget driver
+  with UDC if multiple USB peripheral controllers are present. If unspecified,
+  core is set to zero by default.
+- qcom,supported-func: Represents list of supported function drivers. If this
+  property is present android USB driver dynamically creats the list of
+  supported function drivers and uses this list instead of statically defined default
+  supported function driver list.
+Example Android USB device node :
+	android_usb@fc42b0c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfc42b0c8 0xc8>;
+		qcom,pm-qos-latency = <2 1001 12701>;
+		qcom,supported-func = "rndis_gsi","ecm_gsi","rmnet_gsi";
+		qcom,usb-core-id = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 8654a3e..5256edd 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -1,110 +1,307 @@
 MSM SoC HSUSB controllers
 
-EHCI
+OTG:
 
-Required properties:
-- compatible:	Should contain "qcom,ehci-host"
-- regs:			offset and length of the register set in the memory map
-- usb-phy:		phandle for the PHY device
+Required properties :
+- compatible : should be "qcom,hsusb-otg"
+- regs : Array of offset and length of the register sets in the memory map
+- reg-names : indicates various iomem resources passed by name. The possible
+	strings in this field are:
+	    "core": USB controller register space. (Required)
+	    "tcsr": TCSR register for routing USB Controller signals to
+		    either picoPHY0 or picoPHY1. (Optional)
+	    "phy_csr": PHY Wrapper CSR register space. Provides register level
+		       interface through AHB2PHY for performing PHY related
+		       operations like retention and HV interrupts management.
+- interrupts: IRQ line
+- interrupt-names: OTG interrupt name(s) referenced in interrupts above
+            HSUSB OTG expects "core_irq" which is IRQ line from CORE and
+            "async_irq" from HSPHY for asynchronous wakeup events in LPM.
+            optional ones are described in next section.
+- qcom,hsusb-otg-phy-type: PHY type can be one of
+	    1 - Chipidea PHY (obsolete)
+	    2 - Synopsis Pico PHY
+	    3 - Synopsis Femto PHY
+	    4 - QUSB ULPI PHY
+- qcom,hsusb-otg-mode: Operational mode. Can be one of
+            1 - Peripheral only mode
+	    2 - Host only mode
+	    3 - OTG mode
+	    Based on the mode, OTG driver registers platform devices for
+	    gadget and host.
+- qcom,hsusb-otg-otg-control: OTG control (VBUS and ID notifications)
+  can be one of
+            1 - PHY control
+	    2 - PMIC control
+	    3 - User control (via debugfs)
+- <supply-name>-supply: handle to the regulator device tree node
+         Required "supply-name" is "HSUSB_VDDCX" (when voting for VDDCX) or
+         "hsusb_vdd_dig" (when voting for VDDCX Corner voltage),
+         "HSUSB_1p8-supply" and "HSUSB_3p3-supply".
+- qcom,vdd-voltage-level: This property must be a list of three integer
+	values (none, min, max) where each value represents either a voltage
+	in microvolts or a value corresponding to voltage corner. If usb core
+	supports svs, min value will have absolute SVS or SVS corner otherwise
+	min value will have absolute nominal or nominal corner.
+- clocks: a list of phandles to the USB clocks. Usage is as per
+	Documentation/devicetree/bindings/clock/clock-bindings.txt
+- clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
+	property.
 
-Example EHCI controller device node:
+	Required clocks:
+	"core_clk": USB core clock that is required for data transfers.
+	"iface_clk": USB core clock that is required for register access.
 
-	ehci: ehci@f9a55000 {
-		compatible = "qcom,ehci-host";
-		reg = <0xf9a55000 0x400>;
-		usb-phy = <&usb_otg>;
+	Optional clocks:
+	"sleep_clk": PHY sleep clock. Required for interrupts.
+	"phy_reset_clk": PHY blocks asynchronous reset clock. Required
+		for the USB block reset. It is a reset only clock.
+	"phy_por_clk": Reset only clock for asserting/de-asserting
+		PHY POR signal. Required for overriding PHY parameters.
+	"phy_csr_clk": Required for accessing PHY CSR registers through
+		AHB2PHY interface.
+	"phy_ref_clk": Required when PHY have referance clock,
+	"xo": XO clock. The source clock that is used as a reference clock
+		to the PHY.
+	"bimc_clk", "snoc_clk", "pcnoc_clk": bus voting clocks. Used to
+		keep buses at a nominal frequency during USB peripheral
+		mode for achieving max throughput.
+- qcom,max-nominal-sysclk-rate: Indicates maximum nominal frequency for which
+	system clock should be voted whenever streaming mode is enabled.
+- resets: reset specifier pair consists of phandle for the reset provider
+	and reset lines used by this controller.
+- reset-names: reset signal name strings sorted in the same order as the resets
+	property.
+
+Optional properties :
+- interrupt-names : Optional interrupt resource entries are:
+    "pmic_id_irq" : Interrupt from PMIC for external ID pin notification.
+    "phy_irq" : Interrupt from PHY. Used for ID detection.
+- qcom,hsusb-otg-disable-reset: If present then core is RESET only during
+	    init, otherwise core is RESET for every cable disconnect as well
+- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
+	    performance issue is applied which requires changing the mem-type
+	    attribute via VMIDMT.
+- qcom,hsusb-otg-default-mode: The default USB mode after boot-up.
+  Applicable only when OTG is controlled by user. Can be one of
+            0 - None. Low power mode
+            1 - Peripheral
+	    2 - Host
+- qcom,hsusb-otg-phy-init-seq: PHY configuration sequence. val, reg pairs
+  terminate with -1
+- qcom,hsusb-otg-power-budget: VBUS power budget in mA
+  0 will be treated as 500mA
+- qcom,hsusb-otg-pclk-src-name: The source of pclk
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm-bus.txt" for
+  below optional properties:
+    - qcom,msm-bus,name
+    - qcom,msm-bus,num_cases - There are three valid cases for this: NONE, MAX
+		and MIN bandwidth votes. Minimum two cases must be defined for
+		both NONE and MAX votes. If MIN vote is different from NONE VOTE
+		then specify third case for MIN VOTE. If explicit NOC clock rates
+		are not specified then MAX value should be large enough to get
+		desired BUS frequencies. In case explicit NOC clock rates are
+		specified, peripheral mode bus bandwidth vote should be defined
+		to vote for arbitrated bandwidth so that 60MHz frequency is met.
+
+    - qcom,msm-bus,num_paths
+    - qcom,msm-bus,vectors
+- qcom,hsusb-otg-lpm-on-dev-suspend: If present then USB enter to
+	    low power mode upon receiving bus suspend.
+- qcom,hsusb-otg-clk-always-on-workaround: If present then USB core clocks
+	    remain active upon receiving bus suspend and USB cable is connected.
+	    Used for allowing USB to respond for remote wakup.
+- qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
+	after disconnect before entering low power mode.
+- <supply-name>-supply: handle to the regulator device tree node.
+         Optional "supply-name" is "vbus_otg" to supply vbus in host mode.
+- qcom,dp-manual-pullup: If present, vbus is not routed to USB controller/phy
+	and controller driver therefore enables pull-up explicitly before
+	starting controller using usbcmd run/stop bit.
+- qcom,usb2-enable-hsphy2: If present then USB2 controller is connected to 2nd
+	HSPHY.
+- qcom,hsusb-log2-itc: value of 2^(log2_itc-1) will be used as the
+	interrupt threshold (ITC), when log2_itc is between 1 to 7.
+- qcom,hsusb-l1-supported: If present, the device supports l1 (Link power
+	management).
+- qcom,no-selective-suspend: If present selective suspend is disabled on hub ports.
+- pinctrl-names : This should be defined if a target uses gpio and pinctrl framework.
+  See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+  It should specify the names of the configs that pinctrl can install in driver
+	Following are the pinctrl config that can be installed
+	"hsusb_active" : Active configuration of pins, this should specify active
+	config of vddmin gpio (if used) defined in their pin groups.
+	"hsusb_sleep" : Disabled configuration of pins, this should specify sleep
+	config of vddmin gpio (if used) defined in their pin groups.
+- qcom,hsusb-otg-vddmin-gpio = If present, indicates a gpio that will be used
+	to supply voltage to the D+ line during VDD minimization and peripheral
+	bus suspend. If not exists, then VDD minimization will not be allowed
+	during peripheral bus suspend.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+	mode with device controller for better throughput. With this mode, USB Core
+	runs using PNOC clock and synchronous to it. Hence it is must to have proper
+	"qcom,msm-bus,vectors" to have high bus frequency. User shouldn't try to
+	enable this feature without proper bus voting. When this feature is enabled,
+	it is required to do HW reset during cable disconnect for host mode functionality
+	working and hence need to disable qcom,hsusb-otg-disable-reset. With this feature
+	enabled, USB HW has to vote for maximum PNOC frequency as USB HW cannot tolerate
+	changes in PNOC frequency which results in USB functionality failure.
+- qcom,disable-retention-with-vdd-min: If present don't allow phy retention but allow
+	vdd min.
+- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
+	This will be used to get value of usb power supply's VOLTAGE_NOW property.
+- qcom,usbid-gpio: This corresponds to gpio which is used for USB ID detection.
+- qcom,hub-reset-gpio: This corresponds to gpio which is used for HUB reset.
+- qcom,sw-sel-gpio: This corresponds to gpio which is used for switch select routing
+	of D+/D- between the USB HUB and type B USB jack for peripheral mode.
+- qcom,bus-clk-rate: If present, indicates nominal bus frequency to be voted for
+	bimc/snoc/pcnoc clock with usb cable connected. If AHB2AHB bypass is enabled,
+	pcnoc value should be defined to very large number so that PNOC runs at max
+	frequency. If 'qcom,default-mode-svs' is also set then two set of frequencies
+	must be specified for SVS and NOM modes which user can change using sysfs node.
+- qcom,phy-dvdd-always-on: If present PHY DVDD is supplied by a always-on
+	regulator unlike vddcx/vddmx. PHY can keep D+ pull-up and D+/D-
+	pull-down resistors during peripheral and host bus suspend without
+	any re-work.
+- qcom,emulation: Indicates that we are running on emulation platform.
+- qcom,boost-sysclk-with-streaming: If present, enable controller specific
+	streaming feature. Also this flag can bump up usb system clock to max in streaming
+	mode. This flag enables streaming mode for all compositions and is different from
+	streaming-func property defined in android device node. Please refer Doumentation/
+	devicetree/bindings/usb/android-dev.txt for details about "streaming-func" property.
+- qcom,axi-prefetch-enable: If present, AXI64 interface will be used for transferring data
+       to/from DDR by controller.
+- qcom,enable-phy-id-pullup: If present, PHY can keep D+ pull-up resistor on USB ID line
+	during cable disconnect.
+- qcom,max-svs-sysclk-rate: Indicates system clock frequency voted by driver in
+	non-perf mode. In perf mode driver uses qcom,max-nominal-sysclk-rate.
+- qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs,
+	which is used as a vote by driver to get max performance in perf mode.
+- qcom,default-mode-svs: Indicates USB system clock should run at SVS frequency.
+	User can bump it up using 'perf_mode' sysfs attribute for gadget.
+- qcom,vbus-low-as-hostmode: If present, specifies USB_VBUS to switch to host mode
+	if USB_VBUS is low or device mode if USB_VBUS is high.
+- qcom,usbeth-reset-gpio: If present then an external usb-to-eth is connected to
+	the USB host controller and its RESET_N signal is connected to this
+	usbeth-reset-gpio GPIO. It should be driven LOW to RESET the usb-to-eth.
+- extcon: phandles to external connector devices. First phandle should point to
+	external connector, which provide "USB" cable events, the second should
+	point to external connector device, which provide "USB-HOST" cable events.
+	A single phandle may be specified if a single connector device provides
+	both "USB" and "USB-HOST" events.
+
+Example HSUSB OTG controller device node :
+	usb@f9690000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0xf9690000 0x400>;
+		reg-names = "core";
+		interrupts = <134>;
+		interrupt-names = "core_irq";
+
+		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-mode = <1>;
+		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-disable-reset;
+		qcom,hsusb-otg-pnoc-errata-fix;
+		qcom,hsusb-otg-default-mode = <2>;
+		qcom,hsusb-otg-phy-init-seq = <0x01 0x90 0xffffffff>;
+		qcom,hsusb-otg-power-budget = <500>;
+		qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
+		qcom,hsusb-otg-lpm-on-dev-suspend;
+		qcom,hsusb-otg-clk-always-on-workaround;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
+                HSUSB_1p8-supply = <&pm8226_l10>;
+                HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
+		qcom,dp-manual-pullup;
+		qcom,max-nominal-sysclk-rate = <133330000>;
+		qcom,max-svs-sysclk-rate = <100000000>;
+		qcom,pm-qos-latency = <59>;
+
+		qcom,msm-bus,name = "usb2";
+		qcom,msm-bus,num_cases = <2>;
+		qcom,msm-bus,num_paths = <1>;
+		qcom,msm-bus,vectors =
+				<87 512 0 0>,
+				<87 512 60000000 960000000>;
+		pinctrl-names = "hsusb_active","hsusb_sleep";
+		pinctrl-0 = <&vddmin_act>;
+		pinctrl-0 = <&vddmin_sus>;
+		qcom,hsusb-otg-vddmin-gpio = <&pm8019_mpps 6 0>;
+		qcom,disable-retention-with-vdd-min;
+		qcom,usbin-vadc = <&pm8226_vadc>;
+		qcom,usbid-gpio = <&msm_gpio 110 0>;
 	};
 
-USB PHY with optional OTG:
+MSM HSUSB EHCI controller
 
-Required properties:
-- compatible:   Should contain:
-  "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY
-  "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY
+Required properties :
+- compatible : should be "qcom,ehci-host"
+- reg : offset and length of the register set in the memory map
+- interrupts: IRQ lines used by this controller
+- interrupt-names : Required interrupt resource entries are:
+            HSUSB EHCI expects "core_irq" and optionally "async_irq".
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+- qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
-- regs:         Offset and length of the register set in the memory map
-- interrupts:   interrupt-specifier for the OTG interrupt.
+Optional properties :
+- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+- pinctrl-names : This should be defined if a target uses pinctrl framework.
+  See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+  It should specify the names of the configs that pinctrl can install in driver
+  Following are the pinctrl configs that can be installed
+	"ehci_active" : Active configuration of pins, this should specify active
+	config defined in pin groups of used gpio's from resume and
+	ext-hub-reset.
+	"ehci_sleep" : Disabled configuration of pins, this should specify sleep
+	config defined in pin groups of used gpio's from resume and
+	ext-hub-reset.
+- qcom,resume-gpio: if present then peripheral connected to usb controller
+  cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
+  gpio to wakeup peripheral.
+- qcom,ext-hub-reset-gpio: If present then an external HUB is connected to
+  the USB host controller and its RESET_N signal is connected to this
+  ext-hub-reset-gpio GPIO. It should be driven LOW to RESET the HUB.
+- qcom,usb2-enable-uicc: If present, usb2 port will be used for uicc card connection.
+- usb-phy: phandle for the PHY device, if described as a separate device tree node
+- qcom,pm-qos-latency: This property represents the maximum tolerable CPU latency in
+  microsecs, which is used as a vote to keep the CPUs in a high enough power state when
+  USB bus is in use (not suspended).
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm-bus.txt" for
+  below optional properties:
+    - qcom,msm-bus,name
+    - qcom,msm-bus,num_cases - Two cases (NONE and MAX) for voting are supported.
+    - qcom,msm-bus,num_paths
+    - qcom,msm-bus,vectors
 
-- clocks:       A list of phandle + clock-specifier pairs for the
-                clocks listed in clock-names
-- clock-names:  Should contain the following:
-  "phy"         USB PHY reference clock
-  "core"        Protocol engine clock
-  "iface"       Interface bus clock
-  "alt_core"    Protocol engine clock for targets with asynchronous
-                reset methodology. (optional)
-
-- vdccx-supply: phandle to the regulator for the vdd supply for
-                digital circuit operation.
-- v1p8-supply:  phandle to the regulator for the 1.8V supply
-- v3p3-supply:  phandle to the regulator for the 3.3V supply
-
-- resets:       A list of phandle + reset-specifier pairs for the
-                resets listed in reset-names
-- reset-names:  Should contain the following:
-  "phy"         USB PHY controller reset
-  "link"        USB LINK controller reset
-
-- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of
-                1 - PHY control
-                2 - PMIC control
-
-Optional properties:
-- dr_mode:      One of "host", "peripheral" or "otg". Defaults to "otg"
-
-- switch-gpio:  A phandle + gpio-specifier pair. Some boards are using Dual
-                SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex
-                D+/D- USB lines between connectors.
-
-- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
-                Mode Eye Diagram test. Start address at which these values will be
-                written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
-                "do not overwrite default value at this address".
-                For example: qcom,phy-init-sequence = < -1 0x63 >;
-                Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1.
-
-- qcom,phy-num: Select number of pyco-phy to use, can be one of
-                0 - PHY one, default
-                1 - Second PHY
-                Some platforms may have configuration to allow USB
-                controller work with any of the two HSPHYs present.
-
-- qcom,vdd-levels: This property must be a list of three integer values
-                (no, min, max) where each value represents either a voltage
-                in microvolts or a value corresponding to voltage corner.
-
-- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
-                and controller driver therefore enables pull-up explicitly
-                before starting controller using usbcmd run/stop bit.
-
-- extcon:       phandles to external connector devices. First phandle
-                should point to external connector, which provide "USB"
-                cable events, the second should point to external connector
-                device, which provide "USB-HOST" cable events. If one of
-                the external connector devices is not required empty <0>
-                phandle should be specified.
-
-Example HSUSB OTG controller device node:
-
-    usb@f9a55000 {
-        compatible = "qcom,usb-otg-snps";
-        reg = <0xf9a55000 0x400>;
-        interrupts = <0 134 0>;
-        dr_mode = "peripheral";
-
-        clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>,
-                <&gcc GCC_USB_HS_AHB_CLK>;
-
-        clock-names = "phy", "core", "iface";
-
-        vddcx-supply = <&pm8841_s2_corner>;
-        v1p8-supply = <&pm8941_l6>;
-        v3p3-supply = <&pm8941_l24>;
-
-        resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>;
-        reset-names = "phy", "link";
-
-        qcom,otg-control = <1>;
-        qcom,phy-init-sequence = < -1 0x63 >;
-        qcom,vdd-levels = <1 5 7>;
+Example MSM HSUSB EHCI controller device node :
+	ehci: qcom,ehci-host@f9a55000 {
+		compatible = "qcom,ehci-host";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0>, <0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+		/* If pinctrl is used and ext-hub-reset and resume gpio's are present*/
+		pinctrl-names = "ehci_active","ehci_sleep";
+		pinctrl-0 = <&ehci_reset_act &resume_act>;
+		pinctrl-1 = <&ehci_reset_sus &resume_sus>;
+		qcom,resume-gpio = <&msm_gpio 80 0>;
+		qcom,ext-hub-reset-gpio = <&msm_gpio 0 0>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+		HSUSB_1p8-supply = <&pm8941_l6>;
+		HSUSB_3p3-supply = <&pm8941_l24>;
+		qcom,usb2-enable-hsphy2;
+		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
+		qcom,usb2-enable-uicc;
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index f8c8a69..b880890 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -24,6 +24,9 @@
  - reset-names: reset signal name strings sorted in the same order as the resets
    property.
 
+Optional properties:
+ - qcom,param-override-seq: parameter override sequence with value, reg offset pair.
+
 Example:
 	hsphy@f9200000 {
 		compatible = "qcom,usb-hsphy-snps-femto";
@@ -32,6 +35,7 @@
 		vdda18-supply = <&pm8941_l6>;
 		vdda33-supply = <&pm8941_l24>;
 		qcom,vdd-voltage-level = <0 872000 872000>;
+		qcom,param-override-seq = <0x43 0x70>;
 	};
 
 SSUSB-QMP PHY
@@ -101,6 +105,8 @@
  - qcom,core-voltage-level: This property must be a list of three integer
    values (no, min, max) where each value represents either a voltage in
    microvolts or a value corresponding to voltage corner.
+ - "pcs_clamp_enable_reg" : Clamps the phy data inputs and enables USB3
+   autonomous mode.
 
 Example:
 	ssphy0: ssphy@f9b38000 {
@@ -184,6 +190,11 @@
    state when attached in host mode and "suspend" state when detached.
  - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
    improved rise/fall times.
+ - qcom,host-chirp-erratum: Indicates host chirp fix is required.
+ - nvmem-cells: specifies the handle to represent the SoC revision.
+   usually it is defined by qfprom device node.
+ - nvmem-cell-names: specifies the given nvmem cell name as defined in
+   qfprom node.
 
 Example:
 	qusb_phy: qusb@f9b39000 {
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index e996ba5..01acb65 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -161,6 +161,7 @@
 linux	Linux-specific binding
 lltc	Linear Technology Corporation
 lsi	LSI Corp. (LSI Logic)
+lt	Lontium Semiconductor Corporation
 marvell	Marvell Technology Group Ltd.
 maxim	Maxim Integrated Products
 meas	Measurement Specialties
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9f5bfd6..a226070 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2821,8 +2821,6 @@
 	norandmaps	Don't use address space randomization.  Equivalent to
 			echo 0 > /proc/sys/kernel/randomize_va_space
 
-	noreplace-paravirt	[X86,IA-64,PV_OPS] Don't patch paravirt_ops
-
 	noreplace-smp	[X86-32,SMP] Don't replace SMP instructions
 			with UP alternatives
 
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 7058d43..e52a472 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1502,6 +1502,11 @@
 	Functional default: enabled if accept_ra is enabled.
 			    disabled if accept_ra is disabled.
 
+accept_ra_prefix_route - BOOLEAN
+	Set the prefix route for the autoconfigured interface address
+
+	Functional default: enabled
+
 accept_redirects - BOOLEAN
 	Accept Redirects.
 
diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt
new file mode 100644
index 0000000..e9e6cba
--- /dev/null
+++ b/Documentation/speculation.txt
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+	int load_array(int *array, unsigned int index)
+	{
+		if (index >= MAX_ARRAY_ELEMS)
+			return 0;
+		else
+			return array[index];
+	}
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+	CMP	<index>, #MAX_ARRAY_ELEMS
+	B.LT	less
+	MOV	<returnval>, #0
+	RET
+  less:
+	LDR	<returnval>, [<array>, <index>]
+	RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+	int load_dependent_arrays(int *arr1, int *arr2, int index)
+	{
+		int val1, val2,
+
+		val1 = load_array(arr1, index);
+		val2 = load_array(arr2, val1);
+
+		return val2;
+	}
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+	int load_array(int *array, unsigned int index)
+	{
+		if (index >= MAX_ARRAY_ELEMS)
+			return 0;
+		else {
+			index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+			return array[index];
+		}
+	}
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 95ccbe6..206c9b0 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -30,6 +30,7 @@
 - dirty_writeback_centisecs
 - drop_caches
 - extfrag_threshold
+- extra_free_kbytes
 - hugepages_treat_as_movable
 - hugetlb_shm_group
 - laptop_mode
@@ -240,6 +241,21 @@
 
 ==============================================================
 
+extra_free_kbytes
+
+This parameter tells the VM to keep extra free memory between the threshold
+where background reclaim (kswapd) kicks in, and the threshold where direct
+reclaim (by allocating processes) kicks in.
+
+This is useful for workloads that require low latency memory allocations
+and have a bounded burstiness in memory allocations, for example a
+realtime application that receives and transmits network traffic
+(causing in-kernel memory allocations) with a maximum total message burst
+size of 200MB may need 200MB of extra free memory to avoid direct reclaim
+related latencies.
+
+==============================================================
+
 hugepages_treat_as_movable
 
 This parameter controls whether we can allocate hugepages from ZONE_MOVABLE
diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt
index d11eff6..5cd5843 100644
--- a/Documentation/x86/pti.txt
+++ b/Documentation/x86/pti.txt
@@ -78,7 +78,7 @@
      non-PTI SYSCALL entry code, so requires mapping fewer
      things into the userspace page tables.  The downside is
      that stacks must be switched at entry time.
-  d. Global pages are disabled for all kernel structures not
+  c. Global pages are disabled for all kernel structures not
      mapped into both kernel and userspace page tables.  This
      feature of the MMU allows different processes to share TLB
      entries mapping the kernel.  Losing the feature means more
diff --git a/Makefile b/Makefile
index cf9657e..42db02e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 77
+SUBLEVEL = 82
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
index 2b0ac42..412bb3c 100644
--- a/arch/alpha/kernel/pci_impl.h
+++ b/arch/alpha/kernel/pci_impl.h
@@ -143,7 +143,8 @@
 };
 
 #if defined(CONFIG_ALPHA_SRM) && \
-    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
+    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+     defined(CONFIG_ALPHA_AVANTI))
 # define NEED_SRM_SAVE_RESTORE
 #else
 # undef NEED_SRM_SAVE_RESTORE
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index b483156..60c17b9 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -265,12 +265,13 @@
 	   application calling fork.  */
 	if (clone_flags & CLONE_SETTLS)
 		childti->pcb.unique = regs->r20;
+	else
+		regs->r20 = 0;	/* OSF/1 has some strange fork() semantics.  */
 	childti->pcb.usp = usp ?: rdusp();
 	*childregs = *regs;
 	childregs->r0 = 0;
 	childregs->r19 = 0;
 	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.  */
-	regs->r20 = 0;
 	stack = ((struct switch_stack *) regs) - 1;
 	*childstack = *stack;
 	childstack->r26 = (unsigned long) ret_from_fork;
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 74aceea..32ba92c 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -158,11 +158,16 @@
 	for(i=0; i < kstack_depth_to_print; i++) {
 		if (((long) stack & (THREAD_SIZE-1)) == 0)
 			break;
-		if (i && ((i % 4) == 0))
-			printk("\n       ");
-		printk("%016lx ", *stack++);
+		if ((i % 4) == 0) {
+			if (i)
+				pr_cont("\n");
+			printk("       ");
+		} else {
+			pr_cont(" ");
+		}
+		pr_cont("%016lx", *stack++);
 	}
-	printk("\n");
+	pr_cont("\n");
 	dik_show_trace(sp);
 }
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d8d8b82..41245ce 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -12,6 +12,7 @@
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select ARCH_WANT_IPC_PARSE_VERSION
+	select ARM_PSCI_FW if PM
 	select BUILDTIME_EXTABLE_SORT if MMU
 	select CLONE_BACKWARDS
 	select CPU_PM if (SUSPEND || CPU_IDLE)
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index 7c9e0fa..65e0db1 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -85,7 +85,7 @@
 		timer@20200 {
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0x20200 0x100>;
-			interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
 			clocks = <&periph_clk>;
 		};
 
@@ -93,7 +93,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x20600 0x20>;
 			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
-						  IRQ_TYPE_LEVEL_HIGH)>;
+						  IRQ_TYPE_EDGE_RISING)>;
 			clocks = <&periph_clk>;
 		};
 
diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
index cf2f524..27cc913 100644
--- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
+++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
@@ -53,7 +53,8 @@
 		};
 
 		pinctrl: pin-controller@10000 {
-			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
+			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header
+				     &pmx_gpio_header_gpo>;
 			pinctrl-names = "default";
 
 			pmx_uart0: pmx-uart0 {
@@ -85,11 +86,16 @@
 			 * ground.
 			 */
 			pmx_gpio_header: pmx-gpio-header {
-				marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28",
+				marvell,pins = "mpp17", "mpp29", "mpp28",
 					       "mpp35", "mpp34", "mpp40";
 				marvell,function = "gpio";
 			};
 
+			pmx_gpio_header_gpo: pxm-gpio-header-gpo {
+				marvell,pins = "mpp7";
+				marvell,function = "gpo";
+			};
+
 			pmx_gpio_init: pmx-init {
 				marvell,pins = "mpp38";
 				marvell,function = "gpio";
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index c51581d..28b2ec2 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,7 +1,11 @@
 
 dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \
 	sdxpoorwills-cdp.dtb \
-	sdxpoorwills-mtp.dtb
+	sdxpoorwills-mtp.dtb \
+	sdxpoorwills-cdp-256.dtb \
+	sdxpoorwills-mtp-256.dtb \
+	sdxpoorwills-pcie-ep-cdp.dtb \
+	sdxpoorwills-pcie-ep-mtp.dtb
 
 targets += dtbs
 targets += $(addprefix ../, $(dtb-y))
diff --git a/arch/arm/boot/dts/qcom/msm-gdsc.dtsi b/arch/arm/boot/dts/qcom/msm-gdsc.dtsi
new file mode 100644
index 0000000..9a1f32e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-gdsc.dtsi
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012-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.
+ */
+
+&soc {
+	gdsc_venus: qcom,gdsc@fd8c1024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus";
+		reg = <0xfd8c1024 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_venus_core0: qcom,gdsc@fd8c1040 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus_core0";
+		reg = <0xfd8c1040 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_venus_core1: qcom,gdsc@fd8c1044 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus_core1";
+		reg = <0xfd8c1044 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_venus_core2: qcom,gdsc@fd8c1050 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus_core2";
+		reg = <0xfd8c1050 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_vpu: qcom,gdsc@fd8c1404 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vpu";
+		reg = <0xfd8c1404 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_camss_top: qcom,gdsc@fd8c34a0 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_camss_top";
+		reg = <0xfd8c34a0 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_mdss: qcom,gdsc@fd8c2304 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_mdss";
+		reg = <0xfd8c2304 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_jpeg: qcom,gdsc@fd8c35a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_jpeg";
+		reg = <0xfd8c35a4 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_vfe: qcom,gdsc@fd8c36a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vfe";
+		reg = <0xfd8c36a4 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_cpp: qcom,gdsc@fd8c36d4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_cpp";
+		reg = <0xfd8c36d4 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		reg = <0xfd8c4024 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_oxili_cx: qcom,gdsc@fd8c4034 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_cx";
+		reg = <0xfd8c4034 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_usb_hsic: qcom,gdsc@fc400404 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb_hsic";
+		reg = <0xfc400404 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_pcie: qcom,gdsc@0xfc401e18 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_pcie";
+		reg = <0xfc401e18 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_pcie_0: qcom,gdsc@fc401ac4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_pcie_0";
+		reg = <0xfc401ac4 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_pcie_1: qcom,gdsc@fc401b44 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_pcie_1";
+		reg = <0xfc401b44 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_usb30: qcom,gdsc@fc401e84 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb30";
+		reg = <0xfc401e84 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_usb30_sec: qcom,gdsc@fc401ec0 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb30_sec";
+		reg = <0xfc401ec0 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_vcap: qcom,gdsc@fd8c1804 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vcap";
+		reg = <0xfd8c1804 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_bcss: qcom,gdsc@fc744128 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_bcss";
+		reg = <0xfc744128 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_ufs: qcom,gdsc@fc401d44 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_ufs";
+		reg = <0xfc401d44 0x4>;
+		status = "disabled";
+	};
+
+	gdsc_fd: qcom,gdsc@fd8c3b64 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_fd";
+		reg = <0xfd8c3b64 0x4>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/pm8950.dtsi b/arch/arm/boot/dts/qcom/pm8950.dtsi
deleted file mode 100644
index f47872a..0000000
--- a/arch/arm/boot/dts/qcom/pm8950.dtsi
+++ /dev/null
@@ -1,388 +0,0 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-&spmi_bus {
-	qcom,pm8950@0 {
-		compatible ="qcom,spmi-pmic";
-		reg = <0x0 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
-
-		pm8950_revid: qcom,revid@100 {
-			compatible = "qcom,qpnp-revid";
-			reg = <0x100 0x100>;
-		};
-
-		pm8950_temp_alarm: qcom,temp-alarm@2400 {
-			compatible = "qcom,qpnp-temp-alarm";
-			reg = <0x2400 0x100>;
-			interrupts = <0x0 0x24 0x0>;
-			label = "pm8950_tz";
-			qcom,channel-num = <8>;
-			qcom,threshold-set = <0>;
-			qcom,temp_alarm-vadc = <&pm8950_vadc>;
-		};
-
-		qcom,power-on@800 {
-			compatible = "qcom,qpnp-power-on";
-			reg = <0x800 0x100>;
-			interrupts = <0x0 0x8 0x0>,
-				<0x0 0x8 0x1>,
-				<0x0 0x8 0x4>,
-				<0x0 0x8 0x5>;
-			interrupt-names = "kpdpwr", "resin",
-				"resin-bark", "kpdpwr-resin-bark";
-			qcom,pon-dbc-delay = <15625>;
-			qcom,system-reset;
-
-			qcom,pon_1 {
-				qcom,pon-type = <0>;
-				qcom,pull-up = <1>;
-				linux,code = <116>;
-			};
-
-			qcom,pon_2 {
-				qcom,pon-type = <1>;
-				qcom,pull-up = <1>;
-				linux,code = <114>;
-			};
-		};
-
-		pm8950_coincell: qcom,coincell@2800 {
-			compatible = "qcom,qpnp-coincell";
-			reg = <0x2800 0x100>;
-		};
-
-		pm8950_mpps: mpps {
-			compatible = "qcom,qpnp-pin";
-			spmi-dev-container;
-			gpio-controller;
-			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8950-mpp";
-
-			mpp@a000 {
-				reg = <0xa000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			mpp@a100 {
-				/* MPP2 - PA_THERM config */
-				reg = <0xa100 0x100>;
-				qcom,pin-num = <2>;
-				qcom,mode = <4>; /* AIN input */
-				qcom,invert = <1>; /* Enable MPP */
-				qcom,ain-route = <1>; /* AMUX 6 */
-				qcom,master-en = <1>;
-				qcom,src-sel = <0>; /* Function constant */
-			};
-
-			mpp@a200 {
-				reg = <0xa200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			mpp@a300 {
-				/* MPP4 - CASE_THERM config */
-				reg = <0xa300 0x100>;
-				qcom,pin-num = <4>;
-				qcom,mode = <4>; /* AIN input */
-				qcom,invert = <1>; /* Enable MPP */
-				qcom,ain-route = <3>; /* AMUX 8 */
-				qcom,master-en = <1>;
-				qcom,src-sel = <0>; /* Function constant */
-			};
-		};
-
-		pm8950_gpios: gpios {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
-			gpio-controller;
-			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8950-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			gpio@c200 {
-				reg = <0xc200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			gpio@c300 {
-				reg = <0xc300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
-
-			gpio@c400 {
-				reg = <0xc400 0x100>;
-				qcom,pin-num = <5>;
-				status = "disabled";
-			};
-
-			gpio@c500 {
-				reg = <0xc500 0x100>;
-				qcom,pin-num = <6>;
-				status = "disabled";
-			};
-
-			gpio@c600 {
-				reg = <0xc600 0x100>;
-				qcom,pin-num = <7>;
-				status = "disabled";
-			};
-
-			gpio@c700 {
-				reg = <0xc700 0x100>;
-				qcom,pin-num = <8>;
-				status = "disabled";
-			};
-		};
-
-		pm8950_vadc: vadc@3100 {
-			compatible = "qcom,qpnp-vadc";
-			reg = <0x3100 0x100>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			interrupts = <0x0 0x31 0x0>;
-			interrupt-names = "eoc-int-en-set";
-			qcom,adc-bit-resolution = <15>;
-			qcom,adc-vdd-reference = <1800>;
-			qcom,vadc-poll-eoc;
-			qcom,pmic-revid = <&pm8950_revid>;
-
-			chan@5 {
-				label = "vcoin";
-				reg = <5>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@7 {
-				label = "vph_pwr";
-				reg = <7>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@8 {
-				label = "die_temp";
-				reg = <8>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <3>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@9 {
-				label = "ref_625mv";
-				reg = <9>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@a {
-				label = "ref_1250v";
-				reg = <0xa>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@c {
-				label = "ref_buf_625mv";
-				reg = <0xc>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@36 {
-				label = "pa_therm0";
-				reg = <0x36>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@11 {
-				label = "pa_therm1";
-				reg = <0x11>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
-			};
-
-			chan@32 {
-				label = "xo_therm";
-				reg = <0x32>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <4>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
-			};
-
-			chan@3c {
-				label = "xo_therm_buf";
-				reg = <0x3c>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <4>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
-			};
-
-			chan@13 {
-				label = "case_therm";
-				reg = <0x13>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
-			};
-		};
-
-		pm8950_adc_tm: vadc@3400 {
-			compatible = "qcom,qpnp-adc-tm";
-			reg = <0x3400 0x100>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			interrupts =	<0x0 0x34 0x0>,
-					<0x0 0x34 0x3>,
-					<0x0 0x34 0x4>;
-			interrupt-names =	"eoc-int-en-set",
-						"high-thr-en-set",
-						"low-thr-en-set";
-			qcom,adc-bit-resolution = <15>;
-			qcom,adc-vdd-reference = <1800>;
-			qcom,adc_tm-vadc = <&pm8950_vadc>;
-			qcom,pmic-revid = <&pm8950_revid>;
-
-			chan@36 {
-				label = "pa_therm0";
-				reg = <0x36>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "ratiometric";
-				qcom,scale-function = <2>;
-				qcom,hw-settle-time = <2>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x48>;
-				qcom,thermal-node;
-			};
-
-			chan@7 {
-				label = "vph_pwr";
-				reg = <0x7>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-				qcom,btm-channel-number = <0x68>;
-			};
-		};
-
-		pm8950_rtc: qcom,pm8950_rtc {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-rtc";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			qcom,qpnp-rtc-write = <0>;
-			qcom,qpnp-rtc-alarm-pwrup = <0>;
-
-			qcom,pm8950_rtc_rw@6000 {
-				reg = <0x6000 0x100>;
-			};
-
-			qcom,pm8950_rtc_alarm@6100 {
-				reg = <0x6100 0x100>;
-				interrupts = <0x0 0x61 0x1>;
-			};
-		};
-
-		qcom,leds@a300 {
-			compatible = "qcom,leds-qpnp";
-			reg = <0xa300 0x100>;
-			label = "mpp";
-		};
-	};
-
-	pm8950_1: qcom,pm8950@1 {
-		compatible ="qcom,spmi-pmic";
-		reg = <0x1 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
-
-		pm8950_pwm: pwm@bc00 {
-			status = "disabled";
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xbc00 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <0>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/qcom/pmi8950.dtsi b/arch/arm/boot/dts/qcom/pmi8950.dtsi
deleted file mode 100644
index 0ec1f0b..0000000
--- a/arch/arm/boot/dts/qcom/pmi8950.dtsi
+++ /dev/null
@@ -1,641 +0,0 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <dt-bindings/msm/power-on.h>
-
-&spmi_bus {
-	qcom,pmi8950@2 {
-		compatible ="qcom,spmi-pmic";
-		reg = <0x2 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
-
-		pmi8950_revid: qcom,revid@100 {
-			compatible = "qcom,qpnp-revid";
-			reg = <0x100 0x100>;
-		};
-
-		qcom,power-on@800 {
-			compatible = "qcom,qpnp-power-on";
-			reg = <0x800 0x100>;
-			qcom,secondary-pon-reset;
-			qcom,hard-reset-poweroff-type =
-				<PON_POWER_OFF_SHUTDOWN>;
-
-			pon_perph_reg: qcom,pon_perph_reg {
-				regulator-name = "pon_spare_reg";
-				qcom,pon-spare-reg-addr = <0x8c>;
-				qcom,pon-spare-reg-bit = <1>;
-			};
-		};
-
-		pmi8950_vadc: vadc@3100 {
-			compatible = "qcom,qpnp-vadc";
-			reg = <0x3100 0x100>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			interrupts = <0x2 0x31 0x0>;
-			interrupt-names = "eoc-int-en-set";
-			qcom,adc-bit-resolution = <15>;
-			qcom,adc-vdd-reference = <1800>;
-			qcom,vadc-poll-eoc;
-
-			chan@0 {
-				label = "usbin";
-				reg = <0>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <4>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@1 {
-				label = "dcin";
-				reg = <1>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <4>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@3 {
-				label = "vchg_sns";
-				reg = <3>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@9 {
-				label = "ref_625mv";
-				reg = <9>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@a {
-				label = "ref_1250v";
-				reg = <0xa>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@d {
-				label = "chg_temp";
-				reg = <0xd>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <0>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <16>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
-			};
-
-			chan@43 {
-				label = "usb_dp";
-				reg = <0x43>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-
-			chan@44 {
-				label = "usb_dm";
-				reg = <0x44>;
-				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
-				qcom,calibration-type = "absolute";
-				qcom,scale-function = <0>;
-				qcom,hw-settle-time = <0>;
-				qcom,fast-avg-setup = <0>;
-			};
-		};
-
-		pmi8950_gpios: gpios {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
-			gpio-controller;
-			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pmi8950-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-		};
-
-		pmi8950_mpps: mpps {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
-			gpio-controller;
-			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pmi8950-mpp";
-
-			mpp@a000 {
-				reg = <0xa000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			mpp@a100 {
-				reg = <0xa100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			mpp@a200 {
-				reg = <0xa200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			mpp@a300 {
-				reg = <0xa300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
-		};
-
-		pmi8950_charger: qcom,qpnp-smbcharger {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-smbcharger";
-			#address-cells = <1>;
-			#size-cells = <1>;
-
-			qcom,iterm-ma = <100>;
-			qcom,float-voltage-mv = <4200>;
-			qcom,resume-delta-mv = <200>;
-			qcom,chg-inhibit-fg;
-			qcom,rparasitic-uohm = <100000>;
-			qcom,bms-psy-name = "bms";
-			qcom,thermal-mitigation = <1500 700 600 0>;
-			qcom,parallel-usb-min-current-ma = <1400>;
-			qcom,parallel-usb-9v-min-current-ma = <900>;
-			qcom,parallel-allowed-lowering-ma = <500>;
-			qcom,pmic-revid = <&pmi8950_revid>;
-			qcom,force-aicl-rerun;
-			qcom,aicl-rerun-period-s = <180>;
-			qcom,autoadjust-vfloat;
-
-			qcom,chgr@1000 {
-				reg = <0x1000 0x100>;
-				interrupts =	<0x2 0x10 0x0>,
-						<0x2 0x10 0x1>,
-						<0x2 0x10 0x2>,
-						<0x2 0x10 0x3>,
-						<0x2 0x10 0x4>,
-						<0x2 0x10 0x5>,
-						<0x2 0x10 0x6>,
-						<0x2 0x10 0x7>;
-
-				interrupt-names =	"chg-error",
-							"chg-inhibit",
-							"chg-prechg-sft",
-							"chg-complete-chg-sft",
-							"chg-p2f-thr",
-							"chg-rechg-thr",
-							"chg-taper-thr",
-							"chg-tcc-thr";
-			};
-
-			qcom,otg@1100 {
-				reg = <0x1100 0x100>;
-				interrupts =	<0x2 0x11 0x0>,
-						<0x2 0x11 0x1>,
-						<0x2 0x11 0x3>;
-				interrupt-names =	"otg-fail",
-							"otg-oc",
-						"usbid-change";
-			};
-
-			qcom,bat-if@1200 {
-				reg = <0x1200 0x100>;
-				interrupts =	<0x2 0x12 0x0>,
-						<0x2 0x12 0x1>,
-						<0x2 0x12 0x2>,
-						<0x2 0x12 0x3>,
-					<0x2 0x12 0x4>,
-						<0x2 0x12 0x5>,
-						<0x2 0x12 0x6>,
-						<0x2 0x12 0x7>;
-
-				interrupt-names =	"batt-hot",
-							"batt-warm",
-							"batt-cold",
-							"batt-cool",
-						"batt-ov",
-							"batt-low",
-							"batt-missing",
-							"batt-term-missing";
-			};
-
-			qcom,usb-chgpth@1300 {
-				reg = <0x1300 0x100>;
-				interrupts =	<0x2 0x13 0x0>,
-						<0x2 0x13 0x1>,
-					<0x2 0x13 0x2>,
-						<0x2 0x13 0x5>;
-
-				interrupt-names =	"usbin-uv",
-						"usbin-ov",
-							"usbin-src-det",
-							"aicl-done";
-			};
-
-			qcom,dc-chgpth@1400 {
-				reg = <0x1400 0x100>;
-				interrupts =	<0x2 0x14 0x0>,
-						<0x2 0x14 0x1>;
-				interrupt-names =	"dcin-uv",
-							"dcin-ov";
-			};
-
-			qcom,chgr-misc@1600 {
-				reg = <0x1600 0x100>;
-				interrupts =	<0x2 0x16 0x0>,
-						<0x2 0x16 0x1>,
-						<0x2 0x16 0x2>,
-					<0x2 0x16 0x3>,
-						<0x2 0x16 0x4>,
-						<0x2 0x16 0x5>;
-
-				interrupt-names =	"power-ok",
-							"temp-shutdown",
-							"wdog-timeout",
-							"flash-fail",
-							"otst2",
-							"otst3";
-			};
-
-			smbcharger_charger_otg: qcom,smbcharger-boost-otg {
-				regulator-name = "smbcharger_charger_otg";
-			};
-		};
-
-		pmi8950_fg: qcom,fg {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-fg";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			qcom,resume-soc = <95>;
-			status = "okay";
-			qcom,bcl-lm-threshold-ma = <127>;
-			qcom,bcl-mh-threshold-ma = <405>;
-			qcom,fg-iterm-ma = <150>;
-			qcom,fg-chg-iterm-ma = <100>;
-			qcom,pmic-revid = <&pmi8950_revid>;
-			qcom,fg-cutoff-voltage-mv = <3500>;
-			qcom,cycle-counter-en;
-			qcom,capacity-learning-on;
-
-			qcom,fg-soc@4000 {
-			status = "okay";
-				reg = <0x4000 0x100>;
-				interrupts =	<0x2 0x40 0x0>,
-						<0x2 0x40 0x1>,
-						<0x2 0x40 0x2>,
-						<0x2 0x40 0x3>,
-						<0x2 0x40 0x4>,
-						<0x2 0x40 0x5>,
-						<0x2 0x40 0x6>;
-
-				interrupt-names =	"high-soc",
-							"low-soc",
-							"full-soc",
-							"empty-soc",
-							"delta-soc",
-							"first-est-done",
-							"update-soc";
-			};
-
-			qcom,fg-batt@4100 {
-				reg = <0x4100 0x100>;
-				interrupts =	<0x2 0x41 0x0>,
-						<0x2 0x41 0x1>,
-					<0x2 0x41 0x2>,
-						<0x2 0x41 0x3>,
-						<0x2 0x41 0x4>,
-						<0x2 0x41 0x5>,
-						<0x2 0x41 0x6>,
-						<0x2 0x41 0x7>;
-
-				interrupt-names =	"soft-cold",
-							"soft-hot",
-							"vbatt-low",
-							"batt-ided",
-							"batt-id-req",
-							"batt-unknown",
-							"batt-missing",
-							"batt-match";
-			};
-
-			qcom,revid-tp-rev@1f1 {
-				reg = <0x1f1 0x1>;
-			};
-
-			qcom,fg-memif@4400 {
-				status = "okay";
-				reg = <0x4400 0x100>;
-				interrupts =	<0x2 0x44 0x0>,
-						<0x2 0x44 0x2>;
-
-				interrupt-names =	"mem-avail",
-							"data-rcvry-sug";
-			};
-		};
-
-		bcl@4200 {
-			compatible = "qcom,msm-bcl";
-			reg = <0x4200 0xFF 0x88E 0x2>;
-			reg-names = "fg_user_adc", "pon_spare";
-			interrupts = <0x2 0x42 0x0>,
-					<0x2 0x42 0x1>;
-			interrupt-names = "bcl-high-ibat-int",
-					"bcl-low-vbat-int";
-			qcom,vbat-scaling-factor = <39000>;
-			qcom,vbat-gain-numerator = <1>;
-			qcom,vbat-gain-denominator = <128>;
-			qcom,vbat-polling-delay-ms = <100>;
-			qcom,ibat-scaling-factor = <39000>;
-			qcom,ibat-gain-numerator = <1>;
-			qcom,ibat-gain-denominator = <128>;
-			qcom,ibat-offset-numerator = <1200>;
-			qcom,ibat-offset-denominator = <1>;
-			qcom,ibat-polling-delay-ms = <100>;
-			qcom,inhibit-derating-ua = <550000>;
-		};
-
-		qcom,leds@a100 {
-			compatible = "qcom,leds-qpnp";
-			reg = <0xa100 0x100>;
-			label = "mpp";
-		};
-	};
-
-	qcom,pmi8950@3 {
-		compatible ="qcom,spmi-pmic";
-		reg = <0x3 SPMI_USID>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-
-		pmi8950_pwm: pwm@b000 {
-			status = "disabled";
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb000 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <0>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-		};
-
-		labibb: qpnp-labibb-regulator {
-			status = "disabled";
-			spmi-dev-container;
-			compatible = "qcom,qpnp-labibb-regulator";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			qcom,pmic-revid = <&pmi8950_revid>;
-
-			ibb_regulator: qcom,ibb@dc00 {
-				reg = <0xdc00 0x100>;
-				reg-names = "ibb_reg";
-				regulator-name = "ibb_reg";
-
-				regulator-min-microvolt = <4600000>;
-				regulator-max-microvolt = <6000000>;
-
-				qcom,qpnp-ibb-min-voltage = <1400000>;
-				qcom,qpnp-ibb-step-size = <100000>;
-				qcom,qpnp-ibb-slew-rate = <2000000>;
-				qcom,qpnp-ibb-use-default-voltage;
-				qcom,qpnp-ibb-init-voltage = <5500000>;
-				qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
-				qcom,qpnp-ibb-init-lcd-voltage = <5500000>;
-
-				qcom,qpnp-ibb-soft-start = <1000>;
-
-				qcom,qpnp-ibb-discharge-resistor = <32>;
-				qcom,qpnp-ibb-lab-pwrup-delay = <8000>;
-				qcom,qpnp-ibb-lab-pwrdn-delay = <8000>;
-				qcom,qpnp-ibb-en-discharge;
-
-				qcom,qpnp-ibb-full-pull-down;
-				qcom,qpnp-ibb-pull-down-enable;
-				qcom,qpnp-ibb-switching-clock-frequency =
-									<1480>;
-				qcom,qpnp-ibb-limit-maximum-current = <1550>;
-				qcom,qpnp-ibb-debounce-cycle = <16>;
-				qcom,qpnp-ibb-limit-max-current-enable;
-				qcom,qpnp-ibb-ps-enable;
-			};
-
-			lab_regulator: qcom,lab@de00 {
-				reg = <0xde00 0x100>;
-				reg-names = "lab";
-				regulator-name = "lab_reg";
-
-				regulator-min-microvolt = <4600000>;
-				regulator-max-microvolt = <6000000>;
-
-				qcom,qpnp-lab-min-voltage = <4600000>;
-				qcom,qpnp-lab-step-size = <100000>;
-				qcom,qpnp-lab-slew-rate = <5000>;
-				qcom,qpnp-lab-use-default-voltage;
-				qcom,qpnp-lab-init-voltage = <5500000>;
-				qcom,qpnp-lab-init-amoled-voltage = <4600000>;
-				qcom,qpnp-lab-init-lcd-voltage = <5500000>;
-
-				qcom,qpnp-lab-soft-start = <800>;
-
-				qcom,qpnp-lab-full-pull-down;
-				qcom,qpnp-lab-pull-down-enable;
-				qcom,qpnp-lab-switching-clock-frequency =
-									<1600>;
-				qcom,qpnp-lab-limit-maximum-current = <800>;
-				qcom,qpnp-lab-limit-max-current-enable;
-				qcom,qpnp-lab-ps-threshold = <40>;
-				qcom,qpnp-lab-ps-enable;
-				qcom,qpnp-lab-nfet-size = <100>;
-				qcom,qpnp-lab-pfet-size = <100>;
-				qcom,qpnp-lab-max-precharge-time = <500>;
-			};
-
-		};
-
-		wled: qcom,leds@d800 {
-			compatible = "qcom,qpnp-wled";
-			reg = <0xd800 0x100>,
-				<0xd900 0x100>,
-				<0xdc00 0x100>,
-				<0xde00 0x100>;
-			reg-names = "qpnp-wled-ctrl-base",
-					"qpnp-wled-sink-base",
-					"qpnp-wled-ibb-base",
-					"qpnp-wled-lab-base";
-			interrupts = <0x3 0xd8 0x2>;
-			interrupt-names = "sc-irq";
-			status = "okay";
-			linux,name = "wled";
-			linux,default-trigger = "bkl-trigger";
-			qcom,fdbk-output = "auto";
-			qcom,vref-mv = <350>;
-			qcom,switch-freq-khz = <800>;
-			qcom,ovp-mv = <29500>;
-			qcom,ilim-ma = <980>;
-			qcom,boost-duty-ns = <26>;
-			qcom,mod-freq-khz = <9600>;
-			qcom,dim-mode = "hybrid";
-			qcom,dim-method = "linear";
-			qcom,hyb-thres = <625>;
-			qcom,sync-dly-us = <800>;
-			qcom,fs-curr-ua = <20000>;
-			qcom,led-strings-list = [00 01];
-			qcom,en-ext-pfet-sc-pro;
-			qcom,cons-sync-write-delay-us = <1000>;
-		};
-
-		flash_led: qcom,leds@d300 {
-			compatible = "qcom,qpnp-flash-led";
-			status = "okay";
-			reg = <0xd300 0x100>;
-			label = "flash";
-			qcom,headroom = <500>;
-			qcom,startup-dly = <128>;
-			qcom,clamp-curr = <200>;
-			qcom,pmic-charger-support;
-			qcom,self-check-enabled;
-			qcom,thermal-derate-enabled;
-			qcom,thermal-derate-threshold = <100>;
-			qcom,thermal-derate-rate = "5_PERCENT";
-			qcom,current-ramp-enabled;
-			qcom,ramp_up_step = "6P7_US";
-			qcom,ramp_dn_step = "6P7_US";
-			qcom,vph-pwr-droop-enabled;
-			qcom,vph-pwr-droop-threshold = <3000>;
-			qcom,vph-pwr-droop-debounce-time = <10>;
-			qcom,headroom-sense-ch0-enabled;
-			qcom,headroom-sense-ch1-enabled;
-			qcom,pmic-revid = <&pmi8950_revid>;
-
-			pmi8950_flash0: qcom,flash_0 {
-				label = "flash";
-				qcom,led-name = "led:flash_0";
-				qcom,default-led-trigger =
-						"flash0_trigger";
-				qcom,max-current = <1000>;
-				qcom,duration = <1280>;
-				qcom,id = <0>;
-				qcom,current = <625>;
-			};
-
-			pmi8950_flash1: qcom,flash_1 {
-				label = "flash";
-				qcom,led-name = "led:flash_1";
-				qcom,default-led-trigger =
-						"flash1_trigger";
-				qcom,max-current = <1000>;
-				qcom,duration = <1280>;
-				qcom,id = <1>;
-				qcom,current = <625>;
-			};
-
-			pmi8950_torch0: qcom,torch_0 {
-				label = "torch";
-				qcom,led-name = "led:torch_0";
-				qcom,default-led-trigger =
-						"torch0_trigger";
-				qcom,max-current = <200>;
-				qcom,id = <0>;
-				qcom,current = <120>;
-			};
-
-			pmi8950_torch1: qcom,torch_1 {
-				label = "torch";
-				qcom,led-name = "led:torch_1";
-				qcom,default-led-trigger =
-						"torch1_trigger";
-				qcom,max-current = <200>;
-				qcom,id = <1>;
-				qcom,current = <120>;
-			};
-
-			pmi8950_switch: qcom,switch {
-				label = "switch";
-				qcom,led-name = "led:switch";
-				qcom,default-led-trigger =
-						"switch_trigger";
-				qcom,max-current = <1000>;
-				qcom,duration = <1280>;
-				qcom,id = <2>;
-				qcom,current = <625>;
-				reg0 {
-					regulator-name = "pon_spare_reg";
-				};
-			};
-		};
-
-		pmi_haptic: qcom,haptic@c000 {
-			compatible = "qcom,qpnp-haptic";
-			reg = <0xc000 0x100>;
-			interrupts = <0x3 0xc0 0x0>,
-					<0x3 0xc0 0x1>;
-			interrupt-names = "sc-irq", "play-irq";
-			qcom,pmic-revid = <&pmi8950_revid>;
-			vcc_pon-supply = <&pon_perph_reg>;
-			qcom,play-mode = "direct";
-			qcom,wave-play-rate-us = <5263>;
-			qcom,actuator-type = "erm";
-			qcom,wave-shape = "square";
-			qcom,vmax-mv = <2000>;
-			qcom,ilim-ma = <800>;
-			qcom,sc-deb-cycles = <8>;
-			qcom,int-pwm-freq-khz = <505>;
-			qcom,en-brake;
-			qcom,brake-pattern = [03 03 00 00];
-			qcom,use-play-irq;
-			qcom,use-sc-irq;
-			qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e];
-			qcom,wave-rep-cnt = <1>;
-			qcom,wave-samp-rep-cnt = <1>;
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi b/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi
new file mode 100644
index 0000000..e06f398
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/qpic-panel-ili-hvga.dtsi
@@ -0,0 +1,21 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,mdss_lcdc_ili_hvga {
+		compatible = "qcom,mdss-qpic-panel";
+		label = "ili9488 hvga lcdc panel";
+		qcom,mdss-pan-res = <320 480>;
+		qcom,mdss-pan-bpp = <18>;
+		qcom,refresh_rate = <60>;
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
index e6dc45a..ad1e6ca 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -319,7 +319,7 @@
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn2>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_qhm_blsp1: mas-qhm-blsp1 {
@@ -332,7 +332,7 @@
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn3>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_qhm_qdss_bam: mas-qhm-qdss-bam {
@@ -342,20 +342,21 @@
 			qcom,agg-ports = <1>;
 			qcom,qport = <11>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				&slv_qhs_pdm &slv_qhs_pcie_parf
-				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
-				 &slv_qhs_prng &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_snoc_cfg
-				 &slv_qhs_audio &slv_qhs_sdc1
-				 &slv_qhs_aoss &slv_qhs_ipa
-				 &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
-				 &slv_qhs_aop &slv_qhs_tcsr
-				 &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
-				 &slv_qhs_usb3 &slv_qhs_clk_ctl>;
+				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
+				 &slv_qhs_pdm &slv_qns_snoc_memnoc
+				 &slv_qhs_tcsr &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_ipa
+				 &slv_qhs_usb3_phy &slv_qhs_aop
+				 &slv_qhs_blsp1 &slv_qhs_sdc1
+				 &slv_qhs_pcie_parf &slv_qhs_audio
+				 &slv_qhs_tlmm &slv_qhs_prng
+				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+				 &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn8>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_qhm_qpic: mas-qhm-qpic {
@@ -393,17 +394,18 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				&slv_qhs_snoc_cfg &slv_qhs_sdc1
+				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
 				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
 				 &slv_qhs_pdm &slv_qns_snoc_memnoc
 				 &slv_qhs_tcsr &slv_xs_qdss_stm
 				 &slv_qhs_qpic &slv_qxs_imem
 				 &slv_qhs_ipa &slv_qhs_usb3_phy
 				 &slv_qhs_aop &slv_qhs_blsp1
-				 &slv_qhs_pcie_parf &slv_qhs_audio
-				 &slv_qxs_pcie &slv_qhs_tlmm
-				 &slv_qhs_prng &slv_xs_sys_tcu_cfg
-				 &slv_qhs_clk_ctl &slv_qhs_usb3>;
+				 &slv_qhs_sdc1 &slv_qhs_pcie_parf
+				 &slv_qhs_audio &slv_qxs_pcie
+				 &slv_qhs_tlmm &slv_qhs_prng
+				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+				 &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn7>;
 		};
@@ -414,17 +416,17 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				&slv_qhs_snoc_cfg &slv_qhs_sdc1
+				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
 				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
 				 &slv_qhs_pdm &slv_qns_snoc_memnoc
 				 &slv_qhs_tcsr &slv_xs_qdss_stm
 				 &slv_qhs_qpic &slv_qxs_imem
 				 &slv_qhs_ipa &slv_qhs_usb3_phy
 				 &slv_qhs_aop &slv_qhs_blsp1
-				 &slv_qhs_pcie_parf &slv_qhs_audio
-				 &slv_qhs_tlmm &slv_qhs_prng
-				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
-				 &slv_qhs_usb3>;
+				 &slv_qhs_sdc1 &slv_qhs_pcie_parf
+				 &slv_qhs_audio &slv_qhs_tlmm
+				 &slv_qhs_prng &slv_xs_sys_tcu_cfg
+				 &slv_qhs_clk_ctl &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 		};
 
@@ -434,16 +436,17 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				&slv_qhs_pdm &slv_qhs_pcie_parf
-				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
-				 &slv_qhs_prng &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_snoc_cfg
-				 &slv_qhs_audio &slv_qhs_sdc1
-				 &slv_qhs_aoss &slv_qhs_ipa
+				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
+				 &slv_qhs_pdm &slv_qhs_tcsr
+				 &slv_xs_qdss_stm &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_ipa
 				 &slv_qhs_usb3_phy &slv_qhs_aop
-				 &slv_qhs_tcsr &slv_qhs_blsp1
-				 &slv_xs_sys_tcu_cfg &slv_qhs_usb3
-				 &slv_xs_qdss_stm &slv_qhs_clk_ctl>;
+				 &slv_qhs_blsp1 &slv_qhs_sdc1
+				 &slv_qhs_pcie_parf &slv_qhs_audio
+				 &slv_qhs_tlmm &slv_qhs_prng
+				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+				 &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn9>;
 		};
@@ -458,7 +461,7 @@
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_ce>, <&bcm_pn5>;
 			qcom,ap-owned;
-			qcom,prio = <2>;
+			qcom,prio = <0>;
 		};
 
 		mas_qxm_ipa: mas-qxm-ipa {
@@ -471,7 +474,7 @@
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn11>;
 			qcom,ap-owned;
-			qcom,prio = <2>;
+			qcom,prio = <0>;
 			qcom,forwarding;
 		};
 
@@ -484,7 +487,7 @@
 			qcom,connections = <&slv_qxs_pcie>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,ap-owned;
-			qcom,prio = <2>;
+			qcom,prio = <0>;
 		};
 
 		mas_xm_emac: mas-xm-emac {
@@ -496,7 +499,7 @@
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_xm_pcie: mas-xm-pcie {
@@ -508,7 +511,7 @@
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,ap-owned;
-			qcom,prio = <2>;
+			qcom,prio = <0>;
 			qcom,forwarding;
 		};
 
@@ -519,20 +522,21 @@
 			qcom,agg-ports = <1>;
 			qcom,qport = <3>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				&slv_qhs_pdm &slv_qhs_pcie_parf
-				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
-				 &slv_qhs_prng &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_snoc_cfg
-				 &slv_qhs_audio &slv_qhs_sdc1
-				 &slv_qhs_aoss &slv_qhs_ipa
-				 &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
-				 &slv_qhs_aop &slv_qhs_tcsr
-				 &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
-				 &slv_qhs_usb3 &slv_qhs_clk_ctl>;
+				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
+				 &slv_qhs_pdm &slv_qns_snoc_memnoc
+				 &slv_qhs_tcsr &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_ipa
+				 &slv_qhs_usb3_phy &slv_qhs_aop
+				 &slv_qhs_blsp1 &slv_qhs_sdc1
+				 &slv_qhs_pcie_parf &slv_qhs_audio
+				 &slv_qhs_tlmm &slv_qhs_prng
+				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+				 &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn8>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_xm_sdc1: mas-xm-sdc1 {
@@ -545,7 +549,7 @@
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn1>;
 			qcom,ap-owned;
-			qcom,prio = <1>;
+			qcom,prio = <0>;
 		};
 
 		mas_xm_usb3: mas-xm-usb3 {
@@ -557,7 +561,7 @@
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,ap-owned;
-			qcom,prio = <2>;
+			qcom,prio = <0>;
 		};
 
 		/*Internal nodes*/
@@ -656,6 +660,15 @@
 			qcom,bcms = <&bcm_pn0>;
 		};
 
+		slv_qhs_emac_cfg:slv-qhs-emac-cfg {
+			cell-id = <MSM_BUS_SLAVE_EMAC_CFG>;
+			label = "slv-qhs-emac-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_system_noc>;
+			qcom,bcms = <&bcm_pn0>;
+		};
+
 		slv_qhs_ipa:slv-qhs-ipa {
 			cell-id = <MSM_BUS_SLAVE_IPA_CFG>;
 			label = "slv-qhs-ipa";
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
new file mode 100644
index 0000000..04f11ce
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdxpoorwills-cdp-256.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP (256MB)";
+	compatible = "qcom,sdxpoorwills-cdp",
+		"qcom,sdxpoorwills", "qcom,cdp";
+	qcom,board-id = <1 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
new file mode 100644
index 0000000..8a7b771
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
@@ -0,0 +1,13 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills-cdp.dtsi"
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 261829f..99e3faa 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,143 +12,13 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
+#include "sdxpoorwills-display.dtsi"
+#include "qpic-panel-ili-hvga.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
 	compatible = "qcom,sdxpoorwills-cdp",
 		"qcom,sdxpoorwills", "qcom,cdp";
-	qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
-};
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
+	qcom,board-id = <1 0x102>;
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
new file mode 100644
index 0000000..b5944d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
@@ -0,0 +1,144 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
new file mode 100644
index 0000000..c652a44
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
@@ -0,0 +1,1090 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-name = "coresight-csr";
+		qcom,usb-bam-support;
+		qcom,hwctrl-set-support;
+		qcom,set-byte-cntr-support;
+
+		qcom,blk-size = <1>;
+	};
+
+	swao_csr: csr@6b0e000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6b0e000 0x1000>;
+		reg-names = "csr-base";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		coresight-name = "coresight-swao-csr";
+		qcom,timestamp-support;
+
+		qcom,blk-size = <1>;
+	};
+
+	tmc_etr: tmc@6048000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6048000 0x1000>,
+		      <0x6064000 0x15000>;
+		reg-names = "tmc-base", "bam-base";
+
+		arm,buffer-size = <0x400000>;
+		arm,sg-enable;
+
+		coresight-name = "coresight-tmc-etr";
+		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		interrupts = <GIC_SPI 251 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "byte-cntr-irq";
+
+		port {
+			tmc_etr_in_replicator: endpoint {
+				slave-mode;
+				remote-endpoint = <&replicator_out_tmc_etr>;
+			};
+		};
+	};
+
+	replicator_qdss: replicator@6046000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6046000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				replicator_out_tmc_etr: endpoint {
+					remote-endpoint=
+						<&tmc_etr_in_replicator>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				replicator_in_tmc_etf: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&tmc_etf_out_replicator>;
+				};
+			};
+		};
+	};
+
+	tmc_etf: tmc@6047000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6047000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-name = "coresight-tmc-etf";
+		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
+		arm,default-sink;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tmc_etf_out_replicator: endpoint {
+					remote-endpoint =
+						<&replicator_in_tmc_etf>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_in_funnel_merg: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_merg_out_tmc_etf>;
+				};
+			};
+		};
+	};
+
+	funnel_merg: funnel@6045000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6045000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-merg";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_merg_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_merg>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_merg_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_funnel_merg>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_merg_in_funnel_in1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in1_out_funnel_merg>;
+				};
+			};
+		};
+	};
+
+	funnel_in0: funnel@6041000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6041000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_in0_out_funnel_merg: endpoint {
+					remote-endpoint =
+						<&funnel_merg_in_funnel_in0>;
+				};
+			};
+
+			port@1 {
+				reg = <6>;
+				funnel_in0_in_funnel_qatb: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_qatb_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <7>;
+				funnel_in0_in_stm: endpoint {
+					slave-mode;
+					remote-endpoint = <&stm_out_funnel_in0>;
+				};
+			};
+		};
+	};
+
+	stm: stm@6002000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b962>;
+
+		reg = <0x6002000 0x1000>,
+		      <0x16280000 0x180000>;
+		reg-names = "stm-base", "stm-stimulus-base";
+
+		coresight-name = "coresight-stm";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			stm_out_funnel_in0: endpoint {
+				remote-endpoint = <&funnel_in0_in_stm>;
+			};
+		};
+
+	};
+
+	funnel_qatb: funnel@6005000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6005000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-qatb";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_qatb_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_qatb>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_qatb_in_tpda: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_out_funnel_qatb>;
+				};
+			};
+		};
+	};
+
+	tpda: tpda@6004000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6004000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda";
+
+		qcom,tpda-atid = <65>;
+		qcom,bc-elem-size = <10 32>,
+				    <13 32>;
+		qcom,tc-elem-size = <13 32>;
+		qcom,dsb-elem-size = <0 32>,
+				     <2 32>,
+				     <3 32>,
+				     <5 32>,
+				     <6 32>,
+				     <10 32>,
+				     <11 32>,
+				     <13 32>;
+		qcom,cmb-elem-size = <3 64>,
+				     <7 64>,
+				     <9 64>,
+				     <13 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_out_funnel_qatb: endpoint {
+					remote-endpoint =
+						<&funnel_qatb_in_tpda>;
+				};
+
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_in_funnel_ddr_0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_ddr_0_out_tpda>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				tpda_in_tpdm_vsense: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_vsense_out_tpda>;
+				};
+			};
+
+			port@3 {
+				reg = <2>;
+				tpda_in_tpdm_dcc: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_dcc_out_tpda>;
+				};
+			};
+
+			port@4 {
+				reg = <5>;
+				tpda_in_tpdm_center: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_center_out_tpda>;
+				};
+			};
+		};
+	};
+
+	funnel_ddr_0: funnel@69e2000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x69e2000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-ddr-0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_ddr_0_out_tpda: endpoint {
+					remote-endpoint =
+					    <&tpda_in_funnel_ddr_0>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_ddr_0_in_tpdm_ddr: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&tpdm_ddr_out_funnel_ddr_0>;
+				};
+			};
+		};
+	};
+
+	tpdm_dcc: tpdm@6870280 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6870280 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-dcc";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_dcc_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_dcc>;
+			};
+		};
+	};
+
+	tpdm_vsense: tpdm@6840000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6840000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-vsense";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_vsense_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_vsense>;
+			};
+		};
+	};
+
+	tpdm_center: tpdm@6c28000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6c28000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-center";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_center_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_center>;
+			};
+		};
+	};
+
+	tpdm_ddr: tpdm@69e0000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x69e0000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-ddr";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,msr-fix-req;
+
+		port {
+			tpdm_ddr_out_funnel_ddr_0: endpoint {
+				remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>;
+			};
+		};
+	};
+
+	funnel_in1: funnel@6042000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6042000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_in1_out_funnel_merg: endpoint {
+					remote-endpoint =
+						<&funnel_merg_in_funnel_in1>;
+				};
+			};
+
+			port@1 {
+				reg = <2>;
+				funnel_in1_in_funnel_swao: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_swao_out_funnel_in1>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_in1_in_modem_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&modem_etm0_out_funnel_in1>;
+				};
+			};
+
+			port@3 {
+				reg = <7>;
+				funnel_in1_in_tpda_modem: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_modem_out_funnel_in1>;
+				};
+			};
+		};
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-name = "coresight-modem-etm0";
+		qcom,inst-id = <2>;
+
+		port {
+			modem_etm0_out_funnel_in1: endpoint {
+				remote-endpoint =
+					<&funnel_in1_in_modem_etm0>;
+			};
+		};
+	};
+
+	funnel_swao:funnel@6b08000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6b08000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-swao";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_swao_out_funnel_in1: endpoint {
+					remote-endpoint =
+						<&funnel_in1_in_funnel_swao>;
+				};
+			};
+
+			port@1 {
+				reg = <7>;
+				funnel_swao_in_tpda_swao: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&tpda_swao_out_funnel_swao>;
+				};
+			};
+		};
+	};
+
+	tpda_modem: tpda@6832000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6832000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-modem";
+
+		qcom,tpda-atid = <67>;
+		qcom,dsb-elem-size = <0 32>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_modem_out_funnel_in1: endpoint {
+					remote-endpoint =
+						<&funnel_in1_in_tpda_modem>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_modem_in_tpdm_modem: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_modem_out_tpda_modem>;
+				};
+			};
+		};
+	};
+
+	tpdm_modem: tpdm@6830000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6830000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-modem";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_modem_out_tpda_modem: endpoint {
+				remote-endpoint = <&tpda_modem_in_tpdm_modem>;
+			};
+		};
+	};
+
+	tpda_swao: tpda@6b01000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6b01000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-swao";
+
+		qcom,tpda-atid = <71>;
+		qcom,dsb-elem-size = <1 32>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tpda_swao_out_funnel_swao: endpoint {
+					remote-endpoint =
+						<&funnel_swao_in_tpda_swao>;
+				};
+
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_swao_in_tpdm_swao0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao0_out_tpda_swao>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				tpda_swao_in_tpdm_swao1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao1_out_tpda_swao>;
+				};
+
+			};
+		};
+	};
+
+	tpdm_swao0: tpdm@6b02000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+
+		reg = <0x6b02000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-swao-0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_swao0_out_tpda_swao: endpoint {
+				remote-endpoint = <&tpda_swao_in_tpdm_swao0>;
+			};
+		};
+	};
+
+	tpdm_swao1: tpdm@6b03000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6b03000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name="coresight-tpdm-swao-1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,msr-fix-req;
+
+		port {
+			tpdm_swao1_out_tpda_swao: endpoint {
+				remote-endpoint = <&tpda_swao_in_tpdm_swao1>;
+			};
+		};
+	};
+
+	ipcb_tgu: tgu@6b0c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b999>;
+		reg = <0x6b0c000 0x1000>;
+		reg-names = "tgu-base";
+		tgu-steps = <3>;
+		tgu-conditions = <4>;
+		tgu-regs = <4>;
+		tgu-timer-counters = <8>;
+
+		coresight-name = "coresight-tgu-ipcb";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0: cti@6010000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6010000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti1: cti@6011000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6011000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti2: cti@6012000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6012000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3: cti@6013000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6013000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti3";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti4: cti@6014000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6014000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti4";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti5: cti@6015000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6015000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti5";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti6: cti@6016000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6016000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti6";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti7: cti@6017000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6017000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti7";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti8: cti@6018000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6018000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti8";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti9: cti@6019000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6019000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti9";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti10: cti@601a000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601a000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti10";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti11: cti@601b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601b000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti11";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti12: cti@601c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti12";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti13: cti@601d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601d000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti13";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti14: cti@601e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601e000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti14";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti15: cti@601f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601f000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti15";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti_cpu0: cti@7003000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x7003000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu0";
+		cpu = <&CPU0>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti_modem_cpu0:cti@6837000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6837000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-modem-cpu0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu1:cti@683b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x683b000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-modem-cpu1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_swao:cti@6b04000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b04000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1_swao:cti@6b05000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b05000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2_swao:cti@6b06000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b06000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3_swao:cti@6b07000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b07000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti3";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_ddr0: cti@69e1000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e1000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_0_cti";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_ddr1: cti@69e4000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e4000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1_ddr1: cti@69e5000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e5000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2_ddr1: cti@69e6000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e6000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	hwevent: hwevent@0x014066f0 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0x14066f0 0x4>,
+		      <0x14166f0 0x4>,
+		      <0x1406038 0x4>,
+		      <0x1416038 0x4>;
+		reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
+			    "ddr-ch23-ctrl";
+
+		coresight-name = "coresight-hwevent";
+		coresight-csr = <&csr>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi
new file mode 100644
index 0000000..e63d9d5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-display.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2018, 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.
+ */
+
+/ {
+	mdss_qpic: qcom,msm_qpic@7980000 {
+		compatible = "qcom,mdss_qpic";
+		reg = <0x1B00000 0x24000>;
+		reg-names = "qpic_base";
+		interrupts = <0 251 0>;
+
+		qcom,msm-bus,name = "mdss_qpic";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+
+		qcom,msm-bus,vectors-KBps =
+			<91 512 0 0>,
+			/* Voting for max b/w on PNOC bus for now */
+			<91 512 400000 800000>;
+
+		vdd-supply = <&pmxpoorwills_l6>;
+
+		pinctrl-names= "mdss_default", "mdss_sleep";
+		pinctrl-0 = <&mdss_cs_active &mdss_te_active
+			&mdss_rs_active &mdss_ad_active &mdss_bl_active>;
+		pinctrl-1 = <&mdss_cs_sleep &mdss_te_sleep
+			&mdss_rs_sleep &mdss_ad_sleep &mdss_bl_sleep>;
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
new file mode 100644
index 0000000..2377d79c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdxpoorwills-mtp-256.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP (256MB)";
+	compatible = "qcom,sdxpoorwills-mtp",
+		"qcom,sdxpoorwills", "qcom,mtp";
+	qcom,board-id = <8 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
new file mode 100644
index 0000000..4a2ece8c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
@@ -0,0 +1,13 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills-mtp.dtsi"
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi
new file mode 100644
index 0000000..5b3e0b5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills-audio-overlay.dtsi"
+
+&soc {
+	sound-tavil {
+		qcom,wsa-max-devs = <1>;
+		qcom,wsa-devs = <&wsa881x_0214>;
+		qcom,wsa-aux-dev-prefix = "SpkrRight";
+	};
+};
+
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index 575febe..ae3de38 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,142 +12,11 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
 	compatible = "qcom,sdxpoorwills-mtp",
 		"qcom,sdxpoorwills", "qcom,mtp";
-	qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
-};
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
+	qcom,board-id = <8 0x102>;
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
new file mode 100644
index 0000000..63cc3a4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
@@ -0,0 +1,144 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
new file mode 100644
index 0000000..52eaba3
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -0,0 +1,43 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdxpoorwills-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP CDP";
+	compatible = "qcom,sdxpoorwills-cdp",
+		"qcom,sdxpoorwills", "qcom,cdp";
+	qcom,board-id = <1 0x1>, <1 0x101>;
+};
+
+&vbus_detect {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&vbus_detect>;
+};
+
+&pcie_ep {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "disabled";
+};
+
+&mhi_device {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
new file mode 100644
index 0000000..b68e401
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -0,0 +1,43 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdxpoorwills-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP MTP";
+	compatible = "qcom,sdxpoorwills-mtp",
+		"qcom,sdxpoorwills", "qcom,mtp";
+	qcom,board-id = <8 0x1>, <8 0x101>;
+};
+
+&vbus_detect {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&vbus_detect>;
+};
+
+&pcie_ep {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "disabled";
+};
+
+&mhi_device {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index 1e212b7..08c6c3b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -13,11 +13,13 @@
 &soc {
 	tlmm: pinctrl@3900000 {
 		compatible = "qcom,sdxpoorwills-pinctrl";
-		reg = <0x3900000 0x300000>;
+		reg = <0x3900000 0x300000>,
+			<0xB204900 0x280>;
 		interrupts = <0 212 0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
+		interrupt-parent = <&pdc>;
 		#interrupt-cells = <2>;
 
 		uart2_console_active: uart2_console_active {
@@ -982,6 +984,44 @@
 			};
 		};
 
+		pcie_ep {
+			pcie_ep_clkreq_default: pcie_ep_clkreq_default {
+				mux {
+					pins = "gpio56";
+					function = "pcie_clkreq";
+				};
+				config {
+					pins = "gpio56";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			pcie_ep_perst_default: pcie_ep_perst_default {
+				mux {
+					pins = "gpio57";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio57";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			pcie_ep_wake_default: pcie_ep_wake_default {
+				mux {
+					pins = "gpio53";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio53";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		wcd9xxx_intr {
 			wcd_intr_default: wcd_intr_default{
 				mux {
@@ -1308,6 +1348,138 @@
 			};
 		};
 
+		mdss_cs_active: mdss_cs_active {
+			mux {
+					pins = "gpio21";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio21";
+					drive-strength = <10>; /* 10 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_cs_sleep: mdss_cs_sleep {
+			mux {
+					pins = "gpio21";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio21";
+					drive-strength = <2>; /* 2 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_te_active: mdss_te_active {
+			mux {
+					pins = "gpio22";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio22";
+					drive-strength = <10>; /* 10 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_te_sleep: mdss_te_sleep {
+			mux {
+					pins = "gpio22";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio22";
+					drive-strength = <2>; /* 2 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_rs_active: mdss_rs_active {
+			mux {
+					pins = "gpio23";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio23";
+					drive-strength = <10>; /* 10 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_rs_sleep: mdss_rs_sleep {
+			mux {
+					pins = "gpio23";
+					function = "ebi2_lcd";
+			};
+
+			config {
+					pins = "gpio23";
+					drive-strength = <2>; /* 2 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_ad_active: mdss_ad_active {
+			mux {
+					pins = "gpio20";
+					function = "ebi2_a";
+			};
+
+			config {
+					pins = "gpio20";
+					drive-strength = <10>; /* 10 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_ad_sleep: mdss_ad_sleep {
+			mux {
+					pins = "gpio20";
+					function = "ebi2_a";
+			};
+
+			config {
+					pins = "gpio20";
+					drive-strength = <2>; /* 2 mA */
+					bias-disable; /* NO pull */
+			};
+		};
+
+		mdss_bl_active: mdss_bl_active {
+			mux {
+					pins = "gpio91";
+					function = "gpio";
+			};
+
+			config {
+					pins = "gpio91";
+					drive-strength = <10>; /* 10 mA */
+					bias-disable; /* NO pull */
+					output-high;
+			};
+		};
+
+		mdss_bl_sleep: mdss_bl_sleep {
+			mux {
+					pins = "gpio91";
+					function = "gpio";
+			};
+
+			config {
+					pins = "gpio91";
+					drive-strength = <2>; /* 2 mA */
+					bias-disable; /* NO pull */
+					output-low;
+			};
+		};
+
 		pmx_sec_mi2s_aux_din {
 			sec_din_sleep: sec_din_sleep {
 				mux {
@@ -1425,6 +1597,64 @@
 				input-enable;
 			};
 		};
+
+		cnss_pins {
+			cnss_wlan_en_active: cnss_wlan_en_active {
+				mux {
+					pins = "gpio52";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio52";
+					drive-strength = <16>;
+					output-high;
+					bias-pull-up;
+				};
+			};
+
+			cnss_wlan_en_sleep: cnss_wlan_en_sleep {
+				mux {
+					pins = "gpio52";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio52";
+					drive-strength = <2>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+
+			cnss_sdio_active: cnss_sdio_active {
+				mux {
+					pins = "gpio31";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31";
+					drive-strength = <16>;
+					output-high;
+					bias-pull-up;
+				};
+			};
+
+			cnss_sdio_sleep: cnss_sdio_sleep {
+				mux {
+					pins = "gpio31";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31";
+					drive-strength = <2>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+		};
 	};
 };
 
@@ -1435,4 +1665,11 @@
 			bias-high-impedance;
 		};
 	};
+
+	vdd_wlan {
+		vdd_wlan_default: vdd_wlan_default {
+			pins = "gpio6";
+			bias-high-impedance;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
new file mode 100644
index 0000000..4111071
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
@@ -0,0 +1,101 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,pm-cluster@0{
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			label = "system";
+			qcom,psci-mode-shift = <0>;
+			qcom,psci-mode-mask = <0xf>;
+
+			qcom,pm-cluster-level@0 {
+				reg = <0>;
+				label = "cx_active";
+				qcom,psci-mode = <0x0>;
+				qcom,latency-us = <270>;
+				qcom,ss-power = <455>;
+				qcom,energy-overhead = <270621>;
+				qcom,time-overhead = <500>;
+			};
+
+			qcom,pm-cluster-level@1 {
+				reg = <1>;
+				label = "cx_min";
+				qcom,psci-mode = <0x0>;
+				qcom,latency-us = <285>;
+				qcom,ss-power = <442>;
+				qcom,energy-overhead = <306621>;
+				qcom,time-overhead = <540>;
+				qcom,min-child-idx = <2>;
+				qcom,notify-rpm;
+				qcom,is-reset;
+			};
+
+			qcom,pm-cpu@0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				qcom,psci-mode-shift = <0>;
+				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU0>;
+
+				qcom,pm-cpu-level@0{
+					reg = <0>;
+					label = "wfi";
+					qcom,psci-cpu-mode = <0x1>;
+					qcom,latency-us = <1>;
+					qcom,ss-power = <473>;
+					qcom,energy-overhead = <100000>;
+					qcom,time-overhead = <25>;
+				};
+
+				qcom,pm-cpu-level@1 {
+					reg = <1>;
+					label ="standalone_pc";
+					qcom,psci-cpu-mode = <0x4>;
+					qcom,latency-us = <240>;
+					qcom,ss-power = <467>;
+					qcom,energy-overhead = <202781>;
+					qcom,time-overhead = <420>;
+					qcom,use-broadcast-timer;
+					qcom,is-reset;
+				};
+
+				qcom,pm-cpu-level@2 {
+					reg = <2>;
+					label = "system-pc";
+					qcom,psci-cpu-mode = <0x8>;
+					qcom,latency-us = <270>;
+					qcom,ss-power = <455>;
+					qcom,energy-overhead = <270621>;
+					qcom,time-overhead = <500>;
+					qcom,use-broadcast-timer;
+					qcom,is-reset;
+				};
+			};
+		};
+	};
+
+	qcom,rpm-stats@c300000 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xC300000 0x1000>, <0xC3F0004 0x4>;
+		reg-names = "phys_addr_base", "offset_addr";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
index 37903b9..7543f7c 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
@@ -24,7 +24,8 @@
 		pmxpoorwills_s1_level: regualtor-pmxpoorwills-s1 {
 			regulator-name = "pmxpoorwills_s1_level";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
-			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+			regulator-min-microvolt =
+						<RPMH_REGULATOR_LEVEL_MIN_SVS>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 		};
 	};
@@ -53,7 +54,8 @@
 		pmxpoorwills_s5_level: regualtor-pmxpoorwills-s5-level {
 			regulator-name = "pmxpoorwills_s5_level";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
-			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+			regulator-min-microvolt =
+						<RPMH_REGULATOR_LEVEL_LOW_SVS>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 			qcom,min-dropout-voltage-level = <(-1)>;
 		};
@@ -61,7 +63,8 @@
 		pmxpoorwills_s5_level_ao: regualtor-pmxpoorwills-s5-level-ao {
 			regulator-name = "pmxpoorwills_s5_level_ao";
 			qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
-			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+			regulator-min-microvolt =
+						<RPMH_REGULATOR_LEVEL_LOW_SVS>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 			qcom,min-dropout-voltage-level = <(-1)>;
 		};
@@ -401,4 +404,12 @@
 		gpio = <&tlmm 83 GPIO_ACTIVE_HIGH>;
 		enable-active-high;
 	};
+
+	vreg_wlan: vreg_wlan {
+		compatible = "regulator-fixed";
+		regulator-name = "vreg_wlan";
+		startup-delay-us = <4000>;
+		enable-active-high;
+		gpio = <&pmxpoorwills_gpios 6 GPIO_ACTIVE_HIGH>;
+	};
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index 77e1763..3bccd8a 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -24,13 +24,15 @@
 		#size-cells = <1>;
 		ranges;
 
-		interrupts = <0 131 0>, <0 130 0>, <0 59 0>;
-		interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq";
+		interrupts = <0 197 0>, <0 130 0>, <0 196 0>, <0 198 0>;
+		interrupt-names = "dp_hs_phy_irq", "pwr_event_irq",
+			"ss_phy_irq", "dm_hs_phy_irq";
 
 		USB3_GDSC-supply = <&gdsc_usb30>;
 		qcom,usb-dbm = <&dbm_1p5>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
 		qcom,num-gsi-evt-buffs = <0x3>;
+		qcom,use-pdc-interrupts;
 
 		clocks = <&clock_gcc GCC_USB30_MASTER_CLK>,
 			 <&clock_gcc GCC_SYS_NOC_USB3_CLK>,
@@ -70,6 +72,7 @@
 			usb-phy = <&usb2_phy>, <&usb3_qmp_phy>;
 			tx-fifo-resize;
 			linux,sysdev_is_parent;
+			snps,bus-suspend-enable;
 			snps,disable-clk-gating;
 			snps,has-lpm-erratum;
 			snps,hird-threshold = /bits/ 8 <0x10>;
@@ -123,6 +126,9 @@
 
 		resets = <&clock_gcc GCC_QUSB2PHY_BCR>;
 		reset-names = "phy_reset";
+
+		/* override parameters */
+		qcom,param-override-seq = <0x43 0x70>; /* override_x1 */
 	};
 
 	dbm_1p5: dbm@a6f8000 {
@@ -139,9 +145,11 @@
 	usb3_qmp_phy: ssphy@ff0000 {
 		compatible = "qcom,usb-ssphy-qmp-v2";
 		reg = <0xff0000 0x1000>,
-		    <0x01fcb244 0x4>;
+		    <0x01fcb244 0x4>,
+		    <0x00ff088c 0x4>;
 		reg-names = "qmp_phy_base",
-			"vls_clamp_reg";
+			"vls_clamp_reg",
+			"pcs_clamp_enable_reg";
 
 		vdd-supply = <&pmxpoorwills_l4>;
 		core-supply = <&pmxpoorwills_l1>;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 5829942..960d680 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -23,7 +23,7 @@
 	model = "Qualcomm Technologies, Inc. SDX POORWILLS";
 	compatible = "qcom,sdxpoorwills";
 	qcom,msm-id = <334 0x0>, <335 0x0>;
-	interrupt-parent = <&intc>;
+	interrupt-parent = <&pdc>;
 
 	reserved-memory {
 		#address-cells = <1>;
@@ -61,6 +61,12 @@
 			reusable;
 			size = <0x400000>;
 		 };
+
+		dump_mem: mem_dump_region {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x2400000>;
+		};
 	};
 
 	cpus {
@@ -70,6 +76,7 @@
 		CPU0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a7";
+			enable-method = "psci";
 			reg = <0x0>;
 			#cooling-cells = <2>;
 		};
@@ -81,6 +88,11 @@
 		sdhc1 = &sdhc_1; /* SDC1 eMMC/SD/SDIO slot */
 	};
 
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
 	soc: soc { };
 };
 
@@ -96,6 +108,15 @@
 		#interrupt-cells = <3>;
 		reg = <0x17800000 0x1000>,
 		      <0x17802000 0x1000>;
+		interrupt-parent = <&intc>;
+	};
+
+	pdc: interrupt-controller@b210000{
+		compatible = "qcom,pdc-sdxpoorwills";
+		reg = <0xb210000 0x30000>;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&intc>;
+		interrupt-controller;
 	};
 
 	timer {
@@ -188,7 +209,7 @@
 	};
 
 	clock_gcc: qcom,gcc@100000 {
-		compatible = "qcom,gcc-sdxpoorwills";
+		compatible = "qcom,gcc-sdxpoorwills", "syscon";
 		reg = <0x100000 0x1f0000>;
 		reg-names = "cc_base";
 		vdd_cx-supply = <&pmxpoorwills_s5_level>;
@@ -241,6 +262,14 @@
 			< 1 >;
 	};
 
+	clock_debug: qcom,cc-debug {
+		compatible = "qcom,debugcc-sdxpoorwills";
+		qcom,gcc = <&clock_gcc>;
+		clock-names = "xo_clk_src";
+		clocks = <&clock_rpmh RPMH_CXO_CLK>;
+		#clock-cells = <1>;
+	};
+
 	serial_uart: serial@831000 {
 		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
 		reg = <0x831000 0x200>;
@@ -268,6 +297,159 @@
 		reg = <0x00137004 0x4>;
 	};
 
+	pcie_ep: qcom,pcie@40002000 {
+		compatible = "qcom,pcie-ep";
+
+		reg = <0x40002000 0x1000>,
+			<0x40000000 0xf1d>,
+			<0x40000f20 0xa8>,
+			<0x40001000 0x1000>,
+			<0x01c00000 0x2000>,
+			<0x01c02000 0x1000>,
+			<0x01c04000 0x1000>;
+		reg-names = "msi", "dm_core", "elbi", "iatu", "parf",
+				"phy", "mmio";
+
+		#address-cells = <0>;
+		interrupt-parent = <&pcie_ep>;
+		interrupts = <0>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 140 0>;
+		interrupt-names = "int_global";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie_ep_clkreq_default &pcie_ep_perst_default
+			&pcie_ep_wake_default>;
+
+		clkreq-gpio = <&tlmm 56 0>;
+		perst-gpio = <&tlmm 57 0>;
+		wake-gpio = <&tlmm 53 0>;
+
+		gdsc-vdd-supply = <&gdsc_pcie>;
+		vreg-1.8-supply = <&pmxpoorwills_l1>;
+		vreg-0.9-supply = <&pmxpoorwills_l4>;
+
+		qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+		qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+
+		clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>,
+			<&clock_gcc GCC_PCIE_CFG_AHB_CLK>,
+			<&clock_gcc GCC_PCIE_MSTR_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_AUX_CLK>,
+			<&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+			<&clock_gcc GCC_PCIE_SLEEP_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>;
+
+		clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk",
+				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+				"pcie_0_aux_clk", "pcie_0_ldo",
+				"pcie_0_sleep_clk",
+				"pcie_0_slv_q2a_axi_clk";
+
+		resets = <&clock_gcc GCC_PCIE_BCR>,
+			<&clock_gcc GCC_PCIE_PHY_BCR>;
+
+		reset-names = "pcie_0_core_reset",
+				"pcie_0_phy_reset";
+
+		qcom,msm-bus,name = "pcie-ep";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<45 512 0 0>,
+				<45 512 500 800>;
+
+		qcom,pcie-link-speed = <2>;
+		qcom,pcie-phy-ver = <6>;
+		qcom,pcie-active-config;
+		qcom,pcie-aggregated-irq;
+		qcom,pcie-mhi-a7-irq;
+		qcom,phy-status-reg = <0x814>;
+
+		qcom,phy-init = <0x840 0x001 0x0 0x1
+				0x094 0x000 0x0 0x1
+				0x058 0x00f 0x0 0x1
+				0x0a4 0x042 0x0 0x1
+				0x110 0x024 0x0 0x1
+				0x1bc 0x011 0x0 0x1
+				0x0bc 0x019 0x0 0x1
+				0x0b0 0x004 0x0 0x1
+				0x0ac 0x0ff 0x0 0x1
+				0x158 0x001 0x0 0x1
+				0x074 0x028 0x0 0x1
+				0x07c 0x00d 0x0 0x1
+				0x084 0x000 0x0 0x1
+				0x1b0 0x01d 0x0 0x1
+				0x1ac 0x056 0x0 0x1
+				0x04c 0x007 0x0 0x1
+				0x050 0x007 0x0 0x1
+				0x0f0 0x003 0x0 0x1
+				0x0ec 0x0fb 0x0 0x1
+				0x00c 0x002 0x0 0x1
+				0x29c 0x012 0x0 0x1
+				0x284 0x005 0x0 0x1
+				0x234 0x0d9 0x0 0x1
+				0x238 0x0cc 0x0 0x1
+				0x51c 0x003 0x0 0x1
+				0x518 0x01c 0x0 0x1
+				0x524 0x014 0x0 0x1
+				0x4ec 0x00e 0x0 0x1
+				0x4f0 0x04a 0x0 0x1
+				0x4f4 0x00f 0x0 0x1
+				0x5b4 0x004 0x0 0x1
+				0x434 0x07f 0x0 0x1
+				0x444 0x070 0x0 0x1
+				0x510 0x017 0x0 0x1
+				0x4d8 0x001 0x0 0x1
+				0x598 0x0e0 0x0 0x1
+				0x59c 0x0c8 0x0 0x1
+				0x5a0 0x0c8 0x0 0x1
+				0x5a4 0x009 0x0 0x1
+				0x5a8 0x0b1 0x0 0x1
+				0x584 0x024 0x0 0x1
+				0x588 0x0e4 0x0 0x1
+				0x58c 0x0ec 0x0 0x1
+				0x590 0x039 0x0 0x1
+				0x594 0x036 0x0 0x1
+				0x570 0x0ef 0x0 0x1
+				0x574 0x0ef 0x0 0x1
+				0x578 0x02f 0x0 0x1
+				0x57c 0x0d3 0x0 0x1
+				0x580 0x040 0x0 0x1
+				0x4fc 0x000 0x0 0x1
+				0x4f8 0x0c0 0x0 0x1
+				0x9a4 0x001 0x0 0x1
+				0x840 0x001 0x0 0x1
+				0x848 0x001 0x0 0x1
+				0x8a0 0x011 0x0 0x1
+				0x988 0x088 0x0 0x1
+				0x998 0x008 0x0 0x1
+				0x8dc 0x00d 0x0 0x1
+				0x800 0x000 0x0 0x1
+				0x844 0x003 0x0 0x1>;
+
+		status = "disabled";
+	};
+
+	mhi_device: mhi_dev@1c04000 {
+		compatible = "qcom,msm-mhi-dev";
+		reg = <0x1c04000 0x1000>,
+			<0x1e22000 0x4>,
+			<0x1e22148 0x4>;
+			reg-names = "mhi_mmio_base", "ipa_uc_mbox_crdb",
+			"ipa_uc_mbox_erdb";
+			qcom,mhi-ep-msi = <0>;
+			qcom,mhi-version = <0x1000000>;
+			qcom,use-ipa-software-channel;
+			interrupts = <0 145 0>;
+			interrupt-names = "mhi-device-inta";
+			qcom,mhi-ifc-id = <0x030417cb>;
+			qcom,mhi-interrupt;
+		status = "disabled";
+	};
+
 	gdsc_emac: qcom,gdsc@147004 {
 		compatible = "qcom,gdsc";
 		regulator-name = "gdsc_emac";
@@ -559,6 +741,56 @@
 		reg = <0xc37000c 8>;
 	};
 
+	mem_dump {
+		compatible = "qcom,mem-dump";
+		memory-region = <&dump_mem>;
+
+		rpmh_dump {
+			qcom,dump-size = <0x2000000>;
+			qcom,dump-id = <0xec>;
+		};
+
+		fcm_dump {
+			qcom,dump-size = <0x8400>;
+			qcom,dump-id = <0xee>;
+		};
+
+		rpm_sw_dump {
+			qcom,dump-size = <0x28000>;
+			qcom,dump-id = <0xea>;
+		};
+
+		pmic_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xe4>;
+		};
+
+		tmc_etf_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xf0>;
+		};
+
+		tmc_etr_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x100>;
+		};
+
+		tmc_etf_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x101>;
+		};
+
+		misc_data_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0xe8>;
+		};
+
+		tpdm_swao_dump {
+			qcom,dump-size = <0x512>;
+			qcom,dump-id = <0xf2>;
+		};
+	};
+
 	qcom,msm_gsi {
 		compatible = "qcom,msm_gsi";
 	};
@@ -744,11 +976,145 @@
 		#mbox-cells = <1>;
 	};
 
-	usb_detect: qcom,gpio-usbdetect {
-		compatible = "qcom,gpio-usbdetect";
+	vbus_detect: qcom,pmd-vbus-det {
+		compatible = "qcom,pmd-vbus-det";
 		interrupt-parent = <&spmi_bus>;
 		interrupts = <0x0 0x0d 0x0 IRQ_TYPE_NONE>;
-		interrupt-names = "vbus_det_irq";
+		interrupt-names = "usb_vbus";
+		status = "disabled";
+	};
+
+	qcom,wdt@17817000{
+		compatible = "qcom,msm-watchdog";
+		reg = <0x17817000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <1 3 0>, <1 2 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+	};
+
+	qcom_rng: qrng@793000{
+		compatible = "qcom,msm-rng";
+		reg = <0x793000 0x1000>;
+		qcom,msm-rng-iface-clk;
+		qcom,no-qrng-config;
+		qcom,msm-bus,name = "msm-rng-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<1 618 0 0>,    /* No vote */
+			<1 618 0 800>;  /* 100 KHz */
+		clocks = <&clock_gcc GCC_PRNG_AHB_CLK>;
+		clock-names = "iface_clk";
+	};
+
+	qcom_cedev: qcedev@1de0000 {
+		compatible = "qcom,qcedev";
+		reg = <0x1de0000 0x20000>,
+			<0x1dc4000 0x24000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 252 0>;
+		qcom,bam-pipe-pair = <3>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,bam-ee = <0>;
+		qcom,ce-hw-shared;
+		qcom,clk-mgmt-sus-res;
+		qcom,msm-bus,name = "qcedev-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<125 512 0 0>,
+				<125 512 393600 393600>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		clocks = <&clock_gcc GCC_CE1_CLK>,
+			<&clock_gcc GCC_CE1_CLK>,
+			<&clock_gcc GCC_CE1_AHB_CLK>,
+			<&clock_gcc GCC_CE1_AXI_CLK>;
+		qcom,ce-opp-freq = <171430000>;
+		qcom,request-bw-before-clk;
+		iommus = <&apps_smmu 0x66 0x1>,
+			<&apps_smmu 0x76 0x1>;
+	};
+
+	qcom_crypto: qcrypto@1de0000 {
+		compatible = "qcom,qcrypto";
+		reg = <0x1de0000 0x20000>,
+			<0x1dc4000 0x24000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 252 0>;
+		qcom,bam-pipe-pair = <2>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,bam-ee = <0>;
+		qcom,ce-hw-shared;
+		qcom,clk-mgmt-sus-res;
+		qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<125 512 0 0>,
+				<125 512 393600 393600>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		clocks = <&clock_gcc GCC_CE1_CLK>,
+			<&clock_gcc GCC_CE1_CLK>,
+			<&clock_gcc GCC_CE1_AHB_CLK>,
+			<&clock_gcc GCC_CE1_AXI_CLK>;
+		qcom,ce-opp-freq = <171430000>;
+		qcom,request-bw-before-clk;
+		qcom,use-sw-aes-cbc-ecb-ctr-algo;
+		qcom,use-sw-aes-xts-algo;
+		qcom,use-sw-aes-ccm-algo;
+		qcom,use-sw-aead-algo;
+		qcom,use-sw-ahash-algo;
+		qcom,use-sw-hmac-algo;
+		iommus = <&apps_smmu 0x64 0x1>,
+			<&apps_smmu 0x74 0x1>;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>;
+	};
+
+	cnss_pcie: qcom,cnss {
+		compatible = "qcom,cnss";
+		wlan-en-gpio = <&tlmm 52 0>;
+		vdd-wlan-supply = <&vreg_wlan>;
+		vdd-wlan-xtal-supply = <&pmxpoorwills_l6>;
+		vdd-wlan-io-supply = <&pmxpoorwills_l6>;
+		qcom,notify-modem-status;
+		pinctrl-names = "wlan_en_active", "wlan_en_sleep";
+		pinctrl-0 = <&cnss_wlan_en_active>;
+		pinctrl-1 = <&cnss_wlan_en_sleep>;
+		qcom,wlan-rc-num = <0>;
+		qcom,wlan-ramdump-dynamic = <0x200000>;
+
+		qcom,msm-bus,name = "msm-cnss";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,vectors-KBps =
+				<45 512 0 0>, <1 512 0 0>,
+				/* Upto 200 Mbps */
+				<45 512 41421 655360>, <1 512 41421 655360>,
+				/* Upto 400 Mbps */
+				<45 512 98572 655360>, <1 512 98572 1600000>,
+				/* Upto 800 Mbps */
+				<45 512 207108 1146880>, <1 512 207108 3124992>;
+	};
+
+	cnss_sdio: qcom,cnss_sdio {
+		compatible = "qcom,cnss_sdio";
+		subsys-name = "AR6320_SDIO";
+		vdd-wlan-supply = <&vreg_wlan>;
+		vdd-wlan-io-supply = <&pmxpoorwills_l6>;
+		qcom,wlan-ramdump-dynamic = <0x200000>;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&cnss_sdio_active>;
+		pinctrl-1 = <&cnss_sdio_sleep>;
+		qcom,is-antenna-shared;
 		status = "disabled";
 	};
 };
@@ -764,13 +1130,15 @@
 #include "sdxpoorwills-audio.dtsi"
 #include "sdxpoorwills-ion.dtsi"
 #include "msm-arm-smmu-sdxpoorwills.dtsi"
+#include "sdxpoorwills-coresight.dtsi"
 
 &soc {
 	emac_hw: qcom,emac@00020000 {
 		compatible = "qcom,emac-dwc-eqos";
 		reg = <0x20000 0x10000>,
-		      <0x36000 0x100>;
-		reg-names = "emac-base", "rgmii-base";
+			<0x36000 0x100>,
+			<0x3900000 0x300000>;
+		reg-names = "emac-base", "rgmii-base", "tlmm-central-base";
 		interrupts = <0 62 4>, <0 60 4>,
 			<0 45 4>, <0 49 4>,
 			<0 50 4>, <0 51 4>,
@@ -808,4 +1176,37 @@
 			io-interface = "rgmii";
 		};
 	};
+
+	ess-instance {
+		num_devices = <0x1>;
+		ess-switch@0 {
+			compatible = "qcom,ess-switch-qca83xx";
+			qcom,switch-access-mode = "mdio";
+			qcom,ar8327-initvals = <
+				0x0000c 0x7600000   /* PAD6_MODE */
+				0x00008 0x0         /* PAD5_MODE */
+				0x000e4 0xaa545     /* MAC_POWER_SEL */
+				0x000e0 0xc74164de  /* SGMII_CTRL */
+				0x0007c 0x4e        /* PORT0_STATUS */
+				0x00094 0x4e        /* PORT6_STATUS */
+			>;
+			qcom,link-intr-gpio = <2>;
+			qcom,switch-cpu-bmp = <0x40>;    /* cpu port bitmap */
+			qcom,switch-lan-bmp = <0x3e>;    /* lan port bitmap */
+			qcom,switch-wan-bmp = <0x0>;     /* wan port bitmap */
+		};
+	};
 };
+
+#include "pmxpoorwills.dtsi"
+#include "sdxpoorwills-blsp.dtsi"
+#include "sdxpoorwills-regulator.dtsi"
+#include "sdxpoorwills-smp2p.dtsi"
+#include "sdxpoorwills-usb.dtsi"
+#include "sdxpoorwills-pcie.dtsi"
+#include "sdxpoorwills-bus.dtsi"
+#include "sdxpoorwills-thermal.dtsi"
+#include "sdxpoorwills-audio.dtsi"
+#include "sdxpoorwills-ion.dtsi"
+#include "msm-arm-smmu-sdxpoorwills.dtsi"
+#include "sdxpoorwills-pm.dtsi"
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
new file mode 100644
index 0000000..9533fbf
--- /dev/null
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -0,0 +1,530 @@
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8909=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_HDCP_QSEECOM=y
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8909=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_PM=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_IIO=y
+CONFIG_QCOM_SPMI_IADC=y
+CONFIG_QCOM_SPMI_VADC=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_PATH=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
new file mode 100644
index 0000000..9533fbf
--- /dev/null
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -0,0 +1,530 @@
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8909=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_HDCP_QSEECOM=y
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8909=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_PM=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_IIO=y
+CONFIG_QCOM_SPMI_IADC=y
+CONFIG_QCOM_SPMI_VADC=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_PATH=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 9d710e3..40316bd 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -50,6 +50,7 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 # CONFIG_VDSO is not set
 CONFIG_SMP=y
@@ -274,6 +275,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
 CONFIG_INPUT_EVDEV=y
@@ -287,10 +289,12 @@
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
@@ -301,6 +305,8 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -312,8 +318,11 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -325,18 +334,29 @@
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
 CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_QCOM_KGSL=y
 CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -345,6 +365,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -352,7 +373,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -361,6 +408,26 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_PARANOID_SD_INIT=y
@@ -375,12 +442,15 @@
 CONFIG_MMC_CQ_HCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
 CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
@@ -394,31 +464,36 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_GSI=y
-CONFIG_IPA3=y
-CONFIG_RMNET_IPA3=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_RNDIS_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
-CONFIG_MSM_GLINK=y
-CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
-CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
-CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
 CONFIG_MSM_SMP2P=y
-CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 CONFIG_MSM_QMI_INTERFACE=y
-CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
 CONFIG_MSM_PIL_SSR_GENERIC=y
@@ -429,8 +504,20 @@
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 03f297f..54c2d86 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -56,6 +56,7 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 # CONFIG_VDSO is not set
 CONFIG_SMP=y
@@ -284,6 +285,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
 CONFIG_INPUT_EVDEV=y
@@ -292,6 +294,7 @@
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
 # CONFIG_SERIO_SERPORT is not set
@@ -299,8 +302,12 @@
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
@@ -311,6 +318,8 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -322,8 +331,11 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -335,19 +347,30 @@
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
 CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_QCOM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -356,6 +379,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -363,7 +387,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -372,6 +422,26 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
@@ -387,12 +457,15 @@
 CONFIG_MMC_CQ_HCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
 CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
@@ -406,9 +479,8 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_GSI=y
-CONFIG_IPA3=y
-CONFIG_RMNET_IPA3=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_RNDIS_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
@@ -416,26 +488,34 @@
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_EXT_DISPLAY=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
-# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_CORE_HANG_DETECT=y
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
-CONFIG_MSM_GLINK=y
-CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
-CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
-CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
 CONFIG_TRACER_PKT=y
 CONFIG_MSM_SMP2P=y
-CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 CONFIG_MSM_QMI_INTERFACE=y
-CONFIG_MSM_GLINK_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_PIL=y
 CONFIG_MSM_PIL_SSR_GENERIC=y
@@ -446,8 +526,20 @@
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
@@ -491,6 +583,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index d3500ae..b2dc7f7 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -142,6 +142,7 @@
 CONFIG_BRIDGE_EBT_DNAT=y
 CONFIG_BRIDGE_EBT_SNAT=y
 CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_PRIO=y
 CONFIG_RMNET_DATA=y
@@ -199,7 +200,12 @@
 CONFIG_USB_NET_SMSC75XX=y
 CONFIG_USB_NET_SMSC95XX=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CNSS_PCI=y
+CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_LOGGER=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
@@ -213,6 +219,7 @@
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -221,6 +228,7 @@
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_SDXPOORWILLS=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_DEBUG_GPIO=y
@@ -229,6 +237,7 @@
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_SMB138X_CHARGER=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -286,6 +295,7 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_UEVENT=y
@@ -317,13 +327,15 @@
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_EP_PCIE=y
+CONFIG_EP_PCIE_HW=y
 CONFIG_QPNP_REVID=y
-CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
 CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
+CONFIG_MDM_DEBUGCC_SDXPOORWILLS=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MSM_QMP=y
 CONFIG_IOMMU_IO_PGTABLE_FAST=y
@@ -334,6 +346,10 @@
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_MSM_SMEM=y
 CONFIG_MSM_GLINK=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
@@ -349,6 +365,9 @@
 CONFIG_MSM_PIL_SSR_GENERIC=y
 CONFIG_QCOM_COMMAND_DB=y
 CONFIG_MSM_PM=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_EXTCON_QCOM_SPMI_MISC=y
 CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
@@ -381,4 +400,7 @@
 CONFIG_CORESIGHT_CTI=y
 CONFIG_CORESIGHT_EVENT=y
 CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index af75d1e..ac15d6ea 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -144,6 +144,7 @@
 CONFIG_BRIDGE_EBT_DNAT=y
 CONFIG_BRIDGE_EBT_SNAT=y
 CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_PRIO=y
 CONFIG_RMNET_DATA=y
@@ -191,7 +192,12 @@
 CONFIG_USB_NET_SMSC75XX=y
 CONFIG_USB_NET_SMSC95XX=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CNSS_PCI=y
+CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_LOGGER=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
@@ -207,6 +213,7 @@
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -216,12 +223,14 @@
 CONFIG_SLIMBUS=y
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_SDXPOORWILLS=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_SMB138X_CHARGER=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -245,6 +254,9 @@
 CONFIG_REGULATOR_RPMH=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDP_NONE=y
+CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -285,6 +297,7 @@
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_UEVENT=y
@@ -300,6 +313,9 @@
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_QPNP=y
 CONFIG_DMADEVICES=y
@@ -316,13 +332,15 @@
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_EP_PCIE=y
+CONFIG_EP_PCIE_HW=y
 CONFIG_QPNP_REVID=y
-CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
 CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
+CONFIG_MDM_DEBUGCC_SDXPOORWILLS=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MSM_QMP=y
 CONFIG_IOMMU_IO_PGTABLE_FAST=y
@@ -333,6 +351,8 @@
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_MSM_SMEM=y
@@ -350,7 +370,10 @@
 CONFIG_MSM_PIL_SSR_GENERIC=y
 CONFIG_QCOM_COMMAND_DB=y
 CONFIG_MSM_PM=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON_QCOM_SPMI_MISC=y
 CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
@@ -385,6 +408,7 @@
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_DEBUG_USER=y
 CONFIG_CORESIGHT=y
@@ -400,8 +424,10 @@
 CONFIG_CORESIGHT_TGU=y
 CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_DUMMY=y
-CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_CMAC=y
 CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_XZ_DEC=y
 CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 714da33..5d49b60 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -11,6 +11,7 @@
 CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_CMA=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
@@ -35,6 +36,7 @@
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_AHCI_SUNXI=y
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index d24abe4..aa8fc3f 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/sched_energy.h>
 
 #include <asm/cputype.h>
 #include <asm/topology.h>
@@ -499,125 +500,31 @@
 	update_cpu_capacity(cpuid);
 }
 
-/*
- * ARM TC2 specific energy cost model data. There are no unit requirements for
- * the data. Data can be normalized to any reference point, but the
- * normalization must be consistent. That is, one bogo-joule/watt must be the
- * same quantity for all data, but we don't care what it is.
- */
-static struct idle_state idle_states_cluster_a7[] = {
-	 { .power = 25 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 25 }, /* WFI */
-	 { .power = 10 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_cluster_a15[] = {
-	 { .power = 70 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 70 }, /* WFI */
-	 { .power = 25 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_cluster_a7[] = {
-	/* Cluster only power */
-	 { .cap =  150, .power = 2967, }, /*  350 MHz */
-	 { .cap =  172, .power = 2792, }, /*  400 MHz */
-	 { .cap =  215, .power = 2810, }, /*  500 MHz */
-	 { .cap =  258, .power = 2815, }, /*  600 MHz */
-	 { .cap =  301, .power = 2919, }, /*  700 MHz */
-	 { .cap =  344, .power = 2847, }, /*  800 MHz */
-	 { .cap =  387, .power = 3917, }, /*  900 MHz */
-	 { .cap =  430, .power = 4905, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_cluster_a15[] = {
-	/* Cluster only power */
-	 { .cap =  426, .power =  7920, }, /*  500 MHz */
-	 { .cap =  512, .power =  8165, }, /*  600 MHz */
-	 { .cap =  597, .power =  8172, }, /*  700 MHz */
-	 { .cap =  682, .power =  8195, }, /*  800 MHz */
-	 { .cap =  768, .power =  8265, }, /*  900 MHz */
-	 { .cap =  853, .power =  8446, }, /* 1000 MHz */
-	 { .cap =  938, .power = 11426, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 15200, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_cluster_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a7),
-	  .idle_states    = idle_states_cluster_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a7),
-	  .cap_states     = cap_states_cluster_a7,
-};
-
-static struct sched_group_energy energy_cluster_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a15),
-	  .idle_states    = idle_states_cluster_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a15),
-	  .cap_states     = cap_states_cluster_a15,
-};
-
-static struct idle_state idle_states_core_a7[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_core_a15[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_core_a7[] = {
-	/* Power per cpu */
-	 { .cap =  150, .power =  187, }, /*  350 MHz */
-	 { .cap =  172, .power =  275, }, /*  400 MHz */
-	 { .cap =  215, .power =  334, }, /*  500 MHz */
-	 { .cap =  258, .power =  407, }, /*  600 MHz */
-	 { .cap =  301, .power =  447, }, /*  700 MHz */
-	 { .cap =  344, .power =  549, }, /*  800 MHz */
-	 { .cap =  387, .power =  761, }, /*  900 MHz */
-	 { .cap =  430, .power = 1024, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_core_a15[] = {
-	/* Power per cpu */
-	 { .cap =  426, .power = 2021, }, /*  500 MHz */
-	 { .cap =  512, .power = 2312, }, /*  600 MHz */
-	 { .cap =  597, .power = 2756, }, /*  700 MHz */
-	 { .cap =  682, .power = 3125, }, /*  800 MHz */
-	 { .cap =  768, .power = 3524, }, /*  900 MHz */
-	 { .cap =  853, .power = 3846, }, /* 1000 MHz */
-	 { .cap =  938, .power = 5177, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 6997, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_core_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a7),
-	  .idle_states    = idle_states_core_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a7),
-	  .cap_states     = cap_states_core_a7,
-};
-
-static struct sched_group_energy energy_core_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a15),
-	  .idle_states    = idle_states_core_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a15),
-	  .cap_states     = cap_states_core_a15,
-};
-
 /* sd energy functions */
 static inline
 const struct sched_group_energy * const cpu_cluster_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_cluster_a7 :
-			&energy_cluster_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline
 const struct sched_group_energy * const cpu_core_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_core_a7 :
-			&energy_core_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline int cpu_corepower_flags(void)
@@ -682,4 +589,5 @@
 
 	/* Set scheduler topology descriptor */
 	set_sched_topology(arm_topology);
+	init_sched_energy_costs();
 }
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 19b5f5c..c38bfbe 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -1165,6 +1165,7 @@
 			cpu_hyp_reset();
 
 		return NOTIFY_OK;
+	case CPU_PM_ENTER_FAILED:
 	case CPU_PM_EXIT:
 		if (__this_cpu_read(kvm_arm_hardware_enabled))
 			/* The hardware was enabled before suspend. */
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 42f5daf..4e57ebc 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -38,7 +38,7 @@
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -47,7 +47,16 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	/*
+	 * "If an SMC instruction executed at Non-secure EL1 is
+	 * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+	 * Trap exception, not a Secure Monitor Call exception [...]"
+	 *
+	 * We need to advance the PC after the trap, as it would
+	 * otherwise return to the same address...
+	 */
+	vcpu_set_reg(vcpu, 0, ~0UL);
+	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 	return 1;
 }
 
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 2206e0e..2a35c19 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -1284,7 +1284,7 @@
 		return -EFAULT;
 	}
 
-	if (is_vm_hugetlb_page(vma) && !logging_active) {
+	if (vma_kernel_pagesize(vma) && !logging_active) {
 		hugetlb = true;
 		gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
 	} else {
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 4952b98..3a649df 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -51,6 +51,7 @@
 	select COMMON_CLK
 	select COMMON_CLK_QCOM
 	select QCOM_GDSC
+	select GENERIC_CLOCKEVENTS_BROADCAST
 
 config ARCH_MSM8953
 	bool "Enable support for MSM8953"
@@ -64,6 +65,43 @@
 	select HAVE_CLK_PREPARE
 	select COMMON_CLK_MSM
 
+config ARCH_MSM8937
+	bool "Enable support for MSM8937"
+	select CPU_V7
+	select HAVE_ARM_ARCH_TIMER
+	select PINCTRL
+	select QCOM_SCM if SMP
+	select PM_DEVFREQ
+	select CLKDEV_LOOKUP
+	select HAVE_CLK
+	select HAVE_CLK_PREPARE
+	select COMMON_CLK_MSM
+
+config ARCH_MSM8909
+	bool "Enable support for MSM8909"
+	select HAVE_ARM_ARCH_TIMER
+	select MAY_HAVE_SPARSE_IRQ
+	select PINCTRL_MSM_TLMM
+	select USE_PINCTRL_IRQ
+	select MSM_PM if PM
+	select MSM_RPM_SMD
+	select MSM_RPM_STATS_LOG
+	select MSM_RPM_LOG
+	select MSM_CORTEX_A7
+	select QCOM_SCM if SMP
+	select CPU_FREQ
+	select CPU_FREQ_MSM
+	select PM_DEVFREQ
+	select PM_OPP
+	select MSM_DEVFREQ_DEVBW
+	select DEVFREQ_SIMPLE_DEV
+	select DEVFREQ_GOV_MSM_BW_HWMON
+	select MSM_BIMC_BWMON
+	select CLKDEV_LOOKUP
+	select HAVE_CLK
+	select HAVE_CLK_PREPARE
+	select COMMON_CLK_MSM
+
 config ARCH_SDM450
 	bool "Enable support for SDM450"
 	select CPU_V7
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index 828e9c9..0e1ef7e 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -2,4 +2,6 @@
 obj-$(CONFIG_SMP)	+= platsmp.o
 obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o
 obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o
+obj-$(CONFIG_ARCH_MSM8937) += board-msm8937.o
+obj-$(CONFIG_ARCH_MSM8909) += board-msm8909.o
 obj-$(CONFIG_ARCH_SDM450) += board-sdm450.o
diff --git a/arch/arm/mach-qcom/board-msm8909.c b/arch/arm/mach-qcom/board-msm8909.c
new file mode 100644
index 0000000..da9ca7d
--- /dev/null
+++ b/arch/arm/mach-qcom/board-msm8909.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include "board-dt.h"
+
+static const char *msm8909_dt_match[] __initconst = {
+	"qcom,msm8909",
+	NULL
+};
+
+static void __init msm8909_init(void)
+{
+	board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSM8909_DT,
+	"Qualcomm Technologies, Inc. MSM 8909 (Flattened Device Tree)")
+	.init_machine	= msm8909_init,
+	.dt_compat	= msm8909_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-qcom/board-msm8937.c b/arch/arm/mach-qcom/board-msm8937.c
new file mode 100644
index 0000000..b8d9c26
--- /dev/null
+++ b/arch/arm/mach-qcom/board-msm8937.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "board-dt.h"
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
+static const char *msm8937_dt_match[] __initconst = {
+	"qcom,msm8937",
+	NULL
+};
+
+static void __init msm8937_init(void)
+{
+	board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSM8937_DT,
+	"Qualcomm Technologies, Inc. MSM8937 (Flattened Device Tree)")
+	.init_machine		= msm8937_init,
+	.dt_compat		= msm8937_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c
index cae3bf7..04b0bcc 100644
--- a/arch/arm/mach-qcom/board-msm8953.c
+++ b/arch/arm/mach-qcom/board-msm8953.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 
 static const char *msm8953_dt_match[] __initconst = {
 	"qcom,msm8953",
+	"qcom,apq8053",
 	NULL
 };
 
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 32a80d6..cf5311f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -432,6 +432,20 @@
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_1024718
+	bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+	default y
+	help
+	  This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+	  Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+	  update of the hardware dirty bit when the DBM/AP bits are updated
+	  without a break-before-make. The work around is to disable the usage
+	  of hardware DBM locally on the affected cores. CPUs not affected by
+	  erratum will continue to use the feature.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index d35cecb..1de858e 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -154,6 +154,15 @@
 	  This enables support for the MSM8953 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
 
+config ARCH_MSM8937
+	bool "Enable Support for Qualcomm Technologies Inc. MSM8937"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the MSM8937 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_SDM450
 	bool "Enable Support for Qualcomm Technologies Inc. SDM450"
 	depends on ARCH_QCOM
@@ -172,6 +181,24 @@
 	  This enables support for the sdm632 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
 
+config ARCH_SDM429
+	bool "Enable Support for Qualcomm Technologies Inc. SDM429"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm429 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
+config ARCH_SDM439
+	bool "Enable Support for Qualcomm Technologies Inc. SDM439"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm439 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
 	bool "Rockchip Platforms"
 	select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
new file mode 100644
index 0000000..211e28c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
+
+&soc {
+	qcom,csid@1b08000 {
+		/delete-property/ qcom,mipi-csi-vdd-supply;
+	};
+
+	qcom,csid@1b08400 {
+		/delete-property/ qcom,mipi-csi-vdd-supply;
+	};
+
+	i2c@78b9000 {
+		synaptics@20 {
+			/delete-property/ avdd-supply;
+			/delete-property/ vdd-supply;
+		};
+	};
+
+	qcom,wcnss-wlan@a000000 {
+		/delete-property/ qcom,iris-vddpa-voltage-level;
+		/delete-property/ qcom,iris-vddpa-supply;
+		/delete-property/ qcom,wcnss-adc_tm;
+		/delete-property/ qcom,is-dual-band-disabled;
+		/delete-property/ qcom,iris-vddpa-current;
+		qcom,pronto-vddmx-supply = <&pm660_s2_corner_ao>;
+		qcom,pronto-vddcx-supply = <&pm660_s3_corner>;
+		qcom,pronto-vddpx-supply = <&pm660_l13>;
+		qcom,iris-vddxo-supply	 = <&pm660_l12>;
+		qcom,iris-vddrfa-supply  = <&pm660_l6>;
+		qcom,iris-vdddig-supply  = <&pm660_l13>;
+		qcom,wcn-external-gpio-support;
+	};
+
+	qcom,pronto@a21b000 {
+		vdd_pronto_pll-supply = <&pm660_l12>;
+	};
+
+	qcom,mss@4080000 {
+		vdd_cx-supply = <&pm660_s2_corner>;
+		vdd_mx-supply = <&pm660_s3_corner_ao>;
+		vdd_pll-supply = <&pm660_l12>;
+	};
+
+	tpiu@820000 {
+		/delete-property/ vdd-supply;
+		/delete-property/ vdd-io-supply;
+	};
+
+	qpdi@1941000 {
+		/delete-property/ vdd-supply;
+		/delete-property/ vdd-io-supply;
+	};
+
+	qcom,msm-thermal {
+		/delete-property/ vdd-dig-supply;
+	};
+
+	msm8x16_wcd_codec@f000 {
+		/delete-property/ cdc-vdda-cp-supply;
+		/delete-property/ cdc-vdda-h-supply;
+		/delete-property/ cdc-vdd-px-supply;
+		/delete-property/ cdc-vdd-pa-supply;
+		/delete-property/ cdc-vdd-mic-bias-supply;
+	};
+};
+
+&i2c_3 {
+	qcom,actuator@0 {
+		/delete-property/ cam_vaf-supply;
+	};
+
+	qcom,eeprom@6c {
+		/delete-property/ cam_vdig-supply;
+		/delete-property/ cam_vana-supply;
+		/delete-property/ cam_vio-supply;
+		/delete-property/ cam_vaf-supply;
+	};
+
+	qcom,camera@0 {
+		/delete-property/ cam_vdig-supply;
+		/delete-property/ cam_vana-supply;
+		/delete-property/ cam_vio-supply;
+		/delete-property/ cam_vaf-supply;
+	};
+
+	qcom,camera@1 {
+		/delete-property/ cam_vana-supply;
+		/delete-property/ cam_vio-supply;
+	};
+};
+
+
+&sdhc_2 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vdd-io-supply;
+};
+
+&soc {
+	/delete-node/ qcom,rpm-smd;
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>;
+	};
+};
+
+#include "pm660.dtsi"
+#include "pm660-rpm-regulator.dtsi"
+
+/* over-write the PM660 GPIO mappings for 8909w */
+&pm660_gpios {
+		interrupts  = <0x0 0xc3 0 IRQ_TYPE_NONE>,
+			      <0x0 0xc4 0 IRQ_TYPE_NONE>,
+			      <0x0 0xcb 0 IRQ_TYPE_NONE>;
+		interrupt-names = "pm660_gpio4", "pm660_gpio5", "pm660_gpio12";
+		qcom,gpios-disallowed = <1 2 3 6 7 8 9 10 11 13>;
+};
+
+#include "msm8909w-pm660-regulator.dtsi"
+#include "msm8909-pm660-pm.dtsi"
+
+&soc {
+	qcom,gcc@1800000 {
+		vdd_dig-supply = <&pm660_s2_corner>;
+		vdd_sr2_dig-supply = <&pm660_s2_corner_ao>;
+		vdd_sr2_pll-supply = <&pm660_l12_ao>;
+
+	};
+
+	usb@78d9000 {
+		hsusb_vdd_dig-supply = <&pm660_l5>;
+		HSUSB_1p8-supply = <&pm660_l12>;
+		HSUSB_3p3-supply = <&pm660_l16>;
+	};
+
+	qcom,clock-a7@0b011050 {
+		cpu-vdd-supply = <&apc_vreg_corner>;
+	};
+
+	qcom,rpmcc@1800000 {
+		compatible = "qcom,rpmcc-8909-pm660";
+	};
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm660_l19>;
+	vdd-io-supply = <&pm660_l13>;
+};
+
+&pm660_vadc {
+	/delete-node/ chan@1d;
+};
+
+&mdss_dsi{
+	vdda-supply = <&pm660_l5>; /*1.2V*/
+	vddio-supply = <&pm660_l12>; /*1.8V*/
+	qcom,mdss_dsi_ctrl0@1ac8000 {
+		bklt-supply = <&bob_vreg>;
+		vdd-supply = <&pm660_l18>; /*1.8*/
+		vddio-supply = <&pm660_l11>;
+	};
+};
+
+&mdss_dsi0_pll {
+	vddio-supply = <&pm660_l12>; /*1.8V*/
+};
+
+&pm660_0 {
+	pm660_charger: qcom,qpnp-smb2 {
+		compatible = "qcom,qpnp-smb2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#cooling-cells = <2>;
+
+		qcom,pmic-revid = <&pm660_revid>;
+
+		io-channels = <&pm660_rradc 8>,
+			      <&pm660_rradc 10>,
+			      <&pm660_rradc 3>,
+			      <&pm660_rradc 4>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max",
+				   "usbin_i",
+				   "usbin_v";
+
+		qcom,wipower-max-uw = <5000000>;
+
+		qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+		qcom,auto-recharge-soc;
+
+		qcom,use-extcon;
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =
+				<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "chg-error",
+					  "chg-state-change",
+					  "step-chg-state-change",
+					  "step-chg-soc-update-fail",
+					  "step-chg-soc-update-request";
+		};
+
+		qcom,otg@1100 {
+			reg = <0x1100 0x100>;
+			interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "otg-fail",
+					  "otg-overcurrent",
+					  "otg-oc-dis-sw-sts",
+					  "testmode-change-detect";
+		};
+
+		qcom,bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =
+				<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "bat-temp",
+					  "bat-ocp",
+					  "bat-ov",
+					  "bat-low",
+					  "bat-therm-or-id-missing",
+					  "bat-terminal-missing";
+		};
+
+		qcom,usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =
+				<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "usbin-collapse",
+					  "usbin-lt-3p6v",
+					  "usbin-uv",
+					  "usbin-ov",
+					  "usbin-plugin",
+					  "usbin-src-change",
+					  "usbin-icl-change",
+					  "type-c-change";
+		};
+
+		qcom,dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =
+				<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "dcin-collapse",
+					  "dcin-lt-3p6v",
+					  "dcin-uv",
+					  "dcin-ov",
+					  "dcin-plugin",
+					  "div2-en-dg",
+					  "dcin-icl-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts =
+				<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+				<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "wdog-snarl",
+					  "wdog-bark",
+					  "aicl-fail",
+					  "aicl-done",
+					  "high-duty-cycle",
+					  "input-current-limiting",
+					  "temperature-change",
+					  "switcher-power-ok";
+		};
+		smb2_vbus: qcom,smb2-vbus {
+			regulator-name = "smb2-vbus";
+		};
+
+		smb2_vconn: qcom,smb2-vconn {
+			regulator-name = "smb2-vconn";
+		};
+	};
+
+	pm660_rradc: rradc@4500 {
+		compatible = "qcom,rradc";
+		reg = <0x4500 0x100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#io-channel-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+	};
+
+	pm660_fg: qpnp,fg {
+		compatible = "qcom,fg-gen3";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+		io-channels = <&pm660_rradc 0>,
+			      <&pm660_rradc 7>;
+		io-channel-names = "rradc_batt_id",
+				   "rradc_die_temp";
+		qcom,rradc-base = <0x4500>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
+		qcom,fg-esr-timer-charging = <0 96>;
+		qcom,cycle-counter-en;
+		qcom,hold-soc-while-full;
+		qcom,fg-auto-recharge-soc;
+		qcom,fg-recharge-soc-thr = <98>;
+		status = "okay";
+
+		qcom,fg-batt-soc@4000 {
+			status = "okay";
+			reg = <0x4000 0x100>;
+			interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x2
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x3
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x5
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "soc-update",
+					  "soc-ready",
+					  "bsoc-delta",
+					  "msoc-delta",
+					  "msoc-low",
+					  "msoc-empty",
+					  "msoc-high",
+					  "msoc-full";
+		};
+
+		qcom,fg-batt-info@4100 {
+			status = "okay";
+			reg = <0x4100 0x100>;
+			interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "vbatt-pred-delta",
+					  "vbatt-low",
+					  "esr-delta",
+					  "batt-missing",
+					  "batt-temp-delta";
+		};
+
+		qcom,fg-memif@4400 {
+			status = "okay";
+			reg = <0x4400 0x100>;
+			interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "ima-rdy",
+					  "mem-xcp",
+					  "dma-grant";
+		};
+	};
+};
+
+&pm660_1 {
+	pm660_haptics: qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pm660_revid>;
+		qcom,pmic-misc = <&pm660_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <1>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,lra-high-z = "opt0";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
+};
+
+/* pm660 gpio pinctrl configuration */
+&pm660_gpios {
+	/* GPIO 4 (NFC_CLK_REQ) */
+	nfc_clk {
+		nfc_clk_default: nfc_clk_default {
+		pins = "gpio4";
+		function = "normal";
+		input-enable;
+		power-source = <1>;
+		};
+	};
+
+	vreg_bob {
+		vreg_regulator_bob: vreg_regulator-bob {
+			pins = "gpio12";
+			function = "normal";
+			output-enable;
+			qcom,drive-strength = "medium";
+		};
+	};
+
+	bg_daemon_reset {
+		bg_daemon_reset_msm: bg_daemon_reset_msm {
+			pins = "gpio5";
+			function = "func1";
+			output-enable;
+			qcom,drive-strength = "medium";
+			bias-disable;
+		};
+	};
+};
+
+&pm660_misc {
+	qcom,support-twm-config;
+};
+
+/ {
+	/delete-node/ qcom,battery-data;
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-palladium-1500mah.dtsi"
+	};
+};
+
+&pm660_charger {
+	qcom,pd-not-supported;
+};
+
+&usb_otg {
+	extcon = <&pm660_charger>;
+};
+
+&pm660_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pm660_pdphy {
+	/delete-property/ vdd-pdphy-supply;
+};
+
+&thermal_zones {
+	vbat_adc {
+		cooling-maps {
+			/delete-node/ vbat_map6;
+			/delete-node/ vbat_map7;
+		};
+	};
+	soc {
+		cooling-maps {
+		/delete-node/ soc_map6;
+		/delete-node/ soc_map7;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 80d3e82c..612b9f5 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -34,12 +34,14 @@
 		sda845-v2-mtp-overlay.dtbo \
 		sda845-v2-qrd-overlay.dtbo \
 		sda845-v2-hdk-overlay.dtbo \
+		sda845-v2-svr-overlay.dtbo \
 		sda845-v2-4k-panel-mtp-overlay.dtbo \
 		sda845-v2-4k-panel-cdp-overlay.dtbo \
 		sda845-v2-4k-panel-qrd-overlay.dtbo \
 		sda845-v2.1-cdp-overlay.dtbo \
 		sda845-v2.1-mtp-overlay.dtbo \
 		sda845-v2.1-qrd-overlay.dtbo \
+		sda845-v2.1-svr-overlay.dtbo \
 		sda845-v2.1-4k-panel-cdp-overlay.dtbo \
 		sda845-v2.1-4k-panel-mtp-overlay.dtbo \
 		sda845-v2.1-4k-panel-qrd-overlay.dtbo \
@@ -77,12 +79,14 @@
 sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-hdk-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-svr-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2.1-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-svr-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb
@@ -169,7 +173,7 @@
 qcs605-cdp-overlay.dtbo-base := qcs605.dtb
 qcs605-mtp-overlay.dtbo-base := qcs605.dtb
 qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
-qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb
 qcs605-360camera-overlay.dtbo-base := qcs605.dtb
 
 else
@@ -220,7 +224,15 @@
 	msm8953-cdp-overlay.dtbo \
 	msm8953-rcm-overlay.dtbo \
 	msm8953-qrd-overlay.dtbo \
-	msm8953-iot-mtp-overlay.dtbo
+	msm8953-iot-mtp-overlay.dtbo \
+	sdm450-cdp-s2-overlay.dtbo \
+	sdm450-mtp-s3-overlay.dtbo \
+	sdm450-qrd-sku4-overlay.dtbo
+
+dtbo-$(CONFIG_ARCH_SDM632) += sdm632-rumi-overlay.dtbo \
+	sdm450-cdp-s2-overlay.dtbo \
+	sdm450-mtp-s3-overlay.dtbo \
+	sdm450-qrd-sku4-overlay.dtbo
 
 msm8953-mtp-overlay.dtbo-base := sdm450.dtb \
 	msm8953.dtb \
@@ -251,6 +263,14 @@
 msm8953-ext-codec-rcm-overlay.dtbo-base := msm8953.dtb \
 	apq8053.dtb
 msm8953-cdp-1200p-overlay.dtbo-base := msm8953.dtb
+sdm450-cdp-s2-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb \
+	msm8953-pmi632.dtb
+sdm450-mtp-s3-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb
+sdm450-qrd-sku4-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb
+sdm632-rumi-overlay.dtbo-base := sdm632.dtb
 
 else
 dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \
@@ -274,7 +294,17 @@
 	msm8953-pmi8937-cdp.dtb \
 	msm8953-pmi8937-mtp.dtb \
 	msm8953-pmi8940-ext-codec-mtp.dtb \
-	msm8953-pmi8937-ext-codec-mtp.dtb
+	msm8953-pmi8937-ext-codec-mtp.dtb \
+	msm8953-pmi632-cdp-s2.dtb
+
+dtb-$(CONFIG_ARCH_MSM8937) += msm8937-pmi8950-mtp.dtb \
+	msm8937-interposer-sdm439-cdp.dtb \
+	msm8937-interposer-sdm439-mtp.dtb \
+	msm8937-interposer-sdm439-qrd.dtb
+
+dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb
+
+dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb
 
 dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \
 	sdm450-cdp.dtb \
@@ -287,7 +317,18 @@
 	sdm450-pmi632-cdp-s2.dtb \
 	sdm450-pmi632-mtp-s3.dtb
 
-dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb
+dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb \
+	sdm632-cdp-s2.dtb	\
+	sdm632-mtp-s3.dtb	\
+	sdm632-qrd-sku4.dtb
+
+dtb-$(CONFIG_ARCH_SDM439) += sdm439-mtp.dtb \
+	sdm439-cdp.dtb \
+	sdm439-qrd.dtb
+
+dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \
+	sdm429-cdp.dtb \
+	sdm429-qrd.dtb
 
 endif
 
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
index bf9e2f2..6bb67c3 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "apq8053.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi b/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi
new file mode 100644
index 0000000..7994285
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+		dsi_adv7533_1080p: qcom,mdss_dsi_adv7533_1080p {
+		label = "adv7533 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_1080p";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [
+				E6 38 26 00 68 6C 2A 3A 2C 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0];
+		qcom,dba-panel;
+		qcom,bridge-name = "adv7533";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi b/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi
new file mode 100644
index 0000000..b84488c0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi
@@ -0,0 +1,74 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+dsi_adv7533_720p: qcom,mdss_dsi_adv7533_720p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_720p";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <720>;
+		qcom,mdss-dsi-h-front-porch = <110>;
+		qcom,mdss-dsi-h-back-porch = <220>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <20>;
+		qcom,mdss-dsi-v-front-porch = <5>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-panel-timings = [
+				A4 24 18 00 4E 52 1C 28 1C 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x20>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 08 02 03 01 03 04 a0];
+		qcom,dba-panel;
+		qcom,bridge-name = "adv7533";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi
new file mode 100644
index 0000000..cbf82af
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi
@@ -0,0 +1,67 @@
+/* Copyright (c) 2015, 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.
+ */
+
+&mdss_mdp {
+	dsi_adv7533_1080p: qcom,mdss_dsi_adv7533_1080p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_1080p";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6c 2a 3a
+								2c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,dba-panel;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi
new file mode 100644
index 0000000..55ce9f7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi
@@ -0,0 +1,66 @@
+/* Copyright (c) 2015, 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.
+ */
+
+&mdss_mdp {
+	dsi_adv7533_720p: qcom,mdss_dsi_adv7533_720p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_720p";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <720>;
+		qcom,mdss-dsi-h-front-porch = <110>;
+		qcom,mdss-dsi-h-back-porch = <220>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <20>;
+		qcom,mdss-dsi-v-front-porch = <5>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-panel-timings = [a4 24 18 00 4e 52 1c 28
+								1c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x20>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,dba-panel;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
index 3af01c1f..515efb8 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
@@ -36,8 +36,6 @@
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-lane-2-state;
 		qcom,mdss-dsi-lane-3-state;
-		qcom,mdss-dsi-t-clk-pre = <0x30>;
-		qcom,mdss-dsi-t-clk-post = <0x0e>;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-lp11-init;
@@ -50,27 +48,27 @@
 			timing@0 {
 				qcom,mdss-dsi-panel-width = <1080>;
 				qcom,mdss-dsi-panel-height = <2160>;
-				qcom,mdss-dsi-h-front-porch = <24>;
-				qcom,mdss-dsi-h-back-porch = <24>;
-				qcom,mdss-dsi-h-pulse-width = <16>;
+				qcom,mdss-dsi-h-front-porch = <42>;
+				qcom,mdss-dsi-h-back-porch = <42>;
+				qcom,mdss-dsi-h-pulse-width = <10>;
 				qcom,mdss-dsi-h-sync-skew = <0>;
-				qcom,mdss-dsi-v-back-porch = <40>;
-				qcom,mdss-dsi-v-front-porch = <36>;
-				qcom,mdss-dsi-v-pulse-width = <2>;
+				qcom,mdss-dsi-v-back-porch = <15>;
+				qcom,mdss-dsi-v-front-porch = <10>;
+				qcom,mdss-dsi-v-pulse-width = <3>;
 				qcom,mdss-dsi-panel-framerate = <60>;
 				qcom,mdss-dsi-on-command = [
 					39 01 00 00 00 00 04 B9 FF 83 99
 					39 01 00 00 00 00 02 D2 88
-					39 01 00 00 00 00 10 B1 02 04 74 94 01
-					   32 33 11 11 E6 5D 56 73 02 02
+					39 01 00 00 00 00 0c B1 02 04 72 92 01
+					   32 AA 11 11 52 57
 					39 01 00 00 00 00 10 B2 00 80 80 CC 05
 					   07 5A 11 10 10 00 1E 70 03 D4
-					39 01 00 00 00 00 2D B4 00 FF 59 59 0C
-					   AC 00 00 0C 00 07 0A 00 28 07 08 0C
-					   21 03 00 00 00 AE 87 59 59 0C AC 00
-					   00 0C 00 07 0A 00 28 07 08 0C 01 00
-					   00 AE 01
-					39 01 00 00 05 00 22 D3 00 00 01 01 00
+					39 01 00 00 00 00 2D B4 00 FF 59 59 01
+					   AB 00 00 09 00 03 05 00 28 03 0B 0D
+					   21 03 02 00 0C A3 80 59 59 02 AB 00
+					   00 09 00 03 05 00 28 03 0B 0D 02 00
+					   0C A3 01
+					39 01 00 00 05 00 22 D3 00 0C 03 03 00
 					   00 10 10 00 00 03 00 03 00 08 78 08
 					   78 00 00 00 00 00 24 02 05 05 03 00
 					   00 00 05 40
@@ -86,26 +84,25 @@
 					39 01 00 00 00 00 11 D8 AA AA AA AA AA
 					   AA AA AA AA BA AA AA AA BA AA AA
 					39 01 00 00 00 00 02 BD 01
-					39 01 00 00 00 00 11 D8 82 EA AA AA 82
-					   EA AA AA 82 EA AA AA 82 EA AA AA
+					39 01 00 00 00 00 11 D8 00 00 00 00 00
+					   00 00 00 82 EA AA AA 82 EA AA AA
 					39 01 00 00 00 00 02 BD 02
 					39 01 00 00 00 00 09 D8 FF FF C0 3F FF
 					   FF C0 3F
 					39 01 00 00 00 00 02 BD 00
-					39 01 00 00 05 00 37 E0 08 2A 39 35 74
-					   7C 87 7F 84 8A 8E 91 93 96 9B 9C 9E
-					   A5 A6 AE A1 AF B2 5C 58 63 74 08 2A
-					   39 35 74 7C 87 7F 84 8A 8E 91 93 96
-					   9B 9C 9E A5 A6 AE A1 AF B2 5C 58 63
-					   74
+					39 01 00 00 05 00 37 E0 01 21 31 2D 66
+					   6F 7B 75 7A 81 86 89 8C 90 95 97 9A
+					   A1 A2 AA 9E AD B0 5B 57 63 7A 01 21
+					   31 2D 66 6F 7B 75 7A 81 86 89 8C 90
+					   95 97 9A A1 A2 AA 9E AD B0 5B 57 63
+					   7A
 					39 01 00 00 00 00 03 B6 7E 7E
 					39 01 00 00 00 00 02 CC 08
-					39 01 00 00 00 00 06 C7 00 08 00 01 08
-					39 01 00 00 00 00 03 C0 25 5A
-					05 01 00 00 78 00 02 11 00
-					05 01 00 00 14 00 02 29 00];
-				qcom,mdss-dsi-off-command = [05 01 00 00 14 00
-				  02 28 00 05 01 00 00 78 00 02 10 00];
+					05 01 00 00 96 00 02 11 00
+					05 01 00 00 32 00 02 29 00];
+				qcom,mdss-dsi-off-command = [
+					05 01 00 00 32 00 02 28 00
+					05 01 00 00 96 00 02 10 00];
 				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 			};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
new file mode 100644
index 0000000..77f2a1d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -0,0 +1,133 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&mdss_mdp {
+	dsi_hx8399c_truly_vid: qcom,mdss_dsi_hx8399c_truly_video{
+		qcom,mdss-dsi-panel-name =
+			"hx8399c video mode dsi truly panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <2160>;
+		qcom,mdss-dsi-h-front-porch = <24>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <40>;
+		qcom,mdss-dsi-v-front-porch = <36>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			39 01 00 00 00 00 04
+				b9 ff 83 99
+			39 01 00 00 00 00 02
+				d2 88
+			39 01 00 00 00 00 10
+				b1 02 04 74 94 01 32 33
+				11 11 e6 5d 56 73 02 02
+			39 01 00 00 00 00 10
+				b2 00 80 80 cc 05 07 5a
+				11 10 10 00 1e 70 03 D4
+			39 01 00 00 00 00 2d
+				b4 00 ff 59 59 0c ac 00
+				00 0c 00 07 0a 00 28 07
+				08 0c 21 03 00 00 00 ae
+				87 59 59 0c ac 00 00 0c
+				00 07 0a 00 28 07 08 0c
+				01 00 00 ae 01
+			39 01 00 00 05 00 22
+				d3 00 00 01 01 00 00 10
+				10 00 00 03 00 03 00 08
+				78 08 78 00 00 00 00 00
+				24 02 05 05 03 00 00 00
+				05 40
+			39 01 00 00 05 00 21
+				d5 20 20 19 19 18 18 02
+				03 00 01 24 24 18 18 18
+				18 24 24 00 00 00 00 00
+				00 00 00 2f 2f 30 30 31
+				31
+			39 01 00 00 05 00 21
+				d6 24 24 18 18 19 19 01
+				00 03 02 24 24 18 18 18
+				18 20 20 40 40 40 40 40
+				40 40 40 2f 2f 30 30 31
+				31
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 00 00 11
+				d8 aa aa aa aa aa aa aa
+				aa aa ba aa aa aa ba aa
+				aa
+			39 01 00 00 00 00 02
+				bd 01
+			39 01 00 00 00 00 11
+				d8 82 ea aa aa 82 ea aa
+				aa 82 ea aa aa 82 ea aa
+				aa
+			39 01 00 00 00 00 02
+				bd 02
+			39 01 00 00 00 00 09
+				d8 ff ff c0 3f ff ff c0
+				3f
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 05 00 37
+				e0 08 2a 39 35 74 7c 87
+				7f 84 8a 8e 91 93 96 9b
+				9c 9e a5 a6 ae a1 af b2
+				5c 58 63 74 08 2a 39 35
+				74 7c 87 7f 84 8a 8e 91
+				93 96 9b 9c 9e a5 a6 ae
+				a1 af b2 5c 58 63 74
+			39 01 00 00 00 00 03
+				b6 7e 7e
+			39 01 00 00 00 00 02
+				cc 08
+			39 01 00 00 00 00 06
+				c7 00 08 00 01 08
+			39 01 00 00 00 00 03
+				c0 25 5a
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 14 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-t-clk-post = <0x0e>;
+		qcom,mdss-dsi-t-clk-pre = <0x31>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi
new file mode 100644
index 0000000..7297d2a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi
@@ -0,0 +1,69 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_lt8912_1080_vid: qcom,mdss_dsi_lt8912_1080p_video {
+		qcom,mdss-dsi-panel-name = "lt8912 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			05 01 00 00 a0 00 02 11 00
+			05 01 00 00 a0 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 78 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1a 08 09 05 03 04 a0];
+		qcom,mdss-dsi-panel-timings = [
+				e6 38 26 00 68 6c 2a 3a 2c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2b>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi
new file mode 100644
index 0000000..cde7fb4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi
@@ -0,0 +1,67 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_lt8912_480_vid: qcom,mdss_dsi_lt8912_480p_video {
+		qcom,mdss-dsi-panel-name = "lt8912 480p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <640>;
+		qcom,mdss-dsi-panel-height = <480>;
+		qcom,mdss-dsi-h-front-porch = <16>;
+		qcom,mdss-dsi-h-back-porch = <48>;
+		qcom,mdss-dsi-h-pulse-width = <96>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <32>;
+		qcom,mdss-dsi-v-front-porch = <15>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			05 01 00 00 a0 00 02 11 00
+			05 01 00 00 a0 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 78 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [
+			1D 1A 03 05 01 03 04 a0
+			1D 1A 03 05 01 03 04 a0
+			1D 0A 03 04 01 03 04 a0];
+		qcom,mdss-dsi-panel-timings = [
+			65 12 0C 00 34 38 10 16 0F 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
index 1b38d06..ca28261 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
@@ -27,7 +27,6 @@
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-tx-eot-append;
-		qcom,cmd-sync-wait-broadcast;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-lane-2-state;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi
new file mode 100644
index 0000000..90d42a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------
+ */
+
+&mdss_mdp {
+	dsi_r69006_1080p_cmd: qcom,mdss_dsi_r69006_1080p_cmd {
+		qcom,mdss-dsi-panel-name = "r69006 1080p cmd mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <82>;
+		qcom,mdss-dsi-h-pulse-width = <20>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <9>;
+		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-pulse-width = <15>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 B0 00
+			29 01 00 00 00 00 06
+				B3 04 10 00 00 00
+			29 01 00 00 00 00 03
+				B4 0C 00
+			29 01 00 00 00 00 04
+				B6 3B D3 00
+			23 01 00 00 00 00
+				02 C0 00
+			15 01 00 00 00 00
+				02 36 98
+			23 01 00 00 00 00
+				02 CC 04
+			29 01 00 00 00 00 20
+				C1 84 00 10 EF 8B F1 FF
+				FF DF 9C C5 9A 73 8D AD
+				63 FE FF FF CB F8 01 00
+				AA 40 02 C2 01 08 00 01
+			29 01 00 00 00 00 0A
+				CB 0D FE 1F 2C 00 00 00
+				00 00
+			29 01 00 00 00 00 0B
+				C2 01 F7 80 04 63 00 60
+				00 01 30
+			29 01 00 00 00 00 07
+				C3 55 01 00 01 00 00
+			29 01 00 00 00 00 12
+				C4 70 00 00 00 00 00 00
+				00 00 02 01 00 05 01 00
+				00 00
+			29 01 00 00 00 00 0F
+				C6 57 07 4A 07 4A 01 0E
+				01 02 01 02 09 15 07
+			29 01 00 00 00 00 1F
+				C7 00 06 0C 16 27 35 3F
+				4D 33 3C 49 5B 64 66 67
+				00 06 0C 16 27 35 3F 4D
+				33 3C 49 5B 64 66 67
+			29 01 00 00 00 00 14
+				C8 00 00 FE 01 08 E7 00
+				00 FD 02 03 A8 00 00 FC
+				E7 E9 C9 00
+			29 01 00 00 00 00 09
+				C9 1F 68 1F 68 4C 4C C4
+				11
+			29 01 00 00 00 00 11
+				D0 11 01 91 0B D9 19 19
+				00 00 00 19 99 00 00 00
+				00
+			29 01 00 00 00 00 1D
+				D3 1B 3B BB AD A5 33 33
+				33 00 80 AD A8 37 33 33
+				33 33 F7 F2 1F 7D 7C FF
+				0F 99 00 FF FF
+			29 01 00 00 00 00 04
+				D4 57 33 03
+			29 01 00 00 00 00 0C
+				D5 66 00 00 01 32 01 32
+				00 0b 00 0b
+			29 01 00 00 00 00 02 BE 04
+			29 01 00 00 00 00 11
+				CF 40 10 00 00 00 00 32
+				00 00 00 00 00 00 00 00
+				00
+			29 01 00 00 00 00 06
+				DE 00 00 3F FF 10
+			29 01 00 00 00 00 02 E9 00
+			29 01 00 00 00 00 02 F2 00
+			23 01 00 00 00 00 02 D6 01
+			39 01 00 00 00 00 02 35 00
+			39 01 00 00 00 00 02 51 FF
+			39 01 00 00 00 00 02 53 2C
+			39 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 0A 00 02 28 00
+			29 01 00 00 00 00 1d D3 13 3B BB A5 A5 33 33 33
+				00 80 A4 A8 37 33 33 33 33 F7 F2 1F 7D
+				7C FF 0F 99 00 FF FF
+			05 01 00 00 5A 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [6E 3F 36 00 5A 4F 38 41 54
+			03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x1e>;
+		qcom,mdss-dsi-t-clk-pre = <0x30>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 01 0A];
+		qcom,mdss-dsi-panel-status-command-mode = "dsi_lp_mode";
+		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+		qcom,mdss-dsi-panel-status-read-length = <1>;
+		qcom,mdss-dsi-panel-status-value = <0x1C>;
+		qcom,mdss-dsi-panel-max-error-count = <3>;
+		qcom,mdss-dsi-rx-eot-ignore;
+		qcom,mdss-dsi-tx-eot-append;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi
new file mode 100644
index 0000000..4cbc922
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi
@@ -0,0 +1,137 @@
+/* Copyright (c) 2015, 2018, 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------
+ */
+
+&mdss_mdp {
+	dsi_r69006_1080p_video: qcom,mdss_dsi_r69006_1080p_video {
+		qcom,mdss-dsi-panel-name = "r69006 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <82>;
+		qcom,mdss-dsi-h-pulse-width = <20>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <9>;
+		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-pulse-width = <15>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 B0 00
+			29 01 00 00 00 00 06
+				B3 05 10 00 00 00
+			29 01 00 00 00 00 03 B4 0c 00
+			29 01 00 00 00 00 04 B6 3b c3 00
+			23 01 00 00 00 00 02 C0 00
+			15 01 00 00 00 00 02 36 98
+			23 01 00 00 00 00 02 CC 04
+			29 01 00 00 00 00 20
+				C1 84 00 10 EF 8B
+				F1 FF FF DF 9C C5
+				9A 73 8D AD 63 FE
+				FF FF CB F8 01 00
+				AA 40 00 C2 01 08
+				00 01
+			29 01 00 00 00 00 0A
+				CB 0D FE 1F 2C 00
+				00 00 00 00
+			29 01 00 00 00 00 0B
+				C2 01 F7 80 04 63
+				00 60 00 01 30
+			29 01 00 00 00 00 07
+				C3 55 01 00 01 00
+				00
+			29 01 00 00 00 00 12
+				C4 70 00 00 00 00
+				00 00 00 00 02 01
+				00 05 01 00 00 00
+			29 01 00 00 00 00 0F
+				C6 59 07 4a 07 4a
+				01 0E 01 02 01 02
+				09 15 07
+			29 01 00 00 00 00 1F
+				C7 00 30 32 34 42
+				4E 56 62 44 4A 54
+				62 6B 73 7F 08 30
+				32 34 42 4E 56 62
+				44 4A 54 62 6B 73
+				7F
+			29 01 00 00 00 00 14
+				C8 00 00 00 00 00
+				FC 00 00 00 00 00
+				FC 00 00 00 00 00
+				FC 00
+			29 01 00 00 00 00 09
+				C9 1F 68 1F 68 4C
+				4C C4 11
+			29 01 00 00 00 00 11
+				D0 33 01 91 0B D9
+				19 19 00 00 00 19
+				99 00 00 00 00
+			29 01 00 00 00 00 1D
+				D3 1B 3B BB AD A5
+				33 33 33 00 80 AD
+				A8 6f 6f 33 33 33
+				F7 F2 1F 7D 7C FF
+				0F 99 00 FF FF
+			29 01 00 00 00 00 04
+				D4 57 33 03
+			29 01 00 00 00 00 0C
+				D5 66 00 00 01 27
+				01 27 00 6D 00 6D
+			23 01 00 00 00 00 02 D6 81
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 78 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
+			05 01 00 00 96 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
+			22 27 1e 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2c>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 01 0A];
+		qcom,mdss-dsi-panel-status-command-mode = "dsi_lp_mode";
+		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+		qcom,mdss-dsi-panel-status-read-length = <1>;
+		qcom,mdss-dsi-panel-status-value = <0x1C>;
+		qcom,mdss-dsi-panel-max-error-count = <3>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
new file mode 100644
index 0000000..3a5d272
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
@@ -0,0 +1,50 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&mdss_mdp {
+	dsi_dual_test_cmd: qcom,mdss_dsi_test_oled_cmd {
+		qcom,mdss-dsi-panel-name =
+			"Dual test cmd mode DSI amoled non-DSC panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,adjust-timer-wakeup-ms = <1>;
+		qcom,mdss-dsi-reset-sequence = <1 2>, <0 2>, <1 2>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-hfp-power-mode;
+		qcom,mdss-dsi-hbp-power-mode;
+		qcom,mdss-dsi-hsa-power-mode;
+		qcom,mdss-dsi-display-timings {
+			timing@0{
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi
new file mode 100644
index 0000000..83b8ca0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&mdss_mdp {
+	dsi_truly_1080_cmd: qcom,mdss_dsi_truly_1080p_cmd {
+		qcom,mdss-dsi-panel-name = "truly 1080p cmd mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings =
+			[e6 38 26 00 68 6e 2a 3c 44 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 d6 01
+			15 01 00 00 00 00 02 35 00
+			15 01 00 00 00 00 02 51 ff
+			15 01 00 00 00 00 02 53 2c
+			15 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			23 01 00 00 00 00 02 b0 04
+			29 01 00 00 00 00 07 b3 04 00 00 00 00 00
+			29 01 00 00 00 00 03 b6 3a d3
+			29 01 00 00 00 00 03 c0 00 00
+			29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02
+				58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10
+				00 02 01 22 22 00 01
+			29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00
+			29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06
+				00 00 00 00 00 04 00 00 00 0c 06
+			29 01 00 00 00 00 29 c6 78 69 00 69 00 69 00 00 00 00 00
+				69 00 69 00 69 10 19 07 00 78 00 69 00 69 00 69
+				00 00 00 00 00 69 00 69 00 69 10 19 07
+			29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0
+			23 01 00 00 00 00 02 cc 0b
+			29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00
+			29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00
+				a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33
+			29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32
+			29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52
+				60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60
+				67 6e 77
+			29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00
+				00 fc 00 00 00 00 00 fc 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00
+				 05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi
new file mode 100644
index 0000000..b8a85d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi
@@ -0,0 +1,91 @@
+/* Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&mdss_mdp {
+	dsi_truly_1080_vid: qcom,mdss_dsi_truly_1080p_video {
+		qcom,mdss-dsi-panel-name = "truly 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings =
+			[e6 38 26 00 68 6e 2a 3c 44 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 35 00
+			15 01 00 00 00 00 02 51 ff
+			15 01 00 00 00 00 02 53 2c
+			15 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			23 01 00 00 00 00 02 b0 00
+			29 01 00 00 00 00 07 b3 14 00 00 00 00 00
+			29 01 00 00 00 00 03 b6 3a d3
+			29 01 00 00 00 00 03 c0 00 00
+			29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02
+				58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10
+				00 02 01 22 22 00 01
+			29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00
+			29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06
+				00 00 00 00 00 04 00 00 00 0c 06
+			29 01 00 00 00 00 29 c6 00 69 00 69 00 69 00 00 00 00 00
+				69 00 69 00 69 10 19 07 00 01 00 69 00 69 00 69
+				00 00 00 00 00 69 00 69 00 69 10 19 07
+			29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0
+			23 01 00 00 00 00 02 cc 0b
+			29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00
+			29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00
+				a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33
+			29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32
+			29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52
+				60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60
+				67 6e 77
+			29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00
+				00 fc 00 00 00 00 00 fc 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00
+				 05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-post-init-delay = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi
new file mode 100644
index 0000000..b0d13d0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi
@@ -0,0 +1,59 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_truly_wuxga_vid: qcom,mdss_dsi_truly_wuxga_video {
+		qcom,mdss-dsi-panel-name = "truly wuxga video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1200>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [f3 3a 26 00 6c 6e
+						2c 3e 2f 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00];
+		qcom,mdss-dsi-off-command = [22 01 00 00 00 00 02 00 00];
+		qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
new file mode 100644
index 0000000..5c379d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,fg-gen3-batterydata-demo-3600mah {
+	qcom,faschg-current-ma = <5000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,nom-batt-capacity-mah = <3600>;
+	qcom,batt-id-kohm = <100>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "fg-gen3-batterydata-demo-3600mah";
+	qcom,checksum = <0xA401>;
+	qcom,gui-version = "PMI8998GUI - 2.0.0.54";
+	qcom,fg-profile-data = [
+		B2 1F 79 05
+		86 0A 36 06
+		8D 1D 6F F4
+		39 12 9A 14
+		DC 18 91 22
+		26 3C EB 4B
+		5D 00 00 00
+		11 00 00 00
+		00 00 78 BC
+		26 CD 48 C2
+		1E 00 08 00
+		78 C5 64 E5
+		95 FC 1D F3
+		E1 F5 ED 0B
+		33 FD 8C 2B
+		1E 06 09 20
+		27 00 14 00
+		D8 1F 77 05
+		8B 0A 57 FC
+		59 1D 8B 00
+		33 03 78 0C
+		0F 19 ED 22
+		6B 45 21 53
+		5A 00 00 00
+		0E 00 00 00
+		00 00 F7 07
+		55 C2 AA AA
+		1A 00 00 00
+		B1 EA 64 E5
+		7C 06 93 F2
+		71 FD 9E 03
+		80 0A 7A 22
+		CF 33 CC FF
+		07 10 00 00
+		6F 0E 99 45
+		1A 00 40 00
+		13 01 0A FA
+		FF 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		];
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi
new file mode 100644
index 0000000..251440a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-palladium-1500mah.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,palladium_1500mah_averaged_masterslave_nov28th2017 {
+	/* #Palladium_1500mAh_averaged_MasterSlave_Nov28th2017*/
+	qcom,max-voltage-uv = <4200000>;
+	qcom,fg-cc-cv-threshold-mv = <4180>;
+	qcom,fastchg-current-ma = <1500>;
+	qcom,batt-id-kohm = <75>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "palladium_1500mah_averaged_masterslave_nov28th2017";
+	qcom,checksum = <0x1C13>;
+	qcom,gui-version = "PM660GUI - 0.0.0.45";
+	qcom,fg-profile-data = [
+		 A6 1F B2 05
+		 1F 0A F7 FC
+		 22 1D 32 F2
+		 B9 02 1C 0D
+		 25 11 FB 2B
+		 88 4C 0A 62
+		 65 00 00 00
+		 0E 00 00 00
+		 00 00 3D C4
+		 5D C5 A4 C2
+		 2A 00 08 00
+		 0F C5 76 D4
+		 71 FC 36 F3
+		 7D 06 C4 03
+		 EB DD F0 22
+		 1E 06 09 20
+		 27 00 14 00
+		 47 1F 5F FC
+		 9B 03 BE 06
+		 EE 1C 17 02
+		 F6 0D 27 03
+		 22 11 0B 32
+		 6D 4C 19 62
+		 7D 00 00 00
+		 0E 00 00 00
+		 00 00 6E CC
+		 03 CA FB BC
+		 26 00 00 00
+		 E9 DB 76 D4
+		 41 FD 89 EB
+		 3E 06 A9 F3
+		 C3 05 F3 13
+		 9C 33 CC FF
+		 07 10 00 00
+		 BD 05 33 43
+		 26 00 40 00
+		 35 02 0A FA
+		 FF 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi
new file mode 100644
index 0000000..0676019
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-vrcamera-1300mah.dtsi
@@ -0,0 +1,90 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,kayo_1300mah {
+	/* #kayo_1300mah_averaged_masterslave_feb26th2018 */
+	qcom,max-voltage-uv = <4200000>;
+	qcom,nom-batt-capacity-mah = <1300>;
+	qcom,batt-id-kohm = <100>;
+	qcom,jeita-fcc-ranges = <0   100  975000
+				101  450  1300000
+				451  600  1105000>;
+	qcom,jeita-fv-ranges = <0   100  4000000
+				101 200  4100000
+				201 450  4200000
+				451 500  4100000
+				501 600  4000000>;
+	qcom,step-chg-ranges = <3600000  4200000  2600000>;
+	qcom,battery-beta = <4250>;
+	qcom,fg-cc-cv-threshold-mv = <4190>;
+	qcom,battery-type = "kayo_1300mah_averaged_masterslave_feb26th2018";
+	qcom,checksum = <0xBFF4>;
+	qcom,gui-version = "PM660GUI - 0.0.0.45";
+	qcom,fg-profile-data = [
+		02 1F 9A 06
+		9A 02 A5 F5
+		DF 1C 91 FB
+		4A 04 97 03
+		29 19 F0 1B
+		80 3D 35 4A
+		81 00 00 00
+		18 00 00 00
+		00 00 74 CD
+		92 BC 65 CA
+		2E 00 08 00
+		EF 07 A5 E5
+		D7 F4 D8 E2
+		FF F5 C3 F3
+		20 0C 1E 4B
+		0A 06 09 20
+		27 00 14 00
+		50 1F BB FC
+		00 03 B9 F4
+		B1 1C D6 02
+		6A 0C 73 0B
+		BD 18 E4 22
+		7E 45 08 53
+		70 00 00 00
+		11 00 00 00
+		00 00 B0 CC
+		AA AA 86 CA
+		2A 00 00 00
+		E4 EA A5 E5
+		4D F5 2B DB
+		69 00 AE 02
+		96 05 6B 1A
+		A5 33 CC FF
+		07 10 00 00
+		5C 05 33 43
+		2A 00 40 00
+		31 01 0A FA
+		FF 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi
new file mode 100644
index 0000000..e862b0f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8937.dtsi
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+&soc {
+	kgsl_smmu: arm,smmu-kgsl@1c40000 {
+		status = "ok";
+		compatible = "qcom,smmu-v2";
+		qcom,tz-device-id = "GPU";
+		reg = <0x1c40000 0x10000>;
+		#iommu-cells = <1>;
+		#global-interrupts = <0>;
+		interrupts =  <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
+		qcom,dynamic;
+		qcom,use-3-lvl-tables;
+		qcom,enable-smmu-halt;
+		qcom,skip-init;
+		vdd-supply = <&gdsc_oxili_cx>;
+		qcom,regulator-names = "vdd";
+		clocks = <&clock_gcc clk_gcc_oxili_ahb_clk>,
+			     <&clock_gcc clk_gcc_bimc_gfx_clk>;
+		clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk";
+	};
+
+	/* A test device to test the SMMU operation */
+	kgsl_iommu_test_device0 {
+		status = "disabled";
+		compatible = "iommu-debug-test";
+		/* The SID should be valid one to get the proper
+		 *SMR,S2CR indices.
+		 */
+		iommus = <&kgsl_smmu 0x0>;
+	};
+
+	apps_iommu: qcom,iommu@1e00000 {
+		status = "okay";
+		compatible = "qcom,qsmmu-v500";
+		reg = <0x1e00000 0x40000>,
+			<0x1ee2000 0x20>;
+		reg-names = "base", "tcu-base";
+		#iommu-cells = <2>;
+		qcom,tz-device-id = "APPS";
+		qcom,skip-init;
+		qcom,enable-static-cb;
+		qcom,use-3-lvl-tables;
+		qcom,disable-atos;
+		#global-interrupts = <0>;
+		#size-cells = <1>;
+		#address-cells = <1>;
+		ranges;
+		interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clock_gcc clk_gcc_smmu_cfg_clk>,
+			     <&clock_gcc clk_gcc_apss_tcu_clk>;
+		clock-names = "iface_clk", "core_clk";
+	};
+};
+
+#include "msm-arm-smmu-impl-defs-8937.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi
new file mode 100644
index 0000000..ce3e1c3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8937.dtsi
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&kgsl_smmu {
+	attach-impl-defs = <0x6000 0x270>,
+		<0x6060 0x1055>,
+		<0x6800 0x6>,
+		<0x6900 0x3ff>,
+		<0x6924 0x204>,
+		<0x6928 0x10800>,
+		<0x6930 0x400>,
+		<0x6960 0xffffffff>,
+		<0x6b64 0xa0000>,
+		<0x6b68 0xaaab92a>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
index 49e148c..0e58559 100644
--- a/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 2017-2018, 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
diff --git a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
new file mode 100644
index 0000000..f2cea32
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
@@ -0,0 +1,195 @@
+/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	audio_codec_bg: sound {
+		status = "disabled";
+		compatible = "qcom,msm-bg-audio-codec";
+		qcom,model = "msm-bg-snd-card";
+		reg = <0x7702000 0x4>,
+		      <0x7702004 0x4>,
+		      <0x7702008 0x4>,
+		      <0x770200c 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			    "csr_gp_io_mux_spkr_ctl",
+			    "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			    "csr_gp_io_lpaif_sec_pcm_sec_mode_muxsel";
+
+		qcom,msm-snd-card-id = <0>;
+		qcom,msm-ext-pa = "primary";
+		qcom,tdm-audio-intf;
+		qcom,msm-afe-clk-ver = <1>;
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&lpa>,
+				<&voice_svc>;
+		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-pcm-lpa",
+				"msm-voice-svc";
+		asoc-cpu = <&dai_pri_auxpcm>,
+				<&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+				<&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+				<&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+				<&int_fm_rx>, <&int_fm_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>,
+				<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+				<&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>,
+				<&dai_pri_tdm_rx_2>, <&dai_pri_tdm_tx_2>,
+				<&dai_pri_tdm_rx_3>, <&dai_pri_tdm_tx_3>;
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+				"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+				"msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+				"msm-dai-q6-dev.12293", "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-tdm.36864",
+				"msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36866",
+				"msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36868",
+				"msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36870",
+				"msm-dai-q6-tdm.36871";
+		asoc-codec = <&stub_codec>;
+		asoc-codec-names = "msm-stub-codec.1";
+	};
+
+	pri_tdm_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 = <4>;
+		qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>;
+		qcom,msm-cpudai-tdm-clk-rate = <0>;
+		qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+		qcom,msm-cpudai-tdm-sec-port-enable;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
+		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
+		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-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36866>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36868>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36870>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	pri_tdm_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 = <4>;
+		qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>;
+		qcom,msm-cpudai-tdm-clk-rate = <0>;
+		qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+		qcom,msm-cpudai-tdm-sec-port-enable;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
+		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
+		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-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36867>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36869>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+		dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36871>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <0>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <0>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	wdsp_glink: qcom,wcd-dsp-glink {
+		compatible = "qcom,wcd-dsp-glink";
+		qcom,msm-codec-glink-edge = "bg";
+	};
+
+	bg_cdc: bg_codec {
+		status = "disabled";
+		compatible = "qcom,bg-codec";
+		qcom,subsys-name = "modem";
+		qcom,bg-glink {
+			compatible = "qcom,bg-cdc-glink";
+			qcom,msm-glink-channels = <4>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi
new file mode 100644
index 0000000..eea1a85
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-bus.dtsi
@@ -0,0 +1,1064 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/msm/msm-bus-rule-ops.h>
+
+&soc {
+	static-rules {
+		compatible = "qcom,msm-bus-static-bw-rules";
+
+		rule0 {
+			qcom,src-nodes = <&mas_apps_proc>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_LE>;
+			qcom,thresh = <200000>;
+			qcom,mode = <THROTTLE_ON>;
+			qcom,dest-node = <&mas_apps_proc>;
+			qcom,dest-bw = <600000>;
+		};
+
+		rule1 {
+			qcom,src-nodes = <&mas_apps_proc>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_LE>;
+			qcom,thresh = <400000>;
+			qcom,mode = <THROTTLE_ON>;
+			qcom,dest-node = <&mas_apps_proc>;
+			qcom,dest-bw = <1200000>;
+		};
+
+		rule2 {
+			qcom,src-nodes = <&mas_apps_proc>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_GT>;
+			qcom,thresh = <400000>;
+			qcom,mode = <THROTTLE_OFF>;
+			qcom,dest-node = <&mas_apps_proc>;
+		};
+
+		rule3 {
+			qcom,src-nodes = <&mas_oxili>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_LE>;
+			qcom,thresh = <200000>;
+			qcom,mode = <THROTTLE_ON>;
+			qcom,dest-node = <&mas_oxili>;
+			qcom,dest-bw = <600000>;
+		};
+
+		rule4 {
+			qcom,src-nodes = <&mas_oxili>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_LE>;
+			qcom,thresh = <400000>;
+			qcom,mode = <THROTTLE_ON>;
+			qcom,dest-node = <&mas_oxili>;
+			qcom,dest-bw = <1200000>;
+		};
+
+		rule5 {
+			qcom,src-nodes = <&mas_oxili>;
+			qcom,src-field = <FLD_CLK>;
+			qcom,src-op = <OP_GT>;
+			qcom,thresh = <400000>;
+			qcom,mode = <THROTTLE_OFF>;
+			qcom,dest-node = <&mas_oxili>;
+		};
+	};
+
+	/* Version = 2 */
+	ad_hoc_bus: ad-hoc-bus {
+		compatible = "qcom,msm-bus-device";
+		reg = <0x580000 0x13000>,
+			<0x580000 0x13000>,
+			<0x400000 0x62000>,
+			<0x500000 0x11000>;
+		reg-names = "snoc-base", "snoc-mm-base",
+				 "bimc-base", "pcnoc-base";
+
+		/*Buses*/
+
+		fab_bimc: fab-bimc {
+			cell-id = <MSM_BUS_FAB_BIMC>;
+			label = "fab-bimc";
+			qcom,fab-dev;
+			qcom,base-name = "bimc-base";
+			qcom,bus-type = <2>;
+			qcom,util-fact = <154>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_rpm  clk_bimc_msmbus_clk>,
+				<&clock_rpm  clk_bimc_msmbus_a_clk>;
+		};
+
+		fab_pcnoc: fab-pcnoc {
+			cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+			label = "fab-pcnoc";
+			qcom,fab-dev;
+			qcom,base-name = "pcnoc-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-delta = <0x1000>;
+			qcom,bus-type = <1>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_rpm  clk_pcnoc_msmbus_clk>,
+				<&clock_rpm  clk_pcnoc_msmbus_a_clk>;
+		};
+
+		fab_snoc: fab-snoc {
+			cell-id = <MSM_BUS_FAB_SYS_NOC>;
+			label = "fab-snoc";
+			qcom,fab-dev;
+			qcom,base-name = "snoc-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-off = <0x1000>;
+			qcom,bus-type = <1>;
+			clock-names = "bus_clk", "bus_a_clk", "bus_qos_clk";
+			clocks = <&clock_rpm  clk_snoc_msmbus_clk>,
+				<&clock_rpm  clk_snoc_msmbus_a_clk>,
+				<&clock_gcc clk_gcc_snoc_qosgen_clk>;
+		};
+
+		fab_snoc_mm: fab-snoc-mm {
+			cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+			label = "fab-snoc-mm";
+			qcom,fab-dev;
+			qcom,base-name = "snoc-mm-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-off = <0x1000>;
+			qcom,bus-type = <1>;
+			qcom,util-fact = <167>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_rpm  clk_snoc_mm_msmbus_clk>,
+				<&clock_rpm  clk_snoc_mm_msmbus_a_clk>;
+		};
+
+		/* Masters */
+		mas_apps_proc: mas-apps-proc {
+			cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+			label = "mas-apps-proc";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <0>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+			qcom,prio-lvl = <0>;
+			qcom,prio-rd = <0>;
+			qcom,prio-wr = <0>;
+			qcom,ws = <10000>;
+			qcom,gp = <5000>;
+			qcom,thmp = <50>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+		};
+
+		mas_oxili: mas-oxili {
+			cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+			label = "mas-oxili";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <2>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+			qcom,prio-lvl = <0>;
+			qcom,prio-rd = <0>;
+			qcom,prio-wr = <0>;
+			qcom,ws = <10000>;
+			qcom,gp = <5000>;
+			qcom,thmp = <50>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_GFX3D>;
+		};
+
+		mas_snoc_bimc_0: mas-snoc-bimc-0 {
+			cell-id = <MSM_BUS_SNOC_BIMC_0_MAS>;
+			label = "mas-snoc-bimc-0";
+			qcom,buswidth = <8>;
+			qcom,qport = <3>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_ebi>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_0>;
+		};
+
+		mas_snoc_bimc_1: mas-snoc-bimc-1 {
+			cell-id = <MSM_BUS_SNOC_BIMC_1_MAS>;
+			label = "mas-snoc-bimc-1";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <4>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_ebi>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_1>;
+		};
+
+		mas_tcu_0: mas-tcu-0 {
+			cell-id = <MSM_BUS_MASTER_TCU_0>;
+			label = "mas-tcu-0";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <5>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+			qcom,prio-lvl = <2>;
+			qcom,prio-rd = <2>;
+			qcom,prio-wr = <2>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+		};
+
+		mas_tcu_1: mas-tcu-1 {
+			cell-id = <MSM_BUS_MASTER_TCU_1>;
+			label = "mas-tcu-1";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <6>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_bimc_snoc &slv_ebi>;
+			qcom,prio-lvl = <2>;
+			qcom,prio-rd = <2>;
+			qcom,prio-wr = <2>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_TCU_1>;
+		};
+
+		mas_audio: mas-audio {
+			cell-id = <MSM_BUS_MASTER_AUDIO>;
+			label = "mas-audio";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_AUDIO>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_spdm: mas-spdm {
+			cell-id = <MSM_BUS_MASTER_SPDM>;
+			label = "mas-spdm";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SPDM>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_dehr: mas-dehr {
+			cell-id = <MSM_BUS_MASTER_DEHR>;
+			label = "mas-dehr";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_DEHR>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_qpic: mas-qpic {
+			cell-id = <MSM_BUS_MASTER_QPIC>;
+			label = "mas-qpic";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QPIC>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_blsp_1: mas-blsp-1 {
+			cell-id = <MSM_BUS_MASTER_BLSP_1>;
+			label = "mas-blsp-1";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_usb_hs: mas-usb-hs {
+			cell-id = <MSM_BUS_MASTER_USB_HS>;
+			label = "mas-usb-hs";
+			qcom,buswidth = <4>;
+			qcom,connections = <&pcnoc_m_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_USB_HS>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_crypto: mas-crypto {
+			cell-id = <MSM_BUS_MASTER_CRYPTO_CORE0>;
+			label = "mas-crypto";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <0>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_1>;
+			qcom,prio1 = <0>;
+			qcom,prio0 = <0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_sdcc_1: mas-sdcc-1 {
+			cell-id = <MSM_BUS_MASTER_SDCC_1>;
+			label = "mas-sdcc-1";
+			qcom,buswidth = <8>;
+			qcom,qport = <7>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_sdcc_2: mas-sdcc-2 {
+			cell-id = <MSM_BUS_MASTER_SDCC_2>;
+			label = "mas-sdcc-2";
+			qcom,buswidth = <8>;
+			qcom,qport = <8>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SDCC_2>;
+			qcom,blacklist =
+				<&slv_blsp_1 &slv_message_ram &slv_usb_hs
+				 &slv_venus_cfg &slv_gpu_cfg &slv_camera_ss_cfg
+				 &slv_crypto_0_cfg &slv_tlmm &slv_tcu
+				 &slv_pdm &slv_snoc_cfg &slv_qpic
+				 &slv_tcsr &slv_prng &slv_sdcc_2
+				 &slv_pmic_arb &slv_disp_ss_cfg &slv_usb_phy
+				 &slv_sdcc_1 &slv_audio>;
+		};
+
+		mas_snoc_pcnoc: mas-snoc-pcnoc {
+			cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+			label = "mas-snoc-pcnoc";
+			qcom,buswidth = <8>;
+			qcom,qport = <9>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+		};
+
+		mas_qdss_bam: mas-qdss-bam {
+			cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+			label = "mas-qdss-bam";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,qport = <11>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&qdss_int>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+			qcom,blacklist =
+				<&slv_kpss_ahb &slv_cats_1 &slv_qdss_stm
+				 &slv_cats_0>;
+		};
+
+		mas_bimc_snoc: mas-bimc-snoc {
+			cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+			label = "mas-bimc-snoc";
+			qcom,buswidth = <8>;
+			qcom,connections = <&snoc_int_0 &snoc_int_1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+		};
+
+		mas_mdp: mas-mdp {
+			cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+			label = "mas-mdp";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,qport = <7>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&mm_int_1 &mm_int_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MDP>;
+			qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+				 &slv_qdss_stm &slv_cats_0>;
+		};
+
+		mas_pcnoc_snoc: mas-pcnoc-snoc {
+			cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+			label = "mas-pcnoc-snoc";
+			qcom,buswidth = <8>;
+			qcom,qport = <5>;
+			qcom,qos-mode = "fixed";
+			qcom,connections =
+				<&snoc_int_0 &snoc_int_1 &snoc_int_bimc>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+			qcom,blacklist = <&slv_cats_1 &slv_cats_0>;
+		};
+
+		mas_venus: mas-venus {
+			cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+			label = "mas-venus";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,qport = <8>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&mm_int_0 &mm_int_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_VIDEO>;
+			qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+				 &slv_qdss_stm &slv_cats_0>;
+		};
+
+		mas_vfe: mas-vfe {
+			cell-id = <MSM_BUS_MASTER_VFE>;
+			label = "mas-vfe";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,qport = <9>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&mm_int_1 &mm_int_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_VFE>;
+			qcom,blacklist = <&slv_kpss_ahb &slv_imem &slv_cats_1
+				 &slv_qdss_stm &slv_cats_0>;
+		};
+
+		mas_qdss_etr: mas-qdss-etr {
+			cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+			label = "mas-qdss-etr";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,qport = <10>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&qdss_int>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+			qcom,blacklist =
+				<&slv_kpss_ahb &slv_cats_1 &slv_qdss_stm
+				 &slv_cats_0>;
+		};
+
+	/*Internal nodes*/
+		pcnoc_m_0: pcnoc-m-0 {
+			cell-id = <MSM_BUS_PNOC_M_0>;
+			label = "pcnoc-m-0";
+			qcom,buswidth = <8>;
+			qcom,qport = <5>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_pcnoc_snoc>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+		};
+
+		pcnoc_m_1: pcnoc-m-1 {
+			cell-id = <MSM_BUS_PNOC_M_1>;
+			label = "pcnoc-m-1";
+			qcom,buswidth = <8>;
+			qcom,qport = <6>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_pcnoc_snoc>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+		};
+
+		pcnoc_int_0: pcnoc-int-0 {
+			cell-id = <MSM_BUS_PNOC_INT_0>;
+			label = "pcnoc-int-0";
+			qcom,buswidth = <8>;
+			qcom,connections = <&pcnoc_s_3 &pcnoc_s_2 &pcnoc_s_1 \
+			 &pcnoc_s_0 &pcnoc_s_7 &pcnoc_s_5 &pcnoc_s_4 &slv_tcu>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+		};
+
+		pcnoc_int_1: pcnoc-int-1 {
+			cell-id = <MSM_BUS_PNOC_INT_1>;
+			label = "pcnoc-int-1";
+			qcom,buswidth = <8>;
+			qcom,connections = <&slv_pcnoc_snoc>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+		};
+
+		pcnoc_s_0: pcnoc-s-0 {
+			cell-id = <MSM_BUS_PNOC_SLV_0>;
+			label = "pcnoc-s-0";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_sdcc_1 &slv_tcsr &slv_blsp_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+		};
+
+		pcnoc_s_1: pcnoc-s-1 {
+			cell-id = <MSM_BUS_PNOC_SLV_1>;
+			label = "pcnoc-s-1";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_message_ram &slv_crypto_0_cfg \
+			 &slv_usb_hs &slv_pdm &slv_prng &slv_qpic>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+		};
+
+		pcnoc_s_2: pcnoc-s-2 {
+			cell-id = <MSM_BUS_PNOC_SLV_2>;
+			label = "pcnoc-s-2";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_spdm &slv_sdcc_2 \
+					&slv_audio &slv_dehr_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+		};
+
+		pcnoc_s_3: pcnoc-s-3 {
+			cell-id = <MSM_BUS_PNOC_SLV_3>;
+			label = "pcnoc-s-3";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_qdss_cfg &slv_usb_phy \
+					&slv_snoc_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+		};
+
+		pcnoc_s_4: pcnoc-s-4 {
+			cell-id = <MSM_BUS_PNOC_SLV_4>;
+			label = "pcnoc-s-4";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,connections =
+					<&slv_camera_ss_cfg &slv_disp_ss_cfg \
+					&slv_venus_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+		};
+
+		pcnoc_s_5: pcnoc-s-5 {
+			cell-id = <MSM_BUS_PNOC_SLV_5>;
+			label = "pcnoc-s-5";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_tlmm>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_5>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_5>;
+		};
+
+		pcnoc_s_7: pcnoc-s-7 {
+			cell-id = <MSM_BUS_PNOC_SLV_7>;
+			label = "pcnoc-s-7";
+			qcom,buswidth = <4>;
+			qcom,connections = <&slv_gpu_cfg &slv_imem_cfg \
+					&slv_bimc_cfg &slv_pmic_arb>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+		};
+
+		mm_int_0: mm-int-0 {
+			cell-id = <MSM_BUS_SNOC_MM_INT_0>;
+			label = "mm-int-0";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,connections = <&mm_int_bimc>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_0>;
+		};
+
+		mm_int_1: mm-int-1 {
+			cell-id = <MSM_BUS_SNOC_MM_INT_1>;
+			label = "mm-int-1";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,connections = <&mm_int_bimc>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_1>;
+		};
+
+		mm_int_2: mm-int-2 {
+			cell-id = <MSM_BUS_SNOC_MM_INT_2>;
+			label = "mm-int-2";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,connections = <&snoc_int_0>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_2>;
+		};
+
+		mm_int_bimc: mm-int-bimc {
+			cell-id = <MSM_BUS_SNOC_MM_INT_BIMC>;
+			label = "mm-int-bimc";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,connections = <&slv_snoc_bimc_1>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MM_INT_BIMC>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MM_INT_BIMC>;
+		};
+
+		qdss_int: qdss-int {
+			cell-id = <MSM_BUS_SNOC_QDSS_INT>;
+			label = "qdss-int";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,connections = <&snoc_int_0 &snoc_int_bimc>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_INT>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_INT>;
+		};
+
+		snoc_int_0: snoc-int-0 {
+			cell-id = <MSM_BUS_SNOC_INT_0>;
+			label = "snoc-int-0";
+			qcom,buswidth = <8>;
+			qcom,connections = <&slv_imem &slv_qdss_stm \
+					&slv_snoc_pcnoc>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_0>;
+		};
+
+		snoc_int_1: snoc-int-1 {
+			cell-id = <MSM_BUS_SNOC_INT_1>;
+			label = "snoc-int-1";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,connections = <&slv_cats_0 &slv_kpss_ahb \
+					 &slv_cats_1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_1>;
+		};
+
+		snoc_int_bimc: snoc-int-bimc {
+			cell-id = <MSM_BUS_SNOC_INT_BIMC>;
+			label = "snoc-int-bimc";
+			qcom,buswidth = <8>;
+			qcom,connections = <&slv_snoc_bimc_0>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_BIMC>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_BIMC>;
+		};
+
+	/*Slaves*/
+		slv_ebi:slv-ebi {
+			cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+			label = "slv-ebi";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+		};
+
+		slv_bimc_snoc:slv-bimc-snoc {
+			cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+			label = "slv-bimc-snoc";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,connections = <&mas_bimc_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+		};
+
+		slv_tcsr:slv-tcsr {
+			cell-id = <MSM_BUS_SLAVE_TCSR>;
+			label = "slv-tcsr";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+		};
+
+		slv_sdcc_1:slv-sdcc-1 {
+			cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+			label = "slv-sdcc-1";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+		};
+
+		slv_blsp_1:slv-blsp-1 {
+			cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+			label = "slv-blsp-1";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+		};
+
+		slv_crypto_0_cfg:slv-crypto-0-cfg {
+			cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+			label = "slv-crypto-0-cfg";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+		};
+
+		slv_message_ram:slv-message-ram {
+			cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+			label = "slv-message-ram";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+		};
+
+		slv_pdm:slv-pdm {
+			cell-id = <MSM_BUS_SLAVE_PDM>;
+			label = "slv-pdm";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+		};
+
+		slv_prng:slv-prng {
+			cell-id = <MSM_BUS_SLAVE_PRNG>;
+			label = "slv-prng";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+		};
+
+		slv_usb_hs:slv-usb-hs {
+			cell-id = <MSM_BUS_SLAVE_USB_HS>;
+			label = "slv-usb-hs";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_USB_HS>;
+		};
+
+		slv_qpic:slv-qpic {
+			cell-id = <MSM_BUS_SLAVE_QPIC>;
+			label = "slv-qpic";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QPIC>;
+		};
+
+		slv_spdm: slv-spdm {
+			cell-id = <MSM_BUS_SLAVE_SPDM>;
+			label = "slv-spdm";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SPDM_WRAPPER>;
+		};
+
+		slv_sdcc_2:slv-sdcc-2 {
+			cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+			label = "slv-sdcc-2";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_2>;
+		};
+
+		slv_audio:slv-audio {
+			cell-id = <MSM_BUS_SLAVE_AUDIO>;
+			label = "slv-audio";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_AUDIO>;
+		};
+
+		slv_dehr_cfg: slv-dehr-cfg {
+			cell-id = <MSM_BUS_SLAVE_DEHR_CFG>;
+			label = "slv-dehr-cfg";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_DEHR_CFG>;
+		};
+
+		slv_snoc_cfg:slv-snoc-cfg {
+			cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+			label = "slv-snoc-cfg";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+		};
+
+		slv_qdss_cfg: slv-qdss-cfg {
+			cell-id = <MSM_BUS_SLAVE_QDSS_CFG>;
+			label = "slv-qdss-cfg";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_CFG>;
+		};
+
+		slv_usb_phy:slv-usb-phy {
+			cell-id = <MSM_BUS_SLAVE_USB_PHYS_CFG>;
+			label = "slv-usb-phy";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_USB_PHY_CFG>;
+		};
+
+		slv_camera_ss_cfg:slv-camera-ss-cfg {
+			cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+			label = "slv-camera-ss-cfg";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CAMERA_CFG>;
+		};
+
+		slv_disp_ss_cfg:slv-disp-ss-cfg {
+			cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+			label = "slv-disp-ss-cfg";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_DISPLAY_CFG>;
+		};
+
+		slv_venus_cfg:slv-venus-cfg {
+			cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+			label = "slv-venus-cfg";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_VENUS_CFG>;
+		};
+
+		slv_tlmm:slv-tlmm {
+			cell-id = <MSM_BUS_SLAVE_TLMM>;
+			label = "slv-tlmm";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+		};
+
+		slv_gpu_cfg:slv-gpu-cfg {
+			cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+			label = "slv-gpu-cfg";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_GFX3D_CFG>;
+		};
+
+		slv_imem_cfg: slv-imem-cfg {
+			cell-id = <MSM_BUS_SLAVE_IMEM_CFG>;
+			label = "slv-imem-cfg";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_IMEM_CFG>;
+		};
+
+		 slv_bimc_cfg: slv-bimc-cfg {
+			cell-id = <MSM_BUS_SLAVE_BIMC_CFG>;
+			label = "slv-bimc-cfg";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_CFG>;
+		};
+
+		slv_pmic_arb:slv-pmic-arb {
+			cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+			label = "slv-pmic-arb";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+		};
+
+		slv_tcu:slv-tcu {
+			cell-id = <MSM_BUS_SLAVE_TCU>;
+			label = "slv-tcu";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+		};
+
+		slv_pcnoc_snoc:slv-pcnoc-snoc {
+			cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+			label = "slv-pcnoc-snoc";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,connections = <&mas_pcnoc_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+		};
+
+		slv_kpss_ahb:slv-kpss-ahb {
+			cell-id = <MSM_BUS_SLAVE_APPSS>;
+			label = "slv-kpss-ahb";
+			qcom,buswidth = <4>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+		};
+
+		slv_snoc_bimc_0:slv-snoc-bimc-0 {
+			cell-id = <MSM_BUS_SNOC_BIMC_0_SLV>;
+			label = "slv-snoc-bimc-0";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,connections = <&mas_snoc_bimc_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_0>;
+		};
+
+		slv_snoc_bimc_1:slv-snoc-bimc-1 {
+			cell-id = <MSM_BUS_SNOC_BIMC_1_SLV>;
+			label = "slv-snoc-bimc-1";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,connections = <&mas_snoc_bimc_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_1>;
+		};
+
+		slv_imem:slv-imem {
+			cell-id = <MSM_BUS_SLAVE_SYSTEM_IMEM>;
+			label = "slv-imem";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+		};
+
+		slv_snoc_pcnoc:slv-snoc-pcnoc {
+			cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+			label = "slv-snoc-pcnoc";
+			qcom,buswidth = <8>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,connections = <&mas_snoc_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+		};
+
+		slv_qdss_stm:slv-qdss-stm {
+			cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+			label = "slv-qdss-stm";
+			qcom,buswidth = <4>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+		};
+
+		slv_cats_0:slv-cats-0 {
+			cell-id = <MSM_BUS_SLAVE_CATS_128>;
+			label = "slv-cats-0";
+			qcom,buswidth = <16>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+		};
+
+		slv_cats_1:slv-cats-1 {
+			cell-id = <MSM_BUS_SLAVE_OCMEM_64>;
+			label = "slv-cats-1";
+			qcom,buswidth = <8>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CATS_1>;
+		};
+	};
+
+	devfreq_spdm_cpu {
+		compatible = "qcom,devfreq_spdm";
+		qcom,msm-bus,name = "devfreq_spdm";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<1 512 0 0>,
+				<1 512 0 0>;
+		qcom,msm-bus,active-only;
+		qcom,spdm-client = <0>;
+
+		clock-names = "cci_clk";
+		clocks = <&clock_cpu clk_a7ssmux>;
+
+		qcom,bw-upstep = <400>;
+		qcom,bw-dwnstep = <400>;
+		qcom,max-vote = <4000>;
+		qcom,up-step-multp = <3>;
+		qcom,spdm-interval = <100>;
+
+		qcom,ports = <11>;
+		qcom,alpha-up = <8>;
+		qcom,alpha-down = <15>;
+		qcom,bucket-size = <8>;
+
+		/*max pl1 freq, max pl2 freq*/
+		qcom,pl-freqs = <390000000 410000000>;
+
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,reject-rate = <5000 5000 5000 5000 5000 5000>;
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,response-time-us = <5000 5000 5000 5000 3000 3000>;
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,cci-response-time-us = <5000 5000 5000 5000 1000 1000>;
+		qcom,max-cci-freq = <1090000000>;
+	};
+
+	devfreq_spdm_gov {
+		compatible = "qcom,gov_spdm_hyp";
+		interrupt-names = "spdm-irq";
+		interrupts = <0 192 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
new file mode 100644
index 0000000..4e7d6f8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
@@ -0,0 +1,623 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tmc_etr: tmc@826000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0x826000 0x1000>,
+		      <0x884000 0x15000>;
+		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
+
+		qcom,memory-size = <0x100000>;
+		qcom,sg-enable;
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+		coresight-ctis = <&cti0 &cti8>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	tpiu: tpiu@820000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0x820000 0x1000>,
+		      <0x1100000 0xb0000>;
+		reg-names = "tpiu-base", "nidnt-base";
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+
+		qcom,nidnthw;
+		qcom,nidnt-swduart;
+		qcom,nidnt-swdtrc;
+		qcom,nidnt-jtag;
+		qcom,nidnt-spmi;
+		nidnt-gpio = <38>;
+		nidnt-gpio-polarity = <1>;
+
+		interrupts = <0 82 0>;
+		interrupt-names = "nidnt-irq";
+
+		vdd-supply = <&pm8909_l11>;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <15000 400000>;
+
+		vdd-io-supply = <&pm8909_l12>;
+		qcom,vdd-io-voltage-level = <2950000 2950000>;
+		qcom,vdd-io-current-level = <200 50000>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	replicator: replicator@824000 {
+		compatible = "qcom,coresight-replicator";
+		reg = <0x824000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-id = <2>;
+		coresight-name = "coresight-replicator";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0 1>;
+		coresight-child-list = <&tmc_etr &tpiu>;
+		coresight-child-ports = <0 0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	tmc_etf: tmc@825000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0x825000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-id = <3>;
+		coresight-name = "coresight-tmc-etf";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0>;
+		coresight-child-list = <&replicator>;
+		coresight-child-ports = <0>;
+		coresight-default-sink;
+		coresight-ctis = <&cti0 &cti8>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	funnel_in0: funnel@821000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0x821000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	funnel_in2: funnel@869000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0x869000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in2";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <6>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	funnel_in3: funnel@868000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0x868000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-id = <6>;
+		coresight-name = "coresight-funnel-in3";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in2>;
+		coresight-child-ports = <7>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti0: cti@810000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x810000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <7>;
+		coresight-name = "coresight-cti0";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti1: cti@811000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x811000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <8>;
+		coresight-name = "coresight-cti1";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti2: cti@812000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x812000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <9>;
+		coresight-name = "coresight-cti2";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti3: cti@813000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x813000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <10>;
+		coresight-name = "coresight-cti3";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti4: cti@814000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x814000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <11>;
+		coresight-name = "coresight-cti4";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti5: cti@815000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x815000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <12>;
+		coresight-name = "coresight-cti5";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti6: cti@816000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x816000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <13>;
+		coresight-name = "coresight-cti6";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,cti-gpio-trigout = <2>;
+		pinctrl-names = "cti-trigout-pctrl";
+		pinctrl-0 = <&trigout_a0>;
+	};
+
+	cti7: cti@817000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x817000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-cti7";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti8: cti@818000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x818000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-cti8";
+		coresight-nr-inports = <0>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_cpu0: cti@851000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x851000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-cti-cpu0";
+		coresight-nr-inports = <0>;
+		coresight-cti-cpu = <&CPU0>;
+
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_cpu1: cti@852000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x852000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-cti-cpu1";
+		coresight-nr-inports = <0>;
+		coresight-cti-cpu = <&CPU1>;
+
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_cpu2: cti@853000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x853000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <18>;
+		coresight-name = "coresight-cti-cpu2";
+		coresight-nr-inports = <0>;
+		coresight-cti-cpu = <&CPU2>;
+
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_cpu3: cti@854000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x854000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <19>;
+		coresight-name = "coresight-cti-cpu3";
+		coresight-nr-inports = <0>;
+		coresight-cti-cpu = <&CPU3>;
+
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_rpm_cpu0: cti@83c000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x83c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <20>;
+		coresight-name = "coresight-cti-rpm-cpu0";
+		coresight-nr-inports = <0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_modem_cpu0: cti@838000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x838000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <21>;
+		coresight-name = "coresight-cti-modem-cpu0";
+		coresight-nr-inports = <0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_wcn_cpu0: cti@835000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x835000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <22>;
+		coresight-name = "coresight-cti-wcn-cpu0";
+		coresight-nr-inports = <0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	cti_video_cpu0: cti@830000 {
+		compatible = "arm,coresight-cti";
+		reg = <0x830000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-id = <23>;
+		coresight-name = "coresight-cti-video-cpu0";
+		coresight-nr-inports = <0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	stm: stm@802000 {
+		compatible = "arm,coresight-stm";
+		reg = <0x802000 0x1000>,
+		      <0x9280000 0x180000>;
+		reg-names = "stm-base", "stm-data-base";
+
+		coresight-id = <24>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <7>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	csr: csr@801000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x801000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-id = <25>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+
+		qcom,blk-size = <1>;
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	funnel_apss: funnel@855000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0x855000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-id = <26>;
+		coresight-name = "coresight-funnel-apss";
+		coresight-nr-inports = <4>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <4>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			<&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	etm0: etm@84c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x84c000 0x1000>;
+		reg-names = "etm-base";
+
+		coresight-id = <27>;
+		coresight-name = "coresight-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_apss>;
+		coresight-child-ports = <0>;
+		coresight-etm-cpu = <&CPU0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	etm1: etm@84d000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x84d000 0x1000>;
+		reg-names = "etm-base";
+
+		coresight-id = <28>;
+		coresight-name = "coresight-etm1";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_apss>;
+		coresight-child-ports = <1>;
+		coresight-etm-cpu = <&CPU1>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	etm2: etm@84e000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x84e000 0x1000>;
+		reg-names = "etm-base";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-etm2";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_apss>;
+		coresight-child-ports = <2>;
+		coresight-etm-cpu = <&CPU2>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	etm3: etm@84f000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x84f000 0x1000>;
+		reg-names = "etm-base";
+
+		coresight-id = <30>;
+		coresight-name = "coresight-etm3";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_apss>;
+		coresight-child-ports = <3>;
+		coresight-etm-cpu = <&CPU3>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	hwevent: hwevent@86c000 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0x86c000 0x108>,
+		      <0x86cfb0 0x4>,
+		      <0x78c5010 0x4>,
+		      <0x7885010 0x4>;
+		reg-names = "wrapper-mux", "wrapper-lockaccess", "usbbam-mux",
+				"blsp-mux";
+		coresight-id = <31>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-id = <32>;
+		coresight-name = "coresight-rpm-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <0>;
+
+		qcom,inst-id = <4>;
+	};
+
+	wcn_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-id = <33>;
+		coresight-name = "coresight-wcn-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in3>;
+		coresight-child-ports = <0>;
+
+		qcom,inst-id = <3>;
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-id = <34>;
+		coresight-name = "coresight-modem-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in0>;
+		coresight-child-ports = <2>;
+
+		qcom,inst-id = <2>;
+	};
+
+	fuse: fuse@5e01c {
+		compatible = "arm,coresight-fuse-v2";
+		reg = <0x5e01c 0x8>,
+		      <0x58040 0x4>,
+		      <0x5e00c 0x4>;
+		reg-names = "fuse-base", "nidnt-fuse-base", "qpdi-fuse-base";
+
+		coresight-id = <35>;
+		coresight-name = "coresight-fuse";
+		coresight-nr-inports = <0>;
+	};
+
+	qpdi: qpdi@1941000 {
+		compatible = "qcom,coresight-qpdi";
+		reg = <0x1941000 0x4>;
+		reg-names = "qpdi-base";
+
+		coresight-id = <36>;
+		coresight-name = "coresight-qpdi";
+		coresight-nr-inports = <0>;
+
+		vdd-supply = <&pm8909_l11>;
+		qcom,vdd-voltage-level = <2800000 2950000>;
+		qcom,vdd-current-level = <15000 400000>;
+
+		vdd-io-supply = <&pm8909_l12>;
+		qcom,vdd-io-voltage-level = <1800000 2950000>;
+		qcom,vdd-io-current-level = <200 50000>;
+	};
+
+	dbgui: dbgui@86d000 {
+		compatible = "qcom,coresight-dbgui";
+		reg = <0x86d000 0x1000>;
+		reg-names = "dbgui-base";
+
+		coresight-id = <37>;
+		coresight-name = "coresight-dbgui";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in2>;
+		coresight-child-ports = <2>;
+
+		qcom,dbgui-addr-offset = <0x30>;
+		qcom,dbgui-data-offset = <0xB0>;
+		qcom,dbgui-size = <32>;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
new file mode 100644
index 0000000..74f2be0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
@@ -0,0 +1,48 @@
+/* Copyright (c) 2014, 2016-2018, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@27 { /* QSEECOM HEAP */
+			reg = <27>;
+			memory-region = <&venus_qseecom_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		qcom,ion-heap@28 { /* AUDIO HEAP */
+			reg = <28>;
+			memory-region = <&audio_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		modem_heap: qcom,ion-heap@26 { /* MODEM HEAP */
+			reg = <26>;
+			memory-region = <&modem_adsp_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		adsp_heap: qcom,ion-heap@22 { /* MODEM HEAP */
+			reg = <22>;
+			memory-region = <&adsp_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi
new file mode 100644
index 0000000..aceefdf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-ipcrouter.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2016,2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ipc_router {
+		compatible = "qcom,ipc_router";
+		qcom,node-id = <1>;
+	};
+
+	qcom,ipc_router_modem_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "modem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+		qcom,disable-pil-loading;
+	};
+
+	qcom,ipc_router_wcnss_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "wcnss";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi
new file mode 100644
index 0000000..aa81972
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mdss-pll.dtsi
@@ -0,0 +1,53 @@
+/* Copyright (c) 2016,2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@1ac8300 {
+		compatible = "qcom,mdss_dsi_pll_8909";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x1ac8300 0xd4>, <0x0184d074 0x8>;
+		reg-names = "pll_base", "gdsc_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+		vddio-supply = <&pm8909_l6>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+			qcom,platform-supply-entry@1 {
+				reg = <1>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi
new file mode 100644
index 0000000..0d824e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014-2016,2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		compatible = "qcom,mdss_mdp3";
+		reg = <0x1a00000 0x100000>,
+			<0x1ab0000 0x3000>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+
+		vdd-supply = <&gdsc_mdss>;
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>,
+			 <&clock_gcc clk_mdp_clk_src>,
+			 <&clock_gcc clk_gcc_mdss_mdp_clk>,
+			 <&clock_gcc clk_gcc_mdss_vsync_clk>;
+		clock-names = "iface_clk", "bus_clk", "core_clk_src",
+				"core_clk", "vsync_clk";
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,cont-splash-memory {
+			linux,contiguous-region = <&cont_splash_mem>;
+			};
+		};
+
+		smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+			compatible = "qcom,smmu_mdp_unsec";
+		};
+		smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+			compatible = "qcom,smmu_mdp_sec";
+		};
+	};
+
+	mdss_dsi: qcom,mdss_dsi@0 {
+		compatible = "qcom,mdss-dsi";
+		hw-config = "single_dsi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,mdss-fb-map-prim = <&mdss_fb0>;
+		gdsc-supply = <&gdsc_mdss>;
+		vdda-supply = <&pm8909_l2>;
+		vddio-supply = <&pm8909_l6>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_dsi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 1000>;
+
+		ranges = <0x1ac8000 0x1ac8000 0x25c
+			0x1ac8500 0x1ac8500 0x280
+			0x1ac8780 0x1ac8780 0x30
+			0x193e000 0x193e000 0x30>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+			 <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>;
+		clock-names = "mdp_core_clk", "iface_clk", "bus_clk";
+
+		qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+		qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-post-on-sleep = <5>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+
+		mdss_dsi0: qcom,mdss_dsi_ctrl0@1ac8000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->0";
+			cell-index = <0>;
+			reg = <0x1ac8000 0x25c>,
+			      <0x1ac8500 0x280>,
+			      <0x1ac8780 0x30>,
+			      <0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy",
+				"dsi_phy_regulator", "mmss_misc_phys";
+
+			qcom,dsi-irq-line;
+			interrupts = <0 80 0>;
+
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8909_l17>;
+			vddio-supply = <&pm8909_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+				 <&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+				 <&clock_gcc clk_gcc_mdss_esc0_clk>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk";
+
+			qcom,regulator-ldo-mode;
+
+			qcom,platform-strength-ctrl = [ff 06];
+			qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+			qcom,platform-regulator-settings =
+					[00 01 01 00 20 07 00];
+			qcom,platform-lane-config =
+				[00 00 00 00 00 00 00 01 97
+				00 00 00 00 05 00 00 01 97
+				00 00 00 00 0a 00 00 01 97
+				00 00 00 00 0f 00 00 01 97
+				00 c0 00 00 00 00 00 01 bb];
+		};
+	};
+};
+
+/* #include "msm8909-mdss-panels.dtsi" */
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
new file mode 100644
index 0000000..7f18173
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
@@ -0,0 +1,428 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8909.dtsi"
+#include "msm8909-pinctrl.dtsi"
+#include "msm8909-regulator.dtsi"
+
+&soc {
+	/*
+	 * DT node to add support for SMB135x charger and integrate
+	 * with VM-BMS.
+	 */
+	i2c@78b8000 {
+		smb1357_otg_vreg: smb1357-charger@57 {
+			compatible = "qcom,smb1357-charger";
+			reg = <0x57>;
+			interrupt-parent = <&msm_gpio>;
+			interrupts = <58 8>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&smb_int_default>;
+
+			qcom,bmd-algo-disabled;
+			qcom,float-voltage-mv = <4200>;
+			qcom,charging-timeout = <1536>;
+			qcom,recharge-thresh-mv = <100>;
+			regulator-name = "smb1357_otg_vreg";
+			qcom,soft-vfloat-comp-disabled;
+			qcom,thermal-mitigation = <1500 700 600 0>;
+
+			qcom,bms-psy-name = "bms";
+
+			/*
+			 * Disable SMB1357 based charging termination as BMS
+			 * controls charging.
+			 */
+			qcom,iterm-disabled;
+
+			/*
+			 * Disable charge inhibit feature to start chargin on
+			 * charger insertion independent of battery voltage.
+			 */
+			qcom,inhibit-disabled;
+
+			/* BMS is controlling charging/re-charge */
+			qcom,bms-controlled-charging;
+
+			/*
+			 * To enable charger node:
+			 * set status = "ok" and
+			 * add 'qcom,use-external-charger' to pm8909_chg node
+			 */
+			status = "disabled";
+		};
+	};
+
+	/*
+	 * DT node to add support for SMB358 charger and integrate
+	 * with VM-BMS.
+	 */
+	i2c@78b8000 {
+	};
+
+	i2c@78b9000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,dsx";
+			reg = <0x20>;
+			interrupt-parent = <&msm_gpio>;
+			interrupts = <13 0x2008>;
+			avdd-supply = <&pm8909_l17>;
+			vdd-supply = <&pm8909_l6>;
+			/* pins used by touchscreen */
+			pinctrl-names = "pmx_ts_active",
+				"pmx_ts_suspend","pmx_ts_release";
+			pinctrl-0 = <&ts_int_active &ts_reset_active>;
+			pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+			pinctrl-2 = <&ts_release>;
+			synaptics,irq-gpio = <&msm_gpio 13 0x2008>;
+			synaptics,reset-gpio = <&msm_gpio 12 0x0>;
+			synaptics,disable-gpios;
+			synaptics,display-coords = <0 0 719 1279>;
+			synaptics,panel-coords = <0 0 719 1405>;
+		};
+	};
+
+	i2c@78b6000 { /* BLSP1 QUP2 */
+		nq@28 {
+			compatible = "qcom,nq-nci";
+			reg = <0x28>;
+			qcom,nq-irq = <&msm_gpio 21 0x00>;
+			qcom,nq-ven = <&msm_gpio 20 0x00>;
+			qcom,nq-firm = <&msm_gpio 45 0x00>;
+			qcom,clk-src = "BBCLK2";
+			interrupt-parent = <&msm_gpio>;
+			interrupts = <21 0>;
+			interrupt-names = "nfc_irq";
+			pinctrl-names = "nfc_active","nfc_suspend";
+			pinctrl-0 = <&nfc_int_active &nfc_disable_active>;
+			pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+			clocks = <&clock_rpm clk_bb_clk2_pin>;
+			clock-names = "ref_clk";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msm_gpio 91 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msm_gpio 92 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msm_gpio 90 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	audio_codec_mtp: sound {
+		compatible = "qcom,msm8952-audio-codec";
+		qcom,model = "msm8909-snd-card";
+		reg = <0x7702000 0x4>,
+		      <0x7702004 0x4>,
+		      <0x7702008 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			    "csr_gp_io_mux_spkr_ctl",
+			    "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel";
+
+		qcom,msm-snd-card-id = <0>;
+		qcom,msm-codec-type = "internal";
+		qcom,msm-ext-pa = "primary";
+		qcom,msm-mclk-freq = <9600000>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,msm-hs-micbias-type = "internal";
+		qcom,msm-micbias1-ext-cap;
+		qcom,split-a2dp;
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"SPK_RX_BIAS", "MCLK",
+			"INT_LDO_H", "MCLK",
+			"MIC BIAS External", "Handset Mic",
+			"MIC BIAS Internal2", "Headset Mic",
+			"MIC BIAS External", "Secondary Mic",
+			"AMIC1", "MIC BIAS External",
+			"AMIC2", "MIC BIAS Internal2",
+			"AMIC3", "MIC BIAS External";
+		qcom,msm-gpios =
+			"pri_i2s",
+			"us_eu_gpio";
+		qcom,pinctrl-names =
+			"all_off",
+			"pri_i2s_act",
+			"us_eu_gpio_act",
+			"pri_i2s_us_eu_gpio_act";
+		pinctrl-names =
+			"all_off",
+			"pri_i2s_act",
+			"us_eu_gpio_act",
+			"pri_i2s_us_eu_gpio_act";
+		pinctrl-0 = <&cdc_pdm_lines_sus &cross_conn_det_sus
+							&vdd_spkdrv_sus>;
+		pinctrl-1 = <&cdc_pdm_lines_act &cross_conn_det_sus
+							&vdd_spkdrv_act>;
+		pinctrl-2 = <&cdc_pdm_lines_sus &cross_conn_det_act
+							&vdd_spkdrv_sus>;
+		pinctrl-3 = <&cdc_pdm_lines_act &cross_conn_det_act
+							&vdd_spkdrv_act>;
+		qcom,cdc-us-euro-gpios = <&msm_gpio 97 0>;
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&lpa>,
+				<&voice_svc>;
+		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-pcm-lpa",
+				"msm-voice-svc";
+		asoc-cpu = <&dai_pri_auxpcm>,
+				<&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>,
+				<&dai_mi2s3>, <&dai_mi2s5>, <&dai_mi2s6>,
+				<&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>,
+				<&int_fm_rx>, <&int_fm_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>;
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+				"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+				"msm-dai-q6-dev.12290", "msm-dai-q6-dev.12292",
+				"msm-dai-q6-dev.12293", "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";
+		asoc-codec = <&stub_codec>, <&pm8909_conga_dig>;
+		asoc-codec-names = "msm-stub-codec.1", "cajon_codec";
+	};
+};
+
+&blsp1_uart1 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart_console_sleep>;
+};
+
+&qcom_rng {
+	status = "okay";
+};
+
+&qcom_crypto {
+	status = "okay";
+};
+
+&qcom_cedev {
+	status = "okay";
+};
+
+&qcom_seecom {
+	status = "okay";
+};
+
+&qcom_tzlog {
+	status = "okay";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8909_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 400000>;
+
+	vdd-io-supply = <&pm8909_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 60000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	 #address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msm_gpio 38 0>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msm_gpio 38 0x1>;
+
+	vdd-supply = <&pm8909_l11>;
+	qcom,vdd-voltage-level = <1800000 2950000>;
+	qcom,vdd-current-level = <15000 400000>;
+
+	vdd-io-supply = <&pm8909_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 50000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+	status = "ok";
+};
+
+&i2c_1 { /* BLSP1 QUP1 */
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&msm_gpio {
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio25", "gpio37";
+			};
+			config {
+				pins = "gpio25", "gpio37";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio25", "gpio37";
+			};
+			config {
+				pins = "gpio25", "gpio37";
+			};
+		};
+	};
+	pmx_mdss_te {
+		mdss_te_active: mdss_te_active {
+			mux {
+				pins = "gpio24";
+			};
+			config {
+				pins = "gpio24";
+			};
+		};
+		mdss_te_suspend: mdss_te_suspend {
+			mux {
+				pins = "gpio24";
+			};
+			config {
+				pins = "gpio24";
+			};
+		};
+	};
+	mpu6050_int_pin {
+		mpu6050_default: mpu6050_default {
+			mux {
+				pins = "gpio96";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio96";
+				drive-dtrength = <6>;
+				bias-pull-down;
+			};
+		};
+		mpu6050_sleep: mpu6050_sleep {
+			mux {
+				pins = "gpio96";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio96";
+				drive-dtrength = <2>;
+				bias-pull-down;
+			};
+		};
+	};
+	ak8963_int_pin {
+		ak8963_default: ak8963_default {
+			mux {
+				pins = "gpio65";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio65";
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+		};
+		ak8963_sleep: ak8963_sleep {
+			mux {
+				pins = "gpio65";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio65";
+				drive-strength = <2>;
+				bias-pull-down;
+			};
+		};
+	};
+};
+
+/* CoreSight */
+&tpiu {
+	pinctrl-names = "sdcard", "trace", "swduart",
+			"swdtrc", "jtag", "spmi";
+	/* NIDnT */
+	pinctrl-0 = <&qdsd_clk_sdcard &qdsd_cmd_sdcard
+		     &qdsd_data0_sdcard &qdsd_data1_sdcard
+		     &qdsd_data2_sdcard &qdsd_data3_sdcard>;
+	pinctrl-1 = <&qdsd_clk_trace &qdsd_cmd_trace
+		     &qdsd_data0_trace &qdsd_data1_trace
+		     &qdsd_data2_trace &qdsd_data3_trace>;
+	pinctrl-2 = <&qdsd_cmd_swduart &qdsd_data0_swduart
+		     &qdsd_data1_swduart &qdsd_data2_swduart
+		     &qdsd_data3_swduart>;
+	pinctrl-3 = <&qdsd_clk_swdtrc &qdsd_cmd_swdtrc
+		     &qdsd_data0_swdtrc &qdsd_data1_swdtrc
+		     &qdsd_data2_swdtrc &qdsd_data3_swdtrc>;
+	pinctrl-4 = <&qdsd_cmd_jtag &qdsd_data0_jtag
+		     &qdsd_data1_jtag &qdsd_data2_jtag
+		     &qdsd_data3_jtag>;
+	pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi
+		     &qdsd_data0_spmi &qdsd_data3_spmi>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi
new file mode 100644
index 0000000..25688ff
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi
@@ -0,0 +1,2193 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	msm_gpio: pinctrl@1000000 {
+		compatible = "qcom,msm8909-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		/* sensors */
+		cam_sensor_mclk0_default: cam_sensor_mclk0_default {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_default: cam_sensor_rear_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio35", "gpio34";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio35","gpio34";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_sleep: cam_sensor_rear_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio35","gpio34";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio35","gpio34";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_default: cam_sensor_mclk1_default {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_default: cam_sensor_front_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio28","gpio33";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio28","gpio33";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_sleep: cam_sensor_front_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio28","gpio33";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio28","gpio33";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_flash_default: cam_sensor_flash_default {
+		/* FLASH_RESET,FLASH_EN,FLASH_NOW */
+			mux {
+				pins = "gpio36", "gpio31", "gpio32";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio36", "gpio31", "gpio32";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_flash_sleep: cam_sensor_flash_sleep {
+			 mux {
+				pins = "gpio36", "gpio31", "gpio32";
+				function = "gpio";
+			};
+			config {
+				pins = "gpio36", "gpio31", "gpio32";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		uart_console_active: uart_console_active {
+			mux {
+				pins = "gpio4", "gpio5";
+				function = "blsp_uart1";
+			};
+			config {
+				pins = "gpio4", "gpio5";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+		uart_console_sleep: uart_console_sleep {
+			mux {
+				pins = "gpio4", "gpio5";
+				function = "blsp_uart1";
+			};
+			config {
+				pins = "gpio4", "gpio5";
+				drive-strength = <2>;
+				bias-pull-down;
+			};
+		};
+
+		uart_console2_active: uart_console2_active {
+			mux {
+				pins = "gpio20", "gpio21";
+				function = "blsp_uart2";
+			};
+			config {
+				pins = "gpio20", "gpio21";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+		uart_console2_sleep: uart_console2_sleep {
+			mux {
+				pins = "gpio20", "gpio21";
+				function = "blsp_uart2";
+			};
+			config {
+				pins = "gpio20", "gpio21";
+				drive-strength = <2>;
+				bias-pull-down;
+			};
+		};
+
+		blsp1_uart2_tx_active: blsp1_uart2_tx_active {
+			mux {
+				pins = "gpio20";
+				function = "blsp_uart2";
+			};
+
+			config {
+				pins = "gpio20";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		blsp1_uart2_tx_sleep: blsp1_uart2_tx_sleep {
+			mux {
+				pins = "gpio20";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio20";
+				drive-strength = <2>;
+				bias-pull-up;
+			};
+		};
+
+		blsp1_uart2_rxcts_active: blsp1_uart2_rxcts_active {
+			mux {
+				pins = "gpio21", "gpio111";
+				function = "blsp_uart2";
+			};
+
+			config {
+				pins = "gpio21", "gpio111";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		blsp1_uart2_rxcts_sleep: blsp1_uart2_rxcts_sleep {
+			mux {
+				pins = "gpio21", "gpio111";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio21", "gpio111";
+				drive-strength = <2>;
+				bias-no-pull;
+			};
+		};
+
+		blsp1_uart2_rfr_active: blsp1_uart2_rfr_active {
+			mux {
+				pins = "gpio112";
+				function = "blsp_uart2";
+			};
+
+			config {
+				pins = "gpio112";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		blsp1_uart2_rfr_sleep: blsp1_uart2_rfr_sleep {
+			mux {
+				pins = "gpio112";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio112";
+				drive-strength = <2>;
+				bias-no-pull;
+			};
+		};
+
+		pmx_mdss {
+			mdss_dsi_active: mdss_dsi_active {
+				mux {
+					pins = "gpio25", "gpio37";
+					function = "gpio";
+				};
+
+				config {
+					drive-strength = <8>; /* 8 mA */
+					bias-disable = <0>; /* no pull */
+					output-high;
+				};
+			};
+
+			mdss_dsi_suspend: mdss_dsi_suspend {
+				mux {
+					pins = "gpio25", "gpio37";
+					function = "gpio";
+				};
+
+				config {
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					output-low;
+				};
+			};
+		};
+
+		pmx_mdss_te {
+			mdss_te_active: mdss_te_active {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+
+				config {
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+
+			mdss_te_suspend: mdss_te_suspend {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+
+				config {
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		spi0 {
+			spi0_default: spi0_default {
+				mux {
+					pins = "gpio8", "gpio9",
+						"gpio11";
+					function = "blsp_spi6";
+				};
+				config {
+					pins = "gpio8", "gpio9",
+						"gpio11";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			spi0_sleep: spi0_sleep {
+				mux {
+					pins = "gpio8", "gpio9",
+						"gpio11";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio8", "gpio9",
+						"gpio11";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* pull down */
+				};
+			};
+			spi0_cs0_active: spi0_cs0_active {
+				mux {
+					pins = "gpio10";
+					function = "blsp_spi6";
+				};
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+			spi0_cs0_sleep: spi0_cs0_sleep {
+				mux {
+					pins = "gpio10";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		spi2 {
+			spi2_default: spi2_default {
+				mux {
+					pins = "gpio20", "gpio21",
+						"gpio112";
+					function = "blsp_spi2";
+				};
+				config {
+					pins = "gpio20", "gpio21",
+						"gpio112";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			spi2_sleep: spi2_sleep {
+				mux {
+					pins = "gpio20", "gpio21",
+						"gpio112";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio20", "gpio21",
+						"gpio112";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* pull down */
+				};
+			};
+			spi2_cs0_active: spi2_cs0_active {
+				mux {
+					pins = "gpio111";
+					function = "blsp_spi2";
+				};
+				config {
+					pins = "gpio111";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+			spi2_cs0_sleep: spi2_cs0_sleep {
+				mux {
+					pins = "gpio111";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio111";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		spi4 {
+			spi4_default: spi4_default {
+				mux {
+					pins = "gpio12", "gpio13",
+						"gpio15";
+					function = "blsp_spi4";
+				};
+				config {
+					pins = "gpio12", "gpio13",
+						"gpio15";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			spi4_sleep: spi4_sleep {
+				mux {
+					pins = "gpio12", "gpio13",
+						"gpio15";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio12", "gpio13",
+						"gpio15";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* pull down */
+				};
+			};
+			spi4_cs0_active: spi4_cs0_active {
+				mux {
+					pins = "gpio14";
+					function = "blsp_spi4";
+				};
+				config {
+					pins = "gpio14";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+			spi4_cs0_sleep: spi4_cs0_sleep {
+				mux {
+					pins = "gpio14";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio14";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_i2c_1 {
+			i2c_1_active: i2c_1_active {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "blsp_i2c1";
+				};
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			i2c_1_sleep: i2c_1_sleep {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "blsp_i2c1";
+				};
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		pmx_i2c_2 {
+			i2c_2_active: i2c_2_active {
+				mux {
+					pins = "gpio111", "gpio112";
+					function = "blsp_i2c2";
+				};
+				config {
+					pins = "gpio111", "gpio112";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			i2c_2_sleep: i2c_2_sleep {
+				mux {
+					pins = "gpio111", "gpio112";
+					function = "blsp_i2c2";
+				};
+				config {
+					pins = "gpio111", "gpio112";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		nfc {
+			nfcw_int_active: nfcw_int_active {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio50";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfcw_int_suspend: nfcw_int_suspend {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio50";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfcw_disable_active: nfcw_disable_active {
+				mux {
+					pins = "gpio36";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio36";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfcw_disable_suspend: nfcw_disable_suspend {
+				mux {
+					pins = "gpio36";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio36";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			nfcv2k_disable_active: nfcv2k_disable_active {
+				mux {
+					pins = "gpio52";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio52";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfcv2k_disable_suspend: nfcv2k_disable_suspend {
+				mux {
+					pins = "gpio52";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio52";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			nfc_int_active: nfc_int_active {
+				mux {
+					pins = "gpio21";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio21";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfc_int_suspend: nfc_int_suspend {
+				mux {
+					pins = "gpio21";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio21";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfc_disable_active: nfc_disable_active {
+				mux {
+					pins = "gpio20";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio20";
+					drive-strength = <6>;
+					bias-pull-up;
+				};
+			};
+
+			nfc_disable_suspend: nfc_disable_suspend {
+				mux {
+					pins = "gpio20";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio20";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_i2c_3 {
+			i2c_3_active: i2c_3_active {
+				mux {
+					pins = "gpio29", "gpio30";
+					function = "blsp_i2c3";
+				};
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			i2c_3_sleep: i2c_3_sleep {
+				mux {
+					pins = "gpio29", "gpio30";
+					function = "blsp_i2c3";
+				};
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		pmx_i2c_4 {
+			i2c_4_active: i2c_4_active {
+				mux {
+					pins = "gpio14", "gpio15";
+					function = "blsp_i2c4";
+				};
+				config {
+					pins = "gpio14", "gpio15";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			i2c_4_sleep: i2c_4_sleep {
+				mux {
+					pins = "gpio14", "gpio15";
+					function = "blsp_i2c4";
+				};
+				config {
+					pins = "gpio14", "gpio15";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		pmx_i2c_5 {
+			i2c_5_active: i2c_5_active {
+				mux {
+					pins = "gpio19", "gpio18";
+					function = "blsp_i2c5";
+				};
+				config {
+					pins = "gpio19", "gpio18";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+			i2c_5_sleep: i2c_5_sleep {
+				mux {
+					pins = "gpio19", "gpio18";
+					function = "blsp_i2c5";
+				};
+				config {
+					pins = "gpio19", "gpio18";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		smb_int_pin {
+			smb_int_default: smb_int_default {
+				mux {
+					pins = "gpio58";
+					function ="smb_int";
+				};
+				config {
+					pins = "gpio58";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-up;           /* PULL UP*/
+				};
+			};
+			smb_int_sleep: smb_int_sleep {
+				mux {
+					pins = "gpio58";
+					function ="smb_int";
+				};
+				config {
+					pins = "gpio58";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-up;           /* PULL UP*/
+				};
+			};
+		};
+
+		pmx_sdc1_clk {
+			sdc1_clk_on: sdc1_clk_on {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+			sdc1_clk_off: sdc1_clk_off {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_cmd {
+			sdc1_cmd_on: sdc1_cmd_on {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+			sdc1_cmd_off: sdc1_cmd_off {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_data {
+			sdc1_data_on: sdc1_data_on {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+			sdc1_data_off: sdc1_data_off {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_clk {
+			sdc2_clk_on: sdc2_clk_on {
+				config {
+					pins = "sdc2_clk";
+					drive-strength = <16>; /* 16 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+			sdc2_clk_off: sdc2_clk_off {
+				config {
+					pins = "sdc2_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_cmd {
+			sdc2_cmd_on: sdc2_cmd_on {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+			sdc2_cmd_off: sdc2_cmd_off {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_data {
+			sdc2_data_on: sdc2_data_on {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+			sdc2_data_off: sdc2_data_off {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		sdhc2_cd_pin {
+			sdc2_cd_on: cd_on {
+				mux {
+					pins = "gpio38";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio38";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+			sdc2_cd_off: cd_off {
+				mux {
+					pins = "gpio38";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio38";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* add pingrp for touchscreen */
+		pmx_ts_int_active {
+			ts_int_active: ts_int_active {
+				mux {
+					pins = "gpio13";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio13";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_int_suspend {
+			ts_int_suspend: ts_int_suspend {
+				mux {
+					pins = "gpio13";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio13";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_reset_active {
+			ts_reset_active: ts_reset_active {
+				mux {
+					pins = "gpio12";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_reset_suspend {
+			ts_reset_suspend: ts_reset_suspend {
+				mux {
+					pins = "gpio12";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* Pinctrl dt nodes for reset gpio for ITE tech controller */
+		pmx_ts_ite_reset_active {
+			ts_ite_reset_active: ts_ite_reset_active {
+				mux {
+					pins = "gpio12";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <8>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		pmx_ts_ite_reset_suspend {
+			ts_ite_reset_suspend: ts_ite_reset_suspend {
+				mux {
+					pins = "gpio12";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <2>;
+					bias-pull-down;
+					output-low;
+				};
+			};
+		};
+
+		pmx_ts_release {
+			ts_release: ts_release {
+				mux {
+					pins = "gpio13", "gpio12";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio13", "gpio12";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		tlmm_gpio_key {
+			gpio_key_active: gpio_key_active {
+				mux {
+					pins = "gpio90", "gpio91", "gpio92";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio90", "gpio91", "gpio92";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			gpio_key_suspend: gpio_key_suspend {
+				mux {
+					pins = "gpio90", "gpio91", "gpio92";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio90", "gpio91", "gpio92";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		wcnss_pmux_5wire {
+			wcnss_default: wcnss_default {
+				wcss_wlan2 {
+					pins = "gpio40";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio41";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio42";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio43", "gpio44";
+					function = "wcss_wlan";
+				};
+				config {
+					pins = "gpio40", "gpio41",
+						"gpio42", "gpio43",
+						"gpio44";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+
+			wcnss_sleep: wcnss_sleep {
+				wcss_wlan2 {
+					pins = "gpio40";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio41";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio42";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio43", "gpio44";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio40", "gpio41",
+						"gpio42", "gpio43",
+						"gpio44";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+		};
+
+		wcnss_pmux_gpio: wcnss_pmux_gpio {
+			wcnss_gpio_default: wcnss_gpio_default {
+				mux {
+					pins = "gpio40", "gpio41",
+						"gpio42", "gpio43",
+						"gpio44";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio40", "gpio41",
+						"gpio42", "gpio43",
+						"gpio44";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+		};
+
+		trigout_a0: trigout_a0 {
+			mux {
+				pins = "gpio23";
+				function  = "qdss_cti_trig_out_a0";
+			};
+
+			config {
+				pins = "gpio23";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		pmx_qdsd_clk {
+			qdsd_clk_sdcard: clk_sdcard {
+				config {
+					pins = "qdsd_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <7>; /* 7 MA */
+				};
+			};
+			qdsd_clk_trace: clk_trace {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_clk_swdtrc: clk_swdtrc {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_clk_spmi: clk_spmi {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_cmd {
+			qdsd_cmd_sdcard: cmd_sdcard {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_cmd_trace: cmd_trace {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_cmd_swduart: cmd_uart {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_cmd_swdtrc: cmd_swdtrc {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_cmd_jtag: cmd_jtag {
+				config {
+					pins = "qdsd_cmd";
+					bias-disable; /* NO pull */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_cmd_spmi: cmd_spmi {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <4>; /* 4 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data0 {
+			qdsd_data0_sdcard: data0_sdcard {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data0_trace: data0_trace {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data0_swduart: data0_uart {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data0_swdtrc: data0_swdtrc {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data0_jtag: data0_jtag {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data0_spmi: data0_spmi {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data1 {
+			qdsd_data1_sdcard: data1_sdcard {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data1_trace: data1_trace {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data1_swduart: data1_uart {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data1_swdtrc: data1_swdtrc {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data1_jtag: data1_jtag {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data2 {
+			qdsd_data2_sdcard: data2_sdcard {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data2_trace: data2_trace {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data2_swduart: data2_uart {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data2_swdtrc: data2_swdtrc {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data2_jtag: data2_jtag {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-up; /* pull up */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data3 {
+			qdsd_data3_sdcard: data3_sdcard {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data3_trace: data3_trace {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+			qdsd_data3_swduart: data3_uart {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data3_swdtrc: data3_swdtrc {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data3_jtag: data3_jtag {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <0>; /* 0 MA */
+				};
+			};
+			qdsd_data3_spmi: data3_spmi {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <3>; /* 3 MA */
+				};
+			};
+		};
+
+		/* CoreSight */
+		tpiu_seta_1 {
+			seta_1: seta {
+				mux {
+					pins = "gpio6";
+					function = "qdss_traceclk_a";
+				};
+				config {
+					pins = "gpio6";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_2 {
+			seta_2: seta {
+				mux {
+					pins = "gpio8";
+					function = "qdss_tracectl_a";
+				};
+				config {
+					pins = "gpio8";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_3 {
+			seta_3: seta {
+				mux {
+					pins = "gpio9";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio9";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_4 {
+			seta_4: seta {
+				mux {
+					pins = "gpio10";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio10";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_5 {
+			seta_5: seta {
+				mux {
+					pins = "gpio39";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio39";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_6 {
+			seta_6: seta {
+				mux {
+					pins = "gpio40";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio40";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_7 {
+			seta_7: seta {
+				mux {
+					pins = "gpio41";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio41";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_8 {
+			seta_8: seta {
+				mux {
+					pins = "gpio42";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio42";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_9 {
+			seta_9: seta {
+				mux {
+					pins = "gpio43";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio43";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_10 {
+			seta_10: seta {
+				mux {
+					pins = "gpio45";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio45";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_11 {
+			seta_11: seta {
+				mux {
+					pins = "gpio46";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio46";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_12 {
+			seta_12: seta {
+				mux {
+					pins = "gpio47";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio47";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_13 {
+			seta_13: seta {
+				mux {
+					pins = "gpio48";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio48";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_14 {
+			seta_14: seta {
+				mux {
+					pins = "gpio58";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio58";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_15 {
+			seta_15: seta {
+				mux {
+					pins = "gpio65";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio65";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_16 {
+			seta_16: seta {
+				mux {
+					pins = "gpio94";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio94";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_17 {
+			seta_17: seta {
+				mux {
+					pins = "gpio96";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio96";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_seta_18 {
+			seta_18: seta {
+				mux {
+					pins = "gpio97";
+					function = "qdss_tracedata_a";
+				};
+				config {
+					pins = "gpio97";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_1 {
+			setb_1: setb {
+				mux {
+					pins = "gpio4";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio4";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_2 {
+			setb_2: setb {
+				mux {
+					pins = "gpio5";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio5";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_3 {
+			setb_3: setb {
+				mux {
+					pins = "gpio14";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio14";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_4 {
+			setb_4: setb {
+				mux {
+					pins = "gpio16";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio16";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_5 {
+			setb_5: setb {
+				mux {
+					pins = "gpio17";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio17";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_6 {
+			setb_6: setb {
+				mux {
+					pins = "gpio26";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio26";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_7 {
+			setb_7: setb {
+				mux {
+					pins = "gpio27";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio27";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_8 {
+			setb_8: setb {
+				mux {
+					pins = "gpio28";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio28";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_9 {
+			setb_9: setb {
+				mux {
+					pins = "gpio29";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio29";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_10 {
+			setb_10: setb {
+				mux {
+					pins = "gpio30";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio30";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_11 {
+			setb_11: setb {
+				mux {
+					pins = "gpio31";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio31";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_12 {
+			setb_12: setb {
+				mux {
+					pins = "gpio32";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio32";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_13 {
+			setb_13: setb {
+				mux {
+					pins = "gpio33";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio33";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_14 {
+			setb_14: setb {
+				mux {
+					pins = "gpio34";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio34";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_15 {
+			setb_15: setb {
+				mux {
+					pins = "gpio35";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio35";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_16 {
+			setb_16: setb {
+				mux {
+					pins = "gpio36";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio36";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_17 {
+			setb_17: setb {
+				mux {
+					pins = "gpio37";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio37";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		tpiu_setb_18 {
+			setb_18: setb {
+				mux {
+					pins = "gpio93";
+					function = "qdss_tracedata_b";
+				};
+				config {
+					pins = "gpio93";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+		};
+
+		vdd_spkdrv {
+			vdd_spkdrv_act: vdd_spkdrv_on {
+				mux {
+					pins = "gpio4";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio4";
+					drive-strength = <8>;
+				};
+			};
+			vdd_spkdrv_sus: vdd_spkdrv_off {
+				mux {
+					pins = "gpio4";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cdc-dmic-lines {
+			cdc_dmic0_clk_act: dmic0_clk_on {
+				mux {
+					pins = "gpio4";
+					function = "dmic0_clk";
+				};
+
+				config {
+					pins = "gpio4";
+					drive-strength = <8>;
+					bias-pull-none;
+				};
+			};
+
+			cdc_dmic0_clk_sus: dmic0_clk_off {
+				mux {
+					pins = "gpio4";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			cdc_dmic0_data_act: dmic0_data_on {
+				mux {
+					pins = "gpio5";
+					function = "dmic0_data";
+				};
+
+				config {
+					pins = "gpio5";
+					drive-strength = <8>;
+					bias-pull-none;
+				};
+			};
+
+			cdc_dmic0_data_sus: dmic0_data_off {
+				mux {
+					pins = "gpio5";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cdc-pdm-lines {
+			cdc_pdm_lines_act: pdm_lines_on {
+				mux {
+					pins = "gpio59", "gpio60", "gpio61",
+						"gpio62", "gpio63", "gpio64";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio59", "gpio60", "gpio61",
+						"gpio62", "gpio63", "gpio64";
+					drive-strength = <8>;
+				};
+			};
+			cdc_pdm_lines_sus: pdm_lines_off {
+				mux {
+					pins = "gpio59", "gpio60", "gpio61",
+						"gpio62", "gpio63", "gpio64";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio59", "gpio60", "gpio61",
+						"gpio62", "gpio63", "gpio64";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cross-conn-det {
+			cross_conn_det_act: lines_on {
+				mux {
+					pins = "gpio97";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio97";
+					drive-strength = <8>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+
+			cross_conn_det_sus: lines_off {
+				mux {
+					pins = "gpio97";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio97";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_i2s_mclk {
+			label = "i2s_mclk";
+			i2s_mclk_active: i2s_mclk_active {
+				mux {
+					pins = "gpio59";
+					function = "pri_mi2s_mclk_a";
+				};
+				config {
+					pins = "gpio59";
+					drive-strength = <8>;   /* 8 MA */
+					bias-disable;           /* No PULL */
+					output-high;
+				};
+			};
+
+			i2s_mclk_sleep: i2s_mclk_sleep {
+				mux {
+					pins = "gpio59";
+					function = "pri_mi2s_mclk_a";
+				};
+				configs {
+					pins = "gpio59";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-down;	        /* PULL DOWN */
+				};
+			};
+		};
+
+		pmx_pri_mi2s {
+			label = "pri_mi2s";
+			pri_mi2s_active: pri_mi2s_active {
+				mux {
+					pins = "gpio60";
+					function = "pri_mi2s_sck_a";
+				};
+				configs {
+					pins = "gpio60";
+					drive-strength = <8>;   /* 8 MA */
+					bias-disable;           /* No PULL */
+					output-high;
+				};
+			};
+			pri_mi2s_sleep: pri_mi2s_sleep {
+				mux {
+					pins = "gpio60";
+					function = "pri_mi2s_sck_a";
+				};
+				configs {
+					pins = "gpio60";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-down;	        /* PULL DOWN */
+				};
+			};
+
+			pri_mi2s_ws_active: pri_mi2s_ws_active {
+				mux {
+					pins = "gpio61";
+					function = "pri_mi2s_ws_a";
+				};
+
+				config {
+					pins = "gpio61";
+					drive-strength = <8>;   /* 8 mA */
+					bias-disable;       /* NO PULL*/
+					output-high;
+				};
+			};
+
+			pri_mi2s_ws_sleep: pri_mi2s_ws_sleep {
+				mux {
+					pins = "gpio61";
+					function = "pri_mi2s_ws_a";
+				};
+
+				config {
+					pins = "gpio61";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;     /* PULL DOWN */
+				};
+			};
+
+			pri_mi2s_dout_active: pri_mi2s_dout_active {
+				mux {
+					pins = "gpio63";
+					function = "pri_mi2s_data1_a";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <8>;   /* 8 mA */
+					bias-disable;       /* NO PULL*/
+					output-high;
+				};
+			};
+
+			pri_mi2s_dout_sleep: pri_mi2s_dout_sleep {
+				mux {
+					pins = "gpio63";
+					function = "pri_mi2s_data1_a";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;     /* PULL DOWN */
+				};
+			};
+
+			pri_mi2s_din_sleep: pri_mi2s_din_sleep {
+				mux {
+					pins = "gpio62";
+					function = "pri_mi2s_data0_a";
+				};
+
+				config {
+					pins = "gpio62";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;     /* PULL DOWN */
+				};
+			};
+
+			pri_mi2s_din_active: pri_mi2s_din_active {
+				mux {
+					pins = "gpio62";
+					function = "pri_mi2s_data0_a";
+				};
+
+				config {
+					pins = "gpio62";
+					drive-strength = <8>;   /* 8 mA */
+					bias-disable;       /* NO PULL */
+				};
+			};
+		};
+
+		pmx_quat_mi2s {
+			label = "quat_mi2s";
+			quat_mi2s_active: quat_mi2s_active {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "sec_mi2s";
+				};
+				configs {
+					pins = "gpio0", "gpio1";
+					drive-strength = <8>;   /* 8 MA */
+					bias-disable;           /* No PULL */
+				};
+			};
+			quat_mi2s_sleep: quat_mi2s_sleep {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "sec_mi2s";
+				};
+				configs {
+					pins = "gpio0", "gpio1";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-down;	        /* PULL DOWN */
+				};
+			};
+		};
+
+		pmx_quat_mi2s_din {
+			label = "quat_mi2s_din";
+			quat_mi2s_din_active: quat_mi2s_din_active {
+				mux {
+					pins = "gpio2", "gpio3";
+					function = "sec_mi2s";
+				};
+				configs {
+					pins = "gpio2", "gpio3";
+					drive-strength = <8>;   /* 8 MA */
+					bias-disable;	        /* No PULL */
+					output-high;
+				};
+			};
+			quat_mi2s_din_sleep: quat_mi2s_din_sleep {
+				mux {
+					pins = "gpio2", "gpio3";
+					function = "sec_mi2s";
+				};
+				configs {
+					pins = "gpio2", "gpio3";
+					drive-strength = <2>;   /* 2 MA */
+					bias-pull-down;	        /* PULL DOWN */
+				};
+			};
+		};
+
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi
new file mode 100644
index 0000000..dc2e850
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-pm660-pm.dtsi
@@ -0,0 +1,303 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+	qcom,spm@b089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb089000 0x1000>;
+		qcom,name = "cpu0";
+		qcom,cpu = <&CPU0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x3c102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,mode0 {
+			qcom,label = "qcom,saw2-spm-cmd-wfi";
+			qcom,sequence = [60 03 60 0b 0f];
+			qcom,spm_en;
+		};
+		qcom,mode1 {
+			qcom,label = "qcom,saw2-spm-cmd-spc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+		qcom,mode2 {
+			qcom,label = "qcom,saw2-spm-cmd-pc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+	};
+
+	qcom,spm@b099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb099000 0x1000>;
+		qcom,name = "cpu1";
+		qcom,cpu = <&CPU1>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x3c102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,mode0 {
+			qcom,label = "qcom,saw2-spm-cmd-wfi";
+			qcom,sequence = [60 03 60 0b 0f];
+			qcom,spm_en;
+		};
+		qcom,mode1 {
+			qcom,label = "qcom,saw2-spm-cmd-spc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+		qcom,mode2 {
+			qcom,label = "qcom,saw2-spm-cmd-pc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+	};
+
+	qcom,spm@b0a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb0a9000 0x1000>;
+		qcom,name = "cpu2";
+		qcom,cpu = <&CPU2>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x3c102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,mode0 {
+			qcom,label = "qcom,saw2-spm-cmd-wfi";
+			qcom,sequence = [60 03 60 0b 0f];
+			qcom,spm_en;
+		};
+		qcom,mode1 {
+			qcom,label = "qcom,saw2-spm-cmd-spc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+		qcom,mode2 {
+			qcom,label = "qcom,saw2-spm-cmd-pc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+	};
+
+	qcom,spm@b0b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb0b9000 0x1000>;
+		qcom,name = "cpu3";
+		qcom,cpu = <&CPU3>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-spm-dly= <0x3c102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,mode0 {
+			qcom,label = "qcom,saw2-spm-cmd-wfi";
+			qcom,sequence = [60 03 60 0b 0f];
+			qcom,spm_en;
+		};
+		qcom,mode1 {
+			qcom,label = "qcom,saw2-spm-cmd-spc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+		qcom,mode2 {
+			qcom,label = "qcom,saw2-spm-cmd-pc";
+			qcom,sequence = [20 10 80 30 90 5b 60 03 60 3b 76 76
+						0b 94 5b 80 10 26 30 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+	};
+
+	qcom,spm@b012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb012000 0x1000>;
+		qcom,name = "system-l2";
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-spm-dly= <0x3c102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,saw2-pmic-data0 = <0x05030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,vctl-timeout-us = <500>;
+		qcom,vctl-port = <0x0>;
+		qcom,vctl-port-ub = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,mode0 {
+			qcom,label = "qcom,saw2-spm-cmd-ret";
+			qcom,sequence = [00 03 00 0f];
+			qcom,spm_en;
+		};
+		qcom,mode1 {
+			qcom,label = "qcom,saw2-spm-cmd-gdhs";
+			qcom,sequence = [00 20 32 6b c0 e0 d0 42 03 50 4e 02
+					02 d0 e0 c0 22 6b 02 32 50 0f];
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+		qcom,mode2 {
+			qcom,label = "qcom,saw2-spm-cmd-pc";
+			qcom,sequence = [00 20 32 b0 6b c0 e0 d0 42 11 07
+				01 b0 50 4e 02 02 d0 e0 c0 22 6b 02 32 52
+				0f]; /*APC_L2RAM_ON */
+			qcom,spm_en;
+			qcom,pc_mode;
+		};
+	};
+
+	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 = "system";
+			qcom,spm-device-names = "l2";
+			qcom,default-level = <0>;
+
+			qcom,pm-cluster-level@0 {
+				reg = <0>;
+				label = "l2-cache-active";
+				qcom,spm-l2-mode = "active";
+				qcom,latency-us = <270>;
+				qcom,ss-power = <455>;
+				qcom,energy-overhead = <250621>;
+				qcom,time-overhead = <500>;
+			};
+
+			qcom,pm-cluster-level@1{
+				reg = <1>;
+				label = "l2-gdhs";
+				qcom,spm-l2-mode = "gdhs";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <427>;
+				qcom,energy-overhead = <431578>;
+				qcom,time-overhead = <900>;
+				qcom,min-child-idx = <1>;
+				qcom,reset-level = <LPM_RESET_LVL_GDHS>;
+			};
+
+			qcom,pm-cluster-level@2{
+				reg = <2>;
+				label = "l2-pc";
+				qcom,spm-l2-mode = "pc";
+				qcom,latency-us = <11530>;
+				qcom,ss-power = <400>;
+				qcom,energy-overhead = <800000>;
+				qcom,time-overhead = <2500>;
+				qcom,min-child-idx = <2>;
+				qcom,notify-rpm;
+				qcom,no-cache-flush;
+				qcom,reset-level = <LPM_RESET_LVL_PC>;
+			};
+
+			qcom,pm-cpu {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				qcom,pm-cpu-level@0{
+					reg = <0>;
+					qcom,spm-cpu-mode = "wfi";
+					qcom,latency-us = <1>;
+					qcom,ss-power = <473>;
+					qcom,energy-overhead = <100000>;
+					qcom,time-overhead = <50>;
+				};
+
+				qcom,pm-cpu-level@1 {
+					reg = <1>;
+					qcom,spm-cpu-mode = "standalone_pc";
+					qcom,latency-us = <240>;
+					qcom,ss-power = <467>;
+					qcom,energy-overhead = <202781>;
+					qcom,time-overhead = <420>;
+					qcom,use-broadcast-timer;
+					qcom,reset-level =
+						<LPM_RESET_LVL_PC>;
+				};
+
+				qcom,pm-cpu-level@2 {
+					reg = <2>;
+					qcom,spm-cpu-mode = "pc";
+					qcom,latency-us = <270>;
+					qcom,ss-power = <455>;
+					qcom,energy-overhead = <250621>;
+					qcom,time-overhead = <500>;
+					qcom,use-broadcast-timer;
+					qcom,reset-level =
+						<LPM_RESET_LVL_PC>;
+				};
+			};
+		};
+	};
+
+	qcom,pm@8600664 {
+		compatible = "qcom,pm";
+		reg = <0x8600664 0x40>;
+		clocks = <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>;
+		clock-names = "cpu0_clk", "cpu1_clk",
+			      "cpu2_clk", "cpu3_clk";
+		qcom,pc-mode = "tz_l2_int";
+		qcom,use-sync-timer;
+		qcom,synced-clocks;
+	};
+
+	qcom,rpm-stats@29dba0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0x29dba0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+
+	qcom,rpm-master-stats@60150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0x60150 0x2030>;
+		qcom,masters = "APSS", "MPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <4096>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi
new file mode 100644
index 0000000..7197f88
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-regulator.dtsi
@@ -0,0 +1,280 @@
+/* Copyright (c) 2014-2015, 2018 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.
+ */
+
+/* RPM controlled regulators */
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		status = "okay";
+		pm8909_s1_corner: regulator-s1-corner {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s1_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+		pm8909_s1_corner_ao: regulator-s1-corner-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s1_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+		pm8909_s1_floor_corner: regulator-s1-floor-corner {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s1_floor_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-floor-corner;
+			qcom,always-send-voltage;
+		};
+		pm8909_s1_corner_so: regulator-s1-corner-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s1_corner_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,init-voltage = <1>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	rpm-regulator-smpa2 {
+		status = "okay";
+		pm8909_s2: regulator-s2 {
+			status = "okay";
+			regulator-min-microvolt = <1850000>;
+			regulator-max-microvolt = <1850000>;
+			qcom,init-voltage = <1850000>;
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+			status = "okay";
+		pm8909_l1: regulator-l1 {
+			status = "okay";
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			qcom,init-voltage = <1000000>;
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+			status = "okay";
+		pm8909_l2: regulator-l2 {
+			status = "okay";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <12000000>;
+		};
+	};
+
+	/* PM8909 L3 VDD_MX supply */
+	rpm-regulator-ldoa3 {
+			status = "okay";
+		pm8909_l3: regulator-l3 {
+			status = "okay";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1350000>;
+		};
+
+		pm8909_l3_corner_ao: regulator-l3-corner-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l3_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+
+		pm8909_l3_corner_so: regulator-l3-corner-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l3_corner_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,init-voltage = <1>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+			status = "okay";
+		pm8909_l4: regulator-l4 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+			status = "okay";
+		pm8909_l5: regulator-l5 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+			status = "okay";
+		pm8909_l6: regulator-l6 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+			status = "okay";
+		pm8909_l7: regulator-l7 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+
+		pm8909_l7_ao: regulator-l7-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l7_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+
+		pm8909_l7_so: regulator-l7-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l7_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-enable = <0>;
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+			status = "okay";
+		pm8909_l8: regulator-l8 {
+			status = "okay";
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,init-voltage = <2850000>;
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+			status = "okay";
+		pm8909_l9: regulator-l9 {
+			status = "okay";
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3000000>;
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+			status = "okay";
+		pm8909_l10: regulator-l10 {
+			status = "okay";
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,init-voltage = <1225000>;
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+			status = "okay";
+		pm8909_l11: regulator-l11 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+			status = "okay";
+		pm8909_l12: regulator-l12 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+			status = "okay";
+		pm8909_l13: regulator-l13 {
+			status = "okay";
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,init-voltage = <3075000>;
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+			status = "okay";
+		pm8909_l14: regulator-l14 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+			status = "okay";
+		pm8909_l15: regulator-l15 {
+			status = "okay";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+			status = "okay";
+		pm8909_l17: regulator-l17 {
+			status = "okay";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,init-voltage = <2800000>;
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+			status = "okay";
+		pm8909_l18: regulator-l18 {
+			status = "okay";
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,init-voltage = <2700000>;
+		};
+	};
+};
+
+&soc {
+	spk_vreg: regulator_spk {
+		status = "disabled";
+		compatible = "regulator-fixed";
+		regulator-name = "spk_vreg";
+		startup-delay-us = <0>;
+		enable-active-high;
+		gpio = <&msm_gpio 4 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi
new file mode 100644
index 0000000..fe5d707
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-smp2p.dtsi
@@ -0,0 +1,164 @@
+/* Copyright (c) 2014-2015,2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi
new file mode 100644
index 0000000..9467beb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi
@@ -0,0 +1,1888 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "skeleton64.dtsi"
+#include <dt-bindings/clock/msm-clocks-8909.h>
+#include <dt-bindings/clock/msm-clocks-a7.h>
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8909";
+	compatible = "qcom,msm8909";
+	qcom,msm-id =	<245 0>,
+			<258 0>,
+			<265 0>,
+			<275 0>;
+	interrupt-parent = <&intc>;
+
+	chosen {
+		bootargs = "sched_enable_hmp=1";
+	};
+
+	aliases {
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd8 = &smdtty_data4;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd36 = &smdtty_loopback;
+
+		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+		spi0 = &spi_0; /* SPI0 controller device */
+		spi2 = &spi_2;
+		spi4 = &spi_4;
+		i2c5 = &i2c_5; /* I2c5 cntroller device */
+		i2c3 = &i2c_3; /* I2C3 controller */
+		i2c1 = &i2c_1; /* I2C1 controller */
+		i2c2 = &i2c_2; /* I2C2 NFC qup2 device */
+		i2c4 = &i2c_4; /* I2C4 controller device */
+		qpic_nand1 = &qnand_1; /* qpic nand controller */
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		CPU0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x0>;
+			qcom,sleep-status = <&cpu0_slp_sts>;
+			qcom,limits-info = <&mitigation_profile0>;
+		};
+
+		CPU1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x1>;
+			qcom,sleep-status = <&cpu1_slp_sts>;
+			qcom,limits-info = <&mitigation_profile2>;
+		};
+
+		CPU2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x2>;
+			qcom,sleep-status = <&cpu2_slp_sts>;
+			qcom,limits-info = <&mitigation_profile1>;
+		};
+
+		CPU3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x3>;
+			qcom,sleep-status = <&cpu3_slp_sts>;
+			qcom,limits-info = <&mitigation_profile2>;
+		};
+	};
+
+	firmware: firmware {
+		android {
+			compatible = "android,firmware";
+			fstab {
+				compatible = "android,fstab";
+				vendor_fstab: vendor {
+					compatible = "android,vendor";
+					dev =
+			"/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
+					type = "ext4";
+					mnt_flags = "ro,barrier=1,discard";
+					fsmgr_flags = "wait,verify";
+					status = "ok";
+				};
+				system_fstab: system {
+					compatible = "android,system";
+					dev =
+			"/dev/block/platform/soc/7824900.sdhci/by-name/system";
+					type = "ext4";
+					mnt_flags = "ro,barrier=1,discard";
+					fsmgr_flags = "wait,verify";
+					status = "ok";
+				};
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		external_image_mem: external_image__region@0 {
+			reg = <0x0 0x87a00000 0x0 0x0600000>;
+			compatible = "removed-dma-pool";
+			no-map;
+		};
+
+		modem_adsp_mem: modem_adsp_region@0 {
+			reg = <0x0 0x88000000 0x0 0x05500000>;
+			compatible = "removed-dma-pool";
+			no-map;
+		};
+
+		peripheral_mem: pheripheral_region@0 {
+			reg = <0x0 0x8d500000 0x0 0x0700000>;
+			compatible = "removed-dma-pool";
+			no-map;
+		};
+
+		venus_qseecom_mem: venus_qseecom_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+			alignment = <0 0x400000>;
+			size = <0 0x0800000>;
+		};
+
+		audio_mem: audio_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
+		adsp_mem: adsp_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
+		cont_splash_mem: splash_region@83000000 {
+			reg = <0x0 0x83000000 0x0 0xc00000>;
+		};
+	};
+
+	soc: soc { };
+};
+
+#include "msm8909-ion.dtsi"
+#include "msm8909-smp2p.dtsi"
+#include "msm8909-ipcrouter.dtsi"
+#include "msm-gdsc-8916.dtsi"
+#include "msm8909-coresight.dtsi"
+#include "msm8909-bus.dtsi"
+#include "msm8909-mdss.dtsi"
+#include "msm8909-mdss-pll.dtsi"
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0 0 0xffffffff>;
+	compatible = "simple-bus";
+
+	intc: interrupt-controller@b000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0x0b000000 0x1000>,
+		<0x0b002000 0x1000>;
+	};
+
+	restart@4ab000 {
+		compatible = "qcom,pshold";
+		reg =	<0x4ab000 0x4>,
+			<0x193d100 0x4>;
+		reg-names = "pshold-base", "tcsr-boot-misc-detect";
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0xf08>,
+			     <1 3 0xf08>,
+			     <1 4 0xf08>,
+			     <1 1 0xf08>;
+		clock-frequency = <19200000>;
+	};
+
+	timer@b020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xb020000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@b021000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xb021000 0x1000>,
+			      <0xb022000 0x1000>;
+		};
+		frame@b023000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xb023000 0x1000>;
+			status = "disabled";
+		};
+		frame@b024000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xb024000 0x1000>;
+			status = "disabled";
+		};
+		frame@b025000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xb025000 0x1000>;
+			status = "disabled";
+		};
+		frame@b026000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xb026000 0x1000>;
+			status = "disabled";
+		};
+		frame@b027000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xb027000 0x1000>;
+			status = "disabled";
+		};
+		frame@b028000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xb028000 0x1000>;
+			status = "disabled";
+		};
+	};
+
+	clock_rpm: qcom,rpmcc@1800000 {
+		compatible = "qcom,rpmcc-8909";
+		reg = <0x1800000 0x80000>;
+		reg-names = "cc_base";
+		#clock-cells = <1>;
+	};
+
+	clock_gcc: qcom,gcc@1800000 {
+		compatible = "qcom,gcc-8909";
+		reg = <0x1800000 0x80000>,
+		      <0xb016000 0x00040>;
+		reg-names = "cc_base", "apcs_base";
+		vdd_dig-supply = <&pm8909_s1_corner>;
+		vdd_sr2_dig-supply = <&pm8909_s1_corner_ao>;
+		vdd_sr2_pll-supply = <&pm8909_l7_ao>;
+		clocks = <&clock_rpm clk_xo_clk_src>,
+			<&clock_rpm clk_xo_a_clk_src>;
+		clock-names = "xo", "xo_a";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_gcc_mdss: qcom,gcc-mdss@1ac8300 {
+		compatible = "qcom,gcc-mdss-8909";
+		clocks = <&mdss_dsi0_pll clk_dsi_pll0_pixel_clk_src>,
+			 <&mdss_dsi0_pll clk_dsi_pll0_byte_clk_src>;
+		clock-names = "pixel_src", "byte_src";
+		#clock-cells = <1>;
+	};
+
+	clock_debug: qcom,cc-debug@1874000 {
+		compatible = "qcom,cc-debug-8909";
+		reg = <0x1874000 0x4>,
+			<0xb01101c 0x8>;
+		reg-names = "cc_base", "meas";
+		clocks = <&clock_rpm clk_rpm_debug_mux>;
+		clock-names = "rpm_debug_mux";
+		#clock-cells = <1>;
+	};
+
+	clock_cpu: qcom,clock-a7@0b011050 {
+		compatible = "qcom,clock-a53-8916";
+		reg = <0x0b011050 0x8>,
+		      <0x0005c00c 0x8>;
+		reg-names = "rcg-base", "efuse";
+		qcom,safe-freq = < 400000000 >;
+		cpu-vdd-supply = <&pm8909_s1_corner_ao>;
+		qcom,a7ssmux-opp-store-vcorner = <&CPU0>;
+		clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+			 <&clock_gcc clk_a7sspll>;
+		clock-names = "clk-4", "clk-5";
+		qcom,speed0-bin-v0 =
+			<          0 0>,
+			<  400000000 4>,
+			<  800000000 5>,
+			< 1267200000 7>;
+		qcom,speed2-bin-v0 =
+			<          0 0>,
+			<  400000000 4>,
+			<  800000000 5>,
+			< 1094400000 7>;
+		#clock-cells = <1>;
+	};
+
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<  762 /* 100 MHz */>,
+			< 1525 /* 200 MHz */>,
+			< 3051 /* 400 MHz */>,
+			< 4066 /* 533 MHz */>;
+	};
+
+	devfreq-cpufreq {
+		cpubw-cpufreq {
+			target-dev = <&cpubw>;
+			cpu-to-dev-map =
+				 <  400000  762>,
+				 <  800000  1525>,
+				 <  998400  3051>,
+				 < 1094400  4066>;
+		};
+	};
+
+	qcom,cpu-bwmon {
+		compatible = "qcom,bimc-bwmon2";
+		reg = <0x408000 0x300>, <0x401000 0x200>;
+		reg-names = "base", "global_base";
+		interrupts = <0 183 4>;
+		qcom,mport = <0>;
+		qcom,target-dev = <&cpubw>;
+	};
+
+	qcom,msm-cpufreq {
+		reg = <0 4>;
+		compatible = "qcom,msm-cpufreq";
+		clocks = <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>;
+		clock-names = "cpu0_clk", "cpu1_clk",
+				"cpu2_clk", "cpu3_clk";
+		qcom,cpufreq-table =
+			 <  200000 >,
+			 <  400000 >,
+			 <  533330 >,
+			 <  800000 >,
+			 <  998400 >,
+			 < 1094400 >,
+			 < 1190400 >,
+			 < 1248000 >,
+			 < 1267200 >;
+	};
+
+
+	blsp1_uart1: serial@78af000 {
+		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uart";
+		reg = <0x78af000 0x200>;
+		interrupts = <0 107 0>;
+		status = "disabled";
+		clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>,
+			 <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+		clock-names = "core", "iface";
+	};
+
+	blsp1_uart2_hs: uart@78b0000 {		/*BLSP1 UART2*/
+		compatible = "qcom,msm-hsuart-v14";
+		reg = <0x78b0000 0x200>,
+			<0x7884000 0x1f000>;
+		reg-names = "core_mem", "bam_mem";
+		interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+		#address-cells = <0>;
+		interrupt-parent = <&blsp1_uart2_hs>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 108 0
+				1 &intc 0 238 0
+				2 &msm_gpio 21 0>;
+		qcom,inject-rx-on-wakeup;
+		qcom,rx-char-to-inject = <0xfd>;
+		qcom,master-id = <86>;
+		clock-names = "core_clk", "iface_clk";
+		clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+				<&clock_gcc clk_gcc_blsp1_ahb_clk>;
+		pinctrl-names = "sleep", "default";
+		pinctrl-0 = <&blsp1_uart2_tx_sleep>, <&blsp1_uart2_rxcts_sleep>,
+					<&blsp1_uart2_rfr_sleep>;
+		pinctrl-1 = <&blsp1_uart2_tx_active>,
+			<&blsp1_uart2_rxcts_active>, <&blsp1_uart2_rfr_active>;
+
+		qcom,bam-tx-ep-pipe-index = <2>;
+		qcom,bam-rx-ep-pipe-index = <3>;
+		qcom,msm-bus,name = "blsp1_uart2_hs";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<86 512 0 0>,
+				<86 512 500 800>;
+		status = "disabled";
+	};
+
+	qcom,sps {
+		compatible = "qcom,msm_sps_4k";
+		qcom,device-type = <3>;
+		qcom,pipe-attr-ee;
+	};
+
+	thermal_zones: thermal-zones {};
+
+	qcom,sensor-information {
+		compatible = "qcom,sensor-information";
+		sensor_information0: qcom,sensor-information-0 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor0";
+			qcom,alias-name = "pop_mem";
+		};
+
+		sensor_information1: qcom,sensor-information-1 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor1";
+		};
+
+		sensor_information2: qcom,sensor-information-2 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor2";
+		};
+
+		sensor_information3: qcom,sensor-information-3 {
+			qcom,sensor-type =  "tsens";
+			qcom,sensor-name = "tsens_tz_sensor3";
+		};
+
+		sensor_information4: qcom,sensor-information-4 {
+			qcom,sensor-type = "tsens";
+			qcom,sensor-name = "tsens_tz_sensor4";
+		};
+
+		sensor_information5: qcom,sensor-information-5 {
+			qcom,sensor-type = "adc";
+			qcom,sensor-name = "pa_therm0";
+		};
+
+		sensor_information6: qcom,sensor-information-6 {
+			qcom,sensor-type = "adc";
+			qcom,sensor-name = "case_therm";
+		};
+
+		sensor_information7: qcom,sensor-information-7 {
+			qcom,sensor-type = "alarm";
+			qcom,sensor-name = "pm8909_tz";
+			qcom,scaling-factor = <1000>;
+		};
+
+		sensor_information8: qcom,sensor-information-8 {
+			qcom,sensor-type = "adc";
+			qcom,sensor-name = "xo_therm";
+		};
+
+		sensor_information9: qcom,sensor-information-9 {
+			qcom,sensor-type = "adc";
+			qcom,sensor-name = "xo_therm_buf";
+		};
+	};
+
+	mitigation_profile0: qcom,limit_info-0 {
+		qcom,temperature-sensor = <&sensor_information3>;
+		qcom,boot-frequency-mitigate;
+		qcom,emergency-frequency-mitigate;
+	};
+
+	mitigation_profile1: qcom,limit_info-1 {
+		qcom,temperature-sensor = <&sensor_information3>;
+		qcom,boot-frequency-mitigate;
+		qcom,hotplug-mitigation-enable;
+	};
+
+	mitigation_profile2: qcom,limit_info-2 {
+		qcom,temperature-sensor = <&sensor_information4>;
+		qcom,boot-frequency-mitigate;
+		qcom,hotplug-mitigation-enable;
+	};
+
+	qcom,ipc-spinlock@1905000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0x1905000 0x8000>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@87d00000 {
+		compatible = "qcom,smem";
+		reg = <0x87d00000 0x100000>,
+			<0x0b011008 0x4>,
+			<0x60000 0x8000>,
+			<0x193D000 0x8>;
+		reg-names = "smem", "irq-reg-base",
+				"aux-mem1", "smem_targ_info_reg";
+		qcom,mpu-enabled;
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			interrupts = <0 25 1>;
+			label = "modem";
+			qcom,not-loadable;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			interrupts = <0 142 1>;
+			label = "wcnss";
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			label = "rpm";
+			qcom,irq-no-suspend;
+			qcom,not-loadable;
+		};
+	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data4: qcom,smdtty-data4 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA4";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
+	qcom,smdpkt {
+		compatible = "qcom,smdpkt";
+
+		qcom,smdpkt-data5-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA5_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl0";
+		};
+
+		qcom,smdpkt-data22 {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA22";
+			qcom,smdpkt-dev-name = "smd22";
+		};
+
+		qcom,smdpkt-data40-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA40_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl8";
+		};
+
+		qcom,smdpkt-apr-apps2 {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "apr_apps2";
+			qcom,smdpkt-dev-name = "apr_apps2";
+		};
+
+		qcom,smdpkt-loopback {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "LOOPBACK";
+			qcom,smdpkt-dev-name = "smd_pkt_loopback";
+		};
+	};
+
+	wcnss: qcom,wcnss-wlan@a000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0x0a000000 0x280000>,
+			<0xb011008 0x04>,
+			<0x0a21b000 0x3000>,
+			<0x03204000 0x00000100>,
+			<0x03200800 0x00000200>,
+			<0x0A100400 0x00000200>,
+			<0x0A205050 0x00000200>,
+			<0x0A219000 0x00000020>,
+			<0x0A080488 0x00000008>,
+			<0x0A080fb0 0x00000008>,
+			<0x0A08040c 0x00000008>,
+			<0x0A0120a8 0x00000008>,
+			<0x0A012448 0x00000008>,
+			<0x0A080c00 0x00000001>,
+			<0x0005E000 0x00000064>;
+
+		reg-names = "wcnss_mmio", "wcnss_fiq",
+			    "pronto_phy_base", "riva_phy_base",
+			    "riva_ccu_base", "pronto_a2xb_base",
+			    "pronto_ccpu_base", "pronto_saw2_base",
+			    "wlan_tx_phy_aborts","wlan_brdg_err_source",
+			    "wlan_tx_status", "alarms_txctl",
+			    "alarms_tactl", "pronto_mcu_base",
+			    "pronto_qfuse";
+
+		interrupts = <0 145 0 0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8909_l3_corner_ao>;
+		qcom,pronto-vddcx-supply = <&pm8909_s1_corner>;
+		qcom,pronto-vddpx-supply = <&pm8909_l7>;
+		qcom,iris-vddxo-supply   = <&pm8909_l7>;
+		qcom,iris-vddrfa-supply  = <&pm8909_l10>;
+		qcom,iris-vddpa-supply   = <&pm8909_l9>;
+		qcom,iris-vdddig-supply  = <&pm8909_l5>;
+
+		qcom,iris-vddxo-voltage-level = <1800000 0 1800000>;
+		qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>;
+		qcom,iris-vddpa-voltage-level = <3300000 0 3300000>;
+		qcom,iris-vdddig-voltage-level = <1800000 0 1800000>;
+
+		qcom,vddmx-voltage-level = <5 1 7>;
+		qcom,vddcx-voltage-level = <5 1 7>;
+		qcom,vddpx-voltage-level = <1800000 0 1800000>;
+
+		qcom,iris-vddxo-current = <10000>;
+		qcom,iris-vddrfa-current = <100000>;
+		qcom,iris-vddpa-current = <515000>;
+		qcom,iris-vdddig-current = <10000>;
+
+		qcom,pronto-vddmx-current = <0>;
+		qcom,pronto-vddcx-current = <0>;
+		qcom,pronto-vddpx-current = <0>;
+
+		pinctrl-names = "wcnss_default", "wcnss_sleep",
+						"wcnss_gpio_default";
+		pinctrl-0 = <&wcnss_default>;
+		pinctrl-1 = <&wcnss_sleep>;
+		pinctrl-2 = <&wcnss_gpio_default>;
+
+		gpios = <&msm_gpio 40 0>, <&msm_gpio 41 0>, <&msm_gpio 42 0>,
+					<&msm_gpio 43 0>, <&msm_gpio 44 0>;
+
+		clocks = <&clock_rpm clk_xo_wlan_clk>,
+			 <&clock_rpm clk_rf_clk2>,
+			 <&clock_debug clk_gcc_debug_mux>,
+			 <&clock_gcc clk_wcnss_m_clk>;
+		clock-names = "xo", "rf_clk", "measure", "wcnss_debug";
+
+		qcom,wlan-rx-buff-count = <512>;
+		qcom,has-autodetect-xo;
+		qcom,is-pronto-v3;
+		qcom,is-dual-band-disabled;
+		qcom,is-pronto-vadc;
+		qcom,has-pronto-hw;
+		qcom,wcnss-adc_tm = <&pm8909_adc_tm>;
+	};
+
+	usb_otg: usb@78d9000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0x78d9000 0x400>, <0x6c000 0x200>;
+		reg-names = "core", "phy_csr";
+
+		interrupts = <0 134 0>,<0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+
+		hsusb_vdd_dig-supply = <&pm8909_l2>;
+		HSUSB_1p8-supply = <&pm8909_l7>;
+		HSUSB_3p3-supply = <&pm8909_l13>;
+		qcom,vdd-voltage-level = <0 1200000 1200000>;
+
+		qcom,hsusb-otg-phy-init-seq = <0x73 0x80 0xffffffff>;
+		qcom,hsusb-otg-phy-type = <3>; /* SNPS Femto PHY */
+		qcom,hsusb-otg-mode = <1>; /* DEVICE only */
+		qcom,hsusb-otg-otg-control = <2>; /* PMIC */
+		qcom,dp-manual-pullup;
+		qcom,phy-dvdd-always-on;
+		qcom,hsusb-otg-mpm-dpsehv-int = <49>;
+		qcom,hsusb-otg-mpm-dmsehv-int = <58>;
+
+		qcom,msm-bus,name = "usb2";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<87 512 0 0>,
+				<87 512 80000 0>,
+				<87 512 6000  6000>;
+		clocks = <&clock_gcc clk_gcc_usb_hs_ahb_clk>,
+			 <&clock_gcc clk_gcc_usb_hs_system_clk>,
+			 <&clock_gcc clk_gcc_usb2a_phy_sleep_clk>,
+			 <&clock_rpm clk_bimc_usb_a_clk>,
+			 <&clock_rpm clk_snoc_usb_a_clk>,
+			 <&clock_rpm clk_pcnoc_usb_a_clk>,
+			 <&clock_gcc clk_gcc_qusb2_phy_clk>,
+			 <&clock_gcc clk_gcc_usb2_hs_phy_only_clk>,
+			 <&clock_gcc clk_gcc_usb_hs_phy_cfg_ahb_clk>,
+			 <&clock_rpm clk_xo_otg_clk>;
+		clock-names = "iface_clk", "core_clk", "sleep_clk",
+				"bimc_clk", "snoc_clk", "pcnoc_clk",
+				"phy_reset_clk", "phy_por_clk", "phy_csr_clk",
+				"xo";
+		qcom,bus-clk-rate = <400000000 200000000 100000000>;
+		qcom,max-nominal-sysclk-rate = <100000000>;
+		qcom,boost-sysclk-with-streaming;
+		resets = <&clock_gcc GCC_USB_HS_BCR>,
+			 <&clock_gcc GCC_QUSB2_PHY_BCR>,
+			 <&clock_gcc GCC_USB2_HS_PHY_ONLY_BCR>;
+		reset-names = "core_reset", "phy_reset", "phy_por_reset";
+	};
+
+	android_usb: android_usb@086000c8 {
+		compatible = "qcom,android-usb";
+		reg = <0x086000c8 0xc8>;
+		qcom,pm-qos-latency = <2 1001 12701>;
+	};
+
+	qcom,usbbam@78c4000 {
+		compatible = "qcom,usb-bam-msm";
+		reg = <0x78c4000 0x15000>;
+		reg-names = "hsusb";
+		interrupts = <0 135 0>;
+		interrupt-names = "hsusb";
+		qcom,bam-type = <1>;
+		qcom,usb-bam-num-pipes = <2>;
+		qcom,usb-bam-fifo-baseaddr = <0x08603800>;
+		qcom,ignore-core-reset-ack;
+		qcom,disable-clk-gating;
+		qcom,reset-bam-on-disconnect;
+
+		qcom,pipe0 {
+			label = "hsusb-qdss-in-0";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <0>;
+			qcom,peer-bam-physical-address = <0x884000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-pipe-index = <0>;
+			qcom,data-fifo-offset = <0x0>;
+			qcom,data-fifo-size = <0x600>;
+			qcom,descriptor-fifo-offset = <0x600>;
+			qcom,descriptor-fifo-size = <0x200>;
+		};
+	};
+
+	spmi_bus: qcom,spmi@200f000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0x200f000 0x1000>,
+			<0x2400000 0x400000>,
+			<0x2c00000 0x400000>,
+			<0x3800000 0x200000>,
+			<0x200a000 0x2100>;
+		reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+		interrupt-names = "periph_irq";
+		interrupts = <0 190 0>;
+		qcom,ee = <0>;
+		qcom,channel = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <4>;
+		interrupt-controller;
+		cell-index = <0>;
+	};
+
+	qcom,rmtfs_sharedmem@87c00000 {
+
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x87c00000 0xe0000>;
+		reg-names = "rmtfs";
+		qcom,client-id = <0x00000001>;
+	};
+
+	qcom,dsp_sharedmem@87ce0000 {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x87ce0000 0x10000>;
+		reg-names = "rfsa_dsp";
+		qcom,client-id = <0x011013ec>;
+	};
+
+	qcom,mdm_sharedmem@87cf0000 {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x87cf0000 0x10000>;
+		reg-names = "rfsa_mdm";
+		qcom,client-id = <0x011013ed>;
+	};
+
+	cpu-pmu {
+		compatible = "arm,cortex-a7-pmu";
+		qcom,irq-is-percpu;
+		interrupts = <1 7 0xf00>;
+	};
+
+	jtag_fuse: jtagfuse@5e01c {
+		compatible = "qcom,jtag-fuse-v2";
+		reg = <0x5e01c 0x8>;
+		reg-names = "fuse-base";
+	};
+
+	jtag_mm0: jtagmm@84c000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0x84c000 0x1000>,
+		      <0x840000 0x1000>;
+		reg-names = "etm-base","debug-base";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,coresight-jtagmm-cpu = <&CPU0>;
+	};
+
+	jtag_mm1: jtagmm@84d000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0x84d000 0x1000>,
+		      <0x842000 0x1000>;
+		reg-names = "etm-base","debug-base";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,coresight-jtagmm-cpu = <&CPU1>;
+	};
+
+	jtag_mm2: jtagmm@84e000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0x84e000 0x1000>,
+		      <0x844000 0x1000>;
+		reg-names = "etm-base","debug-base";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,coresight-jtagmm-cpu = <&CPU2>;
+	};
+
+	jtag_mm3: jtagmm@84f000 {
+		compatible = "qcom,jtag-mm";
+		reg = <0x84f000 0x1000>,
+		      <0x846000 0x1000>;
+		reg-names = "etm-base","debug-base";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+
+		qcom,coresight-jtagmm-cpu = <&CPU3>;
+	};
+
+	qnand_1: nand@7980000 {
+		compatible = "qcom,msm-nand";
+		reg = <0x7980000 0x1000>,
+			<0x7984000 0x1a000>,
+			<0x5e02c 0x4>;
+		reg-names = "nand_phys",
+		    "bam_phys", "boot_cfg";
+		qcom,reg-adjustment-offset = <0>;
+		interrupts = <0 132 0>;
+		interrupt-names = "bam_irq";
+
+		qcom,msm-bus,name = "qpic_nand";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<91 512 0 0>,
+		/* Voting for max b/w on PNOC bus for now */
+			<91 512 400000 800000>;
+
+		clock-names = "core_clk";
+		clocks = <&clock_rpm clk_qpic_clk>;
+		status = "disabled";
+	};
+
+	sdhc_1: sdhci@7824000 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0x07824900 0x11c>, <0x07824000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+
+		interrupts = <0 123 0>, <0 138 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+
+		qcom,bus-width = <8>;
+
+		qcom,pm-qos-irq-type = "affine_irq";
+		qcom,pm-qos-irq-latency = <2 250>;
+
+		qcom,msm-bus,name = "sdhc1";
+		qcom,msm-bus,num-cases = <8>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+				<78 512 1046 3200>,    /* 400 KB/s*/
+				<78 512 52286 160000>, /* 20 MB/s */
+				<78 512 65360 200000>, /* 25 MB/s */
+				<78 512 130718 400000>, /* 50 MB/s */
+				<78 512 261438 800000>, /* 100 MB/s */
+				<78 512 261438 800000>, /* 200 MB/s */
+				<78 512 1338562 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+						100000000 200000000 4294967295>;
+
+
+		clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+			 <&clock_gcc clk_gcc_sdcc1_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,clk-rates = <400000 25000000 50000000 100000000 177770000>;
+		qcom,devfreq,freq-table = <50000000 177770000>;
+
+		status = "disabled";
+	};
+
+	sdhc_2: sdhci@07864000 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0x07864900 0x11c>, <0x07864000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+
+		interrupts = <0 125 0>, <0 221 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+
+		qcom,bus-width = <4>;
+
+		qcom,pm-qos-irq-type = "affine_irq";
+		qcom,pm-qos-irq-latency = <2 250>;
+
+		qcom,msm-bus,name = "sdhc2";
+		qcom,msm-bus,num-cases = <8>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+				<81 512 1046 3200>,    /* 400 KB/s*/
+				<81 512 52286 160000>, /* 20 MB/s */
+				<81 512 65360 200000>, /* 25 MB/s */
+				<81 512 130718 400000>, /* 50 MB/s */
+				<81 512 261438 800000>, /* 100 MB/s */
+				<81 512 261438 800000>, /* 200 MB/s */
+				<81 512 1338562 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+						100000000 200000000 4294967295>;
+
+		clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
+			 <&clock_gcc clk_gcc_sdcc2_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,devfreq,freq-table = <50000000 200000000>;
+
+		status = "disabled";
+	};
+
+	qcom,wdt@b017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xb017000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+	};
+
+	qcom,msm-imem@8600000 {
+		compatible = "qcom,msm-imem";
+		reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+		ranges = <0x0 0x08600000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		mem_dump_table@10 {
+			compatible = "qcom,msm-imem-mem_dump_table";
+			reg = <0x10 8>;
+		};
+
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+
+		pil@94c {
+			compatible = "qcom,msm-imem-pil";
+			reg = <0x94c 200>;
+		};
+
+		restart_reason@65c {
+			compatible = "qcom,msm-imem-restart_reason";
+			reg = <0x65c 4>;
+		};
+	};
+
+	qcom,mpm2-sleep-counter@4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0x4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
+	spi_0: spi@78ba000 { /* BLSP1 QUP6 */
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0x78ba000 0x600>,
+		      <0x7884000 0x23000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 100 0>, <0 238 0>;
+		spi-max-frequency = <19200000>;
+		pinctrl-names = "spi_default", "spi_sleep";
+		pinctrl-0 = <&spi0_default &spi0_cs0_active>;
+		pinctrl-1 = <&spi0_sleep &spi0_cs0_sleep>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+		<&clock_gcc clk_gcc_blsp1_qup6_spi_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,use-pinctrl;
+		qcom,ver-reg-exists;
+		qcom,bam-consumer-pipe-index = <14>;
+		qcom,bam-producer-pipe-index = <15>;
+		qcom,master-id = <86>;
+	};
+
+	spi_2: spi@78b6000 { /* BLSP1 QUP2 */
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0x78b6000 0x600>,
+		      <0x7884000 0x23000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 96 0>, <0 238 0>;
+		spi-max-frequency = <50000000>;
+		pinctrl-names = "spi_default", "spi_sleep";
+		pinctrl-0 = <&spi2_default &spi2_cs0_active>;
+		pinctrl-1 = <&spi2_sleep &spi2_cs0_sleep>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+		<&clock_gcc clk_gcc_blsp1_qup2_spi_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,use-pinctrl;
+		qcom,ver-reg-exists;
+		qcom,bam-consumer-pipe-index = <6>;
+		qcom,bam-producer-pipe-index = <7>;
+		qcom,master-id = <86>;
+		status = "disabled";
+	};
+
+	spi_4: spi@78B8000{ /* BLSP1 QUP4 */
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0x78b8000 0x600>,
+		      <0x7884000 0x23000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 98 0>, <0 238 0>;
+		spi-max-frequency = <50000000>;
+		pinctrl-names = "spi_default", "spi_sleep";
+		pinctrl-0 = <&spi4_default &spi4_cs0_active>;
+		pinctrl-1 = <&spi4_sleep &spi4_cs0_sleep>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+		<&clock_gcc clk_gcc_blsp1_qup4_spi_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,use-pinctrl;
+		qcom,ver-reg-exists;
+		qcom,bam-consumer-pipe-index = <10>;
+		qcom,bam-producer-pipe-index = <11>;
+		qcom,master-id = <86>;
+		status = "disabled";
+	};
+
+	dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7884000 0x23000>;
+		interrupts = <0 238 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b6000 0x1000>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 96 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			 <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_2_active>;
+		pinctrl-1 = <&i2c_2_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		dmas = <&dma_blsp1 6 64 0x20000020 0x20>,
+			<&dma_blsp1 7 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		qcom,master-id = <86>;
+	};
+
+	i2c_4: i2c@78b8000 { /* BLSP1 QUP4 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b8000 0x1000>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 98 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			 <&clock_gcc clk_gcc_blsp1_qup4_i2c_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_4_active>;
+		pinctrl-1 = <&i2c_4_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+			<&dma_blsp1 11 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		qcom,master-id = <86>;
+	};
+
+	 i2c_5: i2c@78b9000 { /* BLSP1 QUP5 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b9000 0x1000>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 99 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			 <&clock_gcc clk_gcc_blsp1_qup5_i2c_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,clk-freq-out = <100000>;
+		qcom,clk-freq-in  = <19200000>;
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_5_active>;
+		pinctrl-1 = <&i2c_5_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		dmas = <&dma_blsp1 12 64 0x20000020 0x20>,
+		<&dma_blsp1 13 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		qcom,master-id = <86>;
+};
+
+	i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b7000 0x1000>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 97 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			 <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,clk-freq-out = <100000>;
+		qcom,clk-freq-in  = <19200000>;
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_3_active>;
+		pinctrl-1 = <&i2c_3_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+			<&dma_blsp1 9  32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		qcom,master-id = <86>;
+	};
+
+	i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b5000 0x1000>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 95 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			 <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,clk-freq-out = <100000>;
+		qcom,clk-freq-in  = <19200000>;
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_1_active>;
+		pinctrl-1 = <&i2c_1_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		dmas = <&dma_blsp1 4 64 0x20000020 0x20>,
+			<&dma_blsp1 5  32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		qcom,master-id = <86>;
+	};
+
+	qcom,venus@1de0000 {
+		compatible = "qcom,pil-tz-generic";
+		reg = <0x1de0000 0x4000>;
+
+		vdd-supply = <&gdsc_venus>;
+		qcom,proxy-reg-names = "vdd";
+
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			 <&clock_gcc clk_gcc_venus0_ahb_clk>,
+			 <&clock_gcc clk_gcc_venus0_axi_clk>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>,
+			 <&clock_gcc clk_crypto_clk_src>;
+
+		clock-names = "core_clk", "iface_clk", "bus_clk",
+				"scm_core_clk", "scm_iface_clk",
+				"scm_bus_clk", "scm_core_clk_src";
+
+		qcom,proxy-clock-names = "core_clk", "iface_clk",
+					 "bus_clk", "scm_core_clk",
+					 "scm_iface_clk", "scm_bus_clk",
+					 "scm_core_clk_src";
+		qcom,scm_core_clk_src-freq = <80000000>;
+
+		qcom,pas-id = <9>;
+		qcom,proxy-timeout-ms = <100>;
+		qcom,firmware-name = "venus";
+		memory-region = <&venus_qseecom_mem>;
+	};
+
+	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";
+	};
+
+	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";
+	};
+
+	lpa: qcom,msm-pcm-lpa {
+		compatible = "qcom,msm-pcm-lpa";
+	};
+
+	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;
+		qcom,vote-bms;
+	};
+
+	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";
+	};
+
+	voice_svc: qcom,msm-voice-svc {
+		compatible = "qcom,msm-voice-svc";
+	};
+
+	loopback: qcom,msm-pcm-loopback {
+		compatible = "qcom,msm-pcm-loopback";
+	};
+
+	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_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 = <0>;
+			qcom,msm-mi2s-tx-lines = <3>;
+		};
+
+		dai_mi2s5: qcom,msm-dai-q6-mi2s-quin {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <5>;
+			qcom,msm-mi2s-rx-lines = <1>;
+			qcom,msm-mi2s-tx-lines = <2>;
+		};
+
+		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_mi2s6: 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>;
+		};
+	};
+
+	dai_hdmi: qcom,msm-dai-q6-hdmi {
+		compatible = "qcom,msm-dai-q6-hdmi";
+		qcom,msm-dai-q6-dev-id = <8>;
+	};
+
+	lsm: qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
+	qcom,msm-dai-q6 {
+		compatible = "qcom,msm-dai-q6";
+		sb_0_rx: qcom,msm-dai-q6-sb-0-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16384>;
+		};
+
+		sb_0_tx: qcom,msm-dai-q6-sb-0-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16385>;
+		};
+
+		sb_1_rx: qcom,msm-dai-q6-sb-1-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16386>;
+		};
+
+		sb_1_tx: qcom,msm-dai-q6-sb-1-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16387>;
+		};
+
+		sb_3_rx: qcom,msm-dai-q6-sb-3-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16390>;
+		};
+
+		sb_3_tx: qcom,msm-dai-q6-sb-3-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16391>;
+		};
+
+		sb_4_rx: qcom,msm-dai-q6-sb-4-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16392>;
+		};
+
+		sb_4_tx: qcom,msm-dai-q6-sb-4-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16393>;
+		};
+
+		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>;
+		};
+
+		bt_a2dp_rx: qcom,msm-dai-q6-bt-a2dp-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12290>;
+		};
+
+		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>;
+		};
+
+		afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <24577>;
+		};
+
+		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>;
+		};
+	};
+
+	hostless: qcom,msm-pcm-hostless {
+		compatible = "qcom,msm-pcm-hostless";
+	};
+
+	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-audio-ion {
+		compatible = "qcom,msm-audio-ion";
+	};
+
+	qcom,mdsprpc-mem {
+		compatible = "qcom,msm-mdsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+		qcom,adsp-state = <0>;
+		qcom,proc-img-to-load = "modem";
+	};
+
+	qcom,avtimer@770600c {
+		compatible = "qcom,avtimer";
+		reg = <0x0770600C 0x4>,
+			<0x07706010 0x4>;
+		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+		qcom,clk-div = <27>;
+	};
+
+	qcom,memshare {
+		compatible = "qcom,memshare";
+
+		qcom,client_1 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x200000>;
+			qcom,client-id = <0>;
+			qcom,allocate-boot-time;
+			label = "modem";
+		};
+
+		qcom,client_2 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x300000>;
+			qcom,client-id = <2>;
+			label = "modem";
+		};
+
+		qcom,client_3 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0>;
+			qcom,client-id = <1>;
+			label = "modem";
+		};
+	};
+
+
+	qcom_tzlog: tz-log@8600720 {
+		compatible = "qcom,tz-log";
+		reg = <0x08600720 0x1000>;
+		status = "disabled";
+	};
+
+	qcom_rng: qrng@22000 {
+		compatible = "qcom,msm-rng";
+		reg = <0x22000 0x200>;
+		qcom,msm-rng-iface-clk;
+		qcom,msm-bus,name = "msm-rng-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<1 618 0 0>,		/* No vote */
+				<1 618 0 800>;		/* 100 MB/s */
+		clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+		clock-names = "iface_clk";
+		status = "disabled";
+	};
+
+	qcom_crypto: qcrypto@720000 {
+		compatible = "qcom,qcrypto";
+		reg = <0x720000 0x20000>,
+		      <0x704000 0x20000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <2>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,clk-mgmt-sus-res;
+		qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 393600 800000>; /* 49.2MHz & 100MHz */
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		qcom,use-sw-aes-cbc-ecb-ctr-algo;
+		qcom,use-sw-aes-xts-algo;
+		qcom,use-sw-ahash-algo;
+		status = "disabled";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	qcom_cedev: qcedev@720000 {
+		compatible = "qcom,qcedev";
+		reg = <0x720000 0x20000>,
+		      <0x704000 0x20000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <1>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,ce-hw-shared;
+		qcom,msm-bus,name = "qcedev-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 3936000 393600>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		status = "disabled";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	qcom_seecom: qseecom@87a00000 {
+		compatible = "qcom,qseecom";
+		reg = <0x87a00000 0x200000>;
+		reg-names = "secapp-region";
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <0>;
+		qcom,qsee-ce-hw-instance = <0>;
+		qcom,msm-bus,name = "qseecom-noc";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,support-bus-scaling;
+		qcom,support-fde;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 0 0>,
+				<55 512 120000 1200000>,
+				<55 512 393600 3936000>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		status = "disabled";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	qcom,pronto@a21b000 {
+		compatible = "qcom,pil-tz-generic";
+		reg = <0x0a21b000 0x3000>;
+		interrupts = <0 149 1>;
+
+		vdd_pronto_pll-supply = <&pm8909_l7>;
+		proxy-reg-names = "vdd_pronto_pll";
+		vdd_pronto_pll-uV-uA = <1800000 18000>;
+		clocks = <&clock_rpm clk_xo_pil_pronto_clk>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>,
+			 <&clock_gcc clk_crypto_clk_src>;
+
+		clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				"scm_bus_clk", "scm_core_clk_src";
+		qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				 "scm_bus_clk", "scm_core_clk_src";
+		qcom,scm_core_clk_src = <80000000>;
+
+		qcom,pas-id = <6>;
+		qcom,proxy-timeout-ms = <10000>;
+		qcom,smem-id = <422>;
+		qcom,sysmon-id = <6>;
+		qcom,ssctl-instance-id = <0x13>;
+		qcom,firmware-name = "wcnss";
+
+		/* GPIO inputs from wcnss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
+		qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_4_in 3 0>;
+
+		/* GPIO output to wcnss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
+		memory-region = <&peripheral_mem>;
+	};
+
+	qcom,mss@4080000 {
+		compatible = "qcom,pil-q6v55-mss";
+		reg = <0x04080000 0x100>,
+		      <0x0194f000 0x010>,
+		      <0x01950000 0x008>,
+		      <0x01951000 0x008>,
+		      <0x04020000 0x040>,
+		      <0x0183e000 0x004>;
+		reg-names = "qdsp6_base", "halt_q6", "halt_modem", "halt_nc",
+				 "rmb_base", "restart_reg";
+
+		interrupts = <0 24 1>;
+		vdd_cx-supply = <&pm8909_s1_corner>;
+		vdd_cx-voltage = <7>;
+		vdd_mx-supply = <&pm8909_l3_corner_ao>;
+		vdd_mx-uV = <3>;
+		vdd_pll-supply = <&pm8909_l7>;
+		qcom,vdd_pll = <1800000>;
+
+		clocks = <&clock_rpm clk_xo_pil_mss_clk>,
+			 <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+			 <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+			 <&clock_gcc clk_gcc_boot_rom_ahb_clk>;
+		clock-names = "xo", "iface_clk", "bus_clk", "mem_clk";
+		qcom,proxy-clock-names = "xo";
+		qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
+
+		qcom,firmware-name = "modem";
+		qcom,pil-self-auth;
+		qcom,sysmon-id = <0>;
+		qcom,ssctl-instance-id = <0x12>;
+
+		/* GPIO inputs from mss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+		qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+
+		/* GPIO output to mss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+		memory-region = <&modem_adsp_mem>;
+	};
+
+	mcd {
+		compatible = "qcom,mcd";
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	cpu0_slp_sts: cpu-sleep-status@b088008 {
+		reg = <0xb088008 0x100>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+
+	cpu1_slp_sts: cpu-sleep-status@b098008 {
+		reg = <0xb098008 0x100>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+
+	cpu2_slp_sts: cpu-sleep-status@b0a8008 {
+		reg = <0xb0a8008 0x100>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+
+	cpu3_slp_sts: cpu-sleep-status@b0b8008 {
+		reg = <0xb0b8008 0x100>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+};
+
+&gdsc_venus {
+	clock-names = "bus_clk", "core_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_axi_clk>,
+		 <&clock_gcc clk_gcc_venus0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_venus_core0 {
+	qcom,support-hw-trigger;
+	clock-names = "core0_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_mdss {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+		 <&clock_gcc clk_gcc_mdss_axi_clk>;
+	status = "okay";
+};
+
+&gdsc_vfe {
+	clock-names = "core_clk", "bus_clk", "csi_clk";
+	clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>,
+		 <&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+		 <&clock_gcc clk_gcc_camss_csi_vfe0_clk>;
+	status = "okay";
+};
+
+&gdsc_oxili_gx {
+	clock-names = "core_clk";
+	clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi
new file mode 100644
index 0000000..945b945
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+&external_image_mem {
+	reg = <0x0 0x87b00000 0x0 0x0500000>;
+};
+
+&modem_adsp_mem {
+	reg = <0x0 0x88000000 0x0 0x05200000>;
+};
+
+&peripheral_mem {
+	reg = <0x0 0x8d200000 0x0 0x0600000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
new file mode 100644
index 0000000..8bcbe68
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8909-mtp.dtsi"
+#include "msm8909w.dtsi"
+#include "msm8909w-bg-memory.dtsi"
+#include "8909w-pm660.dtsi"
+#include "msm8909-audio-bg_codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BLACKGHOST WTP";
+	compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp";
+	qcom,msm-id =   <245 0>,
+			<258 0>,
+			<275 0>,
+			<300 0>;
+	qcom,board-id = <8 0x10f>;
+	qcom,pmic-id =  <0x0001001b 0x0 0x0 0x0>,
+			<0x0001011b 0x0 0x0 0x0>;
+};
+
+&soc {
+	i2c@78b9000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,dsx-i2c";
+			reg = <0x20>;
+			interrupt-parent = <&msm_gpio>;
+			interrupts = <98 0x2008>;
+			vdd_ana-supply = <&pm660_l18>;
+			vcc_i2c-supply = <&pm660_l13>;
+			synaptics,pwr-reg-name = "vdd_ana";
+			synaptics,bus-reg-name = "vcc_i2c";
+			pinctrl-names = "pmx_ts_active", "pmx_ts_suspend",
+							"pmx_ts_release";
+			pinctrl-0 = <&ts_int_active &ts_reset_active>;
+			pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+			pinctrl-2 = <&ts_release>;
+			synaptics,irq-gpio = <&msm_gpio 98 0x2008>;
+			synaptics,irq-on-state = <0>;
+			synaptics,irq-flags = <0x2008>;
+			synaptics,power-delay-ms = <200>;
+			synaptics,reset-delay-ms = <200>;
+			synaptics,max-y-for-2d = <389>;
+			synaptics,wakeup-gestures-en;
+			synaptics,resume-in-workqueue;
+			synaptics,x-flip;
+			synaptics,y-flip;
+			/delete-property/ synaptics,reset-gpio;
+			/delete-property/ synaptics,display-coords;
+			/delete-property/ synaptics,panel-coords;
+			/delete-property/ synaptics,power-down;
+			/delete-property/ synaptics,disable-gpios;
+			/delete-property/ synaptics,is_wake;
+		};
+
+		/delete-node/ it7260@46;
+	};
+
+	qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+	};
+
+	qcom,glink-bgcom-xprt-bg {
+		compatible = "qcom,glink-bgcom-xprt";
+		label = "bg";
+		qcom,qos-config = <&glink_qos_bg>;
+		qcom,ramp-time = <0x10>,
+				     <0x20>,
+				     <0x30>,
+				     <0x40>;
+	};
+
+	glink_qos_bg: qcom,glink-qos-config-bg {
+		compatible = "qcom,glink-qos-config";
+		qcom,flow-info = <0x80 0x0>,
+				 <0x70 0x1>,
+				 <0x60 0x2>,
+				 <0x50 0x3>;
+		qcom,mtu-size = <0x800>;
+		qcom,tput-stats-cycle = <0xa>;
+	};
+
+	qcom,glink_pkt {
+		compatible = "qcom,glinkpkt";
+
+		qcom,glinkpkt-bg-daemon {
+			qcom,glinkpkt-transport = "bgcom";
+			qcom,glinkpkt-edge = "bg";
+			qcom,glinkpkt-ch-name = "bg-daemon";
+			qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon";
+		};
+
+		qcom,glinkpkt-bg-display-ctrl {
+			qcom,glinkpkt-transport = "bgcom";
+			qcom,glinkpkt-edge = "bg";
+			qcom,glinkpkt-ch-name = "display-ctrl";
+			qcom,glinkpkt-dev-name = "glink_pkt_bg_display_ctrl";
+		};
+
+		qcom,glinkpkt-bg-display-data {
+			qcom,glinkpkt-transport = "bgcom";
+			qcom,glinkpkt-edge = "bg";
+			qcom,glinkpkt-ch-name = "display-data";
+			qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data";
+		};
+
+		qcom,glinkpkt-bg-rsb-ctrl {
+			qcom,glinkpkt-transport = "bgcom";
+			qcom,glinkpkt-edge = "bg";
+			qcom,glinkpkt-ch-name = "RSB_CTRL";
+			qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl";
+		};
+	};
+
+	spi@78B8000 {  /* BLSP1 QUP4 */
+		status = "ok";
+		qcom,bg-spi {
+			compatible = "qcom,bg-spi";
+			reg = <0>;
+			spi-max-frequency = <16000000>;
+			interrupt-parent = <&msm_gpio>;
+			qcom,irq-gpio = <&msm_gpio 110 1>;
+		};
+	};
+
+	qcom,msm-thermal {
+		vdd-dig-supply = <&pm660_s2_floor_corner>;
+
+		msm_thermal_freq: qcom,vdd-apps-rstr {
+			qcom,vdd-rstr-reg = "vdd-apps";
+			qcom,levels = <1094400>;
+			qcom,freq-req;
+		};
+	};
+
+	qcom,bg-rsb {
+		compatible = "qcom,bg-rsb";
+		vdd-ldo1-supply = <&pm660_l11>;
+		vdd-ldo2-supply = <&pm660_l15>;
+	};
+
+	qcom,bg-daemon {
+		compatible = "qcom,bg-daemon";
+		qcom,bg-reset-gpio = <&pm660_gpios 5 0>;
+	};
+
+	qcom,bcl {
+		compatible = "qcom,bcl";
+		qcom,bcl-enable;
+		qcom,bcl-framework-interface;
+		qcom,bcl-freq-control-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,bcl-hotplug-list = <&CPU2 &CPU3>;
+		qcom,bcl-soc-hotplug-list = <&CPU2 &CPU3>;
+		qcom,ibat-monitor {
+			qcom,low-threshold-uamp = <1000000>;
+			qcom,high-threshold-uamp = <2000000>;
+			qcom,mitigation-freq-khz = <1094400>;
+			qcom,vph-high-threshold-uv = <3500000>;
+			qcom,vph-low-threshold-uv = <3200000>;
+			qcom,soc-low-threshold = <10>;
+			qcom,thermal-handle = <&msm_thermal_freq>;
+		};
+	};
+};
+
+&audio_codec_mtp {
+	status = "disabled";
+};
+
+&audio_codec_bg {
+	status = "ok";
+};
+
+&bg_cdc {
+	status = "ok";
+	vdd-spkr-supply = <&pm660_l11>;
+};
+
+&i2c_1 {
+	status = "okay";
+	nq@28 {
+		compatible = "qcom,nq-nci";
+		reg = <0x28>;
+		qcom,nq-irq = <&msm_gpio 50 0x00>;
+		qcom,nq-ven = <&msm_gpio 36 0x00>;
+		qcom,nq-firm = <&msm_gpio 38 0x00>;
+		qcom,nq-esepwr = <&msm_gpio 49 0x00>;
+		qcom,nq-clkreq = <&pm660_gpios 4 0x00>;
+		qcom,clk-src = "BBCLK3";
+		interrupt-parent = <&msm_gpio>;
+		interrupts = <50 0>;
+		interrupt-names = "nfc_irq";
+		pinctrl-names = "nfc_active","nfc_suspend";
+		pinctrl-0 = <&nfcw_int_active
+			     &nfcw_disable_active
+			     &nfc_clk_default>;
+		pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>;
+		clock-names = "ref_clk";
+	};
+};
+
+&spi_0 {
+	status = "disabled";
+};
+
+&i2c_3 {
+	status = "disabled";
+};
+
+&i2c_4 {
+	status = "disabled";
+};
+
+&i2c_2 {
+	status = "disabled";
+};
+
+&sdhc_2 {
+	status = "disabled";
+};
+
+&blsp1_uart1 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart_console_sleep>;
+};
+
+/* Pinctrl dt nodes for interrupt & reset gpio for Synaptics touch controller */
+&ts_int_active {
+	mux {
+		pins = "gpio98";
+	};
+
+	config {
+		pins = "gpio98";
+	};
+};
+
+&ts_int_suspend {
+	mux {
+		pins = "gpio98";
+	};
+
+	config {
+		pins = "gpio98";
+		/delete-property/ bias-pull-down;
+		bias-disable; /* No PULL */
+	};
+};
+
+&ts_reset_active {
+	mux {
+		pins = "gpio16";
+	};
+
+	config {
+		pins = "gpio16";
+	};
+};
+
+&ts_reset_suspend {
+	mux {
+		pins = "gpio16";
+	};
+
+	config {
+		pins = "gpio16";
+	};
+};
+
+&ts_release {
+	mux {
+		pins = "gpio98", "gpio16";
+	};
+
+	config {
+		pins = "gpio98", "gpio16";
+	};
+};
+
+&spi4_cs0_active {
+	mux {
+		pins = "gpio14";
+		function = "blsp_spi4";
+	};
+	config {
+		pins = "gpio14";
+		drive-strength = <2>;
+		bias-disable; /* No PULL */
+		output-high;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi
new file mode 100644
index 0000000..512b0fb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi
@@ -0,0 +1,411 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+
+&rpm_bus {
+	/* CX supply */
+	rpm-regulator-smpa2 {
+		status = "okay";
+		pm660_s2_corner: regulator-s2-corner {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s2_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+			status = "okay";
+		};
+
+		pm660_s2_corner_ao: regulator-s2-corner-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s2_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+
+		pm660_s2_floor_corner: regulator-s2-floor-corner {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s2_floor_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-floor-corner;
+			qcom,always-send-voltage;
+		};
+
+		pm660_s2_corner_so: regulator-s2-corner-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s2_corner_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,init-voltage = <1>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	/* MX supply */
+	rpm-regulator-smpa3 {
+		status = "okay";
+		pm660_s3_corner: regulator-s3-corner {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s3_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+			status = "okay";
+		};
+
+		pm660_s3_corner_ao: regulator-s3-corner-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s3_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+
+		pm660_s3_corner_so: regulator-s3-corner-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s3_corner_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,init-voltage = <1>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		status = "okay";
+		pm660_s4: regulator-s4 {
+			regulator-min-microvolt = <2040000>;
+			regulator-max-microvolt = <2040000>;
+			qcom,init-voltage = <2040000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-smpa5 {
+		status = "okay";
+		pm660_s5: regulator-s5 {
+			regulator-min-microvolt = <1350000>;
+			regulator-max-microvolt = <1350000>;
+			qcom,init-voltage = <1350000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-smpa6 {
+		status = "okay";
+		pm660_s6: regulator-s6 {
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,init-voltage = <1225000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		status = "okay";
+		pm660_l1: regulator-l1 {
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			qcom,init-voltage = <1000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		status = "okay";
+		pm660_l2: regulator-l2 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		status = "okay";
+		pm660_l3: regulator-l3 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1050000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		status = "okay";
+		pm660_l5: regulator-l5 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		status = "okay";
+		pm660_l6: regulator-l6 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,init-voltage = <1300000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		status = "okay";
+		pm660_l7: regulator-l7 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		status = "okay";
+		pm660_l8: regulator-l8 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		status = "okay";
+		pm660_l9: regulator-l9 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		status = "okay";
+		pm660_l10: regulator-l10 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		status = "okay";
+		pm660_l11: regulator-l11 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		status = "okay";
+		pm660_l12: regulator-l12 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+
+		pm660_l12_ao: regulator-l12-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l12_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		status = "okay";
+		pm660_l13: regulator-l13 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		status = "okay";
+		pm660_l14: regulator-l14 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		status = "okay";
+		pm660_l15: regulator-l15 {
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3300000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		status = "okay";
+		pm660_l16: regulator-l16 {
+			regulator-min-microvolt = <3100000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3100000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		status = "okay";
+		pm660_l17: regulator-l17 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,init-voltage = <2700000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		status = "okay";
+		pm660_l18: regulator-l18 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,init-voltage = <3000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		status = "okay";
+		pm660_l19: regulator-l19 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,init-voltage = <2900000>;
+			status = "okay";
+		};
+	};
+};
+
+/* SPM controlled regulators */
+&spmi_bus {
+	qcom,pm660@1 {
+		pm660_s1: spm-regulator@1400 {
+			compatible = "qcom,spm-regulator";
+			regulator-name = "pm660_s1";
+			reg = <0x1400 0x100>;
+			regulator-min-microvolt = <1052000>;
+			regulator-max-microvolt = <1352000>;
+		};
+	};
+};
+
+/* CPR controlled regulator */
+&soc {
+	mem_acc_vreg_corner: regulator@1942130 {
+		compatible = "qcom,mem-acc-regulator";
+		reg = <0x1942130 0x4>;
+		reg-names = "acc-sel-l1";
+		regulator-name = "mem_acc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <3>;
+
+		qcom,acc-sel-l1-bit-pos = <0>;
+		qcom,corner-acc-map = <0 1 1>;
+	};
+
+	apc_vreg_corner: regulator@b018000 {
+		compatible = "qcom,cpr-regulator";
+		reg = <0xb018000 0x1000>, <0xb011064 4>, <0x58000 0x1000>;
+		reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
+		interrupts = <0 15 0>;
+		regulator-name = "apc_corner";
+		qcom,cpr-fuse-corners = <3>;
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <9>;
+
+		qcom,cpr-voltage-ceiling = <1052000 1228000 1352000>;
+		qcom,cpr-voltage-floor = <1052000 1052000 1156000>;
+		vdd-apc-supply = <&pm660_s1>;
+
+		qcom,vdd-mx-corner-map = <4 5 7>;
+		qcom,vdd-mx-vmin-method = <4>;
+		vdd-mx-supply = <&pm660_s3_corner_ao>;
+		qcom,vdd-mx-vmax = <7>;
+
+		mem-acc-supply = <&mem_acc_vreg_corner>;
+
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <0>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <10>;
+		qcom,cpr-up-threshold = <0>;
+		qcom,cpr-down-threshold = <2>;
+		qcom,cpr-idle-clocks = <15>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <4000>;
+
+		qcom,cpr-fuse-row = <26 0>;
+		qcom,cpr-fuse-target-quot = <42 24 6>;
+		qcom,cpr-fuse-ro-sel = <61 61 54>;
+		qcom,cpr-fuse-bp-cpr-disable = <58>;
+		qcom,cpr-fuse-init-voltage =
+					<26 36 6 0>,
+					<26 18 6 0>,
+					<26 0 6 0>;
+		qcom,cpr-fuse-revision = <26 59 2 0>;
+		qcom,cpr-init-voltage-ref = <1052000 1228000 1352000>;
+		qcom,cpr-init-voltage-step = <10000>;
+		qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3>;
+		qcom,cpr-init-voltage-as-ceiling;
+		qcom,cpr-corner-frequency-map =
+					<1 200000000>,
+					<2 400000000>,
+					<3 533330000>,
+					<4 800000000>,
+					<5 998400000>,
+					<6 1094400000>,
+					<7 1190400000>,
+					<8 1248000000>,
+					<9 1267200000>;
+		qcom,speed-bin-fuse-sel = <1 34 3 0>;
+		qcom,cpr-speed-bin-max-corners =
+					<0 (-1) 2 4 9>,
+					<2 (-1) 2 4 6>;
+		qcom,cpr-quot-adjust-scaling-factor-max = <1400>;
+	};
+
+	bob_vreg: bob_vreg {
+		compatible = "regulator-fixed";
+		regulator-name = "bob_vreg";
+		startup-delay-us = <400>;
+		enable-active-high;
+		gpio = <&pm660_gpios 12 0>;
+		status = "okay";
+		regulator-boot-on;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909w.dtsi b/arch/arm64/boot/dts/qcom/msm8909w.dtsi
new file mode 100644
index 0000000..d35407c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909w.dtsi
@@ -0,0 +1,102 @@
+/* Copyright (c) 2015-2018, 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.
+ */
+
+/ {
+	chosen {
+		bootargs="sched_enable_hmp=0";
+	};
+};
+
+&soc {
+	/delete-node/ qcom,clock-a7@0b011050;
+	clock_cpu: qcom,clock-a7@0b011050 {
+		compatible = "qcom,clock-a53-8916";
+		reg = <0x0b011050 0x8>,
+		      <0x0005c00c 0x8>;
+		reg-names = "rcg-base", "efuse";
+		qcom,safe-freq = < 400000000 >;
+		cpu-vdd-supply = <&apc_vreg_corner>;
+		clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+			 <&clock_gcc clk_a7sspll>;
+		clock-names = "clk-4", "clk-5";
+		qcom,a7ssmux-opp-store-vcorner = <&CPU0>;
+		qcom,speed0-bin-v0 =
+			<          0 0>,
+			<  800000000 4>,
+			< 1267200000 9>;
+
+		qcom,speed2-bin-v0 =
+			<          0 0>,
+			<  800000000 4>,
+			< 1094400000 6>;
+		#clock-cells = <1>;
+	};
+
+	/delete-node/ qcom,msm-cpufreq;
+	qcom,msm-cpufreq {
+		reg = <0 4>;
+		compatible = "qcom,msm-cpufreq";
+		clocks = <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>,
+			 <&clock_cpu  clk_a7ssmux>;
+		clock-names = "cpu0_clk", "cpu1_clk",
+				"cpu2_clk", "cpu3_clk";
+		qcom,cpufreq-table =
+			 <  800000 >,
+			 < 1094400 >,
+			 < 1267200 >;
+	};
+
+	/delete-node/ qcom,cpubw;
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<  732 /*  96 MHz */>,
+			< 1464 /* 192 MHz */>,
+			< 2929 /* 384 MHz */>;
+	};
+
+	/delete-node/ devfreq-cpufreq;
+	devfreq-cpufreq {
+		cpubw-cpufreq {
+			target-dev = <&cpubw>;
+			cpu-to-dev-map =
+				 <  800000  1464>,
+				 < 1094400  2929>,
+				 < 1267200  2929>;
+		};
+	};
+};
+
+&qcom_crypto {
+	qcom,msm-bus,vectors-KBps =
+		<55 512 0 0>,
+		<55 512 393600 393600>; /* 49.2MHz & 49.2MHz */
+};
+
+&qcom_cedev {
+	qcom,msm-bus,vectors-KBps =
+		<55 512 0 0>,
+		<55 512 393600 393600>; /* 49.2MHz & 49.2MHz */
+};
+
+&qcom_seecom {
+	qcom,msm-bus,vectors-KBps =
+		<55 512 0 0>,
+		<55 512 0 0>,
+		<55 512 196800 196800>,
+		<55 512 393600 393600>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
new file mode 100644
index 0000000..792d5d1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+/ {
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu-map {
+
+			cluster0 {
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		CPU0: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x100>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      /* A53 L2 dump not supported */
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_100: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_100: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU1: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x101>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_101: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_101: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU2: cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x102>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_102: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_102: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU3: cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x103>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_103: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_103: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi
new file mode 100644
index 0000000..823d99d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-ion.dtsi
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@8 { /* CP_MM HEAP */
+			reg = <8>;
+			memory-region = <&secure_mem>;
+			qcom,ion-heap-type = "SECURE_DMA";
+		};
+
+		qcom,ion-heap@27 { /* QSEECOM HEAP */
+			reg = <27>;
+			memory-region = <&qseecom_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
new file mode 100644
index 0000000..65bc046
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&blsp1_uart2 {
+	status = "ok";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
new file mode 100644
index 0000000..b8516d5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
@@ -0,0 +1,1669 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8917-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+
+		/* add pingrp for touchscreen */
+		pmx_ts_int_active {
+			ts_int_active: ts_int_active {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_int_suspend {
+			ts_int_suspend: ts_int_suspend {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_reset_active {
+			ts_reset_active: ts_reset_active {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_reset_suspend {
+			ts_reset_suspend: ts_reset_suspend {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_release {
+			ts_release: ts_release {
+				mux {
+					pins = "gpio65", "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+
+		blsp1_uart1 {
+			blsp1_uart1_active: blsp1_uart1_active {
+				mux {
+					pins = "gpio0", "gpio1",
+						"gpio2", "gpio3";
+					function = "blsp_uart1";
+				};
+
+				config {
+					pins = "gpio0", "gpio1",
+						"gpio2", "gpio3";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			blsp1_uart1_sleep: blsp1_uart1_sleep {
+				mux {
+					pins = "gpio0", "gpio1",
+						"gpio2", "gpio3";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio0", "gpio1",
+						"gpio2", "gpio3";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		wcnss_pmux_5wire {
+			/* Active configuration of bus pins */
+			wcnss_default: wcnss_default {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+
+			wcnss_sleep: wcnss_sleep {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins =  "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+		};
+
+		wcnss_pmux_gpio: wcnss_pmux_gpio {
+			wcnss_gpio_default: wcnss_gpio_default {
+				/* Active configuration of bus pins */
+				mux {
+					/* Uses general purpose pins */
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+		};
+
+		pmx_mdss: pmx_mdss {
+			mdss_dsi_active: mdss_dsi_active {
+				mux {
+					pins = "gpio60", "gpio98";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98";
+					drive-strength = <8>; /* 8 mA */
+					bias-disable = <0>; /* no pull */
+					output-high;
+				};
+			};
+			mdss_dsi_suspend: mdss_dsi_suspend {
+				mux {
+					pins = "gpio60", "gpio98";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		pmx_mdss_te {
+			mdss_te_active: mdss_te_active {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 8 mA */
+					bias-pull-down; /* pull down*/
+				};
+			};
+			mdss_te_suspend: mdss_te_suspend {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		pmx_qdsd_clk {
+			qdsd_clk_sdcard: clk_sdcard {
+				config {
+					pins = "qdsd_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+			qdsd_clk_trace: clk_trace {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_swdtrc: clk_swdtrc {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_spmi: clk_spmi {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_cmd {
+			qdsd_cmd_sdcard: cmd_sdcard {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_trace: cmd_trace {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swduart: cmd_uart {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swdtrc: cmd_swdtrc {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_jtag: cmd_jtag {
+				config {
+					pins = "qdsd_cmd";
+					bias-disable; /* NO pull */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_spmi: cmd_spmi {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data0 {
+			qdsd_data0_sdcard: data0_sdcard {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_trace: data0_trace {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_swduart: data0_uart {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_swdtrc: data0_swdtrc {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_jtag: data0_jtag {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_spmi: data0_spmi {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		 pmx_qdsd_data1 {
+			qdsd_data1_sdcard: data1_sdcard {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_trace: data1_trace {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_swduart: data1_uart {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_swdtrc: data1_swdtrc {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_jtag: data1_jtag {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data2 {
+			qdsd_data2_sdcard: data2_sdcard {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_trace: data2_trace {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_swduart: data2_uart {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_swdtrc: data2_swdtrc {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_jtag: data2_jtag {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-up; /* pull up */
+					drive-strength = <8>; /* 8 MA */
+				};
+			 };
+		};
+
+		pmx_qdsd_data3 {
+			qdsd_data3_sdcard: data3_sdcard {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_trace: data3_trace {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_swduart: data3_uart {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_swdtrc: data3_swdtrc {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_jtag: data3_jtag {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_spmi: data3_spmi {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_rclk {
+			sdc1_rclk_on: sdc1_rclk_on {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+
+			sdc1_rclk_off: sdc1_rclk_off {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		pmx_sdc1_clk {
+			sdc1_clk_on: sdc1_clk_on {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc1_clk_off: sdc1_clk_off {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_cmd {
+			sdc1_cmd_on: sdc1_cmd_on {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_cmd_off: sdc1_cmd_off {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_data {
+			sdc1_data_on: sdc1_data_on {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_data_off: sdc1_data_off {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		sdhc2_cd_pin {
+			sdc2_cd_on: cd_on {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			sdc2_cd_off: cd_off {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_sdc2_clk {
+			sdc2_clk_on: sdc2_clk_on {
+				config {
+					pins = "sdc2_clk";
+					drive-strength = <16>; /* 16 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			sdc2_clk_off: sdc2_clk_off {
+				config {
+					pins = "sdc2_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_cmd {
+			sdc2_cmd_on: sdc2_cmd_on {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc2_cmd_off: sdc2_cmd_off {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_data {
+			sdc2_data_on: sdc2_data_on {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc2_data_off: sdc2_data_off {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			 };
+		};
+
+		sdc2_wlan_gpio {
+			sdc2_wlan_gpio_active: sdc2_wlan_gpio_active {
+				config {
+					pins = "gpio99";
+					output-high;
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+			sdc2_wlan_gpio_sleep: sdc2_wlan_gpio_sleep {
+				config {
+					pins = "gpio99";
+					output-low;
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		wcd9xxx_intr {
+			wcd_intr_default: wcd_intr_default{
+				mux {
+					pins = "gpio73";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio73";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					input-enable;
+				};
+			};
+		};
+
+		pri_mi2s_mclk_b_lines {
+			pri_mi2s_mclk_b_default: pri_mi2s_mclk_default {
+				mux {
+					pins = "gpio69";
+					function = "pri_mi2s_mclk_b";
+				};
+				config {
+					pins = "gpio69";
+					drive-strength = <8>;
+					bias-disable;
+					input-enable;
+				};
+			};
+		};
+
+		sec_mi2s_mclk_a_lines {
+			sec_mi2s_mclk_a_active: sec_mi2s_mclk_a_active {
+				mux {
+					pins = "gpio25";
+					function = "sec_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <8>; /* 8 MA */
+					output-high;
+					bias-disable;
+				};
+			};
+
+			sec_mi2s_mclk_a_sleep: sec_mi2s_mclk_a_sleep {
+				mux {
+					pins = "gpio25";
+					function = "sec_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+					bias-pull-down;
+				};
+			};
+		};
+
+		cdc_reset_ctrl {
+			cdc_reset_sleep: cdc_reset_sleep {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-disable;
+					output-low;
+				};
+			};
+			cdc_reset_active:cdc_reset_active {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		cdc-pdm-2-lines {
+			cdc_pdm_lines_2_act: pdm_lines_2_on {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <8>;
+				};
+			};
+
+			cdc_pdm_lines_2_sus: pdm_lines_2_off {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cdc-pdm-lines {
+			cdc_pdm_lines_act: pdm_lines_on {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <8>;
+				};
+			};
+			cdc_pdm_lines_sus: pdm_lines_off {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cross-conn-det {
+			cross_conn_det_act: lines_on {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <8>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+
+			cross_conn_det_sus: lines_off {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA VI sense */
+		wsa-vi {
+			wsa_vi_on: wsa_vi_on {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <8>; /* 8 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			wsa_vi_off: wsa_vi_off {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA Reset */
+		wsa_reset {
+			wsa_reset_on: wsa_reset_on {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-high;
+				};
+			};
+
+			wsa_reset_off: wsa_reset_off {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+				};
+			};
+		};
+
+		/* WSA CLK */
+		wsa_clk {
+			wsa_clk_on: wsa_clk_on {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <8>; /* 8 MA */
+					output-high;
+				};
+			};
+
+			wsa_clk_off: wsa_clk_off {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pri-tlmm-lines {
+			pri_tlmm_lines_act: pri_tlmm_lines_act {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <8>;
+				};
+			};
+
+			pri_tlmm_lines_sus: pri_tlmm_lines_sus {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pri-tlmm-ws-lines {
+			pri_tlmm_ws_act: pri_tlmm_ws_act {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <16>;
+					bias-disable;
+					output-high;
+				};
+			};
+
+			pri_tlmm_ws_sus: pri_tlmm_ws_sus {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <2>;
+					bias-pull-down;
+					input-enable;
+				};
+			};
+		};
+
+		spi3 {
+			spi3_default: spi3_default {
+			/* active state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable = <0>; /* No PULL */
+				};
+			};
+
+			spi3_sleep: spi3_sleep {
+				/* suspended state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+
+			spi3_cs0_active: cs0_active {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi3_cs0_sleep: cs0_sleep {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+		};
+
+		spi6 {
+			spi6_default: spi6_default {
+				/* active state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio20", "gpio21", "gpio23";
+					function = "blsp_spi6";
+				};
+
+				config {
+					pins = "gpio20", "gpio21", "gpio23";
+					drive-strength = <16>; /* 16 MA */
+					bias-disable = <0>; /* No PULL */
+				};
+			};
+
+			spi6_sleep: spi6_sleep {
+				/* suspended state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio20", "gpio21", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio20", "gpio21", "gpio23";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+
+			spi6_cs0_active: cs0_active {
+				/* CS */
+				mux {
+					pins = "gpio47";
+					function = "blsp6_spi";
+				};
+
+				config {
+					pins = "gpio47";
+					drive-strength = <16>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi6_cs0_sleep: cs0_sleep {
+				/* CS */
+				mux {
+					pins = "gpio47";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio47";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi6_cs1_active: cs1_active {
+				/* CS */
+				mux {
+					pins = "gpio22";
+					function = "blsp_spi6";
+				};
+
+				config {
+					pins = "gpio22";
+					drive-strength = <16>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi6_cs1_sleep: cs1_sleep {
+				/* CS */
+				mux {
+					pins = "gpio22";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+		};
+
+		i2c_2 {
+			i2c_2_active: i2c_2_active {
+				/* active state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "blsp_i2c2";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_2_sleep: i2c_2_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_3 {
+			i2c_3_active: i2c_3_active {
+				/* active state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "blsp_i2c3";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_3_sleep: i2c_3_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* IO Expander SX150xq */
+		i2c_4 {
+			i2c_4_active: i2c_4_active {
+				/* active state */
+				mux {
+					pins = "gpio14", "gpio15";
+					function = "blsp_i2c4";
+				};
+
+				config {
+					pins = "gpio14", "gpio15";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_4_sleep: i2c_4_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio14", "gpio15";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio14", "gpio15";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_5 {
+			i2c_5_active: i2c_5_active {
+				/* active state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "blsp_i2c5";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_5_sleep: i2c_5_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_6 {
+			i2c_6_active: i2c_6_active {
+				/* active state */
+				mux {
+					pins = "gpio22", "gpio23";
+					function = "blsp_i2c6";
+				};
+
+				config {
+					pins = "gpio22", "gpio23";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_6_sleep: i2c_6_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio22", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22", "gpio23";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_rd_nfc_int {
+			/*qcom,pins = <&gp 17>;*/
+			pins = "gpio17";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_int";
+
+			nfc_int_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_int_suspend: suspend {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+		};
+
+		pmx_nfc_reset {
+			/*qcom,pins = <&gp 16>;*/
+			pins = "gpio16";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_disable";
+
+			nfc_disable_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_disable_suspend: suspend {
+				drive-strength = <6>;
+				bias-disable;
+			};
+		};
+
+		tlmm_gpio_key {
+			gpio_key_active: gpio_key_active {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			gpio_key_suspend: gpio_key_suspend {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		tlmm_pmi_flash_led {
+			rear_flash_led_enable: rear_flash_led_enable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			rear_flash_led_disable: rear_flash_led_disable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+
+			front_flash_led_enable: front_flash_led_enable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			front_flash_led_disable: front_flash_led_disable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+		};
+
+		usbc_int_default: usbc_int_default {
+			mux {
+				pins = "gpio97", "gpio131";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio97", "gpio131";
+				drive-strength = <2>;
+				bias-pull-up;
+			};
+		};
+
+		pri_mi2s_sck {
+			pri_mi2s_sck_sleep: pri_mi2s_sck_sleep {
+				mux {
+					pins = "gpio85";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+					input-enable;
+				};
+			};
+
+			pri_mi2s_sck_active: pri_mi2s_sck_active {
+				mux {
+					pins = "gpio85";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+					output-high;
+				};
+			};
+		};
+
+		pri_mi2s_sd0 {
+			pri_mi2s_sd0_sleep: pri_mi2s_sd0_sleep {
+				mux {
+					pins = "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio88";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+					input-enable;
+				};
+			};
+
+			pri_mi2s_sd0_active: pri_mi2s_sd0_active {
+				mux {
+					pins = "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio88";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+				};
+			};
+		};
+
+		pri_mi2s_sd1 {
+			pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep {
+				mux {
+					pins = "gpio86";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio86";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+					input-enable;
+				};
+			};
+			pri_mi2s_sd1_active: pri_mi2s_sd1_active {
+				mux {
+					pins = "gpio86";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio86";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+					output-high;
+				};
+			};
+		};
+		sec_mi2s_ws {
+			sec_mi2s_ws_sleep: sec_mi2s_ws_sleep {
+				mux {
+					pins = "gpio95";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio95";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+				};
+			};
+			sec_mi2s_ws_active: sec_mi2s_ws_active {
+				mux {
+					pins = "gpio95";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio95";
+					drive-strength = <16>;
+					bias-disable;
+					output-high;
+				};
+			};
+		};
+		sec_mi2s_sck {
+			sec_mi2s_sck_sleep: sec_mi2s_sck_sleep {
+				mux {
+					pins = "gpio94";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio94";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+				};
+			};
+			sec_mi2s_sck_active: sec_mi2s_sck_active {
+				mux {
+					pins = "gpio94";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio94";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+					output-high;
+				};
+			};
+		};
+
+		sec_mi2s_sd0 {
+			sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep {
+				mux {
+					pins = "gpio12";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+					input-enable;
+				};
+			};
+			sec_mi2s_sd0_active: sec_mi2s_sd0_active {
+				mux {
+					pins = "gpio12";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio12";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+					output-high;
+				};
+			};
+		};
+
+		sec_mi2s_sd1 {
+			sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep {
+				mux {
+					pins = "gpio13";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio13";
+					drive-strength = <2>;   /* 2 mA */
+					bias-pull-down;         /* PULL DOWN */
+					input-enable;
+				};
+			};
+			sec_mi2s_sd1_active: sec_mi2s_sd1_active {
+				mux {
+					pins = "gpio13";
+					function = "sec_mi2s";
+				};
+
+				config {
+					pins = "gpio13";
+					drive-strength = <16>;   /* 16 mA */
+					bias-disable;           /* NO PULL */
+				};
+			};
+		};
+
+		usb_mode_select: usb_mode_select {
+			mux {
+				pins = "gpio130";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio130";
+				drive-strength = <2>;
+				bias-disable;
+				input-enable;
+			};
+		};
+
+		usb2533_hub_reset: usb2533_hub_reset {
+			mux {
+				pins = "gpio100";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio100";
+				drive-strength = <2>;
+				output-low;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
new file mode 100644
index 0000000..3fe60a3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-pmi8950-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP";
+	compatible = "qcom,msm8917-mtp", "qcom,msm8917", "qcom,mtp";
+	qcom,board-id= <8 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi
new file mode 100644
index 0000000..a78f5fe
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dtsi
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "pmi8950.dtsi"
+#include "msm8917-mtp.dtsi"
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+		qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+		qcom,switch-source = <&pmi8950_switch>;
+	};
+
+	bluetooth: bt_qca6174 {
+		compatible = "qca,qca6174";
+		qca,bt-reset-gpio = <&tlmm 129 0>; /* BT_EN */
+	};
+};
+
+&vendor{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&pm8937_gpios {
+	gpio@c400 {
+		qcom,mode = <0>;
+		qcom,output-type = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <0>;
+		qcom,master-en = <1>;
+		status = "okay";
+	};
+};
+
+&pmi8950_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pmi8950_charger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+	/delete-property/ dpdm-supply;
+};
+
+&labibb {
+	status = "ok";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+	qcom,qpnp-ibb-discharge-resistor = <32>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi
new file mode 100644
index 0000000..c1160ad
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "skeleton64.dtsi"
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917";
+	compatible = "qcom,msm8917";
+	qcom,msm-id = <303 0x0>, <308 0x0>, <309 0x0>;
+	interrupt-parent = <&intc>;
+
+	chosen {
+		bootargs = "sched_enable_hmp=1";
+	};
+
+	aliases {
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd4 = &smdtty_mbalbridge;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd8 = &smdtty_data4;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd36 = &smdtty_loopback;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		other_ext_mem: other_ext_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x85b00000 0x0 0xd00000>;
+		};
+
+		modem_mem: modem_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x86800000 0x0 0x5000000>;
+		};
+
+		adsp_fw_mem: adsp_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8b800000 0x0 0x1100000>;
+		};
+
+		wcnss_fw_mem: wcnss_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8c900000 0x0 0x700000>;
+		};
+
+		venus_mem: venus_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+			alignment = <0 0x400000>;
+			size = <0 0x0800000>;
+		};
+
+		secure_mem: secure_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x7000000>;
+		};
+
+		qseecom_mem: qseecom_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x1000000>;
+		};
+
+		adsp_mem: adsp_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
+		cont_splash_mem: splash_region@83000000 {
+			reg = <0x0 0x90000000 0x0 0x1400000>;
+		};
+	};
+
+	soc: soc { };
+
+	vendor: vendor {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0xffffffff>;
+		compatible = "simple-bus";
+	};
+};
+
+#include "msm8917-pinctrl.dtsi"
+#include "msm8917-cpu.dtsi"
+#include "msm8917-ion.dtsi"
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0 0 0xffffffff>;
+	compatible = "simple-bus";
+
+	intc: interrupt-controller@b000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0x0b000000 0x1000>,
+		      <0x0b002000 0x1000>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 2 0xff08>,
+			     <1 3 0xff08>,
+			     <1 4 0xff08>,
+			     <1 1 0xff08>;
+		clock-frequency = <19200000>;
+	};
+
+	qcom,sps {
+		compatible = "qcom,msm_sps_4k";
+		qcom,pipe-attr-ee;
+	};
+
+	timer@b120000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xb120000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@b121000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xb121000 0x1000>,
+			      <0xb122000 0x1000>;
+		};
+
+		frame@b123000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xb123000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b124000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xb124000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b125000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xb125000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b126000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xb126000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b127000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xb127000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b128000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xb128000 0x1000>;
+			status = "disabled";
+		};
+	};
+
+	qcom,rmtfs_sharedmem@00000000 {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x00000000 0x00180000>;
+		reg-names = "rmtfs";
+		qcom,client-id = <0x00000001>;
+	};
+
+	restart@4ab000 {
+		compatible = "qcom,pshold";
+		reg = <0x4ab000 0x4>,
+			<0x193d100 0x4>;
+		reg-names = "pshold-base", "tcsr-boot-misc-detect";
+	};
+
+	qcom,mpm2-sleep-counter@4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0x4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
+	cpu-pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <1 7 0xff00>;
+	};
+
+	slim_msm: slim@c140000{
+		cell-index = <1>;
+		compatible = "qcom,slim-ngd";
+		reg = <0xc140000 0x2c000>,
+		      <0xc104000 0x2a000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0>, <0 180 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,apps-ch-pipes = <0x600000>;
+		qcom,ea-pc = <0x230>;
+		status = "disabled";
+	};
+
+	blsp1_uart2: serial@78b0000 {
+		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+		reg = <0x78b0000 0x200>;
+		interrupts = <0 108 0>;
+		status = "disabled";
+	};
+
+	dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7884000 0x1f000>;
+		interrupts = <0 238 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	dma_blsp2: qcom,sps-dma@7ac4000 { /* BLSP2 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7ac4000 0x1f000>;
+		interrupts = <0 239 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2270 /*  297.6 MHz */ >,	/*SVS */
+			<  2929 /*  384   MHz */ >,
+			<  4248 /*  556.8 MHz */ >,	/*SVS+*/
+			<  4541 /*  595.2 MHz */ >,	/*NOM*/
+			<  5126 /*  672   MHz */ >,	/*NOM+*/
+			<  5645 /*  740   MHz */ >;	/*TURBO*/
+	};
+
+	mincpubw: qcom,mincpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2270 /*  297.6 MHz */ >,
+			<  2929 /*  384   MHz */ >,
+			<  4248 /*  556.8 MHz */ >,
+			<  4541 /*  595.2 MHz */ >,
+			<  5126 /*  672   MHz */ >,
+			<  5645 /*  740   MHz */ >;
+	};
+
+	qcom,cpu-bwmon {
+		compatible = "qcom,bimc-bwmon2";
+		reg = <0x408000 0x300>, <0x401000 0x200>;
+		reg-names = "base", "global_base";
+		interrupts = <0 183 4>;
+		qcom,mport = <0>;
+		qcom,target-dev = <&cpubw>;
+	};
+
+	qcom,wdt@b017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xb017000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping;
+		qcom,wakeup-enable;
+	};
+
+	spmi_bus: qcom,spmi@200f000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0x200f000 0x1000>,
+			<0x2400000 0x800000>,
+			<0x2c00000 0x800000>,
+			<0x3800000 0x200000>,
+			<0x200a000 0x2100>;
+		reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+		interrupt-names = "periph_irq";
+		interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+		qcom,ee = <0>;
+		qcom,channel = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-controller;
+		#interrupt-cells = <4>;
+		cell-index = <0>;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+	};
+
+	qcom,msm-imem@8600000 {
+		compatible = "qcom,msm-imem";
+		reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+		ranges = <0x0 0x08600000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		mem_dump_table@10 {
+			compatible = "qcom,msm-imem-mem_dump_table";
+			reg = <0x10 8>;
+		};
+
+		dload_type@18 {
+			compatible = "qcom,msm-imem-dload-type";
+			reg = <0x18 4>;
+		};
+
+		restart_reason@65c {
+			compatible = "qcom,msm-imem-restart_reason";
+			reg = <0x65c 4>;
+		};
+
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+
+		pil@94c {
+			compatible = "qcom,msm-imem-pil";
+			reg = <0x94c 200>;
+		};
+
+	};
+
+
+	qcom,ipc-spinlock@1905000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0x1905000 0x8000>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@86300000 {
+		compatible = "qcom,smem";
+		reg = <0x86300000 0x100000>,
+			<0xb011008 0x4>,
+			<0x60000 0x8000>,
+			<0x193d000 0x8>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1",
+				"smem_targ_info_reg";
+		qcom,mpu-enabled;
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			interrupts = <0 25 1>;
+			label = "modem";
+			qcom,not-loadable;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			interrupts = <0 142 1>;
+			label = "wcnss";
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x100>;
+			interrupts = <0 289 1>;
+			label = "adsp";
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 290 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			label = "rpm";
+			qcom,irq-no-suspend;
+			qcom,not-loadable;
+		};
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "MBALBRIDGE";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data4: qcom,smdtty-data4 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA4";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
+	qcom,smdpkt {
+		compatible = "qcom,smdpkt";
+
+		qcom,smdpkt-data5-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA5_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl0";
+		};
+
+		qcom,smdpkt-data22 {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA22";
+			qcom,smdpkt-dev-name = "smd22";
+		};
+
+		qcom,smdpkt-data40-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA40_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl8";
+		};
+
+		qcom,smdpkt-apr-apps2 {
+			qcom,smdpkt-remote = "adsp";
+			qcom,smdpkt-port-name = "apr_apps2";
+			qcom,smdpkt-dev-name = "apr_apps2";
+		};
+
+		qcom,smdpkt-loopback {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "LOOPBACK";
+			qcom,smdpkt-dev-name = "smd_pkt_loopback";
+		};
+	};
+
+	qcom_tzlog: tz-log@8600720 {
+		compatible = "qcom,tz-log";
+		reg = <0x08600720 0x2000>;
+	};
+
+	qcom,ipc_router {
+		compatible = "qcom,ipc_router";
+		qcom,node-id = <1>;
+	};
+
+	qcom,ipc_router_modem_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "modem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+		qcom,disable-pil-loading;
+	};
+
+	qcom,ipc_router_q6_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "adsp";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,ipc_router_wcnss_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "wcnss";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
+};
+
+#include "pm8937-rpm-regulator.dtsi"
+#include "pm8937.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
new file mode 100644
index 0000000..2e4d38e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm-audio-lpass.dtsi"
+#include "msm8953-wsa881x.dtsi"
+
+&msm_audio_ion {
+	iommus = <&apps_iommu 0x2001 0x0>;
+	qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
+		};
+	};
+
+	qcom,avtimer@c0a300c {
+		compatible = "qcom,avtimer";
+		reg = <0x0c0a300c 0x4>,
+			<0x0c0a3010 0x4>;
+		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+		qcom,clk-div = <27>;
+	};
+
+	int_codec: sound {
+		status = "okay";
+		compatible = "qcom,msm8952-audio-codec";
+		qcom,model = "msm8952-snd-card-mtp";
+		reg = <0xc051000 0x4>,
+			<0xc051004 0x4>,
+			<0xc055000 0x4>,
+			<0xc052000 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			"csr_gp_io_mux_spkr_ctl",
+			"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			"csr_gp_io_mux_quin_ctl";
+
+		qcom,msm-ext-pa = "primary";
+		qcom,msm-mclk-freq = <9600000>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,msm-hs-micbias-type = "external";
+		qcom,msm-micbias1-ext-cap;
+
+		qcom,audio-routing =
+				"RX_BIAS", "MCLK",
+				"SPK_RX_BIAS", "MCLK",
+				"INT_LDO_H", "MCLK",
+				"RX_I2S_CLK", "MCLK",
+				"TX_I2S_CLK", "MCLK",
+				"MIC BIAS External", "Handset Mic",
+				"MIC BIAS External2", "Headset Mic",
+				"MIC BIAS External", "Secondary Mic",
+				"AMIC1", "MIC BIAS External",
+				"AMIC2", "MIC BIAS External2",
+				"AMIC3", "MIC BIAS External",
+				"ADC1_IN", "ADC1_OUT",
+				"ADC2_IN", "ADC2_OUT",
+				"ADC3_IN", "ADC3_OUT",
+				"PDM_IN_RX1", "PDM_OUT_RX1",
+				"PDM_IN_RX2", "PDM_OUT_RX2",
+				"PDM_IN_RX3", "PDM_OUT_RX3",
+				"WSA_SPK OUT", "VDD_WSA_SWITCH",
+				"SpkrMono WSA_IN", "WSA_SPK OUT";
+
+		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+		qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+		qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>;
+		qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&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-pcm-dsp-noirq";
+		asoc-cpu = <&dai_pri_auxpcm>,
+			<&dai_mi2s0>, <&dai_mi2s1>,
+			<&dai_mi2s2>, <&dai_mi2s3>,
+			<&dai_mi2s4>, <&dai_mi2s5>,
+			<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+			<&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+			<&bt_sco_rx>, <&bt_sco_tx>,
+			<&int_fm_rx>, <&int_fm_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>;
+
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"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-mi2s.6",
+				"msm-dai-q6-dev.16384", "msmdai-q6-dev.16385",
+				"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+				"msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+				"msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+				"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+				"msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+				"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";
+
+		asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+				<&pmic_analog_codec>;
+		asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+					"analog-codec";
+		asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+		asoc-wsa-codec-prefixes = "SpkrMono";
+		msm-vdd-wsa-switch-supply = <&pm8937_l5>;
+		qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+		qcom,msm-vdd-wsa-switch-current = <10000>;
+	};
+
+	cdc_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cross_conn_det_act>;
+		pinctrl-1 = <&cross_conn_det_sus>;
+	};
+
+	cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act>;
+		pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus>;
+	};
+
+	cdc_quin_mi2s_gpios: msm_cdc_pinctrl_quin {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&pri_tlmm_lines_act &pri_tlmm_ws_act>;
+		pinctrl-1 = <&pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+	};
+
+
+	i2c@78b6000 {
+		status = "okay";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		wsa881x_i2c_f: wsa881x-i2c-codec@f {
+			status = "okay";
+			compatible = "qcom,wsa881x-i2c-codec";
+			reg = <0x0f>;
+			qcom,wsa-analog-vi-gpio = <&wsa881x_analog_vi_gpio>;
+			qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>;
+			qcom,wsa-analog-reset-gpio =
+				<&wsa881x_analog_reset_gpio>;
+		};
+		wsa881x_i2c_45: wsa881x-i2c-codec@45 {
+			status = "okay";
+			compatible = "qcom,wsa881x-i2c-codec";
+			reg = <0x45>;
+		};
+	};
+
+	wsa881x_analog_vi_gpio: wsa881x_analog_vi_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_vi_on>;
+		pinctrl-1 = <&wsa_vi_off>;
+	};
+	wsa881x_analog_clk_gpio: wsa881x_analog_clk_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_clk_on>;
+		pinctrl-1 = <&wsa_clk_off>;
+	};
+	wsa881x_analog_reset_gpio: wsa881x_analog_reset_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_reset_on>;
+		pinctrl-1 = <&wsa_reset_off>;
+	};
+
+	ext_codec: sound-9335 {
+		status = "disabled";
+		compatible = "qcom,msm8952-audio-slim-codec";
+		qcom,model = "msm8952-tasha-snd-card";
+
+		reg = <0xc051000 0x4>,
+			<0xc051004 0x4>,
+			<0xc055000 0x4>,
+			<0xc052000 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			"csr_gp_io_mux_spkr_ctl",
+			"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			"csr_gp_io_mux_quin_ctl";
+
+		qcom,audio-routing =
+			"AIF4 VI", "MCLK",
+			"AIF4 VI", "MICBIAS_REGULATOR",
+			"RX_BIAS", "MCLK",
+			"MADINPUT", "MCLK",
+			"AIF4 MAD", "MICBIAS_REGULATOR",
+			"AMIC2", "MIC BIAS2",
+			"MIC BIAS2", "Headset Mic",
+			"AMIC3", "MIC BIAS2",
+			"MIC BIAS2", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2",
+			"MIC BIAS2", "ANCLeft Headset Mic",
+			"AMIC5", "MIC BIAS3",
+			"MIC BIAS3", "Handset Mic",
+			"AMIC6", "MIC BIAS4",
+			"MIC BIAS4", "Analog Mic6",
+			"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",
+			"MIC BIAS1", "MICBIAS_REGULATOR",
+			"MIC BIAS2", "MICBIAS_REGULATOR",
+			"MIC BIAS3", "MICBIAS_REGULATOR",
+			"MIC BIAS4", "MICBIAS_REGULATOR",
+			"SpkrLeft IN", "SPK1 OUT",
+			"SpkrRight IN", "SPK2 OUT";
+
+		qcom,tasha-mclk-clk-freq = <9600000>;
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>;
+		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";
+
+		asoc-cpu = <&dai_pri_auxpcm>,
+				<&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+				<&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>, <&bt_sco_rx>, <&bt_sco_tx>,
+				<&int_fm_rx>, <&int_fm_tx>, <&sb_6_rx>;
+
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.5", "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.12288",
+				"msm-dai-q6-dev.12289", "msm-dai-q6-dev.12292",
+				"msm-dai-q6-dev.12293", "msm-dai-q6-dev.16396";
+
+		asoc-codec = <&stub_codec>, <&hdmi_dba>;
+		asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
+		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+
+		qcom,wsa-max-devs = <2>;
+		qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+				<&wsa881x_213>, <&wsa881x_214>;
+		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+				"SpkrLeft", "SpkrRight";
+	};
+
+	wcd9xxx_intc: wcd9xxx-irq {
+		status = "disabled";
+		interrupt-parent = <&tlmm>;
+		interrupts = <73 0>;
+		qcom,gpio-connect = <&tlmm 73 0>;
+	};
+
+	clock_audio: audio_ext_clk {
+		status = "disabled";
+		compatible = "qcom,audio-ref-clk";
+		clock-names = "osr_clk";
+		qcom,node_has_rpm_clock;
+		#clock-cells = <1>;
+		qcom,audio-ref-clk-gpio = <&pm8937_gpios 1 0>;
+		qcom,lpass-mclk-id = "pri_mclk";
+		clocks = <&clock_gcc clk_div_clk2>;
+		pinctrl-0 = <&cdc_mclk2_sleep>;
+		pinctrl-1 = <&cdc_mclk2_active>;
+	};
+
+	wcd_rst_gpio: wcd_gpio_ctrl {
+		status = "disabled";
+		qcom,cdc-rst-n-gpio = <&tlmm 68 0>;
+	};
+};
+
+&slim_msm {
+	status = "disabled";
+	wcd9335: tasha_codec {
+		status = "disabled";
+		compatible = "qcom,tasha-slim-pgd";
+		clock-names = "wcd_clk", "wcd_native_clk";
+		clocks = <&clock_audio clk_audio_pmi_clk>,
+			<&clock_audio clk_audio_ap_clk2>;
+
+		qcom,cdc-reset-gpio = <&tlmm 68 0>;
+
+		cdc-vdd-buck-supply = <&eldo2_pm8937>;
+		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-buck-current = <650000>;
+
+		cdc-buck-sido-supply = <&eldo2_pm8937>;
+		qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+		qcom,cdc-buck-sido-current = <250000>;
+
+		cdc-vdd-tx-h-supply = <&pm8937_l5>;
+		qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-tx-h-current = <25000>;
+
+		cdc-vdd-rx-h-supply = <&pm8937_l5>;
+		qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-rx-h-current = <25000>;
+
+		cdc-vdd-px-supply = <&pm8937_l5>;
+		qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-px-current = <10000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8937_l13>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+		qcom,cdc-vdd-mic-bias-current = <15000>;
+	};
+};
+
+&pm8937_gpios {
+	gpio@c000 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+};
+
+&pm8937_1 {
+	pmic_analog_codec: analog-codec@f000 {
+		status = "okay";
+		compatible = "qcom,pmic-analog-codec";
+		reg = <0xf000 0x200>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+		interrupt-parent = <&spmi_bus>;
+		interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+		interrupt-names = "spk_cnp_int",
+				"spk_clip_int",
+				"spk_ocp_int",
+				"ins_rem_det1",
+				"but_rel_det",
+				"but_press_det",
+				"ins_rem_det",
+				"mbhc_int",
+				"ear_ocp_int",
+				"hphr_ocp_int",
+				"hphl_ocp_det",
+				"ear_cnp_int",
+				"hphr_cnp_int",
+				"hphl_cnp_int";
+
+		cdc-vdda-cp-supply = <&pm8937_s4>;
+		qcom,cdc-vdda-cp-voltage = <2050000 2050000>;
+		qcom,cdc-vdda-cp-current = <210000>;
+
+		cdc-vdd-io-supply = <&pm8937_l5>;
+		qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-io-current = <5000>;
+
+		cdc-vdd-pa-supply = <&pm8937_s4>;
+		qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+		qcom,cdc-vdd-pa-current = <260000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8937_l13>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+		qcom,cdc-vdd-mic-bias-current = <5000>;
+
+		qcom,cdc-mclk-clk-rate = <9600000>;
+
+		qcom,cdc-static-supplies = "cdc-vdd-io",
+					"cdc-vdd-pa",
+					"cdc-vdda-cp";
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+		msm_digital_codec: msm-dig-codec {
+			compatible = "qcom,msm-digital-codec";
+			reg = <0xc0f0000 0x0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi
new file mode 100644
index 0000000..89bfc73
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-bus.dtsi
@@ -0,0 +1,986 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+		/*Version = 11 */
+	ad_hoc_bus: ad-hoc-bus@580000 {
+		compatible = "qcom,msm-bus-device";
+		reg = <0x580000 0x16080>,
+			<0x580000 0x16080>,
+			<0x400000 0x5A000>,
+			<0x500000 0x13080>;
+		reg-names = "snoc-base", "snoc-mm-base",
+			    "bimc-base", "pcnoc-base";
+
+		/*Buses*/
+		fab_bimc: fab-bimc {
+			cell-id = <MSM_BUS_FAB_BIMC>;
+			label = "fab-bimc";
+			qcom,fab-dev;
+			qcom,base-name = "bimc-base";
+			qcom,bus-type = <2>;
+			qcom,util-fact = <154>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_gcc  clk_bimc_msmbus_clk>,
+				<&clock_gcc  clk_bimc_msmbus_a_clk>;
+		};
+
+		fab_pcnoc: fab-pcnoc {
+			cell-id = <MSM_BUS_FAB_PERIPH_NOC>;
+			label = "fab-pcnoc";
+			qcom,fab-dev;
+			qcom,base-name = "pcnoc-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-off = <0x1000>;
+			qcom,bus-type = <1>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_gcc  clk_pnoc_msmbus_clk>,
+				<&clock_gcc  clk_pnoc_msmbus_a_clk>;
+		};
+
+		fab_snoc: fab-snoc {
+			cell-id = <MSM_BUS_FAB_SYS_NOC>;
+			label = "fab-snoc";
+			qcom,fab-dev;
+			qcom,base-name = "snoc-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-off = <0x1000>;
+			qcom,bus-type = <1>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_gcc  clk_snoc_msmbus_clk>,
+				<&clock_gcc  clk_snoc_msmbus_a_clk>;
+		};
+
+		fab_snoc_mm: fab-snoc-mm {
+			cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+			label = "fab-snoc-mm";
+			qcom,fab-dev;
+			qcom,base-name = "snoc-mm-base";
+			qcom,base-offset = <0x7000>;
+			qcom,qos-off = <0x1000>;
+			qcom,bus-type = <1>;
+			qcom,util-fact = <154>;
+			clock-names = "bus_clk", "bus_a_clk";
+			clocks = <&clock_gcc  clk_sysmmnoc_msmbus_clk>,
+				<&clock_gcc  clk_sysmmnoc_msmbus_a_clk>;
+		};
+
+		/*BIMC Masters*/
+		mas_apps_proc: mas-apps-proc {
+			cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+			label = "mas-apps-proc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <0>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+			qcom,prio-lvl = <0>;
+			qcom,prio-rd = <0>;
+			qcom,prio-wr = <0>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_APPSS_PROC>;
+		};
+
+		mas_oxili: mas-oxili {
+			cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+			label = "mas-oxili";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <2>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+			qcom,prio-lvl = <0>;
+			qcom,prio-rd = <0>;
+			qcom,prio-wr = <0>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_GFX3D>;
+		};
+
+		mas_snoc_bimc_0: mas-snoc-bimc-0 {
+			cell-id = <MSM_BUS_SNOC_BIMC_0_MAS>;
+			label = "mas-snoc-bimc-0";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <3>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_0>;
+		};
+
+		mas_snoc_bimc_2: mas-snoc-bimc-2 {
+			cell-id = <MSM_BUS_SNOC_BIMC_2_MAS>;
+			label = "mas-snoc-bimc-2";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <4>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_2>;
+		};
+
+		mas_snoc_bimc_1: mas-snoc-bimc-1 {
+			cell-id = <MSM_BUS_SNOC_BIMC_1_MAS>;
+			label = "mas-snoc-bimc-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <5>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_ebi>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_BIMC_1>;
+		};
+
+		mas_tcu_0: mas-tcu-0 {
+			cell-id = <MSM_BUS_MASTER_TCU_0>;
+			label = "mas-tcu-0";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <6>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&slv_ebi &slv_bimc_snoc>;
+			qcom,prio-lvl = <2>;
+			qcom,prio-rd = <2>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_TCU_0>;
+		};
+
+		/*PCNOC Masters*/
+		mas_spdm: mas-spdm {
+			cell-id = <MSM_BUS_MASTER_SPDM>;
+			label = "mas-spdm";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,connections = <&pcnoc_m_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SPDM>;
+		};
+
+		mas_blsp_1: mas-blsp-1 {
+			cell-id = <MSM_BUS_MASTER_BLSP_1>;
+			label = "mas-blsp-1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&pcnoc_m_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_BLSP_1>;
+		};
+
+		mas_blsp_2: mas-blsp-2 {
+			cell-id = <MSM_BUS_MASTER_BLSP_2>;
+			label = "mas-blsp-2";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&pcnoc_m_1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_BLSP_2>;
+		};
+
+		mas_usb_hs1: mas-usb-hs1 {
+			cell-id = <MSM_BUS_MASTER_USB_HS>;
+			label = "mas-usb-hs1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <12>;
+			qcom,qos-mode = "fixed";
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_USB_HS1>;
+		};
+
+		mas_xi_usb_hs1: mas-xi-usb-hs1 {
+			cell-id = <MSM_BUS_MASTER_XM_USB_HS1>;
+			label = "mas-xi-usb-hs1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <11>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_XI_USB_HS1>;
+		};
+
+		mas_crypto: mas-crypto {
+			cell-id = <MSM_BUS_MASTER_CRYPTO_CORE0>;
+			label = "mas-crypto";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <0>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_CRYPTO>;
+		};
+
+		mas_sdcc_1: mas-sdcc-1 {
+			cell-id = <MSM_BUS_MASTER_SDCC_1>;
+			label = "mas-sdcc-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <7>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SDCC_1>;
+		};
+
+		mas_sdcc_2: mas-sdcc-2 {
+			cell-id = <MSM_BUS_MASTER_SDCC_2>;
+			label = "mas-sdcc-2";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <8>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SDCC_2>;
+		};
+
+		mas_snoc_pcnoc: mas-snoc-pcnoc {
+			cell-id = <MSM_BUS_SNOC_PNOC_MAS>;
+			label = "mas-snoc-pcnoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <9>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_s_7
+					&pcnoc_int_2 &pcnoc_int_3>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_PCNOC>;
+		};
+
+		/*SNOC Masters*/
+		mas_qdss_bam: mas-qdss-bam {
+			cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+			label = "mas-qdss-bam";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <11>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&qdss_int>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_BAM>;
+		};
+
+		mas_bimc_snoc: mas-bimc-snoc {
+			cell-id = <MSM_BUS_BIMC_SNOC_MAS>;
+			label = "mas-bimc-snoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&snoc_int_0
+					&snoc_int_1 &snoc_int_2>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_BIMC_SNOC>;
+		};
+
+		mas_jpeg: mas-jpeg {
+			cell-id = <MSM_BUS_MASTER_JPEG>;
+			label = "mas-jpeg";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <6>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_JPEG>;
+		};
+
+		mas_mdp: mas-mdp {
+			cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+			label = "mas-mdp";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <7>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_0>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_MDP>;
+		};
+
+		mas_pcnoc_snoc: mas-pcnoc-snoc {
+			cell-id = <MSM_BUS_PNOC_SNOC_MAS>;
+			label = "mas-pcnoc-snoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <5>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&snoc_int_0
+				&snoc_int_1 &slv_snoc_bimc_1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PNOC_SNOC>;
+			qcom,blacklist = <&slv_snoc_pcnoc>;
+		};
+
+		mas_venus: mas-venus {
+			cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+			label = "mas-venus";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <8>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_VIDEO>;
+		};
+
+		mas_vfe0: mas-vfe0 {
+			cell-id = <MSM_BUS_MASTER_VFE>;
+			label = "mas-vfe0";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <9>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_0>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_VFE>;
+		};
+
+		mas_vfe1: mas-vfe1 {
+			cell-id = <MSM_BUS_MASTER_VFE1>;
+			label = "mas-vfe1";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <13>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_0>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_VFE1>;
+		};
+
+		mas_cpp: mas-cpp {
+			cell-id = <MSM_BUS_MASTER_CPP>;
+			label = "mas-cpp";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <12>;
+			qcom,qos-mode = "bypass";
+			qcom,connections = <&slv_snoc_bimc_2>;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,mas-rpm-id = <ICBID_MASTER_CPP>;
+		};
+
+		mas_qdss_etr: mas-qdss-etr {
+			cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+			label = "mas-qdss-etr";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <10>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&qdss_int>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_ETR>;
+		};
+
+		/*Internal nodes*/
+		pcnoc_m_0: pcnoc-m-0 {
+			cell-id = <MSM_BUS_PNOC_M_0>;
+			label = "pcnoc-m-0";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,qport = <5>;
+			qcom,qos-mode = "fixed";
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,prio1 = <1>;
+			qcom,prio0 = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_0>;
+		};
+
+		pcnoc_m_1: pcnoc-m-1 {
+			cell-id = <MSM_BUS_PNOC_M_1>;
+			label = "pcnoc-m-1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&pcnoc_int_0>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_M_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_M_1>;
+		};
+
+		pcnoc_int_0: pcnoc-int-0 {
+			cell-id = <MSM_BUS_PNOC_INT_0>;
+			label = "pcnoc-int-0";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_pcnoc_snoc
+				 &pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_0>;
+		};
+
+		pcnoc_int_1: pcnoc-int-1 {
+			cell-id = <MSM_BUS_PNOC_INT_1>;
+			label = "pcnoc-int-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_pcnoc_snoc
+				&pcnoc_s_7 &pcnoc_int_3 &pcnoc_int_2>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_1>;
+		};
+
+		pcnoc_int_2: pcnoc-int-2 {
+			cell-id = <MSM_BUS_PNOC_INT_2>;
+			label = "pcnoc-int-2";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&pcnoc_s_2
+				&pcnoc_s_3 &pcnoc_s_6 &pcnoc_s_8>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_2>;
+		};
+
+		pcnoc_int_3: pcnoc-int-3 {
+			cell-id = <MSM_BUS_PNOC_INT_3>;
+			label = "pcnoc-int-3";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = < &pcnoc_s_1 &pcnoc_s_0 &pcnoc_s_4
+				 &slv_gpu_cfg &slv_tcu >;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_INT_3>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_INT_3>;
+		};
+
+		pcnoc_s_0: pcnoc-s-0 {
+			cell-id = <MSM_BUS_PNOC_SLV_0>;
+			label = "pcnoc-s-0";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_spdm &slv_pdm &slv_prng
+				&slv_sdcc_2>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_0>;
+		};
+
+		pcnoc_s_1: pcnoc-s-1 {
+			cell-id = <MSM_BUS_PNOC_SLV_1>;
+			label = "pcnoc-s-1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_tcsr>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_1>;
+		};
+
+		pcnoc_s_2: pcnoc-s-2 {
+			cell-id = <MSM_BUS_PNOC_SLV_2>;
+			label = "pcnoc-s-2";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_snoc_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_2>;
+		};
+
+		pcnoc_s_3: pcnoc-s-3 {
+			cell-id = <MSM_BUS_PNOC_SLV_3>;
+			label = "pcnoc-s-3";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_message_ram>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_3>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_3>;
+		};
+
+		pcnoc_s_4: pcnoc-s-4 {
+			cell-id = <MSM_BUS_PNOC_SLV_4>;
+			label = "pcnoc-s-4";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,connections = <&slv_camera_ss_cfg
+				&slv_disp_ss_cfg &slv_venus_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_4>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_4>;
+		};
+
+		pcnoc_s_6: pcnoc-s-6 {
+			cell-id = <MSM_BUS_PNOC_SLV_6>;
+			label = "pcnoc-s-6";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_tlmm &slv_blsp_1 &slv_blsp_2>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_6>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_6>;
+		};
+
+		pcnoc_s_7: pcnoc-s-7 {
+			cell-id = <MSM_BUS_PNOC_SLV_7>;
+			label = "pcnoc-s-7";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = < &slv_sdcc_1 &slv_pmic_arb>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_7>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_7>;
+		};
+
+		pcnoc_s_8: pcnoc-s-8 {
+			cell-id = <MSM_BUS_PNOC_SLV_8>;
+			label = "pcnoc-s-8";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_usb_hs &slv_crypto_0_cfg>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_PCNOC_S_8>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_S_8>;
+		};
+
+		qdss_int: qdss-int {
+			cell-id = <MSM_BUS_SNOC_QDSS_INT>;
+			label = "qdss-int";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,connections = <&snoc_int_1 &slv_snoc_bimc_1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_QDSS_INT>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_INT>;
+		};
+
+		snoc_int_0: snoc-int-0 {
+			cell-id = <MSM_BUS_SNOC_INT_0>;
+			label = "snoc-int-0";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,connections = <&slv_lpass
+				&slv_wcss &slv_kpss_ahb>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_0>;
+		};
+
+		snoc_int_1: snoc-int-1 {
+			cell-id = <MSM_BUS_SNOC_INT_1>;
+			label = "snoc-int-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,connections = <&slv_qdss_stm
+				 &slv_imem &slv_snoc_pcnoc>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_1>;
+		};
+
+		snoc_int_2: snoc-int-2 {
+			cell-id = <MSM_BUS_SNOC_INT_2>;
+			label = "snoc-int-2";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,connections = <&slv_cats_0 &slv_cats_1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,mas-rpm-id = <ICBID_MASTER_SNOC_INT_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_INT_2>;
+		};
+		/*Slaves*/
+
+		slv_ebi:slv-ebi {
+			cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+			label = "slv-ebi";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_EBI1>;
+		};
+
+		slv_bimc_snoc:slv-bimc-snoc {
+			cell-id = <MSM_BUS_BIMC_SNOC_SLV>;
+			label = "slv-bimc-snoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_bimc>;
+			qcom,connections = <&mas_bimc_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BIMC_SNOC>;
+		};
+
+		slv_sdcc_2:slv-sdcc-2 {
+			cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+			label = "slv-sdcc-2";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_2>;
+		};
+
+		slv_spdm:slv-spdm {
+			cell-id = <MSM_BUS_SLAVE_SPDM_WRAPPER>;
+			label = "slv-spdm";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SPDM_WRAPPER>;
+		};
+
+		slv_pdm:slv-pdm {
+			cell-id = <MSM_BUS_SLAVE_PDM>;
+			label = "slv-pdm";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PDM>;
+		};
+
+		slv_prng:slv-prng {
+			cell-id = <MSM_BUS_SLAVE_PRNG>;
+			label = "slv-prng";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PRNG>;
+		};
+
+		slv_tcsr:slv-tcsr {
+			cell-id = <MSM_BUS_SLAVE_TCSR>;
+			label = "slv-tcsr";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TCSR>;
+		};
+
+		slv_snoc_cfg:slv-snoc-cfg {
+			cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+			label = "slv-snoc-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_CFG>;
+		};
+
+		slv_message_ram:slv-message-ram {
+			cell-id = <MSM_BUS_SLAVE_MESSAGE_RAM>;
+			label = "slv-message-ram";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_MESSAGE_RAM>;
+		};
+
+		slv_camera_ss_cfg:slv-camera-ss-cfg {
+			cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+			label = "slv-camera-ss-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CAMERA_CFG>;
+		};
+
+		slv_disp_ss_cfg:slv-disp-ss-cfg {
+			cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+			label = "slv-disp-ss-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_DISPLAY_CFG>;
+		};
+
+		slv_venus_cfg:slv-venus-cfg {
+			cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+			label = "slv-venus-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_VENUS_CFG>;
+		};
+
+		slv_gpu_cfg:slv-gpu-cfg {
+			cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+			label = "slv-gpu-cfg";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_GFX3D_CFG>;
+		};
+
+		slv_tlmm:slv-tlmm {
+			cell-id = <MSM_BUS_SLAVE_TLMM>;
+			label = "slv-tlmm";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TLMM>;
+		};
+
+		slv_blsp_1:slv-blsp-1 {
+			cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+			label = "slv-blsp-1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_1>;
+		};
+
+		slv_blsp_2:slv-blsp-2 {
+			cell-id = <MSM_BUS_SLAVE_BLSP_2>;
+			label = "slv-blsp-2";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_BLSP_2>;
+		};
+
+		slv_pmic_arb:slv-pmic-arb {
+			cell-id = <MSM_BUS_SLAVE_PMIC_ARB>;
+			label = "slv-pmic-arb";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PMIC_ARB>;
+		};
+
+		slv_sdcc_1:slv-sdcc-1 {
+			cell-id = <MSM_BUS_SLAVE_SDCC_1>;
+			label = "slv-sdcc-1";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SDCC_1>;
+		};
+
+		slv_crypto_0_cfg:slv-crypto-0-cfg {
+			cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+			label = "slv-crypto-0-cfg";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CRYPTO_0_CFG>;
+		};
+
+		slv_usb_hs:slv-usb-hs {
+			cell-id = <MSM_BUS_SLAVE_USB_HS>;
+			label = "slv-usb-hs";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_USB_HS>;
+		};
+
+		slv_tcu:slv-tcu {
+			cell-id = <MSM_BUS_SLAVE_TCU>;
+			label = "slv-tcu";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_TCU>;
+		};
+
+		slv_pcnoc_snoc:slv-pcnoc-snoc {
+			cell-id = <MSM_BUS_PNOC_SNOC_SLV>;
+			label = "slv-pcnoc-snoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_pcnoc>;
+			qcom,connections = <&mas_pcnoc_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_PCNOC_SNOC>;
+		};
+
+		slv_kpss_ahb:slv-kpss-ahb {
+			cell-id = <MSM_BUS_SLAVE_APPSS>;
+			label = "slv-kpss-ahb";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_APPSS>;
+		};
+
+		slv_wcss:slv-wcss {
+			cell-id = <MSM_BUS_SLAVE_WCSS>;
+			label = "slv-wcss";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_WCSS>;
+		};
+
+		slv_snoc_bimc_0:slv-snoc-bimc-0 {
+			cell-id = <MSM_BUS_SNOC_BIMC_0_SLV>;
+			label = "slv-snoc-bimc-0";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,connections = <&mas_snoc_bimc_0>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_0>;
+		};
+
+		slv_snoc_bimc_1:slv-snoc-bimc-1 {
+			cell-id = <MSM_BUS_SNOC_BIMC_1_SLV>;
+			label = "slv-snoc-bimc-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,connections = <&mas_snoc_bimc_1>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_1>;
+		};
+
+		slv_snoc_bimc_2:slv-snoc-bimc-2 {
+			cell-id = <MSM_BUS_SNOC_BIMC_2_SLV>;
+			label = "slv-snoc-bimc-2";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,connections = <&mas_snoc_bimc_2>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_BIMC_2>;
+		};
+
+		slv_imem:slv-imem {
+			cell-id = <MSM_BUS_SLAVE_OCIMEM>;
+			label = "slv-imem";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_IMEM>;
+		};
+
+		slv_snoc_pcnoc:slv-snoc-pcnoc {
+			cell-id = <MSM_BUS_SNOC_PNOC_SLV>;
+			label = "slv-snoc-pcnoc";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,connections = <&mas_snoc_pcnoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_SNOC_PCNOC>;
+		};
+
+		slv_qdss_stm:slv-qdss-stm {
+			cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+			label = "slv-qdss-stm";
+			qcom,buswidth = <4>;
+			qcom,agg-ports = <1>;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_QDSS_STM>;
+		};
+
+		slv_cats_0:slv-cats-0 {
+			cell-id = <MSM_BUS_SLAVE_CATS_128>;
+			label = "slv-cats-0";
+			qcom,buswidth = <16>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc_mm>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CATS_0>;
+		};
+
+		slv_cats_1:slv-cats-1 {
+			cell-id = <MSM_BUS_SLAVE_OCMEM_64>;
+			label = "slv-cats-1";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_CATS_1>;
+		};
+
+		slv_lpass:slv-lpass {
+			cell-id = <MSM_BUS_SLAVE_LPASS>;
+			label = "slv-lpass";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,ap-owned;
+			qcom,bus-dev = <&fab_snoc>;
+			qcom,slv-rpm-id = <ICBID_SLAVE_LPASS>;
+		};
+	};
+
+	devfreq_spdm_cpu {
+		compatible = "qcom,devfreq_spdm";
+		qcom,msm-bus,name = "devfreq_spdm";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<1 512 0 0>,
+				<1 512 0 0>;
+		qcom,msm-bus,active-only;
+		qcom,spdm-client = <0>;
+
+		clock-names = "cci_clk";
+		clocks = <&clock_cpu clk_cci_clk>;
+
+		qcom,bw-upstep = <400>;
+		qcom,bw-dwnstep = <3640>;
+		qcom,max-vote = <3640>;
+		qcom,up-step-multp = <1>;
+		qcom,spdm-interval = <50>;
+
+		qcom,ports = <11>;
+		qcom,alpha-up = <8>;
+		qcom,alpha-down = <15>;
+		qcom,bucket-size = <8>;
+
+		/*max pl1 freq, max pl2 freq*/
+		qcom,pl-freqs = <520000 720000>;
+
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,reject-rate = <5000 5000 5000 5000 5000 5000>;
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,response-time-us = <5000 5000 5000 5000 5000 5000>;
+		/* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */
+		qcom,cci-response-time-us = <5000 5000 5000 5000 5000 5000>;
+		qcom,max-cci-freq = <500000>;
+	};
+
+	devfreq_spdm_gov {
+		compatible = "qcom,gov_spdm_hyp";
+		interrupt-names = "spdm-irq";
+		interrupts = <0 192 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi
new file mode 100644
index 0000000..b82767915
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 2015-2018, 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 an
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tmc_etr: tmc@6028000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6028000 0x1000>,
+				<0x6044000 0x15000>;
+		reg-names = "tmc-base", "bam-base";
+
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
+
+		arm,buffer-size = <0x100000>;
+		arm,sg-enable;
+
+		coresight-name = "coresight-tmc-etr";
+		coresight-ctis = <&cti0 &cti8>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			tmc_etr_in_replicator: endpoint {
+				slave-mode;
+				remote-endpoint = <&replicator_out_tmc_etr>;
+			};
+		};
+	};
+
+	tmc_etf: tmc@6027000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6027000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-name = "coresight-tmc-etf";
+
+		arm,default-sink;
+		coresight-ctis = <&cti0 &cti8>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				tmc_etf_out_replicator:endpoint {
+					remote-endpoint =
+						<&replicator_in_tmc_etf>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_tmc_etf>;
+				};
+			};
+		};
+	};
+
+	replicator: replicator@6026000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6026000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				replicator_out_tmc_etr: endpoint {
+					remote-endpoint =
+						<&tmc_etr_in_replicator>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				replicator_in_tmc_etf: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tmc_etf_out_replicator>;
+				};
+			};
+		};
+	};
+
+	funnel_in0: funnel@6021000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6021000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_in0_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_in0>;
+				};
+			};
+
+			port@1 {
+				reg = <7>;
+				funnel_in0_in_stm: endpoint {
+					slave-mode;
+					remote-endpoint = <&stm_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <6>;
+				funnel_in0_in_tpda: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_out_funnel_in0>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+				funnel_in0_in_funnel_center: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_center_out_funnel_in0>;
+				};
+			};
+
+			port@4 {
+				reg = <4>;
+				funnel_in0_in_funnel_right: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_right_out_funnel_in0>;
+				};
+			};
+
+			port@5 {
+				reg = <5>;
+				funnel_in0_in_funnel_mm: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_mm_out_funnel_in0>;
+				};
+			};
+		};
+	};
+
+	funnel_center: funnel@6100000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6100000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-center";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_center_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_center>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_center_in_rpm_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&rpm_etm0_out_funnel_center>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_center_in_dbgui: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&dbgui_out_funnel_center>;
+				};
+			};
+		};
+	};
+
+	funnel_right: funnel@6120000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6120000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-right";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_right_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_right>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				funnel_right_in_modem_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&modem_etm0_out_funnel_right>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_right_in_funnel_apss: endpoint {
+					slave-mode;
+					remote-endpoint =
+					       <&funnel_apss_out_funnel_right>;
+				};
+			};
+		};
+	};
+
+	funnel_mm: funnel@6130000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6130000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-mm";
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_mm_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_mm>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_mm_in_wcn_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&wcn_etm0_out_funnel_mm>;
+				};
+			};
+
+			port@2 {
+				reg = <4>;
+				funnel_mm_in_funnel_cam: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_cam_out_funnel_mm>;
+				};
+			};
+
+			port@3 {
+				reg = <5>;
+				funnel_mm_in_audio_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&audio_etm0_out_funnel_mm>;
+				};
+			};
+		};
+	};
+
+	funnel_cam: funnel@6132000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6132000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-cam";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			funnel_cam_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_funnel_cam>;
+			};
+		};
+	};
+
+	funnel_apss: funnel@61a1000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x61a1000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-apss";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_apss_out_funnel_right: endpoint {
+					remote-endpoint =
+						<&funnel_right_in_funnel_apss>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_apss0_in_etm4: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm4_out_funnel_apss0>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_apss0_in_etm5: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm5_out_funnel_apss0>;
+				};
+			};
+
+			port@3 {
+				reg = <2>;
+				funnel_apss0_in_etm6: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm6_out_funnel_apss0>;
+				};
+			};
+
+			port@4 {
+				reg = <3>;
+				funnel_apss0_in_etm7: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm7_out_funnel_apss0>;
+				};
+			};
+
+			port@5 {
+				reg = <4>;
+				funnel_apss0_in_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm0_out_funnel_apss0>;
+				};
+			};
+
+			port@6 {
+				reg = <5>;
+				funnel_apss0_in_etm1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm1_out_funnel_apss0>;
+				};
+			};
+
+			port@7 {
+				reg = <6>;
+				funnel_apss0_in_etm2: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm2_out_funnel_apss0>;
+					};
+			};
+
+			port@8 {
+				reg = <7>;
+				funnel_apss0_in_etm3: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm3_out_funnel_apss0>;
+				};
+			};
+		};
+	};
+
+	etm4: etm@619c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x619c000 0x1000>;
+		cpu = <&CPU4>;
+		coresight-name = "coresight-etm4";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm4_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm4>;
+			};
+		};
+	};
+
+	etm5: etm@619d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x619d000 0x1000>;
+		cpu = <&CPU5>;
+		coresight-name = "coresight-etm5";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm5_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm5>;
+			};
+		};
+	};
+
+	etm6: etm@619e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x619e000 0x1000>;
+		cpu = <&CPU6>;
+		coresight-name = "coresight-etm6";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm6_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm6>;
+			};
+		};
+	};
+
+	etm7: etm@619f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x619f000 0x1000>;
+		cpu = <&CPU7>;
+		coresight-name = "coresight-etm7";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm7_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm7>;
+			};
+		};
+	};
+
+	etm0: etm@61bc000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bc000 0x1000>;
+		cpu = <&CPU0>;
+		coresight-name = "coresight-etm0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm0_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm0>;
+			};
+		};
+	};
+
+	etm1: etm@61bd000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bd000 0x1000>;
+		cpu = <&CPU1>;
+		coresight-name = "coresight-etm1";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm1_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm1>;
+			};
+		};
+	};
+
+	etm2: etm@61be000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61be000 0x1000>;
+		cpu = <&CPU2>;
+		coresight-name = "coresight-etm2";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm2_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm2>;
+			};
+		};
+	};
+
+	etm3: etm@61bf000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bf000 0x1000>;
+		coresight-name = "coresight-etm3";
+		cpu = <&CPU3>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm3_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm3>;
+			};
+		};
+	};
+
+	stm: stm@6002000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b962>;
+
+		reg = <0x6002000 0x1000>,
+		      <0x9280000 0x180000>;
+		reg-names = "stm-base", "stm-stimulus-base";
+
+		coresight-name = "coresight-stm";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			stm_out_funnel_in0: endpoint {
+				remote-endpoint = <&funnel_in0_in_stm>;
+			};
+		};
+	};
+
+	cti0: cti@6010000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6010000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1: cti@6011000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6011000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti1";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2: cti@6012000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6012000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti2";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3: cti@6013000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6013000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti3";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti4: cti@6014000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6014000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti4";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti5: cti@6015000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6015000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti5";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti6: cti@6016000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6016000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti6";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti7: cti@6017000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6017000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti7";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti8: cti@6018000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6018000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti8";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti9: cti@6019000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6019000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti9";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti10: cti@601a000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601a000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti10";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti11: cti@601b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601b000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti11";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti12: cti@601c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601c000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti12";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti13: cti@601d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601d000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti13";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti14: cti@601e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601e000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti14";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti15: cti@601f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601f000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti15";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu0: cti@6198000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6198000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu0";
+		cpu = <&CPU0>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu1: cti@6199000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6199000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu1";
+		cpu = <&CPU1>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu2: cti@619a000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x619a000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu2";
+		cpu = <&CPU2>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu3: cti@619b000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x619b000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu3";
+		cpu = <&CPU3>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu4: cti@61b8000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61b8000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu4";
+		cpu = <&CPU4>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu5: cti@61b9000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61b9000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu5";
+		cpu = <&CPU5>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu6: cti@61ba000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61ba000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu6";
+		cpu = <&CPU6>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu7: cti@61bb000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61bb000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu7";
+		cpu = <&CPU7>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu0: cti@6128000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6128000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-modem-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu1: cti@6124000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6124000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-modem-cpu1";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Venus CTI */
+	cti_video_cpu0: cti@6134000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6134000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-video-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Pronto CTI */
+	cti_wcn_cpu0: cti@6139000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6139000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-wcn-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* LPASS CTI */
+	cti_audio_cpu0: cti@613c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x613c000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-audio-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_rpm_cpu0: cti@610c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x610c000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-rpm-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Pronto ETM */
+	wcn_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-wcn-etm0";
+		qcom,inst-id = <3>;
+
+		port {
+			wcn_etm0_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_wcn_etm0>;
+			};
+		};
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-rpm-etm0";
+		qcom,inst-id = <4>;
+
+		port {
+			rpm_etm0_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_center_in_rpm_etm0>;
+			};
+		};
+	};
+
+	/* LPASS ETM */
+	audio_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-audio-etm0";
+		qcom,inst-id = <5>;
+
+		port {
+			audio_etm0_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_audio_etm0>;
+			};
+		};
+	};
+
+	/* MSS_SCL */
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-modem-etm0";
+		qcom,inst-id = <11>;
+
+		port {
+			modem_etm0_out_funnel_right: endpoint {
+				remote-endpoint = <&funnel_right_in_modem_etm0>;
+			};
+		};
+	};
+
+
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+		coresight-name = "coresight-csr";
+
+		qcom,blk-size = <1>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	dbgui: dbgui@6108000 {
+		compatible = "qcom,coresight-dbgui";
+		reg = <0x6108000 0x1000>;
+		reg-names = "dbgui-base";
+		coresight-name = "coresight-dbgui";
+
+		qcom,dbgui-addr-offset = <0x30>;
+		qcom,dbgui-data-offset = <0x130>;
+		qcom,dbgui-size = <64>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			dbgui_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_center_in_dbgui>;
+			};
+		};
+	};
+
+	tpda: tpda@6003000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+
+		reg = <0x6003000 0x1000>;
+		reg-names = "tpda-base";
+		coresight-name = "coresight-tpda";
+
+		qcom,tpda-atid = <64>;
+		qcom,cmb-elem-size = <0 32>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+			port@0 {
+				tpda_out_funnel_in0: endpoint {
+					remote-endpoint = <&funnel_in0_in_tpda>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_in_tpdm_dcc: endpoint {
+					slave-mode;
+						remote-endpoint =
+							<&tpdm_dcc_out_tpda>;
+				};
+			};
+		};
+	};
+
+	tpdm_dcc: tpdm@6110000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+
+		reg = <0x6110000 0x1000>;
+		reg-names = "tpdm-base";
+		coresight-name = "coresight-tpdm-dcc";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_dcc_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_dcc>;
+			};
+		};
+	};
+
+	hwevent: hwevent@6101000 {
+		compatible = "qcom,coresight-hwevent";
+
+		reg = <0x6101000 0x148>,
+		      <0x6101fb0 0x4>,
+		      <0x6121000 0x148>,
+		      <0x6121fb0 0x4>,
+		      <0x6131000 0x148>,
+		      <0x6131fb0 0x4>,
+		      <0x7105010 0x4>,
+		      <0x7885010 0x4>;
+
+		reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+				"right-wrapper-mux", "right-wrapper-lockaccess",
+				"mm-wrapper-mux", "mm-wrapper-lockaccess",
+				"usbbam-mux", "blsp-mux";
+
+		coresight-name = "coresight-hwevent";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
new file mode 100644
index 0000000..7aaaf7e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+/ {
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		CPU0: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x100>;
+			enable-method = "psci";
+			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      /* A53 L2 dump not supported */
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_100: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_100: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU1: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x101>;
+			enable-method = "psci";
+			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_101: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_101: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU2: cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x102>;
+			enable-method = "psci";
+			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_102: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_102: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU3: cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x103>;
+			enable-method = "psci";
+			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_103: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_103: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU4: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			enable-method = "psci";
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_0: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_0: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU5: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			enable-method = "psci";
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_1: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_1: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU6: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x2>;
+			enable-method = "psci";
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_2: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_2: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU7: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+			enable-method = "psci";
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_3: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_3: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+	};
+
+	energy_costs: energy-costs {
+		compatible = "sched-energy";
+
+		CPU_COST_0: core-cost0 {
+			busy-cost-data = <
+				 700000  623
+				1000000  917
+				1100000  1106
+				1250000  1432
+				1400000  1740
+			>;
+			idle-cost-data = <
+				100 80 60 40
+			>;
+		};
+		CPU_COST_1: core-cost1 {
+			busy-cost-data = <
+				 500000  70
+				 800000  114
+				 900000  141
+				1000000  178
+				1100000  213
+			>;
+			idle-cost-data = <
+				40 20 10 8
+			>;
+		};
+		CLUSTER_COST_0: cluster-cost0 {
+			busy-cost-data = <
+				 500000  19
+				 800000  29
+				 900000  36
+				1000000  46
+				1100000  55
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+		CLUSTER_COST_1: cluster-cost1 {
+			busy-cost-data = <
+				 700000  85
+				1000000  126
+				1100000  152
+				1250000  197
+				1400000  239
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi
new file mode 100644
index 0000000..2ee4c0e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-gpu.dtsi
@@ -0,0 +1,224 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	msm_bus: qcom,kgsl-busmon {
+		label = "kgsl-busmon";
+		compatible = "qcom,kgsl-busmon";
+	};
+
+	gpubw: qcom,gpubw {
+		compatible = "qcom,devbw";
+		governor = "bw_vbif";
+		qcom,src-dst-ports = <26 512>;
+		/*
+		 * active-only flag is used while registering the bus
+		 * governor.It helps release the bus vote when the CPU
+		 * subsystem is inactiv3
+		 */
+		qcom,active-only;
+		qcom,bw-tbl =
+			< 0    >, /*  off */
+			<  769 >, /* 1. DDR:100.80 MHz BIMC: 50.40 MHz */
+			< 1611 >, /* 2. DDR:211.20 MHz BIMC: 105.60 MHz */
+			< 2124 >, /* 3. DDR:278.40 MHz BIMC: 139.20 MHz */
+			< 2929 >, /* 4. DDR:384.00 MHz BIMC: 192.00 MHz */
+			< 4101 >, /* 5. DDR:537.60 MHz BIMC: 268.80 MHz */
+			< 4248 >, /* 6. DDR:556.80 MHz BIMC: 278.40 MHz */
+			< 5346 >, /* 7. DDR:662.40 MHz BIMC: 331.20 MHz */
+			< 5712 >, /* 8. DDR:748.80 MHz BIMC: 374.40 MHz */
+			< 6152 >, /* 9. DDR:806.40 MHz BIMC: 403.20 MHz */
+			< 7031 >; /* 10. DDR:921.60 MHz BIMC: 460.80 MHz */
+	};
+
+	msm_gpu: qcom,kgsl-3d0@1c00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		status = "ok";
+		reg = <0x1c00000 0x40000
+		       0xa0000 0x6fff>;
+		reg-names = "kgsl_3d0_reg_memory", "qfprom_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+		qcom,chipid = <0x05000500>;
+
+		qcom,initial-pwrlevel = <2>;
+
+		qcom,idle-timeout = <80>; //msecs
+		qcom,strtstp-sleepwake;
+
+		qcom,highest-bank-bit = <14>;
+
+		qcom,snapshot-size = <1048576>; //bytes
+
+		clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>,
+			<&clock_gcc clk_gcc_oxili_ahb_clk>,
+			<&clock_gcc clk_gcc_bimc_gfx_clk>,
+			<&clock_gcc clk_gcc_bimc_gpu_clk>,
+			<&clock_gcc clk_gcc_oxili_timer_clk>,
+			<&clock_gcc clk_gcc_oxili_aon_clk>;
+
+		clock-names = "core_clk", "iface_clk",
+			      "mem_iface_clk", "alt_mem_iface_clk",
+			      "rbbmtimer_clk", "alwayson_clk";
+
+
+		/* Bus Scale Settings */
+		qcom,gpubw-dev = <&gpubw>;
+		qcom,bus-control;
+		qcom,bus-width = <16>;
+		qcom,msm-bus,name = "grp3d";
+		qcom,msm-bus,num-cases = <11>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<26 512 0 0>,	    /*    off        */
+				<26 512 0  806400>, /* 1. 100.80 MHz */
+				<26 512 0 1689600>, /* 2. 211.20 MHz */
+				<26 512 0 2227200>, /* 3. 278.40 MHz */
+				<26 512 0 3072000>, /* 4. 384.00 MHz */
+				<26 512 0 4300800>, /* 5. 537.60 MHz */
+				<26 512 0 4454400>, /* 6. 556.80 MHz */
+				<26 512 0 5299200>, /* 7. 662.40 MHz */
+				<26 512 0 5990400>, /* 8. 748.80 MHz */
+				<26 512 0 6451200>, /* 9. 806.40 MHz */
+				<26 512 0 7372800>; /* 10. 921.60 MHz */
+
+		/* GDSC regulator names */
+		regulator-names = "vddcx", "vdd";
+		/* GDSC oxili regulators */
+		vddcx-supply = <&gdsc_oxili_cx>;
+		vdd-supply = <&gdsc_oxili_gx>;
+
+		/* CPU latency parameter */
+		qcom,pm-qos-active-latency = <360>;
+		qcom,pm-qos-wakeup-latency = <360>;
+
+		/*  Quirks  */
+		qcom,gpu-quirk-two-pass-use-wfi;
+		qcom,gpu-quirk-dp2clockgating-disable;
+		qcom,gpu-quirk-lmloadkill-disable;
+
+		/* 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>;
+
+		/* GPU Mempools */
+		qcom,gpu-mempools {
+			#address-cells= <1>;
+			#size-cells = <0>;
+			compatible = "qcom,gpu-mempools";
+
+			qcom,mempool-max-pages = <32768>;
+
+			/* 4K Page Pool configuration */
+			qcom,gpu-mempool@0 {
+				reg = <0>;
+				qcom,mempool-page-size = <4096>;
+			};
+			/* 64K Page Pool configuration */
+			qcom,gpu-mempool@1 {
+				reg = <1>;
+				qcom,mempool-page-size = <65536>;
+			};
+		};
+
+		/* Power levels */
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			/* TURBO */
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <450000000>;
+				qcom,bus-freq = <9>;
+				qcom,bus-min = <9>;
+				qcom,bus-max = <9>;
+			};
+
+			/* NOM+ */
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <400000000>;
+				qcom,bus-freq = <7>;
+				qcom,bus-min = <6>;
+				qcom,bus-max = <9>;
+			};
+
+			/* NOM */
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <375000000>;
+				qcom,bus-freq = <6>;
+				qcom,bus-min = <5>;
+				qcom,bus-max = <8>;
+			};
+
+			/* SVS+ */
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <300000000>;
+				qcom,bus-freq = <5>;
+				qcom,bus-min = <4>;
+				qcom,bus-max = <7>;
+			};
+
+			/* SVS */
+			qcom,gpu-pwrlevel@4 {
+				reg = <4>;
+				qcom,gpu-freq = <216000000>;
+				qcom,bus-freq = <3>;
+				qcom,bus-min = <1>;
+				qcom,bus-max = <4>;
+			};
+
+			/* XO */
+			qcom,gpu-pwrlevel@5 {
+				reg = <5>;
+				qcom,gpu-freq = <19200000>;
+				qcom,bus-freq = <0>;
+				qcom,bus-min = <0>;
+				qcom,bus-max = <0>;
+			};
+		};
+	};
+
+	kgsl_msm_iommu: qcom,kgsl-iommu@1c40000 {
+		compatible = "qcom,kgsl-smmu-v2";
+
+		reg = <0x1c40000 0x10000>;
+		qcom,protect = <0x40000 0x10000>;
+		qcom,micro-mmu-control = <0x6000>;
+
+		clocks = <&clock_gcc clk_gcc_oxili_ahb_clk>,
+			 <&clock_gcc clk_gcc_bimc_gfx_clk>;
+
+		clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk";
+
+		qcom,secure_align_mask = <0xfff>;
+		qcom,retention;
+		gfx3d_user: gfx3d_user {
+			compatible = "qcom,smmu-kgsl-cb";
+			label = "gfx3d_user";
+			iommus = <&kgsl_smmu 0>;
+			qcom,gpu-offset = <0x48000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts
new file mode 100644
index 0000000..4045e9c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 CDP";
+	compatible = "qcom,msm8937-cdp", "qcom,msm8937", "qcom,cdp";
+	qcom,board-id = <1 2>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts
new file mode 100644
index 0000000..b34974c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 MTP";
+	compatible = "qcom,msm8937-mtp", "qcom,msm8937", "qcom,mtp";
+	qcom,board-id = <8 1>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts
new file mode 100644
index 0000000..2bad28b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8937-interposer-sdm439.dtsi"
+#include "sdm439-qrd.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937 Interposer SDM439 QRD";
+	compatible = "qcom,msm8937-qrd", "qcom,msm8937", "qcom,qrd";
+	qcom,board-id = <0xb 2>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi
new file mode 100644
index 0000000..7f352e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439.dtsi
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8937.dtsi"
+#include "sdm439-pm8953.dtsi"
+#include "sdm439-audio.dtsi"
+#include "sdm439-pmi632.dtsi"
+
+&soc {
+	mem_acc_vreg_corner: regulator@01946004 {
+		compatible = "qcom,mem-acc-regulator";
+		regulator-name = "mem_acc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <3>;
+
+		qcom,acc-reg-addr-list =
+			<0x01942138 0x01942130 0x01942120
+			 0x01942124 0x01946000 0x01946004>;
+
+		qcom,acc-init-reg-config = <1 0xff>, <2 0x5555>, <6 0x55>;
+
+		qcom,num-acc-corners = <3>;
+		qcom,boot-acc-corner = <2>;
+		qcom,corner1-reg-config =
+			/* SVS+ => SVS+ */
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			/* SVS+ => NOM */
+			<  3 0x1041041>, <  4  0x1041>, <  5  0x2020202>,
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			/* SVS+ => TURBO/NOM+ */
+			<  3 0x1041041>, <  4  0x1041>, <  5  0x2020202>,
+			<  3 0x0>,       <  4  0x0>,    <  5  0x0>;
+
+		qcom,corner2-reg-config =
+			/* NOM => SVS+ */
+			<  3 0x30c30c3>, <  4  0x30c3>, <  5  0x6060606>,
+			/* NOM => NOM */
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			/* NOM => TURBO/NOM+ */
+			<  3 0x0>,       <  4  0x0>,    <  5  0x0>;
+
+		qcom,corner3-reg-config =
+			/* TURBO/NOM+ => SVS+ */
+			<  3 0x1041041>, <  4  0x1041>, <  5  0x2020202>,
+			<  3 0x30c30c3>, <  4  0x30c3>, <  5  0x6060606>,
+			/* TURBO/NOM+ => NOM */
+			<  3 0x1041041>, <  4  0x1041>, <  5  0x2020202>,
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			/* TURBO/NOM+ => TURBO/NOM+ */
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>,
+			<(-1) (-1)>,     <(-1) (-1)>,   <(-1) (-1)>;
+	};
+
+	apc_vreg_corner: regulator@b018000 {
+		compatible = "qcom,cpr-regulator";
+		reg = <0xb018000 0x1000>, <0xb011064 4>, <0xa4000 0x1000>;
+		reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
+		interrupts = <0 15 0>;
+		regulator-name = "apc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+
+		qcom,cpr-fuse-corners = <3>;
+		qcom,cpr-voltage-ceiling = <1155000 1225000 1350000>;
+		qcom,cpr-voltage-floor =   <1050000 1050000 1090000>;
+		vdd-apc-supply = <&pm8953_s5>;
+
+		mem-acc-supply = <&mem_acc_vreg_corner>;
+
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <0>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <10>;
+		qcom,cpr-up-threshold = <2>;
+		qcom,cpr-down-threshold = <4>;
+		qcom,cpr-idle-clocks = <15>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
+
+		qcom,cpr-fuse-row = <67 0>;
+		qcom,cpr-fuse-target-quot = <42 24 6>;
+		qcom,cpr-fuse-ro-sel = <60 57 54>;
+		qcom,cpr-init-voltage-ref = <1155000 1225000 1350000>;
+		qcom,cpr-fuse-init-voltage =
+					<67 36 6 0>,
+					<67 18 6 0>,
+					<67  0 6 0>;
+		qcom,cpr-fuse-quot-offset =
+					<71 26 6 0>,
+					<71 20 6 0>,
+					<70 54 7 0>;
+		qcom,cpr-fuse-quot-offset-scale = <5 5 5>;
+		qcom,cpr-init-voltage-step = <10000>;
+		qcom,cpr-corner-map = <1 2 3 3 3 3 3>;
+		qcom,cpr-corner-frequency-map =
+				<1 960000000>,
+				<2 1094400000>,
+				<3 1209600000>,
+				<4 1248000000>,
+				<5 1344000000>,
+				<6 1401000000>,
+				<7 1497600000>;
+		qcom,speed-bin-fuse-sel = <37 34 3 0>;
+		qcom,cpr-speed-bin-max-corners =
+					<0 0 1 2 6>,
+					<1 0 1 2 7>,
+					<2 0 1 2 3>;
+		qcom,cpr-fuse-revision = <69 39 3 0>;
+		qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>;
+		qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>;
+		qcom,cpr-scaled-init-voltage-as-ceiling;
+		qcom,cpr-fuse-version-map =
+			<0	(-1)	1	(-1)	(-1)	(-1)>,
+			<(-1)	(-1)	2	(-1)	(-1)	(-1)>,
+			<(-1)	(-1)	3	(-1)	(-1)	(-1)>,
+			<(-1)	(-1)  (-1)	(-1)	(-1)	(-1)>;
+		qcom,cpr-quotient-adjustment =
+				<(-20)	(-40)	(-20)>,
+				<0	(-40)	 (20)>,
+				<0	  0	 (20)>,
+				<0	  0	    0>;
+		qcom,cpr-init-voltage-adjustment =
+				<0		0	      0>,
+				<(10000)     (15000)	(20000)>,
+				<0		0	      0>,
+				<0		0	      0>;
+		qcom,cpr-enable;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
new file mode 100644
index 0000000..96e7166
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@8 { /* CP_MM HEAP */
+			reg = <8>;
+			memory-region = <&secure_mem>;
+			qcom,ion-heap-type = "SECURE_DMA";
+		};
+
+		qcom,ion-heap@27 { /* QSEECOM HEAP */
+			reg = <27>;
+			memory-region = <&qseecom_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+			reg = <19>;
+			memory-region = <&qseecom_ta_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
new file mode 100644
index 0000000..ab2a365
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
@@ -0,0 +1,64 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-truly-1080p-video.dtsi"
+#include "dsi-panel-truly-1080p-cmd.dtsi"
+#include "dsi-panel-r69006-1080p-cmd.dtsi"
+#include "dsi-panel-r69006-1080p-video.dtsi"
+#include "dsi-adv7533-1080p.dtsi"
+#include "dsi-adv7533-720p.dtsi"
+
+&soc {
+	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@2 {
+			reg = <2>;
+			qcom,supply-name = "lab";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@3 {
+			reg = <3>;
+			qcom,supply-name = "ibb";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-post-on-sleep = <10>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi
new file mode 100644
index 0000000..6987716
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi
@@ -0,0 +1,103 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@1a94a00 {
+		compatible = "qcom,mdss_dsi_pll_8937";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x001a94a00 0xd4>,
+			<0x0184d074 0x8>;
+		reg-names = "pll_base", "gdsc_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+		vddio-supply = <&pm8937_l6>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		qcom,ssc-frequency-hz = <30000>;
+		qcom,ssc-ppm = <5000>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+			qcom,platform-supply-entry@1 {
+				reg = <1>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+	};
+
+	mdss_dsi1_pll: qcom,mdss_dsi_pll@1a96a00 {
+		compatible = "qcom,mdss_dsi_pll_8937";
+		label = "MDSS DSI 1 PLL";
+		cell-index = <1>;
+		#clock-cells = <1>;
+
+		reg = <0x001a96a00 0xd4>,
+			<0x0184d074 0x8>;
+		reg-names = "pll_base", "gdsc_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+		vddio-supply = <&pm8937_l6>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		qcom,ssc-frequency-hz = <30000>;
+		qcom,ssc-ppm = <5000>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+			qcom,platform-supply-entry@1 {
+				reg = <1>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
new file mode 100644
index 0000000..2c86c8f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
@@ -0,0 +1,410 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0x01a00000 0x90000>,
+		      <0x01ab0000 0x1040>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-ib-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-clk-factor = <105 100>;	/* 1.05 times */
+
+		qcom,max-mixer-width = <2048>;
+		qcom,max-pipe-width = <2048>;
+
+		/* VBIF QoS remapper settings*/
+		qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+		qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
+
+		qcom,mdss-has-panic-ctrl;
+		qcom,mdss-per-pipe-panic-luts = <0x000f>,
+						<0xffff>,
+						<0xfffc>,
+						<0xff00>;
+
+		qcom,mdss-mdp-reg-offset = <0x00001000>;
+		qcom,max-bandwidth-low-kbps = <3100000>;
+		qcom,max-bandwidth-high-kbps = <3100000>;
+		qcom,max-bandwidth-per-pipe-kbps = <2300000>;
+
+		/* Bandwidth limit settings */
+		qcom,max-bw-settings = <1 3100000>,	/* Default */
+				       <2 1700000>;	/* Camera */
+
+		qcom,max-clk-rate = <320000000>;
+		qcom,mdss-default-ot-rd-limit = <32>;
+		qcom,mdss-default-ot-wr-limit = <16>;
+
+		qcom,mdss-pipe-vig-off = <0x00005000>;
+		qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000>;
+		qcom,mdss-pipe-dma-off = <0x00025000>;
+		qcom,mdss-pipe-cursor-off = <0x00035000>;
+
+		qcom,mdss-pipe-vig-xin-id = <0>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5>;
+		qcom,mdss-pipe-dma-xin-id = <2>;
+		qcom,mdss-pipe-cursor-xin-id = <7>;
+
+		/* Offsets relative to "mdp_phys + mdp-reg-offset" address */
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2AC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x2AC 4 8>,
+						      <0x2B4 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2AC 8 12>;
+		qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3A8 16 15>;
+
+
+		qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400>;
+		qcom,mdss-mixer-intf-off = <0x00045000 0x00046000>;
+		qcom,mdss-dspp-off = <0x00055000>;
+		qcom,mdss-wb-off = <0x00065000 0x00066000>;
+		qcom,mdss-intf-off = <0x00000000 0x0006B800 0x0006C000>;
+		qcom,mdss-pingpong-off = <0x00071000 0x00071800>;
+		qcom,mdss-slave-pingpong-off = <0x00073000>;
+		qcom,mdss-cdm-off = <0x0007a200>;
+		qcom,mdss-wfd-mode = "intf";
+		qcom,mdss-highest-bank-bit = <0x1>;
+		qcom,mdss-has-decimation;
+		qcom,mdss-has-non-scalar-rgb;
+		qcom,mdss-has-rotator-downscale;
+		qcom,mdss-rot-downscale-min = <2>;
+		qcom,mdss-rot-downscale-max = <16>;
+		qcom,mdss-idle-power-collapse-enabled;
+		qcom,mdss-rot-block-size = <64>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>,
+			 <&clock_gcc clk_mdp_clk_src>,
+			 <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			 <&clock_gcc clk_gcc_mdss_vsync_clk>;
+		clock-names = "iface_clk", "bus_clk", "core_clk_src",
+				"core_clk", "vsync_clk";
+
+		qcom,mdp-settings = <0x0506c 0x00000000>,
+				    <0x1506c 0x00000000>,
+				    <0x1706c 0x00000000>,
+				    <0x2506c 0x00000000>;
+
+		qcom,vbif-settings = <0x0d0 0x00000010>;
+
+		qcom,regs-dump-mdp = <0x01000 0x01454>,
+				     <0x02000 0x02064>,
+				     <0x02200 0x02264>,
+				     <0x02400 0x02464>,
+				     <0x05000 0x05150>,
+				     <0x05200 0x05230>,
+				     <0x15000 0x15150>,
+				     <0x17000 0x17150>,
+				     <0x25000 0x25150>,
+				     <0x35000 0x35150>,
+				     <0x45000 0x452bc>,
+				     <0x46000 0x462bc>,
+				     <0x55000 0x5522c>,
+				     <0x65000 0x652c0>,
+				     <0x66000 0x662c0>,
+				     <0x6b800 0x6ba68>,
+				     <0x6c000 0x6c268>,
+				     <0x71000 0x710d4>,
+				     <0x71800 0x718d4>;
+
+		qcom,regs-dump-names-mdp = "MDP",
+			"CTL_0",    "CTL_1", "CTL_2",
+			"VIG0_SSPP", "VIG0",
+			"RGB0_SSPP", "RGB1_SSPP",
+			"DMA0_SSPP",
+			"CURSOR0_SSPP",
+			"LAYER_0", "LAYER_1",
+			"DSPP_0",
+			"WB_0",    "WB_2",
+			"INTF_1",  "INTF_2",
+			"PP_0",    "PP_1";
+
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <0>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+
+		qcom,mdss-pp-offsets {
+			qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>;
+			qcom,mdss-sspp-vig-pcc-off = <0x1780>;
+			qcom,mdss-sspp-rgb-pcc-off = <0x380>;
+			qcom,mdss-sspp-dma-pcc-off = <0x380>;
+			qcom,mdss-lm-pgc-off = <0x3C0>;
+			qcom,mdss-dspp-pcc-off = <0x1700>;
+			qcom,mdss-dspp-pgc-off = <0x17C0>;
+		};
+
+		qcom,mdss-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_reg";
+			qcom,msm-bus,num-cases = <4>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>,
+				<1 590 0 160000>,
+				<1 590 0 320000>;
+		};
+
+		qcom,mdss-hw-rt-bus {
+			/* Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_hw_rt";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<22 512 0 0>,
+				<22 512 0 1000>;
+		};
+
+		smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+			compatible = "qcom,smmu_mdp_unsec";
+			iommus = <&apps_iommu 0x2800 0>; /* For NS ctx bank */
+		};
+		smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+			compatible = "qcom,smmu_mdp_sec";
+			iommus = <&apps_iommu 0x2801 0>; /* For SEC Ctx Bank */
+		};
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,cont-splash-memory {
+				linux,contiguous-region = <&cont_splash_mem>;
+			};
+		};
+
+		mdss_fb1: qcom,mdss_fb_wfd {
+			cell-index = <1>;
+			compatible = "qcom,mdss-fb";
+		};
+
+		mdss_fb2: qcom,mdss_fb_secondary {
+			cell-index = <2>;
+			compatible = "qcom,mdss-fb";
+		};
+	};
+
+	mdss_dsi: qcom,mdss_dsi@0 {
+		compatible = "qcom,mdss-dsi";
+		hw-config = "single_dsi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		gdsc-supply = <&gdsc_mdss>;
+		vdda-supply = <&pm8937_l2>;
+		vddio-supply = <&pm8937_l6>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_dsi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 1000>;
+
+		ranges = <0x1a94000 0x1a94000 0x300
+			0x1a94400 0x1a94400 0x280
+			0x1a94b80 0x1a94b80 0x30
+			0x193e000 0x193e000 0x30
+			0x1a96000 0x1a96000 0x300
+			0x1a96400 0x1a96400 0x280
+			0x1a96b80 0x1a96b80 0x30
+			0x193e000 0x193e000 0x30>;
+
+		clocks = <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			<&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc clk_gcc_mdss_axi_clk>,
+			<&clock_gcc_mdss clk_ext_byte0_clk_src>,
+			<&clock_gcc_mdss clk_ext_byte1_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk0_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk1_clk_src>;
+		clock-names = "mdp_core_clk", "iface_clk", "bus_clk",
+			"ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk",
+			"ext_pixel1_clk";
+
+		qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+		qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+		qcom,mdss-fb-map-prim = <&mdss_fb0>;
+		qcom,mdss-fb-map-sec = <&mdss_fb2>;
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-post-on-sleep = <20>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+
+		mdss_dsi0: qcom,mdss_dsi_ctrl0@1a94000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->0";
+			cell-index = <0>;
+			reg = <0x1a94000 0x300>,
+				<0x1a94400 0x280>,
+				<0x1a94b80 0x30>,
+				<0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy",
+			      "dsi_phy_regulator", "mmss_misc_phys";
+
+			qcom,timing-db-mode;
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8937_l17>;
+			vddio-supply = <&pm8937_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+				<&clock_gcc clk_gcc_mdss_esc0_clk>,
+				<&clock_gcc_mdss clk_byte0_clk_src>,
+				<&clock_gcc_mdss clk_pclk0_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg";
+
+			qcom,platform-strength-ctrl = [ff 06];
+			qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+			qcom,platform-regulator-settings = [03 08 07 00
+				20 07 01];
+			qcom,platform-lane-config = [01 c0 00 00 00 00 00 01 97
+				01 c0 00 00 05 00 00 01 97
+				01 c0 00 00 0a 00 00 01 97
+				01 c0 00 00 0f 00 00 01 97
+				00 40 00 00 00 00 00 01 ff];
+		};
+
+		mdss_dsi1: qcom,mdss_dsi_ctrl1@1a96000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->1";
+			cell-index = <1>;
+			reg = <0x1a96000 0x300>,
+			      <0x1a96400 0x280>,
+			      <0x1a94b80 0x30>,
+			      <0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy",
+			      "dsi_phy_regulator", "mmss_misc_phys";
+
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8937_l17>;
+			vddio-supply = <&pm8937_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte1_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk1_clk>,
+				<&clock_gcc clk_gcc_mdss_esc1_clk>,
+				<&clock_gcc_mdss clk_byte1_clk_src>,
+				<&clock_gcc_mdss clk_pclk1_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg";
+
+			qcom,platform-strength-ctrl = [ff 06];
+			qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+			qcom,platform-regulator-settings = [03 08 07 00
+				20 07 01];
+			qcom,platform-lane-config = [01 c0 00 00 00 00 00 01 97
+				01 c0 00 00 05 00 00 01 97
+				01 c0 00 00 0a 00 00 01 97
+				01 c0 00 00 0f 00 00 01 97
+				00 40 00 00 00 00 00 01 ff];
+
+		};
+
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 640>;
+		qcom,mdss_pan_bpp = <24>;
+		qcom,mdss-fb-map = <&mdss_fb1>;
+	};
+
+	mdss_rotator: qcom,mdss_rotator {
+		compatible = "qcom,mdss_rotator";
+		qcom,mdss-wb-count = <1>;
+		qcom,mdss-has-downscale;
+		qcom,mdss-has-ubwc;
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_rotator";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		rot-vdd-supply = <&gdsc_mdss>;
+		qcom,supply-names = "rot-vdd";
+		qcom,mdss-has-reg-bus;
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc_mdss clk_mdss_rotator_vote_clk>;
+		clock-names = "iface_clk", "rot_core_clk";
+
+		qcom,mdss-rot-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_rot_reg";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
new file mode 100644
index 0000000..f9af6cd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8937-pinctrl.dtsi"
+&blsp1_uart2 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart_console_active>;
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,pluggable;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
new file mode 100644
index 0000000..1b273ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
@@ -0,0 +1,1551 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8937-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&wakegpio>;
+		#interrupt-cells = <2>;
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+
+		i2c_2 {
+			i2c_2_active: i2c_2_active {
+				/* active state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "blsp_i2c2";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_2_sleep: i2c_2_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_3 {
+			i2c_3_active: i2c_3_active {
+				/* active state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "blsp_i2c3";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_3_sleep: i2c_3_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_5 {
+			i2c_5_active: i2c_5_active {
+				/* active state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "blsp_i2c5";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_5_sleep: i2c_5_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_rd_nfc_int {
+			/*qcom,pins = <&gp 17>;*/
+			pins = "gpio17";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_int";
+
+			nfc_int_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_int_suspend: suspend {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+		};
+
+		pmx_nfc_reset {
+			/*qcom,pins = <&gp 16>;*/
+			pins = "gpio16";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_disable";
+
+			nfc_disable_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_disable_suspend: suspend {
+				drive-strength = <6>;
+				bias-disable;
+			};
+		};
+
+		tlmm_pmi_flash_led {
+			rear_flash_led_enable: rear_flash_led_enable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			rear_flash_led_disable: rear_flash_led_disable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+
+			front_flash_led_enable: front_flash_led_enable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			front_flash_led_disable: front_flash_led_disable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+		};
+
+		spi3 {
+			spi3_default: spi3_default {
+				/* active state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable = <0>; /* No PULL */
+				};
+			};
+
+			spi3_sleep: spi3_sleep {
+				/* suspended state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+
+			spi3_cs0_active: cs0_active {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi3_cs0_sleep: cs0_sleep {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+		};
+
+		wcnss_pmux_5wire {
+			/* Active configuration of bus pins */
+			wcnss_default: wcnss_default {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+
+			wcnss_sleep: wcnss_sleep {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+		};
+
+		wcnss_pmux_gpio: wcnss_pmux_gpio {
+			wcnss_gpio_default: wcnss_gpio_default {
+				/* Active configuration of bus pins */
+				mux {
+					/* Uses general purpose pins */
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					       function = "gpio";
+
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+		};
+
+		cdc_mclk2_pin {
+			cdc_mclk2_sleep: cdc_mclk2_sleep {
+				mux {
+					pins = "gpio66";
+					function = "pri_mi2s";
+				};
+				config {
+					pins = "gpio66";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down;       /* PULL DOWN */
+				};
+			};
+			cdc_mclk2_active: cdc_mclk2_active {
+				mux {
+					pins = "gpio66";
+					function = "pri_mi2s";
+				};
+				config {
+					pins = "gpio66";
+					drive-strength = <8>; /* 8 mA */
+					bias-disable;         /* NO PULL */
+				};
+			};
+		};
+
+		blsp2_uart1_active: blsp2_uart1_active {
+			mux {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				function = "blsp_uart5";
+			};
+
+			config {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		blsp2_uart1_sleep: blsp2_uart1_sleep {
+			mux {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		pmx_adv7533_int: pmx_adv7533_int {
+			adv7533_int_active: adv7533_int_active {
+				mux {
+					pins = "gpio126";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio126";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+
+			adv7533_int_suspend: adv7533_int_suspend {
+				mux {
+					pins = "gpio126";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio126";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+
+		};
+
+		pmx_mdss: pmx_mdss {
+			mdss_dsi_active: mdss_dsi_active {
+				mux {
+					pins = "gpio60", "gpio98", "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98", "gpio99";
+					drive-strength = <8>; /* 8 mA */
+					bias-disable = <0>; /* no pull */
+					output-high;
+				};
+			};
+			mdss_dsi_suspend: mdss_dsi_suspend {
+				mux {
+					pins = "gpio60", "gpio98", "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98", "gpio99";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					input-enable;
+				};
+			};
+		};
+
+		pmx_mdss_te {
+			mdss_te_active: mdss_te_active {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 8 mA */
+					bias-pull-down; /* pull down*/
+				};
+			};
+
+			mdss_te_suspend: mdss_te_suspend {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		usbc_int_default: usbc_int_default {
+			mux {
+				pins = "gpio97", "gpio131";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio97", "gpio131";
+				drive-strength = <2>;
+				bias-pull-up;
+			};
+		};
+
+		tlmm_gpio_key {
+			gpio_key_active: gpio_key_active {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			gpio_key_suspend: gpio_key_suspend {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		/* add pingrp for touchscreen */
+		pmx_ts_int_active {
+			ts_int_active: ts_int_active {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_int_suspend {
+			ts_int_suspend: ts_int_suspend {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_reset_active {
+			ts_reset_active: ts_reset_active {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_reset_suspend {
+			ts_reset_suspend: ts_reset_suspend {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_release {
+			ts_release: ts_release {
+				mux {
+					pins = "gpio65", "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_qdsd_clk {
+			qdsd_clk_sdcard: clk_sdcard {
+				config {
+					pins = "qdsd_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+			qdsd_clk_trace: clk_trace {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_swdtrc: clk_swdtrc {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_spmi: clk_spmi {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_cmd {
+			qdsd_cmd_sdcard: cmd_sdcard {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_trace: cmd_trace {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swduart: cmd_uart {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swdtrc: cmd_swdtrc {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+
+			qdsd_cmd_jtag: cmd_jtag {
+				config {
+					pins = "qdsd_cmd";
+					bias-disable; /* NO pull */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_spmi: cmd_spmi {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data0 {
+			qdsd_data0_sdcard: data0_sdcard {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_trace: data0_trace {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_swduart: data0_uart {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_swdtrc: data0_swdtrc {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_jtag: data0_jtag {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_spmi: data0_spmi {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data1 {
+			qdsd_data1_sdcard: data1_sdcard {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_trace: data1_trace {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_swduart: data1_uart {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_swdtrc: data1_swdtrc {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_jtag: data1_jtag {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data2 {
+			qdsd_data2_sdcard: data2_sdcard {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_trace: data2_trace {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_swduart: data2_uart {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_swdtrc: data2_swdtrc {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_jtag: data2_jtag {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-up; /* pull up */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data3 {
+			qdsd_data3_sdcard: data3_sdcard {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_trace: data3_trace {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_swduart: data3_uart {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_swdtrc: data3_swdtrc {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_jtag: data3_jtag {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_spmi: data3_spmi {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_rclk {
+			sdc1_rclk_on: sdc1_rclk_on {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+
+			sdc1_rclk_off: sdc1_rclk_off {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		wcd9xxx_intr {
+			wcd_intr_default: wcd_intr_default{
+				mux {
+					pins = "gpio73";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio73";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					input-enable;
+				};
+			};
+		};
+
+		cdc_reset_ctrl {
+			cdc_reset_sleep: cdc_reset_sleep {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-disable;
+					output-low;
+				};
+			};
+			cdc_reset_active:cdc_reset_active {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		cdc-pdm-2-lines {
+			cdc_pdm_lines_2_act: pdm_lines_2_on {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <8>;
+				};
+			};
+
+			cdc_pdm_lines_2_sus: pdm_lines_2_off {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cdc-pdm-lines {
+			cdc_pdm_lines_act: pdm_lines_on {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <8>;
+				};
+			};
+			cdc_pdm_lines_sus: pdm_lines_off {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cross-conn-det {
+			cross_conn_det_act: lines_on {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <8>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+
+			cross_conn_det_sus: lines_off {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA VI sense */
+		wsa-vi {
+			wsa_vi_on: wsa_vi_on {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <8>; /* 8 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			wsa_vi_off: wsa_vi_off {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA Reset */
+		wsa_reset {
+			wsa_reset_on: wsa_reset_on {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-high;
+				};
+			};
+
+			wsa_reset_off: wsa_reset_off {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+				};
+			};
+		};
+
+		/* WSA CLK */
+		wsa_clk {
+			wsa_clk_on: wsa_clk_on {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <8>; /* 8 MA */
+					output-high;
+				};
+			};
+
+			wsa_clk_off: wsa_clk_off {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+					bias-pull-down;
+				};
+			};
+		};
+		pri-tlmm-lines {
+			pri_tlmm_lines_act: pri_tlmm_lines_act {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <8>;
+				};
+			};
+
+			pri_tlmm_lines_sus: pri_tlmm_lines_sus {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pri-tlmm-ws-lines {
+			pri_tlmm_ws_act: pri_tlmm_ws_act {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <8>;
+				};
+			};
+
+			pri_tlmm_ws_sus: pri_tlmm_ws_sus {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_sdc1_clk {
+			sdc1_clk_on: sdc1_clk_on {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc1_clk_off: sdc1_clk_off {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_cmd {
+			sdc1_cmd_on: sdc1_cmd_on {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_cmd_off: sdc1_cmd_off {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_data {
+			sdc1_data_on: sdc1_data_on {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_data_off: sdc1_data_off {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		sdhc2_cd_pin {
+			sdc2_cd_on: cd_on {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			sdc2_cd_off: cd_off {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_sdc2_clk {
+			sdc2_clk_on: sdc2_clk_on {
+				config {
+					pins = "sdc2_clk";
+					drive-strength = <16>; /* 16 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			sdc2_clk_off: sdc2_clk_off {
+				config {
+					pins = "sdc2_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_cmd {
+			sdc2_cmd_on: sdc2_cmd_on {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc2_cmd_off: sdc2_cmd_off {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_data {
+			sdc2_data_on: sdc2_data_on {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc2_data_off: sdc2_data_off {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			 };
+		};
+
+		cci {
+			cci0_active: cci0_active {
+				/* cci0 active state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio29", "gpio30";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci0_suspend: cci0_suspend {
+				/* cci0 suspended state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio29", "gpio30";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci1_active: cci1_active {
+				/* cci1 active state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio31", "gpio32";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci1_suspend: cci1_suspend {
+				/* cci1 suspended state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio31", "gpio32";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		/*sensors */
+		cam_sensor_mclk0_default: cam_sensor_mclk0_default {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_default: cam_sensor_rear_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio36", "gpio35";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio36","gpio35";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_sleep: cam_sensor_rear_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio36","gpio35";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio36","gpio35";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_vdig: cam_sensor_rear_vdig {
+			/* VDIG */
+			mux {
+				pins = "gpio62";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio62";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_vdig_sleep: cam_sensor_rear_vdig_sleep {
+			/* VDIG */
+			mux {
+				pins = "gpio62";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio62";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_default: cam_sensor_mclk1_default {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_default: cam_sensor_front_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio38","gpio50";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio38","gpio50";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_sleep: cam_sensor_front_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio38","gpio50";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio38","gpio50";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk2_default: cam_sensor_mclk2_default {
+			/* MCLK2 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio28";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio28";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk2_sleep: cam_sensor_mclk2_sleep {
+			/* MCLK2 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio28";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio28";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front1_default: cam_sensor_front1_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio40", "gpio39";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio40", "gpio39";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front1_sleep: cam_sensor_front1_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio40", "gpio39";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio40", "gpio39";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi
new file mode 100644
index 0000000..463ba63
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pm.dtsi
@@ -0,0 +1,268 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/pm.h>
+
+&soc {
+	qcom,spm@b1d2000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb1d2000 0x1000>;
+		qcom,name = "system-cci";
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0xe>;
+		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3
+				&CPU4 &CPU5 &CPU6 &CPU7>;
+		qcom,vctl-timeout-us = <500>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		qcom,use-psci;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,pm-cluster@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			label = "system";
+			qcom,psci-mode-shift = <8>;
+			qcom,psci-mode-mask = <0xf>;
+
+			qcom,pm-cluster-level@0{
+				reg = <0>;
+				label = "system-active";
+				qcom,psci-mode = <0>;
+				qcom,latency-us = <415>;
+				qcom,ss-power = <405>;
+				qcom,energy-overhead = <558549>;
+				qcom,time-overhead = <980>;
+			};
+
+			qcom,pm-cluster-level@1{
+				reg = <1>;
+				label = "system-wfi";
+				qcom,psci-mode = <1>;
+				qcom,latency-us = <475>;
+				qcom,ss-power = <346>;
+				qcom,energy-overhead = <718929>;
+				qcom,time-overhead = <1050>;
+				qcom,min-child-idx = <1>;
+			};
+
+			qcom,pm-cluster-level@2{
+				reg = <2>;
+				label = "system-ret";
+				qcom,psci-mode = <2>;
+				qcom,latency-us = <900>;
+				qcom,ss-power = <320>;
+				qcom,energy-overhead = <918687>;
+				qcom,time-overhead = <1250>;
+				qcom,min-child-idx = <1>;
+				qcom,reset-level = <LPM_RESET_LVL_RET>;
+			};
+
+			qcom,pm-cluster-level@3{
+				reg = <3>;
+				label = "system-pc";
+				qcom,psci-mode = <3>;
+				qcom,latency-us = <10782>;
+				qcom,ss-power = <306>;
+				qcom,energy-overhead = <1060040>;
+				qcom,time-overhead = <1426>;
+				qcom,min-child-idx = <2>;
+				qcom,notify-rpm;
+				qcom,is-reset;
+				qcom,reset-level = <LPM_RESET_LVL_PC>;
+			};
+
+			qcom,pm-cluster@0{
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				label = "perf";
+				qcom,psci-mode-shift = <4>;
+				qcom,psci-mode-mask = <0xf>;
+
+				qcom,pm-cluster-level@0{
+					reg = <0>;
+					label = "perf-l2-wfi";
+					qcom,psci-mode = <1>;
+					qcom,latency-us = <210>;
+					qcom,ss-power = <472>;
+					qcom,energy-overhead = <233383>;
+					qcom,time-overhead = <326>;
+				};
+
+				qcom,pm-cluster-level@1{
+					reg = <1>;
+					label = "perf-l2-gdhs";
+					qcom,psci-mode = <4>;
+					qcom,latency-us = <267>;
+					qcom,ss-power = <435>;
+					qcom,energy-overhead = <388012>;
+					qcom,time-overhead = <627>;
+					qcom,min-child-idx = <1>;
+					qcom,reset-level = <LPM_RESET_LVL_GDHS>;
+				};
+
+				qcom,pm-cluster-level@2{
+					reg = <2>;
+					label = "perf-l2-pc";
+					qcom,psci-mode = <5>;
+					qcom,latency-us = <305>;
+					qcom,ss-power = <405>;
+					qcom,energy-overhead = <564794>;
+					qcom,time-overhead = <879>;
+					qcom,min-child-idx = <1>;
+					qcom,is-reset;
+					qcom,reset-level = <LPM_RESET_LVL_PC>;
+				};
+
+				qcom,pm-cpu {
+					#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 {
+						reg = <0>;
+						qcom,psci-cpu-mode = <0>;
+						label = "wfi";
+						qcom,latency-us = <1>;
+						qcom,ss-power = <530>;
+						qcom,energy-overhead = <62806>;
+						qcom,time-overhead = <67>;
+					};
+
+					qcom,pm-cpu-level@1 {
+						reg = <1>;
+						qcom,psci-cpu-mode = <3>;
+						label = "pc";
+						qcom,latency-us = <190>;
+						qcom,ss-power = <472>;
+						qcom,energy-overhead = <233383>;
+						qcom,time-overhead = <326>;
+						qcom,use-broadcast-timer;
+						qcom,is-reset;
+						qcom,reset-level =
+							<LPM_RESET_LVL_PC>;
+					};
+				};
+			};
+
+			qcom,pm-cluster@1{
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				label = "pwr";
+				qcom,psci-mode-shift = <4>;
+				qcom,psci-mode-mask = <0xf>;
+
+				qcom,pm-cluster-level@0{
+					reg = <0>;
+					label = "pwr-l2-wfi";
+					qcom,psci-mode = <1>;
+					qcom,latency-us = <221>;
+					qcom,ss-power = <460>;
+					qcom,energy-overhead = <219499>;
+					qcom,time-overhead = <400>;
+				};
+
+				qcom,pm-cluster-level@1{
+					reg = <1>;
+					label = "pwr-l2-gdhs";
+					qcom,psci-mode = <4>;
+					qcom,latency-us = <337>;
+					qcom,ss-power = <433>;
+					qcom,energy-overhead = <372429>;
+					qcom,time-overhead = <717>;
+					qcom,min-child-idx = <1>;
+					qcom,reset-level =
+						<LPM_RESET_LVL_GDHS>;
+				};
+
+				qcom,pm-cluster-level@2{
+					reg = <2>;
+					label = "pwr-l2-pc";
+					qcom,psci-mode = <5>;
+					qcom,latency-us = <415>;
+					qcom,ss-power = <405>;
+					qcom,energy-overhead = <558549>;
+					qcom,time-overhead = <980>;
+					qcom,min-child-idx = <1>;
+					qcom,is-reset;
+					qcom,reset-level =
+						<LPM_RESET_LVL_PC>;
+				};
+
+				qcom,pm-cpu {
+					#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 {
+						reg = <0>;
+						qcom,psci-cpu-mode = <0>;
+						label = "wfi";
+						qcom,latency-us = <1>;
+						qcom,ss-power = <540>;
+						qcom,energy-overhead = <93024>;
+						qcom,time-overhead = <57>;
+					};
+
+					qcom,pm-cpu-level@1 {
+						reg = <1>;
+						qcom,psci-cpu-mode = <3>;
+						label = "pc";
+						qcom,latency-us = <221>;
+						qcom,ss-power = <460>;
+						qcom,energy-overhead = <219499>;
+						qcom,time-overhead = <400>;
+						qcom,use-broadcast-timer;
+						qcom,is-reset;
+						qcom,reset-level =
+							<LPM_RESET_LVL_PC>;
+					};
+				};
+			};
+		};
+	};
+
+	qcom,rpm-stats@200000 {
+		compatible = "qcom,rpm-stats";
+		reg = <0x200000 0x1000>,
+		      <0x290014 0x4>,
+		      <0x29001c 0x4>;
+		reg-names = "phys_addr_base", "offset_addr",
+						"heap_phys_addrbase";
+		qcom,sleep-stats-version = <2>;
+	};
+
+	qcom,rpm-master-stats@60150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0x60150 0x5000>;
+		qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <4096>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts
new file mode 100644
index 0000000..b841a44
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8937.dtsi"
+#include "msm8937-pmi8950-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937-PMI8950 MTP";
+	compatible = "qcom,msm8937-mtp", "qcom,msm8937", "qcom,mtp";
+	qcom,board-id= <8 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
new file mode 100644
index 0000000..1afa230
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "pmi8950.dtsi"
+#include "msm8937-mtp.dtsi"
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+	/delete-property/ dpdm-supply;
+};
+
+&usb_otg {
+	extcon = <&qpnp_smbcharger>;
+};
+
+&labibb {
+	status = "ok";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+	qcom,qpnp-ibb-discharge-resistor = <32>;
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
new file mode 100644
index 0000000..d5537e9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
@@ -0,0 +1,229 @@
+/* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+&soc {
+	qcom,smp2p-modem@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from wcnss. */
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to wcnss */
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
new file mode 100644
index 0000000..b498236
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -0,0 +1,1888 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "skeleton64.dtsi"
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/msm-clocks-8952.h>
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937";
+	compatible = "qcom,msm8937";
+	qcom,msm-id = <294 0x0>;
+	interrupt-parent = <&wakegic>;
+
+	chosen {
+		bootargs = "sched_enable_hmp=1";
+	};
+
+	firmware: firmware {
+		android {
+			compatible = "android,firmware";
+			fstab {
+				compatible = "android,fstab";
+				vendor {
+					compatible = "android,vendor";
+					dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
+					type = "ext4";
+					mnt_flags = "ro,barrier=1,discard";
+					fsmgr_flags = "wait";
+					status = "ok";
+				};
+				system {
+					compatible = "android,system";
+					dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
+					type = "ext4";
+					mnt_flags = "ro,barrier=1,discard";
+					fsmgr_flags = "wait";
+					status = "ok";
+				};
+
+			};
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		other_ext_mem: other_ext_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x85b00000 0x0 0xd00000>;
+		};
+
+		modem_mem: modem_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x86800000 0x0 0x5000000>;
+		};
+
+		adsp_fw_mem: adsp_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8b800000 0x0 0x1100000>;
+		};
+
+		wcnss_fw_mem: wcnss_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8c900000 0x0 0x700000>;
+		};
+
+
+		venus_mem: venus_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+			alignment = <0 0x400000>;
+			size = <0 0x0800000>;
+		};
+
+		secure_mem: secure_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x7000000>;
+		};
+
+		qseecom_mem: qseecom_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x1000000>;
+		};
+
+		qseecom_ta_mem: qseecom_ta_region {
+			 compatible = "shared-dma-pool";
+			 alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			 reusable;
+			 alignment = <0 0x400000>;
+			 size = <0 0x1000000>;
+		};
+
+		adsp_mem: adsp_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
+		cont_splash_mem: splash_region@83000000 {
+			reg = <0x0 0x90000000 0x0 0x1400000>;
+		};
+
+	};
+
+	aliases {
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd4 = &smdtty_mbalbridge;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd8 = &smdtty_data4;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd36 = &smdtty_loopback;
+		i2c2 = &i2c_2;
+		i2c5 = &i2c_5;
+		spi3 = &spi_3;
+		i2c3 = &i2c_3;
+		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+		sdhc2 = &sdhc_2; /* SDC2 for SD card */
+	};
+
+	soc: soc { };
+
+	vendor: vendor {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0xffffffff>;
+		compatible = "simple-bus";
+	};
+
+
+};
+
+#include "msm8937-pinctrl.dtsi"
+#include "msm8937-cpu.dtsi"
+#include "msm8937-ion.dtsi"
+#include "msm-arm-smmu-8937.dtsi"
+#include "msm8937-smp2p.dtsi"
+#include "msm8937-bus.dtsi"
+#include "msm8937-pm.dtsi"
+#include "msm8937-gpu.dtsi"
+#include "msm8937-mdss.dtsi"
+#include "msm8937-mdss-pll.dtsi"
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0 0 0xffffffff>;
+	compatible = "simple-bus";
+
+	intc: interrupt-controller@b000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		interrupt-parent = <&intc>;
+		#interrupt-cells = <3>;
+		reg = <0x0b000000 0x1000>,
+		      <0x0b002000 0x1000>;
+	};
+
+	wakegic: wake-gic {
+		compatible = "qcom,mpm-gic-msm8937", "qcom,mpm-gic";
+		interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+		reg = <0x601d0 0x1000>,
+			<0xb011008 0x4>;  /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		qcom,num-mpm-irqs = <96>;
+		interrupt-controller;
+		interrupt-parent = <&intc>;
+		#interrupt-cells = <3>;
+	};
+
+	wakegpio: wake-gpio {
+		compatible = "qcom,mpm-gpio-msm8937", "qcom,mpm-gpio";
+		interrupt-controller;
+		interrupt-parent = <&intc>;
+		#interrupt-cells = <2>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 2 0xff08>,
+			     <1 3 0xff08>,
+			     <1 4 0xff08>,
+			     <1 1 0xff08>;
+		clock-frequency = <19200000>;
+	};
+
+	timer@b120000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xb120000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@b121000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xb121000 0x1000>,
+			      <0xb122000 0x1000>;
+		};
+
+		frame@b123000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xb123000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b124000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xb124000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b125000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xb125000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b126000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xb126000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b127000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xb127000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b128000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xb128000 0x1000>;
+			status = "disabled";
+		};
+	};
+
+	qcom,rmtfs_sharedmem@00000000 {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x00000000 0x00180000>;
+		reg-names = "rmtfs";
+		qcom,client-id = <0x00000001>;
+	};
+
+	restart@4ab000 {
+		compatible = "qcom,pshold";
+		reg = <0x4ab000 0x4>,
+			<0x193d100 0x4>;
+		reg-names = "pshold-base", "tcsr-boot-misc-detect";
+	};
+
+	qcom,mpm2-sleep-counter@4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0x4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
+	cpu-pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <1 7 0xff00>;
+	};
+
+	qcom,sps {
+		compatible = "qcom,msm_sps_4k";
+		qcom,pipe-attr-ee;
+	};
+
+	thermal_zones: thermal-zones {
+		aoss0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 0>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		mdm-core-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 1>;
+			trips {
+				active-config0 {
+						temperature = <125000>;
+						hysteresis = <1000>;
+						type = "passive";
+				};
+			};
+		};
+
+		mdss-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 2>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		camera-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 3>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		cpuss-0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 4>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu1-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 5>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu2-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 6>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu3-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 7>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu4-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 8>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc0_cpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 9>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		gpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 10>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+	};
+
+	tsens0: tsens@4a8000 {
+		compatible = "qcom,msm8937-tsens";
+		reg = <0x4a8000 0x1000>,
+			<0x4a9000 0x1000>,
+			<0xa4000  0x1000>;
+		reg-names = "tsens_srot_physical",
+			"tsens_tm_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		interrupt-names = "tsens-upper-lower";
+		#thermal-sensor-cells = <1>;
+	};
+
+	slim_msm: slim@c140000{
+		cell-index = <1>;
+		compatible = "qcom,slim-ngd";
+		reg = <0xc140000 0x2c000>,
+		      <0xc104000 0x2a000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0>, <0 180 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,apps-ch-pipes = <0x600000>;
+		qcom,ea-pc = <0x230>;
+		status = "disabled";
+	};
+
+	blsp1_uart2: serial@78b0000 {
+		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+		reg = <0x78b0000 0x200>;
+		interrupts = <0 108 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+		<&clock_gcc clk_gcc_blsp1_ahb_clk>;
+		clock-names = "core", "iface";
+		status = "disabled";
+	};
+
+	dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7884000 0x1f000>;
+		interrupts = <0 238 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	dma_blsp2: qcom,sps-dma@7ac4000 { /* BLSP2 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7ac4000 0x1f000>;
+		interrupts = <0 239 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	clock_gcc: qcom,gcc@1800000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "qcom,gcc-8937";
+		reg = <0x1800000 0x80000>,
+			<0xb016000 0x00040>,
+			<0xb116000 0x00040>,
+			<0x00a6018 0x00004>;
+		reg-names = "cc_base", "apcs_c1_base",
+				"apcs_c0_base", "efuse";
+		vdd_dig-supply = <&pm8937_s2_level>;
+		vdd_sr2_dig-supply = <&pm8937_s2_level_ao>;
+		vdd_sr2_pll-supply = <&pm8937_l7_ao>;
+		vdd_hf_dig-supply = <&pm8937_s2_level_ao>;
+		vdd_hf_pll-supply = <&pm8937_l7_ao>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+		ranges;
+		qcom,spm@0 {
+			compatible = "qcom,gcc-spm-8937";
+			reg = <0x0b111200 0x100>,
+				<0x0b011200 0x100>;
+			reg-names = "spm_c0_base", "spm_c1_base";
+		};
+	};
+
+	clock_debug: qcom,cc-debug@1874000 {
+		compatible = "qcom,cc-debug-8937";
+		reg = <0x1874000 0x4>,
+			<0xb11101c 0x8>;
+		reg-names = "cc_base", "meas";
+		#clock-cells = <1>;
+	};
+
+	clock_gcc_mdss: qcom,gcc-mdss@1800000 {
+		compatible = "qcom,gcc-mdss-8937";
+		clocks = <&mdss_dsi0_pll clk_dsi_pll0_pixel_clk_src>,
+			 <&mdss_dsi0_pll clk_dsi_pll0_byte_clk_src>,
+			 <&mdss_dsi1_pll clk_dsi_pll1_pixel_clk_src>,
+			 <&mdss_dsi1_pll clk_dsi_pll1_byte_clk_src>;
+		clock-names = "pclk0_src", "byte0_src", "pclk1_src",
+			"byte1_src";
+		#clock-cells = <1>;
+	};
+
+	clock_cpu: qcom,cpu-clock-8939@b111050 {
+		compatible = "qcom,cpu-clock-8939";
+		reg =   <0xb011050 0x8>,
+			<0xb111050 0x8>,
+			<0xb1d1050 0x8>,
+			<0x00a412c 0x8>;
+		reg-names = "apcs-c1-rcg-base", "apcs-c0-rcg-base",
+				"apcs-cci-rcg-base", "efuse";
+		vdd-c0-supply = <&apc_vreg_corner>;
+		vdd-c1-supply = <&apc_vreg_corner>;
+		vdd-cci-supply = <&apc_vreg_corner>;
+		clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_a53ss_c0_pll>,
+			<&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_a53ss_c1_pll>,
+			<&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_gpll0_ao_clk_src>;
+		clock-names = "clk-c0-4", "clk-c0-5",
+				"clk-c1-4", "clk-c1-5",
+				"clk-cci-4", "clk-cci-2";
+		qcom,speed0-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 4>,
+			< 1094400000 6>;
+
+		qcom,speed0-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1248000000 4>,
+			< 1344000000 5>,
+			< 1401000000 6>;
+
+		qcom,speed0-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+
+		qcom,speed1-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 4>,
+			< 1094400000 6>,
+			< 1209600000 7>;
+
+		qcom,speed1-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1248000000 4>,
+			< 1344000000 5>,
+			< 1401000000 6>,
+			< 1497600000 7>;
+
+		qcom,speed1-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+
+		qcom,speed2-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 3>;
+
+		qcom,speed2-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1209600000 3>;
+
+		qcom,speed2-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+		#clock-cells = <1>;
+	};
+
+	i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b6000 0x600>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 96 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_2_active>;
+		pinctrl-1 = <&i2c_2_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		qcom,master-id = <86>;
+		dmas = <&dma_blsp1 6 64 0x20000020 0x20>,
+			<&dma_blsp1 7 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		status = "disabled";
+	};
+
+	i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x78b7000 0x600>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 97 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_3_active>;
+		pinctrl-1 = <&i2c_3_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		qcom,master-id = <86>;
+		dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+			<&dma_blsp1 9 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		status = "disabled";
+	};
+
+	i2c_5: i2c@7af5000 { /* BLSP2 QUP1 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x7af5000 0x600>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 299 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp2_qup1_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_5_active>;
+		pinctrl-1 = <&i2c_5_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		qcom,master-id = <84>;
+		dmas = <&dma_blsp2 4 64 0x20000020 0x20>,
+			<&dma_blsp2 5 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		status = "disabled";
+	};
+
+	spi_3: spi@78b7000 { /* BLSP1 QUP3 */
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0x78b7000 0x600>,
+			<0x7884000 0x1f000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 97 0>, <0 238 0>;
+		spi-max-frequency = <19200000>;
+		pinctrl-names = "spi_default", "spi_sleep";
+		pinctrl-0 = <&spi3_default &spi3_cs0_active>;
+		pinctrl-1 = <&spi3_sleep &spi3_cs0_sleep>;
+		clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,use-pinctrl;
+		qcom,ver-reg-exists;
+		qcom,bam-consumer-pipe-index = <8>;
+		qcom,bam-producer-pipe-index = <9>;
+		qcom,master-id = <86>;
+		status = "disabled";
+	};
+
+	msm_cpufreq: qcom,msm-cpufreq {
+		compatible = "qcom,msm-cpufreq";
+		clock-names = "l2_clk", "cpu0_clk", "cpu1_clk", "cpu2_clk",
+				"cpu3_clk", "cpu4_clk", "cpu5_clk",
+				"cpu6_clk", "cpu7_clk";
+		clocks = <&clock_cpu clk_cci_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_lc_clk>,
+			 <&clock_cpu clk_a53_lc_clk>,
+			 <&clock_cpu clk_a53_lc_clk>,
+			 <&clock_cpu clk_a53_lc_clk>;
+
+		qcom,governor-per-policy;
+
+		qcom,cpufreq-table-0 =
+			 <  960000 >,
+			 < 1094400 >,
+			 < 1209600 >,
+			 < 1248000 >,
+			 < 1344000 >,
+			 < 1401000 >,
+			 < 1497600 >;
+
+		qcom,cpufreq-table-4 =
+			 <  768000 >,
+			 <  902400 >,
+			 <  998400 >,
+			 < 1094400 >,
+			 < 1209600 >;
+	};
+
+	cci_cache: qcom,cci {
+		compatible = "devfreq-simple-dev";
+		clock-names = "devfreq_clk";
+		clocks = <&clock_cpu clk_cci_clk>;
+		governor = "cpufreq";
+		freq-tbl-khz =
+			<  400000 >,
+			<  533333 >;
+	};
+
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2124 /*  278.4 MHz */ >,
+			<  2929 /*  384   MHz */ >,	/* SVS	*/
+			<  4101 /*  537.6 MHz */ >,
+			<  4248 /*  556.8 MHz */ >,
+			<  5053 /*  662.4 MHz */ >,	/* SVS+	 */
+			<  5712 /*  748.8 MHz */ >,     /* NOM   */
+			<  6152 /*  806.4 MHz */ >,     /* NOM+  */
+			<  7031 /*  921.6 MHz */ >;     /* TURBO */
+	};
+
+	qcom,cpu-bwmon {
+		compatible = "qcom,bimc-bwmon2";
+		reg = <0x408000 0x300>, <0x401000 0x200>;
+		reg-names = "base", "global_base";
+		interrupts = <0 183 4>;
+		qcom,mport = <0>;
+		qcom,target-dev = <&cpubw>;
+	};
+
+	mincpubw: qcom,mincpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2124 /*  278.4 MHz */ >,
+			<  2929 /*  384   MHz */ >,	/* SVS	*/
+			<  4101 /*  537.6 MHz */ >,
+			<  4248 /*  556.8 MHz */ >,
+			<  5053 /*  662.4 MHz */ >,	/* SVS+	 */
+			<  5712 /*  748.8 MHz */ >,     /* NOM   */
+			<  6152 /*  806.4 MHz */ >,     /* NOM+  */
+			<  7031 /*  921.6 MHz */ >;     /* TURBO */
+	};
+
+	devfreq-cpufreq {
+		cpubw-cpufreq {
+		target-dev = <&cpubw>;
+		cpu-to-dev-map-0 =
+			<  998400  2929 >,      /* SVS   */
+			< 1094400  5053 >,	/* NOM   */
+			< 1248000  5712 >,	/* NOM+  */
+			< 1344000  7031 >,
+			< 1497600  7031 >;	/* TURBO */
+		cpu-to-dev-map-4 =
+			<  806400  2929 >,	/* SVS  */
+			<  902400  5053 >,	/* NOM   */
+			<  998400  6152 >,	/* NOM+  */
+			< 1209600  7031 >;	/* TURBO */
+		};
+
+		cci-cpufreq {
+		target-dev = <&cci_cache>;
+		cpu-to-dev-map-0 =
+			<  998400  400000 >,    /* SVS   */
+			< 1094400  400000 >,	/* NOM   */
+			< 1248000  533333 >,	/* NOM+  */
+			< 1344000  533333 >,
+			< 1497600  533333 >;	/* TURBO */
+		cpu-to-dev-map-4 =
+			<  806400  400000 >,	/* SVS  */
+			<  902400  400000 >,	/* NOM   */
+			<  998400  533333 >,	/* NOM+  */
+			< 1209600  533333 >;	/* TURBO */
+		};
+
+		mincpubw-cpufreq {
+			target-dev = <&mincpubw>;
+			cpu-to-dev-map-0 =
+				< 1094400 2929 >,
+				< 1497600 4248 >;
+			cpu-to-dev-map-4 =
+				<  998400 2929 >,
+				< 1209600 4248 >;
+		};
+	};
+
+	blsp2_uart1: uart@7aef000 {
+		compatible = "qcom,msm-hsuart-v14";
+		reg = <0x7aef000 0x200>,
+			<0x7ac4000 0x1f000>;
+		reg-names = "core_mem", "bam_mem";
+		interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+		#address-cells = <0>;
+		interrupt-parent = <&blsp2_uart1>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 306 0
+				1 &intc 0 239 0
+				2 &tlmm 17 0>;
+
+		qcom,inject-rx-on-wakeup;
+		qcom,rx-char-to-inject = <0xfd>;
+
+		qcom,bam-tx-ep-pipe-index = <0>;
+		qcom,bam-rx-ep-pipe-index = <1>;
+		qcom,master-id = <84>;
+		clock-names = "core_clk", "iface_clk";
+		clocks = <&clock_gcc clk_gcc_blsp2_uart1_apps_clk>,
+				<&clock_gcc clk_gcc_blsp2_ahb_clk>;
+		pinctrl-names = "sleep", "default";
+		pinctrl-0 = <&blsp2_uart1_sleep>;
+		pinctrl-1 = <&blsp2_uart1_active>;
+		qcom,msm-bus,name = "blsp2_uart1";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<84 512 0 0>,
+				<84 512 500 800>;
+		status = "disabled";
+	};
+
+	qcom,ipc-spinlock@1905000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0x1905000 0x8000>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@86300000 {
+		compatible = "qcom,smem";
+		reg = <0x86300000 0x100000>,
+			<0xb011008 0x4>,
+			<0x60000 0x8000>,
+			<0x193d000 0x8>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1",
+				"smem_targ_info_reg";
+		qcom,mpu-enabled;
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			interrupts = <0 25 1>;
+			label = "modem";
+			qcom,not-loadable;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			interrupts = <0 142 1>;
+			label = "wcnss";
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x100>;
+			interrupts = <0 289 1>;
+			label = "adsp";
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 290 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			label = "rpm";
+			qcom,irq-no-suspend;
+			qcom,not-loadable;
+		};
+	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	usb_otg: usb@78db000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0x78db000 0x400>, <0x6c000 0x200>;
+		reg-names = "core", "phy_csr";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		interrupts = <0 134 0>,<0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+
+		hsusb_vdd_dig-supply = <&pm8937_l2>;
+		HSUSB_1p8-supply = <&pm8937_l7>;
+		HSUSB_3p3-supply = <&pm8937_l13>;
+		qcom,vdd-voltage-level = <0 1200000 1200000>;
+		vbus_otg-supply = <&smbcharger_charger_otg>;
+
+		qcom,hsusb-otg-phy-type = <3>; /* SNPS Femto PHY */
+		qcom,hsusb-otg-mode = <3>; /* OTG mode */
+		qcom,hsusb-otg-otg-control = <2>; /* PMIC */
+		qcom,dp-manual-pullup;
+		qcom,phy-dvdd-always-on;
+		qcom,boost-sysclk-with-streaming;
+		qcom,axi-prefetch-enable;
+		qcom,hsusb-otg-delay-lpm;
+
+		qcom,msm-bus,name = "usb2";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<87 512 0 0>,
+				<87 512 80000 0>,
+				<87 512 6000  6000>;
+		clocks = <&clock_gcc clk_gcc_usb_hs_ahb_clk>,
+			 <&clock_gcc clk_gcc_usb_hs_system_clk>,
+			 <&clock_gcc clk_gcc_usb2a_phy_sleep_clk>,
+			 <&clock_gcc clk_bimc_usb_a_clk>,
+			 <&clock_gcc clk_snoc_usb_a_clk>,
+			 <&clock_gcc clk_pnoc_usb_a_clk>,
+			 <&clock_gcc clk_gcc_qusb2_phy_clk>,
+			 <&clock_gcc clk_gcc_usb2_hs_phy_only_clk>,
+			 <&clock_gcc clk_gcc_usb_hs_phy_cfg_ahb_clk>,
+			 <&clock_gcc clk_xo_otg_clk>;
+		clock-names = "iface_clk", "core_clk", "sleep_clk",
+				"bimc_clk", "snoc_clk", "pcnoc_clk",
+				"phy_reset_clk", "phy_por_clk", "phy_csr_clk",
+				"xo";
+		qcom,bus-clk-rate = <748800000 200000000 100000000>;
+		qcom,max-nominal-sysclk-rate = <133330000>;
+
+		resets = <&clock_gcc GCC_USB_HS_BCR>,
+			 <&clock_gcc GCC_QUSB2_PHY_BCR>,
+			 <&clock_gcc GCC_USB2_HS_PHY_ONLY_BCR>;
+		reset-names = "core_reset", "phy_reset", "phy_por_reset";
+
+		qcom,usbbam@78c4000 {
+			compatible = "qcom,usb-bam-msm";
+			reg = <0x78c4000 0x17000>;
+			interrupt-parent = <&intc>;
+			interrupts = <0 135 0>;
+
+			qcom,bam-type = <1>;
+			qcom,usb-bam-num-pipes = <4>;
+			qcom,usb-bam-fifo-baseaddr = <0x08605000>;
+			qcom,ignore-core-reset-ack;
+			qcom,disable-clk-gating;
+			qcom,usb-bam-max-mbps-highspeed = <400>;
+			qcom,reset-bam-on-disconnect;
+
+			qcom,pipe0 {
+				label = "hsusb-qdss-in-0";
+				qcom,usb-bam-mem-type = <2>;
+				qcom,dir = <1>;
+				qcom,pipe-num = <0>;
+				qcom,peer-bam = <0>;
+				qcom,peer-bam-physical-address = <0x6044000>;
+				qcom,src-bam-pipe-index = <0>;
+				qcom,dst-bam-pipe-index = <0>;
+				qcom,data-fifo-offset = <0x0>;
+				qcom,data-fifo-size = <0xe00>;
+				qcom,descriptor-fifo-offset = <0xe00>;
+				qcom,descriptor-fifo-size = <0x200>;
+			};
+		};
+	};
+
+	qcom,wdt@b017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xb017000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping;
+		qcom,wakeup-enable;
+		status = "okay";
+	};
+
+	spmi_bus: qcom,spmi@200f000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0x200f000 0x1000>,
+			<0x2400000 0x800000>,
+			<0x2c00000 0x800000>,
+			<0x3800000 0x200000>,
+			<0x200a000 0x2100>;
+		reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+		interrupt-names = "periph_irq";
+		interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+		qcom,ee = <0>;
+		qcom,channel = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-controller;
+		#interrupt-cells = <4>;
+		cell-index = <0>;
+	};
+
+	qcom,chd {
+		compatible = "qcom,core-hang-detect";
+		qcom,threshold-arr = <0xb088094 0xb098094 0xb0a8094
+			0xb0b8094 0xb188094 0xb198094 0xb1a8094 0xb1a8094>;
+		qcom,config-arr = <0xb08809c 0xb09809c 0xb0a809c
+			0xb0b809c 0xb18809c 0xb19809c 0xb1a809c 0xb1b809c>;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+	};
+
+	qcom,msm-imem@8600000 {
+		compatible = "qcom,msm-imem";
+		reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+		ranges = <0x0 0x08600000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		mem_dump_table@10 {
+			compatible = "qcom,msm-imem-mem_dump_table";
+			reg = <0x10 8>;
+		};
+
+		dload_type@18 {
+			compatible = "qcom,msm-imem-dload-type";
+			reg = <0x18 4>;
+		};
+
+		restart_reason@65c {
+			compatible = "qcom,msm-imem-restart_reason";
+			reg = <0x65c 4>;
+		};
+
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+
+		pil@94c {
+			compatible = "qcom,msm-imem-pil";
+			reg = <0x94c 200>;
+		};
+	};
+
+	qcom,memshare {
+		compatible = "qcom,memshare";
+
+		qcom,client_1 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x200000>;
+			qcom,client-id = <0>;
+			qcom,allocate-boot-time;
+			label = "modem";
+		};
+
+		qcom,client_2 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x300000>;
+			qcom,client-id = <2>;
+			label = "modem";
+		};
+
+		qcom,client_3 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x500000>;
+			qcom,client-id = <1>;
+			qcom,allocate-boot-time;
+			label = "modem";
+		};
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "MBALBRIDGE";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data4: qcom,smdtty-data4 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA4";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
+	qcom,smdpkt {
+		compatible = "qcom,smdpkt";
+
+		qcom,smdpkt-data5-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA5_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl0";
+		};
+
+		qcom,smdpkt-data22 {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA22";
+			qcom,smdpkt-dev-name = "smd22";
+		};
+
+		qcom,smdpkt-data40-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA40_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl8";
+		};
+
+		qcom,smdpkt-apr-apps2 {
+			qcom,smdpkt-remote = "adsp";
+			qcom,smdpkt-port-name = "apr_apps2";
+			qcom,smdpkt-dev-name = "apr_apps2";
+		};
+
+		qcom,smdpkt-loopback {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "LOOPBACK";
+			qcom,smdpkt-dev-name = "smd_pkt_loopback";
+		};
+	};
+
+	qcom_tzlog: tz-log@08600720 {
+		compatible = "qcom,tz-log";
+		reg = <0x08600720 0x2000>;
+	};
+
+	qcom,ipc_router {
+		compatible = "qcom,ipc_router";
+		qcom,node-id = <1>;
+	};
+
+	qcom,ipc_router_modem_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "modem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+		qcom,disable-pil-loading;
+	};
+
+	qcom,ipc_router_q6_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "adsp";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,ipc_router_wcnss_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "wcnss";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+	qcom,msm_fastrpc {
+		compatible = "qcom,msm-fastrpc-legacy-compute";
+		qcom,msm_fastrpc_compute_cb {
+			compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_iommu 0x2008 0x7>;
+			sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+		};
+	};
+
+	sdcc1_ice: sdcc1ice@7803000 {
+		compatible = "qcom,ice";
+		reg = <0x7803000 0x8000>;
+		interrupt-names = "sdcc_ice_nonsec_level_irq",
+				  "sdcc_ice_sec_level_irq";
+		interrupts = <0 312 0>, <0 313 0>;
+		qcom,enable-ice-clk;
+		clock-names = "ice_core_clk_src", "ice_core_clk",
+				"bus_clk", "iface_clk";
+		clocks = <&clock_gcc clk_sdcc1_ice_core_clk_src>,
+			 <&clock_gcc clk_gcc_sdcc1_ice_core_clk>,
+			 <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+			 <&clock_gcc clk_gcc_sdcc1_ahb_clk>;
+		qcom,op-freq-hz = <200000000>, <0>, <0>, <0>;
+		qcom,msm-bus,name = "sdcc_ice_noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<78 512 0 0>,    /* No vote */
+			<78 512 1000 0>; /* Max. bandwidth */
+		qcom,bus-vector-names = "MIN", "MAX";
+		qcom,instance-type = "sdcc";
+	};
+
+	sdhc_1: sdhci@7824900 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>;
+		reg-names = "hc_mem", "core_mem", "cmdq_mem";
+
+		interrupts = <0 123 0>, <0 138 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+
+		sdhc-msm-crypto = <&sdcc1_ice>;
+		qcom,bus-width = <8>;
+		qcom,large-address-bus;
+
+		qcom,devfreq,freq-table = <50000000 200000000>;
+
+		qcom,pm-qos-irq-type = "affine_irq";
+		qcom,pm-qos-irq-latency = <2 200>;
+
+		qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+		qcom,pm-qos-cmdq-latency-us = <2 200>, <2 200>;
+
+		qcom,pm-qos-legacy-latency-us = <2 200>, <2 200>;
+
+		qcom,msm-bus,name = "sdhc1";
+		qcom,msm-bus,num-cases = <9>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
+			<78 512 1046 3200>,    /* 400 KB/s*/
+			<78 512 52286 160000>, /* 20 MB/s */
+			<78 512 65360 200000>, /* 25 MB/s */
+			<78 512 130718 400000>, /* 50 MB/s */
+			<78 512 130718 400000>, /* 100 MB/s */
+			<78 512 261438 800000>, /* 200 MB/s */
+			<78 512 261438 800000>, /* 400 MB/s */
+			<78 512 1338562 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000
+			50000000 100000000 200000000 400000000 4294967295>;
+
+		clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>,
+			 <&clock_gcc clk_gcc_sdcc1_apps_clk>,
+			 <&clock_gcc clk_gcc_sdcc1_ice_core_clk>;
+		clock-names = "iface_clk", "core_clk", "ice_core_clk";
+		qcom,ice-clk-rates = <200000000 100000000>;
+
+		qcom,scaling-lower-bus-speed-mode = "DDR52";
+		status = "disabled";
+	};
+
+	sdhc_2: sdhci@7864900 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0x7864900 0x500>, <0x7864000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+
+		interrupts = <0 125 0>, <0 221 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+
+		qcom,bus-width = <4>;
+		qcom,large-address-bus;
+
+		qcom,pm-qos-irq-type = "affine_irq";
+		qcom,pm-qos-irq-latency = <2 200>;
+
+		qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+		qcom,pm-qos-legacy-latency-us = <2 200>, <2 200>;
+
+		qcom,msm-bus,name = "sdhc2";
+		qcom,msm-bus,num-cases = <8>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+			<81 512 1046 3200>,    /* 400 KB/s*/
+			<81 512 52286 160000>, /* 20 MB/s */
+			<81 512 65360 200000>, /* 25 MB/s */
+			<81 512 130718 400000>, /* 50 MB/s */
+			<81 512 261438 800000>, /* 100 MB/s */
+			<81 512 261438 800000>, /* 200 MB/s */
+			<81 512 1338562 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+			100000000 200000000 4294967295>;
+
+		qcom,devfreq,freq-table = <50000000 200000000>;
+		clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
+			<&clock_gcc clk_gcc_sdcc2_apps_clk>;
+		clock-names = "iface_clk", "core_clk";
+
+		status = "disabled";
+	};
+
+	qcom_seecom: qseecom@85b00000 {
+		compatible = "qcom,qseecom";
+		reg = <0x85b00000 0x800000>;
+		reg-names = "secapp-region";
+		qcom,hlos-num-ce-hw-instances = <1>;
+		qcom,hlos-ce-hw-instance = <0>;
+		qcom,qsee-ce-hw-instance = <0>;
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,support-fde;
+		qcom,msm-bus,name = "qseecom-noc";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,support-bus-scaling;
+		qcom,msm-bus,vectors-KBps =
+			<55 512 0 0>,
+			<55 512 0 0>,
+			<55 512 120000 1200000>,
+			<55 512 393600 3936000>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			<&clock_gcc clk_gcc_crypto_clk>,
+			<&clock_gcc clk_gcc_crypto_ahb_clk>,
+			<&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+			"iface_clk", "bus_clk";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	qcom_rng: qrng@e3000 {
+		compatible = "qcom,msm-rng";
+		reg = <0xe3000 0x1000>;
+		qcom,msm-rng-iface-clk;
+		qcom,no-qrng-config;
+		qcom,msm-bus,name = "msm-rng-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<1 618 0 0>,            /* No vote */
+			<1 618 0 800>;          /* 100 MB/s */
+		clocks = <&clock_gcc clk_gcc_prng_ahb_clk>;
+		clock-names = "iface_clk";
+	};
+
+	qcom_crypto: qcrypto@720000 {
+		compatible = "qcom,qcrypto";
+		reg = <0x720000 0x20000>,
+			<0x704000 0x20000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <2>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,ce-hw-shared;
+		qcom,clk-mgmt-sus-res;
+		qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 393600 393600>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		qcom,use-sw-aes-cbc-ecb-ctr-algo;
+		qcom,use-sw-aes-xts-algo;
+		qcom,use-sw-aes-ccm-algo;
+		qcom,use-sw-ahash-algo;
+		qcom,use-sw-hmac-algo;
+		qcom,use-sw-aead-algo;
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	qcom_cedev: qcedev@720000 {
+		compatible = "qcom,qcedev";
+		reg = <0x720000 0x20000>,
+			<0x704000 0x20000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <1>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,ce-hw-shared;
+		qcom,msm-bus,name = "qcedev-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 393600 393600>;
+		clocks = <&clock_gcc clk_crypto_clk_src>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		qcom,ce-opp-freq = <100000000>;
+	};
+
+	pil_mss: qcom,mss@4080000 {
+		compatible = "qcom,pil-q6v55-mss";
+		reg = <0x04080000 0x100>,
+		      <0x0194f000 0x010>,
+		      <0x01950000 0x008>,
+		      <0x01951000 0x008>,
+		      <0x04020000 0x040>,
+		      <0x01871000 0x004>;
+		reg-names = "qdsp6_base", "halt_q6", "halt_modem", "halt_nc",
+				 "rmb_base", "restart_reg";
+
+		interrupts = <GIC_SPI 24 IRQ_TYPE_EDGE_RISING>;
+		vdd_mss-supply = <&pm8937_s1>;
+		vdd_cx-supply = <&pm8937_s2_level>;
+		vdd_cx-voltage = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+		vdd_mx-supply = <&pm8937_l3_level_ao>;
+		vdd_mx-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+		vdd_pll-supply = <&pm8937_l7>;
+		qcom,vdd_pll = <1800000>;
+		vdd_mss-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+		clocks = <&clock_gcc clk_xo_pil_mss_clk>,
+			 <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+			 <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+			 <&clock_gcc clk_gcc_boot_rom_ahb_clk>;
+		clock-names = "xo", "iface_clk", "bus_clk", "mem_clk";
+		qcom,proxy-clock-names = "xo";
+		qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
+
+		qcom,pas-id = <5>;
+		qcom,pil-mss-memsetup;
+		qcom,firmware-name = "modem";
+		qcom,pil-self-auth;
+		qcom,override-acc-1 = <0x80800000>;
+		qcom,sysmon-id = <0>;
+		qcom,ssctl-instance-id = <0x12>;
+		qcom,qdsp6v56-1-8-inrush-current;
+		qcom,reset-clk;
+
+		/* GPIO inputs from mss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+		qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+		qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+		/* GPIO output to mss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+
+		memory-region = <&modem_mem>;
+	};
+
+	qcom,lpass@c200000 {
+		compatible = "qcom,pil-tz-generic";
+		reg = <0xc200000 0x00100>;
+		interrupts = <GIC_SPI 293 IRQ_TYPE_EDGE_RISING>;
+
+		vdd_cx-supply = <&pm8937_s2_level>;
+		qcom,proxy-reg-names = "vdd_cx";
+		qcom,vdd_cx-uV-uA = <RPM_SMD_REGULATOR_LEVEL_TURBO 100000>;
+
+		clocks = <&clock_gcc clk_xo_pil_lpass_clk>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>,
+			 <&clock_gcc clk_crypto_clk_src>;
+		clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				"scm_bus_clk", "scm_core_clk_src";
+		qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				 "scm_bus_clk", "scm_core_clk_src";
+		qcom,scm_core_clk_src-freq = <80000000>;
+
+		qcom,mas-crypto = <&mas_crypto>;
+		qcom,pas-id = <1>;
+		qcom,proxy-timeout-ms = <10000>;
+		qcom,smem-id = <423>;
+		qcom,sysmon-id = <1>;
+		qcom,ssctl-instance-id = <0x14>;
+		qcom,firmware-name = "adsp";
+
+		/* GPIO inputs from lpass */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+		qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+		/* GPIO output to lpass */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+
+		memory-region = <&adsp_fw_mem>;
+	};
+
+	qcom,pronto@a21b000 {
+		compatible = "qcom,pil-tz-generic";
+		reg = <0x0a21b000 0x3000>;
+		interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
+
+		vdd_pronto_pll-supply = <&pm8937_l7>;
+		proxy-reg-names = "vdd_pronto_pll";
+		vdd_pronto_pll-uV-uA = <1800000 18000>;
+		clocks = <&clock_gcc clk_xo_pil_pronto_clk>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>,
+			 <&clock_gcc clk_crypto_clk_src>;
+
+		clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				"scm_bus_clk", "scm_core_clk_src";
+		qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk",
+				 "scm_bus_clk", "scm_core_clk_src";
+		qcom,scm_core_clk_src = <80000000>;
+
+		qcom,mas-crypto = <&mas_crypto>;
+		qcom,pas-id = <6>;
+		qcom,proxy-timeout-ms = <10000>;
+		qcom,smem-id = <422>;
+		qcom,sysmon-id = <6>;
+		qcom,ssctl-instance-id = <0x13>;
+		qcom,firmware-name = "wcnss";
+
+		/* GPIO inputs from wcnss */
+		qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+		qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
+		qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
+		qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_4_in 3 0>;
+
+		/* GPIO output to wcnss */
+		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
+		memory-region = <&wcnss_fw_mem>;
+	};
+
+	qcom,venus@1de0000 {
+		compatible = "qcom,pil-tz-generic";
+		reg = <0x1de0000 0x4000>;
+
+		vdd-supply = <&gdsc_venus>;
+		qcom,proxy-reg-names = "vdd";
+
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			 <&clock_gcc clk_gcc_venus0_ahb_clk>,
+			 <&clock_gcc clk_gcc_venus0_axi_clk>,
+			 <&clock_gcc clk_gcc_crypto_clk>,
+			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
+			 <&clock_gcc clk_gcc_crypto_axi_clk>,
+			 <&clock_gcc clk_crypto_clk_src>;
+
+		clock-names = "core_clk", "iface_clk", "bus_clk",
+				"scm_core_clk", "scm_iface_clk",
+				"scm_bus_clk", "scm_core_clk_src";
+
+		qcom,proxy-clock-names = "core_clk", "iface_clk",
+					 "bus_clk", "scm_core_clk",
+					 "scm_iface_clk", "scm_bus_clk",
+					 "scm_core_clk_src";
+		qcom,scm_core_clk_src-freq = <80000000>;
+
+		qcom,msm-bus,name = "pil-venus";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<63 512 0 0>,
+				<63 512 0 304000>;
+
+		qcom,mas-crypto = <&mas_crypto>;
+		qcom,pas-id = <9>;
+		qcom,proxy-timeout-ms = <100>;
+		qcom,firmware-name = "venus";
+		memory-region = <&venus_mem>;
+	};
+
+	qcom,wcnss-wlan@0a000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0x0a000000 0x280000>,
+		      <0xb011008 0x04>,
+		      <0x0a21b000 0x3000>,
+		      <0x03204000 0x00000100>,
+		      <0x03200800 0x00000200>,
+		      <0x0a100400 0x00000200>,
+		      <0x0a205050 0x00000200>,
+		      <0x0a219000 0x00000020>,
+		      <0x0a080488 0x00000008>,
+		      <0x0a080fb0 0x00000008>,
+		      <0x0a08040c 0x00000008>,
+		      <0x0a0120a8 0x00000008>,
+		      <0x0a012448 0x00000008>,
+		      <0x0a080c00 0x00000001>;
+
+		reg-names = "wcnss_mmio", "wcnss_fiq",
+			    "pronto_phy_base", "riva_phy_base",
+			    "riva_ccu_base", "pronto_a2xb_base",
+			    "pronto_ccpu_base", "pronto_saw2_base",
+			    "wlan_tx_phy_aborts","wlan_brdg_err_source",
+			    "wlan_tx_status", "alarms_txctl",
+			    "alarms_tactl", "pronto_mcu_base";
+
+		interrupts = <0 145 0 0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8937_l3_level_ao>;
+		qcom,pronto-vddcx-supply = <&pm8937_s2_level>;
+		qcom,pronto-vddpx-supply = <&pm8937_l5>;
+		qcom,iris-vddxo-supply   = <&pm8937_l7>;
+		qcom,iris-vddrfa-supply  = <&pm8937_l19>;
+		qcom,iris-vddpa-supply   = <&pm8937_l9>;
+		qcom,iris-vdddig-supply  = <&pm8937_l5>;
+
+		qcom,iris-vddxo-voltage-level = <1800000 0 1800000>;
+		qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>;
+		qcom,iris-vddpa-voltage-level = <3300000 0 3300000>;
+		qcom,iris-vdddig-voltage-level = <1800000 0 1800000>;
+
+		qcom,vddmx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_TURBO
+					RPM_SMD_REGULATOR_LEVEL_NONE
+					RPM_SMD_REGULATOR_LEVEL_TURBO>;
+		qcom,vddcx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_NOM
+					RPM_SMD_REGULATOR_LEVEL_NONE
+					RPM_SMD_REGULATOR_LEVEL_BINNING>;
+		qcom,vddpx-voltage-level = <1800000 0 1800000>;
+
+		qcom,iris-vddxo-current = <10000>;
+		qcom,iris-vddrfa-current = <100000>;
+		qcom,iris-vddpa-current = <515000>;
+		qcom,iris-vdddig-current = <10000>;
+
+		qcom,pronto-vddmx-current = <0>;
+		qcom,pronto-vddcx-current = <0>;
+		qcom,pronto-vddpx-current = <0>;
+
+		pinctrl-names = "wcnss_default", "wcnss_sleep",
+				"wcnss_gpio_default";
+		pinctrl-0 = <&wcnss_default>;
+		pinctrl-1 = <&wcnss_sleep>;
+		pinctrl-2 = <&wcnss_gpio_default>;
+
+		gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>,
+			<&tlmm 79 0>, <&tlmm 80 0>;
+
+		clocks = <&clock_gcc clk_xo_wlan_clk>,
+			 <&clock_gcc clk_rf_clk2>,
+			 <&clock_debug clk_gcc_debug_mux_8937>,
+			 <&clock_gcc clk_wcnss_m_clk>,
+			 <&clock_gcc clk_snoc_wcnss_a_clk>;
+
+		clock-names = "xo", "rf_clk", "measure", "wcnss_debug",
+				"snoc_wcnss";
+
+		qcom,snoc-wcnss-clock-freq = <200000000>;
+
+		qcom,has-autodetect-xo;
+		qcom,is-pronto-v3;
+		qcom,has-pronto-hw;
+		qcom,has-vsys-adc-channel;
+		qcom,wcnss-adc_tm = <&pm8937_adc_tm>;
+	};
+
+	bam_dmux: qcom,bam_dmux@4044000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0x4044000 0x19000>;
+		interrupts = <0 162 1>;
+		qcom,rx-ring-size = <32>;
+		qcom,max-rx-mtu = <4096>;
+		qcom,fast-shutdown;
+		qcom,no-cpu-affinity;
+	};
+
+	ssc_sensors: qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		status = "ok";
+	};
+
+};
+
+#include "pm8937-rpm-regulator.dtsi"
+#include "msm8937-regulator.dtsi"
+#include "pm8937.dtsi"
+#include "msm8937-audio.dtsi"
+#include "msm-gdsc-8916.dtsi"
+#include "msm8937-coresight.dtsi"
+
+&gdsc_venus {
+	clock-names = "bus_clk", "core_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_axi_clk>,
+		<&clock_gcc clk_gcc_venus0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_venus_core0 {
+	qcom,support-hw-trigger;
+	clock-names ="core0_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_mdss {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+		<&clock_gcc clk_gcc_mdss_axi_clk>;
+	qcom,disallow-clear;
+	status = "okay";
+};
+
+&gdsc_jpeg {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>,
+		<&clock_gcc clk_gcc_camss_jpeg_axi_clk>;
+	status = "okay";
+};
+
+&gdsc_vfe {
+	clock-names = "core_clk", "bus_clk", "micro_clk",
+			"csi_clk";
+	clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>,
+		<&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+		<&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+		<&clock_gcc clk_gcc_camss_csi_vfe0_clk>;
+	status = "okay";
+};
+
+&gdsc_vfe1 {
+	clock-names = "core_clk", "bus_clk", "micro_clk",
+			"csi_clk";
+	clocks = <&clock_gcc clk_gcc_camss_vfe1_clk>,
+		<&clock_gcc clk_gcc_camss_vfe1_axi_clk>,
+		<&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+		<&clock_gcc clk_gcc_camss_csi_vfe1_clk>;
+	status = "okay";
+};
+
+&gdsc_cpp {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_camss_cpp_clk>,
+		<&clock_gcc clk_gcc_camss_cpp_axi_clk>;
+	status = "okay";
+};
+
+&gdsc_oxili_gx {
+	clock-names = "core_root_clk";
+	clocks =<&clock_gcc clk_gfx3d_clk_src>;
+	qcom,enable-root-clk;
+	qcom,clk-dis-wait-val = <0x5>;
+	status = "okay";
+};
+
+&gdsc_oxili_cx {
+	reg = <0x1859044 0x4>;
+	clock-names = "core_clk";
+	clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi
new file mode 100644
index 0000000..493e002
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-audio-cdp.dtsi
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&int_codec {
+	status = "okay";
+	qcom,msm-hs-micbias-type = "external";
+};
+
+&msm_digital_codec {
+	status = "okay";
+};
+
+&pmic_analog_codec {
+	status = "okay";
+};
+
+&wsa881x_i2c_f {
+	status = "okay";
+};
+
+&wsa881x_i2c_45 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi
new file mode 100644
index 0000000..fc10b4d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-audio.dtsi
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm-audio-lpass.dtsi"
+#include "msm8953-wsa881x.dtsi"
+
+&msm_audio_ion {
+	iommus = <&apps_iommu 0x2401 0x0>;
+	qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&soc {
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
+		};
+	};
+
+	qcom,avtimer@c0a300c {
+		compatible = "qcom,avtimer";
+		reg = <0x0c0a300c 0x4>,
+			<0x0c0a3010 0x4>;
+		reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+		qcom,clk-div = <27>;
+	};
+
+	int_codec: sound {
+		status = "okay";
+		compatible = "qcom,msm8952-audio-codec";
+		qcom,model = "msm8953-snd-card-mtp";
+		reg = <0xc051000 0x4>,
+			<0xc051004 0x4>,
+			<0xc055000 0x4>,
+			<0xc052000 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			"csr_gp_io_mux_spkr_ctl",
+			"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			"csr_gp_io_mux_quin_ctl";
+
+		qcom,msm-ext-pa = "primary";
+		qcom,msm-mclk-freq = <9600000>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,msm-hs-micbias-type = "internal";
+		qcom,msm-micbias1-ext-cap;
+
+		qcom,audio-routing =
+				"RX_BIAS", "MCLK",
+				"SPK_RX_BIAS", "MCLK",
+				"INT_LDO_H", "MCLK",
+				"RX_I2S_CLK", "MCLK",
+				"TX_I2S_CLK", "MCLK",
+				"MIC BIAS External", "Handset Mic",
+				"MIC BIAS External2", "Headset Mic",
+				"MIC BIAS External", "Secondary Mic",
+				"AMIC1", "MIC BIAS External",
+				"AMIC2", "MIC BIAS External2",
+				"AMIC3", "MIC BIAS External",
+				"ADC1_IN", "ADC1_OUT",
+				"ADC2_IN", "ADC2_OUT",
+				"ADC3_IN", "ADC3_OUT",
+				"PDM_IN_RX1", "PDM_OUT_RX1",
+				"PDM_IN_RX2", "PDM_OUT_RX2",
+				"PDM_IN_RX3", "PDM_OUT_RX3",
+				"WSA_SPK OUT", "VDD_WSA_SWITCH",
+				"SpkrMono WSA_IN", "WSA_SPK OUT";
+
+		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+		qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+		qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+		qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>;
+		qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+				<&loopback>, <&compress>, <&hostless>,
+				<&afe>, <&lsm>, <&routing>, <&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-pcm-dsp-noirq";
+		asoc-cpu = <&dai_pri_auxpcm>,
+			<&dai_mi2s0>, <&dai_mi2s1>,
+			<&dai_mi2s2>, <&dai_mi2s3>,
+			<&dai_mi2s4>, <&dai_mi2s5>,
+			<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+			<&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+			<&bt_sco_rx>, <&bt_sco_tx>,
+			<&int_fm_rx>, <&int_fm_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>;
+
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"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-mi2s.6",
+				"msm-dai-q6-dev.16384", "msmdai-q6-dev.16385",
+				"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+				"msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+				"msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+				"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+				"msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+				"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";
+
+		asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+				<&pmic_analog_codec>;
+		asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+					"analog-codec";
+		asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+		asoc-wsa-codec-prefixes = "SpkrMono";
+		msm-vdd-wsa-switch-supply = <&pm8953_l5>;
+		qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+		qcom,msm-vdd-wsa-switch-current = <10000>;
+	};
+
+	cdc_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cross_conn_det_act>;
+		pinctrl-1 = <&cross_conn_det_sus>;
+	};
+
+	cdc_comp_gpios: cdc_comp_pinctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_pdm_comp_lines_act>;
+		pinctrl-1 = <&cdc_pdm_comp_lines_sus>;
+	};
+
+	cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act>;
+		pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus>;
+	};
+
+	cdc_quin_mi2s_gpios: msm_cdc_pinctrl_quin {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&pri_tlmm_lines_act &pri_tlmm_ws_act>;
+		pinctrl-1 = <&pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+	};
+
+
+	i2c@78b6000 {
+		status = "okay";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		wsa881x_i2c_f: wsa881x-i2c-codec@f {
+			status = "okay";
+			compatible = "qcom,wsa881x-i2c-codec";
+			reg = <0x0f>;
+			qcom,wsa-analog-vi-gpio = <&wsa881x_analog_vi_gpio>;
+			qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>;
+			qcom,wsa-analog-reset-gpio =
+				<&wsa881x_analog_reset_gpio>;
+		};
+		wsa881x_i2c_45: wsa881x-i2c-codec@45 {
+			status = "okay";
+			compatible = "qcom,wsa881x-i2c-codec";
+			reg = <0x45>;
+		};
+	};
+
+	wsa881x_analog_vi_gpio: wsa881x_analog_vi_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_vi_on>;
+		pinctrl-1 = <&wsa_vi_off>;
+	};
+	wsa881x_analog_clk_gpio: wsa881x_analog_clk_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_clk_on>;
+		pinctrl-1 = <&wsa_clk_off>;
+	};
+	wsa881x_analog_reset_gpio: wsa881x_analog_reset_pctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wsa_reset_on>;
+		pinctrl-1 = <&wsa_reset_off>;
+	};
+
+	ext_codec: sound-9335 {
+		status = "disabled";
+		compatible = "qcom,msm8952-audio-slim-codec";
+		qcom,model = "msm8953-tasha-snd-card";
+
+		reg = <0xc051000 0x4>,
+			<0xc051004 0x4>,
+			<0xc055000 0x4>,
+			<0xc052000 0x4>;
+		reg-names = "csr_gp_io_mux_mic_ctl",
+			"csr_gp_io_mux_spkr_ctl",
+			"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+			"csr_gp_io_mux_quin_ctl";
+
+		qcom,audio-routing =
+			"AIF4 VI", "MCLK",
+			"AIF4 VI", "MICBIAS_REGULATOR",
+			"RX_BIAS", "MCLK",
+			"MADINPUT", "MCLK",
+			"AIF4 MAD", "MICBIAS_REGULATOR",
+			"AMIC2", "MIC BIAS2",
+			"MIC BIAS2", "Headset Mic",
+			"AMIC3", "MIC BIAS2",
+			"MIC BIAS2", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2",
+			"MIC BIAS2", "ANCLeft Headset Mic",
+			"AMIC5", "MIC BIAS3",
+			"MIC BIAS3", "Handset Mic",
+			"AMIC6", "MIC BIAS4",
+			"MIC BIAS4", "Analog Mic6",
+			"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",
+			"MIC BIAS1", "MICBIAS_REGULATOR",
+			"MIC BIAS2", "MICBIAS_REGULATOR",
+			"MIC BIAS3", "MICBIAS_REGULATOR",
+			"MIC BIAS4", "MICBIAS_REGULATOR",
+			"SpkrLeft IN", "SPK1 OUT",
+			"SpkrRight IN", "SPK2 OUT";
+
+		qcom,tasha-mclk-clk-freq = <9600000>;
+		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+		qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
+
+		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_pri_auxpcm>,
+				<&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+				<&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>, <&bt_sco_rx>, <&bt_sco_tx>,
+				<&int_fm_rx>, <&int_fm_tx>, <&sb_6_rx>;
+
+		asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+				"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+				"msm-dai-q6-mi2s.5", "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.12288",
+				"msm-dai-q6-dev.12289", "msm-dai-q6-dev.12292",
+				"msm-dai-q6-dev.12293", "msm-dai-q6-dev.16396";
+
+		asoc-codec = <&stub_codec>, <&hdmi_dba>;
+		asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
+
+		qcom,wsa-max-devs = <2>;
+		qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
+				<&wsa881x_213>, <&wsa881x_214>;
+		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+				"SpkrLeft", "SpkrRight";
+	};
+
+	cpe: qcom,msm-cpe-lsm {
+		compatible = "qcom,msm-cpe-lsm";
+	};
+
+	wcd9xxx_intc: wcd9xxx-irq {
+		status = "disabled";
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&tlmm>;
+		qcom,gpio-connect = <&tlmm 73 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&wcd_intr_default>;
+	};
+
+	clock_audio: audio_ext_clk {
+		status = "disabled";
+		compatible = "qcom,audio-ref-clk";
+		clock-names = "osr_clk";
+		qcom,node_has_rpm_clock;
+		#clock-cells = <1>;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&tasha_mclk_default>;
+		pinctrl-1 = <&tasha_mclk_default>;
+		qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>;
+		clocks = <&clock_gcc clk_div_clk2>;
+	};
+
+	wcd_rst_gpio: msm_cdc_pinctrl@67 {
+		status = "disabled";
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_reset_active>;
+		pinctrl-1 = <&cdc_reset_sleep>;
+	};
+};
+
+&slim_msm {
+	status = "disabled";
+
+	dai_slim: msm_dai_slim {
+		status = "disabled";
+		compatible = "qcom,msm-dai-slim";
+		elemental-addr = [ff ff ff fe 17 02];
+	};
+
+	wcd9335: tasha_codec {
+		status = "disabled";
+		compatible = "qcom,tasha-slim-pgd";
+		elemental-addr = [00 01 A0 01 17 02];
+
+		qcom,cdc-slim-ifd = "tasha-slim-ifd";
+		qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02];
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+				17 18 19 20 21 22 23 24 25 26 27 28 29 30>;
+
+		qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+		clock-names = "wcd_clk", "wcd_native_clk";
+		clocks = <&clock_audio clk_audio_pmi_clk>,
+			<&clock_audio clk_audio_ap_clk2>;
+
+		qcom,cdc-static-supplies =
+				"cdc-vdd-buck",
+				"cdc-buck-sido",
+				"cdc-vdd-tx-h",
+				"cdc-vdd-rx-h",
+				"cdc-vdd-px";
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-mv = <1800>;
+		qcom,cdc-micbias2-mv = <1800>;
+		qcom,cdc-micbias3-mv = <1800>;
+		qcom,cdc-micbias4-mv = <1800>;
+
+		qcom,cdc-dmic-sample-rate = <2400000>;
+		qcom,cdc-mclk-clk-rate = <9600000>;
+
+		cdc-vdd-buck-supply = <&eldo2_8953>;
+		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-buck-current = <650000>;
+
+		cdc-buck-sido-supply = <&eldo2_8953>;
+		qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+		qcom,cdc-buck-sido-current = <150000>;
+
+		cdc-vdd-tx-h-supply = <&eldo2_8953>;
+		qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-tx-h-current = <25000>;
+
+		cdc-vdd-rx-h-supply = <&eldo2_8953>;
+		qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-rx-h-current = <25000>;
+
+		cdc-vdd-px-supply = <&eldo2_8953>;
+		qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-px-current = <10000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+		qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+		qcom,cdc-vdd-mic-bias-current = <15000>;
+	};
+};
+&pm8953_gpios {
+	gpio@c000 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+
+	tasha_mclk {
+		tasha_mclk_default: tasha_mclk_default{
+			pins = "gpio1";
+			function = "func1";
+			qcom,drive-strength = <2>;
+			power-source = <0>;
+			bias-disable;
+			output-low;
+		};
+	};
+};
+
+&pm8953_1 {
+	pmic_analog_codec: analog-codec@f000 {
+		status = "okay";
+		compatible = "qcom,pmic-analog-codec";
+		reg = <0xf000 0x200>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+		interrupt-parent = <&spmi_bus>;
+		interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+		interrupt-names = "spk_cnp_int",
+				"spk_clip_int",
+				"spk_ocp_int",
+				"ins_rem_det1",
+				"but_rel_det",
+				"but_press_det",
+				"ins_rem_det",
+				"mbhc_int",
+				"ear_ocp_int",
+				"hphr_ocp_int",
+				"hphl_ocp_det",
+				"ear_cnp_int",
+				"hphr_cnp_int",
+				"hphl_cnp_int";
+
+		cdc-vdda-cp-supply = <&pm8953_s4>;
+		qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+		qcom,cdc-vdda-cp-current = <500000>;
+
+		cdc-vdd-io-supply = <&pm8953_l5>;
+		qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-io-current = <5000>;
+
+		cdc-vdd-pa-supply = <&pm8953_s4>;
+		qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+		qcom,cdc-vdd-pa-current = <260000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+		qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+		qcom,cdc-vdd-mic-bias-current = <5000>;
+
+		qcom,cdc-mclk-clk-rate = <9600000>;
+
+		qcom,cdc-static-supplies = "cdc-vdd-io",
+					"cdc-vdd-pa",
+					"cdc-vdda-cp";
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+		msm_digital_codec: msm-dig-codec {
+			compatible = "qcom,msm-digital-codec";
+			reg = <0xc0f0000 0x0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..a46bce3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	actuator1: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <1>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l2>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom1: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		qcom,eeprom-name = "sunny_8865";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <8>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0x0 1 0>;
+		qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page1 = <1 0x5002 2 0x00 1 0>;
+		qcom,poll1 = <0 0x0 2 0x0 1 0>;
+		qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+		qcom,poll2 = <0 0x0 2 0x0 1 0>;
+		qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+		qcom,poll3 = <0 0x0 2 0x0 1 0>;
+		qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+		qcom,poll4 = <0 0x0 2 0x0 1 0>;
+		qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+		qcom,poll5 = <0 0x0 2 0x0 1 0>;
+		qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+		qcom,poll6 = <0 0x0 2 0x0 1 0>;
+		qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0x0 1 1>;
+		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+			"sensor_vreg",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+			"sensor_gpio_reset", "sensor_gpio_standby",
+			"sensor_cam_mclk";
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom2: qcom,eeprom@2 {
+		cell-index = <2>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <1>;
+		reg = <0x2>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l2>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom2>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <0x100>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..a7688f0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	actuator1: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <1>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l2>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom1: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		qcom,eeprom-name = "sunny_8865";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <8>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0x0 1 0>;
+		qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page1 = <1 0x5002 2 0x00 1 0>;
+		qcom,poll1 = <0 0x0 2 0x0 1 0>;
+		qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+		qcom,poll2 = <0 0x0 2 0x0 1 0>;
+		qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+		qcom,poll3 = <0 0x0 2 0x0 1 0>;
+		qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+		qcom,poll4 = <0 0x0 2 0x0 1 0>;
+		qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+		qcom,poll5 = <0 0x0 2 0x0 1 0>;
+		qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+		qcom,poll6 = <0 0x0 2 0x0 1 0>;
+		qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0x0 1 1>;
+		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+			"sensor_vreg",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+			"sensor_gpio_reset", "sensor_gpio_standby",
+			"sensor_cam_mclk";
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom2: qcom,eeprom@2 {
+		cell-index = <2>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <1>;
+		reg = <0x2>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l2>;
+		cam_vaf-supply = <&pm8953_l17>;
+		cam_vana-supply = <&pm8953_l22>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+						"cam_vana";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom2>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <0x100>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..8098efb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-qrd.dtsi
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_STANDBY0",
+					"CAM_VANA";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom2: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+						&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-mode = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		cam_vana-supply = <&pm8953_l22>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+						"cam_vana";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "disabled";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom2>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi
new file mode 100644
index 0000000..2685f5a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-camera.dtsi
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,msm-cam@1b00000 {
+		compatible = "qcom,msm-cam";
+		reg = <0x1b00000 0x40000>;
+		reg-names = "msm-cam";
+		status = "ok";
+		bus-vectors = "suspend", "svs", "nominal", "turbo";
+		qcom,bus-votes = <0 320000000 640000000 640000000>;
+	};
+
+	qcom,csiphy@1b34000 {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,csiphy-v3.5", "qcom,csiphy";
+		reg = <0x1b34000 0x1000>,
+			<0x1b00030 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
+		interrupts = <0 78 0>;
+		interrupt-names = "csiphy";
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_csi0phytimer_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi0phytimer_clk>,
+			<&clock_gcc clk_camss_top_ahb_clk_src>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk", "ispif_ahb_clk",
+			"csiphy_timer_src_clk", "csiphy_timer_clk",
+			"camss_ahb_src", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 200000000 0 0 0>;
+	};
+
+	qcom,csiphy@1b35000 {
+		status = "ok";
+		cell-index = <1>;
+		compatible = "qcom,csiphy-v3.5", "qcom,csiphy";
+		reg = <0x1b35000 0x1000>,
+			<0x1b00038 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
+		interrupts = <0 79 0>;
+		interrupt-names = "csiphy";
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_csi1phytimer_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi1phytimer_clk>,
+			<&clock_gcc clk_camss_top_ahb_clk_src>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk", "ispif_ahb_clk",
+			"csiphy_timer_src_clk", "csiphy_timer_clk",
+			"camss_ahb_src", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 200000000 0 0 0>;
+	};
+
+	qcom,csiphy@1b36000 {
+		status = "ok";
+		cell-index = <2>;
+		compatible = "qcom,csiphy-v3.5", "qcom,csiphy";
+		reg = <0x1b36000 0x1000>,
+			<0x1b00040 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
+		interrupts = <0 315 0>;
+		interrupt-names = "csiphy";
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_csi2phytimer_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi2phytimer_clk>,
+			<&clock_gcc clk_camss_top_ahb_clk_src>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk", "ispif_ahb_clk",
+			"csiphy_timer_src_clk", "csiphy_timer_clk",
+			"camss_ahb_src", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 200000000 0 0 0>;
+	};
+
+	qcom,csid@1b30000  {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,csid-v3.5.1", "qcom,csid";
+		reg = <0x1b30000 0x400>;
+		reg-names = "csid";
+		interrupts = <0 51 0>;
+		interrupt-names = "csid";
+		qcom,csi-vdd-voltage = <1225000>;
+		qcom,mipi-csi-vdd-supply = <&pm8953_s3>;
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_csi0_ahb_clk>,
+			<&clock_gcc clk_csi0_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi0phy_clk>,
+			<&clock_gcc clk_gcc_camss_csi0_clk>,
+			<&clock_gcc clk_gcc_camss_csi0pix_clk>,
+			<&clock_gcc clk_gcc_camss_csi0rdi_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk",
+			"ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk",
+			"csi0_phy_clk",
+			"csi_clk",  "csi_pix_clk",
+			"csi_rdi_clk", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0 0>;
+	};
+
+	qcom,csid@1b30400 {
+		status = "ok";
+		cell-index = <1>;
+		compatible = "qcom,csid-v3.5.1", "qcom,csid";
+		reg = <0x1b30400 0x400>;
+		reg-names = "csid";
+		interrupts = <0 52 0>;
+		interrupt-names = "csid";
+		qcom,csi-vdd-voltage = <1225000>;
+		qcom,mipi-csi-vdd-supply = <&pm8953_s3>;
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_csi1_ahb_clk>,
+			<&clock_gcc clk_csi1_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi1phy_clk>,
+			<&clock_gcc clk_gcc_camss_csi1_clk>,
+			<&clock_gcc clk_gcc_camss_csi1pix_clk>,
+			<&clock_gcc clk_gcc_camss_csi1rdi_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk",
+			"ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk",
+			"csi1_phy_clk",
+			"csi_clk", "csi_pix_clk",
+			"csi_rdi_clk", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0 0>;
+	};
+
+	qcom,csid@1b30800 {
+		status = "ok";
+		cell-index = <2>;
+		compatible = "qcom,csid-v3.5.1", "qcom,csid";
+		reg = <0x1b30800 0x400>;
+		reg-names = "csid";
+		interrupts = <0 153 0>;
+		interrupt-names = "csid";
+		qcom,csi-vdd-voltage = <1225000>;
+		qcom,mipi-csi-vdd-supply = <&pm8953_s3>;
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_csi2_ahb_clk>,
+			<&clock_gcc clk_csi2_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi2phy_clk>,
+			<&clock_gcc clk_gcc_camss_csi2_clk>,
+			<&clock_gcc clk_gcc_camss_csi2pix_clk>,
+			<&clock_gcc clk_gcc_camss_csi2rdi_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk",
+			"ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk",
+			"csi2_phy_clk",
+			"csi_clk", "csi_pix_clk",
+			"csi_rdi_clk", "camss_ahb_clk";
+		qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0 0>;
+	};
+
+	qcom,ispif@1b31000 {
+		cell-index = <0>;
+		compatible = "qcom,ispif-v3.0", "qcom,ispif";
+		reg = <0x1b31000 0x500>,
+			<0x1b00020 0x10>;
+		reg-names = "ispif", "csi_clk_mux";
+		interrupts = <0 55 0>;
+		interrupt-names = "ispif";
+		qcom,num-isps = <0x2>;
+		vfe0-vdd-supply = <&gdsc_vfe>;
+		vfe1-vdd-supply = <&gdsc_vfe1>;
+		qcom,vdd-names = "vfe0-vdd", "vfe1-vdd";
+		clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_camss_top_ahb_clk_src>,
+			<&clock_gcc clk_csi0_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi0_clk>,
+			<&clock_gcc clk_gcc_camss_csi0rdi_clk>,
+			<&clock_gcc clk_gcc_camss_csi0pix_clk>,
+			<&clock_gcc clk_csi1_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi1_clk>,
+			<&clock_gcc clk_gcc_camss_csi1rdi_clk>,
+			<&clock_gcc clk_gcc_camss_csi1pix_clk>,
+			<&clock_gcc clk_csi2_clk_src>,
+			<&clock_gcc clk_gcc_camss_csi2_clk>,
+			<&clock_gcc clk_gcc_camss_csi2rdi_clk>,
+			<&clock_gcc clk_gcc_camss_csi2pix_clk>,
+			<&clock_gcc clk_vfe0_clk_src>,
+			<&clock_gcc clk_gcc_camss_vfe0_clk>,
+			<&clock_gcc clk_gcc_camss_csi_vfe0_clk>,
+			<&clock_gcc clk_vfe1_clk_src>,
+			<&clock_gcc clk_gcc_camss_vfe1_clk>,
+			<&clock_gcc clk_gcc_camss_csi_vfe1_clk>;
+		clock-names = "ispif_ahb_clk",
+			"camss_ahb_clk", "camss_top_ahb_clk",
+			"camss_ahb_src",
+			"csi0_src_clk", "csi0_clk",
+			"csi0_rdi_clk", "csi0_pix_clk",
+			"csi1_src_clk", "csi1_clk",
+			"csi1_rdi_clk", "csi1_pix_clk",
+			"csi2_src_clk", "csi2_clk",
+			"csi2_rdi_clk", "csi2_pix_clk",
+			"vfe0_clk_src", "camss_vfe_vfe0_clk",
+			"camss_csi_vfe0_clk", "vfe1_clk_src",
+			"camss_vfe_vfe1_clk", "camss_csi_vfe1_clk";
+		qcom,clock-rates = <61540000 0 0 0
+			200000000 0 0 0
+			200000000 0 0 0
+			200000000 0 0 0
+			0 0 0
+			0 0 0>;
+		qcom,clock-cntl-support;
+		qcom,clock-control = "SET_RATE","NO_SET_RATE", "NO_SET_RATE",
+			"NO_SET_RATE", "SET_RATE", "NO_SET_RATE",
+			"NO_SET_RATE", "NO_SET_RATE", "SET_RATE",
+			"NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+			"SET_RATE", "NO_SET_RATE", "NO_SET_RATE",
+			"NO_SET_RATE", "INIT_RATE", "NO_SET_RATE",
+			"NO_SET_RATE", "INIT_RATE", "NO_SET_RATE",
+			"NO_SET_RATE";
+	};
+
+	vfe0: qcom,vfe0@1b10000 {
+		cell-index = <0>;
+		compatible = "qcom,vfe40";
+		reg = <0x1b10000 0x1000>,
+			<0x1b40000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
+		interrupts = <0 57 0>;
+		interrupt-names = "vfe";
+		vdd-supply = <&gdsc_vfe>;
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>,
+			<&clock_gcc clk_vfe0_clk_src>,
+			<&clock_gcc clk_gcc_camss_vfe0_clk>,
+			<&clock_gcc clk_gcc_camss_csi_vfe0_clk>,
+			<&clock_gcc clk_gcc_camss_vfe_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>;
+		clock-names = "camss_top_ahb_clk", "camss_ahb_clk",
+			"vfe_clk_src", "camss_vfe_vfe_clk",
+			"camss_csi_vfe_clk", "iface_clk",
+			"bus_clk", "iface_ahb_clk";
+		qcom,clock-rates = <0 0 266670000 0 0 0 0 0>;
+		qos-entries = <8>;
+		qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8
+			0x2dc 0x2e0>;
+		qos-settings = <0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55>;
+		vbif-entries = <1>;
+		vbif-regs = <0x124>;
+		vbif-settings = <0x3>;
+		ds-entries = <17>;
+		ds-regs = <0x988 0x98c 0x990 0x994 0x998
+			0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0
+			0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>;
+		ds-settings = <0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0x00000110>;
+		max-clk-nominal = <465000000>;
+		max-clk-turbo = <465000000>;
+	};
+
+	vfe1: qcom,vfe1@1b14000 {
+		cell-index = <1>;
+		compatible = "qcom,vfe40";
+		reg = <0x1b14000 0x1000>,
+			<0x1ba0000 0x200>;
+		reg-names = "vfe", "vfe_vbif";
+		interrupts = <0 29 0>;
+		interrupt-names = "vfe";
+		vdd-supply = <&gdsc_vfe1>;
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>,
+			<&clock_gcc clk_vfe1_clk_src>,
+			<&clock_gcc clk_gcc_camss_vfe1_clk>,
+			<&clock_gcc clk_gcc_camss_csi_vfe1_clk>,
+			<&clock_gcc clk_gcc_camss_vfe1_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_vfe1_axi_clk>,
+			<&clock_gcc clk_gcc_camss_ispif_ahb_clk>;
+		clock-names = "camss_top_ahb_clk" , "camss_ahb_clk",
+			"vfe_clk_src", "camss_vfe_vfe_clk",
+			"camss_csi_vfe_clk", "iface_clk",
+			"bus_clk", "iface_ahb_clk";
+		qcom,clock-rates = <0 0 266670000 0 0 0 0 0>;
+		qos-entries = <8>;
+		qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8
+			0x2dc 0x2e0>;
+		qos-settings = <0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55	0xaa55aa55
+			0xaa55aa55>;
+		vbif-entries = <1>;
+		vbif-regs = <0x124>;
+		vbif-settings = <0x3>;
+		ds-entries = <17>;
+		ds-regs = <0x988 0x98c 0x990 0x994 0x998
+			0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0
+			0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>;
+		ds-settings = <0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0xcccc1111
+			0xcccc1111	0x00000110>;
+		max-clk-nominal = <465000000>;
+		max-clk-turbo = <465000000>;
+	};
+
+	qcom,vfe {
+		compatible = "qcom,vfe";
+		num_child = <2>;
+	};
+
+	qcom,cam_smmu {
+		status = "ok";
+		compatible = "qcom,msm-cam-smmu";
+		msm_cam_smmu_cb1: msm_cam_smmu_cb1 {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_iommu 0x400 0x00>,
+				<&apps_iommu 0x2800 0x00>;
+			label = "vfe";
+			qcom,scratch-buf-support;
+		};
+
+		msm_cam_smmu_cb3: msm_cam_smmu_cb3 {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_iommu 0x1c00 0x00>;
+			label = "cpp";
+		};
+
+		msm_cam_smmu_cb4: msm_cam_smmu_cb4 {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_iommu 0x1800 0x00>;
+			label = "jpeg_enc0";
+		};
+	};
+
+	qcom,jpeg@1b1c000 {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,jpeg";
+		reg = <0x1b1c000 0x400>,
+			<0x1b60000 0xc30>;
+		reg-names = "jpeg_hw", "jpeg_vbif";
+		interrupts = <0 59 0>;
+		interrupt-names = "jpeg";
+		vdd-supply = <&gdsc_jpeg>;
+		qcom,vdd-names = "vdd";
+		clock-names =  "core_clk", "iface_clk", "bus_clk0",
+			"camss_top_ahb_clk", "camss_ahb_clk";
+		clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>,
+			<&clock_gcc clk_gcc_camss_jpeg_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_jpeg_axi_clk>,
+			<&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		qcom,clock-rates = <266670000 0 0 0 0>;
+		qcom,qos-reg-settings = <0x28 0x0000555e>,
+			<0xc8 0x00005555>;
+		qcom,vbif-reg-settings = <0xc0 0x10101000>,
+			<0xb0 0x10100010>;
+		qcom,msm-bus,name = "msm_camera_jpeg0";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <62 512 0 0>,
+			<62 512 800000 800000>;
+	};
+
+	qcom,irqrouter@1b00000 {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,irqrouter";
+		reg = <0x1b00000 0x100>;
+		reg-names = "irqrouter";
+	};
+
+	qcom,cpp@1b04000 {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,cpp";
+		reg = <0x1b04000 0x100>,
+			<0x1b80000 0x200>,
+			<0x1b18000 0x018>,
+			<0x1858078 0x4>;
+		reg-names = "cpp", "cpp_vbif", "cpp_hw", "camss_cpp";
+		interrupts = <0 49 0>;
+		interrupt-names = "cpp";
+		vdd-supply = <&gdsc_cpp>;
+		qcom,vdd-names = "vdd";
+		clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>,
+			<&clock_gcc clk_cpp_clk_src>,
+			<&clock_gcc clk_gcc_camss_cpp_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_cpp_axi_clk>,
+			<&clock_gcc clk_gcc_camss_cpp_clk>,
+			<&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>;
+		clock-names = "camss_top_ahb_clk", "cpp_core_clk",
+			"camss_vfe_cpp_ahb_clk", "camss_vfe_cpp_axi_clk",
+			"camss_vfe_cpp_clk","micro_iface_clk", "camss_ahb_clk";
+		qcom,clock-rates = <0 180000000 0 0 180000000 0 0>;
+		qcom,min-clock-rate = <100000000>;
+		qcom,bus-master = <1>;
+		resets = <&clock_gcc GCC_CAMSS_MICRO_BCR>;
+		reset-names = "micro_iface_reset";
+		qcom,msm-bus,name = "msm_camera_cpp";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<106 512 0 0>,
+			<106 512 0 0>;
+		qcom,msm-bus-vector-dyn-vote;
+		qcom,micro-reset;
+		qcom,cpp-fw-payload-info {
+			qcom,stripe-base = <156>;
+			qcom,plane-base = <141>;
+			qcom,stripe-size = <27>;
+			qcom,plane-size = <5>;
+			qcom,fe-ptr-off = <5>;
+			qcom,we-ptr-off = <11>;
+		};
+	};
+
+	cci: qcom,cci@1b0c000 {
+		status = "ok";
+		cell-index = <0>;
+		compatible = "qcom,cci";
+		reg = <0x1b0c000 0x4000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "cci";
+		interrupts = <0 50 0>;
+		interrupt-names = "cci";
+		clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>,
+			<&clock_gcc clk_cci_clk_src>,
+			<&clock_gcc clk_gcc_camss_cci_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_cci_clk>,
+			<&clock_gcc clk_gcc_camss_ahb_clk>,
+			<&clock_gcc clk_gcc_camss_top_ahb_clk>;
+		clock-names = "ispif_ahb_clk", "cci_src_clk",
+			"cci_ahb_clk", "camss_cci_clk",
+			"camss_ahb_clk", "camss_top_ahb_clk";
+		qcom,clock-rates = <61540000 19200000 0 0 0 0>,
+				<61540000 37500000 0 0 0 0>;
+		pinctrl-names = "cci_default", "cci_suspend";
+			pinctrl-0 = <&cci0_active &cci1_active>;
+			pinctrl-1 = <&cci0_suspend &cci1_suspend>;
+		gpios = <&tlmm 29 0>,
+			<&tlmm 30 0>,
+			<&tlmm 31 0>,
+			<&tlmm 32 0>;
+		qcom,gpio-tbl-num = <0 1 2 3>;
+		qcom,gpio-tbl-flags = <1 1 1 1>;
+		qcom,gpio-tbl-label = "CCI_I2C_DATA0",
+						"CCI_I2C_CLK0",
+						"CCI_I2C_DATA1",
+						"CCI_I2C_CLK1";
+		i2c_freq_100Khz: qcom,i2c_standard_mode {
+			status = "disabled";
+		};
+		i2c_freq_400Khz: qcom,i2c_fast_mode {
+			status = "disabled";
+		};
+		i2c_freq_custom: qcom,i2c_custom_mode {
+			status = "disabled";
+		};
+
+		i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
+			status = "disabled";
+		};
+
+	};
+};
+
+&i2c_freq_100Khz {
+	qcom,hw-thigh = <78>;
+	qcom,hw-tlow = <114>;
+	qcom,hw-tsu-sto = <28>;
+	qcom,hw-tsu-sta = <28>;
+	qcom,hw-thd-dat = <10>;
+	qcom,hw-thd-sta = <77>;
+	qcom,hw-tbuf = <118>;
+	qcom,hw-scl-stretch-en = <0>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <1>;
+};
+
+&i2c_freq_400Khz {
+	qcom,hw-thigh = <20>;
+	qcom,hw-tlow = <28>;
+	qcom,hw-tsu-sto = <21>;
+	qcom,hw-tsu-sta = <21>;
+	qcom,hw-thd-dat = <13>;
+	qcom,hw-thd-sta = <18>;
+	qcom,hw-tbuf = <32>;
+	qcom,hw-scl-stretch-en = <0>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <3>;
+	status = "ok";
+};
+
+&i2c_freq_custom {
+	qcom,hw-thigh = <15>;
+	qcom,hw-tlow = <28>;
+	qcom,hw-tsu-sto = <21>;
+	qcom,hw-tsu-sta = <21>;
+	qcom,hw-thd-dat = <13>;
+	qcom,hw-thd-sta = <18>;
+	qcom,hw-tbuf = <25>;
+	qcom,hw-scl-stretch-en = <1>;
+	qcom,hw-trdhld = <6>;
+	qcom,hw-tsp = <3>;
+	status = "ok";
+};
+
+&i2c_freq_1Mhz {
+	qcom,hw-thigh = <16>;
+	qcom,hw-tlow = <22>;
+	qcom,hw-tsu-sto = <17>;
+	qcom,hw-tsu-sta = <18>;
+	qcom,hw-thd-dat = <16>;
+	qcom,hw-thd-sta = <15>;
+	qcom,hw-tbuf = <19>;
+	qcom,hw-scl-stretch-en = <1>;
+	qcom,hw-trdhld = <3>;
+	qcom,hw-tsp = <3>;
+	qcom,cci-clk-src = <37500000>;
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
index 34c5f8f..6105b52 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-cdp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 CDP";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
index 87b8c74..8f75caf 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -11,12 +11,49 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+#include "msm8953-audio-cdp.dtsi"
+
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart_console_active>;
 };
 
+&pm8953_gpios {
+	nfc_clk {
+		nfc_clk_default: nfc_clk_default {
+			pins = "gpio2";
+			function = "normal";
+			input-enable;
+			power-source = <1>;
+		};
+	};
+};
+
+&i2c_5 { /* BLSP2 QUP1 (NFC) */
+	status = "ok";
+	nq@28 {
+		compatible = "qcom,nq-nci";
+		reg = <0x28>;
+		qcom,nq-irq = <&tlmm 17 0x00>;
+		qcom,nq-ven = <&tlmm 16 0x00>;
+		qcom,nq-firm = <&tlmm 62 0x00>;
+		qcom,nq-clkreq = <&pm8953_gpios 2 0x00>;
+		interrupt-parent = <&tlmm>;
+		qcom,clk-src = "BBCLK2";
+		interrupts = <17 0>;
+		interrupt-names = "nfc_irq";
+		pinctrl-names = "nfc_active", "nfc_suspend";
+		pinctrl-0 = <&nfc_int_active &nfc_disable_active
+						&nfc_clk_default>;
+		pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+		clocks = <&clock_gcc clk_bb_clk2_pin>;
+		clock-names = "ref_clk";
+	};
+};
+
 &sdhc_1 {
 	/* device core power supply */
 	vdd-supply = <&pm8953_l8>;
@@ -74,3 +111,125 @@
 
 	status = "ok";
 };
+
+#include "msm8953-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+		qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,pluggable;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&tlmm 87 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&tlmm 86 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 85 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			debounce-interval = <15>;
+		};
+
+		home {
+			label = "home";
+			gpios = <&tlmm 88 0x1>;
+			linux,input-type = <1>;
+			linux,code = <102>;
+			debounce-interval = <15>;
+		};
+	};
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87", "gpio88";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87", "gpio88";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87", "gpio88";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87", "gpio88";
+			};
+		};
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
index b80583e..ee22633 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-mtp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 Ext Codec MTP";
@@ -25,3 +26,75 @@
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
 
+&int_codec {
+	status = "disabled";
+};
+
+&pmic_analog_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+	status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+	status = "disabled";
+};
+
+&cdc_comp_gpios {
+	status = "disabled";
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&dai_slim {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+};
+
+&cdc_us_euro_sw {
+	status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	qcom,model = "msm8953-tasha-snd-card";
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
index 34004b0..00203a2 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -32,5 +32,11 @@
 			memory-region = <&qseecom_mem>;
 			qcom,ion-heap-type = "DMA";
 		};
+
+		qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+			reg = <19>;
+			memory-region = <&qseecom_ta_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
index 26f4338..b62d12d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
new file mode 100644
index 0000000..c6bc2b9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -0,0 +1,150 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-sim-dualmipi-video.dtsi"
+#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-cmd.dtsi"
+#include "dsi-panel-truly-1080p-video.dtsi"
+#include "dsi-panel-truly-1080p-cmd.dtsi"
+#include "dsi-adv7533-1080p.dtsi"
+#include "dsi-adv7533-720p.dtsi"
+#include "dsi-panel-r69006-1080p-video.dtsi"
+#include "dsi-panel-r69006-1080p-cmd.dtsi"
+#include "dsi-panel-truly-wuxga-video.dtsi"
+#include "dsi-panel-lt8912-480p-video.dtsi"
+#include "dsi-panel-lt8912-1080p-video.dtsi"
+#include "dsi-panel-hx8399c-fhd-plus-video.dtsi"
+
+&soc {
+	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+		qcom,panel-supply-entry@2 {
+			reg = <2>;
+			qcom,supply-name = "lab";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+		qcom,panel-supply-entry@3 {
+			reg = <3>;
+			qcom,supply-name = "ibb";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-post-on-sleep = <10>;
+		};
+	};
+};
+
+&dsi_truly_1080_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+
+};
+
+&dsi_truly_1080_cmd {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+};
+
+&dsi_r69006_1080p_video {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_r69006_1080p_cmd{
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
+	qcom,mdss-dsi-panel-max-error-count = <3>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_adv7533_1080p {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_adv7533_720p {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 0e 04 05 02 03 04 a0];
+};
+
+&dsi_truly_wuxga_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi
new file mode 100644
index 0000000..a279453
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi
@@ -0,0 +1,84 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@994400 {
+		compatible = "qcom,mdss_dsi_pll_8953";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x01a94400 0x588>,
+		      <0x0184d074 0x8>,
+		      <0x01a94200 0x98>;
+		reg-names = "pll_base", "gdsc_base", "dynamic_pll_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		/* Memory region for passing dynamic refresh pll codes */
+		memory-region = <&dfps_data_mem>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+
+	mdss_dsi1_pll: qcom,mdss_dsi_pll@996400 {
+		compatible = "qcom,mdss_dsi_pll_8953";
+		label = "MDSS DSI 1 PLL";
+		cell-index = <1>;
+		#clock-cells = <1>;
+
+		reg = <0x01a96400 0x588>,
+		      <0x0184d074 0x8>,
+		      <0x01a96200 0x98>;
+		reg-names = "pll_base", "gdsc_base", "dynamic_pll_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi
new file mode 100644
index 0000000..310da1f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi
@@ -0,0 +1,434 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0x01a00000 0x90000>,
+		      <0x01ab0000 0x1040>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-ib-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-clk-factor = <105 100>;	/* 1.05 times */
+
+		qcom,max-mixer-width = <2048>;
+		qcom,max-pipe-width = <2048>;
+
+		/* VBIF QoS remapper settings*/
+		qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+		qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
+
+		qcom,mdss-has-panic-ctrl;
+		qcom,mdss-per-pipe-panic-luts = <0x000f>,
+						<0xffff>,
+						<0xfffc>,
+						<0xff00>;
+
+		qcom,mdss-mdp-reg-offset = <0x00001000>;
+		qcom,max-bandwidth-low-kbps = <3400000>;
+		qcom,max-bandwidth-high-kbps = <3400000>;
+		qcom,max-bandwidth-per-pipe-kbps = <2300000>;
+		qcom,max-clk-rate = <400000000>;
+		qcom,mdss-default-ot-rd-limit = <32>;
+		qcom,mdss-default-ot-wr-limit = <16>;
+
+		/* Bandwidth limit settings */
+		qcom,max-bw-settings = <1 3400000>,	/* Default */
+				       <2 3100000>;	/* Camera */
+
+		qcom,mdss-pipe-vig-off = <0x00005000>;
+		qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000>;
+		qcom,mdss-pipe-dma-off = <0x00025000>;
+		qcom,mdss-pipe-cursor-off = <0x00035000>;
+
+		qcom,mdss-pipe-vig-xin-id = <0>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5>;
+		qcom,mdss-pipe-dma-xin-id = <2>;
+		qcom,mdss-pipe-cursor-xin-id = <7>;
+
+		/* Offsets relative to "mdp_phys + mdp-reg-offset" address */
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2aC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x2aC 4 8>,
+						      <0x2b4 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2ac 8 12>;
+		qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3a8 16 15>;
+
+
+		qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400>;
+		qcom,mdss-mixer-intf-off = <0x00045000 0x00046000>;
+		qcom,mdss-dspp-off = <0x00055000>;
+		qcom,mdss-wb-off = <0x00065000 0x00066000>;
+		qcom,mdss-intf-off = <0x0006b000 0x0006b800 0x0006c000>;
+		qcom,mdss-pingpong-off = <0x00071000 0x00071800>;
+		qcom,mdss-slave-pingpong-off = <0x00073000>;
+		qcom,mdss-cdm-off = <0x0007a200>;
+		qcom,mdss-wfd-mode = "intf";
+		qcom,mdss-highest-bank-bit = <0x1>;
+		qcom,mdss-has-decimation;
+		qcom,mdss-has-non-scalar-rgb;
+		qcom,mdss-has-rotator-downscale;
+		qcom,mdss-rot-downscale-min = <2>;
+		qcom,mdss-rot-downscale-max = <16>;
+		qcom,mdss-idle-power-collapse-enabled;
+		qcom,mdss-rot-block-size = <64>;
+		qcom,mdss-ppb-off = <0x00000330>;
+		qcom,mdss-has-pingpong-split;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>,
+			 <&clock_gcc clk_mdp_clk_src>,
+			 <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			 <&clock_gcc clk_gcc_mdss_vsync_clk>;
+		clock-names = "iface_clk", "bus_clk", "core_clk_src",
+				"core_clk", "vsync_clk";
+
+		qcom,mdp-settings = <0x0506c 0x00000000>,
+				    <0x1506c 0x00000000>,
+				    <0x1706c 0x00000000>,
+				    <0x2506c 0x00000000>;
+
+		qcom,vbif-settings = <0x0d0 0x00000010>;
+
+		qcom,regs-dump-mdp = <0x01000 0x01454>,
+				     <0x02000 0x02064>,
+				     <0x02200 0x02264>,
+				     <0x02400 0x02464>,
+				     <0x05000 0x05150>,
+				     <0x05200 0x05230>,
+				     <0x15000 0x15150>,
+				     <0x17000 0x17150>,
+				     <0x25000 0x25150>,
+				     <0x35000 0x35150>,
+				     <0x45000 0x452bc>,
+				     <0x46000 0x462bc>,
+				     <0x55000 0x5522c>,
+				     <0x65000 0x652c0>,
+				     <0x66000 0x662c0>,
+				     <0x6b800 0x6ba68>,
+				     <0x6c000 0x6c268>,
+				     <0x71000 0x710d4>,
+				     <0x71800 0x718d4>;
+
+		qcom,regs-dump-names-mdp = "MDP",
+			"CTL_0",    "CTL_1", "CTL_2",
+			"VIG0_SSPP", "VIG0",
+			"RGB0_SSPP", "RGB1_SSPP",
+			"DMA0_SSPP",
+			"CURSOR0_SSPP",
+			"LAYER_0", "LAYER_1",
+			"DSPP_0",
+			"WB_0",    "WB_2",
+			"INTF_1",  "INTF_2",
+			"PP_0",    "PP_1";
+
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <0>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+
+		qcom,mdss-pp-offsets {
+			qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>;
+			qcom,mdss-sspp-vig-pcc-off = <0x1780>;
+			qcom,mdss-sspp-rgb-pcc-off = <0x380>;
+			qcom,mdss-sspp-dma-pcc-off = <0x380>;
+			qcom,mdss-lm-pgc-off = <0x3c0>;
+			qcom,mdss-dspp-pcc-off = <0x1700>;
+			qcom,mdss-dspp-pgc-off = <0x17c0>;
+		};
+
+		qcom,mdss-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_reg";
+			qcom,msm-bus,num-cases = <4>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>,
+				<1 590 0 160000>,
+				<1 590 0 320000>;
+		};
+
+		qcom,mdss-hw-rt-bus {
+			/* Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_hw_rt";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<22 512 0 0>,
+				<22 512 0 1000>;
+		};
+
+		smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+			compatible = "qcom,smmu_mdp_unsec";
+			iommus = <&apps_iommu 0xC00 0>; /* For NS ctx bank */
+		};
+		smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+			compatible = "qcom,smmu_mdp_sec";
+			iommus = <&apps_iommu 0xC01 0>; /* For SEC Ctx Bank */
+		};
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,cont-splash-memory {
+				linux,contiguous-region = <&cont_splash_mem>;
+			};
+		};
+
+		mdss_fb1: qcom,mdss_fb_wfd {
+			cell-index = <1>;
+			compatible = "qcom,mdss-fb";
+		};
+
+		mdss_fb2: qcom,mdss_fb_secondary {
+			cell-index = <2>;
+			compatible = "qcom,mdss-fb";
+		};
+	};
+
+	mdss_dsi: qcom,mdss_dsi@0 {
+		compatible = "qcom,mdss-dsi";
+		hw-config = "single_dsi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		gdsc-supply = <&gdsc_mdss>;
+		vdda-supply = <&pm8953_s3>;
+		vcca-supply = <&pm8953_l3>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_dsi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 1000>;
+
+		ranges = <0x1a94000 0x1a94000 0x400
+			0x1a94400 0x1a94400 0x588
+			0x193e000 0x193e000 0x30
+			0x1a96000 0x1a96000 0x400
+			0x1a96400 0x1a96400 0x588
+			0x193e000 0x193e000 0x30>;
+
+		clocks = <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			<&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc clk_gcc_mdss_axi_clk>,
+			<&clock_gcc_mdss clk_ext_byte0_clk_src>,
+			<&clock_gcc_mdss clk_ext_byte1_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk0_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk1_clk_src>;
+		clock-names = "mdp_core_clk", "iface_clk", "bus_clk",
+			"ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk",
+			"ext_pixel1_clk";
+
+		qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+		qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+		qcom,mdss-fb-map-prim = <&mdss_fb0>;
+		qcom,mdss-fb-map-sec = <&mdss_fb2>;
+
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1225000>;
+				qcom,supply-max-voltage = <1225000>;
+				qcom,supply-enable-load = <18160>;
+				qcom,supply-disable-load = <1>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vcca";
+				qcom,supply-min-voltage = <925000>;
+				qcom,supply-max-voltage = <925000>;
+				qcom,supply-enable-load = <17000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+
+		mdss_dsi0: qcom,mdss_dsi_ctrl0@1a94000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->0";
+			cell-index = <0>;
+			reg = <0x1a94000 0x400>,
+				<0x1a94400 0x580>,
+				<0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
+
+			qcom,timing-db-mode;
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8953_l17>;
+			vddio-supply = <&pm8953_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+				<&clock_gcc clk_gcc_mdss_esc0_clk>,
+				<&clock_gcc_mdss clk_byte0_clk_src>,
+				<&clock_gcc_mdss clk_pclk0_clk_src>,
+				<&mdss_dsi0_pll clk_dsi0pll_byte_clk_mux>,
+				<&mdss_dsi0_pll clk_dsi0pll_pixel_clk_mux>,
+				<&mdss_dsi0_pll clk_dsi0pll_byte_clk_src>,
+				<&mdss_dsi0_pll clk_dsi0pll_pixel_clk_src>,
+				<&mdss_dsi0_pll
+					clk_dsi0pll_shadow_byte_clk_src>,
+				<&mdss_dsi0_pll
+					clk_dsi0pll_shadow_pixel_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg",
+				"pll_byte_clk_mux", "pll_pixel_clk_mux",
+				"pll_byte_clk_src", "pll_pixel_clk_src",
+				"pll_shadow_byte_clk_src",
+				"pll_shadow_pixel_clk_src";
+
+			qcom,platform-strength-ctrl = [ff 06
+							ff 06
+							ff 06
+							ff 06
+							ff 00];
+			qcom,platform-regulator-settings = [1d
+							1d 1d 1d 1d];
+			qcom,platform-lane-config = [00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 8f];
+		};
+
+		mdss_dsi1: qcom,mdss_dsi_ctrl1@1a96000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->1";
+			cell-index = <1>;
+			reg = <0x1a96000 0x400>,
+			      <0x1a96400 0x588>,
+			      <0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
+
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8953_l17>;
+			vddio-supply = <&pm8953_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte1_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk1_clk>,
+				<&clock_gcc clk_gcc_mdss_esc1_clk>,
+				<&clock_gcc_mdss clk_byte1_clk_src>,
+				<&clock_gcc_mdss clk_pclk1_clk_src>,
+				<&mdss_dsi1_pll clk_dsi1pll_byte_clk_mux>,
+				<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_mux>,
+				<&mdss_dsi1_pll clk_dsi1pll_byte_clk_src>,
+				<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_src>,
+				<&mdss_dsi1_pll
+					clk_dsi1pll_shadow_byte_clk_src>,
+				<&mdss_dsi1_pll
+					clk_dsi1pll_shadow_pixel_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg",
+				"pll_byte_clk_mux", "pll_pixel_clk_mux",
+				"pll_byte_clk_src", "pll_pixel_clk_src",
+				"pll_shadow_byte_clk_src",
+				"pll_shadow_pixel_clk_src";
+
+			qcom,timing-db-mode;
+			qcom,platform-strength-ctrl = [ff 06
+							ff 06
+							ff 06
+							ff 06
+							ff 00];
+			qcom,platform-regulator-settings = [1d
+							1d 1d 1d 1d];
+			qcom,platform-lane-config = [00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 8f];
+		};
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 640>;
+		qcom,mdss_pan_bpp = <24>;
+		qcom,mdss-fb-map = <&mdss_fb1>;
+	};
+
+	mdss_rotator: qcom,mdss_rotator {
+		compatible = "qcom,mdss_rotator";
+		qcom,mdss-wb-count = <1>;
+		qcom,mdss-has-downscale;
+		qcom,mdss-has-ubwc;
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_rotator";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		rot-vdd-supply = <&gdsc_mdss>;
+		qcom,supply-names = "rot-vdd";
+		qcom,mdss-has-reg-bus;
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc_mdss clk_mdss_rotator_vote_clk>;
+		clock-names = "iface_clk", "rot_core_clk";
+
+		qcom,mdss-rot-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_rot_reg";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
index 49956df..c6ae512 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -20,3 +20,21 @@
 	model = "MTP";
 	qcom,board-id = <8 0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index b53f7b8..82f6315 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-mtp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 MTP";
@@ -33,16 +34,12 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
 };
-
-&usb3 {
-	extcon = <&pmi8950_charger>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
index 87b8c74..76e39f6 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -11,12 +11,48 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart_console_active>;
 };
 
+&pm8953_gpios {
+	nfc_clk {
+		nfc_clk_default: nfc_clk_default {
+			pins = "gpio2";
+			function = "normal";
+			input-enable;
+			power-source = <1>;
+		};
+	};
+};
+
+&i2c_5 { /* BLSP2 QUP1 (NFC) */
+	status = "ok";
+	nq@28 {
+		compatible = "qcom,nq-nci";
+		reg = <0x28>;
+		qcom,nq-irq = <&tlmm 17 0x00>;
+		qcom,nq-ven = <&tlmm 16 0x00>;
+		qcom,nq-firm = <&tlmm 62 0x00>;
+		qcom,nq-clkreq = <&pm8953_gpios 2 0x00>;
+		interrupt-parent = <&tlmm>;
+		qcom,clk-src = "BBCLK2";
+		interrupts = <17 0>;
+		interrupt-names = "nfc_irq";
+		pinctrl-names = "nfc_active", "nfc_suspend";
+		pinctrl-0 = <&nfc_int_active &nfc_disable_active
+						&nfc_clk_default>;
+		pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+		clocks = <&clock_gcc clk_bb_clk2_pin>;
+		clock-names = "ref_clk";
+	};
+};
+
 &sdhc_1 {
 	/* device core power supply */
 	vdd-supply = <&pm8953_l8>;
@@ -74,3 +110,96 @@
 
 	status = "ok";
 };
+
+#include "msm8953-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+		qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,pluggable;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&tlmm 87 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&tlmm 86 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 85 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			debounce-interval = <15>;
+		};
+	};
+};
+
+&thermal_zones {
+	case-therm-step {
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index eec350d..6503b33 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -16,9 +16,11 @@
 		compatible = "qcom,msm8953-pinctrl";
 		reg = <0x1000000 0x300000>;
 		interrupts = <0 208 0>;
+		interrupts-extended = <&wakegic GIC_SPI 208 IRQ_TYPE_NONE>;
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
+		interrupt-parent = <&wakegpio>;
 		#interrupt-cells = <2>;
 
 		pmx-uartconsole {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
new file mode 100644
index 0000000..4639f02
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+#include "sdm450-pmi632-cdp-s2.dtsi"
+#include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. msm8953 + PMI632 CDP S2";
+	compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp";
+	qcom,board-id = <1 2>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi632.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi632.dts
new file mode 100644
index 0000000..2ffb0ab
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi632.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. msm8953 + PMI632 SOC";
+	compatible = "qcom,msm8953";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom,pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
index a9f64a4..5ec92ae 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
index a178aa1..80050c4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
@@ -24,9 +24,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8937_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
index e9c80a0d..ba5c3c7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
index 71d6941..c36dd1b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
@@ -24,6 +24,7 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
 &labibb {
@@ -35,7 +36,7 @@
 	qcom,qpnp-ibb-discharge-resistor = <32>;
 };
 
-&pmi8940_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index b9c2a18..e8bdb7a 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -11,17 +11,6 @@
  * GNU General Public License for more details.
  */
 
-&soc {
-	led_flash0: qcom,camera-flash {
-		cell-index = <0>;
-		compatible = "qcom,camera-flash";
-		qcom,flash-type = <1>;
-		qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
-		qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
-		qcom,switch-source = <&pmi8950_switch>;
-	};
-};
-
 &labibb {
 	status = "ok";
 	qpnp,qpnp-labibb-mode = "lcd";
@@ -29,10 +18,20 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
 
+&mdss_dsi0 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
index 87b8c74..845bf70 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -11,12 +11,76 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+
+&soc {
+	i2c@78b7000 { /* BLSP1 QUP3 */
+		/delete-node/ synaptics@4b;
+	};
+
+	vdd_vreg: vdd_vreg {
+		compatible = "regulator-fixed";
+		status = "ok";
+		regulator-name = "vdd_vreg";
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 85 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			debounce-interval = <15>;
+		};
+	};
+};
+
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart_console_active>;
 };
 
+&pm8953_gpios {
+	nfc_clk {
+		nfc_clk_default: nfc_clk_default {
+			pins = "gpio2";
+			function = "normal";
+			input-enable;
+			power-source = <1>;
+		};
+	};
+};
+
+&i2c_5 { /* BLSP2 QUP1 (NFC) */
+	status = "ok";
+	nq@28 {
+		compatible = "qcom,nq-nci";
+		reg = <0x28>;
+		qcom,nq-irq = <&tlmm 17 0x00>;
+		qcom,nq-ven = <&tlmm 16 0x00>;
+		qcom,nq-firm = <&tlmm 62 0x00>;
+		qcom,nq-clkreq = <&pm8953_gpios 2 0x00>;
+		interrupt-parent = <&tlmm>;
+		qcom,clk-src = "BBCLK2";
+		interrupts = <17 0>;
+		interrupt-names = "nfc_irq";
+		pinctrl-names = "nfc_active", "nfc_suspend";
+		pinctrl-0 = <&nfc_int_active &nfc_disable_active
+						&nfc_clk_default>;
+		pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+		clocks = <&clock_gcc clk_bb_clk2_pin>;
+		clock-names = "ref_clk";
+	};
+};
+
 &sdhc_1 {
 	/* device core power supply */
 	vdd-supply = <&pm8953_l8>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
index 9468181..5a4f024 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
@@ -17,9 +17,11 @@
 	rpm-regulator-smpa1 {
 		status = "okay";
 		pm8953_s1: regulator-s1 {
-			regulator-min-microvolt = <870000>;
-			regulator-max-microvolt = <1156000>;
-			qcom,init-voltage = <1000000>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
 			status = "okay";
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
new file mode 100644
index 0000000..e82e2c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
@@ -0,0 +1,227 @@
+/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+&soc {
+	qcom,smp2p-modem@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
index d5a6f52..54634ce 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
@@ -253,6 +253,21 @@
 		};
 	};
 
+	case-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8953_vadc 0x13>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
 	gpu1-step {
 		polling-delay-passive = <250>;
 		polling-delay = <0>;
@@ -1087,4 +1102,101 @@
 			};
 		};
 	};
+
+	pa-therm0 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8953_adc_tm 0x36>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+	};
+
+	case-therm-step {
+		polling-delay-passive = <2000>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8953_vadc 0x13>;
+		thermal-governor = "step_wise";
+
+		trips {
+			cpus_trip: cpus-trip {
+				temperature = <43000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			modem_trip0: modem-trip0 {
+				temperature = <45000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			modem_trip1: modem-trip1 {
+				temperature = <48000>;
+				hysteresis = <3000>;
+				type = "passive";
+			};
+			modem_trip2: modem-trip2 {
+				temperature = <54000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			skin_cpu0 {
+				trip = <&cpus_trip>;
+				/* throttle from fmax to 1689600KHz */
+				cooling-device = <&CPU0 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu1 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU1 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu2 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU2 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu3 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU3 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu4 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU4 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu5 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU5 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu6 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU6 THERMAL_NO_LIMIT 3>;
+			};
+			skin_cpu7 {
+				trip = <&cpus_trip>;
+				cooling-device = <&CPU7 THERMAL_NO_LIMIT 3>;
+			};
+			modem_lvl1 {
+				trip = <&modem_trip1>;
+				cooling-device = <&modem_pa 2 2>;
+			};
+			modem_lvl2 {
+				trip = <&modem_trip2>;
+				cooling-device = <&modem_pa 3 3>;
+			};
+			modem_proc_lvl1 {
+				trip = <&modem_trip0>;
+				cooling-device = <&modem_proc 1 1>;
+			};
+			modem_proc_lvl2 {
+				trip = <&modem_trip2>;
+				cooling-device = <&modem_proc 3 3>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
new file mode 100644
index 0000000..cb8cdf2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
@@ -0,0 +1,197 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,vidc@1d00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0x01d00000 0xff000>,
+			<0x000a4124 0x4>,
+			<0x000a0164 0x4>;
+		reg-names = "vidc", "efuse", "efuse2";
+		qcom,platform-version = <0x00180000 0x13>;
+		qcom,capability-version = <0x00002000 0x0d>;
+		interrupts = <0 44 0>;
+		/* Regulators */
+		venus-supply = <&gdsc_venus>;
+		venus-core0-supply = <&gdsc_venus_core0>;
+		/* Clocks */
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_ahb_clk>,
+			<&clock_gcc clk_gcc_venus0_axi_clk>;
+		clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+		qcom,clock-configs = <0x1 0x0 0x0 0x0 0x0>;
+		qcom,hfi = "venus";
+		qcom,hfi-version = "3xx";
+		qcom,reg-presets = <0xe0020 0x05555556>,
+			<0xe0024 0x05555556>,
+			<0x80124 0x00000003>;
+		qcom,qdss-presets = <0x825000 0x1000>,
+			<0x826000 0x1000>,
+			<0x821000 0x1000>,
+			<0x802000 0x1000>,
+			<0x9180000 0x1000>,
+			<0x9181000 0x1000>;
+		qcom,max-hw-load = <1044480>; /* 4096 x 2176 @ 30 fps */
+		qcom,slave-side-cp;
+		qcom,sw-power-collapse;
+		qcom,firmware-name = "venus";
+		qcom,pm-qos-latency-us = <213>;
+		qcom,dcvs-tbl =
+			/* Dec UHD@30 H.264, HEVC, VP8, VP9 - NOM to NOM+*/
+			<816000 816000 979200 0x3f00000c>,
+
+			/* Enc 3840x1920@30 H.264/HEVC Turbo to Nom+ */
+			<855000 821100 979200 0x4000004>,
+
+			/* Enc True4K@24 H.264/HEVC Nom to Nom+ */
+			<816000 720000 835584 0x4000004>;
+		qcom,dcvs-limit =
+			<28800 24>, /* Encoder 3840x1920 */
+			<32400 24>; /* Decoder UHD */
+		qcom,allowed-clock-rates = <465000000 400000000
+			360000000 310000000 228570000 114290000>;
+		qcom,clock-freq-tbl {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,cycles-per-mb = <863>;
+				qcom,low-power-mode-factor = <35616>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xf3ffffff>;
+				qcom,cycles-per-mb = <355>;
+			};
+			qcom,profile-hevcdec {
+				qcom,codec-mask = <0x0c000000>;
+				qcom,cycles-per-mb = <400>;
+			};
+		};
+
+		/* MMUs */
+		non_secure_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_ns";
+			iommus = <&apps_iommu 0x800 0x01>,
+				<&apps_iommu 0x807 0x00>,
+				<&apps_iommu 0x808 0x07>,
+				<&apps_iommu 0x810 0x01>,
+				<&apps_iommu 0x828 0x01>,
+				<&apps_iommu 0x82c 0x01>,
+				<&apps_iommu 0x821 0x10>;
+			buffer-types = <0xfff>;
+			virtual-addr-pool = <0x5dc00000 0x7f000000
+				0xdcc00000 0x1000000>;
+		};
+
+		secure_bitstream_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_bitstream";
+			 iommus = <&apps_iommu 0x900 0x0>,
+				<&apps_iommu 0x902 0x8>,
+				<&apps_iommu 0x909 0x2>,
+				<&apps_iommu 0x90e 0x0>,
+				<&apps_iommu 0x926 0x0>,
+				<&apps_iommu 0x929 0x2>;
+			buffer-types = <0x241>;
+			virtual-addr-pool = <0x4b000000 0x12c00000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_pixel";
+			iommus = <&apps_iommu 0x904 0x8>,
+				<&apps_iommu 0x910 0x0>,
+				<&apps_iommu 0x92c 0x0>;
+			buffer-types = <0x106>;
+			virtual-addr-pool = <0x25800000 0x25800000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_non_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_non_pixel";
+			iommus = <&apps_iommu 0x908 0x0>,
+				<&apps_iommu 0x905 0xa>,
+				<&apps_iommu 0x925 0x8>,
+				<&apps_iommu 0x928 0x0>;
+			buffer-types = <0x480>;
+			virtual-addr-pool = <0x1000000 0x24800000>;
+			qcom,secure-context-bank;
+		};
+
+		/* Buses */
+		venus_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "venus-ddr-gov";
+			qcom,bus-range-kbps = <1000 2365000>;
+		};
+
+		arm9_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-arm9-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "performance";
+			qcom,bus-range-kbps = <1 1>;
+		};
+	};
+
+	venus-ddr-gov {
+		compatible = "qcom,msm-vidc,governor,table";
+		name = "venus-ddr-gov";
+		status = "ok";
+		qcom,bus-freq-table {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,load-busfreq-tbl =
+					<979200 1044000>,  /* UHD30E     */
+					<864000 887000>,   /* 720p240LPE */
+					<489600 666000>,   /* 1080p60E   */
+					<432000 578000>,   /* 720p120E   */
+					<244800 346000>,   /* 1080p30E   */
+					<216000 293000>,   /* 720p60E    */
+					<108000 151000>,   /* 720p30E    */
+					<0 0>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,load-busfreq-tbl =
+					<979200 2365000>,  /* UHD30D     */
+					<864000 1978000>,  /* 720p240D   */
+					<489600 1133000>,  /* 1080p60D   */
+					<432000 994000>,   /* 720p120D   */
+					<244800 580000>,   /* 1080p30D   */
+					<216000 501000>,   /* 720p60E    */
+					<108000 255000>,   /* 720p30D    */
+					<0 0>;
+			};
+			qcom,profile-dec-ubwc {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,ubwc-mode;
+				qcom,load-busfreq-tbl =
+					<979200 1892000>,  /* UHD30D     */
+					<864000 1554000>,  /* 720p240D   */
+					<489600 895000>,   /* 1080p60D   */
+					<432000 781000>,   /* 720p120D   */
+					<244800 460000>,   /* 1080p30D   */
+					<216000 301000>,   /* 720p60E    */
+					<108000 202000>,   /* 720p30D    */
+					<0 0>;
+			};
+		};
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi
new file mode 100644
index 0000000..86f5323
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-wsa881x.dtsi
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&slim_msm {
+	tasha_codec {
+		swr_master {
+			compatible = "qcom,swr-wcd";
+			qcom,swr-num-dev = <2>;
+			#address-cells = <2>;
+			#size-cells = <0>;
+
+			wsa881x_211: wsa881x@20170211 {
+				compatible = "qcom,wsa881x";
+				reg = <0x00 0x20170211>;
+				qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+			};
+
+			wsa881x_212: wsa881x@20170212 {
+				compatible = "qcom,wsa881x";
+				reg = <0x00 0x20170212>;
+				qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+			};
+
+			wsa881x_213: wsa881x@21170213 {
+				compatible = "qcom,wsa881x";
+				reg = <0x00 0x21170213>;
+				qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+			};
+
+			wsa881x_214: wsa881x@21170214 {
+				compatible = "qcom,wsa881x";
+				reg = <0x00 0x21170214>;
+				qcom,spkr-sd-n-gpio = <&tlmm 96 0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
index ddf2218..2f6cbc4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 69cd4fc..bb370cc 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -23,11 +23,7 @@
 	compatible = "qcom,msm8953";
 	qcom,msm-id = <293 0x0>;
 	qcom,msm-name = "MSM8953";
-	interrupt-parent = <&intc>;
-
-	chosen {
-		bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1";
-	};
+	interrupt-parent = <&wakegic>;
 
 	firmware: firmware {
 		android {
@@ -103,6 +99,14 @@
 			compatible = "shared-dma-pool";
 			reusable;
 			alignment = <0 0x400000>;
+			size = <0 0x0400000>;
+		};
+
+		qseecom_ta_mem: qseecom_ta_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
 			size = <0 0x1000000>;
 		};
 
@@ -113,8 +117,9 @@
 		};
 
 		dfps_data_mem: dfps_data_mem@90000000 {
-		       reg = <0 0x90000000 0 0x1000>;
-		       label = "dfps_data_mem";
+			reg = <0 0x90000000 0 0x1000>;
+			label = "dfps_data_mem";
+			status = "disabled";
 		};
 
 		cont_splash_mem: splash_region@0x90001000 {
@@ -129,6 +134,12 @@
 			alignment = <0 0x400000>;
 			size = <0 0x800000>;
 		};
+
+		dump_mem: mem_dump_region {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x2400000>;
+		};
 	};
 
 	aliases {
@@ -163,7 +174,11 @@
 #include "msm8953-coresight.dtsi"
 #include "msm8953-ion.dtsi"
 #include "msm-arm-smmu-8953.dtsi"
+#include "msm8953-vidc.dtsi"
 #include "msm8953-gpu.dtsi"
+#include "msm8953-mdss.dtsi"
+#include "msm8953-mdss-pll.dtsi"
+#include "msm8953-smp2p.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -195,11 +210,31 @@
 	intc: interrupt-controller@b000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
+		interrupt-parent = <&intc>;
 		#interrupt-cells = <3>;
 		reg = <0x0b000000 0x1000>,
 		      <0x0b002000 0x1000>;
 	};
 
+	wakegic: wake-gic@601d4 {
+		compatible = "qcom,mpm-gic-msm8953", "qcom,mpm-gic";
+		interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+		reg = <0x601d4 0x1000>,
+			<0xb011008 0x4>;  /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		qcom,num-mpm-irqs = <96>;
+		interrupt-controller;
+		interrupt-parent = <&intc>;
+		#interrupt-cells = <3>;
+	};
+
+	wakegpio: wake-gpio {
+		compatible = "qcom,mpm-gpio-msm8953", "qcom,mpm-gpio";
+		interrupt-controller;
+		interrupt-parent = <&intc>;
+		#interrupt-cells = <2>;
+	};
+
 	qcom,msm-gladiator@b1c0000 {
 		compatible = "qcom,msm-gladiator";
 		reg = <0x0b1c0000 0x4000>;
@@ -306,6 +341,52 @@
 
 	thermal_zones: thermal-zones {};
 
+	mem_dump {
+		compatible = "qcom,mem-dump";
+		memory-region = <&dump_mem>;
+
+		rpmh_dump {
+			qcom,dump-size = <0x2000000>;
+			qcom,dump-id = <0xec>;
+		};
+
+		fcm_dump {
+			qcom,dump-size = <0x8400>;
+			qcom,dump-id = <0xee>;
+		};
+
+		rpm_sw_dump {
+			qcom,dump-size = <0x28000>;
+			qcom,dump-id = <0xea>;
+		};
+
+		pmic_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xe4>;
+		};
+
+		tmc_etf_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xf0>;
+		};
+
+		tmc_etr_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x100>;
+		};
+
+		tmc_etf_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x101>;
+		};
+
+		misc_data_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0xe8>;
+		};
+
+	};
+
 	tsens0: tsens@4a8000 {
 		compatible = "qcom,msm8953-tsens";
 		reg = <0x4a8000 0x1000>,
@@ -651,6 +732,19 @@
 		status = "disabled";
 	};
 
+	clock_gcc_mdss: qcom,gcc-mdss@1800000 {
+		compatible = "qcom,gcc-mdss-8953";
+		reg = <0x1800000 0x80000>;
+		reg-names = "cc_base";
+		clock-names = "pclk0_src", "pclk1_src",
+			"byte0_src", "byte1_src";
+		clocks = <&mdss_dsi0_pll clk_dsi0pll_pixel_clk_mux>,
+			<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_mux>,
+			<&mdss_dsi0_pll clk_dsi0pll_byte_clk_mux>,
+			<&mdss_dsi1_pll clk_dsi1pll_byte_clk_mux>;
+		#clock-cells = <1>;
+	};
+
 	clock_gcc: qcom,gcc@1800000 {
 		compatible = "qcom,gcc-8953";
 		reg = <0x1800000 0x80000>,
@@ -1144,6 +1238,11 @@
 			reg = <0x94c 200>;
 
 		};
+
+		diag_dload@c8 {
+			compatible = "qcom,msm-imem-diag-dload";
+			reg = <0xc8 200>;
+		};
 	};
 
 	qcom,memshare {
@@ -1164,10 +1263,11 @@
 			label = "modem";
 		};
 
-		mem_client_3_size: qcom,client_3 {
+		qcom,client_3 {
 			compatible = "qcom,memshare-peripheral";
-			qcom,peripheral-size = <0x0>;
+			qcom,peripheral-size = <0x500000>;
 			qcom,client-id = <1>;
+			qcom,allocate-boot-time;
 			label = "modem";
 		};
 	};
@@ -1281,6 +1381,22 @@
 		status = "disabled";
 	};
 
+	qcom,msm-adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
+	qcom,msm_fastrpc {
+		compatible = "qcom,msm-fastrpc-legacy-compute";
+		qcom,msm_fastrpc_compute_cb {
+			compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_iommu 0x2408 0x7>;
+			sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+		};
+	};
+
+
 	ipa_hw: qcom,ipa@07900000 {
 		compatible = "qcom,ipa";
 		reg = <0x07900000 0x4effc>, <0x07904000 0x26934>;
@@ -1326,8 +1442,8 @@
 		interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
 		qcom,ee = <0>;
 		qcom,channel = <0>;
-		#address-cells = <2>;
-		#size-cells = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
 		interrupt-controller;
 		#interrupt-cells = <4>;
 		cell-index = <0>;
@@ -1843,6 +1959,11 @@
 		qcom,wcnss-adc_tm = <&pm8953_adc_tm>;
 	};
 
+	ssc_sensors: qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		status = "ok";
+	};
+
 };
 
 #include "pm8953-rpm-regulator.dtsi"
@@ -1850,6 +1971,8 @@
 #include "msm8953-regulator.dtsi"
 #include "msm-gdsc-8916.dtsi"
 #include "msm8953-thermal.dtsi"
+#include "msm8953-camera.dtsi"
+#include "msm8953-audio.dtsi"
 
 &gdsc_venus {
 	clock-names = "bus_clk", "core_clk";
diff --git a/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
new file mode 100644
index 0000000..ff91250
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm660-rpm-regulator.dtsi
@@ -0,0 +1,381 @@
+/* Copyright (c) 2016-2018, 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s3 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s4 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa5 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s5 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa6 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s6 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_s6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l1 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l3 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l5 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l6 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l7 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l8 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l8";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l9 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l9";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l10 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l10";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <11>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l11 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l11";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l12 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l12";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <13>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l13 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l13";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l14 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l14";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <15>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l15 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l15";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <16>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l16 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l16";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <17>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l17 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l17";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <18>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l18 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l18";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <19>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l19 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm660_l19";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 4830af4..fa10500 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -218,7 +218,6 @@
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
 			};
 
 			chan@4f {
@@ -230,7 +229,6 @@
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
 			};
 
 			chan@1d {
@@ -504,25 +502,11 @@
 
 		trips {
 			pm660_vbat_adc: vbat-adc {
-				temperature = <3300>;
+				temperature = <3200>;
 				hysteresis = <100>;
 				type = "passive";
 			};
 		};
-		cooling-maps {
-			vbat_map6 {
-				trip = <&pm660_vbat_adc>;
-				cooling-device =
-					<&CPU6 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			vbat_map7 {
-				trip = <&pm660_vbat_adc>;
-				cooling-device =
-					<&CPU7 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-		};
 	};
 
 	vbat_low {
@@ -534,7 +518,7 @@
 
 		trips {
 			vbat-low {
-				temperature = <3100>;
+				temperature = <2800>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -550,7 +534,7 @@
 
 		trips {
 			vbat-too-low {
-				temperature = <2900>;
+				temperature = <2600>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -571,20 +555,6 @@
 				type = "passive";
 			};
 		};
-		cooling-maps {
-			soc_map6 {
-				trip = <&pm660_low_soc>;
-				cooling-device =
-					<&CPU6 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			soc_map7 {
-				trip = <&pm660_low_soc>;
-				cooling-device =
-					<&CPU7 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-		};
 	};
 
 	pm660_temp_alarm: pm660_tz {
@@ -610,97 +580,5 @@
 				type = "critical";
 			};
 		};
-		cooling-maps {
-			trip0_cpu0 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU0 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu1 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU1 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu2 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU2 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu3 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU3 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu4 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU4 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu5 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU5 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu6 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU6 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip0_cpu7 {
-				trip = <&pm660_trip0>;
-				cooling-device =
-					<&CPU7 (THERMAL_MAX_LIMIT-1)
-						(THERMAL_MAX_LIMIT-1)>;
-			};
-			trip1_cpu1 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU1 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu2 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU2 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu3 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU3 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu4 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU4 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu5 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU5 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu6 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU6 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-			trip1_cpu7 {
-				trip = <&pm660_trip1>;
-				cooling-device =
-					<&CPU7 THERMAL_MAX_LIMIT
-						THERMAL_MAX_LIMIT>;
-			};
-		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi
new file mode 100644
index 0000000..6da90de
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8909-rpm-regulator.dtsi
@@ -0,0 +1,317 @@
+/* Copyright (c) 2016, 2018 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s1 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_s2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l1 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l3 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l4 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l5 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l6 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l7 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l8 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l8";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l9 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l9";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l10 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l10";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <11>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l11 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l11";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l12 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l12";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <13>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l13 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l13";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l14 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l14";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <15>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l15 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l15";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <17>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l17 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l17";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <18>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l18 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8909_l18";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi
index 6a61445..fff83d5 100644
--- a/arch/arm64/boot/dts/qcom/pm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi
@@ -92,6 +92,24 @@
 					  "pm8937_mpp3", "pm8937_mpp4";
 			gpio-controller;
 			#gpio-cells = <2>;
+
+			case_therm {
+				cas_therm_default: cas_therm_default {
+					pins = "mpp4";
+					function = "analog";
+					input-enable;
+					qcom,amux-route = <3>;
+				};
+			};
+
+			pa_therm1 {
+				pa_therm1_default: pa_therm1_default {
+					pins = "mpp2";
+					function = "analog";
+					input-enable;
+					qcom,amux-route = <1>;
+				};
+			};
 		};
 
 		pm8937_gpios: gpios {
@@ -120,6 +138,9 @@
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,vadc-poll-eoc;
+			#thermal-sensor-cells = <1>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pa_therm1_default &cas_therm_default>;
 
 			chan@5 {
 				label = "vcoin";
@@ -307,3 +328,80 @@
 		};
 	};
 };
+
+&thermal_zones {
+	pa-therm1-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8937_vadc 0x11>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8937_vadc 0x32>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	xo-therm-buf-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8937_vadc 0x3c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	case-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8937_vadc 0x13>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm0-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8937_adc_tm 0x36>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi
index d77de72..3a587a8 100644
--- a/arch/arm64/boot/dts/qcom/pm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi
@@ -35,6 +35,7 @@
 				"resin-bark", "kpdpwr-resin-bark";
 			qcom,pon-dbc-delay = <15625>;
 			qcom,system-reset;
+			qcom,store-hard-reset-reason;
 
 			qcom,pon_1 {
 				qcom,pon-type = <0>;
@@ -78,6 +79,24 @@
 
 			gpio-controller;
 			#gpio-cells = <2>;
+
+			case_therm {
+				cas_therm_default: cas_therm_default {
+					pins = "mpp4";
+					function = "analog";
+					input-enable;
+					qcom,amux-route = <3>;
+				};
+			};
+
+			pa_therm1 {
+				pa_therm1_default: pa_therm1_default {
+					pins = "mpp2";
+					function = "analog";
+					input-enable;
+					qcom,amux-route = <1>;
+				};
+			};
 		};
 
 		pm8953_gpios: gpios {
@@ -85,15 +104,18 @@
 			reg = <0xc000 0x800>;
 
 			interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+				<0x0 0xc1 0 IRQ_TYPE_NONE>,
 				<0x0 0xc3 0 IRQ_TYPE_NONE>,
+				<0x0 0xc4 0 IRQ_TYPE_NONE>,
 				<0x0 0xc6 0 IRQ_TYPE_NONE>,
 				<0x0 0xc7 0 IRQ_TYPE_NONE>;
-			interrupt-names = "pm8953_gpio1", "pm8953_gpio4",
+			interrupt-names = "pm8953_gpio1", "pm8953_gpio2",
+					"pm8953_gpio4", "pm8953_gpio5",
 					"pm8953_gpio7", "pm8953_gpio8";
 
 			gpio-controller;
 			#gpio-cells = <2>;
-			qcom,gpios-disallowed = <2 3 5 6>;
+			qcom,gpios-disallowed = <3 6>;
 		};
 
 		pm8953_vadc: vadc@3100 {
@@ -106,6 +128,9 @@
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,vadc-poll-eoc;
+			#thermal-sensor-cells = <1>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pa_therm1_default &cas_therm_default>;
 
 			chan@5 {
 				label = "vcoin";
@@ -228,6 +253,7 @@
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
+				qcom,vadc-thermal-node;
 			};
 		};
 
@@ -245,6 +271,7 @@
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,adc_tm-vadc = <&pm8953_vadc>;
+			#thermal-sensor-cells = <1>;
 		};
 
 		pm8953_rtc: qcom,pm8953_rtc {
@@ -292,19 +319,47 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		pm8953_pwm: pwm@bc00 {
+		pm8953_pwm: qcom,pwms@bc00 {
 			status = "disabled";
-			compatible = "qcom,qpnp-pwm";
+			compatible = "qcom,pwm-lpg";
 			reg = <0xbc00 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <0>;
-			qcom,supported-sizes = <6>, <9>;
+			reg-names = "lpg-base";
 			#pwm-cells = <2>;
 		};
 	};
 };
 
 &thermal_zones {
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8953_vadc 0x32>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	xo-therm-buf-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8953_vadc 0x3c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
 	pm8953_tz {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 074b7da..fea37c9 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -18,8 +18,8 @@
 	qcom,pmi632@2 {
 		compatible = "qcom,spmi-pmic";
 		reg = <0x2 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
 
 		pmi632_revid: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
@@ -37,7 +37,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-vdd-reference = <1875>;
 			qcom,adc-full-scale-code = <0x70e4>;
@@ -214,70 +214,270 @@
 			#gpio-cells = <2>;
 			qcom,gpios-disallowed = <1>;
 		};
+
+		pmi632_charger: qcom,qpnp-smb5 {
+			compatible = "qcom,qpnp-smb5";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#cooling-cells = <2>;
+
+			qcom,pmic-revid = <&pmi632_revid>;
+			dpdm-supply = <&qusb_phy>;
+			qcom,auto-recharge-soc = <98>;
+
+			qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =
+					<0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "chgr-error",
+						  "chg-state-change",
+						  "step-chg-state-change",
+						  "step-chg-soc-update-fail",
+						  "step-chg-soc-update-req",
+						  "fg-fvcal-qualified",
+						  "vph-alarm",
+						  "vph-drop-prechg";
+			};
+
+			qcom,dcdc@1100 {
+				reg = <0x1100 0x100>;
+				interrupts =
+					<0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "otg-fail",
+						  "otg-oc-disable-sw",
+						  "otg-oc-hiccup",
+						  "bsm-active",
+						  "high-duty-cycle",
+						  "input-current-limiting",
+						  "concurrent-mode-disable",
+						  "switcher-power-ok";
+			};
+
+			qcom,batif@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =
+					<0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "bat-temp",
+						  "all-chnl-conv-done",
+						  "bat-ov",
+						  "bat-low",
+						  "bat-therm-or-id-missing",
+						  "bat-terminal-missing",
+						  "buck-oc",
+						  "vph-ov";
+			};
+
+			qcom,usb@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =
+					<0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "usbin-collapse",
+						  "usbin-vashdn",
+						  "usbin-uv",
+						  "usbin-ov",
+						  "usbin-plugin",
+						  "usbin-revi-change",
+						  "usbin-src-change",
+						  "usbin-icl-change";
+			};
+
+			qcom,typec@1500 {
+				reg = <0x1500 0x100>;
+				interrupts =
+					<0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "typec-or-rid-detect-change",
+						  "typec-vpd-detect",
+						  "typec-cc-state-change",
+						  "typec-vconn-oc",
+						  "typec-vbus-change",
+						  "typec-attach-detach",
+						  "typec-legacy-cable-detect",
+						  "typec-try-snk-src-detect";
+			};
+
+			qcom,misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts =
+					<0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "wdog-snarl",
+						  "wdog-bark",
+						  "aicl-fail",
+						  "aicl-done",
+						  "smb-en",
+						  "imp-trigger",
+						  "temp-change",
+						  "temp-change-smb";
+			};
+
+			qcom,schgm-flash@a600 {
+				reg = <0xa600 0x100>;
+				interrupts =
+					<0x2 0xa6 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0xa6 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0xa6 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0xa6 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "flash-state-change",
+						"ilim1-s1",
+						"ilim2-s2",
+						"vreg-ok";
+			};
+
+			smb5_vbus: qcom,smb5-vbus {
+				regulator-name = "smb5-vbus";
+			};
+		};
+
+		pmi632_qg: qpnp,qg {
+			compatible = "qcom,qpnp-qg";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,vbatt-empty-mv = <3300>;
+			qcom,vbatt-low-mv = <3500>;
+			qcom,vbatt-cutoff-mv = <3400>;
+			qcom,qg-iterm-ma = <100>;
+			qcom,hold-soc-while-full;
+			qcom,linearize-soc;
+			qcom,qg-vadc = <&pmi632_vadc>;
+			qcom,pmic-revid = <&pmi632_revid>;
+
+			qcom,qgauge@4800 {
+				status = "okay";
+				reg = <0x4800 0x100>;
+				interrupts = <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x2 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x3 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x4 IRQ_TYPE_EDGE_BOTH>;
+				interrupt-names = "qg-batt-missing",
+						  "qg-vbat-low",
+						  "qg-vbat-empty",
+						  "qg-fifo-done",
+						  "qg-good-ocv";
+			};
+
+			qcom,qg-sdam@b100 {
+				status = "okay";
+				reg = <0xb100 0x100>;
+			};
+		};
+
+		bcl_sensor: bcl@3d00 {
+			compatible = "qcom,bcl-v5";
+			reg = <0x3d00 0x100>;
+			interrupts = <0x2 0x3d 0x0 IRQ_TYPE_NONE>,
+					<0x2 0x3d 0x1 IRQ_TYPE_NONE>,
+					<0x2 0x3d 0x0 IRQ_TYPE_NONE>,
+					<0x2 0x3d 0x1 IRQ_TYPE_NONE>,
+					<0x2 0x3d 0x2 IRQ_TYPE_NONE>;
+			interrupt-names = "bcl-ibat-lvl0",
+						"bcl-ibat-lvl1",
+						"bcl-vbat-lvl0",
+						"bcl-vbat-lvl1",
+						"bcl-vbat-lvl2";
+			#thermal-sensor-cells = <1>;
+		};
+
+		bcl_soc: bcl-soc {
+			compatible = "qcom,msm-bcl-soc";
+			#thermal-sensor-cells = <0>;
+		};
 	};
 
 	pmi632_3: qcom,pmi632@3 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x3 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
 
 		pmi632_vib: qcom,vibrator@5700 {
 			compatible = "qcom,qpnp-vibrator-ldo";
 			reg = <0x5700 0x100>;
-			qcom,vib-ldo-volt-uv = <1504000>;
+			qcom,vib-ldo-volt-uv = <3000000>;
 			qcom,vib-overdrive-volt-uv = <3544000>;
-			status = "disabled";
 		};
 
-		pmi632_pwm_1: pwm@b300 {
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb300 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <1>;
-			qcom,supported-sizes = <6>, <9>;
+		pmi632_pwm: qcom,pwms@b300 {
+			compatible = "qcom,pwm-lpg";
+			reg = <0xb300 0x500>;
+			reg-names = "lpg-base";
 			#pwm-cells = <2>;
-			status = "disabled";
 		};
 
-		pmi632_pwm_2: pwm@b400 {
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb400 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <2>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-			status = "disabled";
-		};
-
-		pmi632_pwm_3: pwm@b500 {
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb500 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <3>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-			status = "disabled";
-		};
-
-		pmi632_pwm_4: pwm@b600 {
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb600 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <4>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-			status = "disabled";
-		};
-
-		pmi632_pwm_5: pwm@b700 {
-			compatible = "qcom,qpnp-pwm";
-			reg = <0xb700 0x100>;
-			reg-names = "qpnp-lpg-channel-base";
-			qcom,channel-id = <5>;
-			qcom,supported-sizes = <6>, <9>;
-			#pwm-cells = <2>;
-			status = "disabled";
+		pmi632_rgb: qcom,leds@d000 {
+			compatible = "qcom,tri-led";
+			reg = <0xd000 0x100>;
+			red {
+				label = "red";
+				pwms = <&pmi632_pwm 0 1000000>;
+				led-sources = <0>;
+				linux,default-trigger = "timer";
+			};
+			green {
+				label = "green";
+				pwms = <&pmi632_pwm 1 1000000>;
+				led-sources = <1>;
+				linux,default-trigger = "timer";
+			};
+			blue {
+				label = "blue";
+				pwms = <&pmi632_pwm 2 1000000>;
+				led-sources = <2>;
+				linux,default-trigger = "timer";
+			};
 		};
 
 		pmi632_lcdb: qpnp-lcdb@ec00 {
@@ -304,5 +504,197 @@
 				regulator-max-microvolt = <6000000>;
 			};
 		};
+
+		flash_led: qcom,leds@d300 {
+			compatible = "qcom,qpnp-flash-led-v2";
+			status = "okay";
+			reg = <0xd300 0x100>;
+			label = "flash";
+			interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>,
+				     <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>,
+				     <0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "led-fault-irq",
+					  "all-ramp-down-done-irq",
+					  "all-ramp-up-done-irq";
+			qcom,short-circuit-det;
+			qcom,open-circuit-det;
+			qcom,vph-droop-det;
+			qcom,thermal-derate-en;
+			qcom,thermal-derate-current = <200 500 1000>;
+			qcom,isc-delay = <192>;
+			qcom,pmic-revid = <&pmi632_revid>;
+
+			pmi632_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 = <400>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pmi632_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 = <400>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pmi632_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 = <400>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pmi632_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 = <400>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pmi632_switch0: qcom,led_switch_0 {
+				label = "switch";
+				qcom,led-name = "led:switch_0";
+				qcom,led-mask = <3>;
+				qcom,default-led-trigger = "switch0_trigger";
+			};
+
+			pmi632_switch1: qcom,led_switch_1 {
+				label = "switch";
+				qcom,led-name = "led:switch_1";
+				qcom,led-mask = <2>;
+				qcom,default-led-trigger = "switch1_trigger";
+			};
+
+		};
+
+	};
+};
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi632_flash0 &pmi632_flash1>;
+		qcom,torch-source = <&pmi632_torch0 &pmi632_torch1>;
+		qcom,switch-source = <&pmi632_switch0>;
+	};
+};
+
+&thermal_zones {
+	pmi-ibat-lvl0 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&bcl_sensor 0>;
+
+		trips {
+			pmi632_ibat:ibat-lvl0 {
+				temperature = <3500>;
+				hysteresis = <200>;
+				type = "passive";
+			};
+		};
+	};
+
+	pmi-ibat-lvl1 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&bcl_sensor 1>;
+
+		trips {
+			ibat-lvl1 {
+				temperature = <4000>;
+				hysteresis = <200>;
+				type = "passive";
+			};
+		};
+	};
+
+	pmi-vbat-lvl0 {
+		polling-delay-passive = <100>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 2>;
+		tracks-low;
+
+		trips {
+			pmi632_vbat_lvl0: vbat-lvl0 {
+				temperature = <3000>;
+				hysteresis = <100>;
+				type = "passive";
+			};
+		};
+	};
+
+	pmi-vbat-lvl1 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 3>;
+		tracks-low;
+
+		trips {
+			vbat-lvl1 {
+				temperature = <2800>;
+				hysteresis = <100>;
+				type = "passive";
+			};
+		};
+	};
+
+	pmi-vbat-lvl2 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 4>;
+		tracks-low;
+
+		trips {
+			vbat-lvl1 {
+				temperature = <2600>;
+				hysteresis = <100>;
+				type = "passive";
+			};
+		};
+	};
+
+	soc {
+		polling-delay-passive = <100>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_soc>;
+		tracks-low;
+
+		trips {
+			pmi632_low_soc: low-soc {
+				temperature = <10>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index a7aa08a..c72225d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -153,7 +153,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8937_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -268,7 +268,7 @@
 			};
 		};
 
-		pmi8937_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index c6d5c87..d83145c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -152,7 +152,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8940_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -264,7 +264,7 @@
 			};
 		};
 
-		pmi8940_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 97be32de..8797ea8 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -11,13 +11,15 @@
  */
 
 #include <dt-bindings/msm/power-on.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
 
 &spmi_bus {
 	qcom,pmi8950@2 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x2 SPMI_USID>;
-		#address-cells = <2>;
-		#size-cells = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
 
 		pmi8950_revid: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
@@ -48,6 +50,7 @@
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,vadc-poll-eoc;
+			#thermal-sensor-cells = <1>;
 
 			chan@0 {
 				label = "usbin";
@@ -166,7 +169,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8950_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -282,7 +285,7 @@
 			};
 		};
 
-		pmi8950_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -585,28 +588,53 @@
 		};
 
 		pmi_haptic: qcom,haptic@c000 {
-			compatible = "qcom,qpnp-haptic";
+			compatible = "qcom,qpnp-haptics";
 			reg = <0xc000 0x100>;
 			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
 					<0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
-			interrupt-names = "sc-irq", "play-irq";
+			interrupt-names = "hap-sc-irq", "hap-play-irq";
 			qcom,pmic-revid = <&pmi8950_revid>;
-			vcc_pon-supply = <&pon_perph_reg>;
 			qcom,play-mode = "direct";
 			qcom,wave-play-rate-us = <5263>;
-			qcom,actuator-type = "erm";
+			qcom,actuator-type = <0>;
 			qcom,wave-shape = "square";
 			qcom,vmax-mv = <2000>;
 			qcom,ilim-ma = <800>;
 			qcom,sc-deb-cycles = <8>;
-			qcom,int-pwm-freq-khz = <505>;
 			qcom,en-brake;
-			qcom,brake-pattern = [03 03 00 00];
-			qcom,use-play-irq;
-			qcom,use-sc-irq;
-			qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e];
+			qcom,brake-pattern = <0x3 0x3 0x0 0x0>;
+			qcom,wave-samples = <0x3e 0x3e 0x3e 0x3e 0x3e
+							0x3e 0x3e 0x3e>;
 			qcom,wave-rep-cnt = <1>;
 			qcom,wave-samp-rep-cnt = <1>;
 		};
 	};
 };
+
+&thermal_zones {
+	chg-temp-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pmi8950_vadc 0xd>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+		qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+		qcom,switch-source = <&pmi8950_switch>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
index 0983acf..de25ae9 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
@@ -43,10 +43,107 @@
 	status = "disabled";
 };
 
-&dsi_dual_nt35597_truly_video {
+&dsi_dual_nt35597_truly_video_display {
 	status = "disabled";
 };
 
+&qupv3_se9_i2c {
+	status = "okay";
+	lt9611@3b {
+		compatible = "lt,lt9611";
+		reg = <0x3b>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <125 0>;
+		interrupt-names = "lt_irq";
+		lt,irq-gpio = <&tlmm 125 0x0>;
+		lt,reset-gpio = <&tlmm 134 0x0>;
+		lt,hdmi-ps-gpio = <&tlmm 136 0x0>;
+		lt,hdmi-en-gpio = <&tlmm 137 0x0>;
+		lt,non-pluggable;
+
+		vcc-supply = <&pm660l_l6>;
+		vdd-supply = <&pm660_l11>;
+		lt,supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			lt,supply-entry@0 {
+				reg = <0>;
+				lt,supply-name = "vcc";
+				lt,supply-min-voltage = <3300000>;
+				lt,supply-max-voltage = <3300000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+
+			lt,supply-entry@1 {
+				reg = <1>;
+				lt,supply-name = "vdd";
+				lt,supply-min-voltage = <1800000>;
+				lt,supply-max-voltage = <1800000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+		};
+
+		lt,customize-modes {
+			lt,customize-mode-id@0 {
+				lt,mode-h-active = <1920>;
+				lt,mode-h-front-porch = <88>;
+				lt,mode-h-pulse-width = <44>;
+				lt,mode-h-back-porch = <148>;
+				lt,mode-h-active-high;
+				lt,mode-v-active = <1080>;
+				lt,mode-v-front-porch = <4>;
+				lt,mode-v-pulse-width = <5>;
+				lt,mode-v-back-porch = <36>;
+				lt,mode-v-active-high;
+				lt,mode-refresh-rate = <60>;
+				lt,mode-clock-in-khz = <148500>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lt9611_in: endpoint {
+					remote-endpoint = <&ext_dsi_out>;
+				};
+			};
+		};
+	};
+};
+
+&soc {
+	qcom,dsi-display@17 {
+		qcom,dsi-display-active;
+
+		ports {
+			port@0 {
+				endpoint {
+					remote-endpoint = <&lt9611_in>;
+				};
+			};
+		};
+	};
+};
+
+/delete-node/ &mtp_batterydata;
+
+&vendor {
+	qcs_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-vrcamera-1300mah.dtsi"
+	};
+};
+
+&pm660_fg {
+	qcom,battery-data = <&qcs_batterydata>;
+};
+
 &int_codec {
 	qcom,model = "sdm670-360cam-snd-card";
 	qcom,audio-routing =
@@ -172,6 +269,8 @@
 				&wifi_led_green_default
 				&wifi_led_red_default>;
 		status = "okay";
+		vdd_ldo_1-supply = <&pm660_l15>;
+		vdd_ldo_2-supply = <&pm660_l17>;
 
 		led@1 {
 			label = "PWR_LED:red:106";
@@ -215,7 +314,7 @@
 			label = "cam_snapshot";
 			gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
 			linux,input-type = <1>;
-			linux,code = <766>;
+			linux,code = <767>;
 			gpio-key,wakeup;
 			debounce-interval = <15>;
 			linux,can-disable;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
index 01471b6..1429880 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -32,3 +32,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
index ea10fa0..6c6012e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -26,3 +26,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
index 194bfeb..3ca53b7 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -11,14 +11,14 @@
  * GNU General Public License for more details.
  */
 
+
 /dts-v1/;
 
-#include "qcs605.dtsi"
+#include "qcs605-lc.dtsi"
 #include "qcs605-lc-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
 	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
 	qcom,board-id = <8 4>;
-
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
index 025d9a2..f592c0e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,196 +10,77 @@
  * GNU General Public License for more details.
  */
 
-#include "pm8005.dtsi"
-#include "sdm670-pmic-overlay.dtsi"
-#include "qcs605-pm660-pm8005-regulator.dtsi"
+#include "qcs605-lc-pmic-overlay.dtsi"
 
-/ {
-	cpus {
-		/delete-node/ cpu@200;
-		/delete-node/ cpu@300;
-		/delete-node/ cpu@400;
-		/delete-node/ cpu@500;
+&qupv3_se9_2uart {
+	status = "disabled";
+};
 
-		cpu-map {
-			cluster0 {
-				/delete-node/ core2;
-				/delete-node/ core3;
-				/delete-node/ core4;
-				/delete-node/ core5;
+&qupv3_se12_2uart {
+	status = "ok";
+};
+
+&qupv3_se8_spi {
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm660_l19>;
+	qcom,vdd-voltage-level = <2960000 2960000>;
+	qcom,vdd-current-level = <0 570000>;
+
+	vdd-io-supply = <&pm660_l8>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <0 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on  &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	status = "ok";
+};
+
+&tlmm {
+	sdc2_cd_on: cd_on {
+		mux {
+			pins = "gpio116";
+			function = "gpio";
+		};
+
+		config {
+			pins = "gpio116";
+			drive-strength = <2>;
+			bias-pull-up;
 			};
 		};
-	};
 
-
-};
-
-&soc {
-	/delete-node/ jtagmm@7240000;
-	/delete-node/ jtagmm@7340000;
-	/delete-node/ jtagmm@7440000;
-	/delete-node/ jtagmm@7540000;
-	/delete-node/ cti@7220000;
-	/delete-node/ cti@7320000;
-	/delete-node/ cti@7420000;
-	/delete-node/ cti@7520000;
-	/delete-node/ etm@7240000;
-	/delete-node/ etm@7340000;
-	/delete-node/ etm@7440000;
-	/delete-node/ etm@7540000;
-	cpuss_dump {
-		/delete-node/ qcom,l1_i_cache200;
-		/delete-node/ qcom,l1_i_cache300;
-		/delete-node/ qcom,l1_i_cache400;
-		/delete-node/ qcom,l1_i_cache500;
-		/delete-node/ qcom,l1_d_cache200;
-		/delete-node/ qcom,l1_d_cache300;
-		/delete-node/ qcom,l1_d_cache400;
-		/delete-node/ qcom,l1_d_cache500;
-		/delete-node/ qcom,l1_tlb_dump200;
-		/delete-node/ qcom,l1_tlb_dump300;
-		/delete-node/ qcom,l1_tlb_dump400;
-		/delete-node/ qcom,l1_tlb_dump500;
-	};
-
-	devfreq_memlat_0: qcom,cpu0-memlat-mon {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-
-	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-	devfreq_compute0: qcom,devfreq-compute0 {
-		qcom,cpulist = <&CPU0 &CPU1>;
-	};
-
-	funnel_apss: funnel@7800000 {
-		ports {
-			/delete-node/ port@3;
-			/delete-node/ port@4;
-			/delete-node/ port@5;
-			/delete-node/ port@6;
+	sdc2_cd_off: cd_off {
+		mux {
+			pins = "gpio116";
+			function = "gpio";
 		};
-	};
 
-	qcom,lpm-levels {
-		qcom,pm-cluster@0 {
-			qcom,pm-cpu@0 {
-				qcom,cpu = <&CPU0 &CPU1>;
+		config {
+			pins = "gpio116";
+			drive-strength = <2>;
+			bias-disable;
 			};
-		};
 	};
 };
 
-&pm660_temp_alarm {
-	cooling-maps {
-		/delete-node/ trip0_cpu2;
-		/delete-node/ trip0_cpu3;
-		/delete-node/ trip0_cpu4;
-		/delete-node/ trip0_cpu5;
-		/delete-node/ trip1_cpu2;
-		/delete-node/ trip1_cpu3;
-		/delete-node/ trip1_cpu4;
-		/delete-node/ trip1_cpu5;
-	};
-};
+&sdhc_2 {
+	/* VDD external regulator is enabled/disabled by pm660_l18 regulator */
+	vdd-io-supply = <&pm660_l18>;
+	qcom,vdd-io-voltage-level = <1800000 2960000>;
+	qcom,vdd-io-current-level = <0 22000>;
 
-&thermal_zones {
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
 
-	xo-therm-cpu-step {
-		cooling-maps {
-			/delete-node/ skin_cpu2;
-			/delete-node/ skin_cpu3;
-			/delete-node/ skin_cpu4;
-			/delete-node/ skin_cpu5;
-		};
-	};
-};
+	cd-gpios = <&tlmm 116 0x1>;
 
-&spmi_bus {
-	/delete-node/ qcom,pm660l@2;
-	/delete-node/ qcom,pm660l@3;
-};
-
-&thermal_zones {
-	pm660l_tz {
-		/delete-property/ thermal-sensors;
-	};
-};
-
-&soc {
-	qcom,turing@8300000 {
-		/delete-property/ vdd_cx-supply;
-	};
-
-	qcom,lpass@62400000 {
-		/delete-property/ vdd_cx-supply;
-	};
-};
-
-&clock_cpucc {
-	/delete-property/ vdd_l3_mx_ao-supply;
-	/delete-property/ vdd_pwrcl_mx_ao-supply;
-};
-
-&clock_gcc {
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_cx_ao-supply;
-};
-
-&clock_videocc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_camcc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_dispcc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_gpucc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&pil_modem {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_mss-supply;
-};
-
-&clock_gfx {
-	/delete-property/ vdd_gfx-supply;
-};
-
-&gpu_gx_gdsc {
-	/delete-property/ parent-supply;
-};
-
-&mdss_dsi_phy0 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&mdss_dsi_phy1 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&sde_dp {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&qusb_phy0 {
-	/delete-property/ vdd-supply;
-	/delete-property/ vdda33-supply;
-};
-
-&usb_qmp_dp_phy {
-	/delete-property/ vdd-supply;
-};
-
-&pm660_pdphy {
-	/delete-property/ vdd-pdphy-supply;
+	status = "ok";
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
new file mode 100644
index 0000000..2436687
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
@@ -0,0 +1,260 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&pm660_0 {
+	pm660_charger: qcom,qpnp-smb2 {
+		compatible = "qcom,qpnp-smb2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#cooling-cells = <2>;
+
+		qcom,pmic-revid = <&pm660_revid>;
+
+		io-channels = <&pm660_rradc 8>,
+			      <&pm660_rradc 10>,
+			      <&pm660_rradc 3>,
+			      <&pm660_rradc 4>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max",
+				   "usbin_i",
+				   "usbin_v";
+
+		qcom,wipower-max-uw = <5000000>;
+
+		dpdm-supply = <&qusb_phy0>;
+
+		qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+		qcom,auto-recharge-soc;
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =
+				<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "chg-error",
+					  "chg-state-change",
+					  "step-chg-state-change",
+					  "step-chg-soc-update-fail",
+					  "step-chg-soc-update-request";
+		};
+
+		qcom,otg@1100 {
+			reg = <0x1100 0x100>;
+			interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "otg-fail",
+					  "otg-overcurrent",
+					  "otg-oc-dis-sw-sts",
+					  "testmode-change-detect";
+		};
+
+		qcom,bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =
+				<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "bat-temp",
+					  "bat-ocp",
+					  "bat-ov",
+					  "bat-low",
+					  "bat-therm-or-id-missing",
+					  "bat-terminal-missing";
+		};
+
+		qcom,usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =
+				<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "usbin-collapse",
+					  "usbin-lt-3p6v",
+					  "usbin-uv",
+					  "usbin-ov",
+					  "usbin-plugin",
+					  "usbin-src-change",
+					  "usbin-icl-change",
+					  "type-c-change";
+		};
+
+		qcom,dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =
+				<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "dcin-collapse",
+					  "dcin-lt-3p6v",
+					  "dcin-uv",
+					  "dcin-ov",
+					  "dcin-plugin",
+					  "div2-en-dg",
+					  "dcin-icl-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts =
+				<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+				<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "wdog-snarl",
+					  "wdog-bark",
+					  "aicl-fail",
+					  "aicl-done",
+					  "high-duty-cycle",
+					  "input-current-limiting",
+					  "temperature-change",
+					  "switcher-power-ok";
+		};
+		smb2_vbus: qcom,smb2-vbus {
+			regulator-name = "smb2-vbus";
+		};
+
+		smb2_vconn: qcom,smb2-vconn {
+			regulator-name = "smb2-vconn";
+		};
+	};
+
+	pm660_rradc: rradc@4500 {
+		compatible = "qcom,rradc";
+		reg = <0x4500 0x100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#io-channel-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+	};
+
+	pm660_fg: qpnp,fg {
+		compatible = "qcom,fg-gen3";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+		io-channels = <&pm660_rradc 0>,
+			      <&pm660_rradc 7>;
+		io-channel-names = "rradc_batt_id",
+				   "rradc_die_temp";
+		qcom,rradc-base = <0x4500>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
+		qcom,fg-esr-timer-charging = <0 96>;
+		qcom,cycle-counter-en;
+		qcom,hold-soc-while-full;
+		qcom,fg-auto-recharge-soc;
+		qcom,fg-recharge-soc-thr = <98>;
+		status = "okay";
+
+		qcom,fg-batt-soc@4000 {
+			status = "okay";
+			reg = <0x4000 0x100>;
+			interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x2
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x3
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x5
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "soc-update",
+					  "soc-ready",
+					  "bsoc-delta",
+					  "msoc-delta",
+					  "msoc-low",
+					  "msoc-empty",
+					  "msoc-high",
+					  "msoc-full";
+		};
+
+		qcom,fg-batt-info@4100 {
+			status = "okay";
+			reg = <0x4100 0x100>;
+			interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "vbatt-pred-delta",
+					  "vbatt-low",
+					  "esr-delta",
+					  "batt-missing",
+					  "batt-temp-delta";
+		};
+
+		qcom,fg-memif@4400 {
+			status = "okay";
+			reg = <0x4400 0x100>;
+			interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "ima-rdy",
+					  "mem-xcp",
+					  "dma-grant";
+		};
+	};
+};
+
+&pm660_1 {
+	pm660_haptics: qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pm660_revid>;
+		qcom,pmic-misc = <&pm660_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <0>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,lra-high-z = "opt0";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dts b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
new file mode 100644
index 0000000..88d838e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "qcs605-lc.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QCS605 LC SoC";
+	compatible = "qcom,qcs605";
+	qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
new file mode 100644
index 0000000..8a187fb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "qcs605.dtsi"
+#include "pm8005.dtsi"
+#include "qcs605-pm660-pm8005-regulator.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QCS605 SoC";
+	compatible = "qcom,qcs605";
+
+	cpus {
+		/delete-node/ cpu@200;
+		/delete-node/ cpu@300;
+		/delete-node/ cpu@400;
+		/delete-node/ cpu@500;
+
+		cpu-map {
+			cluster0 {
+				/delete-node/ core2;
+				/delete-node/ core3;
+				/delete-node/ core4;
+				/delete-node/ core5;
+			};
+		};
+	};
+};
+
+&soc {
+	/delete-node/ jtagmm@7240000;
+	/delete-node/ jtagmm@7340000;
+	/delete-node/ jtagmm@7440000;
+	/delete-node/ jtagmm@7540000;
+	/delete-node/ cti@7220000;
+	/delete-node/ cti@7320000;
+	/delete-node/ cti@7420000;
+	/delete-node/ cti@7520000;
+	/delete-node/ etm@7240000;
+	/delete-node/ etm@7340000;
+	/delete-node/ etm@7440000;
+	/delete-node/ etm@7540000;
+	cpuss_dump {
+		/delete-node/ qcom,l1_i_cache200;
+		/delete-node/ qcom,l1_i_cache300;
+		/delete-node/ qcom,l1_i_cache400;
+		/delete-node/ qcom,l1_i_cache500;
+		/delete-node/ qcom,l1_d_cache200;
+		/delete-node/ qcom,l1_d_cache300;
+		/delete-node/ qcom,l1_d_cache400;
+		/delete-node/ qcom,l1_d_cache500;
+		/delete-node/ qcom,l1_tlb_dump200;
+		/delete-node/ qcom,l1_tlb_dump300;
+		/delete-node/ qcom,l1_tlb_dump400;
+		/delete-node/ qcom,l1_tlb_dump500;
+	};
+
+	devfreq_memlat_0: qcom,cpu0-memlat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+	devfreq_compute0: qcom,devfreq-compute0 {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	funnel_apss: funnel@7800000 {
+		ports {
+			/delete-node/ port@3;
+			/delete-node/ port@4;
+			/delete-node/ port@5;
+			/delete-node/ port@6;
+		};
+	};
+
+	qcom,lpm-levels {
+		qcom,pm-cluster@0 {
+			qcom,pm-cpu@0 {
+				qcom,cpu = <&CPU0 &CPU1>;
+			};
+		};
+	};
+
+	qcom,chd_silver {
+		compatible = "qcom,core-hang-detect";
+		label = "silver";
+		qcom,threshold-arr = <0x17e00058 0x17e10058>;
+		qcom,config-arr = <0x17e00060 0x17e10060>;
+	};
+};
+
+&pm660_temp_alarm {
+	cooling-maps {
+		/delete-node/ trip0_cpu2;
+		/delete-node/ trip0_cpu3;
+		/delete-node/ trip0_cpu4;
+		/delete-node/ trip0_cpu5;
+		/delete-node/ trip1_cpu2;
+		/delete-node/ trip1_cpu3;
+		/delete-node/ trip1_cpu4;
+		/delete-node/ trip1_cpu5;
+	};
+};
+
+&thermal_zones {
+
+	xo-therm-step {
+		cooling-maps {
+			/delete-node/ skin_cpu2;
+			/delete-node/ skin_cpu3;
+			/delete-node/ skin_cpu4;
+			/delete-node/ skin_cpu5;
+		};
+	};
+};
+
+&spmi_bus {
+	/delete-node/ qcom,pm660l@2;
+	/delete-node/ qcom,pm660l@3;
+};
+
+&thermal_zones {
+	pm660l_tz {
+		/delete-property/ thermal-sensors;
+	};
+};
+
+&soc {
+	qcom,turing@8300000 {
+		/delete-property/ vdd_cx-supply;
+		vdd_cx-supply = <&pm8005_s1_level>;
+	};
+
+	qcom,lpass@62400000 {
+		/delete-property/ vdd_cx-supply;
+		vdd_cx-supply = <&pm8005_s1_level>;
+	};
+};
+
+&clock_cpucc {
+	/delete-property/ vdd_l3_mx_ao-supply;
+	/delete-property/ vdd_pwrcl_mx_ao-supply;
+	vdd_l3_mx_ao-supply = <&pm660_s2_level_ao>;
+	vdd_pwrcl_mx_ao-supply = <&pm660_s2_level_ao>;
+};
+
+&clock_gcc {
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_cx_ao-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+	vdd_cx_ao-supply = <&pm8005_s1_level_ao>;
+};
+
+&clock_videocc {
+	/delete-property/ vdd_cx-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+};
+
+&clock_camcc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+	vdd_mx-supply = <&pm660_s2_level>;
+};
+
+&clock_dispcc {
+	/delete-property/ vdd_cx-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+};
+
+&clock_gpucc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+	vdd_mx-supply = <&pm660_s2_level>;
+};
+
+&pil_modem {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_mss-supply;
+	vdd_cx-supply = <&pm8005_s1_level>;
+	vdd_mx-supply = <&pm660_s2_level>;
+	vdd_mss-supply = <&pm8005_s1_level>;
+};
+
+&clock_gfx {
+	/delete-property/ vdd_gfx-supply;
+	vdd_gfx-supply = <&pm8005_s2>;
+};
+
+&gpu_gx_gdsc {
+	/delete-property/ parent-supply;
+	parent-supply = <&pm8005_s2>;
+};
+
+&mdss_dsi_phy0 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&mdss_dsi_phy1 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&sde_dp {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&qusb_phy0 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+	/delete-property/ vdd-supply;
+};
+
+&pm660_pdphy {
+	/delete-property/ vdd-pdphy-supply;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index 6cf9a82..5adbbb8 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,42 @@
 	qcom,msm-id = <347 0x0>;
 };
 
+&pil_modem_mem {
+	reg = <0 0x8b000000 0 0x3e00000>;
+};
+
+&pil_video_mem {
+	reg = <0 0x8ee00000 0 0x500000>;
+};
+
+&wlan_msa_mem {
+	reg = <0 0x8f300000 0 0x100000>;
+};
+
+&pil_cdsp_mem {
+	reg = <0 0x8f400000 0 0x800000>;
+};
+
+&pil_mba_mem {
+	reg = <0 0x8fc00000 0 0x200000>;
+};
+
+&pil_adsp_mem {
+	reg = <0 0x8fe00000 0 0x1e00000>;
+};
+
+&pil_ipa_fw_mem {
+	reg = <0 0x91c00000 0 0x10000>;
+};
+
+&pil_ipa_gsi_mem {
+	reg = <0 0x91c10000 0 0x5000>;
+};
+
+&pil_gpu_mem {
+	reg = <0 0x91c15000 0 0x2000>;
+};
+
 &soc {
 	qcom,rmnet-ipa {
 		status = "disabled";
@@ -47,3 +83,7 @@
 		};
 	};
 };
+
+&msm_gpu {
+	/delete-node/qcom,gpu-mempools;
+};
diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi
new file mode 100644
index 0000000..4d35628
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi
@@ -0,0 +1,1024 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,ascent_3450mah {
+	/* Ascent_wConn_3450mAh_Fresh_averaged_MasterSlave_Feb7th2018 */
+	qcom,max-voltage-uv = <4350000>;
+	qcom,fg-cc-cv-threshold-mv = <4340>;
+	qcom,fastchg-current-ma = <3450>;
+	qcom,batt-id-kohm = <60>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-therm-kohm = <68>;
+	qcom,battery-type =
+		"Ascent_wConn_3450mAh_Fresh_averaged_MasterSlave_Feb7th2018";
+	qcom,qg-batt-profile-ver = <100>;
+
+	qcom,jeita-fcc-ranges = <0   100  1725000
+				101  400  3450000
+				401  450  2760000>;
+	qcom,jeita-fv-ranges = <0   100  4250000
+				101 400  4350000
+				401 450  4250000>;
+	qcom,step-chg-ranges = <3600000  4200000  3450000
+				4201000  4300000  2760000
+				4301000  4350000  2070000>;
+
+	qcom,fcc1-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <3377 3428 3481 3496 3500>;
+	};
+
+	qcom,fcc2-temp-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-data = <3474 3480 3482 3476 3492 3478 3466>;
+	};
+
+	qcom,pc-temp-v1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43212 43315 43370 43380 43383>,
+			<42963 43071 43141 43149 43152>,
+			<42723 42832 42902 42916 42922>,
+			<42488 42597 42662 42683 42693>,
+			<42262 42367 42430 42454 42465>,
+			<42043 42143 42202 42225 42238>,
+			<41832 41924 41976 41999 42013>,
+			<41624 41709 41754 41775 41791>,
+			<41419 41497 41536 41556 41571>,
+			<41220 41288 41322 41341 41355>,
+			<41039 41091 41113 41132 41143>,
+			<40866 40911 40916 40928 40936>,
+			<40676 40732 40729 40729 40734>,
+			<40449 40526 40541 40538 40541>,
+			<40230 40302 40340 40351 40355>,
+			<40061 40115 40146 40170 40176>,
+			<39918 39974 39984 40002 40007>,
+			<39787 39846 39843 39845 39846>,
+			<39672 39712 39697 39690 39689>,
+			<39560 39579 39548 39536 39538>,
+			<39426 39419 39388 39376 39384>,
+			<39271 39170 39192 39187 39198>,
+			<39112 38928 38961 38960 38967>,
+			<38934 38809 38788 38776 38775>,
+			<38764 38736 38674 38650 38646>,
+			<38660 38665 38581 38546 38539>,
+			<38589 38587 38491 38448 38439>,
+			<38533 38513 38408 38359 38347>,
+			<38487 38444 38334 38278 38263>,
+			<38448 38381 38265 38204 38187>,
+			<38407 38323 38204 38138 38118>,
+			<38364 38269 38149 38078 38055>,
+			<38322 38219 38099 38026 37999>,
+			<38284 38175 38053 37975 37942>,
+			<38249 38137 38014 37930 37889>,
+			<38211 38098 37974 37884 37834>,
+			<38174 38061 37930 37831 37767>,
+			<38129 38020 37882 37771 37691>,
+			<38055 37954 37816 37698 37610>,
+			<37946 37848 37718 37605 37524>,
+			<37825 37726 37602 37497 37426>,
+			<37689 37595 37474 37372 37301>,
+			<37541 37451 37332 37231 37156>,
+			<37372 37290 37178 37080 36999>,
+			<37271 37162 37061 36964 36886>,
+			<37191 37093 36992 36897 36819>,
+			<37157 37064 36970 36870 36798>,
+			<37128 37039 36949 36844 36770>,
+			<37084 37007 36903 36788 36714>,
+			<36927 36851 36683 36562 36488>,
+			<36555 36481 36290 36180 36108>,
+			<36071 35999 35771 35687 35620>,
+			<35450 35376 35098 35050 34994>,
+			<34604 34523 34174 34184 34150>,
+			<33275 33138 32725 32851 32862>,
+			<30000 30000 30000 30000 30000>;
+	};
+
+	qcom,pc-temp-v2-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <43435 43425 43415 43385 43360 43315 43295>,
+			<43032 43070 43109 43097 43094 43052 43033>,
+			<42666 42748 42821 42826 42838 42799 42781>,
+			<42342 42462 42555 42571 42594 42557 42541>,
+			<42053 42208 42308 42333 42361 42326 42312>,
+			<41788 41968 42072 42101 42133 42099 42086>,
+			<41531 41736 41844 41872 41904 41872 41860>,
+			<41298 41516 41625 41649 41680 41649 41637>,
+			<41128 41303 41405 41431 41460 41430 41419>,
+			<41009 41100 41186 41217 41243 41215 41204>,
+			<40843 40896 40979 41012 41034 41005 40994>,
+			<40462 40694 40796 40826 40840 40802 40789>,
+			<40004 40482 40616 40642 40648 40604 40590>,
+			<39736 40220 40407 40432 40445 40411 40399>,
+			<39556 39903 40175 40199 40233 40222 40214>,
+			<39382 39636 39954 39996 40043 40042 40036>,
+			<39187 39443 39759 39844 39886 39877 39868>,
+			<39001 39272 39570 39700 39736 39717 39706>,
+			<38839 39091 39370 39511 39573 39556 39547>,
+			<38695 38908 39162 39283 39399 39396 39391>,
+			<38574 38742 38973 39072 39208 39217 39217>,
+			<38477 38591 38806 38886 38975 38988 38994>,
+			<38393 38460 38655 38721 38760 38766 38771>,
+			<38314 38358 38519 38585 38613 38613 38614>,
+			<38242 38274 38396 38468 38496 38494 38494>,
+			<38176 38201 38287 38362 38390 38388 38387>,
+			<38117 38138 38189 38265 38294 38291 38288>,
+			<38062 38080 38106 38177 38206 38202 38198>,
+			<38006 38027 38039 38096 38126 38120 38114>,
+			<37953 37980 37983 38021 38051 38044 38037>,
+			<37900 37934 37935 37954 37984 37976 37967>,
+			<37847 37889 37895 37891 37921 37915 37905>,
+			<37795 37843 37856 37838 37862 37856 37846>,
+			<37742 37795 37815 37799 37803 37790 37781>,
+			<37690 37746 37774 37768 37746 37720 37707>,
+			<37635 37692 37727 37728 37685 37643 37621>,
+			<37574 37633 37677 37677 37620 37554 37517>,
+			<37509 37568 37618 37617 37550 37465 37411>,
+			<37441 37491 37546 37548 37475 37387 37327>,
+			<37368 37404 37459 37466 37395 37313 37256>,
+			<37292 37310 37360 37369 37301 37226 37174>,
+			<37209 37206 37243 37246 37187 37117 37069>,
+			<37119 37103 37111 37106 37050 36988 36945>,
+			<37020 37005 36964 36946 36900 36839 36796>,
+			<36901 36909 36860 36837 36818 36761 36712>,
+			<36762 36808 36782 36769 36775 36718 36673>,
+			<36671 36746 36740 36732 36741 36690 36651>,
+			<36552 36670 36688 36684 36692 36649 36612>,
+			<36386 36553 36594 36591 36575 36542 36528>,
+			<36157 36329 36380 36368 36272 36271 36278>,
+			<35824 35961 35991 35957 35796 35833 35867>,
+			<35340 35436 35452 35401 35193 35271 35340>,
+			<34648 34709 34745 34680 34409 34550 34676>,
+			<33623 33672 33759 33677 33330 33585 33791>,
+			<31758 31857 32191 32244 31867 32001 32517>,
+			<27623 28160 28896 29014 27510 28586 29617>;
+	};
+
+	qcom,pc-temp-z1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <13703 12983 12375 12138 12079>,
+			<13647 12967 12370 12145 12092>,
+			<13621 12953 12363 12143 12093>,
+			<13606 12942 12357 12142 12093>,
+			<13594 12927 12349 12140 12093>,
+			<13585 12916 12342 12137 12093>,
+			<13577 12905 12339 12136 12092>,
+			<13569 12898 12337 12135 12092>,
+			<13560 12896 12337 12135 12091>,
+			<13551 12895 12339 12135 12091>,
+			<13540 12896 12342 12136 12091>,
+			<13527 12899 12342 12136 12091>,
+			<13512 12901 12342 12137 12093>,
+			<13488 12896 12342 12139 12095>,
+			<13469 12887 12343 12141 12097>,
+			<13469 12883 12347 12144 12098>,
+			<13473 12891 12352 12147 12101>,
+			<13478 12904 12360 12151 12103>,
+			<13489 12912 12369 12155 12106>,
+			<13502 12919 12378 12160 12109>,
+			<13514 12927 12387 12165 12113>,
+			<13525 12937 12396 12171 12117>,
+			<13538 12948 12404 12177 12122>,
+			<13555 12957 12412 12184 12127>,
+			<13572 12965 12422 12189 12131>,
+			<13578 12971 12431 12195 12135>,
+			<13580 12978 12440 12200 12139>,
+			<13582 12985 12448 12206 12143>,
+			<13594 12992 12456 12212 12147>,
+			<13613 13004 12464 12218 12151>,
+			<13625 13010 12472 12224 12156>,
+			<13631 13010 12479 12230 12160>,
+			<13632 13010 12486 12237 12165>,
+			<13627 13015 12494 12244 12171>,
+			<13618 13033 12505 12253 12177>,
+			<13619 13047 12517 12262 12183>,
+			<13629 13056 12529 12271 12190>,
+			<13640 13065 12541 12280 12196>,
+			<13647 13068 12553 12290 12203>,
+			<13654 13070 12565 12301 12210>,
+			<13663 13071 12577 12311 12217>,
+			<13678 13085 12588 12322 12224>,
+			<13694 13098 12598 12332 12232>,
+			<13718 13107 12607 12344 12239>,
+			<13717 13110 12621 12356 12248>,
+			<13717 13111 12638 12367 12256>,
+			<13693 13110 12640 12374 12262>,
+			<13712 13131 12642 12382 12269>,
+			<13714 13118 12659 12395 12280>,
+			<13717 13140 12677 12408 12291>,
+			<13717 13160 12678 12422 12303>,
+			<13740 13166 12691 12436 12316>,
+			<13739 13183 12711 12456 12332>,
+			<13754 13201 12735 12479 12355>,
+			<13754 13201 12735 12479 12355>,
+			<13754 13201 12735 12479 12355>;
+	};
+
+	qcom,pc-temp-z2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9983 10351 10639 10481 10418>,
+			<10020 10341 10669 10329 10279>,
+			<10051 10333 10528 10319 10282>,
+			<10083 10331 10397 10312 10281>,
+			<10100 10329 10358 10299 10263>,
+			<10094 10325 10328 10285 10234>,
+			<10081 10303 10324 10279 10227>,
+			<10069 10281 10328 10277 10237>,
+			<10058 10278 10330 10276 10251>,
+			<10050 10280 10326 10276 10266>,
+			<10044 10285 10321 10281 10280>,
+			<10039 10298 10323 10288 10285>,
+			<10038 10310 10324 10308 10284>,
+			<10045 10309 10318 10321 10285>,
+			<10054 10304 10304 10319 10295>,
+			<10056 10302 10291 10314 10309>,
+			<10056 10312 10297 10316 10321>,
+			<10058 10329 10320 10326 10335>,
+			<10070 10353 10339 10334 10341>,
+			<10090 10386 10349 10339 10346>,
+			<10111 10400 10358 10343 10354>,
+			<10138 10396 10373 10334 10340>,
+			<10157 10388 10395 10289 10270>,
+			<10169 10381 10400 10243 10212>,
+			<10178 10372 10354 10197 10174>,
+			<10183 10364 10306 10161 10144>,
+			<10190 10352 10304 10160 10141>,
+			<10194 10341 10307 10170 10149>,
+			<10185 10335 10310 10181 10158>,
+			<10169 10332 10311 10196 10169>,
+			<10165 10332 10314 10216 10183>,
+			<10168 10343 10327 10238 10202>,
+			<10171 10357 10356 10267 10226>,
+			<10175 10368 10381 10298 10253>,
+			<10180 10376 10405 10333 10288>,
+			<10183 10384 10422 10367 10326>,
+			<10186 10393 10431 10393 10358>,
+			<10189 10403 10438 10416 10387>,
+			<10187 10410 10442 10437 10405>,
+			<10181 10419 10455 10461 10418>,
+			<10175 10423 10465 10476 10426>,
+			<10164 10407 10466 10476 10430>,
+			<10152 10385 10468 10474 10428>,
+			<10142 10373 10453 10473 10402>,
+			<10064 10371 10455 10479 10389>,
+			<10173 10285 10486 10517 10402>,
+			<10003 10290 10490 10530 10416>,
+			<10151 10295 10531 10566 10477>,
+			<10255 10515 10588 10612 10540>,
+			<10077 10376 10556 10524 10421>,
+			<9948 10240 10480 10454 10314>,
+			<9854 10122 10384 10398 10256>,
+			<9640 9998 10319 10342 10182>,
+			<9440 9830 10255 10261 10065>,
+			<9440 9830 10255 10261 10065>,
+			<9440 9830 10255 10261 10065>;
+	};
+
+	qcom,pc-temp-z3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <19441 19367 19362 19326 19316>,
+			<19560 19428 19358 19334 19329>,
+			<19615 19467 19373 19341 19335>,
+			<19645 19480 19383 19346 19340>,
+			<19658 19487 19385 19351 19344>,
+			<19657 19488 19387 19354 19347>,
+			<19657 19486 19386 19355 19348>,
+			<19655 19483 19384 19354 19347>,
+			<19651 19481 19382 19352 19346>,
+			<19647 19479 19380 19350 19345>,
+			<19645 19477 19378 19347 19344>,
+			<19642 19470 19377 19345 19342>,
+			<19642 19464 19374 19345 19342>,
+			<19642 19464 19372 19344 19341>,
+			<19643 19467 19372 19343 19338>,
+			<19639 19467 19372 19342 19336>,
+			<19626 19460 19371 19340 19334>,
+			<19615 19450 19369 19338 19332>,
+			<19604 19448 19368 19337 19330>,
+			<19596 19446 19368 19337 19328>,
+			<19597 19447 19369 19337 19326>,
+			<19605 19452 19372 19340 19328>,
+			<19612 19460 19378 19350 19341>,
+			<19619 19462 19386 19357 19350>,
+			<19626 19464 19394 19361 19353>,
+			<19627 19466 19401 19364 19355>,
+			<19626 19472 19400 19364 19355>,
+			<19624 19480 19398 19362 19352>,
+			<19620 19480 19395 19359 19349>,
+			<19615 19476 19391 19356 19346>,
+			<19611 19473 19388 19353 19343>,
+			<19609 19469 19384 19350 19340>,
+			<19606 19466 19381 19347 19336>,
+			<19604 19463 19379 19343 19332>,
+			<19601 19461 19377 19338 19327>,
+			<19597 19458 19375 19335 19324>,
+			<19592 19454 19373 19334 19325>,
+			<19587 19451 19370 19334 19329>,
+			<19584 19448 19368 19334 19330>,
+			<19582 19446 19366 19334 19328>,
+			<19579 19443 19364 19334 19326>,
+			<19575 19441 19362 19334 19326>,
+			<19571 19438 19360 19334 19327>,
+			<19565 19434 19359 19336 19329>,
+			<19361 19423 19353 19335 19328>,
+			<19262 19382 19344 19323 19324>,
+			<19263 19371 19336 19321 19317>,
+			<19261 19361 19332 19317 19313>,
+			<19261 19273 19326 19317 19309>,
+			<19262 19274 19335 19327 19319>,
+			<19263 19303 19337 19330 19324>,
+			<19263 19274 19357 19333 19327>,
+			<19266 19275 19361 19337 19335>,
+			<19272 19280 19368 19349 19345>,
+			<19272 19280 19368 19349 19345>,
+			<19272 19280 19368 19349 19345>;
+	};
+
+	qcom,pc-temp-z4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <15627 15107 14765 14761 14758>,
+			<15711 15099 14864 14812 14796>,
+			<15693 15080 14843 14798 14788>,
+			<15530 15036 14821 14778 14775>,
+			<15355 14952 14794 14760 14761>,
+			<15246 14887 14764 14740 14745>,
+			<15155 14845 14741 14726 14731>,
+			<15085 14812 14721 14713 14719>,
+			<15031 14784 14710 14705 14711>,
+			<14985 14760 14705 14700 14707>,
+			<14938 14745 14702 14697 14705>,
+			<14895 14735 14696 14693 14702>,
+			<14876 14729 14689 14688 14699>,
+			<14872 14730 14686 14684 14697>,
+			<14869 14735 14686 14681 14694>,
+			<14856 14737 14686 14680 14692>,
+			<14830 14720 14682 14677 14689>,
+			<14808 14702 14673 14672 14684>,
+			<14790 14701 14669 14669 14681>,
+			<14778 14706 14676 14670 14679>,
+			<14782 14717 14687 14675 14677>,
+			<14805 14815 14716 14690 14685>,
+			<14835 14927 14778 14733 14726>,
+			<14898 14927 14803 14755 14750>,
+			<14965 14883 14774 14738 14735>,
+			<14974 14842 14741 14715 14712>,
+			<14963 14813 14728 14705 14703>,
+			<14950 14789 14721 14700 14699>,
+			<14932 14778 14717 14696 14696>,
+			<14910 14771 14715 14693 14692>,
+			<14892 14767 14713 14691 14688>,
+			<14878 14766 14712 14688 14683>,
+			<14867 14765 14712 14684 14677>,
+			<14856 14764 14710 14681 14673>,
+			<14847 14763 14709 14676 14668>,
+			<14838 14761 14706 14673 14666>,
+			<14826 14756 14703 14673 14669>,
+			<14816 14748 14700 14674 14680>,
+			<14809 14744 14697 14674 14683>,
+			<14804 14742 14695 14673 14677>,
+			<14797 14739 14693 14671 14673>,
+			<14787 14730 14687 14667 14673>,
+			<14774 14718 14678 14663 14675>,
+			<14753 14708 14673 14662 14682>,
+			<14897 14683 14660 14653 14674>,
+			<14965 14689 14638 14630 14635>,
+			<14964 14694 14635 14621 14624>,
+			<14958 14699 14630 14614 14617>,
+			<14951 14794 14633 14616 14620>,
+			<14945 14795 14637 14644 14655>,
+			<14957 14769 14642 14654 14664>,
+			<14968 14805 14636 14660 14668>,
+			<14977 14809 14655 14668 14668>,
+			<14993 14817 14684 14674 14665>,
+			<14993 14817 14684 14674 14665>,
+			<14993 14817 14684 14674 14665>;
+	};
+
+	qcom,pc-temp-z5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <11983 12740 15393 15537 15330>,
+			<13357 14824 16249 17310 17529>,
+			<14286 16482 17811 18377 18523>,
+			<14945 17642 19175 19223 19510>,
+			<15486 18555 20024 20275 20513>,
+			<15957 19327 20723 21346 21540>,
+			<16368 19918 21568 22345 22519>,
+			<16781 20541 22514 23454 23469>,
+			<17187 21683 23120 24074 24236>,
+			<17674 23224 23449 23971 24698>,
+			<18442 24060 23713 23757 25052>,
+			<19483 24549 23914 23816 25554>,
+			<20437 24925 24207 24637 26312>,
+			<21361 25257 24451 25542 26851>,
+			<22105 25909 24697 26092 27021>,
+			<22478 26475 25087 26614 27131>,
+			<22735 27141 26348 27394 27470>,
+			<23076 28081 28954 28566 28331>,
+			<23809 29715 30229 29356 28825>,
+			<24938 32251 30431 29724 28646>,
+			<27176 33544 30446 29885 28135>,
+			<31932 33025 28578 28445 26783>,
+			<35226 31860 23567 23249 22747>,
+			<36819 29994 21621 20580 20432>,
+			<37874 26035 23092 21806 21763>,
+			<37147 24128 25214 23841 23948>,
+			<34993 26078 27156 25488 25430>,
+			<32825 29127 29386 27105 26647>,
+			<30980 31187 31134 28441 27481>,
+			<29376 32887 32400 29515 28206>,
+			<28873 34208 33430 30375 28775>,
+			<28786 35400 34311 31101 29161>,
+			<28801 36250 35051 31824 29873>,
+			<28836 36325 35497 32045 30283>,
+			<28862 36122 35938 31861 30590>,
+			<28907 35854 36221 31646 31106>,
+			<28980 35186 35497 31570 32686>,
+			<29132 34291 33694 31549 35494>,
+			<29670 33796 32315 31543 36261>,
+			<30652 33516 31332 31469 34185>,
+			<30992 33114 30388 31412 32325>,
+			<29938 32130 29262 32046 32870>,
+			<29033 30867 28327 33225 34089>,
+			<28928 29512 27958 34867 35083>,
+			<16971 28826 27177 35407 35456>,
+			<11113 18542 25875 28236 38118>,
+			<11084 16735 22486 31621 32274>,
+			<11037 15601 21798 36765 39261>,
+			<11035 11499 20071 40032 37713>,
+			<11055 11574 22201 35765 26327>,
+			<11017 12415 21829 29484 22484>,
+			<10951 11419 39496 26044 20817>,
+			<10890 11348 40899 24307 20580>,
+			<10822 11392 37952 25288 21070>,
+			<10822 11392 37952 25288 21070>,
+			<10822 11392 37952 25288 21070>;
+	};
+
+	qcom,pc-temp-z6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <15711 15103 14773 14710 14694>,
+			<15778 15117 14813 14736 14718>,
+			<15776 15120 14809 14733 14717>,
+			<15702 15106 14804 14728 14716>,
+			<15620 15065 14793 14722 14713>,
+			<15561 15031 14779 14715 14707>,
+			<15508 15007 14768 14709 14701>,
+			<15467 14987 14758 14703 14696>,
+			<15435 14971 14751 14698 14692>,
+			<15407 14959 14748 14695 14689>,
+			<15379 14949 14746 14692 14687>,
+			<15353 14940 14743 14689 14685>,
+			<15339 14935 14739 14687 14684>,
+			<15332 14935 14736 14685 14682>,
+			<15326 14938 14737 14684 14680>,
+			<15316 14939 14738 14683 14678>,
+			<15302 14930 14736 14681 14676>,
+			<15293 14921 14733 14679 14673>,
+			<15289 14921 14732 14677 14671>,
+			<15286 14926 14736 14678 14670>,
+			<15291 14936 14744 14682 14669>,
+			<15312 14986 14761 14691 14674>,
+			<15338 15040 14795 14718 14702>,
+			<15373 15042 14808 14732 14717>,
+			<15408 15027 14802 14727 14713>,
+			<15415 15016 14795 14720 14706>,
+			<15414 15011 14791 14717 14702>,
+			<15412 15007 14788 14714 14699>,
+			<15408 15006 14786 14712 14697>,
+			<15402 15004 14785 14710 14694>,
+			<15399 15004 14784 14708 14691>,
+			<15398 15005 14784 14706 14688>,
+			<15397 15006 14784 14704 14684>,
+			<15397 15009 14784 14701 14680>,
+			<15398 15012 14784 14699 14677>,
+			<15400 15015 14785 14696 14674>,
+			<15402 15016 14785 14697 14677>,
+			<15405 15017 14786 14699 14684>,
+			<15410 15020 14787 14700 14687>,
+			<15416 15026 14789 14702 14685>,
+			<15423 15031 14791 14703 14683>,
+			<15430 15034 14791 14703 14684>,
+			<15437 15037 14791 14704 14687>,
+			<15444 15040 14792 14706 14693>,
+			<15425 15039 14789 14704 14690>,
+			<15419 15030 14781 14691 14673>,
+			<15424 15030 14778 14688 14665>,
+			<15425 15032 14777 14685 14661>,
+			<15431 15036 14780 14688 14662>,
+			<15438 15047 14792 14708 14685>,
+			<15458 15060 14801 14718 14695>,
+			<15477 15072 14815 14726 14702>,
+			<15501 15088 14835 14737 14710>,
+			<15534 15114 14862 14753 14720>,
+			<15534 15114 14862 14753 14720>,
+			<15534 15114 14862 14753 14720>;
+	};
+
+	qcom,pc-temp-y1-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <7619 6963 6363 6007 5630 5512 5470>,
+			<7591 6945 6361 6003 5629 5510 5471>,
+			<7573 6934 6357 5999 5628 5508 5471>,
+			<7563 6929 6354 5995 5627 5506 5471>,
+			<7558 6928 6353 5992 5626 5505 5470>,
+			<7556 6928 6357 5988 5625 5503 5470>,
+			<7563 6934 6366 5985 5624 5502 5469>,
+			<7573 6942 6374 5981 5624 5501 5467>,
+			<7583 6939 6374 5982 5623 5500 5467>,
+			<7616 6920 6366 5984 5624 5499 5467>,
+			<7634 6910 6360 5985 5624 5498 5466>,
+			<7600 6919 6357 5980 5623 5498 5466>,
+			<7557 6931 6356 5973 5622 5498 5465>,
+			<7560 6935 6362 5973 5622 5499 5465>,
+			<7590 6938 6380 5978 5625 5500 5466>,
+			<7605 6939 6390 5981 5628 5501 5467>,
+			<7608 6942 6389 5985 5631 5501 5468>,
+			<7612 6946 6387 5990 5634 5502 5469>,
+			<7604 6943 6388 5989 5637 5503 5470>,
+			<7584 6932 6391 5988 5639 5506 5471>,
+			<7570 6929 6394 5987 5643 5508 5472>,
+			<7557 6957 6397 5989 5647 5510 5473>,
+			<7546 6985 6400 5994 5653 5513 5475>,
+			<7543 6976 6405 6001 5658 5515 5478>,
+			<7542 6942 6414 6012 5663 5518 5480>,
+			<7542 6928 6418 6018 5668 5522 5483>,
+			<7552 6934 6419 6019 5674 5525 5486>,
+			<7565 6942 6418 6020 5681 5529 5488>,
+			<7569 6951 6418 6021 5687 5533 5491>,
+			<7568 6972 6418 6023 5692 5537 5493>,
+			<7564 6978 6418 6025 5698 5541 5497>,
+			<7549 6971 6422 6028 5705 5545 5500>,
+			<7534 6961 6425 6032 5712 5550 5504>,
+			<7531 6947 6422 6038 5720 5554 5507>,
+			<7529 6929 6416 6048 5727 5559 5509>,
+			<7527 6925 6416 6055 5734 5563 5512>,
+			<7537 6932 6428 6059 5741 5569 5516>,
+			<7548 6939 6438 6062 5748 5575 5522>,
+			<7546 6939 6433 6063 5757 5580 5526>,
+			<7534 6942 6422 6064 5767 5585 5529>,
+			<7527 6944 6417 6067 5775 5591 5533>,
+			<7526 6946 6416 6077 5783 5596 5537>,
+			<7530 6941 6418 6083 5787 5603 5541>,
+			<7568 6923 6429 6090 5790 5610 5546>,
+			<7559 6953 6428 6086 5808 5622 5555>,
+			<7568 6932 6433 6091 5813 5631 5561>,
+			<7570 6928 6433 6099 5818 5635 5565>,
+			<7608 6933 6442 6113 5834 5640 5567>,
+			<7652 6932 6430 6105 5835 5645 5571>,
+			<7693 6936 6436 6106 5848 5654 5578>,
+			<7737 6965 6440 6099 5858 5666 5585>,
+			<7770 6990 6464 6110 5873 5684 5600>,
+			<7830 7027 6445 6123 5887 5704 5613>,
+			<7848 7064 6471 6136 5914 5726 5633>,
+			<7848 7064 6471 6136 5914 5726 5633>,
+			<7848 7064 6471 6136 5914 5726 5633>;
+	};
+
+	qcom,pc-temp-y2-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <9652 9643 10780 11037 11216 11097 11009>,
+			<9653 9653 10747 10993 11177 11076 11016>,
+			<9654 9867 10710 10945 11129 11053 11018>,
+			<9655 10082 10673 10898 11080 11031 11018>,
+			<9655 10246 10642 10860 11037 11010 11015>,
+			<9655 10308 10624 10837 11007 10992 11010>,
+			<9655 10281 10616 10826 10987 10977 10981>,
+			<9655 10241 10610 10820 10968 10962 10937>,
+			<9655 10275 10600 10816 10953 10942 10920>,
+			<9655 10440 10586 10802 10939 10913 10908>,
+			<9655 10531 10580 10792 10927 10894 10901>,
+			<9654 10522 10610 10786 10915 10881 10897>,
+			<9654 10502 10665 10780 10900 10869 10890>,
+			<9653 10430 10721 10797 10878 10869 10877>,
+			<9653 10226 10789 10873 10846 10876 10849>,
+			<9653 10115 10817 10940 10834 10878 10831>,
+			<9653 9949 10805 10988 10876 10871 10840>,
+			<9653 9749 10791 11021 10939 10863 10860>,
+			<9653 9704 10791 11014 10991 10869 10866>,
+			<9653 9683 10795 10979 11041 10898 10870>,
+			<9653 9677 10801 10965 11063 10936 10877>,
+			<9653 9676 10808 10997 11078 11004 10940>,
+			<9653 9676 10820 11042 11093 11066 11026>,
+			<9652 9674 10836 11062 11099 11074 11055>,
+			<9652 9670 10861 11077 11105 11063 11066>,
+			<9652 9667 10915 11082 11111 11064 11068>,
+			<9652 9665 11341 11085 11126 11092 11072>,
+			<9652 9663 11748 11091 11149 11125 11083>,
+			<9652 9661 11516 11099 11179 11148 11096>,
+			<9652 9659 10816 11110 11217 11174 11118>,
+			<9652 9658 10376 11118 11236 11190 11131>,
+			<9652 9657 10155 11117 11245 11208 11140>,
+			<9652 9656 10000 11109 11252 11224 11152>,
+			<9652 9655 9892 11094 11259 11233 11175>,
+			<9652 9654 9812 11060 11260 11250 11208>,
+			<9652 9654 9762 11020 11250 11255 11218>,
+			<9652 9653 9725 10915 11227 11244 11186>,
+			<9652 9653 9701 10784 11207 11227 11146>,
+			<9652 9653 9688 10695 11192 11211 11135>,
+			<9651 9652 9678 10615 11172 11194 11131>,
+			<9651 9652 9671 10480 11143 11192 11126>,
+			<9651 9652 9665 10201 11106 11216 11112>,
+			<9651 9651 9661 10108 11076 11220 11105>,
+			<9651 9651 9658 10159 11042 11183 11120>,
+			<9650 9651 9656 9965 10929 11157 11073>,
+			<9650 9651 9654 9856 10889 11090 11023>,
+			<9650 9651 9653 9796 10823 11057 10968>,
+			<9649 9650 9653 9741 10794 11051 10955>,
+			<9649 9650 9652 9696 10740 11029 10918>,
+			<9649 9650 9652 9680 10652 10968 10907>,
+			<9648 9650 9651 9670 10540 10916 10868>,
+			<9648 9649 9651 9663 10397 10801 10776>,
+			<9647 9648 9650 9657 10262 10712 10696>,
+			<9647 9648 9650 9654 10448 10584 10596>,
+			<9647 9648 9650 9654 10448 10584 10596>,
+			<9647 9648 9650 9654 10448 10584 10596>;
+	};
+
+	qcom,pc-temp-y3-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <14249 13491 13351 13296 13276 13275 13272>,
+			<14289 13481 13348 13297 13278 13275 13272>,
+			<14293 13476 13346 13298 13280 13275 13273>,
+			<14269 13476 13347 13300 13282 13276 13274>,
+			<14223 13480 13349 13302 13283 13276 13274>,
+			<14165 13486 13352 13303 13283 13276 13275>,
+			<14057 13513 13358 13303 13283 13276 13275>,
+			<13951 13546 13363 13304 13283 13276 13275>,
+			<13946 13543 13365 13306 13283 13277 13275>,
+			<13996 13505 13365 13310 13284 13278 13275>,
+			<14024 13476 13366 13315 13285 13278 13276>,
+			<13979 13465 13371 13319 13285 13278 13276>,
+			<13920 13456 13377 13322 13285 13278 13276>,
+			<13916 13446 13376 13322 13286 13278 13276>,
+			<13935 13434 13369 13321 13288 13279 13277>,
+			<13956 13428 13363 13320 13290 13279 13277>,
+			<13974 13428 13359 13318 13291 13280 13278>,
+			<13993 13428 13354 13316 13292 13282 13278>,
+			<14013 13414 13349 13313 13292 13283 13279>,
+			<14037 13377 13343 13308 13291 13283 13281>,
+			<14068 13356 13338 13304 13290 13284 13281>,
+			<14115 13351 13336 13301 13286 13280 13278>,
+			<14171 13349 13333 13299 13283 13276 13274>,
+			<14221 13354 13323 13298 13282 13275 13273>,
+			<14271 13374 13301 13297 13281 13275 13273>,
+			<14325 13397 13289 13297 13281 13275 13273>,
+			<14385 13424 13273 13297 13280 13275 13273>,
+			<14448 13457 13259 13297 13280 13275 13273>,
+			<14513 13494 13259 13296 13280 13275 13273>,
+			<14578 13537 13259 13296 13280 13275 13273>,
+			<14647 13586 13260 13295 13280 13274 13272>,
+			<14717 13644 13261 13291 13280 13274 13272>,
+			<14792 13708 13262 13288 13279 13274 13272>,
+			<14878 13777 13264 13289 13279 13274 13272>,
+			<14972 13853 13268 13293 13279 13273 13272>,
+			<15069 13939 13274 13295 13279 13273 13272>,
+			<15166 14040 13285 13294 13279 13274 13272>,
+			<15270 14153 13299 13292 13280 13274 13273>,
+			<15386 14276 13317 13292 13279 13274 13273>,
+			<15514 14412 13340 13293 13279 13274 13273>,
+			<15658 14564 13372 13291 13279 13274 13273>,
+			<15825 14738 13423 13271 13280 13275 13273>,
+			<16019 14925 13493 13262 13280 13275 13273>,
+			<16253 15128 13598 13261 13280 13274 13273>,
+			<16581 15354 13729 13263 13279 13275 13274>,
+			<16918 15547 13885 13266 13284 13276 13275>,
+			<17576 15700 13996 13270 13284 13277 13277>,
+			<18634 15883 14139 13280 13288 13279 13277>,
+			<20075 16098 14305 13309 13290 13280 13277>,
+			<22149 16340 14489 13343 13292 13280 13276>,
+			<25271 16656 14726 13389 13294 13281 13277>,
+			<29950 17634 15025 13481 13299 13283 13278>,
+			<37310 19636 15401 13635 13309 13286 13283>,
+			<47876 22946 16005 13899 13335 13293 13287>,
+			<47876 22946 16005 13899 13335 13293 13287>,
+			<47876 22946 16005 13899 13335 13293 13287>;
+	};
+
+	qcom,pc-temp-y4-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <17711 16973 16623 16526 16458 16452 16456>,
+			<17567 16999 16632 16525 16457 16452 16456>,
+			<17504 17030 16641 16525 16457 16452 16456>,
+			<17504 17060 16652 16526 16457 16452 16456>,
+			<17547 17082 16663 16528 16457 16452 16456>,
+			<17613 17089 16674 16531 16457 16452 16456>,
+			<17765 17077 16687 16535 16459 16452 16456>,
+			<17948 17059 16701 16539 16462 16453 16456>,
+			<18024 17098 16711 16545 16465 16453 16456>,
+			<18066 17276 16720 16552 16468 16454 16457>,
+			<18080 17396 16735 16563 16473 16455 16457>,
+			<17811 17426 16824 16584 16480 16458 16458>,
+			<17427 17443 16930 16612 16490 16461 16460>,
+			<17319 17384 16951 16638 16498 16465 16462>,
+			<17285 17155 16958 16663 16504 16470 16465>,
+			<17245 17028 16959 16695 16515 16476 16469>,
+			<17166 17014 16934 16758 16539 16486 16475>,
+			<17085 17005 16887 16816 16571 16502 16486>,
+			<17039 16980 16831 16800 16609 16530 16506>,
+			<17007 16933 16754 16713 16656 16576 16541>,
+			<16985 16886 16692 16635 16664 16593 16558>,
+			<16968 16837 16644 16572 16570 16535 16521>,
+			<16957 16797 16610 16522 16475 16468 16470>,
+			<16954 16783 16607 16507 16460 16455 16458>,
+			<16953 16776 16623 16498 16454 16451 16455>,
+			<16953 16770 16632 16494 16453 16449 16454>,
+			<16951 16765 16645 16493 16454 16449 16453>,
+			<16951 16761 16659 16493 16455 16448 16453>,
+			<16953 16761 16662 16492 16457 16449 16453>,
+			<16959 16761 16663 16493 16461 16452 16454>,
+			<16965 16762 16667 16493 16466 16456 16455>,
+			<16974 16764 16677 16492 16474 16464 16461>,
+			<16982 16767 16687 16492 16479 16471 16470>,
+			<16985 16770 16690 16494 16478 16474 16476>,
+			<16987 16775 16693 16500 16474 16474 16483>,
+			<16990 16778 16693 16505 16467 16471 16482>,
+			<16999 16782 16689 16508 16455 16458 16467>,
+			<17010 16784 16685 16510 16448 16447 16453>,
+			<17021 16783 16685 16511 16449 16450 16455>,
+			<17033 16781 16683 16512 16452 16456 16465>,
+			<17048 16779 16681 16517 16455 16459 16471>,
+			<17066 16770 16670 16558 16460 16458 16470>,
+			<17087 16768 16654 16579 16464 16456 16468>,
+			<17112 16776 16634 16584 16465 16448 16452>,
+			<17124 16801 16629 16593 16474 16448 16444>,
+			<17066 16819 16647 16617 16493 16467 16470>,
+			<17161 16856 16669 16641 16507 16488 16496>,
+			<17324 16905 16699 16672 16536 16520 16521>,
+			<17559 16944 16754 16675 16565 16529 16536>,
+			<17893 16949 16780 16683 16555 16503 16488>,
+			<18450 16941 16767 16681 16554 16495 16479>,
+			<19496 17078 16794 16695 16582 16508 16485>,
+			<21979 17565 16874 16751 16646 16545 16510>,
+			<30091 19162 17124 16888 16859 16671 16581>,
+			<30091 19162 17124 16888 16859 16671 16581>,
+			<30091 19162 17124 16888 16859 16671 16581>;
+	};
+
+	qcom,pc-temp-y5-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <9336 11501 16034 14767 13793 19407 15565>,
+			<10230 11603 15822 15156 15683 19413 16938>,
+			<10807 11875 15497 15333 17017 19416 18058>,
+			<11133 12285 15152 15352 17855 19416 18894>,
+			<11279 12803 14881 15266 18259 19413 19416>,
+			<11310 13403 14778 15128 18284 19405 19590>,
+			<11059 14551 14807 14793 17405 18933 19301>,
+			<10701 15710 14848 14419 16236 18269 18809>,
+			<11143 15425 14688 14471 15943 18195 18561>,
+			<13343 13533 13983 14951 15873 18327 18385>,
+			<14582 12513 13556 15219 15744 18394 18198>,
+			<13448 13803 13493 14892 15050 17832 17726>,
+			<11924 15473 13460 14418 14306 16921 17099>,
+			<11782 15394 13744 14254 14381 16318 16821>,
+			<12065 14258 14851 14181 14869 15815 16673>,
+			<12212 13562 15643 14199 15070 15556 16471>,
+			<12106 13428 15965 14556 14786 15450 15954>,
+			<11900 13274 16199 15160 14490 15387 15465>,
+			<11618 12936 16398 15863 14755 15446 15449>,
+			<11196 12423 16588 16824 15793 15777 15650>,
+			<11019 11952 16732 17460 16919 16267 15980>,
+			<11074 11476 16879 17821 18292 17600 16933>,
+			<11141 11117 16964 18087 19430 19112 18163>,
+			<11133 11033 16245 18242 19821 19838 19000>,
+			<11069 11009 14141 18325 19945 20331 19696>,
+			<11046 11024 12876 18331 19914 20756 20093>,
+			<11109 11056 11798 18517 19842 21457 20297>,
+			<11170 11084 10948 18759 19785 21999 20418>,
+			<11161 11132 10879 18828 19716 21658 20286>,
+			<11138 11232 10862 18868 19575 20509 19563>,
+			<11111 11269 10868 18768 19409 19604 18813>,
+			<11071 11345 11005 17096 19184 18920 18072>,
+			<11039 11421 11165 15478 19049 18499 17524>,
+			<11083 11456 11261 16038 19331 18661 17776>,
+			<11207 11520 11350 17571 20041 19331 19034>,
+			<11252 11543 11387 18037 20606 20274 20444>,
+			<11213 11613 11553 17270 21412 23017 22060>,
+			<11168 11678 11697 16300 21789 25208 23225>,
+			<11151 11640 11640 15861 20914 24442 22731>,
+			<11145 11545 11511 15530 19618 22425 21047>,
+			<11154 11506 11463 14798 19274 21559 20283>,
+			<11189 11457 11412 12697 19217 21506 20308>,
+			<11250 11415 11500 11853 18717 21719 20486>,
+			<11392 11368 11742 11779 17923 22443 22679>,
+			<11471 11364 11818 11639 16687 21754 22971>,
+			<11412 11379 11581 11310 17555 18408 18279>,
+			<11284 11464 11576 11214 16686 17313 17483>,
+			<10955 11729 11969 11315 17033 16467 15409>,
+			<10501 12142 11899 11677 16717 15881 14424>,
+			<10146 11979 11895 11966 17491 17177 15372>,
+			<9743 11649 12007 11983 17478 18213 16253>,
+			<9402 11017 11938 11964 17190 17836 15973>,
+			<9188 10265 11845 11923 16780 17343 17751>,
+			<8988 9626 11312 12185 16916 17400 17911>,
+			<8988 9626 11312 12185 16916 17400 17911>,
+			<8988 9626 11312 12185 16916 17400 17911>;
+	};
+
+	qcom,pc-temp-y6-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <7520 6106 5405 5178 5064 5046 5042>,
+			<7480 6097 5401 5177 5064 5046 5042>,
+			<7441 6092 5400 5176 5065 5046 5042>,
+			<7405 6089 5400 5176 5066 5047 5043>,
+			<7374 6088 5401 5176 5067 5047 5044>,
+			<7350 6088 5403 5176 5067 5047 5044>,
+			<7329 6090 5407 5176 5068 5047 5044>,
+			<7314 6094 5413 5177 5068 5047 5044>,
+			<7323 6102 5416 5178 5069 5047 5044>,
+			<7367 6117 5418 5182 5071 5048 5044>,
+			<7391 6129 5422 5187 5073 5049 5045>,
+			<7291 6135 5450 5195 5075 5050 5045>,
+			<7156 6139 5483 5204 5078 5051 5046>,
+			<7138 6123 5488 5211 5081 5052 5047>,
+			<7142 6059 5490 5218 5085 5054 5048>,
+			<7144 6027 5490 5226 5089 5056 5050>,
+			<7141 6030 5484 5243 5097 5060 5052>,
+			<7136 6034 5472 5259 5107 5066 5055>,
+			<7138 6032 5457 5253 5118 5075 5062>,
+			<7150 6027 5435 5225 5131 5088 5073>,
+			<7165 6025 5421 5201 5133 5093 5078>,
+			<7194 6031 5414 5182 5104 5074 5065>,
+			<7230 6042 5409 5169 5075 5052 5048>,
+			<7265 6061 5410 5167 5071 5048 5044>,
+			<7301 6095 5412 5166 5069 5047 5043>,
+			<7340 6132 5415 5166 5069 5046 5042>,
+			<7383 6169 5421 5168 5070 5047 5042>,
+			<7430 6210 5431 5171 5071 5047 5042>,
+			<7476 6254 5444 5175 5073 5048 5043>,
+			<7523 6302 5464 5178 5075 5049 5043>,
+			<7575 6354 5486 5181 5078 5050 5044>,
+			<7633 6411 5511 5183 5081 5052 5046>,
+			<7696 6471 5539 5185 5083 5055 5048>,
+			<7764 6535 5569 5192 5084 5056 5050>,
+			<7836 6602 5603 5205 5084 5056 5053>,
+			<7911 6677 5640 5216 5084 5056 5053>,
+			<7991 6759 5681 5225 5083 5053 5049>,
+			<8076 6849 5727 5234 5083 5051 5046>,
+			<8172 6948 5778 5244 5084 5052 5047>,
+			<8278 7058 5835 5257 5087 5055 5050>,
+			<8396 7178 5899 5273 5091 5057 5052>,
+			<8531 7313 5971 5295 5095 5058 5052>,
+			<8689 7461 6060 5322 5099 5058 5052>,
+			<8881 7625 6170 5355 5104 5056 5049>,
+			<9142 7801 6295 5404 5112 5059 5048>,
+			<9395 7952 6438 5465 5127 5066 5057>,
+			<9966 8083 6542 5513 5135 5074 5067>,
+			<10874 8233 6666 5574 5150 5086 5075>,
+			<12099 8404 6813 5646 5166 5090 5080>,
+			<13825 8597 6972 5725 5172 5084 5066>,
+			<16318 8831 7159 5819 5184 5085 5065>,
+			<20019 9655 7408 5955 5214 5093 5070>,
+			<25895 11356 7725 6149 5262 5110 5083>,
+			<35348 14260 8288 6430 5374 5157 5109>,
+			<35348 14260 8288 6430 5374 5157 5109>,
+			<35348 14260 8288 6430 5374 5157 5109>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi
new file mode 100644
index 0000000..f418fa0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi
@@ -0,0 +1,1050 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,mlp356477_2800mah {
+	/* mlp356477_2800mah_averaged_MasterSlave_Aug14th2017 */
+	qcom,max-voltage-uv = <4400000>;
+	qcom,fg-cc-cv-threshold-mv = <4390>;
+	qcom,fastchg-current-ma = <4200>;
+	qcom,batt-id-kohm = <82>;
+	qcom,battery-beta = <4250>;
+	qcom,battery-therm-kohm = <32>;
+	qcom,battery-type =
+		"mlp356477_2800mah_averaged_MasterSlave_Aug14th2017";
+	qcom,qg-batt-profile-ver = <100>;
+
+	qcom,jeita-fcc-ranges = <0   150   560000
+				 151 450  4200000
+				 451 550  2380000>;
+	qcom,jeita-fv-ranges =  <0   150  4150000
+				 151 450  4400000
+				 451 550  4150000>;
+
+	qcom,fcc1-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <2715 2788 2861 2898 2908>;
+	};
+
+	qcom,fcc2-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <2846 2860 2868 2865 2865>;
+	};
+
+	qcom,pc-temp-v1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43494 43682 43812 43865 43879>,
+			<43243 43420 43582 43645 43659>,
+			<42984 43174 43350 43418 43434>,
+			<42737 42940 43115 43191 43208>,
+			<42506 42710 42878 42958 42978>,
+			<42287 42479 42641 42722 42746>,
+			<42087 42250 42407 42489 42514>,
+			<41903 42027 42175 42255 42281>,
+			<41709 41807 41948 42023 42050>,
+			<41489 41592 41723 41794 41822>,
+			<41265 41381 41502 41568 41596>,
+			<41069 41176 41286 41348 41374>,
+			<40898 40982 41074 41131 41155>,
+			<40720 40799 40871 40921 40942>,
+			<40501 40613 40673 40716 40735>,
+			<40269 40405 40482 40518 40534>,
+			<40088 40193 40295 40329 40343>,
+			<39955 40022 40116 40148 40162>,
+			<39834 39894 39952 39975 39988>,
+			<39708 39765 39807 39818 39827>,
+			<39583 39577 39645 39659 39667>,
+			<39447 39345 39420 39461 39475>,
+			<39277 39148 39173 39221 39239>,
+			<39089 38991 38991 39014 39028>,
+			<38930 38860 38851 38860 38868>,
+			<38794 38758 38733 38728 38732>,
+			<38683 38676 38628 38611 38612>,
+			<38607 38602 38535 38507 38505>,
+			<38548 38529 38451 38414 38409>,
+			<38501 38462 38373 38327 38317>,
+			<38466 38407 38305 38251 38234>,
+			<38437 38360 38245 38182 38160>,
+			<38405 38317 38193 38121 38092>,
+			<38366 38277 38147 38067 38030>,
+			<38329 38240 38109 38022 37980>,
+			<38300 38203 38069 37977 37929>,
+			<38273 38170 38027 37921 37863>,
+			<38236 38130 37980 37857 37784>,
+			<38162 38057 37912 37781 37700>,
+			<38062 37946 37816 37690 37609>,
+			<37947 37830 37704 37585 37507>,
+			<37801 37713 37578 37463 37382>,
+			<37644 37575 37436 37322 37239>,
+			<37473 37394 37270 37162 37082>,
+			<37320 37251 37129 37032 36959>,
+			<37220 37161 37058 36960 36899>,
+			<37185 37129 37033 36942 36880>,
+			<37156 37103 37014 36927 36865>,
+			<37120 37070 36988 36902 36835>,
+			<37014 36957 36885 36755 36652>,
+			<36682 36593 36544 36398 36287>,
+			<36204 36109 36077 35921 35807>,
+			<35597 35486 35476 35307 35181>,
+			<34771 34630 34656 34460 34321>,
+			<33460 33262 33379 33128 32955>,
+			<30000 30000 30000 30000 30000>;
+	};
+
+	qcom,pc-temp-v2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43850 43830 43805 43740 43725>,
+			<43429 43514 43528 43481 43467>,
+			<43064 43219 43264 43228 43216>,
+			<42767 42948 43012 42983 42973>,
+			<42526 42700 42773 42744 42738>,
+			<42296 42458 42537 42509 42505>,
+			<42059 42213 42303 42277 42272>,
+			<41822 41972 42071 42047 42041>,
+			<41571 41739 41843 41820 41814>,
+			<41298 41515 41619 41595 41589>,
+			<41069 41297 41398 41374 41368>,
+			<40928 41088 41181 41158 41151>,
+			<40808 40884 40967 40946 40938>,
+			<40611 40677 40763 40742 40734>,
+			<40284 40461 40566 40541 40534>,
+			<39989 40259 40373 40348 40342>,
+			<39811 40087 40180 40164 40158>,
+			<39662 39920 39993 39985 39980>,
+			<39459 39722 39821 39814 39808>,
+			<39184 39492 39664 39651 39646>,
+			<38924 39264 39483 39469 39466>,
+			<38721 39048 39237 39230 39230>,
+			<38546 38846 38982 38986 38989>,
+			<38403 38678 38799 38809 38813>,
+			<38282 38535 38654 38669 38674>,
+			<38189 38406 38530 38547 38552>,
+			<38125 38286 38419 38438 38442>,
+			<38075 38179 38320 38341 38343>,
+			<38030 38090 38229 38250 38250>,
+			<37992 38012 38144 38166 38164>,
+			<37955 37949 38066 38089 38086>,
+			<37916 37900 37993 38019 38016>,
+			<37875 37857 37925 37953 37949>,
+			<37832 37817 37860 37884 37875>,
+			<37788 37781 37801 37812 37795>,
+			<37738 37740 37738 37728 37702>,
+			<37680 37688 37671 37625 37587>,
+			<37613 37625 37600 37519 37469>,
+			<37537 37552 37525 37430 37374>,
+			<37448 37465 37446 37352 37292>,
+			<37349 37363 37353 37263 37200>,
+			<37237 37238 37238 37151 37088>,
+			<37114 37101 37106 37022 36960>,
+			<36989 36957 36952 36870 36813>,
+			<36875 36859 36862 36807 36758>,
+			<36792 36792 36828 36785 36734>,
+			<36754 36762 36812 36769 36719>,
+			<36707 36710 36780 36736 36687>,
+			<36633 36613 36721 36656 36581>,
+			<36472 36411 36517 36379 36276>,
+			<36149 36031 36113 35946 35829>,
+			<35650 35485 35584 35386 35258>,
+			<34964 34771 34884 34643 34500>,
+			<34007 33739 33902 33598 33440>,
+			<32474 32144 32393 32025 31829>,
+			<28051 26513 28737 27554 26991>;
+	};
+
+	qcom,pc-temp-z1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <14442 13243 12339 11979 11839>,
+			<14411 13218 12328 11916 11773>,
+			<14392 13199 12294 11893 11756>,
+			<14384 13180 12273 11879 11745>,
+			<14381 13174 12263 11870 11738>,
+			<14377 13179 12257 11863 11735>,
+			<14369 13182 12253 11858 11731>,
+			<14358 13175 12250 11851 11726>,
+			<14349 13158 12248 11847 11722>,
+			<14339 13146 12242 11845 11720>,
+			<14332 13143 12237 11845 11719>,
+			<14327 13144 12237 11844 11718>,
+			<14321 13142 12238 11840 11716>,
+			<14313 13135 12234 11837 11715>,
+			<14306 13128 12222 11835 11714>,
+			<14299 13120 12215 11834 11714>,
+			<14293 13113 12211 11833 11713>,
+			<14293 13111 12203 11830 11714>,
+			<14297 13119 12202 11828 11715>,
+			<14304 13129 12210 11831 11716>,
+			<14312 13133 12215 11837 11718>,
+			<14318 13130 12221 11841 11721>,
+			<14319 13125 12230 11843 11726>,
+			<14320 13135 12234 11846 11730>,
+			<14324 13151 12236 11852 11734>,
+			<14340 13158 12238 11860 11737>,
+			<14358 13165 12247 11865 11741>,
+			<14373 13167 12258 11870 11747>,
+			<14389 13165 12260 11873 11752>,
+			<14394 13167 12258 11877 11757>,
+			<14373 13169 12256 11880 11760>,
+			<14334 13168 12253 11886 11764>,
+			<14321 13167 12247 11892 11768>,
+			<14348 13170 12248 11897 11772>,
+			<14378 13177 12260 11901 11778>,
+			<14371 13182 12271 11905 11783>,
+			<14343 13188 12277 11910 11788>,
+			<14331 13194 12283 11917 11792>,
+			<14346 13205 12290 11924 11797>,
+			<14369 13219 12300 11931 11803>,
+			<14389 13228 12307 11937 11809>,
+			<14412 13237 12311 11941 11815>,
+			<14410 13245 12315 11945 11820>,
+			<14367 13259 12315 11949 11823>,
+			<14429 13239 12311 11954 11824>,
+			<14440 13243 12333 11959 11830>,
+			<14452 13241 12320 11961 11828>,
+			<14443 13243 12329 11964 11831>,
+			<14484 13241 12332 11968 11836>,
+			<14448 13263 12343 11977 11845>,
+			<14473 13293 12346 11988 11856>,
+			<14501 13300 12357 12000 11864>,
+			<14521 13333 12374 12015 11879>,
+			<14603 13373 12420 12034 11897>,
+			<14603 13373 12420 12034 11897>,
+			<14603 13373 12420 12034 11897>;
+	};
+
+	qcom,pc-temp-z2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9070 11213 10264 10349 10299>,
+			<9403 10211 10276 10386 10313>,
+			<9826 10116 10342 10430 10322>,
+			<9983 10114 10362 10447 10350>,
+			<9978 10115 10368 10437 10342>,
+			<9967 10120 10372 10407 10282>,
+			<9846 10126 10371 10393 10237>,
+			<9534 10132 10368 10388 10217>,
+			<9372 10137 10365 10382 10206>,
+			<9574 10141 10365 10378 10208>,
+			<9873 10143 10365 10386 10216>,
+			<9940 10145 10357 10384 10231>,
+			<9908 10147 10346 10370 10273>,
+			<9890 10148 10344 10357 10310>,
+			<9864 10149 10352 10353 10325>,
+			<9749 10147 10354 10353 10336>,
+			<9714 10144 10347 10355 10342>,
+			<10069 10146 10343 10360 10343>,
+			<10530 10156 10344 10366 10344>,
+			<10637 10166 10343 10378 10353>,
+			<10631 10154 10344 10396 10363>,
+			<10605 10119 10374 10405 10360>,
+			<10392 10103 10415 10412 10326>,
+			<10061 10118 10414 10414 10294>,
+			<9958 10135 10371 10402 10266>,
+			<9962 10132 10339 10387 10241>,
+			<9968 10117 10335 10377 10241>,
+			<9971 10107 10337 10360 10253>,
+			<9975 10109 10342 10353 10270>,
+			<9977 10112 10351 10373 10299>,
+			<9855 10116 10359 10397 10330>,
+			<9628 10123 10362 10398 10343>,
+			<9563 10131 10365 10389 10349>,
+			<9597 10143 10370 10392 10366>,
+			<9647 10159 10379 10443 10415>,
+			<9714 10166 10389 10499 10464>,
+			<9809 10169 10397 10520 10486>,
+			<9844 10172 10405 10533 10511>,
+			<9756 10186 10432 10548 10531>,
+			<9631 10212 10505 10586 10563>,
+			<9541 10225 10551 10621 10587>,
+			<9445 10161 10538 10637 10540>,
+			<9378 10144 10527 10646 10468>,
+			<9335 10322 10539 10611 10495>,
+			<9269 13378 10554 10627 10491>,
+			<9218 14361 10475 10629 10534>,
+			<9220 14794 10469 10642 10588>,
+			<9212 15070 10496 10651 10586>,
+			<9188 13785 10469 10739 10647>,
+			<9170 13219 10622 10694 10458>,
+			<9151 12652 10655 10557 10325>,
+			<9135 12236 10610 10495 10272>,
+			<9116 11644 10496 10432 10195>,
+			<9081 11027 10456 10300 10139>,
+			<9081 11027 10456 10300 10139>,
+			<9081 11027 10456 10300 10139>;
+	};
+
+	qcom,pc-temp-z3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <19308 19258 19367 19369 19345>,
+			<19567 19611 19463 19395 19370>,
+			<19850 19705 19512 19411 19381>,
+			<19967 19740 19520 19416 19385>,
+			<19987 19749 19515 19414 19384>,
+			<19996 19735 19507 19405 19379>,
+			<19860 19713 19499 19400 19373>,
+			<19484 19698 19492 19395 19369>,
+			<19288 19687 19483 19391 19365>,
+			<19508 19679 19473 19388 19362>,
+			<19829 19673 19467 19382 19358>,
+			<19858 19667 19463 19378 19357>,
+			<19678 19660 19461 19372 19355>,
+			<19567 19648 19461 19369 19353>,
+			<19627 19641 19463 19369 19353>,
+			<19647 19646 19465 19368 19355>,
+			<19577 19654 19458 19367 19355>,
+			<19415 19653 19447 19366 19345>,
+			<19268 19631 19443 19365 19337>,
+			<19258 19613 19443 19365 19337>,
+			<19258 19623 19446 19366 19337>,
+			<19260 19652 19459 19374 19342>,
+			<19450 19665 19480 19393 19364>,
+			<19797 19666 19494 19403 19379>,
+			<19919 19667 19506 19402 19379>,
+			<19924 19671 19511 19400 19378>,
+			<19927 19681 19507 19400 19374>,
+			<19922 19686 19499 19400 19366>,
+			<19906 19684 19492 19399 19360>,
+			<19891 19680 19487 19397 19359>,
+			<19798 19673 19482 19393 19359>,
+			<19639 19661 19476 19390 19359>,
+			<19579 19650 19470 19386 19357>,
+			<19566 19644 19465 19382 19355>,
+			<19553 19639 19460 19380 19352>,
+			<19468 19636 19457 19378 19348>,
+			<19316 19630 19455 19375 19346>,
+			<19261 19624 19453 19373 19344>,
+			<19262 19618 19450 19371 19343>,
+			<19263 19609 19443 19369 19345>,
+			<19264 19576 19437 19368 19347>,
+			<19267 19367 19435 19368 19350>,
+			<19269 19261 19432 19367 19353>,
+			<19270 19260 19421 19365 19353>,
+			<19274 19257 19413 19361 19354>,
+			<19278 19257 19368 19354 19332>,
+			<19278 19257 19367 19346 19332>,
+			<19279 19257 19362 19331 19323>,
+			<19282 19257 19368 19326 19327>,
+			<19284 19257 19354 19338 19350>,
+			<19287 19257 19361 19346 19348>,
+			<19290 19257 19368 19356 19347>,
+			<19295 19257 19370 19353 19356>,
+			<19308 19258 19392 19382 19373>,
+			<19308 19258 19392 19382 19373>,
+			<19308 19258 19392 19382 19373>;
+	};
+
+	qcom,pc-temp-z4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <16598 15992 15337 14972 14879>,
+			<16815 16035 15386 15059 14940>,
+			<16561 15923 15277 14982 14899>,
+			<16283 15657 15173 14901 14842>,
+			<15982 15436 15082 14879 14824>,
+			<15774 15304 15020 14868 14816>,
+			<15800 15207 14988 14856 14809>,
+			<15941 15154 14966 14843 14802>,
+			<16005 15119 14946 14830 14794>,
+			<15750 15094 14928 14818 14785>,
+			<15383 15076 14912 14807 14775>,
+			<15316 15063 14897 14797 14766>,
+			<15433 15048 14884 14788 14757>,
+			<15501 15033 14874 14778 14748>,
+			<15463 15025 14866 14769 14737>,
+			<15509 15037 14860 14760 14725>,
+			<15596 15057 14852 14751 14718>,
+			<15677 15056 14841 14742 14715>,
+			<15729 15002 14835 14738 14712>,
+			<15708 14951 14832 14736 14709>,
+			<15684 15017 14833 14735 14707>,
+			<15650 15207 14923 14756 14718>,
+			<15508 15302 15068 14837 14777>,
+			<15298 15313 15091 14879 14814>,
+			<15235 15319 15040 14870 14809>,
+			<15282 15294 14989 14855 14800>,
+			<15330 15200 14962 14841 14793>,
+			<15320 15131 14943 14826 14787>,
+			<15270 15105 14932 14814 14780>,
+			<15232 15088 14926 14805 14771>,
+			<15276 15076 14923 14798 14761>,
+			<15373 15065 14921 14794 14754>,
+			<15397 15057 14920 14791 14747>,
+			<15385 15051 14919 14789 14742>,
+			<15376 15043 14916 14787 14738>,
+			<15430 15036 14914 14786 14736>,
+			<15544 15016 14915 14794 14745>,
+			<15577 14998 14918 14811 14767>,
+			<15550 14991 14917 14816 14774>,
+			<15520 14987 14909 14811 14768>,
+			<15502 14998 14896 14803 14760>,
+			<15491 15139 14873 14788 14752>,
+			<15475 15211 14850 14774 14747>,
+			<15445 15195 14842 14774 14750>,
+			<15345 15130 14813 14764 14741>,
+			<15318 15079 14802 14736 14721>,
+			<15308 15066 14777 14720 14700>,
+			<15301 15057 14757 14705 14684>,
+			<15285 15045 14739 14698 14668>,
+			<15274 15053 14775 14717 14688>,
+			<15294 15076 14782 14719 14696>,
+			<15311 15080 14778 14712 14701>,
+			<15326 15091 14779 14719 14701>,
+			<15354 15108 14768 14706 14703>,
+			<15354 15108 14768 14706 14703>,
+			<15354 15108 14768 14706 14703>;
+	};
+
+	qcom,pc-temp-z5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <10764 10957 12110 13794 13670>,
+			<11745 12925 13686 14768 14977>,
+			<12716 14010 14746 16056 16445>,
+			<13404 14718 15521 16744 17361>,
+			<13905 15321 16180 16789 17415>,
+			<14200 15933 16545 16568 17166>,
+			<13611 16455 16653 16420 16940>,
+			<11869 16730 16710 16364 16838>,
+			<10978 16895 16699 16401 16763>,
+			<12521 17062 16594 16402 16659>,
+			<14783 17315 16549 16292 16587>,
+			<15011 17507 16656 16178 16634>,
+			<13819 17490 16845 16003 16770>,
+			<13134 17527 17100 15977 16943>,
+			<13823 17638 17538 16159 17435>,
+			<14192 17626 17786 16425 18421>,
+			<13660 17482 17557 16723 18632>,
+			<12194 17384 17254 17131 17493>,
+			<10877 17447 17366 17305 16542>,
+			<10795 17704 18253 17609 16717>,
+			<10808 18910 18937 18108 17070>,
+			<10857 21136 18167 17900 17037>,
+			<13850 21892 16713 16569 16529>,
+			<19285 19957 16394 15708 16174>,
+			<21102 17736 16736 15560 16006>,
+			<20977 17560 17186 15557 15832>,
+			<20752 18050 17734 15845 15773>,
+			<20272 18693 18431 16567 15708>,
+			<19413 19705 19132 17289 15707>,
+			<18772 20743 19927 17959 16182>,
+			<17386 21034 20581 18611 16967>,
+			<15327 21059 21018 19179 17620>,
+			<14631 21034 21355 19699 18403>,
+			<14512 21133 21507 20256 19056>,
+			<14338 21373 21604 21000 19675>,
+			<13329 21460 21643 21494 20064>,
+			<11563 21322 21601 20994 19488>,
+			<10927 21163 21493 19730 18023>,
+			<10937 21134 21270 19156 17559>,
+			<10948 21040 20651 18991 17865>,
+			<10942 20318 20135 18929 18319>,
+			<10912 14582 19994 18903 18925>,
+			<10885 11608 19761 18788 19444>,
+			<10861 11587 18126 17802 18686>,
+			<10871 11314 17978 17266 18426>,
+			<10857 11130 15054 17271 15914>,
+			<10841 11088 15214 17078 16658>,
+			<10831 11067 15184 16484 17071>,
+			<10841 11046 15966 16365 19357>,
+			<10877 11142 14378 15551 19427>,
+			<10922 11156 14140 15626 17699>,
+			<10887 11109 14272 16679 16814>,
+			<10848 11069 14202 15606 17668>,
+			<10790 10995 15166 19180 19716>,
+			<10790 10995 15166 19180 19716>,
+			<10790 10995 15166 19180 19716>;
+	};
+
+	qcom,pc-temp-z6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <17029 15901 15123 14807 14723>,
+			<17156 16022 15165 14844 14750>,
+			<17081 15990 15131 14815 14734>,
+			<16977 15851 15090 14780 14711>,
+			<16818 15720 15039 14766 14700>,
+			<16645 15630 15000 14756 14693>,
+			<16486 15560 14978 14746 14686>,
+			<16331 15519 14962 14737 14680>,
+			<16255 15490 14945 14728 14674>,
+			<16244 15468 14929 14720 14668>,
+			<16238 15452 14916 14712 14662>,
+			<16217 15438 14905 14704 14656>,
+			<16172 15422 14897 14697 14651>,
+			<16139 15401 14891 14691 14646>,
+			<16146 15390 14887 14686 14642>,
+			<16166 15395 14883 14681 14638>,
+			<16163 15403 14876 14677 14633>,
+			<16120 15402 14866 14672 14627>,
+			<16076 15372 14862 14670 14622>,
+			<16063 15345 14862 14670 14621>,
+			<16057 15380 14865 14671 14621>,
+			<16055 15480 14915 14684 14629>,
+			<16092 15533 14991 14732 14668>,
+			<16168 15543 15006 14757 14692>,
+			<16218 15549 14992 14753 14691>,
+			<16251 15541 14976 14746 14687>,
+			<16270 15511 14964 14741 14683>,
+			<16266 15488 14954 14735 14676>,
+			<16246 15479 14948 14730 14671>,
+			<16227 15473 14944 14726 14666>,
+			<16204 15467 14942 14722 14662>,
+			<16176 15459 14941 14719 14659>,
+			<16164 15454 14939 14716 14657>,
+			<16159 15453 14938 14715 14654>,
+			<16154 15453 14937 14714 14651>,
+			<16145 15453 14936 14714 14649>,
+			<16133 15450 14939 14717 14652>,
+			<16130 15447 14943 14725 14662>,
+			<16133 15449 14943 14727 14665>,
+			<16139 15454 14940 14725 14664>,
+			<16147 15454 14936 14723 14663>,
+			<16161 15429 14929 14718 14662>,
+			<16171 15417 14922 14712 14662>,
+			<16178 15424 14918 14713 14664>,
+			<16162 15408 14909 14708 14663>,
+			<16165 15399 14883 14694 14643>,
+			<16168 15398 14875 14684 14633>,
+			<16172 15401 14867 14670 14622>,
+			<16179 15405 14866 14665 14618>,
+			<16193 15425 14881 14682 14641>,
+			<16228 15451 14892 14690 14645>,
+			<16262 15468 14902 14695 14650>,
+			<16300 15497 14912 14700 14657>,
+			<16361 15535 14930 14716 14672>,
+			<16361 15535 14930 14716 14672>,
+			<16361 15535 14930 14716 14672>;
+	};
+
+	qcom,pc-temp-y1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <6704 6050 5566 5322 5235>,
+			<6701 6050 5560 5320 5234>,
+			<6693 6051 5554 5318 5233>,
+			<6684 6051 5548 5316 5231>,
+			<6676 6052 5543 5313 5230>,
+			<6673 6053 5540 5311 5228>,
+			<6667 6054 5539 5308 5225>,
+			<6659 6054 5538 5305 5222>,
+			<6663 6055 5536 5302 5222>,
+			<6693 6056 5529 5299 5222>,
+			<6717 6055 5525 5298 5222>,
+			<6716 6050 5525 5297 5220>,
+			<6707 6044 5526 5296 5217>,
+			<6706 6044 5528 5295 5216>,
+			<6707 6049 5533 5293 5217>,
+			<6709 6052 5536 5291 5217>,
+			<6705 6053 5534 5290 5219>,
+			<6699 6055 5532 5288 5221>,
+			<6700 6057 5532 5289 5221>,
+			<6708 6062 5531 5290 5220>,
+			<6715 6065 5531 5292 5219>,
+			<6712 6067 5532 5294 5220>,
+			<6706 6071 5532 5296 5222>,
+			<6703 6071 5532 5297 5223>,
+			<6702 6070 5532 5298 5225>,
+			<6702 6069 5532 5299 5227>,
+			<6700 6068 5535 5301 5229>,
+			<6699 6065 5539 5305 5232>,
+			<6697 6062 5540 5309 5236>,
+			<6691 6059 5541 5311 5240>,
+			<6688 6059 5542 5314 5243>,
+			<6691 6063 5546 5317 5244>,
+			<6695 6069 5550 5320 5245>,
+			<6693 6072 5553 5324 5247>,
+			<6677 6077 5556 5329 5251>,
+			<6667 6080 5558 5333 5255>,
+			<6679 6081 5563 5336 5258>,
+			<6697 6082 5568 5339 5261>,
+			<6698 6085 5570 5342 5263>,
+			<6684 6094 5571 5348 5265>,
+			<6675 6101 5572 5352 5268>,
+			<6691 6098 5581 5353 5271>,
+			<6707 6096 5586 5356 5275>,
+			<6704 6102 5586 5363 5282>,
+			<6708 6104 5593 5368 5284>,
+			<6725 6098 5595 5370 5288>,
+			<6724 6114 5601 5370 5288>,
+			<6743 6089 5598 5376 5290>,
+			<6750 6086 5605 5374 5291>,
+			<6722 6104 5609 5381 5293>,
+			<6738 6105 5608 5384 5292>,
+			<6759 6112 5624 5392 5304>,
+			<6766 6128 5643 5400 5313>,
+			<6779 6149 5656 5417 5324>,
+			<6779 6149 5656 5417 5324>,
+			<6779 6149 5656 5417 5324>;
+	};
+
+	qcom,pc-temp-y2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9643 10639 11070 11121 11086>,
+			<9643 10662 11056 11097 11058>,
+			<9643 10675 11037 11063 11029>,
+			<9871 10680 11014 11027 11001>,
+			<10190 10680 10988 10997 10976>,
+			<10325 10677 10959 10981 10958>,
+			<10308 10664 10918 10973 10946>,
+			<10282 10644 10881 10967 10935>,
+			<10301 10632 10875 10959 10916>,
+			<10440 10623 10874 10933 10882>,
+			<10534 10619 10874 10919 10864>,
+			<10489 10626 10869 10936 10874>,
+			<10417 10643 10861 10961 10888>,
+			<10413 10676 10856 10952 10885>,
+			<10487 10748 10851 10897 10860>,
+			<10553 10801 10851 10866 10840>,
+			<10580 10826 10885 10876 10837>,
+			<10597 10843 10946 10896 10845>,
+			<10521 10842 11018 10943 10884>,
+			<10042 10822 11115 11060 10984>,
+			<9696 10809 11159 11120 11034>,
+			<9682 10815 11129 11098 11013>,
+			<9676 10826 11091 11071 10987>,
+			<9675 10835 11085 11079 11009>,
+			<9676 10846 11088 11121 11106>,
+			<9676 10848 11093 11154 11162>,
+			<9675 10684 11108 11176 11166>,
+			<9671 10460 11130 11199 11168>,
+			<9668 10652 11152 11224 11182>,
+			<9665 11565 11178 11263 11214>,
+			<9662 12069 11192 11286 11238>,
+			<9660 11796 11199 11310 11257>,
+			<9659 11319 11203 11338 11277>,
+			<9657 10963 11202 11344 11307>,
+			<9656 10643 11198 11320 11345>,
+			<9655 10423 11189 11299 11359>,
+			<9654 10140 11148 11294 11325>,
+			<9653 9828 11108 11301 11280>,
+			<9653 9733 11099 11301 11271>,
+			<9653 9707 11096 11290 11278>,
+			<9652 9692 11071 11287 11277>,
+			<9652 9681 10975 11329 11250>,
+			<9652 9674 10939 11356 11231>,
+			<9652 9668 10913 11303 11229>,
+			<9652 9664 10802 11253 11135>,
+			<9652 9663 10839 11180 11044>,
+			<9652 9661 10832 11146 11009>,
+			<9652 9660 10811 11105 10962>,
+			<9651 9659 10794 11061 10965>,
+			<9651 9658 10764 11053 10938>,
+			<9651 9658 10711 10981 10871>,
+			<9651 9656 10651 10927 10829>,
+			<9651 9654 10594 10851 10747>,
+			<9651 9654 10531 10798 10659>,
+			<9651 9654 10531 10798 10659>,
+			<9651 9654 10531 10798 10659>;
+	};
+
+	qcom,pc-temp-y3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <13677 13390 13309 13301 13279>,
+			<13657 13393 13309 13294 13279>,
+			<13634 13397 13311 13289 13279>,
+			<13612 13400 13312 13285 13279>,
+			<13596 13403 13314 13283 13279>,
+			<13590 13406 13315 13282 13279>,
+			<13594 13408 13315 13283 13280>,
+			<13600 13410 13316 13286 13281>,
+			<13594 13412 13317 13287 13282>,
+			<13548 13416 13319 13287 13282>,
+			<13515 13419 13321 13287 13282>,
+			<13513 13421 13322 13289 13282>,
+			<13512 13423 13323 13291 13282>,
+			<13509 13422 13325 13291 13283>,
+			<13504 13414 13328 13291 13284>,
+			<13497 13407 13329 13291 13286>,
+			<13488 13401 13328 13292 13287>,
+			<13478 13395 13325 13294 13288>,
+			<13470 13387 13324 13297 13290>,
+			<13465 13376 13323 13301 13294>,
+			<13458 13367 13322 13303 13296>,
+			<13428 13360 13315 13297 13290>,
+			<13384 13354 13306 13287 13281>,
+			<13362 13349 13303 13283 13278>,
+			<13349 13346 13300 13281 13277>,
+			<13344 13341 13299 13280 13277>,
+			<13351 13308 13299 13280 13277>,
+			<13369 13266 13299 13282 13277>,
+			<13391 13259 13298 13282 13277>,
+			<13422 13259 13299 13283 13277>,
+			<13460 13258 13299 13283 13277>,
+			<13503 13258 13298 13283 13277>,
+			<13554 13259 13298 13283 13277>,
+			<13615 13263 13298 13283 13277>,
+			<13690 13285 13299 13283 13278>,
+			<13777 13302 13299 13283 13278>,
+			<13879 13294 13296 13281 13277>,
+			<13996 13281 13292 13279 13276>,
+			<14118 13282 13292 13278 13276>,
+			<14247 13299 13292 13277 13277>,
+			<14377 13319 13293 13277 13277>,
+			<14502 13343 13295 13277 13278>,
+			<14624 13368 13298 13277 13278>,
+			<14737 13402 13303 13278 13276>,
+			<14824 13470 13304 13280 13278>,
+			<14801 13476 13307 13284 13280>,
+			<14824 13517 13316 13291 13286>,
+			<14890 13560 13319 13292 13287>,
+			<14961 13607 13332 13295 13287>,
+			<15021 13665 13332 13292 13286>,
+			<15095 13703 13333 13294 13286>,
+			<15215 13779 13341 13296 13289>,
+			<15382 13934 13350 13299 13292>,
+			<15571 14143 13370 13308 13299>,
+			<15571 14143 13370 13308 13299>,
+			<15571 14143 13370 13308 13299>;
+	};
+
+	qcom,pc-temp-y4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <17305 16798 16610 16483 16470>,
+			<17330 16862 16610 16486 16469>,
+			<17378 16934 16609 16489 16468>,
+			<17433 17001 16608 16491 16467>,
+			<17479 17051 16607 16493 16467>,
+			<17501 17070 16605 16493 16466>,
+			<17503 17059 16603 16493 16466>,
+			<17504 17041 16601 16492 16466>,
+			<17511 17030 16599 16493 16466>,
+			<17550 17023 16599 16497 16470>,
+			<17608 17020 16599 16500 16473>,
+			<17742 17034 16602 16502 16478>,
+			<17902 17062 16609 16506 16483>,
+			<17876 17086 16619 16512 16487>,
+			<17547 17110 16638 16523 16492>,
+			<17320 17134 16659 16535 16498>,
+			<17344 17161 16679 16546 16506>,
+			<17386 17183 16703 16560 16518>,
+			<17370 17170 16748 16586 16537>,
+			<17216 17080 16821 16630 16569>,
+			<17060 16974 16852 16651 16585>,
+			<16974 16865 16754 16602 16552>,
+			<16908 16761 16616 16529 16502>,
+			<16873 16703 16567 16502 16483>,
+			<16851 16662 16543 16489 16473>,
+			<16841 16647 16535 16485 16469>,
+			<16841 16681 16535 16485 16470>,
+			<16842 16727 16535 16487 16471>,
+			<16843 16732 16537 16489 16474>,
+			<16844 16721 16543 16497 16482>,
+			<16845 16716 16549 16507 16491>,
+			<16852 16721 16554 16521 16504>,
+			<16866 16730 16558 16535 16515>,
+			<16879 16732 16556 16540 16518>,
+			<16893 16714 16549 16540 16515>,
+			<16906 16704 16540 16534 16509>,
+			<16920 16735 16528 16505 16492>,
+			<16932 16784 16517 16477 16475>,
+			<16941 16805 16517 16476 16471>,
+			<16947 16815 16522 16479 16469>,
+			<16950 16818 16530 16481 16469>,
+			<16948 16818 16544 16482 16469>,
+			<16945 16817 16555 16481 16467>,
+			<16947 16815 16561 16471 16454>,
+			<16965 16826 16575 16477 16456>,
+			<16961 16849 16584 16493 16477>,
+			<16977 16893 16606 16503 16495>,
+			<17046 16954 16635 16528 16531>,
+			<17107 17025 16679 16557 16532>,
+			<17131 17054 16682 16515 16493>,
+			<17101 17038 16673 16527 16498>,
+			<17060 17051 16712 16548 16514>,
+			<17063 17124 16764 16588 16554>,
+			<17135 17255 16879 16727 16719>,
+			<17135 17255 16879 16727 16719>,
+			<17135 17255 16879 16727 16719>;
+	};
+
+	qcom,pc-temp-y5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <8712 14223 14774 19943 16308>,
+			<8888 14349 15148 18667 15835>,
+			<10562 14526 15365 17009 15457>,
+			<12204 14713 15466 15353 15176>,
+			<13579 14867 15489 14086 14997>,
+			<14452 14948 15472 13593 14920>,
+			<14948 14973 15335 13800 15003>,
+			<15270 14986 15151 14123 15144>,
+			<15028 14986 15098 14118 15087>,
+			<13370 14973 15056 13826 14716>,
+			<12246 14930 14978 13664 14315>,
+			<13353 14287 14743 13788 13961>,
+			<15163 13386 14398 13870 13634>,
+			<15495 13334 14078 13643 13482>,
+			<15197 13853 13740 13191 13549>,
+			<14993 14346 13497 12887 13638>,
+			<15443 14672 13207 12793 13546>,
+			<16191 15006 12923 12796 13423>,
+			<16138 15417 13004 13001 13548>,
+			<14708 15994 13654 13569 14033>,
+			<13284 16419 14434 14193 14440>,
+			<12599 16670 15491 14905 14826>,
+			<12068 16832 16433 15541 15160>,
+			<11544 16827 16644 15650 15196>,
+			<10962 16682 16591 15306 15346>,
+			<10655 16390 16622 15048 15474>,
+			<10648 14341 16597 15293 15494>,
+			<10645 11728 16540 15744 15472>,
+			<10665 11156 16578 15865 15229>,
+			<10802 11032 16695 15749 14663>,
+			<10946 10959 16756 15607 14352>,
+			<11017 10901 16831 15502 14290>,
+			<11076 10865 16959 15400 14311>,
+			<11177 11054 17363 15705 14665>,
+			<11367 12196 18097 16573 15740>,
+			<11520 13011 18310 16919 16424>,
+			<11584 12496 17269 16620 16376>,
+			<11627 11602 15914 16091 16215>,
+			<11630 11486 15213 15448 16327>,
+			<11595 11681 14700 14692 16543>,
+			<11570 11787 14330 14365 16550>,
+			<11579 11797 14105 14243 16259>,
+			<11596 11778 14219 14209 16346>,
+			<11509 11647 14611 15058 16893>,
+			<11331 11779 14198 14882 16382>,
+			<11388 11508 14156 14882 14589>,
+			<11488 11654 14603 16012 16142>,
+			<11493 11662 14001 15040 14960>,
+			<11613 11939 14918 15399 14828>,
+			<11747 12726 15439 17093 17327>,
+			<11665 12655 15981 17753 17255>,
+			<11585 12280 16288 17881 17960>,
+			<11459 12118 16141 17436 18200>,
+			<11818 11932 16090 17352 17825>,
+			<11818 11932 16090 17352 17825>,
+			<11818 11932 16090 17352 17825>;
+	};
+
+	qcom,pc-temp-y6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <6132 5538 5158 5055 5027>,
+			<6176 5550 5158 5053 5026>,
+			<6205 5557 5158 5050 5025>,
+			<6223 5561 5157 5048 5025>,
+			<6232 5562 5156 5046 5025>,
+			<6234 5562 5154 5046 5025>,
+			<6227 5555 5152 5046 5025>,
+			<6211 5540 5150 5047 5026>,
+			<6191 5531 5149 5047 5027>,
+			<6161 5522 5149 5048 5028>,
+			<6144 5519 5149 5049 5029>,
+			<6170 5520 5150 5051 5030>,
+			<6214 5522 5151 5053 5031>,
+			<6207 5523 5154 5055 5033>,
+			<6119 5523 5160 5058 5035>,
+			<6058 5522 5167 5061 5038>,
+			<6060 5524 5172 5065 5041>,
+			<6065 5527 5177 5070 5045>,
+			<6054 5521 5188 5079 5052>,
+			<5986 5487 5208 5095 5064>,
+			<5923 5449 5216 5102 5070>,
+			<5892 5413 5184 5083 5056>,
+			<5871 5381 5138 5056 5035>,
+			<5868 5365 5122 5045 5028>,
+			<5872 5355 5114 5040 5024>,
+			<5878 5349 5111 5038 5023>,
+			<5895 5343 5112 5039 5023>,
+			<5926 5339 5113 5040 5024>,
+			<5960 5339 5115 5042 5026>,
+			<5999 5342 5118 5045 5028>,
+			<6044 5346 5121 5048 5031>,
+			<6096 5354 5124 5053 5034>,
+			<6156 5367 5126 5057 5038>,
+			<6222 5383 5127 5059 5039>,
+			<6297 5405 5127 5060 5039>,
+			<6380 5430 5127 5058 5038>,
+			<6470 5458 5124 5049 5032>,
+			<6568 5491 5120 5041 5027>,
+			<6667 5530 5121 5040 5027>,
+			<6768 5579 5127 5041 5027>,
+			<6867 5632 5133 5042 5028>,
+			<6963 5689 5144 5044 5028>,
+			<7053 5751 5155 5044 5028>,
+			<7135 5817 5167 5043 5024>,
+			<7206 5905 5181 5046 5026>,
+			<7192 5921 5188 5056 5034>,
+			<7214 5976 5205 5063 5044>,
+			<7280 6034 5219 5072 5055>,
+			<7350 6096 5248 5083 5055>,
+			<7405 6155 5252 5069 5043>,
+			<7454 6196 5257 5074 5046>,
+			<7535 6282 5285 5084 5053>,
+			<7666 6442 5320 5100 5069>,
+			<7846 6646 5385 5148 5123>,
+			<7846 6646 5385 5148 5123>,
+			<7846 6646 5385 5148 5123>;
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sda632.dtsi b/arch/arm64/boot/dts/qcom/sda632.dtsi
index 8a71b19..0248630 100644
--- a/arch/arm64/boot/dts/qcom/sda632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda632.dtsi
@@ -22,3 +22,12 @@
 	status = "disabled";
 };
 
+&soc {
+	qcom,rmnet-ipa {
+		status = "disabled";
+	};
+};
+
+&ipa_hw {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..c76ef2b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
@@ -0,0 +1,97 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&cam_sensor_mclk0_active{
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-disable; /* No PULL */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_mclk0_suspend {
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_active {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_suspend {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
+
+&cam_sensor_front_active{
+	/* RESET  AVDD_LDO*/
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_front_suspend{
+	/* RESET */
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
new file mode 100644
index 0000000..51dbe74
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -0,0 +1,552 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+#include "sda845-svr-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-svr.dtsi"
+#include "smb1355.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+&vendor {
+	bluetooth: bt_wcn3990 {
+		compatible = "qca,wcn3990";
+		qca,bt-vdd-io-supply = <&pm8998_s3>;
+		qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+		qca,bt-vdd-core-supply = <&pm8998_l7>;
+		qca,bt-vdd-pa-supply = <&pm8998_l17>;
+		qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+		qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+		qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+		qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+		qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+		qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+		qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+	};
+
+	svr_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-demo-3600mah.dtsi"
+	};
+};
+
+&pmi8998_pdphy {
+	vbus-supply = <&smb2_vbus>;
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&pmi8998_fg {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,fg-bmd-en-delay-ms = <300>;
+};
+
+&pmi8998_charger {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,sw-jeita-enable;
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&smb1355_charger_0 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&smb1355_charger_1 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&soc {
+	qcom,qbt1000 {
+		status = "disabled";
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_vol_up_default
+				&key_home_default
+				&key_cam_focus_default>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		home {
+			label = "home"; /* BACK Key*/
+			gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <158>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+		key_cam_focus {
+			label = "Confirm"; /* Confirm Key*/
+			gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+
+	dsi_panel_pwr_supply_amoled: dsi_panel_pwr_supply_amoled {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1880000>;
+			qcom,supply-max-voltage = <1880000>;
+			qcom,supply-enable-load = <62000>;
+			qcom,supply-disable-load = <80>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "lab";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@2 {
+			reg = <2>;
+			qcom,supply-name = "ibb";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+		qcom,panel-supply-entry@3 {
+			reg = <3>;
+			qcom,supply-name = "oled-vdda";
+			qcom,supply-min-voltage = <3312000>;
+			qcom,supply-max-voltage = <3312000>;
+			qcom,supply-enable-load = <857000>;
+			qcom,supply-disable-load = <0>;
+			qcom,supply-post-on-sleep = <0>;
+		};
+	};
+};
+
+&sde_rscc {
+	status = "disabled";
+};
+
+&mdss_dsi0 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&mdss_dsi1 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&pmi8998_wled {
+	status = "ok";
+	qcom,disp-type-amoled;
+	qcom,avdd-target-voltage-mv = <7600>;
+};
+
+&labibb {
+	status = "ok";
+	qcom,qpnp-labibb-mode = "amoled";
+	qcom,swire-control;
+};
+
+&ibb_regulator {
+	status = "ok";
+	qcom,qpnp-ibb-init-amoled-voltage = <4600000>;
+	qcom,qpnp-ibb-discharge-resistor = <300>;
+};
+
+&lab_regulator {
+	status = "ok";
+	qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+};
+
+&mdss_mdp {
+	connectors = <&sde_wb &sde_dp>;
+};
+
+&dsi_dual_test_cmd {
+	qcom,mdss-dsi-t-clk-post = <0x0e>;
+	qcom,mdss-dsi-t-clk-pre = <0x35>;
+	qcom,mdss-dsi-display-timings {
+		timing@0{
+			qcom,mdss-dsi-panel-phy-timings =
+				[00 24 09 09 26 24 09 09 06 03 04 00];
+			qcom,display-topology = <2 0 2>,
+						<2 0 2>;
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
+
+&dsi_dual_test_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply_amoled>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <255>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_dual_test_cmd_display {
+	qcom,dsi-display-active;
+};
+
+&snd_934x {
+	qcom,msm-mbhc-hphl-swh = <0>;
+};
+
+&pmi8998_haptics {
+	qcom,vmax-mv = <2400>;
+	qcom,lra-auto-mode;
+	status = "okay";
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8998_l21>;
+	qcom,vdd-voltage-level = <2950000 2960000>;
+	qcom,vdd-current-level = <200 800000>;
+
+	vdd-io-supply = <&pm8998_l13>;
+	qcom,vdd-io-voltage-level = <1808000 2960000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep", "ds_400KHz",
+			"ds_50MHz", "ds_100MHz", "ds_200MHz";
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on &storage_cd>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>;
+	pinctrl-2 = <&sdc2_clk_ds_400KHz
+			&sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>;
+	pinctrl-3 = <&sdc2_clk_ds_50MHz
+			&sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>;
+	pinctrl-4 = <&sdc2_clk_ds_100MHz
+			&sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>;
+	pinctrl-5 = <&sdc2_clk_ds_200MHz
+			&sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>;
+
+	cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+
+	status = "ok";
+};
+
+&pmi8998_switch1 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_switch2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_iris_en>;
+	pinctrl-1 = <&flash_led3_iris_dis>;
+};
+
+&vendor {
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		vbus-gpio = <&pmi8998_gpios 8 GPIO_ACTIVE_HIGH>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_vbus_det_default>;
+	};
+};
+
+&adsp_mem {
+	size = <0 0xc800000>;
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&qupv3_se8_spi {
+	status = "ok";
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&usb1 {
+	status = "okay";
+	extcon = <&extcon_usb1>;
+};
+
+&qusb_phy1 {
+	status = "okay";
+};
+
+&ext_5v_boost {
+	status = "ok";
+};
+
+&usb_qmp_phy {
+	status = "okay";
+};
+
+&pm8998_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@85 {
+		label = "vcoin";
+		reg = <0x85>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm8998_adc_tm {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,btm-channel-number = <0x60>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x70>;
+		qcom,thermal-node;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x78>;
+		qcom,thermal-node;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x80>;
+		qcom,thermal-node;
+	};
+};
+
+&thermal_zones {
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	msm-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4d>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm1-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4f>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	quiet-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x51>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
new file mode 100644
index 0000000..1c6db6f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
@@ -0,0 +1,31 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
new file mode 100644
index 0000000..1d7bf7d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
@@ -0,0 +1,25 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
new file mode 100644
index 0000000..b4326a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
@@ -0,0 +1,32 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2.1 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20001>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp.dts
new file mode 100644
index 0000000..f3312bd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm429.dtsi"
+#include "sdm429-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM429 CDP";
+	compatible = "qcom,sdm429-cdp", "qcom,sdm429", "qcom,cdp";
+	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi
new file mode 100644
index 0000000..4ba4c00
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm439-cdp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi
new file mode 100644
index 0000000..9960c47
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/ {
+	/delete-node/ cpus;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu-map {
+
+			cluster0 {
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		CPU0: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x100>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      /* A53 L2 dump not supported */
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_100: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_100: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU1: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x101>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_101: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_101: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU2: cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x102>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_102: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_102: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU3: cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x103>;
+			enable-method = "psci";
+			cpu-release-addr = <0x0 0x90000000>;
+			next-level-cache = <&L2_1>;
+			L1_I_103: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_103: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp.dts
new file mode 100644
index 0000000..a809be7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm429.dtsi"
+#include "sdm429-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM429 MTP";
+	compatible = "qcom,sdm429-mtp", "qcom,sdm429", "qcom,mtp";
+	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi
new file mode 100644
index 0000000..839fa56
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm439-mtp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd.dts
new file mode 100644
index 0000000..d97cf54
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm429.dtsi"
+#include "sdm429-qrd.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM429 QRD";
+	compatible = "qcom,sdm429-qrd", "qcom,sdm429", "qcom,qrd";
+	qcom,board-id = <0xb 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
new file mode 100644
index 0000000..7116662
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm439-qrd.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi
new file mode 100644
index 0000000..88cf1da
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include "sdm439.dtsi"
+#include "sdm429-cpu.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM429";
+	compatible = "qcom,sdm429";
+	qcom,msm-id = <354 0x0>;
+};
+
+&soc {
+	/delete-node/ qcom,spm@b1d2000;
+	/delete-node/ qcom,lpm-levels;
+	/delete-node/ etm@619c000;
+	/delete-node/ etm@619d000;
+	/delete-node/ etm@619e000;
+	/delete-node/ etm@619f000;
+	/delete-node/ cti@61b8000;
+	/delete-node/ cti@61b9000;
+	/delete-node/ cti@61ba000;
+	/delete-node/ cti@61bb000;
+};
+
+&funnel_apss {
+	ports {
+		/delete-node/ port@1;
+		/delete-node/ port@2;
+		/delete-node/ port@3;
+		/delete-node/ port@4;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
new file mode 100644
index 0000000..fae43ba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	int_codec: sound {
+		qcom,msm-hs-micbias-type = "internal";
+
+		asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+				<&pmic_analog_codec>;
+		asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+					"analog-codec";
+		msm-vdd-wsa-switch-supply = <&pm8953_l5>;
+		qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+		qcom,msm-vdd-wsa-switch-current = <10000>;
+	};
+};
+
+&pm8953_1 {
+	pmic_analog_codec: analog-codec@f000 {
+		status = "okay";
+		compatible = "qcom,pmic-analog-codec";
+		reg = <0xf000 0x200>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+		interrupt-parent = <&spmi_bus>;
+		interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+			<0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+			<0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+		interrupt-names = "spk_cnp_int",
+				"spk_clip_int",
+				"spk_ocp_int",
+				"ins_rem_det1",
+				"but_rel_det",
+				"but_press_det",
+				"ins_rem_det",
+				"mbhc_int",
+				"ear_ocp_int",
+				"hphr_ocp_int",
+				"hphl_ocp_det",
+				"ear_cnp_int",
+				"hphr_cnp_int",
+				"hphl_cnp_int";
+
+		cdc-vdda-cp-supply = <&pm8953_s4>;
+		qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+		qcom,cdc-vdda-cp-current = <500000>;
+
+		cdc-vdd-io-supply = <&pm8953_l5>;
+		qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-io-current = <5000>;
+
+		cdc-vdd-pa-supply = <&pm8953_s4>;
+		qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+		qcom,cdc-vdd-pa-current = <260000>;
+
+		cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+		qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+		qcom,cdc-vdd-mic-bias-current = <5000>;
+
+		qcom,cdc-mclk-clk-rate = <9600000>;
+
+		qcom,cdc-static-supplies = "cdc-vdd-io",
+					"cdc-vdd-pa",
+					"cdc-vdda-cp";
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+		msm_digital_codec: msm-dig-codec {
+			compatible = "qcom,msm-digital-codec";
+			reg = <0xc0f0000 0x0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp.dts
new file mode 100644
index 0000000..1306230
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm439.dtsi"
+#include "sdm439-cdp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM439 CDP";
+	compatible = "qcom,sdm439-cdp", "qcom,sdm439", "qcom,cdp";
+	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp.dts
new file mode 100644
index 0000000..9f221f0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM439 MTP";
+	compatible = "qcom,sdm439-mtp", "qcom,sdm439", "qcom,mtp";
+	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi
new file mode 100644
index 0000000..48938a5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&rpm_bus {
+	/* Deleting all pm8937 regulators */
+	/delete-node/ rpm-regulator-smpa1;
+	/delete-node/ rpm-regulator-smpa2;
+	/delete-node/ rpm-regulator-smpa3;
+	/delete-node/ rpm-regulator-smpa4;
+	/delete-node/ rpm-regulator-ldoa2;
+	/delete-node/ rpm-regulator-ldoa3;
+	/delete-node/ rpm-regulator-ldoa5;
+	/delete-node/ rpm-regulator-ldoa6;
+	/delete-node/ rpm-regulator-ldoa7;
+	/delete-node/ rpm-regulator-ldoa8;
+	/delete-node/ rpm-regulator-ldoa9;
+	/delete-node/ rpm-regulator-ldoa10;
+	/delete-node/ rpm-regulator-ldoa11;
+	/delete-node/ rpm-regulator-ldoa12;
+	/delete-node/ rpm-regulator-ldoa13;
+	/delete-node/ rpm-regulator-ldoa14;
+	/delete-node/ rpm-regulator-ldoa15;
+	/delete-node/ rpm-regulator-ldoa16;
+	/delete-node/ rpm-regulator-ldoa17;
+	/delete-node/ rpm-regulator-ldoa19;
+	/delete-node/ rpm-regulator-ldoa22;
+	/delete-node/ rpm-regulator-ldoa23;
+};
+
+&spmi_bus {
+	/delete-node/ qcom,pm8937@0;
+	/delete-node/ qcom,pm8937@1;
+};
+
+&thermal_zones {
+	/delete-node/ pa-therm1-adc;
+	/delete-node/ xo-therm-adc;
+	/delete-node/ xo-therm-buf-adc;
+	/delete-node/ case-therm-adc;
+	/delete-node/ pa-therm0-adc;
+};
+
+&int_codec {
+	asoc-codec = <&stub_codec>;
+	asoc-codec-names = "msm-stub-codec.1";
+	/delete-property/ msm-vdd-wsa-switch-supply;
+};
+
+&clock_audio {
+	/delete-property/ qcom,audio-ref-clk-gpio;
+};
+
+&wcd9335 {
+	/delete-property/ cdc-vdd-buck-supply;
+	/delete-property/ cdc-buck-sido-supply;
+	/delete-property/ cdc-vdd-tx-h-supply;
+	/delete-property/ cdc-vdd-rx-h-supply;
+	/delete-property/ cdc-vdd-px-supply;
+	/delete-property/ cdc-vdd-mic-bias-supply;
+};
+
+&soc {
+	/delete-node/ regulator@01946004;
+	/delete-node/ regulator@b018000;
+	/delete-node/ eldo2;
+	/delete-node/ adv_vreg;
+
+	qcom,gcc@1800000 {
+		/delete-property/ vdd_dig-supply;
+		/delete-property/ vdd_sr2_dig-supply;
+		/delete-property/ vdd_sr2_pll-supply;
+		/delete-property/ vdd_hf_dig-supply;
+		/delete-property/ vdd_hf_pll-supply;
+	};
+
+	qcom,cpu-clock-8939@b111050 {
+		/delete-property/ vdd-c0-supply;
+		/delete-property/ vdd-c1-supply;
+		/delete-property/ vdd-cci-supply;
+	};
+
+	usb@78db000 {
+		/delete-property/ hsusb_vdd_dig-supply;
+		/delete-property/ HSUSB_1p8-supply;
+		/delete-property/ HSUSB_3p3-supply;
+	};
+
+	qcom,lpass@c200000 {
+		/delete-property/ vdd_cx-supply;
+	};
+
+	qcom,pronto@a21b000 {
+		/delete-property/ vdd_pronto_pll-supply;
+	};
+
+	qcom,wcnss-wlan@0a000000 {
+		/delete-property/ qcom,pronto-vddmx-supply;
+		/delete-property/ qcom,pronto-vddcx-supply;
+		/delete-property/ qcom,pronto-vddpx-supply;
+		/delete-property/ qcom,iris-vddxo-supply;
+		/delete-property/ qcom,iris-vddrfa-supply;
+		/delete-property/ qcom,iris-vddpa-supply;
+		/delete-property/ qcom,iris-vdddig-supply;
+		/delete-property/ qcom,wcnss-adc_tm;
+	};
+};
+
+&pil_mss {
+	/delete-property/ vdd_mss-supply;
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_cx-voltage;
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_mx-uV;
+	/delete-property/ vdd_pll-supply;
+};
+
+&mdss_dsi {
+	/delete-property/ vdda-supply;
+	/delete-property/ vddio-supply;
+};
+
+&usb_otg {
+	/delete-property/ hsusb_vdd_dig-supply;
+	/delete-property/ HSUSB_1p8-supply;
+	/delete-property/ HSUSB_3p3-supply;
+};
+
+&mdss_dsi0_pll {
+	/delete-property/ vddio-supply;
+};
+
+&mdss_dsi1_pll {
+	/delete-property/ vddio-supply;
+};
+
+&mdss_dsi0 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vddio-supply;
+};
+
+&mdss_dsi1 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vddio-supply;
+};
+
+&int_codec {
+	/delete-property/ asoc-codec;
+	/delete-property/ msm-vdd-wsa-switch-supply;
+};
+
+&clock_audio {
+	/delete-property/ qcom,audio-ref-clk-gpio;
+};
+
+&wcd9335 {
+	/delete-property/ cdc-vdd-buck-supply;
+	/delete-property/ cdc-buck-sido-supply;
+	/delete-property/ cdc-vdd-tx-h-supply;
+	/delete-property/ cdc-vdd-rx-h-supply;
+	/delete-property/ cdc-vdd-px-supply;
+	/delete-property/ cdc-vdd-mic-bias-supply;
+};
+
+#include "pm8953.dtsi"
+#include "pm8953-rpm-regulator.dtsi"
+#include "sdm439-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
new file mode 100644
index 0000000..ad2b0fe
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "pmi632.dtsi"
+
+&pmi632_charger {
+	dpdm-supply = <&usb_otg>;
+};
+
+&usb_otg {
+	vbus_otg-supply = <&smb5_vbus>;
+};
+
+&pmi632_pon {
+	qcom,ps-hold-hard-reset-disable;
+	qcom,ps-hold-shutdown-disable;
+};
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "qg-batterydata-ascent-3450mah.dtsi"
+		#include "qg-batterydata-mlp356477-2800mah.dtsi"
+	};
+};
+
+&pmi632_qg {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,rbat-conn-mohm = <20>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts
new file mode 100644
index 0000000..7b93e0c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm439.dtsi"
+#include "sdm439-qrd.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM439 QRD";
+	compatible = "qcom,sdm439-qrd", "qcom,sdm439", "qcom,qrd";
+	qcom,board-id = <0xb 0>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
new file mode 100644
index 0000000..5512297
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&blsp1_uart2 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8953_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8953_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
new file mode 100644
index 0000000..27307d8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&rpm_bus {
+	/* PM8953 regulators */
+	rpm-regulator-smpa1 {
+		status = "okay";
+		pm8953_s1: regulator-s1 {
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+			status = "okay";
+		};
+	};
+
+	/* PM8953 S2 - VDD_CX supply */
+	rpm-regulator-smpa2 {
+		status = "okay";
+		pm8953_s2_level: regulator-s2-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+		};
+
+		pm8953_s2_floor_level: regulator-s2-floor-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_floor_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-floor-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s2_level_ao: regulator-s2-level-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_level_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		status = "okay";
+		pm8953_s3: regulator-s3 {
+			regulator-min-microvolt = <1280000>;
+			regulator-max-microvolt = <1280000>;
+			qcom,init-voltage = <1280000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		status = "okay";
+		pm8953_s4: regulator-s4 {
+			regulator-min-microvolt = <2040000>;
+			regulator-max-microvolt = <2040000>;
+			qcom,init-voltage = <2040000>;
+			status = "okay";
+		};
+	};
+
+	/* VDD_MX supply */
+	rpm-regulator-smpa7 {
+		status = "okay";
+		pm8953_s7_level: regulator-s7-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,init-voltage-level =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			qcom,use-voltage-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s7_level_ao: regulator-s7-level-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s7_level_so: regulator-s7-level-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level_so";
+			qcom,set = <2>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,init-voltage-level =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			qcom,use-voltage-level;
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		status = "okay";
+		pm8953_l1: regulator-l1 {
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			qcom,init-voltage = <1000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		status = "okay";
+		pm8953_l2: regulator-l2 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		status = "okay";
+		pm8953_l3: regulator-l3 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "okay";
+		pm8953_l4: regulator-l4 {
+			compatible = "qcom,rpm-smd-regulator-resource";
+			regulator-name = "pm8953_l4";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		status = "okay";
+		pm8953_l5: regulator-l5 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		status = "okay";
+		pm8953_l6: regulator-l6 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		status = "okay";
+		pm8953_l7: regulator-l7 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+
+		pm8953_l7_ao: regulator-l7-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l7_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		status = "okay";
+		pm8953_l8: regulator-l8 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,init-voltage = <2900000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		status = "okay";
+		pm8953_l9: regulator-l9 {
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3300000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		status = "okay";
+		pm8953_l10: regulator-l10 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,init-voltage = <3000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		status = "okay";
+		pm8953_l11: regulator-l11 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <2950000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		status = "okay";
+		pm8953_l12: regulator-l12 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		status = "okay";
+		pm8953_l13: regulator-l13 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3075000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "okay";
+		pm8953_l14: regulator-l14 {
+			compatible = "qcom,rpm-smd-regulator-resource";
+			regulator-name = "pm8953_l14";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <15>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "okay";
+		pm8953_l15: regulator-l15 {
+			compatible = "qcom,rpm-smd-regulator-resource";
+			regulator-name = "pm8953_l15";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		status = "okay";
+		pm8953_l16: regulator-l16 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		status = "okay";
+		pm8953_l17: regulator-l17 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,init-voltage = <2850000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		status = "okay";
+		pm8953_l19: regulator-l19 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1350000>;
+			qcom,init-voltage = <1300000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		status = "okay";
+		pm8953_l22: regulator-l22 {
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			qcom,init-voltage = <2800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa23 {
+		status = "okay";
+		pm8953_l23: regulator-l23 {
+			regulator-min-microvolt = <800000>;
+			regulator-max-microvolt = <800000>;
+			qcom,init-voltage = <800000>;
+			status = "okay";
+		};
+	};
+};
+
+&spmi_bus {
+	qcom,pm8953@1 {
+		/* PM8953 S5 + S6 = VDD_APC_supply */
+		pm8953_s5: spm-regulator@2000 {
+			compatible = "qcom,spm-regulator";
+			reg = <0x2000 0x100>;
+			regulator-name = "pm8953_s5";
+			regulator-min-microvolt = <490000>;
+			regulator-max-microvolt = <910000>;
+
+			pm8953_s5_limit: avs-limit-regulator {
+				regulator-name = "pm8953_s5_avs_limit";
+				regulator-min-microvolt = <490000>;
+				regulator-max-microvolt = <910000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi
new file mode 100644
index 0000000..b176858
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8937.dtsi"
+#include "sdm439-pm8953.dtsi"
+#include "sdm439-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM439";
+	compatible = "qcom,sdm439";
+	qcom,msm-id = <353 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
new file mode 100644
index 0000000..e12ad51
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "sdm450-pmi632-cdp-s2.dtsi"
+
+/ {
+	model = "CDP S2";
+	compatible = "qcom,cdp";
+	qcom,board-id = <1 2>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
index c55622a..0458650 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-cdp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
new file mode 100644
index 0000000..ae522a5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "sdm450-pmi632-mtp-s3.dtsi"
+
+/ {
+	model = "MTP S3";
+	compatible = "qcom,mtp";
+	qcom,board-id = <8 3>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 040b4ba..f097895 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-mtp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 MTP";
@@ -24,3 +25,21 @@
 	qcom,board-id = <8 0>;
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
index 68f02a8..004186b6be 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts
@@ -16,6 +16,7 @@
 #include "sdm450.dtsi"
 #include "sdm450-pmi632-cdp-s2.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 CDP S2";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
index 220ec20..d8a0e9d 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi
@@ -13,3 +13,27 @@
 
 #include "msm8953-cdp.dtsi"
 
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active &bklt_en_default>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
index b9aadc1..1a2309f 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
@@ -16,6 +16,7 @@
 #include "sdm450.dtsi"
 #include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm632-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
index adb7f47..129d507 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
@@ -13,3 +13,28 @@
 
 #include "msm8953-mtp.dtsi"
 
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active &bklt_en_default>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+
+};
+
+&dsi_truly_1080_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dts
new file mode 100644
index 0000000..4f6e7f5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom,pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
index 413612d..d29d6fa 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
@@ -26,3 +26,140 @@
 	qcom,ps-hold-hard-reset-disable;
 	qcom,ps-hold-shutdown-disable;
 };
+
+&usb3 {
+	extcon = <&pmi632_charger>, <&pmi632_charger>, <0>,
+		 <&pmi632_charger>, <&pmi632_charger>;
+	vbus_dwc3-supply = <&smb5_vbus>;
+};
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "qg-batterydata-ascent-3450mah.dtsi"
+		#include "qg-batterydata-mlp356477-2800mah.dtsi"
+	};
+};
+
+&pmi632_qg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pm8953_gpios {
+	bklt_en {
+		bklt_en_default: bklt_en_default {
+		pins = "gpio4";
+		function = "normal";
+		power-source = <0>;
+		output-high;
+		};
+	};
+};
+
+&pm8953_pwm {
+	status = "ok";
+};
+
+&thermal_zones {
+	pmi-vbat-lvl0 {
+		cooling-maps {
+			vbat_map4 {
+				trip = <&pmi632_vbat_lvl0>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			vbat_map5 {
+				trip = <&pmi632_vbat_lvl0>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			vbat_map6 {
+				trip = <&pmi632_vbat_lvl0>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			vbat_map7 {
+				trip = <&pmi632_vbat_lvl0>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	soc {
+		cooling-maps {
+			soc_map4 {
+				trip = <&pmi632_low_soc>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			soc_map5 {
+				trip = <&pmi632_low_soc>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			soc_map6 {
+				trip = <&pmi632_low_soc>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			soc_map7 {
+				trip = <&pmi632_low_soc>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	case-therm-step {
+		trips {
+			batt_trip1: batt-trip1 {
+				temperature = <38000>;
+				hysteresis = <3000>;
+				type = "passive";
+			};
+			batt_trip2: batt-trip2 {
+				temperature = <40000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			batt_trip3: batt-trip3 {
+				temperature = <43000>;
+				hysteresis = <3000>;
+				type = "passive";
+			};
+			batt_trip4: batt-trip4 {
+				temperature = <48000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			battery_lvl1 {
+				trip = <&batt_trip1>;
+				cooling-device = <&pmi632_charger 2 2>;
+			};
+			battery_lvl2 {
+				trip = <&batt_trip2>;
+				cooling-device = <&pmi632_charger 3 3>;
+			};
+			battery_lvl3 {
+				trip = <&batt_trip3>;
+				cooling-device = <&pmi632_charger 4 4>;
+			};
+			battery_lvl4 {
+				trip = <&batt_trip4>;
+				cooling-device = <&pmi632_charger 5 5>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
index 700e950..eb6a692 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
index f50d177..cfdd4e9 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
new file mode 100644
index 0000000..558c3c6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "sdm450-qrd-sku4.dtsi"
+
+/ {
+	model = "QRD SKU4";
+	compatible = "qcom,qrd";
+	qcom,board-id = <0xb 1>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
index 977a978..1dc8874 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts
@@ -16,6 +16,7 @@
 #include "sdm450.dtsi"
 #include "sdm450-qrd-sku4.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "msm8953-camera-sensor-qrd.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 QRD SKU4";
@@ -24,3 +25,8 @@
 	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
 };
 
+&pmi632_vadc {
+	chan@4a {
+		qcom,scale-function = <22>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 0a98528..4a63f9e 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -12,8 +12,140 @@
  */
 
 #include "msm8953-qrd.dtsi"
+#include "msm8953-mdss-panels.dtsi"
+
+&qusb_phy {
+	qcom,qusb-phy-init-seq = <0x78 0x80
+				0xb3 0x84
+				0x83 0x88
+				0xc7 0x8c
+				0x14 0x9c
+				0x30 0x08
+				0x79 0x0c
+				0x21 0x10
+				0x00 0x90
+				0x9f 0x1c
+				0x00 0x18>;
+};
 
 &i2c_3 {
 	status = "disabled";
 };
 
+&int_codec {
+	status = "okay";
+	qcom,model = "msm8953-sku4-snd-card";
+	qcom,msm-micbias1-ext-cap;
+	qcom,msm-micbias2-ext-cap;
+	qcom,msm-mbhc-hphl-swh = <1>;
+	qcom,msm-mbhc-gnd-swh = <0>;
+	qcom,msm-hs-micbias-type = "external";
+};
+
+&wsa881x_i2c_f {
+	status = "okay";
+};
+
+&wsa881x_i2c_45 {
+	status = "okay";
+};
+
+&tlmm {
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+	};
+};
+
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+		qcom,supply-post-on-sleep = <10>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+	/delete-property/ vdd-supply;
+
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 85 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+};
+
+&sdhc_2 {
+	cd-gpios = <&tlmm 133 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-rcm.dts b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
index 1b7831b..68a7ca2 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts
@@ -17,6 +17,7 @@
 #include "pmi8950.dtsi"
 #include "msm8953-cdp.dtsi"
 #include "msm8953-pmi8950.dtsi"
+#include "msm8953-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 RCM";
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
index b829b81..6cdf897 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
index 3e24714..38eacd1 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi
@@ -48,3 +48,86 @@
 		< 560000000   6 >,  /* Nom Plus  */
 		< 600000000   7 >;  /* Turbo     */
 };
+
+/* GPU Overrides*/
+&msm_gpu {
+
+	/delete-node/qcom,gpu-pwrlevels;
+
+	qcom,gpu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gpu-pwrlevels";
+
+		/* TURBO */
+		qcom,gpu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gpu-freq = <600000000>;
+			qcom,bus-freq = <10>;
+			qcom,bus-min = <10>;
+			qcom,bus-max = <10>;
+		};
+
+		/* NOM+ */
+		qcom,gpu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gpu-freq = <560000000>;
+			qcom,bus-freq = <10>;
+			qcom,bus-min = <8>;
+			qcom,bus-max = <10>;
+		};
+
+		/* NOM */
+		qcom,gpu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gpu-freq = <510000000>;
+			qcom,bus-freq = <9>;
+			qcom,bus-min = <6>;
+			qcom,bus-max = <10>;
+		};
+
+		/* SVS+ */
+		qcom,gpu-pwrlevel@3 {
+			reg = <3>;
+			qcom,gpu-freq = <400000000>;
+			qcom,bus-freq = <7>;
+			qcom,bus-min = <5>;
+			qcom,bus-max = <8>;
+		};
+
+		/* SVS */
+		qcom,gpu-pwrlevel@4 {
+			reg = <4>;
+			qcom,gpu-freq = <320000000>;
+			qcom,bus-freq = <4>;
+			qcom,bus-min = <2>;
+			qcom,bus-max = <6>;
+		};
+
+		/* Low SVS */
+		qcom,gpu-pwrlevel@5 {
+			reg = <5>;
+			qcom,gpu-freq = <216000000>;
+			qcom,bus-freq = <1>;
+			qcom,bus-min = <1>;
+			qcom,bus-max = <4>;
+		};
+
+		/* Min SVS */
+		qcom,gpu-pwrlevel@6 {
+			reg = <6>;
+			qcom,gpu-freq = <133300000>;
+			qcom,bus-freq = <1>;
+			qcom,bus-min = <1>;
+			qcom,bus-max = <4>;
+		};
+		/* XO */
+		qcom,gpu-pwrlevel@7 {
+			reg = <7>;
+			qcom,gpu-freq = <19200000>;
+			qcom,bus-freq = <0>;
+			qcom,bus-min = <0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..e9295ad
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-cdp.dtsi
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	actuator1: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <1>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom1: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		qcom,eeprom-name = "sunny_8865";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <8>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0x0 1 0>;
+		qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page1 = <1 0x5002 2 0x00 1 0>;
+		qcom,poll1 = <0 0x0 2 0x0 1 0>;
+		qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+		qcom,poll2 = <0 0x0 2 0x0 1 0>;
+		qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+		qcom,poll3 = <0 0x0 2 0x0 1 0>;
+		qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+		qcom,poll4 = <0 0x0 2 0x0 1 0>;
+		qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+		qcom,poll5 = <0 0x0 2 0x0 1 0>;
+		qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+		qcom,poll6 = <0 0x0 2 0x0 1 0>;
+		qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0x0 1 1>;
+		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+			"sensor_vreg",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+			"sensor_gpio_reset", "sensor_gpio_standby",
+			"sensor_cam_mclk";
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom2: qcom,eeprom@2 {
+		cell-index = <2>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <1>;
+		reg = <0x2>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom2>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <0x100>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..07b3811
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-camera-sensor-mtp.dtsi
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	actuator1: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <1>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vaf";
+		qcom,cam-vreg-min-voltage = <2850000>;
+		qcom,cam-vreg-max-voltage = <2850000>;
+		qcom,cam-vreg-op-mode = <80000>;
+	};
+
+	eeprom0: qcom,eeprom@0 {
+		cell-index = <0>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <0>;
+		reg = <0x0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom1: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		qcom,eeprom-name = "sunny_8865";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <8>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0x0 1 0>;
+		qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page1 = <1 0x5002 2 0x00 1 0>;
+		qcom,poll1 = <0 0x0 2 0x0 1 0>;
+		qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+		qcom,poll2 = <0 0x0 2 0x0 1 0>;
+		qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+		qcom,poll3 = <0 0x0 2 0x0 1 0>;
+		qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+		qcom,poll4 = <0 0x0 2 0x0 1 0>;
+		qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+		qcom,poll5 = <0 0x0 2 0x0 1 0>;
+		qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+		qcom,poll6 = <0 0x0 2 0x0 1 0>;
+		qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+		qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0x0 1 1>;
+		qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+			&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+			"sensor_vreg",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+			"sensor_gpio_reset", "sensor_gpio_standby",
+			"sensor_cam_mclk";
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	eeprom2: qcom,eeprom@2 {
+		cell-index = <2>;
+		compatible = "qcom,eeprom";
+		qcom,cci-master = <1>;
+		reg = <0x2>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <19200000 0>;
+	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vaf-supply = <&pm8953_l17>;
+		cam_vana-supply = <&pm8953_l22>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf",
+						"cam_vana";
+		qcom,cam-vreg-min-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <0 1100000 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <0 105000 100000 80000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_default
+				&cam_sensor_rear_default
+				&cam_sensor_rear_vana>;
+		pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+				&cam_sensor_rear_vana_sleep>;
+		gpios = <&tlmm 26 0>,
+			<&tlmm 40 0>,
+			<&tlmm 39 0>,
+			<&tlmm 134 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vana = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VANA";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk0_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk0_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom2>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_default
+				&cam_sensor_front_default>;
+		pinctrl-1 = <&cam_sensor_mclk2_sleep
+				&cam_sensor_front_sleep>;
+		gpios = <&tlmm 28 0>,
+			<&tlmm 131 0>,
+			<&tlmm 132 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+			"CAM_RESET1",
+			"CAM_STANDBY1";
+		qcom,sensor-position = <0x100>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk2_clk_src>,
+				<&clock_gcc clk_gcc_camss_mclk2_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,actuator-src = <&actuator1>;
+		cam_vdig-supply = <&pm8953_l23>;
+		cam_vio-supply = <&pm8953_l6>;
+		cam_vana-supply = <&pm8953_l22>;
+		cam_vaf-supply = <&pm8953_l17>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+					"cam_vaf";
+		qcom,cam-vreg-min-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1175000 0 2800000 2850000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_default
+				&cam_sensor_front1_default>;
+		pinctrl-1 = <&cam_sensor_mclk1_sleep
+				&cam_sensor_front1_sleep>;
+		gpios = <&tlmm 27 0>,
+			<&tlmm 129 0>,
+			<&tlmm 130 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_gcc clk_mclk1_clk_src>,
+			<&clock_gcc clk_gcc_camss_mclk1_clk>;
+		clock-names = "cam_src_clk", "cam_clk";
+		qcom,clock-rates = <24000000 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
new file mode 100644
index 0000000..a544d59
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-pmi632-cdp-s2.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 CDP S2";
+	compatible = "qcom,sdm632-cdp", "qcom,sdm632", "qcom,cdp";
+	qcom,board-id = <1 2>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
+
+&soc {
+	gpio_keys {
+		/delete-node/home;
+	};
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
index 031fd7e..c53bb56 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -58,6 +58,7 @@
 			efficiency = <1024>;
 			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
+			#cooling-cells = <2>;
 			L2_0: l2-cache {
 			      compatible = "arm,arch-cache";
 			      cache-level = <2>;
@@ -85,6 +86,7 @@
 			efficiency = <1024>;
 			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
+			#cooling-cells = <2>;
 			L1_I_1: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x9040>;
@@ -106,6 +108,7 @@
 			efficiency = <1024>;
 			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
+			#cooling-cells = <2>;
 			L1_I_2: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x9040>;
@@ -127,6 +130,7 @@
 			efficiency = <1024>;
 			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
+			#cooling-cells = <2>;
 			L1_I_3: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x9040>;
@@ -146,8 +150,9 @@
 			enable-method = "psci";
 			reg = <0x0 0x100>;
 			efficiency = <1638>;
-			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
+			#cooling-cells = <2>;
 			L2_1: l2-cache {
 			      compatible = "arm,arch-cache";
 			      cache-level = <2>;
@@ -171,8 +176,9 @@
 			enable-method = "psci";
 			reg = <0x0 0x101>;
 			efficiency = <1638>;
-			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
+			#cooling-cells = <2>;
 			L1_I_101: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x12000>;
@@ -192,8 +198,9 @@
 			enable-method = "psci";
 			reg = <0x0 0x102>;
 			efficiency = <1638>;
-			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
+			#cooling-cells = <2>;
 			L1_I_102: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x12000>;
@@ -213,8 +220,9 @@
 			enable-method = "psci";
 			reg = <0x0 0x103>;
 			efficiency = <1638>;
-			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
+			#cooling-cells = <2>;
 			L1_I_103: l1-icache {
 			      compatible = "arm,arch-cache";
 			      qcom,dump-size = <0x12000>;
@@ -228,6 +236,69 @@
 			};
 		};
 	};
+
+	energy_costs: energy-costs {
+		compatible = "sched-energy";
+
+		CPU_COST_0: core-cost0 {
+			busy-cost-data = <
+				614400	23
+				883200	41
+				1036800	56
+				1363200	88
+				1536000	112
+				1670400	151
+				1785600	192
+			>;
+			idle-cost-data = <
+				20 16 12 8
+			>;
+		};
+		CPU_COST_1: core-cost1 {
+			busy-cost-data = <
+				633600	722
+				902400	1287
+				1036800	1739
+				1401600	2819
+				1555200	3532
+				1785600	4985
+				1996000	6624
+				2082800	6905
+			>;
+			idle-cost-data = <
+				100 80 60 40
+			>;
+		};
+		CLUSTER_COST_0: cluster-cost0 {
+			busy-cost-data = <
+				614400	8
+				883200	14
+				1036800	18
+				1363200	28
+				1536000	35
+				1670400	43
+				1785600	54
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+		CLUSTER_COST_1: cluster-cost1 {
+			busy-cost-data = <
+				633600	68
+				902400	103
+				1036800	132
+				1401600	193
+				1555200	233
+				1785600	289
+				1996000	374
+				2082800	386
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+	};
 };
 
 &cpuss_dump {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
new file mode 100644
index 0000000..6339c3c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 MTP S3";
+	compatible = "qcom,sdm632-mtp", "qcom,sdm632", "qcom,mtp";
+	qcom,board-id = <8 3>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
new file mode 100644
index 0000000..a158e33
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-qrd-sku4.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 QRD SKU4";
+	compatible = "qcom,sdm632-qrd", "qcom,sdm632", "qcom,qrd";
+	qcom,board-id = <0xb 1>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
+&pmi632_vadc {
+	chan@4a {
+		qcom,scale-function = <22>;
+	};
+};
+
+&soc {
+	gpio_keys {
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&tlmm 87 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&tlmm 86 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			debounce-interval = <15>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts
new file mode 100644
index 0000000..4d8ce5c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "sdm632-rumi.dtsi"
+
+/ {
+	model = "RUMI";
+	compatible = "qcom,rumi";
+	qcom,board-id = <15 0>;
+	qcom,pmic-id = <0 0 0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dts b/arch/arm64/boot/dts/qcom/sdm632.dts
new file mode 100644
index 0000000..dab409c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+	qcom,pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index 3ebd50e..c9d17ce 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -18,5 +18,613 @@
 	model = "Qualcomm Technologies, Inc. SDM632";
 	compatible = "qcom,sdm632";
 	qcom,msm-id = <349 0x0>;
+	qcom,msm-name = "SDM632";
 };
 
+&clock_gcc_mdss {
+	compatible = "qcom,gcc-mdss-sdm632";
+};
+
+&clock_gcc {
+	compatible = "qcom,gcc-sdm632";
+};
+
+&clock_debug {
+	compatible = "qcom,cc-debug-sdm632";
+};
+
+&clock_gcc_gfx {
+	compatible = "qcom,gcc-gfx-sdm632";
+};
+
+&thermal_zones {
+	/delete-node/ camera-usr;
+	/delete-node/ apc1-l2-usr;
+	/delete-node/ apc0-cpu0-usr;
+	/delete-node/ apc0-cpu1-usr;
+	/delete-node/ apc0-cpu2-usr;
+	/delete-node/ apc0-cpu3-usr;
+	/delete-node/ apc0-l2-usr;
+	/delete-node/ gpu0-usr;
+	/delete-node/ gpu1-usr;
+	/delete-node/ gpu1-step;
+	/delete-node/ deca-cpu-max-step;
+	/delete-node/ apc0-cpu0-step;
+	/delete-node/ apc0-cpu1-step;
+	/delete-node/ apc0-cpu2-step;
+	/delete-node/ apc0-cpu3-step;
+	/delete-node/ camera-lowf;
+	/delete-node/ apc1-l2-lowf;
+	/delete-node/ apc0-cpu0-lowf;
+	/delete-node/ apc0-cpu1-lowf;
+	/delete-node/ apc0-cpu2-lowf;
+	/delete-node/ apc0-cpu3-lowf;
+	/delete-node/ apc0-l2-lowf;
+	/delete-node/ gpu0-lowf;
+	/delete-node/ gpu1-lowf;
+
+	case-therm-step {
+		status = "disabled";
+	};
+
+	video-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 3>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpuss0-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 8>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpuss1-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 9>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpuss3-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 13>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	camera-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 14>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	gpu0-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 15>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	gpu0-step {
+		polling-delay-passive = <250>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 15>;
+		thermal-governor = "step_wise";
+
+		trips {
+			sdm632_gpu_trip0: gpu-trip0 {
+				temperature = <95000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			gpu_cdev0 {
+				trip = <&sdm632_gpu_trip0>;
+				cooling-device =
+					<&msm_gpu THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+			};
+		};
+	};
+
+	hepta-cpu-max-step {
+		polling-delay-passive = <50>;
+		polling-delay = <100>;
+		thermal-governor = "step_wise";
+
+		trips {
+			sdm632_cpu_trip:cpu-trip {
+				temperature = <95000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			cpu0_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU0 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu1_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU1 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu2_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU2 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu3_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU3 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu4_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU4 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu5_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU5 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu6_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU6 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			cpu7_cdev {
+				trip = <&sdm632_cpu_trip>;
+				cooling-device =
+					<&CPU7 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+		};
+	};
+
+	cpuss3-step {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 13>;
+		thermal-governor = "step_wise";
+
+		trips {
+			cpuss3_trip: cpuss3-trip {
+				temperature = <105000>;
+				hysteresis = <15000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_cdev {
+				trip = <&cpuss3_trip>;
+				cooling-device =
+					<&CPU0 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			cpu1_cdev {
+				trip = <&cpuss3_trip>;
+				cooling-device =
+					<&CPU1 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			cpu2_cdev {
+				trip = <&cpuss3_trip>;
+				cooling-device =
+					<&CPU2 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			cpu3_cdev {
+				trip = <&cpuss3_trip>;
+				cooling-device =
+					<&CPU3 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	video-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 3>;
+		tracks-low;
+
+		trips {
+			video_trip: video-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&video_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&video_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&video_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&video_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	cpuss0-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 8>;
+		tracks-low;
+
+		trips {
+			sdm632_cpuss0_trip: cpuss0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&sdm632_cpuss0_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&sdm632_cpuss0_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&sdm632_cpuss0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&sdm632_cpuss0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	cpuss1-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 9>;
+		tracks-low;
+
+		trips {
+			sdm632_cpuss1_trip: cpuss1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&sdm632_cpuss1_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&sdm632_cpuss1_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&sdm632_cpuss1_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&sdm632_cpuss1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	cpuss3-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 13>;
+		tracks-low;
+
+		trips {
+			sdm632_cpuss3_trip: cpuss3-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&sdm632_cpuss3_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&sdm632_cpuss3_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&sdm632_cpuss3_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&sdm632_cpuss3_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	camera-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 14>;
+		tracks-low;
+
+		trips {
+			sdm632_camera_trip: camera-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&sdm632_camera_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&sdm632_camera_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&sdm632_camera_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&sdm632_camera_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+
+	gpu0-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 15>;
+		tracks-low;
+
+		trips {
+			sdm632_gpu0_trip: gpu0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&sdm632_gpu0_trip>;
+				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
+						(THERMAL_MAX_LIMIT - 4)>;
+			};
+			gpu_vdd_cdev {
+				trip = <&sdm632_gpu0_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
+			cx_vdd_cdev {
+				trip = <&sdm632_gpu0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&sdm632_gpu0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+		};
+	};
+};
+
+&clock_cpu {
+	/delete-property/ vdd-cl-supply;
+	status = "disabled";
+	compatible = "qcom,cpu-clock-sdm632";
+	reg =   <0xb114000  0x68>,
+		<0xb014000  0x68>,
+		<0xb016000  0x8>,
+		<0xb116000  0x8>,
+		<0xb1d0000  0x8>,
+		<0xb011050  0x8>,
+		<0xb111050  0x8>,
+		<0xb1d1050  0x8>,
+		<0x00a412c  0x8>;
+	reg-names = "rcgwr-c0-base", "rcgwr-c1-base",
+		    "apcs-c1-pll-base", "apcs-c0-pll-base",
+		    "apcs-cci-pll-base", "apcs-c1-rcg-base",
+		    "apcs-c0-rcg-base", "apcs-cci-rcg-base",
+		    "efuse";
+	qcom,num-clusters = <2>;
+	clocks = <&clock_gcc clk_xo_a_clk_src>;
+	clock-names = "xo_a";
+	qcom,speed0-bin-v0-c0 =
+		<          0 0>,
+		<   614400000 1>,
+		<   883200000 2>,
+		<  1036200000 3>,
+		<  1363200000 4>,
+		<  1563000000 5>,
+		<  1670400000 6>,
+		<  1785600000 7>;
+	qcom,speed0-bin-v0-c1 =
+		<          0 0>,
+		<   633600000 1>,
+		<   902400000 2>,
+		<  1094400000 3>,
+		<  1401600000 4>,
+		<  1555200000 5>,
+		<  1785600000 6>;
+	qcom,speed0-bin-v0-cci =
+		<          0 0>,
+		<  307200000 1>,
+		<  403200000 2>,
+		<  499200000 3>,
+		<  691200000 4>,
+		<  768000000 5>,
+		<  787200000 6>;
+	#clock-cells = <1>;
+};
+
+&apc_vreg {
+	status = "disabled";
+};
+
+&soc {
+	/delete-node/ msm_cpufreq;
+	msm_cpufreq: qcom,msm-cpufreq {
+		compatible = "qcom,msm-cpufreq";
+		clock-names =
+			"l2_clk",
+			"cpu0_clk",
+			"cpu4_clk";
+		clocks =
+			<&clock_cpu clk_a53_cci_clk >,
+			<&clock_cpu clk_a53_pwr_clk >,
+			<&clock_cpu clk_a53_perf_clk >;
+
+		qcom,governor-per-policy;
+
+		qcom,cpufreq-table-0 =
+			<  614400 >,
+			<  883200 >,
+			< 1036800 >,
+			< 1363200 >,
+			< 1536000 >,
+			< 1670400 >,
+			< 1785600 >;
+
+		qcom,cpufreq-table-4 =
+			<  633600 >,
+			<  902400 >,
+			< 1036800 >,
+			< 1401600 >,
+			< 1555200 >,
+			< 1785600 >,
+			< 1996200 >,
+			< 2082800 >;
+	};
+
+	cci_cache: qcom,cci {
+		compatible = "devfreq-simple-dev";
+		clock-names = "devfreq_clk";
+		clocks = <&clock_cpu clk_a53_cci_clk >;
+		governor = "cpufreq";
+		freq-tbl-khz =
+			<  307200 >,
+			<  403200 >,
+			<  499200 >,
+			<  748800 >,
+			<  768000 >,
+			<  787200 >;
+	};
+
+	/delete-node/ devfreq-cpufreq;
+	devfreq-cpufreq {
+		mincpubw-cpufreq {
+			target-dev = <&mincpubw>;
+			cpu-to-dev-map-0 =
+				<  614400 1611>,
+				< 1363200 3221>,
+				< 1785600 5859>;
+			cpu-to-dev-map-4 =
+				<  633600 1611>,
+				< 1401600 4248>,
+				< 1785600 5859>,
+				< 1996200 7104>,
+				< 2082800 7104>;
+		};
+
+		cci-cpufreq {
+			target-dev = <&cci_cache>;
+			cpu-to-dev-map-0 =
+				<  614400 307200>,      /* SVS   */
+				<  883200 403200>,
+				< 1036800 499200>,
+				< 1363200 748800>,      /* NOM   */
+				< 1536000 768000>,      /* NOM+  */
+				< 1670400 787200>;      /* TURBO */
+			cpu-to-dev-map-4 =
+				<  633600 307200>,      /* SVS   */
+				<  902400 403200>,
+				< 1036800 499200>,
+				< 1401600 748800>,      /* NOM   */
+				< 1555200 768000>,      /* NOM+  */
+				< 1785600 787200>;      /* TURBO */
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
index faaf644..73c7be2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -19,10 +19,10 @@
 };
 
 &soc {
-	audio_load_mod {
-		compatible = "qcom,audio-load-mod";
-		audio_test_mod {
-			compatible = "qcom,audio-test-mod";
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
index 4f5a9b1..aa7cc97 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -669,35 +669,6 @@
 			qcom,bcms = <&bcm_cn0>;
 		};
 
-		mas_qhm_tic: mas-qhm-tic {
-			cell-id = <MSM_BUS_MASTER_TIC>;
-			label = "mas-qhm-tic";
-			qcom,buswidth = <4>;
-			qcom,agg-ports = <1>;
-			qcom,connections = <&slv_qhs_tlmm_south
-				&slv_qhs_camera_cfg &slv_qhs_sdc4
-				&slv_qhs_sdc2 &slv_qhs_mnoc_cfg
-				&slv_qhs_ufs_mem_cfg &slv_qhs_glm
-				&slv_qhs_pdm &slv_qhs_a2_noc_cfg
-				&slv_qhs_qdss_cfg &slv_qhs_display_cfg
-				&slv_qhs_tcsr &slv_qhs_dcc_cfg
-				&slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
-				&slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
-				&slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
-				&slv_qhs_tsif &slv_qhs_compute_dsp_cfg
-				&slv_qhs_aop &slv_qhs_qupv3_north
-				&slv_srvc_cnoc &slv_qhs_usb3_0
-				&slv_qhs_ipa &slv_qhs_cpr_cx
-				&slv_qhs_a1_noc_cfg &slv_qhs_aoss
-				&slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
-				&slv_qhs_emmc_cfg &slv_qhs_qupv3_south
-				&slv_qhs_spdm &slv_qhs_crypto0_cfg
-				&slv_qhs_pimem_cfg &slv_qhs_tlmm_north
-				&slv_qhs_clk_ctl &slv_qhs_imem_cfg>;
-			qcom,bus-dev = <&fab_config_noc>;
-			qcom,bcms = <&bcm_cn0>;
-		};
-
 		mas_qnm_snoc: mas-qnm-snoc {
 			cell-id = <MSM_BUS_SNOC_CNOC_MAS>;
 			label = "mas-qnm-snoc";
@@ -727,36 +698,6 @@
 			qcom,bcms = <&bcm_cn0>;
 		};
 
-		mas_xm_qdss_dap: mas-xm-qdss-dap {
-			cell-id = <MSM_BUS_MASTER_QDSS_DAP>;
-			label = "mas-xm-qdss-dap";
-			qcom,buswidth = <8>;
-			qcom,agg-ports = <1>;
-			qcom,connections = <&slv_qhs_tlmm_south
-				&slv_qhs_camera_cfg
-				&slv_qhs_sdc4
-				&slv_qhs_sdc2 &slv_qhs_mnoc_cfg
-				&slv_qhs_ufs_mem_cfg &slv_qhs_glm
-				&slv_qhs_pdm &slv_qhs_a2_noc_cfg
-				&slv_qhs_qdss_cfg &slv_qhs_display_cfg
-				&slv_qhs_tcsr &slv_qhs_dcc_cfg
-				&slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
-				&slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
-				&slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
-				&slv_qhs_tsif &slv_qhs_compute_dsp_cfg
-				&slv_qhs_aop &slv_qhs_qupv3_north
-				&slv_srvc_cnoc &slv_qhs_usb3_0
-				&slv_qhs_ipa &slv_qhs_cpr_cx
-				&slv_qhs_a1_noc_cfg &slv_qhs_aoss
-				&slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
-				&slv_qhs_qupv3_south &slv_qhs_spdm
-				&slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg
-				&slv_qhs_tlmm_north &slv_qhs_clk_ctl
-				&slv_qhs_imem_cfg>;
-			qcom,bus-dev = <&fab_config_noc>;
-			qcom,bcms = <&bcm_cn0>;
-		};
-
 		mas_qhm_cnoc: mas-qhm-cnoc {
 			cell-id = <MSM_BUS_MASTER_CNOC_DC_NOC>;
 			label = "mas-qhm-cnoc";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
index 7ab99a3..c8f7ac0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -22,6 +22,16 @@
 		status = "ok";
 	};
 
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
 	actuator_regulator: gpio-regulator@0 {
 		compatible = "regulator-fixed";
 		reg = <0x00 0x00>;
@@ -386,7 +396,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
-		led-flash-src = <&led_flash_rear>;
+		led-flash-src = <&led_flash_rear_aux>;
 		actuator-src = <&actuator_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&cam_iovdd_gpio_regulator>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 715affd..9402294 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -234,9 +234,7 @@
 		msm_cam_smmu_lrme {
 			compatible = "qcom,msm-cam-smmu-cb";
 			iommus = <&apps_smmu 0x1038 0x0>,
-				<&apps_smmu 0x1058 0x0>,
-				<&apps_smmu 0x1039 0x0>,
-				<&apps_smmu 0x1059 0x0>;
+				<&apps_smmu 0x1058 0x0>;
 			label = "lrme";
 			lrme_iova_mem_map: iova-mem-map {
 				iova-mem-region-shared {
@@ -338,13 +336,23 @@
 				};
 
 				iova-mem-region-io {
-					/* IO region is approximately 3.3 GB */
+					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd900000>;
-					iova-region-len = <0xd2700000>;
+					iova-region-start = <0xd911000>;
+					iova-region-len = <0xd26ef000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
+
+				iova-mem-qdss-region {
+					/* qdss region is approximately 64K */
+					iova-region-name = "qdss";
+					iova-region-start = <0xd900000>;
+					iova-region-len = <0x10000>;
+					iova-region-id = <0x5>;
+					qdss-phy-addr = <0x16790000>;
+					status = "ok";
+				};
 			};
 		};
 
@@ -393,13 +401,16 @@
 		label = "cpas";
 		arch-compat = "cpas_top";
 		status = "ok";
-		reg-names = "cam_cpas_top", "cam_camnoc";
+		reg-names = "cam_cpas_top", "cam_camnoc", "core_top_csr_tcsr";
 		reg = <0xac40000 0x1000>,
-			<0xac42000 0x5000>;
-		reg-cam-base = <0x40000 0x42000>;
+			<0xac42000 0x5000>,
+			<0x01fc0000 0x30000>;
+		reg-cam-base = <0x40000 0x42000 0x0>;
 		interrupt-names = "cpas_camnoc";
 		interrupts = <0 459 0>;
 		qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */
+		nvmem-cells = <&minor_rev>;
+		nvmem-cell-names = "minor_rev";
 		regulator-names = "camss-vdd";
 		camss-vdd-supply = <&titan_top_gdsc>;
 		clock-names = "gcc_ahb_clk",
@@ -892,7 +903,7 @@
 			<0 0 200000000 0 0 0 0 600000000>;
 		clock-cntl-level = "svs", "turbo";
 		fw_name = "CAMERA_ICP.elf";
-		ubwc-cfg = <0x77 0x1DF>;
+		ubwc-cfg = <0x73 0x1CF>;
 		status = "ok";
 	};
 
@@ -913,12 +924,12 @@
 				<&clock_camcc CAM_CC_IPE_0_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -940,12 +951,12 @@
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -967,12 +978,12 @@
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 200000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 600000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 6dc5c2c..dc9e54e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -11,6 +11,19 @@
  */
 &soc {
 
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-name = "coresight-csr";
+
+		qcom,usb-bam-support;
+		qcom,hwctrl-set-support;
+		qcom,set-byte-cntr-support;
+		qcom,blk-size = <1>;
+	};
+
 	replicator_qdss: replicator@6046000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b909>;
@@ -59,6 +72,7 @@
 
 		coresight-name = "coresight-tmc-etr";
 		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
 
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
@@ -117,6 +131,7 @@
 		reg-names = "tmc-base";
 
 		coresight-name = "coresight-tmc-etf-swao";
+		coresight-csr = <&csr>;
 
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
@@ -284,6 +299,7 @@
 		coresight-name = "coresight-tmc-etf";
 		coresight-ctis = <&cti0 &cti8>;
 		arm,default-sink;
+		coresight-csr = <&csr>;
 
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
@@ -395,22 +411,13 @@
 		reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
 			    "ddr-ch23-ctrl";
 
+		coresight-csr = <&csr>;
 		coresight-name = "coresight-hwevent";
 
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 	};
 
-	csr: csr@6001000 {
-		compatible = "qcom,coresight-csr";
-		reg = <0x6001000 0x1000>;
-		reg-names = "csr-base";
-
-		coresight-name = "coresight-csr";
-
-		qcom,blk-size = <1>;
-	};
-
 	funnel_in0: funnel@0x6041000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 75a2762..7d2d657 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -134,6 +134,28 @@
 
 		qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
 
+		qcom,soc-hw-rev-efuse = <0x414c 28 0x3>;
+
+		qcom,soc-hw-revisions {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "qcom,soc-hw-revisions";
+
+			qcom,soc-hw-revision-0 {
+				qcom,soc-hw-revision = <0>;
+				qcom,chipid = <0x06010500>;
+				qcom,gpu-quirk-hfi-use-reg;
+				qcom,gpu-quirk-limit-uche-gbif-rw;
+				qcom,gpu-quirk-mmu-secure-cb-alt;
+			};
+
+			qcom,soc-hw-revision-1 {
+				qcom,soc-hw-revision = <1>;
+				qcom,chipid = <0x06010501>;
+				qcom,gpu-quirk-hfi-use-reg;
+			};
+		};
+
 		qcom,gpu-coresights {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -217,6 +239,7 @@
 				qcom,speed-bin = <0>;
 
 				qcom,initial-pwrlevel = <3>;
+				qcom,ca-target-pwrlevel = <1>;
 
 				/* SVS_L1 */
 				qcom,gpu-pwrlevel@0 {
@@ -271,6 +294,7 @@
 				qcom,speed-bin = <90>;
 
 				qcom,initial-pwrlevel = <3>;
+				qcom,ca-target-pwrlevel = <1>;
 
 				/* SVS_L1 */
 				qcom,gpu-pwrlevel@0 {
@@ -326,6 +350,7 @@
 				qcom,speed-bin = <146>;
 
 				qcom,initial-pwrlevel = <6>;
+				qcom,ca-target-pwrlevel = <4>;
 
 				/* TURBO */
 				qcom,gpu-pwrlevel@0 {
@@ -407,38 +432,75 @@
 
 				qcom,speed-bin = <163>;
 
-				qcom,initial-pwrlevel = <3>;
+				qcom,initial-pwrlevel = <7>;
+				qcom,ca-target-pwrlevel = <5>;
 
-				/* SVS_L1 */
+				/* TURBO_L1 */
 				qcom,gpu-pwrlevel@0 {
 					reg = <0>;
-					qcom,gpu-freq = <430000000>;
+					qcom,gpu-freq = <780000000>;
 					qcom,bus-freq = <11>;
+					qcom,bus-min = <10>;
+					qcom,bus-max = <11>;
+				};
+
+				/* TURBO */
+				qcom,gpu-pwrlevel@1 {
+					reg = <1>;
+					qcom,gpu-freq = <750000000>;
+					qcom,bus-freq = <11>;
+					qcom,bus-min = <9>;
+					qcom,bus-max = <11>;
+				};
+
+				/* NOM_L1 */
+				qcom,gpu-pwrlevel@2 {
+					reg = <2>;
+					qcom,gpu-freq = <650000000>;
+					qcom,bus-freq = <10>;
 					qcom,bus-min = <8>;
 					qcom,bus-max = <11>;
 				};
 
-				/* SVS */
-				qcom,gpu-pwrlevel@1 {
-					reg = <1>;
-					qcom,gpu-freq = <355000000>;
-					qcom,bus-freq = <8>;
-					qcom,bus-min = <5>;
-					qcom,bus-max = <9>;
+				/* NOM */
+				qcom,gpu-pwrlevel@3 {
+					reg = <3>;
+					qcom,gpu-freq = <565000000>;
+					qcom,bus-freq = <9>;
+					qcom,bus-min = <8>;
+					qcom,bus-max = <10>;
 				};
 
-				/* LOW SVS */
-				qcom,gpu-pwrlevel@2 {
-					reg = <2>;
-					qcom,gpu-freq = <267000000>;
-					qcom,bus-freq = <6>;
-					qcom,bus-min = <4>;
+				/* SVS_L1 */
+				qcom,gpu-pwrlevel@4 {
+					reg = <4>;
+					qcom,gpu-freq = <430000000>;
+					qcom,bus-freq = <8>;
+					qcom,bus-min = <7>;
+					qcom,bus-max = <10>;
+				};
+
+				/* SVS */
+				qcom,gpu-pwrlevel@5 {
+					reg = <5>;
+					qcom,gpu-freq = <355000000>;
+					qcom,bus-freq = <7>;
+					qcom,bus-min = <5>;
 					qcom,bus-max = <8>;
 				};
 
+				/* LOW SVS */
+				qcom,gpu-pwrlevel@6 {
+					reg = <6>;
+					qcom,gpu-freq = <267000000>;
+					qcom,bus-freq = <6>;
+					qcom,bus-min = <4>;
+					qcom,bus-max = <7>;
+				};
+
 				/* MIN SVS */
-				qcom,gpu-pwrlevel@3 {
-					reg = <3>;
+				qcom,gpu-pwrlevel@7 {
+					reg = <7>;
 					qcom,gpu-freq = <180000000>;
 					qcom,bus-freq = <4>;
 					qcom,bus-min = <3>;
@@ -446,8 +508,8 @@
 				};
 
 				/* XO */
-				qcom,gpu-pwrlevel@4 {
-					reg = <4>;
+				qcom,gpu-pwrlevel@8 {
+					reg = <8>;
 					qcom,gpu-freq = <0>;
 					qcom,bus-freq = <0>;
 					qcom,bus-min = <0>;
@@ -485,6 +547,11 @@
 
 		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/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index de9e40e..68f51e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -365,13 +365,7 @@
 };
 
 &thermal_zones {
-	xo-therm-cpu-step {
-		status = "disabled";
-	};
-	xo-therm-mdm-step {
-		status = "disabled";
-	};
-	xo-therm-batt-step {
+	xo-therm-step {
 		status = "disabled";
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index 5bf8df7..c54b8db 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -186,7 +186,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 5d3975c..27be1fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -175,8 +175,8 @@
 		io-channel-names = "rradc_batt_id",
 				   "rradc_die_temp";
 		qcom,rradc-base = <0x4500>;
-		qcom,fg-esr-timer-awake = <96 96>;
-		qcom,fg-esr-timer-asleep = <256 256>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
 		qcom,fg-esr-timer-charging = <0 96>;
 		qcom,cycle-counter-en;
 		qcom,hold-soc-while-full;
@@ -387,35 +387,25 @@
 };
 
 &thermal_zones {
-	xo-therm-batt-step {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-sensors = <&pm660_adc_tm 0x4c>;
-		thermal-governor = "step_wise";
-
+	xo-therm-step {
 		trips {
 			batt_trip1: batt-trip1 {
-				temperature = <40000>;
-				hysteresis = <2000>;
+				temperature = <50000>;
+				hysteresis = <4000>;
 				type = "passive";
 			};
 			batt_trip2: batt-trip2 {
-				temperature = <45000>;
+				temperature = <52000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
 			batt_trip3: batt-trip3 {
-				temperature = <48000>;
-				hysteresis = <3000>;
-				type = "passive";
-			};
-			batt_trip4: batt-trip4 {
-				temperature = <50000>;
+				temperature = <54000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
-			batt_trip5: batt-trip5 {
-				temperature = <52000>;
+			batt_trip4: batt-trip4 {
+				temperature = <56000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
@@ -432,14 +422,10 @@
 			};
 			battery_lvl3 {
 				trip = <&batt_trip3>;
-				cooling-device = <&pm660_charger 3 3>;
+				cooling-device = <&pm660_charger 4 4>;
 			};
 			battery_lvl4 {
 				trip = <&batt_trip4>;
-				cooling-device = <&pm660_charger 4 4>;
-			};
-			battery_lvl5 {
-				trip = <&batt_trip5>;
 				cooling-device = <&pm660_charger 5 5>;
 			};
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index 9a7e742..43f1465 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -75,6 +75,7 @@
 &pm660_fg {
 	qcom,battery-data = <&qrd_batterydata>;
 	qcom,fg-bmd-en-delay-ms = <300>;
+	qcom,fg-jeita-thresholds = <0 15 45 55>;
 };
 
 &pm660_charger {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 6b24593..9d3f37d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -684,6 +684,5 @@
 		regulator-enable-ramp-delay = <5>;
 		proxy-supply = <&refgen>;
 		qcom,proxy-consumer-enable;
-		regulator-always-on;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index 007f937..48deca6 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -489,6 +489,29 @@
 		ibb-supply = <&lcdb_ncp_vreg>;
 	};
 
+	ext_dsi_bridge_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "ext_dsi_bridge_display";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0>;
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+		       <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				ext_dsi_out: endpoint {
+				};
+			};
+		};
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
@@ -831,7 +854,7 @@
 	qcom,esd-check-enabled;
 	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
 	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
-	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
 	qcom,mdss-dsi-panel-status-value = <0x9c>;
 	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
 	qcom,mdss-dsi-panel-status-read-length = <1>;
@@ -849,6 +872,18 @@
 &dsi_hx8399_truly_cmd {
 	qcom,mdss-dsi-t-clk-post = <0x0E>;
 	qcom,mdss-dsi-t-clk-pre = <0x30>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
index 7c4e682..3022998 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
@@ -224,6 +224,7 @@
 			qcom,sde-dspp-pcc = <0x1700 0x00040000>;
 			qcom,sde-dspp-gc = <0x17c0 0x00010008>;
 			qcom,sde-dspp-hist = <0x800 0x00010007>;
+			qcom,sde-dspp-dither = <0x82c 0x00010007>;
 		};
 
 		qcom,platform-supply-entries {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
index f3e5ddb..b2601ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -268,4 +268,16 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
+
+	/* wlan - inbound entry from mss/WLAN PD */
+	smp2pgpio_wlan_1_in: qcom,smp2pgpio-wlan-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "wlan";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index a0fa9cf..8707af2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -576,7 +576,7 @@
 		};
 	};
 
-	xo-therm-cpu-step {
+	xo-therm-step {
 		polling-delay-passive = <2000>;
 		polling-delay = <0>;
 		thermal-sensors = <&pm660_adc_tm 0x4c>;
@@ -584,15 +584,35 @@
 
 		trips {
 			gold_trip0: gold-trip0 {
-				temperature = <45000>;
+				temperature = <47000>;
 				hysteresis = <0>;
 				type = "passive";
 			};
 			silver_trip1: silver-trip1 {
-				temperature = <50000>;
+				temperature = <52000>;
 				hysteresis = <0>;
 				type = "passive";
 			};
+			modem_trip0: modem-trip0 {
+				temperature = <48000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+			modem_trip1: modem-trip1 {
+				temperature = <50000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+			modem_trip2: modem-trip2 {
+				temperature = <52000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			modem_trip3: modem-trip3 {
+				temperature = <56000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
 		};
 
 		cooling-maps {
@@ -634,39 +654,6 @@
 				trip = <&silver_trip1>;
 				cooling-device = <&CPU5 THERMAL_NO_LIMIT 2>;
 			};
-		};
-	};
-
-	xo-therm-mdm-step {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-sensors = <&pm660_adc_tm 0x4c>;
-		thermal-governor = "step_wise";
-
-		trips {
-			modem_trip0: modem-trip0 {
-				temperature = <44000>;
-				hysteresis = <4000>;
-				type = "passive";
-			};
-			modem_trip1: modem-trip1 {
-				temperature = <46000>;
-				hysteresis = <3000>;
-				type = "passive";
-			};
-			modem_trip2: modem-trip2 {
-				temperature = <48000>;
-				hysteresis = <3000>;
-				type = "passive";
-			};
-			modem_trip3: modem-trip3 {
-				temperature = <55000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-
-		cooling-maps {
 			modem_lvl1 {
 				trip = <&modem_trip1>;
 				cooling-device = <&modem_pa 1 1>;
@@ -689,4 +676,133 @@
 			};
 		};
 	};
+
+	vbat_adc {
+		cooling-maps {
+			vbat_map6 {
+				trip = <&pm660_vbat_adc>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			vbat_map7 {
+				trip = <&pm660_vbat_adc>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	soc {
+		cooling-maps {
+			soc_map6 {
+				trip = <&pm660_low_soc>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			soc_map7 {
+				trip = <&pm660_low_soc>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	pm660_temp_alarm: pm660_tz {
+		cooling-maps {
+			trip0_cpu0 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU0 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu1 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU1 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu2 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU2 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu3 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU3 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu4 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU4 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu5 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU5 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu6 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU6 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu7 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU7 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip1_cpu1 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU1 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu2 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU2 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu3 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU3 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu4 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu5 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu6 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu7 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index 32864a0..8b1f3d1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -27,8 +27,6 @@
 };
 
 &usb0 {
-	/delete-property/ iommus;
-	/delete-property/ qcom,smmu-s1-bypass;
 	qcom,pm-qos-latency = <601>; /* CPU-CLUSTER-WFI-LVL latency +1 */
 	extcon = <0>, <0>, <&eud>, <0>, <0>;
 };
@@ -37,6 +35,27 @@
 	vdd-supply = <&pm660l_l1>;
 	vdda18-supply = <&pm660_l10>;
 	vdda33-supply = <&pm660l_l7>;
+	qcom,host-chirp-erratum;
+	qcom,qusb-phy-host-init-seq =
+			/* <value reg_offset> */
+			   <0x23 0x210 /* PWR_CTRL1 */
+			    0x03 0x04  /* PLL_ANALOG_CONTROLS_TWO */
+			    0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+			    0x80 0x2c  /* PLL_CMODE */
+			    0x0a 0x184 /* PLL_LOCK_DELAY */
+			    0x19 0xb4  /* PLL_DIGITAL_TIMERS_TWO */
+			    0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+			    0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+			    0x21 0x214 /* PWR_CTRL2 */
+			    0x08 0x220 /* IMP_CTRL1 */
+			    0x58 0x224 /* IMP_CTRL2 */
+			    0x45 0x240 /* TUNE1 */
+			    0x29 0x244 /* TUNE2 */
+			    0xca 0x248 /* TUNE3 */
+			    0x04 0x24c /* TUNE4 */
+			    0x03 0x250 /* TUNE5 */
+			    0x00 0x23c /* CHG_CTRL2 */
+			    0x22 0x210>; /* PWR_CTRL1 */
 	qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
 			   <0x23 0x210 /* PWR_CTRL1 */
@@ -57,6 +76,8 @@
 			    0x03 0x250 /* TUNE5 */
 			    0x00 0x23c /* CHG_CTRL2 */
 			    0x22 0x210>; /* PWR_CTRL1 */
+	nvmem-cells = <&minor_rev>;
+	nvmem-cell-names = "minor_rev";
 };
 
 &usb_qmp_dp_phy {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
index 01d4057..a0b4a22 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -42,7 +42,7 @@
 			"bus_clk", "core0_clk", "core0_bus_clk",
 			"core1_clk", "core1_bus_clk";
 		qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
-		qcom,allowed-clock-rates = <100000000 200000000 320000000
+		qcom,allowed-clock-rates = <100000000 200000000 330000000
 			380000000 444000000 533000000>;
 
 		/* Buses */
@@ -138,7 +138,7 @@
 		qcom,proxy-clock-names = "core_clk", "iface_clk",
 			"bus_clk", "core0_clk", "core0_bus_clk";
 		qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>;
-		qcom,allowed-clock-rates = <100000000 200000000 320000000
+		qcom,allowed-clock-rates = <100000000 200000000 330000000
 			364700000>;
 
 		/* Buses */
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 9bc083f..e6bf8ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -585,8 +585,8 @@
 			size = <0 0x5c00000>;
 		};
 
-		cont_splash_memory: cont_splash_region@9d400000 {
-			reg = <0x0 0x9d400000 0x0 0x02400000>;
+		cont_splash_memory: cont_splash_region@9c000000 {
+			reg = <0x0 0x9c000000 0x0 0x02400000>;
 			label = "cont_splash_region";
 		};
 
@@ -809,6 +809,10 @@
 			 <&apps_smmu 0x716 0x1>;
 	};
 
+	qcom_msmhdcp: qcom,msm_hdcp {
+		compatible = "qcom,msm-hdcp";
+	};
+
 	qcom_crypto: qcrypto@1de0000 {
 		compatible = "qcom,qcrypto";
 		reg = <0x1de0000 0x20000>,
@@ -1037,6 +1041,20 @@
 		vdd_mx-supply = <&pm660l_s1_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
+		qcom,cam_cc_csi0phytimer_clk_src-opp-handle = <&cam_csiphy0>;
+		qcom,cam_cc_csi1phytimer_clk_src-opp-handle = <&cam_csiphy1>;
+		qcom,cam_cc_csi2phytimer_clk_src-opp-handle = <&cam_csiphy2>;
+		qcom,cam_cc_cci_clk_src-opp-handle = <&cam_cci>;
+		qcom,cam_cc_ife_0_csid_clk_src-opp-handle = <&cam_csid0>;
+		qcom,cam_cc_ife_0_clk_src-opp-handle = <&cam_vfe0>;
+		qcom,cam_cc_ife_1_csid_clk_src-opp-handle = <&cam_csid1>;
+		qcom,cam_cc_ife_1_clk_src-opp-handle = <&cam_vfe1>;
+		qcom,cam_cc_ife_lite_csid_clk_src-opp-handle = <&cam_csid_lite>;
+		qcom,cam_cc_ife_lite_clk_src-opp-handle = <&cam_vfe_lite>;
+		qcom,cam_cc_icp_clk_src-opp-handle = <&cam_a5>;
+		qcom,cam_cc_ipe_0_clk_src-opp-handle = <&cam_ipe0>;
+		qcom,cam_cc_ipe_1_clk_src-opp-handle = <&cam_ipe1>;
+		qcom,cam_cc_bps_clk_src-opp-handle = <&cam_bps>;
 	};
 
 	clock_dispcc: qcom,dispcc@af00000 {
@@ -1657,7 +1675,7 @@
 		};
 	};
 
-	qcom,chd_sliver {
+	qcom,chd_silver {
 		compatible = "qcom,core-hang-detect";
 		label = "silver";
 		qcom,threshold-arr = <0x17e00058 0x17e10058 0x17e20058
@@ -2139,6 +2157,8 @@
 		compatible = "qcom,pil-tz-generic";
 		qcom,pas-id = <0xf>;
 		qcom,firmware-name = "ipa_fws";
+		qcom,pil-force-shutdown;
+		memory-region = <&pil_ipa_fw_mem>;
 	};
 
 	pil_modem: qcom,mss@4080000 {
@@ -2440,6 +2460,7 @@
 	qcom,msm-adsprpc-mem {
 		compatible = "qcom,msm-adsprpc-mem-region";
 		memory-region = <&adsp_mem>;
+		restrict-access;
 	};
 
 	qcom,msm_fastrpc {
@@ -2564,6 +2585,8 @@
 		qcom,vdd-3.3-ch0-config = <3000000 3312000>;
 		qcom,wlan-msa-memory = <0x100000>;
 		qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
+		qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+		qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
 		qcom,smmu-s1-bypass;
 	};
 
@@ -2647,6 +2670,18 @@
 			< 1 >;
 	};
 
+	bus_proxy_client: qcom,bus_proxy_client {
+		compatible = "qcom,bus-proxy-client";
+		qcom,msm-bus,name = "bus-proxy-client";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>, <23 512 0 0>,
+			<22 512 0 5000000>, <23 512 0 5000000>;
+		qcom,msm-bus,active-only;
+		status = "ok";
+	};
+
 	devfreq_memlat_0: qcom,cpu0-memlat-mon {
 		compatible = "qcom,arm-memlat-mon";
 		qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>;
@@ -2836,14 +2871,14 @@
 
 	qfprom: qfprom@0x780000 {
 		compatible	= "qcom,qfprom";
-		reg		= <0x00780000 0x1000>;
+		reg		= <0x00784000 0x1000>;
 		#address-cells	= <1>;
 		#size-cells	= <1>;
 		ranges;
 
-		minor_rev: minor_rev@0x78014c {
+		minor_rev: minor_rev@0x78414c {
 			reg = <0x14c 0x4>;
-			bits = <0x1c 0x2>;
+			bits = <0 30>; /* Access 30 bits from bit offset 0 */
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index f6fa948..9903d19 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -138,7 +138,8 @@
 			 0x254 /* QUSB2PHY_TEST1 */
 			 0x198 /* PLL_BIAS_CONTROL_2 */
 			 0x228 /* QUSB2PHY_SQ_CTRL1 */
-			 0x22c>; /* QUSB2PHY_SQ_CTRL2 */
+			 0x22c /* QUSB2PHY_SQ_CTRL2 */
+			 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
 
 		qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..365b383
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>,
+			<&tlmm 27 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vaf = <3>;
+		gpio-req-tbl-num = <0 1 2 3>;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0",
+					"CAM_VAF";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-position = <1>;
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi
new file mode 100644
index 0000000..b671d0e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr-dvt.dtsi
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include "sdm845-camera-sensor-qvr.dtsi"
+/* PMD ToF MD101D */
+&cam_cci {
+	qcom,cam-sensor@4 {
+		cell-index = <4>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x4>;
+		csiphy-sd-index = <3>;
+		sensor-position-roll = <270>; /* checked, MTP845 */
+		sensor-position-pitch = <0>; /* checked, MTP845 */
+		sensor-position-yaw = <180>; /* checked, MTP845 */
+		cam_vio-supply = <&pm8998_lvs1>; /* checked, MTP845 */
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_eyetracking_force>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk3_active
+				&cam_sensor_depth_active>;
+		pinctrl-1 = <&cam_sensor_mclk3_suspend
+				&cam_sensor_depth_suspend>;
+		gpios = <&tlmm 16 0>, //MCLK1
+			    <&tlmm 28 0>, //RESET
+			    <&tlmm 23 0>, //vana
+			    <&tlmm 24 0>;
+		gpio-reset = <1>;   //RESET
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-req-tbl-num = <0 1 2 3> ;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1",
+					"CAM_VDIG1";
+		sensor-mode = <0>; // 0 -> back camera 2D
+		cci-master = <1>; /* checked, MTP845 we are on I2C 0 */
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+/* 6dof */
+	qcom,camera@6 {
+		cell-index = <6>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x6>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_s3>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+					"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&max_6dof_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&max_6dof_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 30 0>,
+			<&tlmm 95 0>,
+			<&tlmm 94 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-req-tbl-num = <0 1 2 3 >;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK3",
+					"CAM_RESET3",
+					"CAM_VANA3",
+					"CAM_VDIG3" ;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
index 8ad5f3c..71566d0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -71,6 +71,30 @@
 		pinctrl-0 = <&camera_dvdd_en_default>;
 		vin-supply = <&pm8998_s3>;
 	};
+
+	camera_eyetracking_force: gpio-regulator@3 {
+		compatible = "regulator-fixed";
+		reg = <0x03 0x00>;
+		regulator-name = "camera_eyetracking_force";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 77 0>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_eyetracking_force_front: gpio-regulator@4 {
+		compatible = "regulator-fixed";
+		reg = <0x04 0x00>;
+		regulator-name = "camera_eyetracking_force_front";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 77 0>;
+		vin-supply = <&pm8998_lvs1>;
+	};
 };
 
 &cam_cci {
@@ -343,7 +367,7 @@
 		sensor-position-yaw = <0>;
 		eeprom-src = <&eeprom_front>;
 		cam_vdig-supply = <&camera_ldo>;
-		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vio-supply = <&camera_eyetracking_force_front>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_clk-supply = <&titan_top_gdsc>;
 		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
@@ -376,4 +400,187 @@
 		clock-cntl-level = "turbo";
 		clock-rates = <24000000>;
 	};
+
+	qcom,camera@3 {
+		cell-index = <3>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x3>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_s3>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+					"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				&max_rst_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				&max_rst_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 31 0>,
+			<&tlmm 77 0>,
+			<&tlmm 78 0>,
+			<&tlmm 32 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-custom1 = <3>;
+		gpio-custom2 = <4>;
+		gpio-req-tbl-num = <0 1 2 3 4>;
+		gpio-req-tbl-flags = <1 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA2",
+					"CAM_CUSTOM1",
+					"CAM_CUSTOM2";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@5 {
+		cell-index = <5>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x05>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_eyetracking_force>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				 &cam_sensor_fisheye_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				 &cam_sensor_fisheye_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 76 0>,
+			<&tlmm 75 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@4 {
+		cell-index = <4>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x4>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>; /* checked, MTP845 */
+		sensor-position-pitch = <0>; /* checked, MTP845 */
+		sensor-position-yaw = <180>; /* checked, MTP845 */
+		cam_vio-supply = <&pm8998_lvs1>; /* checked, MTP845 */
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_eyetracking_force>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_depth_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_depth_suspend>;
+		gpios = <&tlmm 14 0>, //MCLK1
+			    <&tlmm 28 0>, //RESET
+			    <&tlmm 23 0>, //vana
+			    <&tlmm 24 0>;
+		gpio-reset = <1>;   //RESET
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-req-tbl-num = <0 1 2 3> ;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1",
+					"CAM_VDIG1";
+		sensor-mode = <0>; // 0 -> back camera 2D
+		cci-master = <1>; /* checked, MTP845 we are on I2C 0 */
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,camera@6 {
+		cell-index = <6>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x6>;
+		csiphy-sd-index = <3>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_s3>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+					"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk3_active
+				&max_6dof_active>;
+		pinctrl-1 = <&cam_sensor_mclk3_suspend
+				&max_6dof_suspend>;
+		gpios = <&tlmm 16 0>,
+			<&tlmm 30 0>,
+			<&tlmm 95 0>,
+			<&tlmm 94 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-req-tbl-num = <0 1 2 3 >;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK3",
+					"CAM_RESET3",
+					"CAM_VANA3",
+					"CAM_VDIG3" ;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
new file mode 100644
index 0000000..d387f93
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	led_flash_iris: qcom,camera-flash@3 {
+		cell-index = <3>;
+		reg = <0x03 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch2>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	qcom,cam-res-mgr {
+		compatible = "qcom,cam-res-mgr";
+		status = "ok";
+		shared-gpios = <9>;
+		pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
+		pinctrl-0 = <&cam_res_mgr_active>;
+		pinctrl-1 = <&cam_res_mgr_suspend>;
+	};
+
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_rear_aux: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0 2800000>;
+		rgltr-max-voltage = <1050000 0 3600000 0 2800000>;
+		rgltr-load-current = <105000 0 80000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 28 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA2";
+		sensor-position = <1>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_l9>;
+		cam_vio-supply = <&pm8998_l8>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1704000 1200000>;
+		rgltr-max-voltage = <0 3600000 2928000 1248000>;
+		rgltr-load-current = <0 80000 105000 1200000>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 8 0>,
+			<&tlmm 115 0>,
+			<&tlmm 95 0 >,
+			<&tlmm 97 0>;
+		gpio-reset = <1>;
+		gpio-vio = <2>;
+		gpio-vana = <3>;
+		gpio-vdig = <4>;
+		gpio-req-tbl-num = <0 1 2 3 4>;
+		gpio-req-tbl-flags = <1 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VIO",
+					"CAM_VANA",
+					"CAM_VDIG";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		actuator-src = <&actuator_rear_aux>;
+		led-flash-src = <&led_flash_rear_aux>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "disabled";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_lvs1>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1800000 0>;
+		rgltr-max-voltage = <0 3600000 1800000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 26 0>,
+			<&tlmm 132 0>,
+			<&tlmm 133 0>,
+			<&tlmm 90 0>,
+			<&tlmm 40 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-vio = <4>;
+		gpio-standby = <5>;
+		gpio-req-tbl-num = <0 1 2 3 4 5>;
+		gpio-req-tbl-flags = <1 0 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET2",
+					"CAM_VANA2",
+					"CAM_VDIG2",
+					"CAM_VIO2",
+					"CAM_STANDBY2";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@3 {
+		cell-index = <3>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x03>;
+		csiphy-sd-index = <3>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		led-flash-src = <&led_flash_iris>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk3_active
+				 &cam_sensor_iris_active>;
+		pinctrl-1 = <&cam_sensor_mclk3_suspend
+				 &cam_sensor_iris_suspend>;
+		gpios = <&tlmm 16 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK3",
+					"CAM_RESET3",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 35a7774..fd6a0c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -309,13 +309,23 @@
 				};
 
 				iova-mem-region-io {
-					/* IO region is approximately 3.3 GB */
+					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd900000>;
-					iova-region-len = <0xd2700000>;
+					iova-region-start = <0xd911000>;
+					iova-region-len = <0xd26ef000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
+
+				iova-mem-qdss-region {
+					/* qdss region is approximately 64K */
+					iova-region-name = "qdss";
+					iova-region-start = <0xd900000>;
+					iova-region-len = <0x10000>;
+					iova-region-id = <0x5>;
+					qdss-phy-addr = <0x16790000>;
+					status = "ok";
+				};
 			};
 		};
 
@@ -863,7 +873,7 @@
 			<0 0 200000000 0 0 0 0 600000000>;
 		clock-cntl-level = "svs", "turbo";
 		fw_name = "CAMERA_ICP.elf";
-		ubwc-cfg = <0x7F 0x1FF>;
+		ubwc-cfg = <0x7B 0x1EF>;
 		status = "ok";
 	};
 
@@ -885,12 +895,11 @@
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
 		clock-rates =
-			<0 0 0 0 240000000>,
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -912,12 +921,12 @@
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -939,12 +948,12 @@
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 200000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 600000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 5a88dc2..2c38f51 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -320,7 +320,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -328,8 +327,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 1c7269a..d6be6d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -72,6 +72,13 @@
 	ibb-supply = <&lcdb_ncp_vreg>;
 };
 
+&dsi_dual_test_cmd_display {
+	/delete-property/ vddio-supply;
+	/delete-property/ lab-supply;
+	/delete-property/ ibb-supply;
+	/delete-property/ oled-vdda-supply;
+};
+
 &sde_dp {
 	status = "disabled";
 	/delete-property/ vdda-1p2-supply;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index fc4b674..349c4c0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -319,7 +319,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -327,8 +326,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 78be790..019607c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2228,33 +2228,41 @@
 		};
 
 		qupv3_se6_4uart_pins: qupv3_se6_4uart_pins {
-			qupv3_se6_4uart_active: qupv3_se6_4uart_active {
+			qupv3_se6_ctsrx: qupv3_se6_ctsrx {
 				mux {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio45", "gpio48";
 					function = "qup6";
 				};
 
 				config {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio45", "gpio48";
 					drive-strength = <2>;
-					bias-disable;
+					bias-no-pull;
 				};
 			};
 
-			qupv3_se6_4uart_sleep: qupv3_se6_4uart_sleep {
+			qupv3_se6_rts: qupv3_se6_rts {
 				mux {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
-					function = "gpio";
+					pins = "gpio46";
+					function = "qup6";
 				};
 
 				config {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio46";
 					drive-strength = <2>;
-					bias-disable;
+					bias-pull-down;
+				};
+			};
+			qupv3_se6_tx: qupv3_se6_tx {
+				mux {
+					pins = "gpio47";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio47";
+					drive-strength = <2>;
+					bias-pull-up;
 				};
 			};
 		};
@@ -2985,6 +2993,119 @@
 			};
 		};
 
+		cam_sensor_fisheye_active: cam_sensor_fisheye_active {
+			/* RESET, AVDD LO */
+			mux {
+				pins = "gpio76","gpio75";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio76","gpio75";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_fisheye_suspend: cam_sensor_fisheye_suspend {
+			/* RESET, AVDD LO*/
+			mux {
+				pins = "gpio76","gpio75";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio76","gpio75";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+				output-low;
+			};
+		};
+
+		cam_sensor_depth_active: cam_sensor_depth_active {
+			/* RESET,AVDD LO ,IMG_START, ILLU_EN */
+			mux {
+				pins = "gpio28","gpio23","gpio24";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio28","gpio23","gpio24";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_depth_suspend: cam_sensor_depth_suspend {
+			/* RESET, AVDD LO ,IMG_START, ILLU_EN */
+			mux {
+				pins = "gpio28","gpio23","gpio24";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio28","gpio23","gpio24";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		max_rst_active: max_rst_active {
+			/* RESET */
+			mux {
+				pins = "gpio31","gpio77","gpio78","gpio32";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio31","gpio77","gpio78","gpio32";
+				bias-disable; /* No PULL */
+				drive-strength = <8>; /* 2 MA */
+			};
+		};
+
+		max_rst_suspend: max_rst_suspend {
+			/* RESET */
+			mux {
+				pins = "gpio31","gpio77","gpio78","gpio32";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio31","gpio77","gpio78","gpio32";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <8>; /* 2 MA */
+			};
+		};
+
+		max_6dof_active: max_6dof_active {
+			/* RESET */
+			mux {
+				pins = "gpio30","gpio95","gpio94";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio30","gpio95","gpio94";
+				bias-disable; /* No PULL */
+				drive-strength = <8>; /* 2 MA */
+			};
+		};
+
+		max_6dof_suspend: max_6dof_suspend {
+			/* RESET */
+			mux {
+				pins = "gpio30","gpio95","gpio94";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio30","gpio95","gpio94";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <8>; /* 2 MA */
+			};
+		};
+
 		cam_sensor_mclk0_active: cam_sensor_mclk0_active {
 			/* MCLK0 */
 			mux {
@@ -3151,7 +3272,7 @@
 
 			config {
 				pins = "gpio9";
-				bias-disable; /* No PULL */
+				bias-pull-down; /* PULL DOWN */
 				drive-strength = <2>; /* 2 MA */
 				output-low;
 			};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index ee10cfc..929239a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -140,7 +140,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 3ee0138..6034b6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,6 +12,7 @@
 
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-qrd.dtsi"
 #include "smb1355.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
@@ -82,7 +83,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -90,8 +90,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
index 5fce5ff..097c3ac 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -40,8 +40,10 @@
 			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
 			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
 		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&qupv3_se6_4uart_active>;
-		pinctrl-1 = <&qupv3_se6_4uart_sleep>;
+		pinctrl-0 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>,
+							<&qupv3_se6_tx> ;
+		pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>,
+							<&qupv3_se6_tx> ;
 		interrupts-extended = <&pdc GIC_SPI 607 0>,
 				<&tlmm 48 0>;
 		status = "disabled";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index dd4e0b1..8b67649 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -28,6 +28,7 @@
 #include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
 #include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
 #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
+#include "dsi-panel-test-dualmipi-oled-cmd.dtsi"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
 &soc {
@@ -476,6 +477,31 @@
 		ibb-supply = <&ibb_regulator>;
 	};
 
+	dsi_dual_test_cmd_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_dual_test_cmd";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+				<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		pinctrl-names = "panel_active", "panel_suspend";
+		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+		qcom,platform-te-gpio = <&tlmm 10 0>;
+		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
+
+		qcom,dsi-panel = <&dsi_dual_test_cmd>;
+		vddio-supply = <&pm8998_l14>;
+		lab-supply = <&lab_regulator>;
+		ibb-supply = <&ibb_regulator>;
+		oled-vdda-supply = <&pm8998_l22>;
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 4194e67..bfcebf6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -233,6 +233,7 @@
 			qcom,sde-dspp-pcc = <0x1700 0x00040000>;
 			qcom,sde-dspp-gc = <0x17c0 0x00010008>;
 			qcom,sde-dspp-hist = <0x800 0x00010007>;
+			qcom,sde-dspp-dither = <0x82c 0x00010007>;
 		};
 
 		qcom,platform-supply-entries {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 05d77d3..85419c8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -161,9 +161,7 @@
 		msm_cam_smmu_lrme {
 			compatible = "qcom,msm-cam-smmu-cb";
 			iommus = <&apps_smmu 0x1038 0x0>,
-				<&apps_smmu 0x1058 0x0>,
-				<&apps_smmu 0x1039 0x0>,
-				<&apps_smmu 0x1059 0x0>;
+				<&apps_smmu 0x1058 0x0>;
 			label = "lrme";
 			lrme_iova_mem_map: iova-mem-map {
 				iova-mem-region-shared {
@@ -248,13 +246,23 @@
 				};
 
 				iova-mem-region-io {
-					/* IO region is approximately 3.3 GB */
+					/* IO region is approximately 3 GB */
 					iova-region-name = "io";
-					iova-region-start = <0xd900000>;
-					iova-region-len = <0xd2700000>;
+					iova-region-start = <0xd911000>;
+					iova-region-len = <0xd26ef000>;
 					iova-region-id = <0x3>;
 					status = "ok";
 				};
+
+				iova-mem-qdss-region {
+					/* qdss region is approximately 64K */
+					iova-region-name = "qdss";
+					iova-region-start = <0xd900000>;
+					iova-region-len = <0x10000>;
+					iova-region-id = <0x5>;
+					qdss-phy-addr = <0x16790000>;
+					status = "ok";
+				};
 			};
 		};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
index c629c53..7dd7017 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi
@@ -11,5 +11,5 @@
  */
 #include "sdm845-qvr.dtsi"
 #include "sdm845-sde-display.dtsi"
-#include "sdm845-camera-sensor-qvr.dtsi"
+#include "sdm845-camera-sensor-qvr-dvt.dtsi"
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index d138094..575cf12 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -51,6 +51,7 @@
 			compatible = "qcom,memshare-peripheral";
 			qcom,peripheral-size = <0x500000>;
 			qcom,client-id = <1>;
+			qcom,allocate-boot-time;
 			label = "modem";
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 7832165..a667b01 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -87,7 +87,7 @@
 				qcom,dump-size = <0xa000>;
 			};
 			L1_TLB_0: l1-tlb {
-				qcom,dump-size = <0x3000>;
+				qcom,dump-size = <0x6000>;
 			};
 		};
 
@@ -118,7 +118,7 @@
 				qcom,dump-size = <0xa000>;
 			};
 			L1_TLB_100: l1-tlb {
-				qcom,dump-size = <0x3000>;
+				qcom,dump-size = <0x6000>;
 			};
 		};
 
@@ -149,7 +149,7 @@
 				qcom,dump-size = <0xa000>;
 			};
 			L1_TLB_200: l1-tlb {
-				qcom,dump-size = <0x3000>;
+				qcom,dump-size = <0x6000>;
 			};
 		};
 
@@ -180,7 +180,7 @@
 				qcom,dump-size = <0xa000>;
 			};
 			L1_TLB_300: l1-tlb {
-				qcom,dump-size = <0x3000>;
+				qcom,dump-size = <0x6000>;
 			};
 		};
 
@@ -211,7 +211,7 @@
 				qcom,dump-size = <0x14000>;
 			};
 			L1_TLB_400: l1-tlb {
-				qcom,dump-size = <0x3c00>;
+				qcom,dump-size = <0x6800>;
 			};
 		};
 
@@ -242,7 +242,7 @@
 				qcom,dump-size = <0x14000>;
 			};
 			L1_TLB_500: l1-tlb {
-				qcom,dump-size = <0x3c00>;
+				qcom,dump-size = <0x6800>;
 			};
 		};
 
@@ -273,7 +273,7 @@
 				qcom,dump-size = <0x14000>;
 			};
 			L1_TLB_600: l1-tlb {
-				qcom,dump-size = <0x3c00>;
+				qcom,dump-size = <0x6800>;
 			};
 		};
 
@@ -304,7 +304,7 @@
 				qcom,dump-size = <0x14000>;
 			};
 			L1_TLB_700: l1-tlb {
-				qcom,dump-size = <0x3c00>;
+				qcom,dump-size = <0x6800>;
 			};
 		};
 
@@ -2045,35 +2045,35 @@
 		};
 		qcom,l1_tlb_dump0 {
 			qcom,dump-node = <&L1_TLB_0>;
-			qcom,dump-id = <0x20>;
+			qcom,dump-id = <0x120>;
 		};
 		qcom,l1_tlb_dump100 {
 			qcom,dump-node = <&L1_TLB_100>;
-			qcom,dump-id = <0x21>;
+			qcom,dump-id = <0x121>;
 		};
 		qcom,l1_tlb_dump200 {
 			qcom,dump-node = <&L1_TLB_200>;
-			qcom,dump-id = <0x22>;
+			qcom,dump-id = <0x122>;
 		};
 		qcom,l1_tlb_dump300 {
 			qcom,dump-node = <&L1_TLB_300>;
-			qcom,dump-id = <0x23>;
+			qcom,dump-id = <0x123>;
 		};
 		qcom,l1_tlb_dump400 {
 			qcom,dump-node = <&L1_TLB_400>;
-			qcom,dump-id = <0x24>;
+			qcom,dump-id = <0x124>;
 		};
 		qcom,l1_tlb_dump500 {
 			qcom,dump-node = <&L1_TLB_500>;
-			qcom,dump-id = <0x25>;
+			qcom,dump-id = <0x125>;
 		};
 		qcom,l1_tlb_dump600 {
 			qcom,dump-node = <&L1_TLB_600>;
-			qcom,dump-id = <0x26>;
+			qcom,dump-id = <0x126>;
 		};
 		qcom,l1_tlb_dump700 {
 			qcom,dump-node = <&L1_TLB_700>;
-			qcom,dump-id = <0x27>;
+			qcom,dump-id = <0x127>;
 		};
 	};
 
@@ -3080,6 +3080,7 @@
 			     <0 425 0 /* CE11 */ >;
 		qcom,wlan-msa-memory = <0x100000>;
 		qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+		qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
 
 		vdd-0.8-cx-mx-supply = <&pm8998_l5>;
 		vdd-1.8-xo-supply = <&pm8998_l7>;
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 801c66a..6859413 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -52,8 +52,11 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -274,6 +277,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
 CONFIG_INPUT_EVDEV=y
@@ -288,13 +292,14 @@
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -305,6 +310,8 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
@@ -317,8 +324,10 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -333,8 +342,11 @@
 CONFIG_QTI_VIRTUAL_SENSOR=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
 CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
@@ -350,14 +362,47 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_CAMERA_DEBUG=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI20_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI31_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_EEPROM=y
+CONFIG_MSM_ISPIF=y
+CONFIG_IMX134=y
+CONFIG_IMX132=y
+CONFIG_OV9724=y
+CONFIG_OV5648=y
+CONFIG_GC0339=y
+CONFIG_OV8825=y
+CONFIG_OV8865=y
+CONFIG_s5k4e1=y
+CONFIG_OV12830=y
+CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_FD=y
+CONFIG_MSM_JPEGDMA=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -380,6 +425,7 @@
 CONFIG_USB_MON=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -408,10 +454,12 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_NCM=y
 CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
 CONFIG_USB_CONFIGFS_RMNET_BAM=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
@@ -420,8 +468,11 @@
 CONFIG_USB_CONFIGFS_F_ACC=y
 CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
 CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -435,14 +486,15 @@
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_SDHCI_MSM_ICE=y
 CONFIG_MMC_CQ_HCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
 CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
@@ -464,10 +516,12 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_MSM_SPM=y
 CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
@@ -492,18 +546,33 @@
 CONFIG_ICNSS=y
 CONFIG_MSM_PERFORMANCE=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
 CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
 CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index 009c420..8c81b28 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -56,8 +56,11 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -284,6 +287,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
 CONFIG_INPUT_EVDEV=y
@@ -302,9 +306,12 @@
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -315,6 +322,8 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
+CONFIG_PINCTRL_MSM8917=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
@@ -327,8 +336,10 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -343,8 +354,11 @@
 CONFIG_QTI_VIRTUAL_SENSOR=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
 CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
@@ -360,8 +374,36 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_CAMERA_DEBUG=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI20_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI31_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_EEPROM=y
+CONFIG_MSM_ISPIF=y
+CONFIG_IMX134=y
+CONFIG_IMX132=y
+CONFIG_OV9724=y
+CONFIG_OV5648=y
+CONFIG_GC0339=y
+CONFIG_OV8825=y
+CONFIG_OV8865=y
+CONFIG_s5k4e1=y
+CONFIG_OV12830=y
+CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_FD=y
+CONFIG_MSM_JPEGDMA=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
@@ -369,6 +411,11 @@
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
 CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -391,6 +438,7 @@
 CONFIG_USB_MON=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
@@ -419,10 +467,12 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_CONFIGFS=y
 CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_NCM=y
 CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RNDIS=y
 CONFIG_USB_CONFIGFS_RMNET_BAM=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
@@ -431,8 +481,11 @@
 CONFIG_USB_CONFIGFS_F_ACC=y
 CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
 CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -447,14 +500,15 @@
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_SDHCI_MSM_ICE=y
 CONFIG_MMC_CQ_HCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
 CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
@@ -476,6 +530,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
@@ -483,6 +538,7 @@
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_DEBUG_TRACKING=y
 CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_MSM_SPM=y
 CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
@@ -510,18 +566,26 @@
 CONFIG_ICNSS=y
 CONFIG_MSM_PERFORMANCE=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_PM=y
 CONFIG_QCOM_DCC=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_MSM_BAM_DMUX=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
 CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
@@ -565,6 +629,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 8aa1e7d..560c510 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -378,6 +378,7 @@
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_DRM_LT_LT9611=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -440,7 +441,6 @@
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 8022e88..0e8ef8f 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -384,6 +384,7 @@
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_DRM_LT_LT9611=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -446,7 +447,6 @@
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
 CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
@@ -524,6 +524,7 @@
 CONFIG_MSM_GLADIATOR_ERP=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QPNP_PBS=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_MINIDUMP=y
@@ -621,7 +622,6 @@
 CONFIG_DEBUG_OBJECTS_FREE=y
 CONFIG_DEBUG_OBJECTS_TIMERS=y
 CONFIG_DEBUG_OBJECTS_WORK=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_SLUB_DEBUG_ON=y
 CONFIG_DEBUG_KMEMLEAK=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index f7ef61e..0c67988 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -224,6 +224,7 @@
 CONFIG_RMNET_DATA=y
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
 CONFIG_BT=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
@@ -247,13 +248,11 @@
 CONFIG_CHR_DEV_SG=y
 CONFIG_CHR_DEV_SCH=y
 CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_SCSI_UFSHCD=y
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_DEBUG=y
@@ -290,6 +289,11 @@
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -568,6 +572,8 @@
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_EXT4_FS_ENCRYPTION=y
 CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -606,6 +612,7 @@
 CONFIG_FORTIFY_SOURCE=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_GCM=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index a4f0ffa..a3da988 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -229,6 +229,7 @@
 CONFIG_RMNET_DATA=y
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
 CONFIG_BT=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
@@ -294,6 +295,11 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -519,6 +525,7 @@
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
@@ -585,6 +592,8 @@
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_EXT4_FS_ENCRYPTION=y
 CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -671,6 +680,7 @@
 CONFIG_FORTIFY_SOURCE=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_GCM=y
 CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 46d0448..88a4d1e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -25,6 +25,7 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/cpufeature.h>
+#include <asm/cputype.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
@@ -452,4 +453,43 @@
 	mrs	\rd, sp_el0
 	.endm
 
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ *	model:		MIDR_CPU_MODEL of CPU
+ *	rv_min:		Minimum of MIDR_CPU_VAR_REV()
+ *	rv_max:		Maximum of MIDR_CPU_VAR_REV()
+ *	res:		Result register.
+ *	tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns:  0, if the CPU id doesn't match. Non-zero otherwise
+ */
+	.macro	cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+	mrs		\res, midr_el1
+	mov_q		\tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+	mov_q		\tmp2, MIDR_CPU_MODEL_MASK
+	and		\tmp3, \res, \tmp2	// Extract model
+	and		\tmp1, \res, \tmp1	// rev & variant
+	mov_q		\tmp2, \model
+	cmp		\tmp3, \tmp2
+	cset		\res, eq
+	cbz		\res, .Ldone\@		// Model matches ?
+
+	.if (\rv_min != 0)			// Skip min check if rv_min == 0
+	mov_q		\tmp3, \rv_min
+	cmp		\tmp1, \tmp3
+	cset		\res, ge
+	.endif					// \rv_min != 0
+	/* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+	.if ((\rv_min != \rv_max) || \rv_min == 0)
+	mov_q		\tmp2, \rv_max
+	cmp		\tmp1, \tmp2
+	cset		\tmp2, le
+	and		\res, \res, \tmp2
+	.endif
+.Ldone\@:
+	.endm
+
 #endif	/* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ddbf3b1..c088c4f 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -56,6 +56,9 @@
 	(0xf			<< MIDR_ARCHITECTURE_SHIFT) | \
 	((partnum)		<< MIDR_PARTNUM_SHIFT))
 
+#define MIDR_CPU_VAR_REV(var, rev) \
+	(((var)	<< MIDR_VARIANT_SHIFT) | (rev))
+
 #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
 			     MIDR_ARCHITECTURE_MASK)
 
@@ -79,7 +82,9 @@
 #define ARM_CPU_PART_CORTEX_A53		0xD03
 #define ARM_CPU_PART_CORTEX_A73		0xD09
 #define ARM_CPU_PART_CORTEX_A75		0xD0A
+#define ARM_CPU_PART_KRYO3S		0x803
 #define ARM_CPU_PART_KRYO3G		0x802
+#define ARM_CPU_PART_CORTEX_A55		0xD05
 
 #define APM_CPU_PART_POTENZA		0x000
 
@@ -93,7 +98,9 @@
 #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
 #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
 #define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+#define MIDR_KRYO3S	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3S)
 #define MIDR_KRYO3G	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3G)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 4e7eec7..ea06f3f 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -82,19 +82,21 @@
 		if (mm != current->active_mm) {
 			/*
 			 * Update the current thread's saved ttbr0 since it is
-			 * restored as part of a return from exception. Set
-			 * the hardware TTBR0_EL1 using cpu_switch_mm()
-			 * directly to enable potential errata workarounds.
+			 * restored as part of a return from exception. Enable
+			 * access to the valid TTBR0_EL1 and invoke the errata
+			 * workaround directly since there is no return from
+			 * exception when invoking the EFI run-time services.
 			 */
 			update_saved_ttbr0(current, mm);
-			cpu_switch_mm(mm->pgd, mm);
+			uaccess_ttbr0_enable();
+			post_ttbr_update_workaround();
 		} else {
 			/*
 			 * Defer the switch to the current thread's TTBR0_EL1
 			 * until uaccess_enable(). Restore the current
 			 * thread's saved ttbr0 corresponding to its active_mm
 			 */
-			cpu_set_reserved_ttbr0();
+			uaccess_ttbr0_disable();
 			update_saved_ttbr0(current, current->active_mm);
 		}
 	}
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index af0215a..a0fac5c 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -177,7 +177,7 @@
 	else
 		ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
 
-	task_thread_info(tsk)->ttbr0 = ttbr;
+	WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr);
 }
 #else
 static inline void update_saved_ttbr0(struct task_struct *tsk,
@@ -232,5 +232,6 @@
 #define activate_mm(prev,next)	switch_mm(prev, next, current)
 
 void verify_cpu_asid_bits(void);
+void post_ttbr_update_workaround(void);
 
 #endif
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 8b38b0d..9311547 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -132,16 +132,18 @@
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 static inline void __uaccess_ttbr0_disable(void)
 {
-	unsigned long ttbr;
+	unsigned long flags, ttbr;
 
+	local_irq_save(flags);
 	ttbr = read_sysreg(ttbr1_el1);
+	ttbr &= ~TTBR_ASID_MASK;
 	/* reserved_ttbr0 placed at the end of swapper_pg_dir */
 	write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1);
 	isb();
 	/* Set reserved ASID */
-	ttbr &= ~TTBR_ASID_MASK;
 	write_sysreg(ttbr, ttbr1_el1);
 	isb();
+	local_irq_restore(flags);
 }
 
 static inline void __uaccess_ttbr0_enable(void)
@@ -154,10 +156,11 @@
 	 * roll-over and an update of 'ttbr0'.
 	 */
 	local_irq_save(flags);
-	ttbr0 = current_thread_info()->ttbr0;
+	ttbr0 = READ_ONCE(current_thread_info()->ttbr0);
 
 	/* Restore active ASID */
 	ttbr1 = read_sysreg(ttbr1_el1);
+	ttbr1 &= ~TTBR_ASID_MASK;		/* safety measure */
 	ttbr1 |= ttbr0 & TTBR_ASID_MASK;
 	write_sysreg(ttbr1, ttbr1_el1);
 	isb();
@@ -450,11 +453,11 @@
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	.macro	__uaccess_ttbr0_disable, tmp1
 	mrs	\tmp1, ttbr1_el1		// swapper_pg_dir
+	bic     \tmp1, \tmp1, #TTBR_ASID_MASK
 	add	\tmp1, \tmp1, #SWAPPER_DIR_SIZE	// reserved_ttbr0 at the end of swapper_pg_dir
 	msr	ttbr0_el1, \tmp1		// set reserved TTBR0_EL1
 	isb
 	sub     \tmp1, \tmp1, #SWAPPER_DIR_SIZE
-	bic     \tmp1, \tmp1, #TTBR_ASID_MASK
 	msr     ttbr1_el1, \tmp1                // set reserved ASID
 	isb
 	.endm
@@ -471,9 +474,11 @@
 	isb
 	.endm
 
-	.macro	uaccess_ttbr0_disable, tmp1
+	.macro	uaccess_ttbr0_disable, tmp1, tmp2
 alternative_if_not ARM64_HAS_PAN
+	save_and_disable_irq \tmp2		// avoid preemption
 	__uaccess_ttbr0_disable \tmp1
+	restore_irq \tmp2
 alternative_else_nop_endif
 	.endm
 
@@ -485,7 +490,7 @@
 alternative_else_nop_endif
 	.endm
 #else
-	.macro	uaccess_ttbr0_disable, tmp1
+	.macro	uaccess_ttbr0_disable, tmp1, tmp2
 	.endm
 
 	.macro	uaccess_ttbr0_enable, tmp1, tmp2, tmp3
@@ -495,8 +500,8 @@
 /*
  * These macros are no-ops when UAO is present.
  */
-	.macro	uaccess_disable_not_uao, tmp1
-	uaccess_ttbr0_disable \tmp1
+	.macro	uaccess_disable_not_uao, tmp1, tmp2
+	uaccess_ttbr0_disable \tmp1, \tmp2
 alternative_if ARM64_ALT_PAN_NOT_UAO
 	SET_PSTATE_PAN(1)
 alternative_else_nop_endif
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 653359b..c7b3ba68 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -180,8 +180,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 832075",
 		.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_834220
@@ -189,8 +190,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 834220",
 		.capability = ARM64_WORKAROUND_834220,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_845719
@@ -214,8 +216,9 @@
 	/* Cavium ThunderX, T88 pass 1.x - 2.1 */
 		.desc = "Cavium erratum 27456",
 		.capability = ARM64_WORKAROUND_CAVIUM_27456,
-		MIDR_RANGE(MIDR_THUNDERX, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 1),
+		MIDR_RANGE(MIDR_THUNDERX,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 1)),
 	},
 	{
 	/* Cavium ThunderX, T81 pass 1.0 */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 80ff3df5..5cf4c64 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -722,13 +722,11 @@
 static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
 {
 	u32 midr = read_cpuid_id();
-	u32 rv_min, rv_max;
 
 	/* Cavium ThunderX pass 1.x and 2.x */
-	rv_min = 0;
-	rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
-
-	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
+		MIDR_CPU_VAR_REV(0, 0),
+		MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
 }
 
 static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 8030583..3b22fa3 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -150,7 +150,7 @@
 alternative_else_nop_endif
 
 	.if	\el != 0
-	mrs	x21, ttbr1_el1
+	mrs	x21, ttbr0_el1
 	tst	x21, #TTBR_ASID_MASK		// Check for the reserved ASID
 	orr	x23, x23, #PSR_PAN_BIT		// Set the emulated PAN in the saved SPSR
 	b.eq	1f				// TTBR0 access already disabled
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 85baada..2e6e9e9 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -44,7 +44,7 @@
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -53,7 +53,7 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
index dd65ca2..07c7ad9 100644
--- a/arch/arm64/lib/clear_user.S
+++ b/arch/arm64/lib/clear_user.S
@@ -50,7 +50,7 @@
 	b.mi	5f
 uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
 5:	mov	x0, #0
-	uaccess_disable_not_uao x2
+	uaccess_disable_not_uao x2, x3
 	ret
 ENDPROC(__clear_user)
 
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
index 7e7e687..c7a7d96 100644
--- a/arch/arm64/lib/copy_from_user.S
+++ b/arch/arm64/lib/copy_from_user.S
@@ -67,7 +67,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0				// Nothing to copy
 	ret
 ENDPROC(__arch_copy_from_user)
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
index 074d52f..e8bfaf1 100644
--- a/arch/arm64/lib/copy_in_user.S
+++ b/arch/arm64/lib/copy_in_user.S
@@ -68,7 +68,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0
 	ret
 ENDPROC(__copy_in_user)
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
index 6711844..f6cfcc0 100644
--- a/arch/arm64/lib/copy_to_user.S
+++ b/arch/arm64/lib/copy_to_user.S
@@ -66,7 +66,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0
 	ret
 ENDPROC(__arch_copy_to_user)
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 9dd6d32..b98b3fc 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -145,7 +145,7 @@
 	isb
 	mov	x0, #0
 1:
-	uaccess_ttbr0_disable x1
+	uaccess_ttbr0_disable x1, x2
 	ret
 9:
 	mov	x0, #-EFAULT
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index c66fa93..63001be 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -823,6 +823,10 @@
 
 int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
 {
+	/* ioremap_page_range doesn't honour BBM */
+	if (pud_present(READ_ONCE(*pud)))
+		return 0;
+
 	BUG_ON(phys & ~PUD_MASK);
 	set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
 	return 1;
@@ -830,6 +834,10 @@
 
 int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
 {
+	/* ioremap_page_range doesn't honour BBM */
+	if (pmd_present(READ_ONCE(*pmd)))
+		return 0;
+
 	BUG_ON(phys & ~PMD_MASK);
 	set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
 	return 1;
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index fa20d13..2e69a14 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -186,6 +186,9 @@
 ENTRY(cpu_do_switch_mm)
 	mrs	x2, ttbr1_el1
 	mmid	x1, x1				// get mm->context.id
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+	bfi	x0, x1, #48, #16		// set the ASID field in TTBR0
+#endif
 	bfi	x2, x1, #48, #16		// set the ASID
 	msr	ttbr1_el1, x2			// in TTBR1 (since TCR.A1 is set)
 	isb
@@ -290,6 +293,12 @@
 	cbz	x9, 2f
 	cmp	x9, #2
 	b.lt	1f
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+	/* Disable hardware DBM on Kryo3S */
+	cpu_midr_match MIDR_KRYO3S, MIDR_CPU_VAR_REV(7, 12), \
+			MIDR_CPU_VAR_REV(7, 13), x1, x2, x3, x4
+	cbnz	x1, 1f
+#endif
 	orr	x10, x10, #TCR_HD		// hardware Dirty flag update
 1:	orr	x10, x10, #TCR_HA		// hardware Access flag update
 2:
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
index f542252..69711f2 100644
--- a/arch/arm64/xen/hypercall.S
+++ b/arch/arm64/xen/hypercall.S
@@ -106,6 +106,6 @@
 	/*
 	 * Disable userspace access from kernel once the hyp call completed.
 	 */
-	uaccess_ttbr0_disable x6
+	uaccess_ttbr0_disable x6, x7
 	ret
 ENDPROC(privcmd_call);
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index 3446b6f..9da4e22 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -576,7 +576,7 @@
 	uart_port.type		= PORT_AR7;
 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
 	uart_port.iotype	= UPIO_MEM32;
-	uart_port.flags		= UPF_FIXED_TYPE;
+	uart_port.flags		= UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF;
 	uart_port.regshift	= 2;
 
 	uart_port.line		= 0;
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index b9920b1..70cef54 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -437,7 +437,7 @@
 
 	info.si_signo	= SIGSEGV;
 	info.si_errno	= 0;
-	info.si_code	= 0;
+	info.si_code	= SEGV_MAPERR;
 	info.si_addr	= (void *) regs->pc;
 	force_sig_info(SIGSEGV, &info, current);
 	return;
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index 3d3f606..605a284 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -302,12 +302,12 @@
 	siginfo_t info;
 
 	if (user_mode(regs)) {
-		/* Send a SIGSEGV */
-		info.si_signo = SIGSEGV;
+		/* Send a SIGBUS */
+		info.si_signo = SIGBUS;
 		info.si_errno = 0;
-		/* info.si_code has been set above */
-		info.si_addr = (void *)address;
-		force_sig_info(SIGSEGV, &info, current);
+		info.si_code = BUS_ADRALN;
+		info.si_addr = (void __user *)address;
+		force_sig_info(SIGBUS, &info, current);
 	} else {
 		printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
 		show_registers(regs);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index acb6026..bc11d709f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -129,6 +129,7 @@
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_CMOS_UPDATE
+	select GENERIC_CPU_VULNERABILITIES	if PPC_BOOK3S_64
 	select GENERIC_TIME_VSYSCALL_OLD
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
index a703452..555e22d 100644
--- a/arch/powerpc/include/asm/exception-64e.h
+++ b/arch/powerpc/include/asm/exception-64e.h
@@ -209,5 +209,11 @@
 	ori	r3,r3,vector_offset@l;		\
 	mtspr	SPRN_IVOR##vector_number,r3;
 
+#define RFI_TO_KERNEL							\
+	rfi
+
+#define RFI_TO_USER							\
+	rfi
+
 #endif /* _ASM_POWERPC_EXCEPTION_64E_H */
 
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 9a3eee6..cab6d2a 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -51,6 +51,59 @@
 #define EX_PPR		88	/* SMT thread status register (priority) */
 #define EX_CTR		96
 
+/*
+ * Macros for annotating the expected destination of (h)rfid
+ *
+ * The nop instructions allow us to insert one or more instructions to flush the
+ * L1-D cache when returning to userspace or a guest.
+ */
+#define RFI_FLUSH_SLOT							\
+	RFI_FLUSH_FIXUP_SECTION;					\
+	nop;								\
+	nop;								\
+	nop
+
+#define RFI_TO_KERNEL							\
+	rfid
+
+#define RFI_TO_USER							\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define RFI_TO_USER_OR_KERNEL						\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define RFI_TO_GUEST							\
+	RFI_FLUSH_SLOT;							\
+	rfid;								\
+	b	rfi_flush_fallback
+
+#define HRFI_TO_KERNEL							\
+	hrfid
+
+#define HRFI_TO_USER							\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_USER_OR_KERNEL						\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_GUEST							\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
+#define HRFI_TO_UNKNOWN							\
+	RFI_FLUSH_SLOT;							\
+	hrfid;								\
+	b	hrfi_flush_fallback
+
 #ifdef CONFIG_RELOCATABLE
 #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)			\
 	mfspr	r11,SPRN_##h##SRR0;	/* save SRR0 */			\
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index ddf54f5..7b33234 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -189,4 +189,19 @@
 void setup_feature_keys(void);
 #endif
 
+#define RFI_FLUSH_FIXUP_SECTION				\
+951:							\
+	.pushsection __rfi_flush_fixup,"a";		\
+	.align 2;					\
+952:							\
+	FTR_ENTRY_OFFSET 951b-952b;			\
+	.popsection;
+
+
+#ifndef __ASSEMBLY__
+
+extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
+
+#endif
+
 #endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 708edeb..dc0996b 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -240,6 +240,7 @@
 #define H_GET_HCA_INFO          0x1B8
 #define H_GET_PERF_COUNT        0x1BC
 #define H_MANAGE_TRACE          0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
 #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
 #define H_QUERY_INT_STATE       0x1E4
 #define H_POLL_PENDING		0x1D8
@@ -306,7 +307,19 @@
 #define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE	3
 #define H_SET_MODE_RESOURCE_LE			4
 
+/* H_GET_CPU_CHARACTERISTICS return values */
+#define H_CPU_CHAR_SPEC_BAR_ORI31	(1ull << 63) // IBM bit 0
+#define H_CPU_CHAR_BCCTRL_SERIALISED	(1ull << 62) // IBM bit 1
+#define H_CPU_CHAR_L1D_FLUSH_ORI30	(1ull << 61) // IBM bit 2
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2	(1ull << 60) // IBM bit 3
+#define H_CPU_CHAR_L1D_THREAD_PRIV	(1ull << 59) // IBM bit 4
+
+#define H_CPU_BEHAV_FAVOUR_SECURITY	(1ull << 63) // IBM bit 0
+#define H_CPU_BEHAV_L1D_FLUSH_PR	(1ull << 62) // IBM bit 1
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR	(1ull << 61) // IBM bit 2
+
 #ifndef __ASSEMBLY__
+#include <linux/types.h>
 
 /**
  * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
@@ -433,6 +446,11 @@
 }
 #endif /* CONFIG_PPC_PSERIES */
 
+struct h_cpu_char_result {
+	u64 character;
+	u64 behaviour;
+};
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 6a6792b..ea43897 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -205,6 +205,16 @@
 	struct sibling_subcore_state *sibling_subcore_state;
 #endif
 #endif
+#ifdef CONFIG_PPC_BOOK3S_64
+	/*
+	 * rfi fallback flush must be in its own cacheline to prevent
+	 * other paca data leaking into the L1d
+	 */
+	u64 exrfi[13] __aligned(0x80);
+	void *rfi_flush_fallback_area;
+	u64 l1d_flush_congruence;
+	u64 l1d_flush_sets;
+#endif
 };
 
 #ifdef CONFIG_PPC_BOOK3S
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
index 1b39424..4e53b85 100644
--- a/arch/powerpc/include/asm/plpar_wrappers.h
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -340,4 +340,18 @@
 	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
 }
 
+static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
+{
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+	long rc;
+
+	rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
+	if (rc == H_SUCCESS) {
+		p->character = retbuf[0];
+		p->behaviour = retbuf[1];
+	}
+
+	return rc;
+}
+
 #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
index 654d64c..6825a67 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -38,6 +38,19 @@
 static inline void pseries_little_endian_exceptions(void) {}
 #endif /* CONFIG_PPC_PSERIES */
 
+void rfi_flush_enable(bool enable);
+
+/* These are bit flags */
+enum l1d_flush_type {
+	L1D_FLUSH_NONE		= 0x1,
+	L1D_FLUSH_FALLBACK	= 0x2,
+	L1D_FLUSH_ORI		= 0x4,
+	L1D_FLUSH_MTTRIG	= 0x8,
+};
+
+void __init setup_rfi_flush(enum l1d_flush_type, bool enable);
+void do_rfi_flush_fixups(enum l1d_flush_type types);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif	/* _ASM_POWERPC_SETUP_H */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index c833d88..64bcbd5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -240,6 +240,10 @@
 #ifdef CONFIG_PPC_BOOK3S_64
 	DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
 	DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
+	DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area));
+	DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi));
+	DEFINE(PACA_L1D_FLUSH_CONGRUENCE, offsetof(struct paca_struct, l1d_flush_congruence));
+	DEFINE(PACA_L1D_FLUSH_SETS, offsetof(struct paca_struct, l1d_flush_sets));
 #endif
 	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
 	DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index caa6596..c33b69d 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -251,13 +251,23 @@
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 
 	ld	r13,GPR13(r1)	/* only restore r13 if returning to usermode */
+	ld	r2,GPR2(r1)
+	ld	r1,GPR1(r1)
+	mtlr	r4
+	mtcr	r5
+	mtspr	SPRN_SRR0,r7
+	mtspr	SPRN_SRR1,r8
+	RFI_TO_USER
+	b	.	/* prevent speculative execution */
+
+	/* exit to kernel */
 1:	ld	r2,GPR2(r1)
 	ld	r1,GPR1(r1)
 	mtlr	r4
 	mtcr	r5
 	mtspr	SPRN_SRR0,r7
 	mtspr	SPRN_SRR1,r8
-	RFI
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 syscall_error:	
@@ -859,7 +869,7 @@
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 	ACCOUNT_CPU_USER_EXIT(r13, r2, r4)
 	REST_GPR(13, r1)
-1:
+
 	mtspr	SPRN_SRR1,r3
 
 	ld	r2,_CCR(r1)
@@ -872,8 +882,22 @@
 	ld	r3,GPR3(r1)
 	ld	r4,GPR4(r1)
 	ld	r1,GPR1(r1)
+	RFI_TO_USER
+	b	.	/* prevent speculative execution */
 
-	rfid
+1:	mtspr	SPRN_SRR1,r3
+
+	ld	r2,_CCR(r1)
+	mtcrf	0xFF,r2
+	ld	r2,_NIP(r1)
+	mtspr	SPRN_SRR0,r2
+
+	ld	r0,GPR0(r1)
+	ld	r2,GPR2(r1)
+	ld	r3,GPR3(r1)
+	ld	r4,GPR4(r1)
+	ld	r1,GPR1(r1)
+	RFI_TO_KERNEL
 	b	.	/* prevent speculative execution */
 
 #endif /* CONFIG_PPC_BOOK3E */
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index fd68e19..96db6c3 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -655,6 +655,8 @@
 
 	andi.	r10,r12,MSR_RI	/* check for unrecoverable exception */
 	beq-	2f
+	andi.	r10,r12,MSR_PR	/* check for user mode (PR != 0) */
+	bne	1f
 
 	/* All done -- return from exception. */
 
@@ -671,7 +673,23 @@
 	ld	r11,PACA_EXSLB+EX_R11(r13)
 	ld	r12,PACA_EXSLB+EX_R12(r13)
 	ld	r13,PACA_EXSLB+EX_R13(r13)
-	rfid
+	RFI_TO_KERNEL
+	b	.	/* prevent speculative execution */
+
+1:
+.machine	push
+.machine	"power4"
+	mtcrf	0x80,r9
+	mtcrf	0x01,r9		/* slb_allocate uses cr0 and cr7 */
+.machine	pop
+
+	RESTORE_PPR_PACA(PACA_EXSLB, r9)
+	ld	r9,PACA_EXSLB+EX_R9(r13)
+	ld	r10,PACA_EXSLB+EX_R10(r13)
+	ld	r11,PACA_EXSLB+EX_R11(r13)
+	ld	r12,PACA_EXSLB+EX_R12(r13)
+	ld	r13,PACA_EXSLB+EX_R13(r13)
+	RFI_TO_USER
 	b	.	/* prevent speculative execution */
 
 2:	mfspr	r11,SPRN_SRR0
@@ -679,7 +697,7 @@
 	mtspr	SPRN_SRR0,r10
 	ld	r10,PACAKMSR(r13)
 	mtspr	SPRN_SRR1,r10
-	rfid
+	RFI_TO_KERNEL
 	b	.
 
 8:	mfspr	r11,SPRN_SRR0
@@ -1576,6 +1594,92 @@
 	bl	kernel_bad_stack
 	b	1b
 
+	.globl rfi_flush_fallback
+rfi_flush_fallback:
+	SET_SCRATCH0(r13);
+	GET_PACA(r13);
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	std	r11,PACA_EXRFI+EX_R11(r13)
+	std	r12,PACA_EXRFI+EX_R12(r13)
+	std	r8,PACA_EXRFI+EX_R13(r13)
+	mfctr	r9
+	ld	r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+	ld	r11,PACA_L1D_FLUSH_SETS(r13)
+	ld	r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
+	/*
+	 * The load adresses are at staggered offsets within cachelines,
+	 * which suits some pipelines better (on others it should not
+	 * hurt).
+	 */
+	addi	r12,r12,8
+	mtctr	r11
+	DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+	/* order ld/st prior to dcbt stop all streams with flushing */
+	sync
+1:	li	r8,0
+	.rept	8 /* 8-way set associative */
+	ldx	r11,r10,r8
+	add	r8,r8,r12
+	xor	r11,r11,r11	// Ensure r11 is 0 even if fallback area is not
+	add	r8,r8,r11	// Add 0, this creates a dependency on the ldx
+	.endr
+	addi	r10,r10,128 /* 128 byte cache line */
+	bdnz	1b
+
+	mtctr	r9
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ld	r11,PACA_EXRFI+EX_R11(r13)
+	ld	r12,PACA_EXRFI+EX_R12(r13)
+	ld	r8,PACA_EXRFI+EX_R13(r13)
+	GET_SCRATCH0(r13);
+	rfid
+
+	.globl hrfi_flush_fallback
+hrfi_flush_fallback:
+	SET_SCRATCH0(r13);
+	GET_PACA(r13);
+	std	r9,PACA_EXRFI+EX_R9(r13)
+	std	r10,PACA_EXRFI+EX_R10(r13)
+	std	r11,PACA_EXRFI+EX_R11(r13)
+	std	r12,PACA_EXRFI+EX_R12(r13)
+	std	r8,PACA_EXRFI+EX_R13(r13)
+	mfctr	r9
+	ld	r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+	ld	r11,PACA_L1D_FLUSH_SETS(r13)
+	ld	r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
+	/*
+	 * The load adresses are at staggered offsets within cachelines,
+	 * which suits some pipelines better (on others it should not
+	 * hurt).
+	 */
+	addi	r12,r12,8
+	mtctr	r11
+	DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+	/* order ld/st prior to dcbt stop all streams with flushing */
+	sync
+1:	li	r8,0
+	.rept	8 /* 8-way set associative */
+	ldx	r11,r10,r8
+	add	r8,r8,r12
+	xor	r11,r11,r11	// Ensure r11 is 0 even if fallback area is not
+	add	r8,r8,r11	// Add 0, this creates a dependency on the ldx
+	.endr
+	addi	r10,r10,128 /* 128 byte cache line */
+	bdnz	1b
+
+	mtctr	r9
+	ld	r9,PACA_EXRFI+EX_R9(r13)
+	ld	r10,PACA_EXRFI+EX_R10(r13)
+	ld	r11,PACA_EXRFI+EX_R11(r13)
+	ld	r12,PACA_EXRFI+EX_R12(r13)
+	ld	r8,PACA_EXRFI+EX_R13(r13)
+	GET_SCRATCH0(r13);
+	hrfid
+
 /*
  * Called from arch_local_irq_enable when an interrupt needs
  * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index a12be60..7c30a91 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -37,6 +37,7 @@
 #include <linux/memblock.h>
 #include <linux/memory.h>
 #include <linux/nmi.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <asm/kdump.h>
@@ -678,4 +679,142 @@
 	return 0;
 }
 early_initcall(disable_hardlockup_detector);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+static enum l1d_flush_type enabled_flush_types;
+static void *l1d_flush_fallback_area;
+static bool no_rfi_flush;
+bool rfi_flush;
+
+static int __init handle_no_rfi_flush(char *p)
+{
+	pr_info("rfi-flush: disabled on command line.");
+	no_rfi_flush = true;
+	return 0;
+}
+early_param("no_rfi_flush", handle_no_rfi_flush);
+
+/*
+ * The RFI flush is not KPTI, but because users will see doco that says to use
+ * nopti we hijack that option here to also disable the RFI flush.
+ */
+static int __init handle_no_pti(char *p)
+{
+	pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
+	handle_no_rfi_flush(NULL);
+	return 0;
+}
+early_param("nopti", handle_no_pti);
+
+static void do_nothing(void *unused)
+{
+	/*
+	 * We don't need to do the flush explicitly, just enter+exit kernel is
+	 * sufficient, the RFI exit handlers will do the right thing.
+	 */
+}
+
+void rfi_flush_enable(bool enable)
+{
+	if (rfi_flush == enable)
+		return;
+
+	if (enable) {
+		do_rfi_flush_fixups(enabled_flush_types);
+		on_each_cpu(do_nothing, NULL, 1);
+	} else
+		do_rfi_flush_fixups(L1D_FLUSH_NONE);
+
+	rfi_flush = enable;
+}
+
+static void init_fallback_flush(void)
+{
+	u64 l1d_size, limit;
+	int cpu;
+
+	l1d_size = ppc64_caches.dsize;
+	limit = min(safe_stack_limit(), ppc64_rma_size);
+
+	/*
+	 * Align to L1d size, and size it at 2x L1d size, to catch possible
+	 * hardware prefetch runoff. We don't have a recipe for load patterns to
+	 * reliably avoid the prefetcher.
+	 */
+	l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit));
+	memset(l1d_flush_fallback_area, 0, l1d_size * 2);
+
+	for_each_possible_cpu(cpu) {
+		/*
+		 * The fallback flush is currently coded for 8-way
+		 * associativity. Different associativity is possible, but it
+		 * will be treated as 8-way and may not evict the lines as
+		 * effectively.
+		 *
+		 * 128 byte lines are mandatory.
+		 */
+		u64 c = l1d_size / 8;
+
+		paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
+		paca[cpu].l1d_flush_congruence = c;
+		paca[cpu].l1d_flush_sets = c / 128;
+	}
+}
+
+void __init setup_rfi_flush(enum l1d_flush_type types, bool enable)
+{
+	if (types & L1D_FLUSH_FALLBACK) {
+		pr_info("rfi-flush: Using fallback displacement flush\n");
+		init_fallback_flush();
+	}
+
+	if (types & L1D_FLUSH_ORI)
+		pr_info("rfi-flush: Using ori type flush\n");
+
+	if (types & L1D_FLUSH_MTTRIG)
+		pr_info("rfi-flush: Using mttrig type flush\n");
+
+	enabled_flush_types = types;
+
+	if (!no_rfi_flush)
+		rfi_flush_enable(enable);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int rfi_flush_set(void *data, u64 val)
+{
+	if (val == 1)
+		rfi_flush_enable(true);
+	else if (val == 0)
+		rfi_flush_enable(false);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rfi_flush_get(void *data, u64 *val)
+{
+	*val = rfi_flush ? 1 : 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
+
+static __init int rfi_flush_debugfs_init(void)
+{
+	debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush);
+	return 0;
+}
+device_initcall(rfi_flush_debugfs_init);
+#endif
+
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if (rfi_flush)
+		return sprintf(buf, "Mitigation: RFI Flush\n");
+
+	return sprintf(buf, "Vulnerable\n");
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
 #endif
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7394b77..b61fb79 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -132,6 +132,15 @@
 	/* Read-only data */
 	RODATA
 
+#ifdef CONFIG_PPC64
+	. = ALIGN(8);
+	__rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) {
+		__start___rfi_flush_fixup = .;
+		*(__rfi_flush_fixup)
+		__stop___rfi_flush_fixup = .;
+	}
+#endif
+
 	EXCEPTION_TABLE(0)
 
 	NOTES :kernel :notes
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 043415f..e86bfa1 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -23,6 +23,7 @@
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/firmware.h>
+#include <asm/setup.h>
 
 struct fixup_entry {
 	unsigned long	mask;
@@ -115,6 +116,47 @@
 	}
 }
 
+#ifdef CONFIG_PPC_BOOK3S_64
+void do_rfi_flush_fixups(enum l1d_flush_type types)
+{
+	unsigned int instrs[3], *dest;
+	long *start, *end;
+	int i;
+
+	start = PTRRELOC(&__start___rfi_flush_fixup),
+	end = PTRRELOC(&__stop___rfi_flush_fixup);
+
+	instrs[0] = 0x60000000; /* nop */
+	instrs[1] = 0x60000000; /* nop */
+	instrs[2] = 0x60000000; /* nop */
+
+	if (types & L1D_FLUSH_FALLBACK)
+		/* b .+16 to fallback flush */
+		instrs[0] = 0x48000010;
+
+	i = 0;
+	if (types & L1D_FLUSH_ORI) {
+		instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+		instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+	}
+
+	if (types & L1D_FLUSH_MTTRIG)
+		instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+	for (i = 0; start < end; start++, i++) {
+		dest = (void *)start + *start;
+
+		pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+		patch_instruction(dest, instrs[0]);
+		patch_instruction(dest + 1, instrs[1]);
+		patch_instruction(dest + 2, instrs[2]);
+	}
+
+	printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i);
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 {
 	long *start, *end;
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index b33faa0..6f8b4c1 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -35,13 +35,63 @@
 #include <asm/opal.h>
 #include <asm/kexec.h>
 #include <asm/smp.h>
+#include <asm/tm.h>
+#include <asm/setup.h>
 
 #include "powernv.h"
 
+static void pnv_setup_rfi_flush(void)
+{
+	struct device_node *np, *fw_features;
+	enum l1d_flush_type type;
+	int enable;
+
+	/* Default to fallback in case fw-features are not available */
+	type = L1D_FLUSH_FALLBACK;
+	enable = 1;
+
+	np = of_find_node_by_name(NULL, "ibm,opal");
+	fw_features = of_get_child_by_name(np, "fw-features");
+	of_node_put(np);
+
+	if (fw_features) {
+		np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2");
+		if (np && of_property_read_bool(np, "enabled"))
+			type = L1D_FLUSH_MTTRIG;
+
+		of_node_put(np);
+
+		np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0");
+		if (np && of_property_read_bool(np, "enabled"))
+			type = L1D_FLUSH_ORI;
+
+		of_node_put(np);
+
+		/* Enable unless firmware says NOT to */
+		enable = 2;
+		np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0");
+		if (np && of_property_read_bool(np, "disabled"))
+			enable--;
+
+		of_node_put(np);
+
+		np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1");
+		if (np && of_property_read_bool(np, "disabled"))
+			enable--;
+
+		of_node_put(np);
+		of_node_put(fw_features);
+	}
+
+	setup_rfi_flush(type, enable > 0);
+}
+
 static void __init pnv_setup_arch(void)
 {
 	set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
 
+	pnv_setup_rfi_flush();
+
 	/* Initialize SMP */
 	pnv_smp_init();
 
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 97aa3f3..1845fc6 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -450,6 +450,39 @@
 	of_pci_check_probe_only();
 }
 
+static void pseries_setup_rfi_flush(void)
+{
+	struct h_cpu_char_result result;
+	enum l1d_flush_type types;
+	bool enable;
+	long rc;
+
+	/* Enable by default */
+	enable = true;
+
+	rc = plpar_get_cpu_characteristics(&result);
+	if (rc == H_SUCCESS) {
+		types = L1D_FLUSH_NONE;
+
+		if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2)
+			types |= L1D_FLUSH_MTTRIG;
+		if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30)
+			types |= L1D_FLUSH_ORI;
+
+		/* Use fallback if nothing set in hcall */
+		if (types == L1D_FLUSH_NONE)
+			types = L1D_FLUSH_FALLBACK;
+
+		if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
+			enable = false;
+	} else {
+		/* Default to fallback if case hcall is not available */
+		types = L1D_FLUSH_FALLBACK;
+	}
+
+	setup_rfi_flush(types, enable);
+}
+
 static void __init pSeries_setup_arch(void)
 {
 	set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
@@ -467,6 +500,8 @@
 
 	fwnmi_init();
 
+	pseries_setup_rfi_flush();
+
 	/* By default, only probe PCI (can be overridden by rtas_pci) */
 	pci_add_flags(PCI_PROBE_ONLY);
 
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index ff63934..c5b9977 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -607,7 +607,8 @@
 		break;
 	}
 
-	force_sig_info(SIGFPE, &info, current);
+	info.si_signo = SIGFPE;
+	force_sig_info(info.si_signo, &info, current);
 }
 #endif
 
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 0ca46ede..9c150cc 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -117,7 +117,7 @@
 archprepare: include/generated/user_constants.h
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
-LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
+LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie)
 
 CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
 	$(call cc-option, -fno-stack-protector,) \
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index aa8b067..d9ae404 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -906,7 +906,7 @@
 
 	if (sg_is_last(req->src) &&
 	    req->src->offset + req->src->length <= PAGE_SIZE &&
-	    sg_is_last(req->dst) &&
++	    sg_is_last(req->dst) && req->dst->length &&
 	    req->dst->offset + req->dst->length <= PAGE_SIZE) {
 		one_entry_in_sg = 1;
 		scatterwalk_start(&src_sg_walk, req->src);
diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c
index e32142b..28c3720 100644
--- a/arch/x86/crypto/poly1305_glue.c
+++ b/arch/x86/crypto/poly1305_glue.c
@@ -164,7 +164,6 @@
 	.init		= poly1305_simd_init,
 	.update		= poly1305_simd_update,
 	.final		= crypto_poly1305_final,
-	.setkey		= crypto_poly1305_setkey,
 	.descsize	= sizeof(struct poly1305_simd_desc_ctx),
 	.base		= {
 		.cra_name		= "poly1305",
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
index 36870b2..d088050 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
+++ b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
@@ -57,10 +57,12 @@
 {
 	unsigned int j;
 
-	state->lens[0] = 0;
-	state->lens[1] = 1;
-	state->lens[2] = 2;
-	state->lens[3] = 3;
+	/* initially all lanes are unused */
+	state->lens[0] = 0xFFFFFFFF00000000;
+	state->lens[1] = 0xFFFFFFFF00000001;
+	state->lens[2] = 0xFFFFFFFF00000002;
+	state->lens[3] = 0xFFFFFFFF00000003;
+
 	state->unused_lanes = 0xFF03020100;
 	for (j = 0; j < 4; j++)
 		state->ldata[j].job_in_lane = NULL;
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index bdd9cc5..b0cd306 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -20,6 +20,7 @@
 #include <linux/export.h>
 #include <linux/context_tracking.h>
 #include <linux/user-return-notifier.h>
+#include <linux/nospec.h>
 #include <linux/uprobes.h>
 
 #include <asm/desc.h>
@@ -201,7 +202,7 @@
 	 * special case only applies after poking regs and before the
 	 * very next return to user mode.
 	 */
-	current->thread.status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
+	ti->status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
 #endif
 
 	user_enter_irqoff();
@@ -277,7 +278,8 @@
 	 * regs->orig_ax, which changes the behavior of some syscalls.
 	 */
 	if (likely((nr & __SYSCALL_MASK) < NR_syscalls)) {
-		regs->ax = sys_call_table[nr & __SYSCALL_MASK](
+		nr = array_index_nospec(nr & __SYSCALL_MASK, NR_syscalls);
+		regs->ax = sys_call_table[nr](
 			regs->di, regs->si, regs->dx,
 			regs->r10, regs->r8, regs->r9);
 	}
@@ -299,7 +301,7 @@
 	unsigned int nr = (unsigned int)regs->orig_ax;
 
 #ifdef CONFIG_IA32_EMULATION
-	current->thread.status |= TS_COMPAT;
+	ti->status |= TS_COMPAT;
 #endif
 
 	if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY) {
@@ -313,6 +315,7 @@
 	}
 
 	if (likely(nr < IA32_NR_syscalls)) {
+		nr = array_index_nospec(nr, IA32_NR_syscalls);
 		/*
 		 * It's possible that a 32-bit syscall implementation
 		 * takes a 64-bit parameter but nonetheless assumes that
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index bdc9aea..f5434b4 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -229,6 +229,18 @@
 	movl	%ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset
 #endif
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+	/* Clobbers %ebx */
+	FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+#endif
+
 	/* restore callee-saved registers */
 	popl	%esi
 	popl	%edi
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index b9c901ce..db5009c 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -177,96 +177,17 @@
 	pushq	%r9				/* pt_regs->r9 */
 	pushq	%r10				/* pt_regs->r10 */
 	pushq	%r11				/* pt_regs->r11 */
-	sub	$(6*8), %rsp			/* pt_regs->bp, bx, r12-15 not saved */
+	pushq	%rbx				/* pt_regs->rbx */
+	pushq	%rbp				/* pt_regs->rbp */
+	pushq	%r12				/* pt_regs->r12 */
+	pushq	%r13				/* pt_regs->r13 */
+	pushq	%r14				/* pt_regs->r14 */
+	pushq	%r15				/* pt_regs->r15 */
 
-	/*
-	 * If we need to do entry work or if we guess we'll need to do
-	 * exit work, go straight to the slow path.
-	 */
-	movq	PER_CPU_VAR(current_task), %r11
-	testl	$_TIF_WORK_SYSCALL_ENTRY|_TIF_ALLWORK_MASK, TASK_TI_flags(%r11)
-	jnz	entry_SYSCALL64_slow_path
-
-entry_SYSCALL_64_fastpath:
-	/*
-	 * Easy case: enable interrupts and issue the syscall.  If the syscall
-	 * needs pt_regs, we'll call a stub that disables interrupts again
-	 * and jumps to the slow path.
-	 */
-	TRACE_IRQS_ON
-	ENABLE_INTERRUPTS(CLBR_NONE)
-#if __SYSCALL_MASK == ~0
-	cmpq	$__NR_syscall_max, %rax
-#else
-	andl	$__SYSCALL_MASK, %eax
-	cmpl	$__NR_syscall_max, %eax
-#endif
-	ja	1f				/* return -ENOSYS (already in pt_regs->ax) */
-	movq	%r10, %rcx
-
-	/*
-	 * This call instruction is handled specially in stub_ptregs_64.
-	 * It might end up jumping to the slow path.  If it jumps, RAX
-	 * and all argument registers are clobbered.
-	 */
-#ifdef CONFIG_RETPOLINE
-	movq	sys_call_table(, %rax, 8), %rax
-	call	__x86_indirect_thunk_rax
-#else
-	call	*sys_call_table(, %rax, 8)
-#endif
-.Lentry_SYSCALL_64_after_fastpath_call:
-
-	movq	%rax, RAX(%rsp)
-1:
-
-	/*
-	 * If we get here, then we know that pt_regs is clean for SYSRET64.
-	 * If we see that no exit work is required (which we are required
-	 * to check with IRQs off), then we can go straight to SYSRET64.
-	 */
-	DISABLE_INTERRUPTS(CLBR_NONE)
-	TRACE_IRQS_OFF
-	movq	PER_CPU_VAR(current_task), %r11
-	testl	$_TIF_ALLWORK_MASK, TASK_TI_flags(%r11)
-	jnz	1f
-
-	LOCKDEP_SYS_EXIT
-	TRACE_IRQS_ON		/* user mode is traced as IRQs on */
-	movq	RIP(%rsp), %rcx
-	movq	EFLAGS(%rsp), %r11
-	RESTORE_C_REGS_EXCEPT_RCX_R11
-	/*
-	 * This opens a window where we have a user CR3, but are
-	 * running in the kernel.  This makes using the CS
-	 * register useless for telling whether or not we need to
-	 * switch CR3 in NMIs.  Normal interrupts are OK because
-	 * they are off here.
-	 */
-	SWITCH_USER_CR3
-	movq	RSP(%rsp), %rsp
-	USERGS_SYSRET64
-
-1:
-	/*
-	 * The fast path looked good when we started, but something changed
-	 * along the way and we need to switch to the slow path.  Calling
-	 * raise(3) will trigger this, for example.  IRQs are off.
-	 */
-	TRACE_IRQS_ON
-	ENABLE_INTERRUPTS(CLBR_NONE)
-	SAVE_EXTRA_REGS
-	movq	%rsp, %rdi
-	call	syscall_return_slowpath	/* returns with IRQs disabled */
-	jmp	return_from_SYSCALL_64
-
-entry_SYSCALL64_slow_path:
 	/* IRQs are off. */
-	SAVE_EXTRA_REGS
 	movq	%rsp, %rdi
 	call	do_syscall_64		/* returns with IRQs disabled */
 
-return_from_SYSCALL_64:
 	RESTORE_EXTRA_REGS
 	TRACE_IRQS_IRETQ		/* we're about to change IF */
 
@@ -339,6 +260,7 @@
 syscall_return_via_sysret:
 	/* rcx and r11 are already restored (see code above) */
 	RESTORE_C_REGS_EXCEPT_RCX_R11
+
 	/*
 	 * This opens a window where we have a user CR3, but are
 	 * running in the kernel.  This makes using the CS
@@ -363,45 +285,6 @@
 	jmp	restore_c_regs_and_iret
 END(entry_SYSCALL_64)
 
-ENTRY(stub_ptregs_64)
-	/*
-	 * Syscalls marked as needing ptregs land here.
-	 * If we are on the fast path, we need to save the extra regs,
-	 * which we achieve by trying again on the slow path.  If we are on
-	 * the slow path, the extra regs are already saved.
-	 *
-	 * RAX stores a pointer to the C function implementing the syscall.
-	 * IRQs are on.
-	 */
-	cmpq	$.Lentry_SYSCALL_64_after_fastpath_call, (%rsp)
-	jne	1f
-
-	/*
-	 * Called from fast path -- disable IRQs again, pop return address
-	 * and jump to slow path
-	 */
-	DISABLE_INTERRUPTS(CLBR_NONE)
-	TRACE_IRQS_OFF
-	popq	%rax
-	jmp	entry_SYSCALL64_slow_path
-
-1:
-	JMP_NOSPEC %rax				/* Called from C */
-END(stub_ptregs_64)
-
-.macro ptregs_stub func
-ENTRY(ptregs_\func)
-	leaq	\func(%rip), %rax
-	jmp	stub_ptregs_64
-END(ptregs_\func)
-.endm
-
-/* Instantiate ptregs_stub for each ptregs-using syscall */
-#define __SYSCALL_64_QUAL_(sym)
-#define __SYSCALL_64_QUAL_ptregs(sym) ptregs_stub sym
-#define __SYSCALL_64(nr, sym, qual) __SYSCALL_64_QUAL_##qual(sym)
-#include <asm/syscalls_64.h>
-
 /*
  * %rdi: prev task
  * %rsi: next task
@@ -427,6 +310,18 @@
 	movq	%rbx, PER_CPU_VAR(irq_stack_union)+stack_canary_offset
 #endif
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+	/* Clobbers %rbx */
+	FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+#endif
+
 	/* restore callee-saved registers */
 	popq	%r15
 	popq	%r14
@@ -1053,7 +948,7 @@
 #endif
 
 #ifdef CONFIG_X86_MCE
-idtentry machine_check					has_error_code=0	paranoid=1 do_sym=*machine_check_vector(%rip)
+idtentry machine_check		do_mce			has_error_code=0	paranoid=1
 #endif
 
 /*
diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c
index 9dbc5ab..6705edd 100644
--- a/arch/x86/entry/syscall_64.c
+++ b/arch/x86/entry/syscall_64.c
@@ -6,14 +6,11 @@
 #include <asm/asm-offsets.h>
 #include <asm/syscall.h>
 
-#define __SYSCALL_64_QUAL_(sym) sym
-#define __SYSCALL_64_QUAL_ptregs(sym) ptregs_##sym
-
-#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long __SYSCALL_64_QUAL_##qual(sym)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 #include <asm/syscalls_64.h>
 #undef __SYSCALL_64
 
-#define __SYSCALL_64(nr, sym, qual) [nr] = __SYSCALL_64_QUAL_##qual(sym),
+#define __SYSCALL_64(nr, sym, qual) [nr] = sym,
 
 extern long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 
diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index 6bb7e92..0174290 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -46,6 +46,7 @@
 #else
 	EMULATE;
 #endif
+unsigned long vsyscall_pgprot = __PAGE_KERNEL_VSYSCALL;
 
 static int __init vsyscall_setup(char *str)
 {
@@ -336,11 +337,11 @@
 	extern char __vsyscall_page;
 	unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
 
+	if (vsyscall_mode != NATIVE)
+		vsyscall_pgprot = __PAGE_KERNEL_VVAR;
 	if (vsyscall_mode != NONE)
 		__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
-			     vsyscall_mode == NATIVE
-			     ? PAGE_KERNEL_VSYSCALL
-			     : PAGE_KERNEL_VVAR);
+			     __pgprot(vsyscall_pgprot));
 
 	BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
 		     (unsigned long)VSYSCALL_ADDR);
diff --git a/arch/x86/events/amd/power.c b/arch/x86/events/amd/power.c
index 9842270..21a4e41 100644
--- a/arch/x86/events/amd/power.c
+++ b/arch/x86/events/amd/power.c
@@ -277,7 +277,7 @@
 	int ret;
 
 	if (!x86_match_cpu(cpu_match))
-		return 0;
+		return -ENODEV;
 
 	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
 		return -ENODEV;
diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 982c9e3..21298c1 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/coredump.h>
+#include <linux/kaiser.h>
 
 #include <asm-generic/sizes.h>
 #include <asm/perf_event.h>
@@ -77,6 +78,23 @@
 	return 1 << (PAGE_SHIFT + page_private(page));
 }
 
+static void bts_buffer_free_aux(void *data)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	struct bts_buffer *buf = data;
+	int nbuf;
+
+	for (nbuf = 0; nbuf < buf->nr_bufs; nbuf++) {
+		struct page *page = buf->buf[nbuf].page;
+		void *kaddr = page_address(page);
+		size_t page_size = buf_size(page);
+
+		kaiser_remove_mapping((unsigned long)kaddr, page_size);
+	}
+#endif
+	kfree(data);
+}
+
 static void *
 bts_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool overwrite)
 {
@@ -113,29 +131,33 @@
 	buf->real_size = size - size % BTS_RECORD_SIZE;
 
 	for (pg = 0, nbuf = 0, offset = 0, pad = 0; nbuf < buf->nr_bufs; nbuf++) {
-		unsigned int __nr_pages;
+		void *kaddr = pages[pg];
+		size_t page_size;
 
-		page = virt_to_page(pages[pg]);
-		__nr_pages = PagePrivate(page) ? 1 << page_private(page) : 1;
+		page = virt_to_page(kaddr);
+		page_size = buf_size(page);
+
+		if (kaiser_add_mapping((unsigned long)kaddr,
+					page_size, __PAGE_KERNEL) < 0) {
+			buf->nr_bufs = nbuf;
+			bts_buffer_free_aux(buf);
+			return NULL;
+		}
+
 		buf->buf[nbuf].page = page;
 		buf->buf[nbuf].offset = offset;
 		buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);
-		buf->buf[nbuf].size = buf_size(page) - buf->buf[nbuf].displacement;
+		buf->buf[nbuf].size = page_size - buf->buf[nbuf].displacement;
 		pad = buf->buf[nbuf].size % BTS_RECORD_SIZE;
 		buf->buf[nbuf].size -= pad;
 
-		pg += __nr_pages;
-		offset += __nr_pages << PAGE_SHIFT;
+		pg += page_size >> PAGE_SHIFT;
+		offset += page_size;
 	}
 
 	return buf;
 }
 
-static void bts_buffer_free_aux(void *data)
-{
-	kfree(data);
-}
-
 static unsigned long bts_buffer_offset(struct bts_buffer *buf, unsigned int idx)
 {
 	return buf->buf[idx].offset + buf->buf[idx].displacement;
diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h
index b15aa40..1666542 100644
--- a/arch/x86/include/asm/asm-prototypes.h
+++ b/arch/x86/include/asm/asm-prototypes.h
@@ -37,5 +37,7 @@
 INDIRECT_THUNK(si)
 INDIRECT_THUNK(di)
 INDIRECT_THUNK(bp)
-INDIRECT_THUNK(sp)
+asmlinkage void __fill_rsb(void);
+asmlinkage void __clear_rsb(void);
+
 #endif /* CONFIG_RETPOLINE */
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 0052352..7bb29a4 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -11,10 +11,12 @@
 # define __ASM_FORM_COMMA(x) " " #x ","
 #endif
 
-#ifdef CONFIG_X86_32
+#ifndef __x86_64__
+/* 32 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(a)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
 #else
+/* 64 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(b)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
 #endif
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index bfb28ca..8575903 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -23,6 +23,34 @@
 #define wmb()	asm volatile("sfence" ::: "memory")
 #endif
 
+/**
+ * array_index_mask_nospec() - generate a mask that is ~0UL when the
+ * 	bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ *     0 - (index < size)
+ */
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+		unsigned long size)
+{
+	unsigned long mask;
+
+	asm ("cmp %1,%2; sbb %0,%0;"
+			:"=r" (mask)
+			:"r"(size),"r" (index)
+			:"cc");
+	return mask;
+}
+
+/* Override the default implementation from linux/nospec.h. */
+#define array_index_mask_nospec array_index_mask_nospec
+
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \
+					   "lfence", X86_FEATURE_LFENCE_RDTSC)
+
 #ifdef CONFIG_X86_PPRO_FENCE
 #define dma_rmb()	rmb()
 #else
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 9ea67a0..8c10157 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -28,6 +28,7 @@
 	CPUID_8000_000A_EDX,
 	CPUID_7_ECX,
 	CPUID_8000_0007_EBX,
+	CPUID_7_EDX,
 };
 
 #ifdef CONFIG_X86_FEATURE_NAMES
@@ -78,8 +79,9 @@
 	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 15, feature_bit) ||	\
 	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) ||	\
 	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) ||	\
 	   REQUIRED_MASK_CHECK					  ||	\
-	   BUILD_BUG_ON_ZERO(NCAPINTS != 18))
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
 
 #define DISABLED_MASK_BIT_SET(feature_bit)				\
 	 ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  0, feature_bit) ||	\
@@ -100,8 +102,9 @@
 	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 15, feature_bit) ||	\
 	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) ||	\
 	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) ||	\
 	   DISABLED_MASK_CHECK					  ||	\
-	   BUILD_BUG_ON_ZERO(NCAPINTS != 18))
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
 
 #define cpu_has(c, bit)							\
 	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :	\
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 4467568..8eb23f5 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -12,7 +12,7 @@
 /*
  * Defines x86 CPU feature bits
  */
-#define NCAPINTS	18	/* N 32-bit words worth of info */
+#define NCAPINTS	19	/* N 32-bit words worth of info */
 #define NBUGINTS	1	/* N 32-bit bug flags */
 
 /*
@@ -194,16 +194,16 @@
 #define X86_FEATURE_HW_PSTATE	( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 
-#define X86_FEATURE_RETPOLINE	( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE	( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
 
-#define X86_FEATURE_INTEL_PT	( 7*32+15) /* Intel Processor Trace */
-#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
-#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_RSB_CTXSW	( 7*32+19) /* "" Fill RSB on context switches */
 
 /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */
 #define X86_FEATURE_KAISER	( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
 
+#define X86_FEATURE_USE_IBPB	( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
+
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
 #define X86_FEATURE_VNMI        ( 8*32+ 1) /* Intel Virtual NMI */
@@ -235,6 +235,7 @@
 #define X86_FEATURE_SMAP	( 9*32+20) /* Supervisor Mode Access Prevention */
 #define X86_FEATURE_CLFLUSHOPT	( 9*32+23) /* CLFLUSHOPT instruction */
 #define X86_FEATURE_CLWB	( 9*32+24) /* CLWB instruction */
+#define X86_FEATURE_INTEL_PT	( 9*32+25) /* Intel Processor Trace */
 #define X86_FEATURE_AVX512PF	( 9*32+26) /* AVX-512 Prefetch */
 #define X86_FEATURE_AVX512ER	( 9*32+27) /* AVX-512 Exponential and Reciprocal */
 #define X86_FEATURE_AVX512CD	( 9*32+28) /* AVX-512 Conflict Detection */
@@ -259,6 +260,9 @@
 /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
 #define X86_FEATURE_CLZERO	(13*32+0) /* CLZERO instruction */
 #define X86_FEATURE_IRPERF	(13*32+1) /* Instructions Retired Count */
+#define X86_FEATURE_IBPB	(13*32+12) /* Indirect Branch Prediction Barrier */
+#define X86_FEATURE_IBRS	(13*32+14) /* Indirect Branch Restricted Speculation */
+#define X86_FEATURE_STIBP	(13*32+15) /* Single Thread Indirect Branch Predictors */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
 #define X86_FEATURE_DTHERM	(14*32+ 0) /* Digital Thermal Sensor */
@@ -294,6 +298,13 @@
 #define X86_FEATURE_SUCCOR	(17*32+1) /* Uncorrectable error containment and recovery */
 #define X86_FEATURE_SMCA	(17*32+3) /* Scalable MCA */
 
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
+#define X86_FEATURE_AVX512_4VNNIW	(18*32+ 2) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS	(18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_SPEC_CTRL		(18*32+26) /* "" Speculation Control (IBRS + IBPB) */
+#define X86_FEATURE_INTEL_STIBP		(18*32+27) /* "" Single Thread Indirect Branch Predictors */
+#define X86_FEATURE_ARCH_CAPABILITIES	(18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
+
 /*
  * BUG word(s)
  */
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 21c5ac1..1f8cca4 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -59,6 +59,7 @@
 #define DISABLED_MASK15	0
 #define DISABLED_MASK16	(DISABLE_PKU|DISABLE_OSPKE)
 #define DISABLED_MASK17	0
-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define DISABLED_MASK18	0
+#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
 
 #endif /* _ASM_X86_DISABLED_FEATURES_H */
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
index 34a46dc..75b748a 100644
--- a/arch/x86/include/asm/intel-family.h
+++ b/arch/x86/include/asm/intel-family.h
@@ -12,6 +12,7 @@
  */
 
 #define INTEL_FAM6_CORE_YONAH		0x0E
+
 #define INTEL_FAM6_CORE2_MEROM		0x0F
 #define INTEL_FAM6_CORE2_MEROM_L	0x16
 #define INTEL_FAM6_CORE2_PENRYN		0x17
@@ -21,6 +22,7 @@
 #define INTEL_FAM6_NEHALEM_G		0x1F /* Auburndale / Havendale */
 #define INTEL_FAM6_NEHALEM_EP		0x1A
 #define INTEL_FAM6_NEHALEM_EX		0x2E
+
 #define INTEL_FAM6_WESTMERE		0x25
 #define INTEL_FAM6_WESTMERE_EP		0x2C
 #define INTEL_FAM6_WESTMERE_EX		0x2F
@@ -36,9 +38,9 @@
 #define INTEL_FAM6_HASWELL_GT3E		0x46
 
 #define INTEL_FAM6_BROADWELL_CORE	0x3D
-#define INTEL_FAM6_BROADWELL_XEON_D	0x56
 #define INTEL_FAM6_BROADWELL_GT3E	0x47
 #define INTEL_FAM6_BROADWELL_X		0x4F
+#define INTEL_FAM6_BROADWELL_XEON_D	0x56
 
 #define INTEL_FAM6_SKYLAKE_MOBILE	0x4E
 #define INTEL_FAM6_SKYLAKE_DESKTOP	0x5E
@@ -57,9 +59,10 @@
 #define INTEL_FAM6_ATOM_SILVERMONT2	0x4D /* Avaton/Rangely */
 #define INTEL_FAM6_ATOM_AIRMONT		0x4C /* CherryTrail / Braswell */
 #define INTEL_FAM6_ATOM_MERRIFIELD	0x4A /* Tangier */
-#define INTEL_FAM6_ATOM_MOOREFIELD	0x5A /* Annidale */
+#define INTEL_FAM6_ATOM_MOOREFIELD	0x5A /* Anniedale */
 #define INTEL_FAM6_ATOM_GOLDMONT	0x5C
 #define INTEL_FAM6_ATOM_DENVERTON	0x5F /* Goldmont Microserver */
+#define INTEL_FAM6_ATOM_GEMINI_LAKE	0x7A
 
 /* Xeon Phi */
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index cbd1d44..20cfeeb 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1113,7 +1113,8 @@
 static inline int emulate_instruction(struct kvm_vcpu *vcpu,
 			int emulation_type)
 {
-	return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0);
+	return x86_emulate_instruction(vcpu, 0,
+			emulation_type | EMULTYPE_NO_REEXECUTE, NULL, 0);
 }
 
 void kvm_enable_efer_bits(u64);
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index b11c4c0..c768bc1 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -37,6 +37,13 @@
 #define EFER_FFXSR		(1<<_EFER_FFXSR)
 
 /* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_SPEC_CTRL		0x00000048 /* Speculation Control */
+#define SPEC_CTRL_IBRS			(1 << 0)   /* Indirect Branch Restricted Speculation */
+#define SPEC_CTRL_STIBP			(1 << 1)   /* Single Thread Indirect Branch Predictors */
+
+#define MSR_IA32_PRED_CMD		0x00000049 /* Prediction Command */
+#define PRED_CMD_IBPB			(1 << 0)   /* Indirect Branch Prediction Barrier */
+
 #define MSR_IA32_PERFCTR0		0x000000c1
 #define MSR_IA32_PERFCTR1		0x000000c2
 #define MSR_FSB_FREQ			0x000000cd
@@ -50,6 +57,11 @@
 #define SNB_C3_AUTO_UNDEMOTE		(1UL << 28)
 
 #define MSR_MTRRcap			0x000000fe
+
+#define MSR_IA32_ARCH_CAPABILITIES	0x0000010a
+#define ARCH_CAP_RDCL_NO		(1 << 0)   /* Not susceptible to Meltdown */
+#define ARCH_CAP_IBRS_ALL		(1 << 1)   /* Enhanced IBRS support */
+
 #define MSR_IA32_BBL_CR_CTL		0x00000119
 #define MSR_IA32_BBL_CR_CTL3		0x0000011e
 
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index b5fee97..ed35b91 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -188,8 +188,7 @@
 	 * that some other imaginary CPU is updating continuously with a
 	 * time stamp.
 	 */
-	alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC,
-			  "lfence", X86_FEATURE_LFENCE_RDTSC);
+	barrier_nospec();
 	return rdtsc();
 }
 
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 402a11c..300cc15 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -1,54 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
-#ifndef __NOSPEC_BRANCH_H__
-#define __NOSPEC_BRANCH_H__
+#ifndef _ASM_X86_NOSPEC_BRANCH_H_
+#define _ASM_X86_NOSPEC_BRANCH_H_
 
 #include <asm/alternative.h>
 #include <asm/alternative-asm.h>
 #include <asm/cpufeatures.h>
 
-/*
- * Fill the CPU return stack buffer.
- *
- * Each entry in the RSB, if used for a speculative 'ret', contains an
- * infinite 'pause; jmp' loop to capture speculative execution.
- *
- * This is required in various cases for retpoline and IBRS-based
- * mitigations for the Spectre variant 2 vulnerability. Sometimes to
- * eliminate potentially bogus entries from the RSB, and sometimes
- * purely to ensure that it doesn't get empty, which on some CPUs would
- * allow predictions from other (unwanted!) sources to be used.
- *
- * We define a CPP macro such that it can be used from both .S files and
- * inline assembly. It's possible to do a .macro and then include that
- * from C via asm(".include <asm/nospec-branch.h>") but let's not go there.
- */
-
-#define RSB_CLEAR_LOOPS		32	/* To forcibly overwrite all entries */
-#define RSB_FILL_LOOPS		16	/* To avoid underflow */
-
-/*
- * Google experimented with loop-unrolling and this turned out to be
- * the optimal version — two calls, each with their own speculation
- * trap should their return address end up getting used, in a loop.
- */
-#define __FILL_RETURN_BUFFER(reg, nr, sp)	\
-	mov	$(nr/2), reg;			\
-771:						\
-	call	772f;				\
-773:	/* speculation trap */			\
-	pause;					\
-	jmp	773b;				\
-772:						\
-	call	774f;				\
-775:	/* speculation trap */			\
-	pause;					\
-	jmp	775b;				\
-774:						\
-	dec	reg;				\
-	jnz	771b;				\
-	add	$(BITS_PER_LONG/8) * nr, sp;
-
 #ifdef __ASSEMBLY__
 
 /*
@@ -73,6 +31,7 @@
 	call	.Ldo_rop_\@
 .Lspec_trap_\@:
 	pause
+	lfence
 	jmp	.Lspec_trap_\@
 .Ldo_rop_\@:
 	mov	\reg, (%_ASM_SP)
@@ -118,17 +77,10 @@
 #endif
 .endm
 
- /*
-  * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
-  * monstrosity above, manually.
-  */
-.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+/* This clobbers the BX register */
+.macro FILL_RETURN_BUFFER nr:req ftr:req
 #ifdef CONFIG_RETPOLINE
-	ANNOTATE_NOSPEC_ALTERNATIVE
-	ALTERNATIVE "jmp .Lskip_rsb_\@",				\
-		__stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP))	\
-		\ftr
-.Lskip_rsb_\@:
+	ALTERNATIVE "", "call __clear_rsb", \ftr
 #endif
 .endm
 
@@ -165,6 +117,7 @@
 	"       .align 16\n"					\
 	"901:	call   903f;\n"					\
 	"902:	pause;\n"					\
+	"    	lfence;\n"					\
 	"       jmp    902b;\n"					\
 	"       .align 16\n"					\
 	"903:	addl   $4, %%esp;\n"				\
@@ -190,25 +143,37 @@
 	SPECTRE_V2_IBRS,
 };
 
+extern char __indirect_thunk_start[];
+extern char __indirect_thunk_end[];
+
 /*
  * On VMEXIT we must ensure that no RSB predictions learned in the guest
  * can be followed in the host, by overwriting the RSB completely. Both
  * retpoline and IBRS mitigations for Spectre v2 need this; only on future
- * CPUs with IBRS_ATT *might* it be avoided.
+ * CPUs with IBRS_ALL *might* it be avoided.
  */
 static inline void vmexit_fill_RSB(void)
 {
 #ifdef CONFIG_RETPOLINE
-	unsigned long loops = RSB_CLEAR_LOOPS / 2;
-
-	asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE
-		      ALTERNATIVE("jmp 910f",
-				  __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
-				  X86_FEATURE_RETPOLINE)
-		      "910:"
-		      : "=&r" (loops), ASM_CALL_CONSTRAINT
-		      : "r" (loops) : "memory" );
+	alternative_input("",
+			  "call __fill_rsb",
+			  X86_FEATURE_RETPOLINE,
+			  ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory"));
 #endif
 }
+
+static inline void indirect_branch_prediction_barrier(void)
+{
+	asm volatile(ALTERNATIVE("",
+				 "movl %[msr], %%ecx\n\t"
+				 "movl %[val], %%eax\n\t"
+				 "movl $0, %%edx\n\t"
+				 "wrmsr",
+				 X86_FEATURE_USE_IBPB)
+		     : : [msr] "i" (MSR_IA32_PRED_CMD),
+			 [val] "i" (PRED_CMD_IBPB)
+		     : "eax", "ecx", "edx", "memory");
+}
+
 #endif /* __ASSEMBLY__ */
-#endif /* __NOSPEC_BRANCH_H__ */
+#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
index 1178a51..b6d4259 100644
--- a/arch/x86/include/asm/pgalloc.h
+++ b/arch/x86/include/asm/pgalloc.h
@@ -27,17 +27,6 @@
  */
 extern gfp_t __userpte_alloc_gfp;
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
-/*
- * Instead of one PGD, we acquire two PGDs.  Being order-1, it is
- * both 8k in size and 8k-aligned.  That lets us just flip bit 12
- * in a pointer to swap between the two 4k halves.
- */
-#define PGD_ALLOCATION_ORDER 1
-#else
-#define PGD_ALLOCATION_ORDER 0
-#endif
-
 /*
  * Allocate and free page tables.
  */
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 2536f90..5af0401 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -20,9 +20,15 @@
 
 #ifdef CONFIG_PAGE_TABLE_ISOLATION
 extern int kaiser_enabled;
+/*
+ * Instead of one PGD, we acquire two PGDs.  Being order-1, it is
+ * both 8k in size and 8k-aligned.  That lets us just flip bit 12
+ * in a pointer to swap between the two 4k halves.
+ */
 #else
 #define kaiser_enabled 0
 #endif
+#define PGD_ALLOCATION_ORDER kaiser_enabled
 
 void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
 void ptdump_walk_pgd_level_checkwx(void);
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e40b19c..cb866ae 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -391,8 +391,6 @@
 	unsigned short		gsindex;
 #endif
 
-	u32			status;		/* thread synchronous flags */
-
 #ifdef CONFIG_X86_64
 	unsigned long		fsbase;
 	unsigned long		gsbase;
@@ -596,7 +594,7 @@
 {
 	int tmp;
 
-#ifdef CONFIG_M486
+#ifdef CONFIG_X86_32
 	/*
 	 * Do a CPUID if available, otherwise do a jump.  The jump
 	 * can conveniently enough be the jump around CPUID.
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
index fac9a5c..6847d85 100644
--- a/arch/x86/include/asm/required-features.h
+++ b/arch/x86/include/asm/required-features.h
@@ -100,6 +100,7 @@
 #define REQUIRED_MASK15	0
 #define REQUIRED_MASK16	0
 #define REQUIRED_MASK17	0
-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
+#define REQUIRED_MASK18	0
+#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
 
 #endif /* _ASM_X86_REQUIRED_FEATURES_H */
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index e3c95e8..03eedc2 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -60,7 +60,7 @@
 	 * TS_COMPAT is set for 32-bit syscall entries and then
 	 * remains set until we return to user mode.
 	 */
-	if (task->thread.status & (TS_COMPAT|TS_I386_REGS_POKED))
+	if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED))
 		/*
 		 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
 		 * and will match correctly in comparisons.
@@ -116,7 +116,7 @@
 					 unsigned long *args)
 {
 # ifdef CONFIG_IA32_EMULATION
-	if (task->thread.status & TS_COMPAT)
+	if (task->thread_info.status & TS_COMPAT)
 		switch (i) {
 		case 0:
 			if (!n--) break;
@@ -177,7 +177,7 @@
 					 const unsigned long *args)
 {
 # ifdef CONFIG_IA32_EMULATION
-	if (task->thread.status & TS_COMPAT)
+	if (task->thread_info.status & TS_COMPAT)
 		switch (i) {
 		case 0:
 			if (!n--) break;
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index bdf9c4c..89978b9 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -54,6 +54,7 @@
 
 struct thread_info {
 	unsigned long		flags;		/* low level flags */
+	u32			status;		/* thread synchronous flags */
 };
 
 #define INIT_THREAD_INFO(tsk)			\
@@ -213,7 +214,7 @@
 #define in_ia32_syscall() true
 #else
 #define in_ia32_syscall() (IS_ENABLED(CONFIG_IA32_EMULATION) && \
-			   current->thread.status & TS_COMPAT)
+			   current_thread_info()->status & TS_COMPAT)
 #endif
 
 /*
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 01fd0a7..688315b 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -92,6 +92,7 @@
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
+dotraplinkage void do_mce(struct pt_regs *, long);
 
 static inline int get_si_code(unsigned long condition)
 {
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index dead0f3..a8d85a6 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -123,6 +123,11 @@
 
 #define __uaccess_begin() stac()
 #define __uaccess_end()   clac()
+#define __uaccess_begin_nospec()	\
+({					\
+	stac();				\
+	barrier_nospec();		\
+})
 
 /*
  * This is a type: either unsigned long, if the argument fits into
@@ -432,7 +437,7 @@
 ({									\
 	int __gu_err;							\
 	__inttype(*(ptr)) __gu_val;					\
-	__uaccess_begin();						\
+	__uaccess_begin_nospec();					\
 	__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);	\
 	__uaccess_end();						\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
@@ -474,6 +479,10 @@
 	__uaccess_begin();						\
 	barrier();
 
+#define uaccess_try_nospec do {						\
+	current->thread.uaccess_err = 0;				\
+	__uaccess_begin_nospec();					\
+
 #define uaccess_catch(err)						\
 	__uaccess_end();						\
 	(err) |= (current->thread.uaccess_err ? -EFAULT : 0);		\
@@ -538,7 +547,7 @@
  *	get_user_ex(...);
  * } get_user_catch(err)
  */
-#define get_user_try		uaccess_try
+#define get_user_try		uaccess_try_nospec
 #define get_user_catch(err)	uaccess_catch(err)
 
 #define get_user_ex(x, ptr)	do {					\
@@ -573,7 +582,7 @@
 	__typeof__(ptr) __uval = (uval);				\
 	__typeof__(*(ptr)) __old = (old);				\
 	__typeof__(*(ptr)) __new = (new);				\
-	__uaccess_begin();						\
+	__uaccess_begin_nospec();					\
 	switch (size) {							\
 	case 1:								\
 	{								\
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 7d3bdd1..d6d2450 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -102,17 +102,17 @@
 
 		switch (n) {
 		case 1:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret, 1);
 			__uaccess_end();
 			return ret;
 		case 2:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret, 2);
 			__uaccess_end();
 			return ret;
 		case 4:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret, 4);
 			__uaccess_end();
 			return ret;
@@ -130,17 +130,17 @@
 
 		switch (n) {
 		case 1:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u8 *)to, from, 1, ret, 1);
 			__uaccess_end();
 			return ret;
 		case 2:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u16 *)to, from, 2, ret, 2);
 			__uaccess_end();
 			return ret;
 		case 4:
-			__uaccess_begin();
+			__uaccess_begin_nospec();
 			__get_user_size(*(u32 *)to, from, 4, ret, 4);
 			__uaccess_end();
 			return ret;
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 673059a..6e5cc08 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -59,31 +59,31 @@
 		return copy_user_generic(dst, (__force void *)src, size);
 	switch (size) {
 	case 1:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u8 *)dst, (u8 __user *)src,
 			      ret, "b", "b", "=q", 1);
 		__uaccess_end();
 		return ret;
 	case 2:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u16 *)dst, (u16 __user *)src,
 			      ret, "w", "w", "=r", 2);
 		__uaccess_end();
 		return ret;
 	case 4:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u32 *)dst, (u32 __user *)src,
 			      ret, "l", "k", "=r", 4);
 		__uaccess_end();
 		return ret;
 	case 8:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			      ret, "q", "", "=r", 8);
 		__uaccess_end();
 		return ret;
 	case 10:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			       ret, "q", "", "=r", 10);
 		if (likely(!ret))
@@ -93,7 +93,7 @@
 		__uaccess_end();
 		return ret;
 	case 16:
-		__uaccess_begin();
+		__uaccess_begin_nospec();
 		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
 			       ret, "q", "", "=r", 16);
 		if (likely(!ret))
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
index 4865e10..62210da 100644
--- a/arch/x86/include/asm/vsyscall.h
+++ b/arch/x86/include/asm/vsyscall.h
@@ -21,5 +21,6 @@
 }
 static inline bool vsyscall_enabled(void) { return false; }
 #endif
+extern unsigned long vsyscall_pgprot;
 
 #endif /* _ASM_X86_VSYSCALL_H */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 10d5a3d..03b6e5c 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -46,17 +46,6 @@
 }
 __setup("noreplace-smp", setup_noreplace_smp);
 
-#ifdef CONFIG_PARAVIRT
-static int __initdata_or_module noreplace_paravirt = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
-	noreplace_paravirt = 1;
-	return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-#endif
-
 #define DPRINTK(fmt, args...)						\
 do {									\
 	if (debug_alternative)						\
@@ -588,9 +577,6 @@
 	struct paravirt_patch_site *p;
 	char insnbuf[MAX_PATCH_LEN];
 
-	if (noreplace_paravirt)
-		return;
-
 	for (p = start; p < end; p++) {
 		unsigned int used;
 
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index f3557a1..b5229ab 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -361,14 +361,17 @@
 		irq_data->chip_data = data;
 		irq_data->hwirq = virq + i;
 		err = assign_irq_vector_policy(virq + i, node, data, info);
-		if (err)
+		if (err) {
+			irq_data->chip_data = NULL;
+			free_apic_chip_data(data);
 			goto error;
+		}
 	}
 
 	return 0;
 
 error:
-	x86_vector_free_irqs(domain, virq, i + 1);
+	x86_vector_free_irqs(domain, virq, i);
 	return err;
 }
 
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 49d25dd..957ad44 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/cpu.h>
+#include <linux/module.h>
 
 #include <asm/nospec-branch.h>
 #include <asm/cmdline.h>
@@ -22,6 +23,7 @@
 #include <asm/alternative.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/intel-family.h>
 
 static void __init spectre_v2_select_mitigation(void);
 
@@ -88,20 +90,41 @@
 };
 
 #undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 mitigation: " fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
 
 static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
 
+#ifdef RETPOLINE
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+	if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
+		return true;
+
+	pr_err("System may be vulnerable to spectre v2\n");
+	spectre_v2_bad_module = true;
+	return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+	return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+#else
+static inline const char *spectre_v2_module_string(void) { return ""; }
+#endif
+
 static void __init spec2_print_if_insecure(const char *reason)
 {
 	if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
-		pr_info("%s\n", reason);
+		pr_info("%s selected on command line.\n", reason);
 }
 
 static void __init spec2_print_if_secure(const char *reason)
 {
 	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
-		pr_info("%s\n", reason);
+		pr_info("%s selected on command line.\n", reason);
 }
 
 static inline bool retp_compiler(void)
@@ -116,42 +139,85 @@
 	return len == arglen && !strncmp(arg, opt, len);
 }
 
+static const struct {
+	const char *option;
+	enum spectre_v2_mitigation_cmd cmd;
+	bool secure;
+} mitigation_options[] = {
+	{ "off",               SPECTRE_V2_CMD_NONE,              false },
+	{ "on",                SPECTRE_V2_CMD_FORCE,             true },
+	{ "retpoline",         SPECTRE_V2_CMD_RETPOLINE,         false },
+	{ "retpoline,amd",     SPECTRE_V2_CMD_RETPOLINE_AMD,     false },
+	{ "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+	{ "auto",              SPECTRE_V2_CMD_AUTO,              false },
+};
+
 static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
 {
 	char arg[20];
-	int ret;
+	int ret, i;
+	enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
 
-	ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
-				  sizeof(arg));
-	if (ret > 0)  {
-		if (match_option(arg, ret, "off")) {
-			goto disable;
-		} else if (match_option(arg, ret, "on")) {
-			spec2_print_if_secure("force enabled on command line.");
-			return SPECTRE_V2_CMD_FORCE;
-		} else if (match_option(arg, ret, "retpoline")) {
-			spec2_print_if_insecure("retpoline selected on command line.");
-			return SPECTRE_V2_CMD_RETPOLINE;
-		} else if (match_option(arg, ret, "retpoline,amd")) {
-			if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
-				pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
-				return SPECTRE_V2_CMD_AUTO;
-			}
-			spec2_print_if_insecure("AMD retpoline selected on command line.");
-			return SPECTRE_V2_CMD_RETPOLINE_AMD;
-		} else if (match_option(arg, ret, "retpoline,generic")) {
-			spec2_print_if_insecure("generic retpoline selected on command line.");
-			return SPECTRE_V2_CMD_RETPOLINE_GENERIC;
-		} else if (match_option(arg, ret, "auto")) {
+	if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+		return SPECTRE_V2_CMD_NONE;
+	else {
+		ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
+					  sizeof(arg));
+		if (ret < 0)
+			return SPECTRE_V2_CMD_AUTO;
+
+		for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+			if (!match_option(arg, ret, mitigation_options[i].option))
+				continue;
+			cmd = mitigation_options[i].cmd;
+			break;
+		}
+
+		if (i >= ARRAY_SIZE(mitigation_options)) {
+			pr_err("unknown option (%s). Switching to AUTO select\n",
+			       mitigation_options[i].option);
 			return SPECTRE_V2_CMD_AUTO;
 		}
 	}
 
-	if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+	if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+	    !IS_ENABLED(CONFIG_RETPOLINE)) {
+		pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+		       mitigation_options[i].option);
 		return SPECTRE_V2_CMD_AUTO;
-disable:
-	spec2_print_if_insecure("disabled on command line.");
-	return SPECTRE_V2_CMD_NONE;
+	}
+
+	if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
+	    boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+		pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if (mitigation_options[i].secure)
+		spec2_print_if_secure(mitigation_options[i].option);
+	else
+		spec2_print_if_insecure(mitigation_options[i].option);
+
+	return cmd;
+}
+
+/* Check for Skylake-like CPUs (for RSB handling) */
+static bool __init is_skylake_era(void)
+{
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+	    boot_cpu_data.x86 == 6) {
+		switch (boot_cpu_data.x86_model) {
+		case INTEL_FAM6_SKYLAKE_MOBILE:
+		case INTEL_FAM6_SKYLAKE_DESKTOP:
+		case INTEL_FAM6_SKYLAKE_X:
+		case INTEL_FAM6_KABYLAKE_MOBILE:
+		case INTEL_FAM6_KABYLAKE_DESKTOP:
+			return true;
+		}
+	}
+	return false;
 }
 
 static void __init spectre_v2_select_mitigation(void)
@@ -172,10 +238,10 @@
 		return;
 
 	case SPECTRE_V2_CMD_FORCE:
-		/* FALLTRHU */
 	case SPECTRE_V2_CMD_AUTO:
-		goto retpoline_auto;
-
+		if (IS_ENABLED(CONFIG_RETPOLINE))
+			goto retpoline_auto;
+		break;
 	case SPECTRE_V2_CMD_RETPOLINE_AMD:
 		if (IS_ENABLED(CONFIG_RETPOLINE))
 			goto retpoline_amd;
@@ -212,6 +278,30 @@
 
 	spectre_v2_enabled = mode;
 	pr_info("%s\n", spectre_v2_strings[mode]);
+
+	/*
+	 * If neither SMEP or KPTI are available, there is a risk of
+	 * hitting userspace addresses in the RSB after a context switch
+	 * from a shallow call stack to a deeper one. To prevent this fill
+	 * the entire RSB, even when using IBRS.
+	 *
+	 * Skylake era CPUs have a separate issue with *underflow* of the
+	 * RSB, when they will predict 'ret' targets from the generic BTB.
+	 * The proper mitigation for this is IBRS. If IBRS is not supported
+	 * or deactivated in favour of retpolines the RSB fill on context
+	 * switch is required.
+	 */
+	if ((!boot_cpu_has(X86_FEATURE_KAISER) &&
+	     !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) {
+		setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
+		pr_info("Filling RSB on context switch\n");
+	}
+
+	/* Initialize Indirect Branch Prediction Barrier if supported */
+	if (boot_cpu_has(X86_FEATURE_IBPB)) {
+		setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
+		pr_info("Enabling Indirect Branch Prediction Barrier\n");
+	}
 }
 
 #undef pr_fmt
@@ -232,7 +322,7 @@
 {
 	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
 		return sprintf(buf, "Not affected\n");
-	return sprintf(buf, "Vulnerable\n");
+	return sprintf(buf, "Mitigation: __user pointer sanitization\n");
 }
 
 ssize_t cpu_show_spectre_v2(struct device *dev,
@@ -241,6 +331,8 @@
 	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
 		return sprintf(buf, "Not affected\n");
 
-	return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]);
+	return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+		       boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "",
+		       spectre_v2_module_string());
 }
 #endif
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7b9ae04..08e89ed 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -44,6 +44,8 @@
 #include <asm/pat.h>
 #include <asm/microcode.h>
 #include <asm/microcode_intel.h>
+#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/uv/uv.h>
@@ -716,6 +718,26 @@
 	}
 }
 
+static void init_speculation_control(struct cpuinfo_x86 *c)
+{
+	/*
+	 * The Intel SPEC_CTRL CPUID bit implies IBRS and IBPB support,
+	 * and they also have a different bit for STIBP support. Also,
+	 * a hypervisor might have set the individual AMD bits even on
+	 * Intel CPUs, for finer-grained selection of what's available.
+	 *
+	 * We use the AMD bits in 0x8000_0008 EBX as the generic hardware
+	 * features, which are visible in /proc/cpuinfo and used by the
+	 * kernel. So set those accordingly from the Intel bits.
+	 */
+	if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) {
+		set_cpu_cap(c, X86_FEATURE_IBRS);
+		set_cpu_cap(c, X86_FEATURE_IBPB);
+	}
+	if (cpu_has(c, X86_FEATURE_INTEL_STIBP))
+		set_cpu_cap(c, X86_FEATURE_STIBP);
+}
+
 void get_cpu_cap(struct cpuinfo_x86 *c)
 {
 	u32 eax, ebx, ecx, edx;
@@ -737,6 +759,7 @@
 		cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
 		c->x86_capability[CPUID_7_0_EBX] = ebx;
 		c->x86_capability[CPUID_7_ECX] = ecx;
+		c->x86_capability[CPUID_7_EDX] = edx;
 	}
 
 	/* Extended state features: level 0x0000000d */
@@ -809,6 +832,7 @@
 		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
 	init_scattered_cpuid_features(c);
+	init_speculation_control(c);
 }
 
 static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -837,6 +861,41 @@
 #endif
 }
 
+static const __initconst struct x86_cpu_id cpu_no_speculation[] = {
+	{ X86_VENDOR_INTEL,	6, INTEL_FAM6_ATOM_CEDARVIEW,	X86_FEATURE_ANY },
+	{ X86_VENDOR_INTEL,	6, INTEL_FAM6_ATOM_CLOVERVIEW,	X86_FEATURE_ANY },
+	{ X86_VENDOR_INTEL,	6, INTEL_FAM6_ATOM_LINCROFT,	X86_FEATURE_ANY },
+	{ X86_VENDOR_INTEL,	6, INTEL_FAM6_ATOM_PENWELL,	X86_FEATURE_ANY },
+	{ X86_VENDOR_INTEL,	6, INTEL_FAM6_ATOM_PINEVIEW,	X86_FEATURE_ANY },
+	{ X86_VENDOR_CENTAUR,	5 },
+	{ X86_VENDOR_INTEL,	5 },
+	{ X86_VENDOR_NSC,	5 },
+	{ X86_VENDOR_ANY,	4 },
+	{}
+};
+
+static const __initconst struct x86_cpu_id cpu_no_meltdown[] = {
+	{ X86_VENDOR_AMD },
+	{}
+};
+
+static bool __init cpu_vulnerable_to_meltdown(struct cpuinfo_x86 *c)
+{
+	u64 ia32_cap = 0;
+
+	if (x86_match_cpu(cpu_no_meltdown))
+		return false;
+
+	if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES))
+		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
+
+	/* Rogue Data Cache Load? No! */
+	if (ia32_cap & ARCH_CAP_RDCL_NO)
+		return false;
+
+	return true;
+}
+
 /*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -883,11 +942,12 @@
 
 	setup_force_cpu_cap(X86_FEATURE_ALWAYS);
 
-	/* Assume for now that ALL x86 CPUs are insecure */
-	setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
-
-	setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
-	setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
+	if (!x86_match_cpu(cpu_no_speculation)) {
+		if (cpu_vulnerable_to_meltdown(c))
+			setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+		setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
+		setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
+	}
 
 	fpu__init_system(c);
 
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index fcd484d..4097b43 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -61,6 +61,59 @@
 	}
 }
 
+/*
+ * Early microcode releases for the Spectre v2 mitigation were broken.
+ * Information taken from;
+ * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/microcode-update-guidance.pdf
+ * - https://kb.vmware.com/s/article/52345
+ * - Microcode revisions observed in the wild
+ * - Release note from 20180108 microcode release
+ */
+struct sku_microcode {
+	u8 model;
+	u8 stepping;
+	u32 microcode;
+};
+static const struct sku_microcode spectre_bad_microcodes[] = {
+	{ INTEL_FAM6_KABYLAKE_DESKTOP,	0x0B,	0x84 },
+	{ INTEL_FAM6_KABYLAKE_DESKTOP,	0x0A,	0x84 },
+	{ INTEL_FAM6_KABYLAKE_DESKTOP,	0x09,	0x84 },
+	{ INTEL_FAM6_KABYLAKE_MOBILE,	0x0A,	0x84 },
+	{ INTEL_FAM6_KABYLAKE_MOBILE,	0x09,	0x84 },
+	{ INTEL_FAM6_SKYLAKE_X,		0x03,	0x0100013e },
+	{ INTEL_FAM6_SKYLAKE_X,		0x04,	0x0200003c },
+	{ INTEL_FAM6_SKYLAKE_MOBILE,	0x03,	0xc2 },
+	{ INTEL_FAM6_SKYLAKE_DESKTOP,	0x03,	0xc2 },
+	{ INTEL_FAM6_BROADWELL_CORE,	0x04,	0x28 },
+	{ INTEL_FAM6_BROADWELL_GT3E,	0x01,	0x1b },
+	{ INTEL_FAM6_BROADWELL_XEON_D,	0x02,	0x14 },
+	{ INTEL_FAM6_BROADWELL_XEON_D,	0x03,	0x07000011 },
+	{ INTEL_FAM6_BROADWELL_X,	0x01,	0x0b000025 },
+	{ INTEL_FAM6_HASWELL_ULT,	0x01,	0x21 },
+	{ INTEL_FAM6_HASWELL_GT3E,	0x01,	0x18 },
+	{ INTEL_FAM6_HASWELL_CORE,	0x03,	0x23 },
+	{ INTEL_FAM6_HASWELL_X,		0x02,	0x3b },
+	{ INTEL_FAM6_HASWELL_X,		0x04,	0x10 },
+	{ INTEL_FAM6_IVYBRIDGE_X,	0x04,	0x42a },
+	/* Updated in the 20180108 release; blacklist until we know otherwise */
+	{ INTEL_FAM6_ATOM_GEMINI_LAKE,	0x01,	0x22 },
+	/* Observed in the wild */
+	{ INTEL_FAM6_SANDYBRIDGE_X,	0x06,	0x61b },
+	{ INTEL_FAM6_SANDYBRIDGE_X,	0x07,	0x712 },
+};
+
+static bool bad_spectre_microcode(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) {
+		if (c->x86_model == spectre_bad_microcodes[i].model &&
+		    c->x86_mask == spectre_bad_microcodes[i].stepping)
+			return (c->microcode <= spectre_bad_microcodes[i].microcode);
+	}
+	return false;
+}
+
 static void early_init_intel(struct cpuinfo_x86 *c)
 {
 	u64 misc_enable;
@@ -87,6 +140,19 @@
 		rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
 	}
 
+	/* Now if any of them are set, check the blacklist and clear the lot */
+	if ((cpu_has(c, X86_FEATURE_SPEC_CTRL) ||
+	     cpu_has(c, X86_FEATURE_INTEL_STIBP) ||
+	     cpu_has(c, X86_FEATURE_IBRS) || cpu_has(c, X86_FEATURE_IBPB) ||
+	     cpu_has(c, X86_FEATURE_STIBP)) && bad_spectre_microcode(c)) {
+		pr_warn("Intel Spectre v2 broken microcode detected; disabling Speculation Control\n");
+		setup_clear_cpu_cap(X86_FEATURE_IBRS);
+		setup_clear_cpu_cap(X86_FEATURE_IBPB);
+		setup_clear_cpu_cap(X86_FEATURE_STIBP);
+		setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL);
+		setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP);
+	}
+
 	/*
 	 * Atom erratum AAE44/AAF40/AAG38/AAH41:
 	 *
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index de6626c..be63371 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -934,6 +934,8 @@
 		ci_leaf_init(this_leaf++, &id4_regs);
 		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
+	this_cpu_ci->cpu_map_populated = true;
+
 	return 0;
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 8ca5f8a..fe5cd6e 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -1754,6 +1754,11 @@
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
 						unexpected_machine_check;
 
+dotraplinkage void do_mce(struct pt_regs *regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 5ce5155..0afaf00 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -43,7 +43,7 @@
 #define MICROCODE_VERSION	"2.01"
 
 static struct microcode_ops	*microcode_ops;
-static bool dis_ucode_ldr;
+static bool dis_ucode_ldr = true;
 
 /*
  * Synchronization.
@@ -73,6 +73,7 @@
 static bool __init check_loader_disabled_bsp(void)
 {
 	static const char *__dis_opt_str = "dis_ucode_ldr";
+	u32 a, b, c, d;
 
 #ifdef CONFIG_X86_32
 	const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
@@ -85,8 +86,20 @@
 	bool *res = &dis_ucode_ldr;
 #endif
 
-	if (cmdline_find_option_bool(cmdline, option))
-		*res = true;
+	a = 1;
+	c = 0;
+	native_cpuid(&a, &b, &c, &d);
+
+	/*
+	 * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
+	 * completely accurate as xen pv guests don't see that CPUID bit set but
+	 * that's good enough as they don't land on the BSP path anyway.
+	 */
+	if (c & BIT(31))
+		return *res;
+
+	if (cmdline_find_option_bool(cmdline, option) <= 0)
+		*res = false;
 
 	return *res;
 }
@@ -114,9 +127,7 @@
 {
 	int vendor;
 	unsigned int family;
-
-	if (check_loader_disabled_bsp())
-		return;
+	bool intel = true;
 
 	if (!have_cpuid_p())
 		return;
@@ -126,16 +137,27 @@
 
 	switch (vendor) {
 	case X86_VENDOR_INTEL:
-		if (family >= 6)
-			load_ucode_intel_bsp();
+		if (family < 6)
+			return;
 		break;
+
 	case X86_VENDOR_AMD:
-		if (family >= 0x10)
-			load_ucode_amd_bsp(family);
+		if (family < 0x10)
+			return;
+		intel = false;
 		break;
+
 	default:
-		break;
+		return;
 	}
+
+	if (check_loader_disabled_bsp())
+		return;
+
+	if (intel)
+		load_ucode_intel_bsp();
+	else
+		load_ucode_amd_bsp(family);
 }
 
 static bool check_loader_disabled_ap(void)
@@ -154,9 +176,6 @@
 	if (check_loader_disabled_ap())
 		return;
 
-	if (!have_cpuid_p())
-		return;
-
 	vendor = x86_cpuid_vendor();
 	family = x86_cpuid_family();
 
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index ac3e636..f90f176 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -40,6 +40,9 @@
 #include <asm/setup.h>
 #include <asm/msr.h>
 
+/* last level cache size per core */
+static int llc_size_per_core;
+
 /*
  * Temporary microcode blobs pointers storage. We note here during early load
  * the pointers to microcode blobs we've got from whatever storage (detached
@@ -1053,12 +1056,14 @@
 
 	/*
 	 * Late loading on model 79 with microcode revision less than 0x0b000021
-	 * may result in a system hang. This behavior is documented in item
-	 * BDF90, #334165 (Intel Xeon Processor E7-8800/4800 v4 Product Family).
+	 * and LLC size per core bigger than 2.5MB may result in a system hang.
+	 * This behavior is documented in item BDF90, #334165 (Intel Xeon
+	 * Processor E7-8800/4800 v4 Product Family).
 	 */
 	if (c->x86 == 6 &&
 	    c->x86_model == INTEL_FAM6_BROADWELL_X &&
 	    c->x86_mask == 0x01 &&
+	    llc_size_per_core > 2621440 &&
 	    c->microcode < 0x0b000021) {
 		pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
 		pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
@@ -1125,6 +1130,15 @@
 	.microcode_fini_cpu               = microcode_fini_cpu,
 };
 
+static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
+{
+	u64 llc_size = c->x86_cache_size * 1024;
+
+	do_div(llc_size, c->x86_max_cores);
+
+	return (int)llc_size;
+}
+
 struct microcode_ops * __init init_intel_microcode(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -1135,6 +1149,8 @@
 		return NULL;
 	}
 
+	llc_size_per_core = calc_llc_size_per_core(c);
+
 	return &microcode_intel_ops;
 }
 
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 1db8dc4..afbb525 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,9 +31,6 @@
 	const struct cpuid_bit *cb;
 
 	static const struct cpuid_bit cpuid_bits[] = {
-		{ X86_FEATURE_INTEL_PT,		CR_EBX,25, 0x00000007, 0 },
-		{ X86_FEATURE_AVX512_4VNNIW,	CR_EDX, 2, 0x00000007, 0 },
-		{ X86_FEATURE_AVX512_4FMAPS,	CR_EDX, 3, 0x00000007, 0 },
 		{ X86_FEATURE_APERFMPERF,	CR_ECX, 0, 0x00000006, 0 },
 		{ X86_FEATURE_EPB,		CR_ECX, 3, 0x00000006, 0 },
 		{ X86_FEATURE_HW_PSTATE,	CR_EDX, 7, 0x80000007, 0 },
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 4d74f73..dc20da1c 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -37,6 +37,7 @@
 #include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 #include "common.h"
 
@@ -192,7 +193,7 @@
 }
 
 /* Check whether insn is indirect jump */
-static int insn_is_indirect_jump(struct insn *insn)
+static int __insn_is_indirect_jump(struct insn *insn)
 {
 	return ((insn->opcode.bytes[0] == 0xff &&
 		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -226,6 +227,26 @@
 	return (start <= target && target <= start + len);
 }
 
+static int insn_is_indirect_jump(struct insn *insn)
+{
+	int ret = __insn_is_indirect_jump(insn);
+
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * Jump to x86_indirect_thunk_* is treated as an indirect jump.
+	 * Note that even with CONFIG_RETPOLINE=y, the kernel compiled with
+	 * older gcc may use indirect jump. So we add this check instead of
+	 * replace indirect-jump check.
+	 */
+	if (!ret)
+		ret = insn_jump_into_range(insn,
+				(unsigned long)__indirect_thunk_start,
+				(unsigned long)__indirect_thunk_end -
+				(unsigned long)__indirect_thunk_start);
+#endif
+	return ret;
+}
+
 /* Decode whole function to ensure any instructions don't jump into target */
 static int can_optimize(unsigned long paddr)
 {
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 0887d2a..dffe81d 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -538,7 +538,7 @@
 		current->personality &= ~READ_IMPLIES_EXEC;
 		/* in_compat_syscall() uses the presence of the x32
 		   syscall bit flag to determine compat status */
-		current->thread.status &= ~TS_COMPAT;
+		current_thread_info()->status &= ~TS_COMPAT;
 	} else {
 		set_thread_flag(TIF_IA32);
 		clear_thread_flag(TIF_X32);
@@ -546,7 +546,7 @@
 			current->mm->context.ia32_compat = TIF_IA32;
 		current->personality |= force_personality32;
 		/* Prepare the first "return" to user space */
-		current->thread.status |= TS_COMPAT;
+		current_thread_info()->status |= TS_COMPAT;
 	}
 }
 EXPORT_SYMBOL_GPL(set_personality_ia32);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 0e63c02..e497d37 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -934,7 +934,7 @@
 		 */
 		regs->orig_ax = value;
 		if (syscall_get_nr(child, regs) >= 0)
-			child->thread.status |= TS_I386_REGS_POKED;
+			child->thread_info.status |= TS_I386_REGS_POKED;
 		break;
 
 	case offsetof(struct user32, regs.eflags):
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 763af1d..b1a5d25 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -785,7 +785,7 @@
 	 * than the tracee.
 	 */
 #ifdef CONFIG_IA32_EMULATION
-	if (current->thread.status & (TS_COMPAT|TS_I386_REGS_POKED))
+	if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
 		return __NR_ia32_restart_syscall;
 #endif
 #ifdef CONFIG_X86_X32_ABI
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 8402907..21454e2 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -134,6 +134,16 @@
 		return -1;
 	set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
 	pte_unmap(pte);
+
+	/*
+	 * PTI poisons low addresses in the kernel page tables in the
+	 * name of making them unusable for userspace.  To execute
+	 * code at such a low address, the poison must be cleared.
+	 *
+	 * Note: 'pgd' actually gets set in pud_alloc().
+	 */
+	pgd->pgd &= ~_PAGE_NX;
+
 	return 0;
 }
 
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 44bf5cf..d07a9390 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -693,7 +693,6 @@
 		case INTEL_FAM6_KABYLAKE_DESKTOP:
 			crystal_khz = 24000;	/* 24.0 MHz */
 			break;
-		case INTEL_FAM6_SKYLAKE_X:
 		case INTEL_FAM6_ATOM_DENVERTON:
 			crystal_khz = 25000;	/* 25.0 MHz */
 			break;
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index dbf67f6..c7194e9 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -105,6 +105,13 @@
 		SOFTIRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
+
+#ifdef CONFIG_RETPOLINE
+		__indirect_thunk_start = .;
+		*(.text.__x86.indirect_thunk)
+		__indirect_thunk_end = .;
+#endif
+
 		/* End of text section */
 		_etext = .;
 	} :text = 0x9090
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 91af75e..93f924d 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -355,6 +355,10 @@
 		F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
 		0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
+	/* cpuid 0x80000008.ebx */
+	const u32 kvm_cpuid_8000_0008_ebx_x86_features =
+		F(IBPB) | F(IBRS);
+
 	/* cpuid 0xC0000001.edx */
 	const u32 kvm_cpuid_C000_0001_edx_x86_features =
 		F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
@@ -376,6 +380,10 @@
 	/* cpuid 7.0.ecx*/
 	const u32 kvm_cpuid_7_0_ecx_x86_features = F(PKU) | 0 /*OSPKE*/;
 
+	/* cpuid 7.0.edx*/
+	const u32 kvm_cpuid_7_0_edx_x86_features =
+		F(SPEC_CTRL) | F(ARCH_CAPABILITIES);
+
 	/* all calls to cpuid_count() should be made on the same cpu */
 	get_cpu();
 
@@ -458,12 +466,14 @@
 			/* PKU is not yet implemented for shadow paging. */
 			if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
 				entry->ecx &= ~F(PKU);
+			entry->edx &= kvm_cpuid_7_0_edx_x86_features;
+			cpuid_mask(&entry->edx, CPUID_7_EDX);
 		} else {
 			entry->ebx = 0;
 			entry->ecx = 0;
+			entry->edx = 0;
 		}
 		entry->eax = 0;
-		entry->edx = 0;
 		break;
 	}
 	case 9:
@@ -607,7 +617,14 @@
 		if (!g_phys_as)
 			g_phys_as = phys_as;
 		entry->eax = g_phys_as | (virt_as << 8);
-		entry->ebx = entry->edx = 0;
+		entry->edx = 0;
+		/* IBRS and IBPB aren't necessarily present in hardware cpuid */
+		if (boot_cpu_has(X86_FEATURE_IBPB))
+			entry->ebx |= F(IBPB);
+		if (boot_cpu_has(X86_FEATURE_IBRS))
+			entry->ebx |= F(IBRS);
+		entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;
+		cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX);
 		break;
 	}
 	case 0x80000019:
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 9368fec..d1beb71 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -160,6 +160,37 @@
 	return best && (best->edx & bit(X86_FEATURE_RDTSCP));
 }
 
+static inline bool guest_cpuid_has_ibpb(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+	if (best && (best->ebx & bit(X86_FEATURE_IBPB)))
+		return true;
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL));
+}
+
+static inline bool guest_cpuid_has_ibrs(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
+	if (best && (best->ebx & bit(X86_FEATURE_IBRS)))
+		return true;
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL));
+}
+
+static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->edx & bit(X86_FEATURE_ARCH_CAPABILITIES));
+}
+
+
 /*
  * NRIPS is provided through cpuidfn 0x8000000a.edx bit 3
  */
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c8f8dd8..c8d5738 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -25,6 +25,7 @@
 #include <asm/kvm_emulate.h>
 #include <linux/stringify.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 #include "x86.h"
 #include "tss.h"
@@ -1012,8 +1013,8 @@
 	void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf);
 
 	flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
-	asm("push %[flags]; popf; call *%[fastop]"
-	    : "=a"(rc) : [fastop]"r"(fop), [flags]"r"(flags));
+	asm("push %[flags]; popf; " CALL_NOSPEC
+	    : "=a"(rc) : [thunk_target]"r"(fop), [flags]"r"(flags));
 	return rc;
 }
 
@@ -4990,6 +4991,8 @@
 	bool op_prefix = false;
 	bool has_seg_override = false;
 	struct opcode opcode;
+	u16 dummy;
+	struct desc_struct desc;
 
 	ctxt->memop.type = OP_NONE;
 	ctxt->memopp = NULL;
@@ -5008,6 +5011,11 @@
 	switch (mode) {
 	case X86EMUL_MODE_REAL:
 	case X86EMUL_MODE_VM86:
+		def_op_bytes = def_ad_bytes = 2;
+		ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS);
+		if (desc.d)
+			def_op_bytes = def_ad_bytes = 4;
+		break;
 	case X86EMUL_MODE_PROT16:
 		def_op_bytes = def_ad_bytes = 2;
 		break;
@@ -5299,15 +5307,14 @@
 
 static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
 {
-	register void *__sp asm(_ASM_SP);
 	ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
 
 	if (!(ctxt->d & ByteOp))
 		fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
 
-	asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
+	asm("push %[flags]; popf; " CALL_NOSPEC " ; pushf; pop %[flags]\n"
 	    : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
-	      [fastop]"+S"(fop), "+r"(__sp)
+	      [thunk_target]"+S"(fop), ASM_CALL_CONSTRAINT
 	    : "c"(ctxt->src2.val));
 
 	ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 6e219e5..5f810bb 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -257,8 +257,7 @@
 		    index == RTC_GSI) {
 			if (kvm_apic_match_dest(vcpu, NULL, 0,
 			             e->fields.dest_id, e->fields.dest_mode) ||
-			    (e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
-			     kvm_apic_pending_eoi(vcpu, e->fields.vector)))
+			    kvm_apic_pending_eoi(vcpu, e->fields.vector))
 				__set_bit(e->fields.vector,
 					  ioapic_handled_vectors);
 		}
@@ -279,6 +278,7 @@
 {
 	unsigned index;
 	bool mask_before, mask_after;
+	int old_remote_irr, old_delivery_status;
 	union kvm_ioapic_redirect_entry *e;
 
 	switch (ioapic->ioregsel) {
@@ -301,14 +301,28 @@
 			return;
 		e = &ioapic->redirtbl[index];
 		mask_before = e->fields.mask;
+		/* Preserve read-only fields */
+		old_remote_irr = e->fields.remote_irr;
+		old_delivery_status = e->fields.delivery_status;
 		if (ioapic->ioregsel & 1) {
 			e->bits &= 0xffffffff;
 			e->bits |= (u64) val << 32;
 		} else {
 			e->bits &= ~0xffffffffULL;
 			e->bits |= (u32) val;
-			e->fields.remote_irr = 0;
 		}
+		e->fields.remote_irr = old_remote_irr;
+		e->fields.delivery_status = old_delivery_status;
+
+		/*
+		 * Some OSes (Linux, Xen) assume that Remote IRR bit will
+		 * be cleared by IOAPIC hardware when the entry is configured
+		 * as edge-triggered. This behavior is used to simulate an
+		 * explicit EOI on IOAPICs that don't have the EOI register.
+		 */
+		if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
+			e->fields.remote_irr = 0;
+
 		mask_after = e->fields.mask;
 		if (mask_before != mask_after)
 			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 24af898..be644af 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -183,6 +183,8 @@
 		u64 gs_base;
 	} host;
 
+	u64 spec_ctrl;
+
 	u32 *msrpm;
 
 	ulong nmi_iret_rip;
@@ -248,6 +250,8 @@
 	{ .index = MSR_CSTAR,				.always = true  },
 	{ .index = MSR_SYSCALL_MASK,			.always = true  },
 #endif
+	{ .index = MSR_IA32_SPEC_CTRL,			.always = false },
+	{ .index = MSR_IA32_PRED_CMD,			.always = false },
 	{ .index = MSR_IA32_LASTBRANCHFROMIP,		.always = false },
 	{ .index = MSR_IA32_LASTBRANCHTOIP,		.always = false },
 	{ .index = MSR_IA32_LASTINTFROMIP,		.always = false },
@@ -510,6 +514,7 @@
 	struct kvm_ldttss_desc *tss_desc;
 
 	struct page *save_area;
+	struct vmcb *current_vmcb;
 };
 
 static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
@@ -861,6 +866,25 @@
 	return false;
 }
 
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, unsigned msr)
+{
+	u8 bit_write;
+	unsigned long tmp;
+	u32 offset;
+	u32 *msrpm;
+
+	msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
+				      to_svm(vcpu)->msrpm;
+
+	offset    = svm_msrpm_offset(msr);
+	bit_write = 2 * (msr & 0x0f) + 1;
+	tmp       = msrpm[offset];
+
+	BUG_ON(offset == MSR_INVALID);
+
+	return !!test_bit(bit_write,  &tmp);
+}
+
 static void set_msr_interception(u32 *msrpm, unsigned msr,
 				 int read, int write)
 {
@@ -1535,6 +1559,8 @@
 	u32 dummy;
 	u32 eax = 1;
 
+	svm->spec_ctrl = 0;
+
 	if (!init_event) {
 		svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
 					   MSR_IA32_APICBASE_ENABLE;
@@ -1644,11 +1670,17 @@
 	__free_pages(virt_to_page(svm->nested.msrpm), MSRPM_ALLOC_ORDER);
 	kvm_vcpu_uninit(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, svm);
+	/*
+	 * The vmcb page can be recycled, causing a false negative in
+	 * svm_vcpu_load(). So do a full IBPB now.
+	 */
+	indirect_branch_prediction_barrier();
 }
 
 static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
+	struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
 	int i;
 
 	if (unlikely(cpu != vcpu->cpu)) {
@@ -1677,6 +1709,10 @@
 	if (static_cpu_has(X86_FEATURE_RDTSCP))
 		wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
 
+	if (sd->current_vmcb != svm->vmcb) {
+		sd->current_vmcb = svm->vmcb;
+		indirect_branch_prediction_barrier();
+	}
 	avic_vcpu_load(vcpu, cpu);
 }
 
@@ -3508,6 +3544,13 @@
 	case MSR_VM_CR:
 		msr_info->data = svm->nested.vm_cr_msr;
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_ibrs(vcpu))
+			return 1;
+
+		msr_info->data = svm->spec_ctrl;
+		break;
 	case MSR_IA32_UCODE_REV:
 		msr_info->data = 0x01000065;
 		break;
@@ -3599,6 +3642,49 @@
 	case MSR_IA32_TSC:
 		kvm_write_tsc(vcpu, msr);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr->host_initiated &&
+		    !guest_cpuid_has_ibrs(vcpu))
+			return 1;
+
+		/* The STIBP bit doesn't fault even if it's not advertised */
+		if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
+			return 1;
+
+		svm->spec_ctrl = data;
+
+		if (!data)
+			break;
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_svm_vmrun_msrpm.
+		 * We update the L1 MSR bit as well since it will end up
+		 * touching the MSR anyway now.
+		 */
+		set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
+		break;
+	case MSR_IA32_PRED_CMD:
+		if (!msr->host_initiated &&
+		    !guest_cpuid_has_ibpb(vcpu))
+			return 1;
+
+		if (data & ~PRED_CMD_IBPB)
+			return 1;
+
+		if (!data)
+			break;
+
+		wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+		if (is_guest_mode(vcpu))
+			break;
+		set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1);
+		break;
 	case MSR_STAR:
 		svm->vmcb->save.star = data;
 		break;
@@ -4826,6 +4912,15 @@
 
 	local_irq_enable();
 
+	/*
+	 * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+	 * it's non-zero. Since vmentry is serialising on affected CPUs, there
+	 * is no need to worry about the conditional branch over the wrmsr
+	 * being speculatively taken.
+	 */
+	if (svm->spec_ctrl)
+		wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
+
 	asm volatile (
 		"push %%" _ASM_BP "; \n\t"
 		"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -4918,6 +5013,27 @@
 #endif
 		);
 
+	/*
+	 * We do not use IBRS in the kernel. If this vCPU has used the
+	 * SPEC_CTRL MSR it may have left it on; save the value and
+	 * turn it off. This is much more efficient than blindly adding
+	 * it to the atomic save/restore list. Especially as the former
+	 * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+	 *
+	 * For non-nested case:
+	 * If the L01 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 *
+	 * For nested case:
+	 * If the L02 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 */
+	if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
+		rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
+
+	if (svm->spec_ctrl)
+		wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
 	/* Eliminate branch target predictions from guest mode */
 	vmexit_fill_RSB();
 
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3ca6d15..d66224e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/tboot.h>
 #include <linux/hrtimer.h>
+#include <linux/nospec.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
@@ -109,6 +110,14 @@
 static bool __read_mostly enable_pml = 1;
 module_param_named(pml, enable_pml, bool, S_IRUGO);
 
+#define MSR_TYPE_R	1
+#define MSR_TYPE_W	2
+#define MSR_TYPE_RW	3
+
+#define MSR_BITMAP_MODE_X2APIC		1
+#define MSR_BITMAP_MODE_X2APIC_APICV	2
+#define MSR_BITMAP_MODE_LM		4
+
 #define KVM_VMX_TSC_MULTIPLIER_MAX     0xffffffffffffffffULL
 
 /* Guest_tsc -> host_tsc conversion requires 64-bit division.  */
@@ -173,7 +182,6 @@
 extern const ulong vmx_return;
 
 #define NR_AUTOLOAD_MSRS 8
-#define VMCS02_POOL_SIZE 1
 
 struct vmcs {
 	u32 revision_id;
@@ -191,6 +199,7 @@
 	struct vmcs *shadow_vmcs;
 	int cpu;
 	int launched;
+	unsigned long *msr_bitmap;
 	struct list_head loaded_vmcss_on_cpu_link;
 };
 
@@ -207,7 +216,7 @@
  * stored in guest memory specified by VMPTRLD, but is opaque to the guest,
  * which must access it using VMREAD/VMWRITE/VMCLEAR instructions.
  * More than one of these structures may exist, if L1 runs multiple L2 guests.
- * nested_vmx_run() will use the data here to build a vmcs02: a VMCS for the
+ * nested_vmx_run() will use the data here to build the vmcs02: a VMCS for the
  * underlying hardware which will be used to run L2.
  * This structure is packed to ensure that its layout is identical across
  * machines (necessary for live migration).
@@ -386,13 +395,6 @@
  */
 #define VMCS12_SIZE 0x1000
 
-/* Used to remember the last vmcs02 used for some recently used vmcs12s */
-struct vmcs02_list {
-	struct list_head list;
-	gpa_t vmptr;
-	struct loaded_vmcs vmcs02;
-};
-
 /*
  * The nested_vmx structure is part of vcpu_vmx, and holds information we need
  * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -419,15 +421,15 @@
 	 */
 	bool sync_shadow_vmcs;
 
-	/* vmcs02_list cache of VMCSs recently used to run L2 guests */
-	struct list_head vmcs02_pool;
-	int vmcs02_num;
 	bool change_vmcs01_virtual_x2apic_mode;
 	/* L2 must run next, and mustn't decide to exit to L1. */
 	bool nested_run_pending;
+
+	struct loaded_vmcs vmcs02;
+
 	/*
-	 * Guest pages referred to in vmcs02 with host-physical pointers, so
-	 * we must keep them pinned while L2 runs.
+	 * Guest pages referred to in the vmcs02 with host-physical
+	 * pointers, so we must keep them pinned while L2 runs.
 	 */
 	struct page *apic_access_page;
 	struct page *virtual_apic_page;
@@ -436,8 +438,6 @@
 	bool pi_pending;
 	u16 posted_intr_nv;
 
-	unsigned long *msr_bitmap;
-
 	struct hrtimer preemption_timer;
 	bool preemption_timer_expired;
 
@@ -538,6 +538,7 @@
 	unsigned long         host_rsp;
 	u8                    fail;
 	bool                  nmi_known_unmasked;
+	u8		      msr_bitmap_mode;
 	u32                   exit_intr_info;
 	u32                   idt_vectoring_info;
 	ulong                 rflags;
@@ -549,6 +550,10 @@
 	u64 		      msr_host_kernel_gs_base;
 	u64 		      msr_guest_kernel_gs_base;
 #endif
+
+	u64 		      arch_capabilities;
+	u64 		      spec_ctrl;
+
 	u32 vm_entry_controls_shadow;
 	u32 vm_exit_controls_shadow;
 	/*
@@ -856,21 +861,18 @@
 
 static inline short vmcs_field_to_offset(unsigned long field)
 {
-	BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+	const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
+	unsigned short offset;
 
-	if (field >= ARRAY_SIZE(vmcs_field_to_offset_table))
+	BUILD_BUG_ON(size > SHRT_MAX);
+	if (field >= size)
 		return -ENOENT;
 
-	/*
-	 * FIXME: Mitigation for CVE-2017-5753.  To be replaced with a
-	 * generic mechanism.
-	 */
-	asm("lfence");
-
-	if (vmcs_field_to_offset_table[field] == 0)
+	field = array_index_nospec(field, size);
+	offset = vmcs_field_to_offset_table[field];
+	if (offset == 0)
 		return -ENOENT;
-
-	return vmcs_field_to_offset_table[field];
+	return offset;
 }
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
@@ -912,6 +914,9 @@
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
 static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
 static int alloc_identity_pagetable(struct kvm *kvm);
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu);
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+							  u32 msr, int type);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -931,12 +936,6 @@
 
 static unsigned long *vmx_io_bitmap_a;
 static unsigned long *vmx_io_bitmap_b;
-static unsigned long *vmx_msr_bitmap_legacy;
-static unsigned long *vmx_msr_bitmap_longmode;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
 static unsigned long *vmx_vmread_bitmap;
 static unsigned long *vmx_vmwrite_bitmap;
 
@@ -1853,6 +1852,52 @@
 	vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
+/*
+ * Check if MSR is intercepted for currently loaded MSR bitmap.
+ */
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
+{
+	unsigned long *msr_bitmap;
+	int f = sizeof(unsigned long);
+
+	if (!cpu_has_vmx_msr_bitmap())
+		return true;
+
+	msr_bitmap = to_vmx(vcpu)->loaded_vmcs->msr_bitmap;
+
+	if (msr <= 0x1fff) {
+		return !!test_bit(msr, msr_bitmap + 0x800 / f);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff;
+		return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+	}
+
+	return true;
+}
+
+/*
+ * Check if MSR is intercepted for L01 MSR bitmap.
+ */
+static bool msr_write_intercepted_l01(struct kvm_vcpu *vcpu, u32 msr)
+{
+	unsigned long *msr_bitmap;
+	int f = sizeof(unsigned long);
+
+	if (!cpu_has_vmx_msr_bitmap())
+		return true;
+
+	msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
+
+	if (msr <= 0x1fff) {
+		return !!test_bit(msr, msr_bitmap + 0x800 / f);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff;
+		return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+	}
+
+	return true;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 		unsigned long entry, unsigned long exit)
 {
@@ -2262,6 +2307,7 @@
 	if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
 		per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
 		vmcs_load(vmx->loaded_vmcs->vmcs);
+		indirect_branch_prediction_barrier();
 	}
 
 	if (!already_loaded) {
@@ -2530,36 +2576,6 @@
 	vmx->guest_msrs[from] = tmp;
 }
 
-static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
-{
-	unsigned long *msr_bitmap;
-
-	if (is_guest_mode(vcpu))
-		msr_bitmap = to_vmx(vcpu)->nested.msr_bitmap;
-	else if (cpu_has_secondary_exec_ctrls() &&
-		 (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
-		  SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
-		if (enable_apicv && kvm_vcpu_apicv_active(vcpu)) {
-			if (is_long_mode(vcpu))
-				msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
-			else
-				msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
-		} else {
-			if (is_long_mode(vcpu))
-				msr_bitmap = vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
-			else
-				msr_bitmap = vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
-		}
-	} else {
-		if (is_long_mode(vcpu))
-			msr_bitmap = vmx_msr_bitmap_longmode;
-		else
-			msr_bitmap = vmx_msr_bitmap_legacy;
-	}
-
-	vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
-}
-
 /*
  * Set up the vmcs to automatically save and restore system
  * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
@@ -2600,7 +2616,7 @@
 	vmx->save_nmsrs = save_nmsrs;
 
 	if (cpu_has_vmx_msr_bitmap())
-		vmx_set_msr_bitmap(&vmx->vcpu);
+		vmx_update_msr_bitmap(&vmx->vcpu);
 }
 
 /*
@@ -2989,6 +3005,19 @@
 	case MSR_IA32_TSC:
 		msr_info->data = guest_read_tsc(vcpu);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_ibrs(vcpu))
+			return 1;
+
+		msr_info->data = to_vmx(vcpu)->spec_ctrl;
+		break;
+	case MSR_IA32_ARCH_CAPABILITIES:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_arch_capabilities(vcpu))
+			return 1;
+		msr_info->data = to_vmx(vcpu)->arch_capabilities;
+		break;
 	case MSR_IA32_SYSENTER_CS:
 		msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
 		break;
@@ -3093,6 +3122,68 @@
 	case MSR_IA32_TSC:
 		kvm_write_tsc(vcpu, msr_info);
 		break;
+	case MSR_IA32_SPEC_CTRL:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_ibrs(vcpu))
+			return 1;
+
+		/* The STIBP bit doesn't fault even if it's not advertised */
+		if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
+			return 1;
+
+		vmx->spec_ctrl = data;
+
+		if (!data)
+			break;
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_vmx_merge_msr_bitmap. We should not touch the
+		 * vmcs02.msr_bitmap here since it gets completely overwritten
+		 * in the merging. We update the vmcs01 here for L1 as well
+		 * since it will end up touching the MSR anyway now.
+		 */
+		vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap,
+					      MSR_IA32_SPEC_CTRL,
+					      MSR_TYPE_RW);
+		break;
+	case MSR_IA32_PRED_CMD:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has_ibpb(vcpu))
+			return 1;
+
+		if (data & ~PRED_CMD_IBPB)
+			return 1;
+
+		if (!data)
+			break;
+
+		wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+
+		/*
+		 * For non-nested:
+		 * When it's written (to non-zero) for the first time, pass
+		 * it through.
+		 *
+		 * For nested:
+		 * The handling of the MSR bitmap for L2 guests is done in
+		 * nested_vmx_merge_msr_bitmap. We should not touch the
+		 * vmcs02.msr_bitmap here since it gets completely overwritten
+		 * in the merging.
+		 */
+		vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, MSR_IA32_PRED_CMD,
+					      MSR_TYPE_W);
+		break;
+	case MSR_IA32_ARCH_CAPABILITIES:
+		if (!msr_info->host_initiated)
+			return 1;
+		vmx->arch_capabilities = data;
+		break;
 	case MSR_IA32_CR_PAT:
 		if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
 			if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
@@ -3532,11 +3623,6 @@
 	return vmcs;
 }
 
-static struct vmcs *alloc_vmcs(void)
-{
-	return alloc_vmcs_cpu(raw_smp_processor_id());
-}
-
 static void free_vmcs(struct vmcs *vmcs)
 {
 	free_pages((unsigned long)vmcs, vmcs_config.order);
@@ -3552,9 +3638,38 @@
 	loaded_vmcs_clear(loaded_vmcs);
 	free_vmcs(loaded_vmcs->vmcs);
 	loaded_vmcs->vmcs = NULL;
+	if (loaded_vmcs->msr_bitmap)
+		free_page((unsigned long)loaded_vmcs->msr_bitmap);
 	WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
 }
 
+static struct vmcs *alloc_vmcs(void)
+{
+	return alloc_vmcs_cpu(raw_smp_processor_id());
+}
+
+static int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
+{
+	loaded_vmcs->vmcs = alloc_vmcs();
+	if (!loaded_vmcs->vmcs)
+		return -ENOMEM;
+
+	loaded_vmcs->shadow_vmcs = NULL;
+	loaded_vmcs_init(loaded_vmcs);
+
+	if (cpu_has_vmx_msr_bitmap()) {
+		loaded_vmcs->msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
+		if (!loaded_vmcs->msr_bitmap)
+			goto out_vmcs;
+		memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE);
+	}
+	return 0;
+
+out_vmcs:
+	free_loaded_vmcs(loaded_vmcs);
+	return -ENOMEM;
+}
+
 static void free_kvm_area(void)
 {
 	int cpu;
@@ -4561,10 +4676,8 @@
 	spin_unlock(&vmx_vpid_lock);
 }
 
-#define MSR_TYPE_R	1
-#define MSR_TYPE_W	2
-static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
-						u32 msr, int type)
+static void __always_inline vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+							  u32 msr, int type)
 {
 	int f = sizeof(unsigned long);
 
@@ -4598,8 +4711,8 @@
 	}
 }
 
-static void __vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
-						u32 msr, int type)
+static void __always_inline vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
+							 u32 msr, int type)
 {
 	int f = sizeof(unsigned long);
 
@@ -4633,6 +4746,15 @@
 	}
 }
 
+static void __always_inline vmx_set_intercept_for_msr(unsigned long *msr_bitmap,
+			     			      u32 msr, int type, bool value)
+{
+	if (value)
+		vmx_enable_intercept_for_msr(msr_bitmap, msr, type);
+	else
+		vmx_disable_intercept_for_msr(msr_bitmap, msr, type);
+}
+
 /*
  * If a msr is allowed by L0, we should check whether it is allowed by L1.
  * The corresponding bit will be cleared unless both of L0 and L1 allow it.
@@ -4679,58 +4801,68 @@
 	}
 }
 
-static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
+static u8 vmx_msr_bitmap_mode(struct kvm_vcpu *vcpu)
 {
-	if (!longmode_only)
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy,
-						msr, MSR_TYPE_R | MSR_TYPE_W);
-	__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode,
-						msr, MSR_TYPE_R | MSR_TYPE_W);
+	u8 mode = 0;
+
+	if (cpu_has_secondary_exec_ctrls() &&
+	    (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
+	     SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
+		mode |= MSR_BITMAP_MODE_X2APIC;
+		if (enable_apicv && kvm_vcpu_apicv_active(vcpu))
+			mode |= MSR_BITMAP_MODE_X2APIC_APICV;
+	}
+
+	if (is_long_mode(vcpu))
+		mode |= MSR_BITMAP_MODE_LM;
+
+	return mode;
 }
 
-static void vmx_enable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
+#define X2APIC_MSR(r) (APIC_BASE_MSR + ((r) >> 4))
+
+static void vmx_update_msr_bitmap_x2apic(unsigned long *msr_bitmap,
+					 u8 mode)
 {
-	if (apicv_active) {
-		__vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-				msr, MSR_TYPE_R);
-		__vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-				msr, MSR_TYPE_R);
-	} else {
-		__vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
-				msr, MSR_TYPE_R);
-		__vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
-				msr, MSR_TYPE_R);
+	int msr;
+
+	for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
+		unsigned word = msr / BITS_PER_LONG;
+		msr_bitmap[word] = (mode & MSR_BITMAP_MODE_X2APIC_APICV) ? 0 : ~0;
+		msr_bitmap[word + (0x800 / sizeof(long))] = ~0;
+	}
+
+	if (mode & MSR_BITMAP_MODE_X2APIC) {
+		/*
+		 * TPR reads and writes can be virtualized even if virtual interrupt
+		 * delivery is not in use.
+		 */
+		vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TASKPRI), MSR_TYPE_RW);
+		if (mode & MSR_BITMAP_MODE_X2APIC_APICV) {
+			vmx_enable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_TMCCT), MSR_TYPE_R);
+			vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_EOI), MSR_TYPE_W);
+			vmx_disable_intercept_for_msr(msr_bitmap, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W);
+		}
 	}
 }
 
-static void vmx_disable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
+static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu)
 {
-	if (apicv_active) {
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-				msr, MSR_TYPE_R);
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-				msr, MSR_TYPE_R);
-	} else {
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
-				msr, MSR_TYPE_R);
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
-				msr, MSR_TYPE_R);
-	}
-}
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	unsigned long *msr_bitmap = vmx->vmcs01.msr_bitmap;
+	u8 mode = vmx_msr_bitmap_mode(vcpu);
+	u8 changed = mode ^ vmx->msr_bitmap_mode;
 
-static void vmx_disable_intercept_msr_write_x2apic(u32 msr, bool apicv_active)
-{
-	if (apicv_active) {
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
-				msr, MSR_TYPE_W);
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
-				msr, MSR_TYPE_W);
-	} else {
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
-				msr, MSR_TYPE_W);
-		__vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
-				msr, MSR_TYPE_W);
-	}
+	if (!changed)
+		return;
+
+	vmx_set_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW,
+				  !(mode & MSR_BITMAP_MODE_LM));
+
+	if (changed & (MSR_BITMAP_MODE_X2APIC | MSR_BITMAP_MODE_X2APIC_APICV))
+		vmx_update_msr_bitmap_x2apic(msr_bitmap, mode);
+
+	vmx->msr_bitmap_mode = mode;
 }
 
 static bool vmx_get_enable_apicv(void)
@@ -4738,30 +4870,45 @@
 	return enable_apicv;
 }
 
-static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+static void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu)
+{
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+	gfn_t gfn;
+
+	/*
+	 * Don't need to mark the APIC access page dirty; it is never
+	 * written to by the CPU during APIC virtualization.
+	 */
+
+	if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) {
+		gfn = vmcs12->virtual_apic_page_addr >> PAGE_SHIFT;
+		kvm_vcpu_mark_page_dirty(vcpu, gfn);
+	}
+
+	if (nested_cpu_has_posted_intr(vmcs12)) {
+		gfn = vmcs12->posted_intr_desc_addr >> PAGE_SHIFT;
+		kvm_vcpu_mark_page_dirty(vcpu, gfn);
+	}
+}
+
+
+static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	int max_irr;
 	void *vapic_page;
 	u16 status;
 
-	if (vmx->nested.pi_desc &&
-	    vmx->nested.pi_pending) {
-		vmx->nested.pi_pending = false;
-		if (!pi_test_and_clear_on(vmx->nested.pi_desc))
-			return 0;
+	if (!vmx->nested.pi_desc || !vmx->nested.pi_pending)
+		return;
 
-		max_irr = find_last_bit(
-			(unsigned long *)vmx->nested.pi_desc->pir, 256);
+	vmx->nested.pi_pending = false;
+	if (!pi_test_and_clear_on(vmx->nested.pi_desc))
+		return;
 
-		if (max_irr == 256)
-			return 0;
-
+	max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
+	if (max_irr != 256) {
 		vapic_page = kmap(vmx->nested.virtual_apic_page);
-		if (!vapic_page) {
-			WARN_ON(1);
-			return -ENOMEM;
-		}
 		__kvm_apic_update_irr(vmx->nested.pi_desc->pir, vapic_page);
 		kunmap(vmx->nested.virtual_apic_page);
 
@@ -4772,7 +4919,8 @@
 			vmcs_write16(GUEST_INTR_STATUS, status);
 		}
 	}
-	return 0;
+
+	nested_mark_vmcs12_pages_dirty(vcpu);
 }
 
 static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -4819,14 +4967,15 @@
 
 	if (is_guest_mode(vcpu) &&
 	    vector == vmx->nested.posted_intr_nv) {
-		/* the PIR and ON have been set by L1. */
-		kvm_vcpu_trigger_posted_interrupt(vcpu);
 		/*
 		 * If a posted intr is not recognized by hardware,
 		 * we will accomplish it in the next vmentry.
 		 */
 		vmx->nested.pi_pending = true;
 		kvm_make_request(KVM_REQ_EVENT, vcpu);
+		/* the PIR and ON have been set by L1. */
+		if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
+			kvm_vcpu_kick(vcpu);
 		return 0;
 	}
 	return -1;
@@ -4959,7 +5108,7 @@
 	}
 
 	if (cpu_has_vmx_msr_bitmap())
-		vmx_set_msr_bitmap(vcpu);
+		vmx_update_msr_bitmap(vcpu);
 }
 
 static u32 vmx_exec_control(struct vcpu_vmx *vmx)
@@ -5048,7 +5197,7 @@
 		vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap));
 	}
 	if (cpu_has_vmx_msr_bitmap())
-		vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy));
+		vmcs_write64(MSR_BITMAP, __pa(vmx->vmcs01.msr_bitmap));
 
 	vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
 
@@ -5122,6 +5271,8 @@
 		++vmx->nmsrs;
 	}
 
+	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
+		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, vmx->arch_capabilities);
 
 	vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl);
 
@@ -5150,6 +5301,7 @@
 	u64 cr0;
 
 	vmx->rmode.vm86_active = 0;
+	vmx->spec_ctrl = 0;
 
 	vmx->soft_vnmi_blocked = 0;
 
@@ -5194,7 +5346,7 @@
 		vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 	}
 
-	vmcs_writel(GUEST_RFLAGS, 0x02);
+	kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
 	kvm_rip_write(vcpu, 0xfff0);
 
 	vmcs_writel(GUEST_GDTR_BASE, 0);
@@ -6257,7 +6409,7 @@
 		if (test_bit(KVM_REQ_EVENT, &vcpu->requests))
 			return 1;
 
-		err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE);
+		err = emulate_instruction(vcpu, 0);
 
 		if (err == EMULATE_USER_EXIT) {
 			++vcpu->stat.mmio_exits;
@@ -6379,7 +6531,7 @@
 
 static __init int hardware_setup(void)
 {
-	int r = -ENOMEM, i, msr;
+	int r = -ENOMEM, i;
 
 	rdmsrl_safe(MSR_EFER, &host_efer);
 
@@ -6394,41 +6546,13 @@
 	if (!vmx_io_bitmap_b)
 		goto out;
 
-	vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_legacy)
-		goto out1;
-
-	vmx_msr_bitmap_legacy_x2apic =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_legacy_x2apic)
-		goto out2;
-
-	vmx_msr_bitmap_legacy_x2apic_apicv_inactive =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_legacy_x2apic_apicv_inactive)
-		goto out3;
-
-	vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_longmode)
-		goto out4;
-
-	vmx_msr_bitmap_longmode_x2apic =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_longmode_x2apic)
-		goto out5;
-
-	vmx_msr_bitmap_longmode_x2apic_apicv_inactive =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-	if (!vmx_msr_bitmap_longmode_x2apic_apicv_inactive)
-		goto out6;
-
 	vmx_vmread_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
 	if (!vmx_vmread_bitmap)
-		goto out7;
+		goto out1;
 
 	vmx_vmwrite_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
 	if (!vmx_vmwrite_bitmap)
-		goto out8;
+		goto out2;
 
 	memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
 	memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
@@ -6437,12 +6561,9 @@
 
 	memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
 
-	memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
-	memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
-
 	if (setup_vmcs_config(&vmcs_config) < 0) {
 		r = -EIO;
-		goto out9;
+		goto out3;
 	}
 
 	if (boot_cpu_has(X86_FEATURE_NX))
@@ -6499,47 +6620,8 @@
 		kvm_tsc_scaling_ratio_frac_bits = 48;
 	}
 
-	vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
-	vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
-	vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
-	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
-
-	memcpy(vmx_msr_bitmap_legacy_x2apic,
-			vmx_msr_bitmap_legacy, PAGE_SIZE);
-	memcpy(vmx_msr_bitmap_longmode_x2apic,
-			vmx_msr_bitmap_longmode, PAGE_SIZE);
-	memcpy(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
-			vmx_msr_bitmap_legacy, PAGE_SIZE);
-	memcpy(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
-			vmx_msr_bitmap_longmode, PAGE_SIZE);
-
 	set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
 
-	/*
-	 * enable_apicv && kvm_vcpu_apicv_active()
-	 */
-	for (msr = 0x800; msr <= 0x8ff; msr++)
-		vmx_disable_intercept_msr_read_x2apic(msr, true);
-
-	/* TMCCT */
-	vmx_enable_intercept_msr_read_x2apic(0x839, true);
-	/* TPR */
-	vmx_disable_intercept_msr_write_x2apic(0x808, true);
-	/* EOI */
-	vmx_disable_intercept_msr_write_x2apic(0x80b, true);
-	/* SELF-IPI */
-	vmx_disable_intercept_msr_write_x2apic(0x83f, true);
-
-	/*
-	 * (enable_apicv && !kvm_vcpu_apicv_active()) ||
-	 * 	!enable_apicv
-	 */
-	/* TPR */
-	vmx_disable_intercept_msr_read_x2apic(0x808, false);
-	vmx_disable_intercept_msr_write_x2apic(0x808, false);
-
 	if (enable_ept) {
 		kvm_mmu_set_mask_ptes(VMX_EPT_READABLE_MASK,
 			(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
@@ -6585,22 +6667,10 @@
 
 	return alloc_kvm_area();
 
-out9:
-	free_page((unsigned long)vmx_vmwrite_bitmap);
-out8:
-	free_page((unsigned long)vmx_vmread_bitmap);
-out7:
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
-out6:
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-out5:
-	free_page((unsigned long)vmx_msr_bitmap_longmode);
-out4:
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
 out3:
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
+	free_page((unsigned long)vmx_vmwrite_bitmap);
 out2:
-	free_page((unsigned long)vmx_msr_bitmap_legacy);
+	free_page((unsigned long)vmx_vmread_bitmap);
 out1:
 	free_page((unsigned long)vmx_io_bitmap_b);
 out:
@@ -6611,12 +6681,6 @@
 
 static __exit void hardware_unsetup(void)
 {
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
-	free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-	free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
-	free_page((unsigned long)vmx_msr_bitmap_legacy);
-	free_page((unsigned long)vmx_msr_bitmap_longmode);
 	free_page((unsigned long)vmx_io_bitmap_b);
 	free_page((unsigned long)vmx_io_bitmap_a);
 	free_page((unsigned long)vmx_vmwrite_bitmap);
@@ -6664,94 +6728,6 @@
 }
 
 /*
- * To run an L2 guest, we need a vmcs02 based on the L1-specified vmcs12.
- * We could reuse a single VMCS for all the L2 guests, but we also want the
- * option to allocate a separate vmcs02 for each separate loaded vmcs12 - this
- * allows keeping them loaded on the processor, and in the future will allow
- * optimizations where prepare_vmcs02 doesn't need to set all the fields on
- * every entry if they never change.
- * So we keep, in vmx->nested.vmcs02_pool, a cache of size VMCS02_POOL_SIZE
- * (>=0) with a vmcs02 for each recently loaded vmcs12s, most recent first.
- *
- * The following functions allocate and free a vmcs02 in this pool.
- */
-
-/* Get a VMCS from the pool to use as vmcs02 for the current vmcs12. */
-static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
-{
-	struct vmcs02_list *item;
-	list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
-		if (item->vmptr == vmx->nested.current_vmptr) {
-			list_move(&item->list, &vmx->nested.vmcs02_pool);
-			return &item->vmcs02;
-		}
-
-	if (vmx->nested.vmcs02_num >= max(VMCS02_POOL_SIZE, 1)) {
-		/* Recycle the least recently used VMCS. */
-		item = list_last_entry(&vmx->nested.vmcs02_pool,
-				       struct vmcs02_list, list);
-		item->vmptr = vmx->nested.current_vmptr;
-		list_move(&item->list, &vmx->nested.vmcs02_pool);
-		return &item->vmcs02;
-	}
-
-	/* Create a new VMCS */
-	item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL);
-	if (!item)
-		return NULL;
-	item->vmcs02.vmcs = alloc_vmcs();
-	item->vmcs02.shadow_vmcs = NULL;
-	if (!item->vmcs02.vmcs) {
-		kfree(item);
-		return NULL;
-	}
-	loaded_vmcs_init(&item->vmcs02);
-	item->vmptr = vmx->nested.current_vmptr;
-	list_add(&(item->list), &(vmx->nested.vmcs02_pool));
-	vmx->nested.vmcs02_num++;
-	return &item->vmcs02;
-}
-
-/* Free and remove from pool a vmcs02 saved for a vmcs12 (if there is one) */
-static void nested_free_vmcs02(struct vcpu_vmx *vmx, gpa_t vmptr)
-{
-	struct vmcs02_list *item;
-	list_for_each_entry(item, &vmx->nested.vmcs02_pool, list)
-		if (item->vmptr == vmptr) {
-			free_loaded_vmcs(&item->vmcs02);
-			list_del(&item->list);
-			kfree(item);
-			vmx->nested.vmcs02_num--;
-			return;
-		}
-}
-
-/*
- * Free all VMCSs saved for this vcpu, except the one pointed by
- * vmx->loaded_vmcs. We must be running L1, so vmx->loaded_vmcs
- * must be &vmx->vmcs01.
- */
-static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx)
-{
-	struct vmcs02_list *item, *n;
-
-	WARN_ON(vmx->loaded_vmcs != &vmx->vmcs01);
-	list_for_each_entry_safe(item, n, &vmx->nested.vmcs02_pool, list) {
-		/*
-		 * Something will leak if the above WARN triggers.  Better than
-		 * a use-after-free.
-		 */
-		if (vmx->loaded_vmcs == &item->vmcs02)
-			continue;
-
-		free_loaded_vmcs(&item->vmcs02);
-		list_del(&item->list);
-		kfree(item);
-		vmx->nested.vmcs02_num--;
-	}
-}
-
-/*
  * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
  * set the success or error code of an emulated VMX instruction, as specified
  * by Vol 2B, VMX Instruction Reference, "Conventions".
@@ -7025,6 +7001,7 @@
 	struct vmcs *shadow_vmcs;
 	const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
 		| FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
+	int r;
 
 	/* The Intel VMX Instruction Reference lists a bunch of bits that
 	 * are prerequisite to running VMXON, most notably cr4.VMXE must be
@@ -7064,12 +7041,9 @@
 		return 1;
 	}
 
-	if (cpu_has_vmx_msr_bitmap()) {
-		vmx->nested.msr_bitmap =
-				(unsigned long *)__get_free_page(GFP_KERNEL);
-		if (!vmx->nested.msr_bitmap)
-			goto out_msr_bitmap;
-	}
+	r = alloc_loaded_vmcs(&vmx->nested.vmcs02);
+	if (r < 0)
+		goto out_vmcs02;
 
 	vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL);
 	if (!vmx->nested.cached_vmcs12)
@@ -7086,9 +7060,6 @@
 		vmx->vmcs01.shadow_vmcs = shadow_vmcs;
 	}
 
-	INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
-	vmx->nested.vmcs02_num = 0;
-
 	hrtimer_init(&vmx->nested.preemption_timer, CLOCK_MONOTONIC,
 		     HRTIMER_MODE_REL_PINNED);
 	vmx->nested.preemption_timer.function = vmx_preemption_timer_fn;
@@ -7103,9 +7074,9 @@
 	kfree(vmx->nested.cached_vmcs12);
 
 out_cached_vmcs12:
-	free_page((unsigned long)vmx->nested.msr_bitmap);
+	free_loaded_vmcs(&vmx->nested.vmcs02);
 
-out_msr_bitmap:
+out_vmcs02:
 	return -ENOMEM;
 }
 
@@ -7181,17 +7152,13 @@
 	vmx->nested.vmxon = false;
 	free_vpid(vmx->nested.vpid02);
 	nested_release_vmcs12(vmx);
-	if (vmx->nested.msr_bitmap) {
-		free_page((unsigned long)vmx->nested.msr_bitmap);
-		vmx->nested.msr_bitmap = NULL;
-	}
 	if (enable_shadow_vmcs) {
 		vmcs_clear(vmx->vmcs01.shadow_vmcs);
 		free_vmcs(vmx->vmcs01.shadow_vmcs);
 		vmx->vmcs01.shadow_vmcs = NULL;
 	}
 	kfree(vmx->nested.cached_vmcs12);
-	/* Unpin physical memory we referred to in current vmcs02 */
+	/* Unpin physical memory we referred to in the vmcs02 */
 	if (vmx->nested.apic_access_page) {
 		nested_release_page(vmx->nested.apic_access_page);
 		vmx->nested.apic_access_page = NULL;
@@ -7207,7 +7174,7 @@
 		vmx->nested.pi_desc = NULL;
 	}
 
-	nested_free_all_saved_vmcss(vmx);
+	free_loaded_vmcs(&vmx->nested.vmcs02);
 }
 
 /* Emulate the VMXOFF instruction */
@@ -7241,8 +7208,6 @@
 			vmptr + offsetof(struct vmcs12, launch_state),
 			&zero, sizeof(zero));
 
-	nested_free_vmcs02(vmx, vmptr);
-
 	skip_emulated_instruction(vcpu);
 	nested_vmx_succeed(vcpu);
 	return 1;
@@ -8029,6 +7994,19 @@
 				vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
 				KVM_ISA_VMX);
 
+	/*
+	 * The host physical addresses of some pages of guest memory
+	 * are loaded into the vmcs02 (e.g. vmcs12's Virtual APIC
+	 * Page). The CPU may write to these pages via their host
+	 * physical address while L2 is running, bypassing any
+	 * address-translation-based dirty tracking (e.g. EPT write
+	 * protection).
+	 *
+	 * Mark them dirty on every exit from L2 to prevent them from
+	 * getting out of sync with dirty tracking.
+	 */
+	nested_mark_vmcs12_pages_dirty(vcpu);
+
 	if (vmx->nested.nested_run_pending)
 		return false;
 
@@ -8520,7 +8498,7 @@
 	}
 	vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control);
 
-	vmx_set_msr_bitmap(vcpu);
+	vmx_update_msr_bitmap(vcpu);
 }
 
 static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa)
@@ -8676,14 +8654,14 @@
 #endif
 			"pushf\n\t"
 			__ASM_SIZE(push) " $%c[cs]\n\t"
-			"call *%[entry]\n\t"
+			CALL_NOSPEC
 			:
 #ifdef CONFIG_X86_64
 			[sp]"=&r"(tmp),
 #endif
 			"+r"(__sp)
 			:
-			[entry]"r"(entry),
+			THUNK_TARGET(entry),
 			[ss]"i"(__KERNEL_DS),
 			[cs]"i"(__KERNEL_CS)
 			);
@@ -8909,6 +8887,15 @@
 
 	vmx_arm_hv_timer(vcpu);
 
+	/*
+	 * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+	 * it's non-zero. Since vmentry is serialising on affected CPUs, there
+	 * is no need to worry about the conditional branch over the wrmsr
+	 * being speculatively taken.
+	 */
+	if (vmx->spec_ctrl)
+		wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl);
+
 	vmx->__launched = vmx->loaded_vmcs->launched;
 	asm(
 		/* Store host registers */
@@ -9027,6 +9014,27 @@
 #endif
 	      );
 
+	/*
+	 * We do not use IBRS in the kernel. If this vCPU has used the
+	 * SPEC_CTRL MSR it may have left it on; save the value and
+	 * turn it off. This is much more efficient than blindly adding
+	 * it to the atomic save/restore list. Especially as the former
+	 * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+	 *
+	 * For non-nested case:
+	 * If the L01 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 *
+	 * For nested case:
+	 * If the L02 MSR bitmap does not intercept the MSR, then we need to
+	 * save it.
+	 */
+	if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
+		rdmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl);
+
+	if (vmx->spec_ctrl)
+		wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
 	/* Eliminate branch target predictions from guest mode */
 	vmexit_fill_RSB();
 
@@ -9140,6 +9148,7 @@
 {
 	int err;
 	struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+	unsigned long *msr_bitmap;
 	int cpu;
 
 	if (!vmx)
@@ -9172,17 +9181,24 @@
 	if (!vmx->guest_msrs)
 		goto free_pml;
 
-	vmx->loaded_vmcs = &vmx->vmcs01;
-	vmx->loaded_vmcs->vmcs = alloc_vmcs();
-	vmx->loaded_vmcs->shadow_vmcs = NULL;
-	if (!vmx->loaded_vmcs->vmcs)
-		goto free_msrs;
 	if (!vmm_exclusive)
 		kvm_cpu_vmxon(__pa(per_cpu(vmxarea, raw_smp_processor_id())));
-	loaded_vmcs_init(vmx->loaded_vmcs);
+	err = alloc_loaded_vmcs(&vmx->vmcs01);
 	if (!vmm_exclusive)
 		kvm_cpu_vmxoff();
+	if (err < 0)
+		goto free_msrs;
 
+	msr_bitmap = vmx->vmcs01.msr_bitmap;
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_FS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_GS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_CS, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW);
+	vmx_disable_intercept_for_msr(msr_bitmap, MSR_IA32_SYSENTER_EIP, MSR_TYPE_RW);
+	vmx->msr_bitmap_mode = 0;
+
+	vmx->loaded_vmcs = &vmx->vmcs01;
 	cpu = get_cpu();
 	vmx_vcpu_load(&vmx->vcpu, cpu);
 	vmx->vcpu.cpu = cpu;
@@ -9576,21 +9592,31 @@
 	int msr;
 	struct page *page;
 	unsigned long *msr_bitmap_l1;
-	unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.msr_bitmap;
+	unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
+	/*
+	 * pred_cmd & spec_ctrl are trying to verify two things:
+	 *
+	 * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
+	 *    ensures that we do not accidentally generate an L02 MSR bitmap
+	 *    from the L12 MSR bitmap that is too permissive.
+	 * 2. That L1 or L2s have actually used the MSR. This avoids
+	 *    unnecessarily merging of the bitmap if the MSR is unused. This
+	 *    works properly because we only update the L01 MSR bitmap lazily.
+	 *    So even if L0 should pass L1 these MSRs, the L01 bitmap is only
+	 *    updated to reflect this when L1 (or its L2s) actually write to
+	 *    the MSR.
+	 */
+	bool pred_cmd = msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD);
+	bool spec_ctrl = msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL);
 
-	/* This shortcut is ok because we support only x2APIC MSRs so far. */
-	if (!nested_cpu_has_virt_x2apic_mode(vmcs12))
+	if (!nested_cpu_has_virt_x2apic_mode(vmcs12) &&
+	    !pred_cmd && !spec_ctrl)
 		return false;
 
 	page = nested_get_page(vcpu, vmcs12->msr_bitmap);
 	if (!page)
 		return false;
 	msr_bitmap_l1 = (unsigned long *)kmap(page);
-	if (!msr_bitmap_l1) {
-		nested_release_page_clean(page);
-		WARN_ON(1);
-		return false;
-	}
 
 	memset(msr_bitmap_l0, 0xff, PAGE_SIZE);
 
@@ -9617,6 +9643,19 @@
 				MSR_TYPE_W);
 		}
 	}
+
+	if (spec_ctrl)
+		nested_vmx_disable_intercept_for_msr(
+					msr_bitmap_l1, msr_bitmap_l0,
+					MSR_IA32_SPEC_CTRL,
+					MSR_TYPE_R | MSR_TYPE_W);
+
+	if (pred_cmd)
+		nested_vmx_disable_intercept_for_msr(
+					msr_bitmap_l1, msr_bitmap_l0,
+					MSR_IA32_PRED_CMD,
+					MSR_TYPE_W);
+
 	kunmap(page);
 	nested_release_page_clean(page);
 
@@ -10096,6 +10135,9 @@
 	if (kvm_has_tsc_control)
 		decache_tsc_multiplier(vmx);
 
+	if (cpu_has_vmx_msr_bitmap())
+		vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap));
+
 	if (enable_vpid) {
 		/*
 		 * There is no direct mapping between vpid02 and vpid12, the
@@ -10191,7 +10233,6 @@
 	struct vmcs12 *vmcs12;
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	int cpu;
-	struct loaded_vmcs *vmcs02;
 	bool ia32e;
 	u32 msr_entry_idx;
 
@@ -10331,17 +10372,13 @@
 	 * the nested entry.
 	 */
 
-	vmcs02 = nested_get_current_vmcs02(vmx);
-	if (!vmcs02)
-		return -ENOMEM;
-
 	enter_guest_mode(vcpu);
 
 	if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
 		vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
 
 	cpu = get_cpu();
-	vmx->loaded_vmcs = vmcs02;
+	vmx->loaded_vmcs = &vmx->nested.vmcs02;
 	vmx_vcpu_put(vcpu);
 	vmx_vcpu_load(vcpu, cpu);
 	vcpu->cpu = cpu;
@@ -10493,7 +10530,8 @@
 		return 0;
 	}
 
-	return vmx_complete_nested_posted_interrupt(vcpu);
+	vmx_complete_nested_posted_interrupt(vcpu);
+	return 0;
 }
 
 static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
@@ -10804,7 +10842,7 @@
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 
 	if (cpu_has_vmx_msr_bitmap())
-		vmx_set_msr_bitmap(vcpu);
+		vmx_update_msr_bitmap(vcpu);
 
 	if (nested_vmx_load_msr(vcpu, vmcs12->vm_exit_msr_load_addr,
 				vmcs12->vm_exit_msr_load_count))
@@ -10855,10 +10893,6 @@
 	vm_exit_controls_reset_shadow(vmx);
 	vmx_segment_cache_clear(vmx);
 
-	/* if no vmcs02 cache requested, remove the one we used */
-	if (VMCS02_POOL_SIZE == 0)
-		nested_free_vmcs02(vmx, vmx->nested.current_vmptr);
-
 	load_vmcs12_host_state(vcpu, vmcs12);
 
 	/* Update any VMCS fields that might have changed while L2 ran */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d3f80cc..75f756e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -975,6 +975,7 @@
 #endif
 	MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
 	MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX,
+	MSR_IA32_SPEC_CTRL, MSR_IA32_ARCH_CAPABILITIES
 };
 
 static unsigned num_msrs_to_save;
@@ -1751,10 +1752,13 @@
 	/* both __this_cpu_read() and rdtsc() should be on the same cpu */
 	get_cpu();
 
-	kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
-			   &hv_clock.tsc_shift,
-			   &hv_clock.tsc_to_system_mul);
-	ret = __pvclock_read_cycles(&hv_clock, rdtsc());
+	if (__this_cpu_read(cpu_tsc_khz)) {
+		kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
+				   &hv_clock.tsc_shift,
+				   &hv_clock.tsc_to_system_mul);
+		ret = __pvclock_read_cycles(&hv_clock, rdtsc());
+	} else
+		ret = ktime_get_boot_ns() + ka->kvmclock_offset;
 
 	put_cpu();
 
@@ -5308,7 +5312,7 @@
 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
 		vcpu->run->internal.ndata = 0;
-		r = EMULATE_FAIL;
+		r = EMULATE_USER_EXIT;
 	}
 	kvm_queue_exception(vcpu, UD_VECTOR);
 
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 6bf1898..4ad7c4d 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -26,6 +26,7 @@
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
 lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
 lib-$(CONFIG_RETPOLINE) += retpoline.o
+OBJECT_FILES_NON_STANDARD_retpoline.o :=y
 
 obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index 073d1f1..9758524 100644
--- a/arch/x86/lib/delay.c
+++ b/arch/x86/lib/delay.c
@@ -93,6 +93,13 @@
 {
 	u64 start, end, delay, loops = __loops;
 
+	/*
+	 * Timer value of 0 causes MWAITX to wait indefinitely, unless there
+	 * is a store on the memory monitored by MONITORX.
+	 */
+	if (loops == 0)
+		return;
+
 	start = rdtsc_ordered();
 
 	for (;;) {
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 37b62d4..b12b214 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -39,6 +39,8 @@
 	mov PER_CPU_VAR(current_task), %_ASM_DX
 	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 1:	movzbl (%_ASM_AX),%edx
 	xor %eax,%eax
@@ -53,6 +55,8 @@
 	mov PER_CPU_VAR(current_task), %_ASM_DX
 	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 2:	movzwl -1(%_ASM_AX),%edx
 	xor %eax,%eax
@@ -67,6 +71,8 @@
 	mov PER_CPU_VAR(current_task), %_ASM_DX
 	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 3:	movl -3(%_ASM_AX),%edx
 	xor %eax,%eax
@@ -82,6 +88,8 @@
 	mov PER_CPU_VAR(current_task), %_ASM_DX
 	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 4:	movq -7(%_ASM_AX),%rdx
 	xor %eax,%eax
@@ -93,6 +101,8 @@
 	mov PER_CPU_VAR(current_task), %_ASM_DX
 	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user_8
+	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
+	and %_ASM_DX, %_ASM_AX
 	ASM_STAC
 4:	movl -7(%_ASM_AX),%edx
 5:	movl -3(%_ASM_AX),%ecx
diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index cb45c6c..480edc3 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -7,9 +7,10 @@
 #include <asm/alternative-asm.h>
 #include <asm/export.h>
 #include <asm/nospec-branch.h>
+#include <asm/bitsperlong.h>
 
 .macro THUNK reg
-	.section .text.__x86.indirect_thunk.\reg
+	.section .text.__x86.indirect_thunk
 
 ENTRY(__x86_indirect_thunk_\reg)
 	CFI_STARTPROC
@@ -25,7 +26,8 @@
  * than one per register with the correct names. So we do it
  * the simple and nasty way...
  */
-#define EXPORT_THUNK(reg) EXPORT_SYMBOL(__x86_indirect_thunk_ ## reg)
+#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym)
+#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg)
 #define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg)
 
 GENERATE_THUNK(_ASM_AX)
@@ -35,7 +37,6 @@
 GENERATE_THUNK(_ASM_SI)
 GENERATE_THUNK(_ASM_DI)
 GENERATE_THUNK(_ASM_BP)
-GENERATE_THUNK(_ASM_SP)
 #ifdef CONFIG_64BIT
 GENERATE_THUNK(r8)
 GENERATE_THUNK(r9)
@@ -46,3 +47,58 @@
 GENERATE_THUNK(r14)
 GENERATE_THUNK(r15)
 #endif
+
+/*
+ * Fill the CPU return stack buffer.
+ *
+ * Each entry in the RSB, if used for a speculative 'ret', contains an
+ * infinite 'pause; lfence; jmp' loop to capture speculative execution.
+ *
+ * This is required in various cases for retpoline and IBRS-based
+ * mitigations for the Spectre variant 2 vulnerability. Sometimes to
+ * eliminate potentially bogus entries from the RSB, and sometimes
+ * purely to ensure that it doesn't get empty, which on some CPUs would
+ * allow predictions from other (unwanted!) sources to be used.
+ *
+ * Google experimented with loop-unrolling and this turned out to be
+ * the optimal version - two calls, each with their own speculation
+ * trap should their return address end up getting used, in a loop.
+ */
+.macro STUFF_RSB nr:req sp:req
+	mov	$(\nr / 2), %_ASM_BX
+	.align 16
+771:
+	call	772f
+773:						/* speculation trap */
+	pause
+	lfence
+	jmp	773b
+	.align 16
+772:
+	call	774f
+775:						/* speculation trap */
+	pause
+	lfence
+	jmp	775b
+	.align 16
+774:
+	dec	%_ASM_BX
+	jnz	771b
+	add	$((BITS_PER_LONG/8) * \nr), \sp
+.endm
+
+#define RSB_FILL_LOOPS		16	/* To avoid underflow */
+
+ENTRY(__fill_rsb)
+	STUFF_RSB RSB_FILL_LOOPS, %_ASM_SP
+	ret
+END(__fill_rsb)
+EXPORT_SYMBOL_GPL(__fill_rsb)
+
+#define RSB_CLEAR_LOOPS		32	/* To forcibly overwrite all entries */
+
+ENTRY(__clear_rsb)
+	STUFF_RSB RSB_CLEAR_LOOPS, %_ASM_SP
+	ret
+END(__clear_rsb)
+EXPORT_SYMBOL_GPL(__clear_rsb)
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 3bc7baf..5c06dbf 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -570,12 +570,12 @@
 unsigned long __copy_to_user_ll(void __user *to, const void *from,
 				unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel(to, from, n);
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_to_user_ll);
@@ -627,7 +627,7 @@
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
-	stac();
+	__uaccess_begin_nospec();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && static_cpu_has(X86_FEATURE_XMM2))
 		n = __copy_user_intel_nocache(to, from, n);
@@ -636,7 +636,7 @@
 #else
 	__copy_user(to, from, n);
 #endif
-	clac();
+	__uaccess_end();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8b5ff88..74dea7f 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -191,14 +191,15 @@
  * 6. T1   : reaches here, sees vma_pkey(vma)=5, when we really
  *	     faulted on a pte with its pkey=4.
  */
-static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
+static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
+		u32 *pkey)
 {
 	/* This is effectively an #ifdef */
 	if (!boot_cpu_has(X86_FEATURE_OSPKE))
 		return;
 
 	/* Fault not from Protection Keys: nothing to do */
-	if (si_code != SEGV_PKUERR)
+	if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
 		return;
 	/*
 	 * force_sig_info_fault() is called from a number of
@@ -237,7 +238,7 @@
 		lsb = PAGE_SHIFT;
 	info.si_addr_lsb = lsb;
 
-	fill_sig_info_pkey(si_code, &info, pkey);
+	fill_sig_info_pkey(si_signo, si_code, &info, pkey);
 
 	force_sig_info(si_signo, &info, tsk);
 }
diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c
index a8ade08..ec678aa 100644
--- a/arch/x86/mm/kaiser.c
+++ b/arch/x86/mm/kaiser.c
@@ -344,7 +344,7 @@
 	if (vsyscall_enabled())
 		kaiser_add_user_map_early((void *)VSYSCALL_ADDR,
 					  PAGE_SIZE,
-					   __PAGE_KERNEL_VSYSCALL);
+					  vsyscall_pgprot);
 
 	for_each_possible_cpu(cpu) {
 		void *percpu_vaddr = __per_cpu_user_mapped_start +
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 15f7436..7840331 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -278,10 +278,10 @@
 	/* if (index >= array->map.max_entries)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x8B, 0x46,                   /* mov rax, qword ptr [rsi + 16] */
+	EMIT2(0x89, 0xD2);                        /* mov edx, edx */
+	EMIT3(0x39, 0x56,                         /* cmp dword ptr [rsi + 16], edx */
 	      offsetof(struct bpf_array, map.max_entries));
-	EMIT3(0x48, 0x39, 0xD0);                  /* cmp rax, rdx */
-#define OFFSET1 47 /* number of bytes to jump */
+#define OFFSET1 43 /* number of bytes to jump */
 	EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
 	label1 = cnt;
 
@@ -290,21 +290,20 @@
 	 */
 	EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
 	EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 36
+#define OFFSET2 32
 	EMIT2(X86_JA, OFFSET2);                   /* ja out */
 	label2 = cnt;
 	EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
 	EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
 
 	/* prog = array->ptrs[index]; */
-	EMIT4_off32(0x48, 0x8D, 0x84, 0xD6,       /* lea rax, [rsi + rdx * 8 + offsetof(...)] */
+	EMIT4_off32(0x48, 0x8B, 0x84, 0xD6,       /* mov rax, [rsi + rdx * 8 + offsetof(...)] */
 		    offsetof(struct bpf_array, ptrs));
-	EMIT3(0x48, 0x8B, 0x00);                  /* mov rax, qword ptr [rax] */
 
 	/* if (prog == NULL)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x83, 0xF8, 0x00);            /* cmp rax, 0 */
+	EMIT3(0x48, 0x85, 0xC0);		  /* test rax,rax */
 #define OFFSET3 10
 	EMIT2(X86_JE, OFFSET3);                   /* je out */
 	label3 = cnt;
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
index b39531b..72bfc1c 100644
--- a/arch/xtensa/include/asm/futex.h
+++ b/arch/xtensa/include/asm/futex.h
@@ -109,7 +109,6 @@
 			      u32 oldval, u32 newval)
 {
 	int ret = 0;
-	u32 prev;
 
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
@@ -120,26 +119,24 @@
 
 	__asm__ __volatile__ (
 	"	# futex_atomic_cmpxchg_inatomic\n"
-	"1:	l32i	%1, %3, 0\n"
-	"	mov	%0, %5\n"
-	"	wsr	%1, scompare1\n"
-	"2:	s32c1i	%0, %3, 0\n"
-	"3:\n"
+	"	wsr	%5, scompare1\n"
+	"1:	s32c1i	%1, %4, 0\n"
+	"	s32i	%1, %6, 0\n"
+	"2:\n"
 	"	.section .fixup,\"ax\"\n"
 	"	.align 4\n"
-	"4:	.long	3b\n"
-	"5:	l32r	%1, 4b\n"
-	"	movi	%0, %6\n"
+	"3:	.long	2b\n"
+	"4:	l32r	%1, 3b\n"
+	"	movi	%0, %7\n"
 	"	jx	%1\n"
 	"	.previous\n"
 	"	.section __ex_table,\"a\"\n"
-	"	.long 1b,5b,2b,5b\n"
+	"	.long 1b,4b\n"
 	"	.previous\n"
-	: "+r" (ret), "=&r" (prev), "+m" (*uaddr)
-	: "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
+	: "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
+	: "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
 	: "memory");
 
-	*uval = prev;
 	return ret;
 }
 
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 8ba0af7..d673a69 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -184,7 +184,7 @@
 		goto err_free_blkg;
 	}
 
-	wb_congested = wb_congested_get_create(&q->backing_dev_info,
+	wb_congested = wb_congested_get_create(q->backing_dev_info,
 					       blkcg->css.id,
 					       GFP_NOWAIT | __GFP_NOWARN);
 	if (!wb_congested) {
@@ -469,8 +469,8 @@
 const char *blkg_dev_name(struct blkcg_gq *blkg)
 {
 	/* some drivers (floppy) instantiate a queue w/o disk registered */
-	if (blkg->q->backing_dev_info.dev)
-		return dev_name(blkg->q->backing_dev_info.dev);
+	if (blkg->q->backing_dev_info->dev)
+		return dev_name(blkg->q->backing_dev_info->dev);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(blkg_dev_name);
diff --git a/block/blk-core.c b/block/blk-core.c
index 37b814a..3bf59cd 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -75,7 +75,7 @@
 	 * flip its congestion state for events on other blkcgs.
 	 */
 	if (rl == &rl->q->root_rl)
-		clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+		clear_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -86,7 +86,7 @@
 #else
 	/* see blk_clear_congested() */
 	if (rl == &rl->q->root_rl)
-		set_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+		set_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -105,22 +105,6 @@
 	q->nr_congestion_off = nr;
 }
 
-/**
- * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
- * @bdev:	device
- *
- * Locates the passed device's request queue and returns the address of its
- * backing_dev_info.  This function can only be called if @bdev is opened
- * and the return value is never NULL.
- */
-struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
-{
-	struct request_queue *q = bdev_get_queue(bdev);
-
-	return &q->backing_dev_info;
-}
-EXPORT_SYMBOL(blk_get_backing_dev_info);
-
 void blk_rq_init(struct request_queue *q, struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
@@ -586,7 +570,7 @@
 	blk_flush_integrity();
 
 	/* @q won't process any more request, flush async actions */
-	del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
+	del_timer_sync(&q->backing_dev_info->laptop_mode_wb_timer);
 	blk_sync_queue(q);
 
 	if (q->mq_ops)
@@ -598,8 +582,6 @@
 		q->queue_lock = &q->__queue_lock;
 	spin_unlock_irq(lock);
 
-	bdi_unregister(&q->backing_dev_info);
-
 	/* @q is and will stay empty, shutdown and put */
 	blk_put_queue(q);
 }
@@ -695,7 +677,6 @@
 struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 {
 	struct request_queue *q;
-	int err;
 
 	q = kmem_cache_alloc_node(blk_requestq_cachep,
 				gfp_mask | __GFP_ZERO, node_id);
@@ -710,17 +691,17 @@
 	if (!q->bio_split)
 		goto fail_id;
 
-	q->backing_dev_info.ra_pages =
-			(VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
-	q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK;
-	q->backing_dev_info.name = "block";
-	q->node = node_id;
-
-	err = bdi_init(&q->backing_dev_info);
-	if (err)
+	q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
+	if (!q->backing_dev_info)
 		goto fail_split;
 
-	setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
+	q->backing_dev_info->ra_pages =
+			(VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
+	q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
+	q->backing_dev_info->name = "block";
+	q->node = node_id;
+
+	setup_timer(&q->backing_dev_info->laptop_mode_wb_timer,
 		    laptop_mode_timer_fn, (unsigned long) q);
 	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
 	INIT_WORK(&q->timeout_work, NULL);
@@ -771,7 +752,7 @@
 fail_ref:
 	percpu_ref_exit(&q->q_usage_counter);
 fail_bdi:
-	bdi_destroy(&q->backing_dev_info);
+	bdi_put(q->backing_dev_info);
 fail_split:
 	bioset_free(q->bio_split);
 fail_id:
@@ -1197,7 +1178,7 @@
 	 * disturb iosched and blkcg but weird is bettern than dead.
 	 */
 	printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
-			   __func__, dev_name(q->backing_dev_info.dev));
+			   __func__, dev_name(q->backing_dev_info->dev));
 
 	rq->cmd_flags &= ~REQ_ELVPRIV;
 	rq->elv.icq = NULL;
@@ -2739,7 +2720,7 @@
 	BUG_ON(blk_queued_rq(req));
 
 	if (unlikely(laptop_mode) && req->cmd_type == REQ_TYPE_FS)
-		laptop_io_completion(&req->q->backing_dev_info);
+		laptop_io_completion(req->q->backing_dev_info);
 
 	blk_delete_timer(req);
 
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 478f572..e4ebd79 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -418,7 +418,7 @@
 	bi->tuple_size = template->tuple_size;
 	bi->tag_size = template->tag_size;
 
-	disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+	disk->queue->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 }
 EXPORT_SYMBOL(blk_integrity_register);
 
@@ -431,7 +431,7 @@
  */
 void blk_integrity_unregister(struct gendisk *disk)
 {
-	disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
+	disk->queue->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES;
 	memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
 }
 EXPORT_SYMBOL(blk_integrity_unregister);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 9cc8d7c..07c75d0 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -75,7 +75,7 @@
 
 static ssize_t queue_ra_show(struct request_queue *q, char *page)
 {
-	unsigned long ra_kb = q->backing_dev_info.ra_pages <<
+	unsigned long ra_kb = q->backing_dev_info->ra_pages <<
 					(PAGE_SHIFT - 10);
 
 	return queue_var_show(ra_kb, (page));
@@ -90,7 +90,7 @@
 	if (ret < 0)
 		return ret;
 
-	q->backing_dev_info.ra_pages = ra_kb >> (PAGE_SHIFT - 10);
+	q->backing_dev_info->ra_pages = ra_kb >> (PAGE_SHIFT - 10);
 
 	return ret;
 }
@@ -627,7 +627,7 @@
 	struct request_queue *q =
 		container_of(kobj, struct request_queue, kobj);
 
-	bdi_exit(&q->backing_dev_info);
+	bdi_put(q->backing_dev_info);
 	blkcg_exit_queue(q);
 
 	if (q->elevator) {
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 556826a..570021a 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -661,7 +661,6 @@
 	struct block_device *bdev = inode->i_bdev;
 	struct gendisk *disk = bdev->bd_disk;
 	fmode_t mode = file->f_mode;
-	struct backing_dev_info *bdi;
 	loff_t size;
 	unsigned int max_sectors;
 
@@ -708,9 +707,8 @@
 	case BLKFRAGET:
 		if (!arg)
 			return -EINVAL;
-		bdi = blk_get_backing_dev_info(bdev);
 		return compat_put_long(arg,
-				       (bdi->ra_pages * PAGE_SIZE) / 512);
+			       (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
 	case BLKROGET: /* compatible */
 		return compat_put_int(arg, bdev_read_only(bdev) != 0);
 	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
@@ -728,8 +726,7 @@
 	case BLKFRASET:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		bdi = blk_get_backing_dev_info(bdev);
-		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
 		return 0;
 	case BLKGETSIZE:
 		size = i_size_read(bdev->bd_inode);
diff --git a/block/genhd.c b/block/genhd.c
index c6eb25d..6ad0fd0 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -613,7 +613,7 @@
 	disk_alloc_events(disk);
 
 	/* Register BDI before referencing it from bdev */
-	bdi = &disk->queue->backing_dev_info;
+	bdi = disk->queue->backing_dev_info;
 	bdi_register_owner(bdi, disk_to_dev(disk));
 
 	blk_register_region(disk_devt(disk), disk->minors, NULL,
@@ -649,16 +649,27 @@
 			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
 	while ((part = disk_part_iter_next(&piter))) {
 		invalidate_partition(disk, part->partno);
+		bdev_unhash_inode(part_devt(part));
 		delete_partition(disk, part->partno);
 	}
 	disk_part_iter_exit(&piter);
 
 	invalidate_partition(disk, 0);
+	bdev_unhash_inode(disk_devt(disk));
 	set_capacity(disk, 0);
 	disk->flags &= ~GENHD_FL_UP;
 
 	sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
-	blk_unregister_queue(disk);
+	if (disk->queue) {
+		/*
+		 * Unregister bdi before releasing device numbers (as they can
+		 * get reused and we'd get clashes in sysfs).
+		 */
+		bdi_unregister(disk->queue->backing_dev_info);
+		blk_unregister_queue(disk);
+	} else {
+		WARN_ON(1);
+	}
 	blk_unregister_region(disk_devt(disk), disk->minors);
 
 	part_stat_set_all(&disk->part0, 0);
@@ -1358,7 +1369,7 @@
 	owner = disk->fops->owner;
 	if (owner && !try_module_get(owner))
 		return NULL;
-	kobj = kobject_get(&disk_to_dev(disk)->kobj);
+	kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
 	if (kobj == NULL) {
 		module_put(owner);
 		return NULL;
diff --git a/block/ioctl.c b/block/ioctl.c
index 755119c..c4555b1 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -502,7 +502,6 @@
 int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 			unsigned long arg)
 {
-	struct backing_dev_info *bdi;
 	void __user *argp = (void __user *)arg;
 	loff_t size;
 	unsigned int max_sectors;
@@ -525,8 +524,7 @@
 	case BLKFRAGET:
 		if (!arg)
 			return -EINVAL;
-		bdi = blk_get_backing_dev_info(bdev);
-		return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512);
+		return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
 	case BLKROGET:
 		return put_int(arg, bdev_read_only(bdev) != 0);
 	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
@@ -553,8 +551,7 @@
 	case BLKFRASET:
 		if(!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		bdi = blk_get_backing_dev_info(bdev);
-		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
 		return 0;
 	case BLKBSZSET:
 		return blkdev_bszset(bdev, mode, argp);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 84d7148..ab0d93a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -120,7 +120,7 @@
 
 config CRYPTO_ECDH
 	tristate "ECDH algorithm"
-	select CRYTPO_KPP
+	select CRYPTO_KPP
 	help
 	  Generic implementation of the ECDH algorithm
 
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index f5e18c2..ca50eeb 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -149,7 +149,7 @@
 
 static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	const u32 forbidden = CRYPTO_ALG_INTERNAL;
+	const u32 allowed = CRYPTO_ALG_KERN_DRIVER_ONLY;
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
 	struct sockaddr_alg *sa = (void *)uaddr;
@@ -157,6 +157,10 @@
 	void *private;
 	int err;
 
+	/* If caller uses non-allowed flag, return error. */
+	if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+		return -EINVAL;
+
 	if (sock->state == SS_CONNECTED)
 		return -EINVAL;
 
@@ -175,9 +179,7 @@
 	if (IS_ERR(type))
 		return PTR_ERR(type);
 
-	private = type->bind(sa->salg_name,
-			     sa->salg_feat & ~forbidden,
-			     sa->salg_mask & ~forbidden);
+	private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
 	if (IS_ERR(private)) {
 		module_put(type->owner);
 		return PTR_ERR(private);
diff --git a/crypto/ahash.c b/crypto/ahash.c
index cce0268..f3fa104 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -625,5 +625,16 @@
 }
 EXPORT_SYMBOL_GPL(ahash_attr_alg);
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
+{
+	struct crypto_alg *alg = &halg->base;
+
+	if (alg->cra_type != &crypto_ahash_type)
+		return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
+
+	return __crypto_ahash_alg(alg)->setkey != NULL;
+}
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 0c654e5..af9ad45 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -691,7 +691,8 @@
 	inst->alg.finup  = cryptd_hash_finup_enqueue;
 	inst->alg.export = cryptd_hash_export;
 	inst->alg.import = cryptd_hash_import;
-	inst->alg.setkey = cryptd_hash_setkey;
+	if (crypto_shash_alg_has_setkey(salg))
+		inst->alg.setkey = cryptd_hash_setkey;
 	inst->alg.digest = cryptd_hash_digest_enqueue;
 
 	err = ahash_register_instance(tmpl, inst);
diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
index a14100e..6e9389c 100644
--- a/crypto/mcryptd.c
+++ b/crypto/mcryptd.c
@@ -534,7 +534,8 @@
 	inst->alg.finup  = mcryptd_hash_finup_enqueue;
 	inst->alg.export = mcryptd_hash_export;
 	inst->alg.import = mcryptd_hash_import;
-	inst->alg.setkey = mcryptd_hash_setkey;
+	if (crypto_hash_alg_has_setkey(halg))
+		inst->alg.setkey = mcryptd_hash_setkey;
 	inst->alg.digest = mcryptd_hash_digest_enqueue;
 
 	err = ahash_register_instance(tmpl, inst);
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
index 2df9835d..bca9923 100644
--- a/crypto/poly1305_generic.c
+++ b/crypto/poly1305_generic.c
@@ -51,17 +51,6 @@
 }
 EXPORT_SYMBOL_GPL(crypto_poly1305_init);
 
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-			   const u8 *key, unsigned int keylen)
-{
-	/* Poly1305 requires a unique key for each tag, which implies that
-	 * we can't set it on the tfm that gets accessed by multiple users
-	 * simultaneously. Instead we expect the key as the first 32 bytes in
-	 * the update() call. */
-	return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
-
 static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
 {
 	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
@@ -80,6 +69,11 @@
 	dctx->s[3] = le32_to_cpuvp(key + 12);
 }
 
+/*
+ * Poly1305 requires a unique key for each tag, which implies that we can't set
+ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+ * expect the key as the first 32 bytes in the update() call.
+ */
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
 					const u8 *src, unsigned int srclen)
 {
@@ -285,7 +279,6 @@
 	.init		= crypto_poly1305_init,
 	.update		= crypto_poly1305_update,
 	.final		= crypto_poly1305_final,
-	.setkey		= crypto_poly1305_setkey,
 	.descsize	= sizeof(struct poly1305_desc_ctx),
 	.base		= {
 		.cra_name		= "poly1305",
diff --git a/crypto/sha3_generic.c b/crypto/sha3_generic.c
index 7e8ed96..a68be62 100644
--- a/crypto/sha3_generic.c
+++ b/crypto/sha3_generic.c
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <crypto/sha3.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #define KECCAK_ROUNDS 24
 
@@ -149,7 +150,7 @@
 			unsigned int i;
 
 			for (i = 0; i < sctx->rsizw; i++)
-				sctx->st[i] ^= ((u64 *) src)[i];
+				sctx->st[i] ^= get_unaligned_le64(src + 8 * i);
 			keccakf(sctx->st);
 
 			done += sctx->rsiz;
@@ -174,7 +175,7 @@
 	sctx->buf[sctx->rsiz - 1] |= 0x80;
 
 	for (i = 0; i < sctx->rsizw; i++)
-		sctx->st[i] ^= ((u64 *) sctx->buf)[i];
+		sctx->st[i] ^= get_unaligned_le64(sctx->buf + 8 * i);
 
 	keccakf(sctx->st);
 
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index e3af318..2a07341 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -223,11 +223,13 @@
 	}
 
 	sg_init_table(sg, np + 1);
-	np--;
+	if (rem)
+		np--;
 	for (k = 0; k < np; k++)
 		sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
 
-	sg_set_buf(&sg[k + 1], xbuf[k], rem);
+	if (rem)
+		sg_set_buf(&sg[k + 1], xbuf[k], rem);
 }
 
 static void test_aead_speed(const char *algo, int enc, unsigned int secs,
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 691814d..943702d 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -594,25 +594,20 @@
 void acpi_ns_terminate(void)
 {
 	acpi_status status;
+	union acpi_operand_object *prev;
+	union acpi_operand_object *next;
 
 	ACPI_FUNCTION_TRACE(ns_terminate);
 
-#ifdef ACPI_EXEC_APP
-	{
-		union acpi_operand_object *prev;
-		union acpi_operand_object *next;
+	/* Delete any module-level code blocks */
 
-		/* Delete any module-level code blocks */
-
-		next = acpi_gbl_module_code_list;
-		while (next) {
-			prev = next;
-			next = next->method.mutex;
-			prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
-			acpi_ut_remove_reference(prev);
-		}
+	next = acpi_gbl_module_code_list;
+	while (next) {
+		prev = next;
+		next = next->method.mutex;
+		prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
+		acpi_ut_remove_reference(prev);
 	}
-#endif
 
 	/*
 	 * Free the entire namespace -- all nodes and all objects
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 7b2c48f..201c7ce 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -146,6 +146,10 @@
 	int count;
 	struct acpi_hardware_id *id;
 
+	/* Avoid unnecessarily loading modules for non present devices. */
+	if (!acpi_device_is_present(acpi_dev))
+		return 0;
+
 	/*
 	 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
 	 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 73c9c7f..f06317d 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -99,13 +99,13 @@
 		return -ENODEV;
 
 	/*
-	 * If the device has a _HID (or _CID) returning a valid ACPI/PNP
-	 * device ID, it is better to make it look less attractive here, so that
-	 * the other device with the same _ADR value (that may not have a valid
-	 * device ID) can be matched going forward.  [This means a second spec
-	 * violation in a row, so whatever we do here is best effort anyway.]
+	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
+	 * better to make it look less attractive here, so that the other device
+	 * with the same _ADR value (that may not have a valid device ID) can be
+	 * matched going forward.  [This means a second spec violation in a row,
+	 * so whatever we do here is best effort anyway.]
 	 */
-	return sta_present && list_empty(&adev->pnp.ids) ?
+	return sta_present && !adev->pnp.type.platform_id ?
 			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 }
 
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index fe03d00..b1815b2 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1535,6 +1535,9 @@
 		struct kernfs_node *nfit_kernfs;
 
 		nvdimm = nfit_mem->nvdimm;
+		if (!nvdimm)
+			continue;
+
 		nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
 		if (nfit_kernfs)
 			nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 2fa8304..7a34310 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -275,8 +275,8 @@
 	device->driver_data = hc;
 
 	acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
-	printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
-		hc->ec, hc->offset, hc->query_bit);
+	dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
+		 hc->offset, hc->query_bit);
 
 	return 0;
 }
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c940382..9b46ef4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -265,9 +265,9 @@
 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
-	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
-	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */
 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
 	{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
 	{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
@@ -290,9 +290,9 @@
 	{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
 	{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
-	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
-	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */
 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
@@ -301,20 +301,20 @@
 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
-	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
-	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */
 	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
@@ -355,21 +355,21 @@
 	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
-	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */
 	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
-	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */
 	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
 	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
 	{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
-	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
+	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */
 	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
-	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
+	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */
 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
@@ -383,6 +383,11 @@
 	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
+	{ PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
+	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
+	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 33e363d..aee3952 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4322,6 +4322,7 @@
 	 * https://bugzilla.kernel.org/show_bug.cgi?id=121671
 	 */
 	{ "LITEON CX1-JB*-HP",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
+	{ "LITEON EP1-*",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
 
 	/* Devices we expect to fail diagnostics */
 
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 10e1b9e..f03cf1d 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -121,6 +121,7 @@
 
 config IMG_ASCII_LCD
 	tristate "Imagination Technologies ASCII LCD Display"
+	depends on HAS_IOMEM
 	default y if MIPS_MALTA || MIPS_SEAD3
 	select SYSCON
 	help
diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c
index 83f1439..6e8eaa7 100644
--- a/drivers/auxdisplay/img-ascii-lcd.c
+++ b/drivers/auxdisplay/img-ascii-lcd.c
@@ -442,3 +442,7 @@
 	.remove	= img_ascii_lcd_remove,
 };
 module_platform_driver(img_ascii_lcd_driver);
+
+MODULE_DESCRIPTION("Imagination Technologies ASCII LCD Display");
+MODULE_AUTHOR("Paul Burton <paul.burton@mips.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 0651010..0335e23 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -165,6 +165,11 @@
 
 	  If you are unsure about this, say N here.
 
+config FW_CACHE
+       bool "Enable firmware caching during suspend"
+       depends on PM_SLEEP
+       default n
+
 config WANT_DEV_COREDUMP
 	bool
 	help
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index e9fd32e..70e13cf 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -16,6 +16,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+#include <linux/acpi.h>
 #include <linux/bitops.h>
 #include <linux/cacheinfo.h>
 #include <linux/compiler.h>
@@ -104,9 +105,16 @@
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct cacheinfo *this_leaf, *sib_leaf;
 	unsigned int index;
-	int ret;
+	int ret = 0;
 
-	ret = cache_setup_of_node(cpu);
+	if (this_cpu_ci->cpu_map_populated)
+		return 0;
+
+	if (of_have_populated_dt())
+		ret = cache_setup_of_node(cpu);
+	else if (!acpi_disabled)
+		/* No cache property/hierarchy support yet in ACPI */
+		ret = -ENOTSUPP;
 	if (ret)
 		return ret;
 
@@ -203,8 +211,7 @@
 	 */
 	ret = cache_shared_cpu_map_setup(cpu);
 	if (ret) {
-		pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
-			cpu);
+		pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu);
 		goto free_ci;
 	}
 	return 0;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 914433f..813a191 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -994,7 +994,7 @@
 	return _request_firmware_load(fw_priv, opt_flags, timeout);
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 /* kill pending requests without uevent to avoid blocking suspend */
 static void kill_requests_without_uevent(void)
 {
@@ -1395,7 +1395,7 @@
 }
 EXPORT_SYMBOL(request_firmware_nowait);
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
 
 /**
@@ -1741,7 +1741,7 @@
 	INIT_LIST_HEAD(&fw_cache.head);
 	fw_cache.state = FW_LOADER_NO_CACHE;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 	spin_lock_init(&fw_cache.name_lock);
 	INIT_LIST_HEAD(&fw_cache.fw_names);
 
@@ -1768,7 +1768,7 @@
 
 static void __exit firmware_class_exit(void)
 {
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_FW_CACHE
 	unregister_syscore_ops(&fw_syscore_ops);
 	unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index ec9d861..027b876 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -396,8 +396,8 @@
 	WARN_ON(d->gd);
 	WARN_ON(d->flags & DEVFL_UP);
 	blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS);
-	q->backing_dev_info.name = "aoe";
-	q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_SIZE;
+	q->backing_dev_info->name = "aoe";
+	q->backing_dev_info->ra_pages = READ_AHEAD / PAGE_SIZE;
 	d->bufpool = mp;
 	d->blkq = gd->queue = q;
 	q->queuedata = d;
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 8348272..d305f05 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2462,7 +2462,7 @@
 
 	if (get_ldev(device)) {
 		q = bdev_get_queue(device->ldev->backing_bdev);
-		r = bdi_congested(&q->backing_dev_info, bdi_bits);
+		r = bdi_congested(q->backing_dev_info, bdi_bits);
 		put_ldev(device);
 		if (r)
 			reason = 'b';
@@ -2834,8 +2834,8 @@
 	/* we have no partitions. we contain only ourselves. */
 	device->this_bdev->bd_contains = device->this_bdev;
 
-	q->backing_dev_info.congested_fn = drbd_congested;
-	q->backing_dev_info.congested_data = device;
+	q->backing_dev_info->congested_fn = drbd_congested;
+	q->backing_dev_info->congested_data = device;
 
 	blk_queue_make_request(q, drbd_make_request);
 	blk_queue_write_cache(q, true, true);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f35db29..908c704 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1328,11 +1328,13 @@
 	if (b) {
 		blk_queue_stack_limits(q, b);
 
-		if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+		if (q->backing_dev_info->ra_pages !=
+		    b->backing_dev_info->ra_pages) {
 			drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
-				 q->backing_dev_info.ra_pages,
-				 b->backing_dev_info.ra_pages);
-			q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+				 q->backing_dev_info->ra_pages,
+				 b->backing_dev_info->ra_pages);
+			q->backing_dev_info->ra_pages =
+						b->backing_dev_info->ra_pages;
 		}
 	}
 	fixup_discard_if_not_supported(q);
@@ -3345,7 +3347,7 @@
 		s->dev_disk_flags = md->flags;
 		q = bdev_get_queue(device->ldev->backing_bdev);
 		s->dev_lower_blocked =
-			bdi_congested(&q->backing_dev_info,
+			bdi_congested(q->backing_dev_info,
 				      (1 << WB_async_congested) |
 				      (1 << WB_sync_congested));
 		put_ldev(device);
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index be2b93f..8378142 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -288,7 +288,7 @@
 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
 		} else {
 			/* reset device->congestion_reason */
-			bdi_rw_congested(&device->rq_queue->backing_dev_info);
+			bdi_rw_congested(device->rq_queue->backing_dev_info);
 
 			nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
 			wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index de279fe..cb6bdb7 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -938,7 +938,7 @@
 
 	switch (rbm) {
 	case RB_CONGESTED_REMOTE:
-		bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+		bdi = device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
 		return bdi_read_congested(bdi);
 	case RB_LEAST_PENDING:
 		return atomic_read(&device->local_cnt) >
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 24d6cef..402254d 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1558,9 +1558,8 @@
 	return err;
 }
 
-static void lo_release(struct gendisk *disk, fmode_t mode)
+static void __lo_release(struct loop_device *lo)
 {
-	struct loop_device *lo = disk->private_data;
 	int err;
 
 	if (atomic_dec_return(&lo->lo_refcnt))
@@ -1586,6 +1585,13 @@
 	mutex_unlock(&lo->lo_ctl_mutex);
 }
 
+static void lo_release(struct gendisk *disk, fmode_t mode)
+{
+	mutex_lock(&loop_index_mutex);
+	__lo_release(disk->private_data);
+	mutex_unlock(&loop_index_mutex);
+}
+
 static const struct block_device_operations lo_fops = {
 	.owner =	THIS_MODULE,
 	.open =		lo_open,
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 90fa4ac..4a5bccd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1276,7 +1276,7 @@
 	 		&& pd->bio_queue_size <= pd->write_congestion_off);
 	spin_unlock(&pd->lock);
 	if (wakeup) {
-		clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+		clear_bdi_congested(pd->disk->queue->backing_dev_info,
 					BLK_RW_ASYNC);
 	}
 
@@ -2405,7 +2405,7 @@
 	spin_lock(&pd->lock);
 	if (pd->write_congestion_on > 0
 	    && pd->bio_queue_size >= pd->write_congestion_on) {
-		set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
+		set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC);
 		do {
 			spin_unlock(&pd->lock);
 			congestion_wait(BLK_RW_ASYNC, HZ);
@@ -2779,7 +2779,7 @@
 	pd->pkt_dev = MKDEV(pktdev_major, idx);
 	ret = pkt_new_dev(pd, dev);
 	if (ret)
-		goto out_new_dev;
+		goto out_mem2;
 
 	/* inherit events of the host device */
 	disk->events = pd->bdev->bd_disk->events;
@@ -2797,8 +2797,6 @@
 	mutex_unlock(&ctl_mutex);
 	return 0;
 
-out_new_dev:
-	blk_cleanup_queue(disk->queue);
 out_mem2:
 	put_disk(disk);
 out_mem:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index e32badd..2622e14 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4524,7 +4524,7 @@
 	q->limits.discard_zeroes_data = 1;
 
 	if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
-		q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+		q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 
 	disk->queue = q;
 
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ed9de1b..58f7c39 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -122,7 +122,7 @@
 {
 	revalidate_disk(zram->disk);
 	/* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */
-	zram->disk->queue->backing_dev_info.capabilities |=
+	zram->disk->queue->backing_dev_info->capabilities |=
 		BDI_CAP_STABLE_WRITES;
 }
 
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 1cb958e..94e914a 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 
+#include <linux/mmc/host.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_func.h>
 
@@ -291,6 +292,14 @@
 		tuple = tuple->next;
 	}
 
+	/* BCM43341 devices soldered onto the PCB (non-removable) use an
+	 * uart connection for bluetooth, ignore the BT SDIO interface.
+	 */
+	if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
+	    func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
+	    !mmc_card_is_removable(func->card->host))
+		return -ENODEV;
+
 	data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6930286..3257647 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,7 @@
 
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb/quirks.h>
 #include <linux/firmware.h>
 #include <asm/unaligned.h>
 
@@ -369,8 +370,8 @@
 #define BTUSB_FIRMWARE_LOADED	7
 #define BTUSB_FIRMWARE_FAILED	8
 #define BTUSB_BOOTING		9
-#define BTUSB_RESET_RESUME	10
-#define BTUSB_DIAG_RUNNING	11
+#define BTUSB_DIAG_RUNNING	10
+#define BTUSB_OOB_WAKE_ENABLED	11
 
 struct btusb_data {
 	struct hci_dev       *hdev;
@@ -2928,9 +2929,9 @@
 
 		/* QCA Rome devices lose their updated firmware over suspend,
 		 * but the USB hub doesn't notice any status change.
-		 * Explicitly request a device reset on resume.
+		 * explicitly request a device reset on resume.
 		 */
-		set_bit(BTUSB_RESET_RESUME, &data->flags);
+		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
 	}
 
 #ifdef CONFIG_BT_HCIBTUSB_RTL
@@ -2941,7 +2942,7 @@
 		 * but the USB hub doesn't notice any status change.
 		 * Explicitly request a device reset on resume.
 		 */
-		set_bit(BTUSB_RESET_RESUME, &data->flags);
+		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
 	}
 #endif
 
@@ -3098,14 +3099,6 @@
 	btusb_stop_traffic(data);
 	usb_kill_anchored_urbs(&data->tx_anchor);
 
-	/* Optionally request a device reset on resume, but only when
-	 * wakeups are disabled. If wakeups are enabled we assume the
-	 * device will stay powered up throughout suspend.
-	 */
-	if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
-	    !device_may_wakeup(&data->udev->dev))
-		data->udev->reset_resume = 1;
-
 	return 0;
 }
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1ea2053..b0d0181 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -607,7 +607,7 @@
 
 config MSM_ADSPRPC
         tristate "QTI ADSP RPC driver"
-        depends on MSM_GLINK
+        depends on MSM_GLINK || MSM_SMD
         help
           Provides a communication mechanism that allows for clients to
           make remote method invocations across processor boundary to
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 3f35d54..c9ceb48 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -26,6 +26,7 @@
 #include <linux/msm_ion.h>
 #include <soc/qcom/secure_buffer.h>
 #include <soc/qcom/glink.h>
+#include <soc/qcom/smd.h>
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/subsystem_restart.h>
 #include <soc/qcom/service-notifier.h>
@@ -55,6 +56,8 @@
 #define TZ_PIL_AUTH_QDSP6_PROC 1
 #define ADSP_MMAP_HEAP_ADDR 4
 #define ADSP_MMAP_REMOTE_HEAP_ADDR 8
+#define FASTRPC_DMAHANDLE_NOMAP (16)
+
 #define FASTRPC_ENOSUCH 39
 #define VMID_SSC_Q6     5
 #define VMID_ADSP_Q6    6
@@ -71,6 +74,8 @@
 #define M_CRCLIST	(64)
 #define SESSION_ID_INDEX (30)
 #define FASTRPC_CTX_MAGIC (0xbeeddeed)
+#define FASTRPC_CTX_MAX (256)
+#define FASTRPC_CTXID_MASK (0xFF0)
 
 #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
 
@@ -198,7 +203,6 @@
 	remote_arg_t *lpra;
 	remote_arg64_t *rpra;
 	int *fds;
-	unsigned int *attrs;
 	struct fastrpc_mmap **maps;
 	struct fastrpc_buf *buf;
 	size_t used;
@@ -207,8 +211,10 @@
 	struct overlap *overs;
 	struct overlap **overps;
 	struct smq_msg msg;
-	uint32_t *crc;
 	unsigned int magic;
+	unsigned int *attrs;
+	uint32_t *crc;
+	uint64_t ctxid;
 };
 
 struct fastrpc_ctx_lst {
@@ -261,6 +267,7 @@
 	struct completion workport;
 	struct notifier_block nb;
 	struct kref kref;
+	int channel;
 	int sesscount;
 	int ssrcount;
 	void *handle;
@@ -288,6 +295,10 @@
 	struct ion_client *client;
 	struct device *dev;
 	unsigned int latency;
+	bool glink;
+	bool legacy;
+	spinlock_t ctxlock;
+	struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX];
 };
 
 struct fastrpc_mmap {
@@ -363,6 +374,7 @@
 	int qos_request;
 	struct mutex map_mutex;
 	struct mutex fl_map_mutex;
+	int refcount;
 };
 
 static struct fastrpc_apps gfa;
@@ -371,6 +383,7 @@
 	{
 		.name = "adsprpc-smd",
 		.subsys = "adsp",
+		.channel = SMD_APPS_QDSP,
 		.link.link_info.edge = "lpass",
 		.link.link_info.transport = "smem",
 		.spd = {
@@ -385,12 +398,14 @@
 	{
 		.name = "mdsprpc-smd",
 		.subsys = "modem",
+		.channel = SMD_APPS_MODEM,
 		.link.link_info.edge = "mpss",
 		.link.link_info.transport = "smem",
 	},
 	{
 		.name = "sdsprpc-smd",
 		.subsys = "slpi",
+		.channel = SMD_APPS_DSPS,
 		.link.link_info.edge = "dsps",
 		.link.link_info.transport = "smem",
 	},
@@ -659,6 +674,9 @@
 			dma_free_coherent(me->dev, map->size,
 				(void *)map->va, (dma_addr_t)map->phys);
 		}
+	} else if (map->flags == FASTRPC_DMAHANDLE_NOMAP) {
+		if (!IS_ERR_OR_NULL(map->handle))
+			ion_free(fl->apps->client, map->handle);
 	} else {
 		int destVM[1] = {VMID_HLOS};
 		int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
@@ -738,6 +756,26 @@
 		map->phys = (uintptr_t)region_phys;
 		map->size = len;
 		map->va = (uintptr_t)region_vaddr;
+	} else if (mflags == FASTRPC_DMAHANDLE_NOMAP) {
+		ion_phys_addr_t iphys;
+
+		VERIFY(err, !IS_ERR_OR_NULL(map->handle =
+				ion_import_dma_buf_fd(fl->apps->client, fd)));
+		if (err)
+			goto bail;
+
+		map->uncached = 1;
+		map->buf = NULL;
+		map->attach = NULL;
+		map->table = NULL;
+		map->va = 0;
+		map->phys = 0;
+
+		err = ion_phys(fl->apps->client, map->handle,
+			&iphys, &map->size);
+		if (err)
+			goto bail;
+		map->phys = (uint64_t)iphys;
 	} else {
 		if (map->attr && (map->attr & FASTRPC_ATTR_KEEP_MAP)) {
 			pr_info("adsprpc: buffer mapped with persist attr %x\n",
@@ -807,13 +845,24 @@
 			goto bail;
 		}
 		map->phys = sg_dma_address(map->table->sgl);
+
 		if (sess->smmu.cb) {
 			map->phys += ((uint64_t)sess->smmu.cb << 32);
 			map->size = sg_dma_len(map->table->sgl);
 		} else {
 			map->size = buf_page_size(len);
 		}
+
 		vmid = fl->apps->channel[fl->cid].vmid;
+		if (!sess->smmu.enabled && !vmid) {
+			VERIFY(err, map->phys >= me->range.addr &&
+			map->phys + map->size <=
+			me->range.addr + me->range.size);
+			if (err) {
+				pr_err("adsprpc: mmap fail out of range\n");
+				goto bail;
+			}
+		}
 		if (vmid) {
 			int srcVM[1] = {VMID_HLOS};
 			int destVM[2] = {VMID_HLOS, vmid};
@@ -1018,7 +1067,8 @@
 			 struct fastrpc_ioctl_invoke_crc *invokefd,
 			 struct smq_invoke_ctx **po)
 {
-	int err = 0, bufs, size = 0;
+	struct fastrpc_apps *me = &gfa;
+	int err = 0, bufs, ii, size = 0;
 	struct smq_invoke_ctx *ctx = NULL;
 	struct fastrpc_ctx_lst *clst = &fl->clst;
 	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
@@ -1040,9 +1090,14 @@
 	ctx->maps = (struct fastrpc_mmap **)(&ctx[1]);
 	ctx->lpra = (remote_arg_t *)(&ctx->maps[bufs]);
 	ctx->fds = (int *)(&ctx->lpra[bufs]);
-	ctx->attrs = (unsigned int *)(&ctx->fds[bufs]);
-	ctx->overs = (struct overlap *)(&ctx->attrs[bufs]);
-	ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	if (me->legacy) {
+		ctx->overs = (struct overlap *)(&ctx->fds[bufs]);
+		ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	} else {
+		ctx->attrs = (unsigned int *)(&ctx->fds[bufs]);
+		ctx->overs = (struct overlap *)(&ctx->attrs[bufs]);
+		ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	}
 
 	K_COPY_FROM_USER(err, kernel, (void *)ctx->lpra, invoke->pra,
 					bufs * sizeof(*ctx->lpra));
@@ -1078,6 +1133,21 @@
 	hlist_add_head(&ctx->hn, &clst->pending);
 	spin_unlock(&fl->hlock);
 
+	spin_lock(&me->ctxlock);
+	for (ii = 0; ii < FASTRPC_CTX_MAX; ii++) {
+		if (!me->ctxtable[ii]) {
+			me->ctxtable[ii] = ctx;
+			ctx->ctxid = (ptr_to_uint64(ctx) & ~0xFFF)|(ii << 4);
+			break;
+		}
+	}
+	spin_unlock(&me->ctxlock);
+	VERIFY(err, ii < FASTRPC_CTX_MAX);
+	if (err) {
+		pr_err("adsprpc: out of context memory\n");
+		goto bail;
+	}
+
 	*po = ctx;
 bail:
 	if (ctx && err)
@@ -1100,6 +1170,7 @@
 static void context_free(struct smq_invoke_ctx *ctx)
 {
 	int i;
+	struct fastrpc_apps *me = &gfa;
 	int nbufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
 		    REMOTE_SCALARS_OUTBUFS(ctx->sc);
 	spin_lock(&ctx->fl->hlock);
@@ -1112,6 +1183,17 @@
 	mutex_unlock(&ctx->fl->fl_map_mutex);
 	fastrpc_buf_free(ctx->buf, 1);
 	ctx->magic = 0;
+	ctx->ctxid = 0;
+
+	spin_lock(&me->ctxlock);
+	for (i = 0; i < FASTRPC_CTX_MAX; i++) {
+		if (me->ctxtable[i] == ctx) {
+			me->ctxtable[i] = NULL;
+			break;
+		}
+	}
+	spin_unlock(&me->ctxlock);
+
 	kfree(ctx);
 }
 
@@ -1226,6 +1308,7 @@
 
 static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
 {
+	struct fastrpc_apps *me = &gfa;
 	remote_arg64_t *rpra;
 	remote_arg_t *lpra = ctx->lpra;
 	struct smq_invoke_buf *list;
@@ -1255,10 +1338,16 @@
 		size_t len = lpra[i].buf.len;
 
 		mutex_lock(&ctx->fl->fl_map_mutex);
-		if (ctx->fds[i] && (ctx->fds[i] != -1))
+		if (ctx->fds[i] && (ctx->fds[i] != -1)) {
+			unsigned int attrs = 0;
+
+			if (ctx->attrs)
+				attrs = ctx->attrs[i];
+
 			fastrpc_mmap_create(ctx->fl, ctx->fds[i],
-					ctx->attrs[i], buf, len,
+					attrs, buf, len,
 					mflags, &ctx->maps[i]);
+		}
 		mutex_unlock(&ctx->fl->fl_map_mutex);
 		ipage += 1;
 	}
@@ -1266,8 +1355,12 @@
 	handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
 	mutex_lock(&ctx->fl->fl_map_mutex);
 	for (i = bufs; i < bufs + handles; i++) {
+		int dmaflags = 0;
+
+		if (ctx->attrs && (ctx->attrs[i] & FASTRPC_ATTR_NOMAP))
+			dmaflags = FASTRPC_DMAHANDLE_NOMAP;
 		VERIFY(err, !fastrpc_mmap_create(ctx->fl, ctx->fds[i],
-				FASTRPC_ATTR_NOVA, 0, 0, 0, &ctx->maps[i]));
+			FASTRPC_ATTR_NOVA, 0, 0, dmaflags, &ctx->maps[i]));
 		if (err) {
 			mutex_unlock(&ctx->fl->fl_map_mutex);
 			goto bail;
@@ -1275,8 +1368,13 @@
 		ipage += 1;
 	}
 	mutex_unlock(&ctx->fl->fl_map_mutex);
-	metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) +
-				 (sizeof(uint32_t) * M_CRCLIST);
+	if (!me->legacy) {
+		metalen = copylen = (size_t)&ipage[0] +
+				(sizeof(uint64_t) * M_FDLIST) +
+				(sizeof(uint32_t) * M_CRCLIST);
+	} else {
+		metalen = copylen = (size_t)&ipage[0];
+	}
 
 	/* calculate len requreed for copying */
 	for (oix = 0; oix < inbufs + outbufs; ++oix) {
@@ -1372,16 +1470,18 @@
 		pages[i].addr = map->phys;
 		pages[i].size = map->size;
 	}
-	fdlist = (uint64_t *)&pages[bufs + handles];
-	for (i = 0; i < M_FDLIST; i++)
-		fdlist[i] = 0;
-	crclist = (uint32_t *)&fdlist[M_FDLIST];
-	memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST);
+	if (!me->legacy) {
+		fdlist = (uint64_t *)&pages[bufs + handles];
+		for (i = 0; i < M_FDLIST; i++)
+			fdlist[i] = 0;
+		crclist = (uint32_t *)&fdlist[M_FDLIST];
+		memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST);
+	}
 
 	/* copy non ion buffers */
 	PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY),
 	rlen = copylen - metalen;
-	for (oix = 0; oix < inbufs + outbufs; ++oix) {
+	for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) {
 		int i = ctx->overps[oix]->raix;
 		struct fastrpc_mmap *map = ctx->maps[i];
 		size_t mlen;
@@ -1432,7 +1532,7 @@
 		if (map && (map->attr & FASTRPC_ATTR_COHERENT))
 			continue;
 
-		if (rpra[i].buf.len && ctx->overps[oix]->mstart)
+		if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart)
 			dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
 			uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len));
 	}
@@ -1455,11 +1555,12 @@
 static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
 		    remote_arg_t *upra)
 {
+	struct fastrpc_apps *me = &gfa;
 	uint32_t sc = ctx->sc;
 	struct smq_invoke_buf *list;
 	struct smq_phy_page *pages;
 	struct fastrpc_mmap *mmap;
-	uint64_t *fdlist;
+	uint64_t *fdlist = NULL;
 	uint32_t *crclist = NULL;
 
 	remote_arg64_t *rpra = ctx->rpra;
@@ -1471,8 +1572,10 @@
 	handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
 	list = smq_invoke_buf_start(ctx->rpra, sc);
 	pages = smq_phy_page_start(sc, list);
-	fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
-	crclist = (uint32_t *)(fdlist + M_FDLIST);
+	if (!me->legacy) {
+		fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
+		crclist = (uint32_t *)(fdlist + M_FDLIST);
+	}
 
 	for (i = inbufs; i < inbufs + outbufs; ++i) {
 		if (!ctx->maps[i]) {
@@ -1490,7 +1593,7 @@
 		}
 	}
 	mutex_lock(&ctx->fl->fl_map_mutex);
-	if (inbufs + outbufs + handles) {
+	if (fdlist && (inbufs + outbufs + handles)) {
 		for (i = 0; i < M_FDLIST; i++) {
 			if (!fdlist[i])
 				break;
@@ -1590,7 +1693,7 @@
 	struct smq_msg *msg = &ctx->msg;
 	struct fastrpc_file *fl = ctx->fl;
 	struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid];
-	int err = 0;
+	int err = 0, len;
 
 	VERIFY(err, NULL != channel_ctx->chan);
 	if (err)
@@ -1601,27 +1704,89 @@
 		msg->tid |= (1 << SESSION_ID_INDEX);
 	if (kernel)
 		msg->pid = 0;
-	msg->invoke.header.ctx = ptr_to_uint64(ctx) | fl->pd;
+	msg->invoke.header.ctx = ctx->ctxid | fl->pd;
 	msg->invoke.header.handle = handle;
 	msg->invoke.header.sc = ctx->sc;
 	msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0;
 	msg->invoke.page.size = buf_page_size(ctx->used);
-
-	if (fl->ssrcount != channel_ctx->ssrcount) {
-		err = -ECONNRESET;
-		goto bail;
-	}
-	VERIFY(err, channel_ctx->link.port_state ==
+	if (fl->apps->glink) {
+		if (fl->ssrcount != channel_ctx->ssrcount) {
+			err = -ECONNRESET;
+			goto bail;
+		}
+		VERIFY(err, channel_ctx->link.port_state ==
 			FASTRPC_LINK_CONNECTED);
-	if (err)
-		goto bail;
-	err = glink_tx(channel_ctx->chan,
-		(void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
-		GLINK_TX_REQ_INTENT);
+		if (err)
+			goto bail;
+		err = glink_tx(channel_ctx->chan,
+			(void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
+			GLINK_TX_REQ_INTENT);
+	} else {
+		spin_lock(&fl->apps->hlock);
+		len = smd_write((smd_channel_t *)
+				channel_ctx->chan,
+				msg, sizeof(*msg));
+		spin_unlock(&fl->apps->hlock);
+		VERIFY(err, len == sizeof(*msg));
+	}
  bail:
 	return err;
 }
 
+static void fastrpc_smd_read_handler(int cid)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct smq_invoke_rsp rsp = {0};
+	int ret = 0, err = 0;
+	uint32_t index;
+
+	do {
+		ret = smd_read_from_cb(me->channel[cid].chan, &rsp,
+					sizeof(rsp));
+		if (ret != sizeof(rsp))
+			break;
+
+		index = (uint32_t)((rsp.ctx & FASTRPC_CTXID_MASK) >> 4);
+		VERIFY(err, index < FASTRPC_CTX_MAX);
+		if (err)
+			goto bail;
+
+		VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index]));
+		if (err)
+			goto bail;
+
+		VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp.ctx & ~1)) &&
+			me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC));
+		if (err)
+			goto bail;
+
+		context_notify_user(me->ctxtable[index], rsp.retval);
+	} while (ret == sizeof(rsp));
+bail:
+	if (err)
+		pr_err("adsprpc: invalid response or context\n");
+
+}
+
+static void smd_event_handler(void *priv, unsigned int event)
+{
+	struct fastrpc_apps *me = &gfa;
+	int cid = (int)(uintptr_t)priv;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+		complete(&me->channel[cid].workport);
+		break;
+	case SMD_EVENT_CLOSE:
+		fastrpc_notify_drivers(me, cid);
+		break;
+	case SMD_EVENT_DATA:
+		fastrpc_smd_read_handler(cid);
+		break;
+	}
+}
+
+
 static void fastrpc_init(struct fastrpc_apps *me)
 {
 	int i;
@@ -1629,6 +1794,7 @@
 	INIT_HLIST_HEAD(&me->drivers);
 	INIT_HLIST_HEAD(&me->maps);
 	spin_lock_init(&me->hlock);
+	spin_lock_init(&me->ctxlock);
 	mutex_init(&me->smd_mutex);
 	me->channel = &gcinfo[0];
 	for (i = 0; i < NUM_CHANNELS; i++) {
@@ -1914,6 +2080,8 @@
 		if (!strcmp(proc_name, "audiopd")) {
 			fl->spdname = AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME;
 			VERIFY(err, !fastrpc_mmap_remove_pdr(fl));
+			if (err)
+				goto bail;
 		}
 
 		if (!me->staticpd_flags) {
@@ -2296,8 +2464,8 @@
 	if (err)
 		goto bail;
 	mutex_lock(&fl->fl_map_mutex);
-	if (!fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
-		pr_err("mapping not found to unamp %x va %llx %x\n",
+	if (fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
+		pr_err("adsprpc: mapping not found to unmap %d va %llx %x\n",
 			ud->fd, (unsigned long long)ud->va,
 			(unsigned int)ud->len);
 		err = -1;
@@ -2355,10 +2523,11 @@
 
 	ctx = container_of(kref, struct fastrpc_channel_ctx, kref);
 	cid = ctx - &gcinfo[0];
-	fastrpc_glink_close(ctx->chan, cid);
+	if (!me->glink)
+		smd_close(ctx->chan);
+	else
+		fastrpc_glink_close(ctx->chan, cid);
 	ctx->chan = NULL;
-	glink_unregister_link_state_cb(ctx->link.link_notify_handle);
-	ctx->link.link_notify_handle = NULL;
 	mutex_unlock(&me->smd_mutex);
 	pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
 						MAJOR(me->dev_no), cid);
@@ -2414,19 +2583,29 @@
 	const void *pkt_priv, const void *ptr, size_t size)
 {
 	struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)ptr;
-	struct smq_invoke_ctx *ctx;
+	struct fastrpc_apps *me = &gfa;
+	uint32_t index;
 	int err = 0;
 
 	VERIFY(err, (rsp && size >= sizeof(*rsp)));
 	if (err)
 		goto bail;
 
-	ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rsp->ctx & ~1));
-	VERIFY(err, (ctx && ctx->magic == FASTRPC_CTX_MAGIC));
+	index = (uint32_t)((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
+	VERIFY(err, index < FASTRPC_CTX_MAX);
 	if (err)
 		goto bail;
 
-	context_notify_user(ctx, rsp->retval);
+	VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index]));
+	if (err)
+		goto bail;
+
+	VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp->ctx & ~1)) &&
+		me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC));
+	if (err)
+		goto bail;
+
+	context_notify_user(me->ctxtable[index], rsp->retval);
 bail:
 	if (err)
 		pr_err("adsprpc: invalid response or context\n");
@@ -2512,7 +2691,7 @@
 		fastrpc_mmap_free(map, 1);
 	}
 	mutex_unlock(&fl->fl_map_mutex);
-	if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
+	if (fl->refcount && (fl->ssrcount == fl->apps->channel[cid].ssrcount))
 		kref_put_mutex(&fl->apps->channel[cid].kref,
 				fastrpc_channel_close, &fl->apps->smd_mutex);
 	if (fl->sctx)
@@ -2805,15 +2984,21 @@
 		}
 	}
 	fl->ssrcount = me->channel[cid].ssrcount;
+	fl->refcount = 1;
 	if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) ||
 	    (me->channel[cid].chan == NULL)) {
-		VERIFY(err, 0 == fastrpc_glink_register(cid, me));
-		if (err)
-			goto bail;
-		VERIFY(err, 0 == fastrpc_glink_open(cid));
-		if (err)
-			goto bail;
-
+		if (me->glink) {
+			VERIFY(err, 0 == fastrpc_glink_register(cid, me));
+			if (err)
+				goto bail;
+			VERIFY(err, 0 == fastrpc_glink_open(cid));
+		} else {
+		VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID,
+				gcinfo[cid].channel,
+				(smd_channel_t **)&me->channel[cid].chan,
+				(void *)(uintptr_t)cid,
+				smd_event_handler));
+		}
 		VERIFY(err,
 			 wait_for_completion_timeout(&me->channel[cid].workport,
 						RPC_TIMEOUT));
@@ -2824,13 +3009,15 @@
 		kref_init(&me->channel[cid].kref);
 		pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
 						MAJOR(me->dev_no), cid);
-		err = glink_queue_rx_intent(me->channel[cid].chan, NULL,
-			FASTRPC_GLINK_INTENT_LEN);
-		err |= glink_queue_rx_intent(me->channel[cid].chan, NULL,
-			FASTRPC_GLINK_INTENT_LEN);
-		if (err)
-			pr_warn("adsprpc: initial intent fail for %d err %d\n",
-					 cid, err);
+		if (me->glink) {
+			err = glink_queue_rx_intent(me->channel[cid].chan, NULL,
+				FASTRPC_GLINK_INTENT_LEN);
+			err |= glink_queue_rx_intent(me->channel[cid].chan,
+				NULL, FASTRPC_GLINK_INTENT_LEN);
+			if (err)
+				pr_warn("adsprpc: initial intent fail for %d err %d\n",
+					cid, err);
+		}
 		if (cid == 0 && me->channel[cid].ssrcount !=
 				 me->channel[cid].prevssrcount) {
 			if (fastrpc_mmap_remove_ssr(fl))
@@ -2870,8 +3057,8 @@
 	fl->cid = -1;
 	if (debugfs_file != NULL)
 		fl->debugfs_file = debugfs_file;
-	memset(&fl->perf, 0, sizeof(fl->perf));
 	fl->qos_request = 0;
+	fl->refcount = 0;
 	filp->private_data = fl;
 	mutex_init(&fl->map_mutex);
 	mutex_init(&fl->fl_map_mutex);
@@ -3153,7 +3340,10 @@
 		ctx->ssrcount++;
 		ctx->issubsystemup = 0;
 		if (ctx->chan) {
-			fastrpc_glink_close(ctx->chan, cid);
+			if (me->glink)
+				fastrpc_glink_close(ctx->chan, cid);
+			else
+				smd_close(ctx->chan);
 			ctx->chan = NULL;
 			pr_info("'restart notifier: closed /dev/%s c %d %d'\n",
 				 gcinfo[cid].name, MAJOR(me->dev_no), cid);
@@ -3243,6 +3433,8 @@
 	{ .compatible = "qcom,msm-fastrpc-adsp", },
 	{ .compatible = "qcom,msm-fastrpc-compute", },
 	{ .compatible = "qcom,msm-fastrpc-compute-cb", },
+	{ .compatible = "qcom,msm-fastrpc-legacy-compute", },
+	{ .compatible = "qcom,msm-fastrpc-legacy-compute-cb", },
 	{ .compatible = "qcom,msm-adsprpc-mem-region", },
 	{}
 };
@@ -3311,6 +3503,85 @@
 	return err;
 }
 
+static int fastrpc_cb_legacy_probe(struct device *dev)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct fastrpc_channel_ctx *chan;
+	struct fastrpc_session_ctx *first_sess = NULL, *sess = NULL;
+	const char *name;
+	unsigned int *sids = NULL, sids_size = 0;
+	int err = 0, ret = 0, i;
+
+	unsigned int start = 0x80000000;
+
+	VERIFY(err, NULL != (name = of_get_property(dev->of_node,
+					 "label", NULL)));
+	if (err)
+		goto bail;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (!gcinfo[i].name)
+			continue;
+		if (!strcmp(name, gcinfo[i].name))
+			break;
+	}
+	VERIFY(err, i < NUM_CHANNELS);
+	if (err)
+		goto bail;
+
+	chan = &gcinfo[i];
+	VERIFY(err, chan->sesscount < NUM_SESSIONS);
+	if (err)
+		goto bail;
+
+	first_sess  = &chan->session[chan->sesscount];
+
+	VERIFY(err, NULL != of_get_property(dev->of_node,
+				"sids", &sids_size));
+	if (err)
+		goto bail;
+
+	VERIFY(err, NULL != (sids = kzalloc(sids_size, GFP_KERNEL)));
+	if (err)
+		goto bail;
+	ret = of_property_read_u32_array(dev->of_node, "sids", sids,
+					sids_size/sizeof(unsigned int));
+	if (ret)
+		goto bail;
+
+	VERIFY(err, !IS_ERR_OR_NULL(first_sess->smmu.mapping =
+				arm_iommu_create_mapping(&platform_bus_type,
+						start, 0x78000000)));
+	if (err)
+		goto bail;
+
+	VERIFY(err, !arm_iommu_attach_device(dev, first_sess->smmu.mapping));
+	if (err)
+		goto bail;
+
+
+	for (i = 0; i < sids_size/sizeof(unsigned int); i++) {
+		VERIFY(err, chan->sesscount < NUM_SESSIONS);
+		if (err)
+			goto bail;
+		sess = &chan->session[chan->sesscount];
+		sess->smmu.cb = sids[i];
+		sess->smmu.dev = dev;
+		sess->smmu.mapping = first_sess->smmu.mapping;
+		sess->smmu.enabled = 1;
+		sess->used = 0;
+		sess->smmu.coherent = false;
+		sess->smmu.secure = false;
+		chan->sesscount++;
+	}
+	me->legacy = 1;
+bail:
+	kfree(sids);
+	return err;
+}
+
+
+
 static void init_secure_vmid_list(struct device *dev, char *prop_name,
 						struct secure_vm *destvm)
 {
@@ -3378,6 +3649,16 @@
 		return fastrpc_cb_probe(dev);
 
 	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-fastrpc-legacy-compute")) {
+		me->glink = false;
+	}
+
+	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-fastrpc-legacy-compute-cb")){
+		return fastrpc_cb_legacy_probe(dev);
+	}
+
+	if (of_device_is_compatible(dev->of_node,
 					"qcom,msm-adsprpc-mem-region")) {
 		me->dev = dev;
 		range.addr = 0;
@@ -3399,7 +3680,8 @@
 				break;
 			}
 		}
-		if (range.addr) {
+		if (range.addr && !of_property_read_bool(dev->of_node,
+							 "restrict-access")) {
 			int srcVM[1] = {VMID_HLOS};
 			int destVM[4] = {VMID_HLOS, VMID_MSS_MSA, VMID_SSC_Q6,
 						VMID_ADSP_Q6};
@@ -3413,6 +3695,8 @@
 					srcVM, 1, destVM, destVMperm, 4));
 			if (err)
 				goto bail;
+			me->range.addr = range.addr;
+			me->range.size = range.size;
 		}
 		return 0;
 	}
@@ -3492,6 +3776,7 @@
 
 	fastrpc_init(me);
 	me->dev = NULL;
+	me->glink = true;
 	VERIFY(err, 0 == platform_driver_register(&fastrpc_driver));
 	if (err)
 		goto register_bail;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 535160a..bb7b654 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -47,6 +47,9 @@
 /* Fastrpc attribute for keeping the map persistent */
 #define FASTRPC_ATTR_KEEP_MAP	0x8
 
+/* Fastrpc attribute for no map */
+#define FASTRPC_ATTR_NOMAP   (16)
+
 /* Driver should operate in parallel with the co-processor */
 #define FASTRPC_MODE_PARALLEL    0
 
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index e309241..93c164b 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -34,4 +34,11 @@
 	  become available, this bridge driver enables DIAG traffic over MHI
 	  and SMUX.
 
+config DIAG_USES_SMD
+	bool "Enable diag internal interface over SMD"
+	depends on DIAG_CHAR && MSM_SMD
+	help
+	  Diag over SMD enables exchanging diagnostic information between
+	  application processor and peripherals over SDM.
+
 endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index b61aae8..897375e 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -3,4 +3,5 @@
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_smux.o
 obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.o
+obj-$(CONFIG_DIAG_USES_SMD) += diagfwd_smd.o
 diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 0aad08a..a469eb9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -865,7 +865,7 @@
 	read_len += sizeof(struct diag_ctrl_dci_status);
 
 	for (i = 0; i < header->count; i++) {
-		if (read_len > len) {
+		if (read_len > (len - 2)) {
 			pr_err("diag: In %s, Invalid length len: %d\n",
 			       __func__, len);
 			return;
@@ -1163,18 +1163,31 @@
 	struct list_head *start, *temp;
 	struct diag_dci_client_tbl *entry = NULL;
 
-	length = *(uint16_t *)(buf + 1); /* total length of event series */
-	if (length == 0) {
-		pr_err("diag: Incoming dci event length is invalid\n");
+	if (!buf) {
+		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
 	/*
-	 * Move directly to the start of the event series. 1 byte for
-	 * event code and 2 bytes for the length field.
+	 * 1 byte for event code and 2 bytes for the length field.
 	 * The length field indicates the total length removing the cmd_code
 	 * and the length field. The event parsing in that case should happen
 	 * till the end.
 	 */
+	if (len < 3) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
+	length = *(uint16_t *)(buf + 1); /* total length of event series */
+	if ((length == 0) || (len != (length + 3))) {
+		pr_err("diag: Incoming dci event length: %d is invalid\n",
+			length);
+		return;
+	}
+	/*
+	 * Move directly to the start of the event series.
+	 * The event parsing should happen from start of event
+	 * series till the end.
+	 */
 	temp_len = 3;
 	while (temp_len < length) {
 		event_id_packet = *(uint16_t *)(buf + temp_len);
@@ -1191,30 +1204,60 @@
 			 * necessary.
 			 */
 			timestamp_len = 8;
-			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
+			if ((temp_len + timestamp_len + 2) <= len)
+				memcpy(timestamp, buf + temp_len + 2,
+					timestamp_len);
+			else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
 		}
 		/* 13th and 14th bit represent the payload length */
 		if (((event_id_packet & 0x6000) >> 13) == 3) {
 			payload_len_field = 1;
-			payload_len = *(uint8_t *)
+			if ((temp_len + timestamp_len + 3) <= len) {
+				payload_len = *(uint8_t *)
 					(buf + temp_len + 2 + timestamp_len);
-			if (payload_len < (MAX_EVENT_SIZE - 13)) {
-				/* copy the payload length and the payload */
+			} else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
+			if ((payload_len < (MAX_EVENT_SIZE - 13)) &&
+			((temp_len + timestamp_len + payload_len + 3) <= len)) {
+				/*
+				 * Copy the payload length and the payload
+				 * after skipping temp_len bytes for already
+				 * parsed packet, timestamp_len for timestamp
+				 * buffer, 2 bytes for event_id_packet.
+				 */
 				memcpy(event_data + 12, buf + temp_len + 2 +
 							timestamp_len, 1);
 				memcpy(event_data + 13, buf + temp_len + 2 +
 					timestamp_len + 1, payload_len);
 			} else {
-				pr_err("diag: event > %d, payload_len = %d\n",
-					(MAX_EVENT_SIZE - 13), payload_len);
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 13), payload_len, temp_len);
 				return;
 			}
 		} else {
 			payload_len_field = 0;
 			payload_len = (event_id_packet & 0x6000) >> 13;
-			/* copy the payload */
-			memcpy(event_data + 12, buf + temp_len + 2 +
+			/*
+			 * Copy the payload after skipping temp_len bytes
+			 * for already parsed packet, timestamp_len for
+			 * timestamp buffer, 2 bytes for event_id_packet.
+			 */
+			if ((payload_len < (MAX_EVENT_SIZE - 12)) &&
+			((temp_len + timestamp_len + payload_len + 2) <= len))
+				memcpy(event_data + 12, buf + temp_len + 2 +
 						timestamp_len, payload_len);
+			else {
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 12), payload_len, temp_len);
+				return;
+			}
 		}
 
 		/* Before copying the data to userspace, check if we are still
@@ -1340,19 +1383,19 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
-
-	/* The first six bytes for the incoming log packet contains
-	 * Command code (2), the length of the packet (2) and the length
-	 * of the log (2)
+	/*
+	 * The first eight bytes for the incoming log packet contains
+	 * Command code (2), the length of the packet (2), the length
+	 * of the log (2) and log code (2)
 	 */
-	log_code = *(uint16_t *)(buf + 6);
-	read_bytes += sizeof(uint16_t) + 6;
-	if (read_bytes > len) {
-		pr_err("diag: Invalid length in %s, len: %d, read: %d",
-						__func__, len, read_bytes);
+	if (len < 8) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
 		return;
 	}
 
+	log_code = *(uint16_t *)(buf + 6);
+	read_bytes += sizeof(uint16_t) + 6;
+
 	/* parse through log mask table of each client and check mask */
 	mutex_lock(&driver->dci_mutex);
 	list_for_each_safe(start, temp, &driver->dci_client_list) {
@@ -1379,6 +1422,10 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
+	if (len < (EXT_HDR_LEN + sizeof(uint8_t))) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
 
 	version = *(uint8_t *)buf + 1;
 	if (version < EXT_HDR_VERSION)  {
@@ -1390,10 +1437,6 @@
 	pkt = buf + EXT_HDR_LEN;
 	pkt_cmd_code = *(uint8_t *)pkt;
 	len -= EXT_HDR_LEN;
-	if (len < 0) {
-		pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
-		return;
-	}
 
 	switch (pkt_cmd_code) {
 	case LOG_CMD_CODE:
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 0a3faba..a7f29e6 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -32,6 +32,7 @@
 #include "diag_dci.h"
 #include "diag_usb.h"
 #include "diagfwd_peripheral.h"
+#include "diagfwd_smd.h"
 #include "diagfwd_socket.h"
 #include "diagfwd_glink.h"
 #include "diag_debugfs.h"
@@ -42,6 +43,7 @@
 static int diag_dbgfs_table_index;
 static int diag_dbgfs_mempool_index;
 static int diag_dbgfs_usbinfo_index;
+static int diag_dbgfs_smdinfo_index;
 static int diag_dbgfs_socketinfo_index;
 static int diag_dbgfs_glinkinfo_index;
 static int diag_dbgfs_hsicinfo_index;
@@ -479,6 +481,112 @@
 	return ret;
 }
 
+#ifdef CONFIG_DIAG_USES_SMD
+static ssize_t diag_dbgfs_read_smdinfo(struct file *file, char __user *ubuf,
+				       size_t count, loff_t *ppos)
+{
+	char *buf = NULL;
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+	unsigned int buf_size;
+	unsigned int bytes_remaining = 0;
+	unsigned int bytes_written = 0;
+	unsigned int bytes_in_buffer = 0;
+	struct diag_smd_info *smd_info = NULL;
+	struct diagfwd_info *fwd_ctxt = NULL;
+
+	if (diag_dbgfs_smdinfo_index >= NUM_PERIPHERALS) {
+		/* Done. Reset to prepare for future requests */
+		diag_dbgfs_smdinfo_index = 0;
+		return 0;
+	}
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf_size = DEBUG_BUF_SIZE;
+	bytes_remaining = buf_size;
+	for (i = 0; i < NUM_TYPES; i++) {
+		for (j = 0; j < NUM_PERIPHERALS; j++) {
+			switch (i) {
+			case TYPE_DATA:
+				smd_info = &smd_data[j];
+				break;
+			case TYPE_CNTL:
+				smd_info = &smd_cntl[j];
+				break;
+			case TYPE_DCI:
+				smd_info = &smd_dci[j];
+				break;
+			case TYPE_CMD:
+				smd_info = &smd_cmd[j];
+				break;
+			case TYPE_DCI_CMD:
+				smd_info = &smd_dci_cmd[j];
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			fwd_ctxt = (struct diagfwd_info *)(smd_info->fwd_ctxt);
+
+			bytes_written = scnprintf(buf+bytes_in_buffer,
+				bytes_remaining,
+				"name\t\t:\t%s\n"
+				"hdl\t\t:\t%pK\n"
+				"inited\t\t:\t%d\n"
+				"opened\t\t:\t%d\n"
+				"diag_state\t:\t%d\n"
+				"fifo size\t:\t%d\n"
+				"open pending\t:\t%d\n"
+				"close pending\t:\t%d\n"
+				"read pending\t:\t%d\n"
+				"buf_1 busy\t:\t%d\n"
+				"buf_2 busy\t:\t%d\n"
+				"bytes read\t:\t%lu\n"
+				"bytes written\t:\t%lu\n"
+				"fwd inited\t:\t%d\n"
+				"fwd opened\t:\t%d\n"
+				"fwd ch_open\t:\t%d\n\n",
+				smd_info->name,
+				smd_info->hdl,
+				smd_info->inited,
+				atomic_read(&smd_info->opened),
+				atomic_read(&smd_info->diag_state),
+				smd_info->fifo_size,
+				work_pending(&smd_info->open_work),
+				work_pending(&smd_info->close_work),
+				work_pending(&smd_info->read_work),
+				(fwd_ctxt && fwd_ctxt->buf_1) ?
+				atomic_read(&fwd_ctxt->buf_1->in_busy) : -1,
+				(fwd_ctxt && fwd_ctxt->buf_2) ?
+				atomic_read(&fwd_ctxt->buf_2->in_busy) : -1,
+				(fwd_ctxt) ? fwd_ctxt->read_bytes : 0,
+				(fwd_ctxt) ? fwd_ctxt->write_bytes : 0,
+				(fwd_ctxt) ? fwd_ctxt->inited : -1,
+				(fwd_ctxt) ?
+				atomic_read(&fwd_ctxt->opened) : -1,
+				(fwd_ctxt) ? fwd_ctxt->ch_open : -1);
+			bytes_in_buffer += bytes_written;
+
+			/* Check if there is room to add another table entry */
+			bytes_remaining = buf_size - bytes_in_buffer;
+
+			if (bytes_remaining < bytes_written)
+				break;
+		}
+	}
+	diag_dbgfs_smdinfo_index = i+1;
+	*ppos = 0;
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
+
+	kfree(buf);
+	return ret;
+}
+#endif
+
 static ssize_t diag_dbgfs_read_socketinfo(struct file *file, char __user *ubuf,
 					  size_t count, loff_t *ppos)
 {
@@ -944,6 +1052,12 @@
 	.read = diag_dbgfs_read_status,
 };
 
+#ifdef CONFIG_DIAG_USES_SMD
+static const struct file_operations diag_dbgfs_smdinfo_ops = {
+	.read = diag_dbgfs_read_smdinfo,
+};
+#endif
+
 const struct file_operations diag_dbgfs_socketinfo_ops = {
 	.read = diag_dbgfs_read_socketinfo,
 };
@@ -989,6 +1103,13 @@
 	if (!entry)
 		goto err;
 
+#ifdef CONFIG_DIAG_USES_SMD
+	entry = debugfs_create_file("smdinfo", 0444, diag_dbgfs_dent, NULL,
+				    &diag_dbgfs_smdinfo_ops);
+	if (!entry)
+		goto err;
+#endif
+
 	entry = debugfs_create_file("socketinfo", 0444, diag_dbgfs_dent, 0,
 				    &diag_dbgfs_socketinfo_ops);
 	if (!entry)
@@ -1050,6 +1171,7 @@
 	diag_dbgfs_table_index = 0;
 	diag_dbgfs_mempool_index = 0;
 	diag_dbgfs_usbinfo_index = 0;
+	diag_dbgfs_smdinfo_index = 0;
 	diag_dbgfs_socketinfo_index = 0;
 	diag_dbgfs_hsicinfo_index = 0;
 	diag_dbgfs_bridgeinfo_index = 0;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index f510c14..223bc03 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -536,8 +536,7 @@
 }
 
 static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
@@ -545,23 +544,30 @@
 	struct diag_msg_ssid_query_t rsp;
 	struct diag_ssid_range_t ssid_range;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 	mutex_lock(&driver->msg_mask_lock);
 	rsp.cmd_code = DIAG_CMD_MSG_CONFIG;
 	rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE;
@@ -583,12 +589,12 @@
 		write_len += sizeof(ssid_range);
 	}
 	mutex_unlock(&driver->msg_mask_lock);
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i = 0;
 	int write_len = 0;
@@ -641,8 +647,7 @@
 }
 
 static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
@@ -651,6 +656,10 @@
 	struct diag_build_mask_req_t *req = NULL;
 	struct diag_msg_build_mask_t rsp;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -658,15 +667,19 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 
 	mutex_lock(&driver->msg_mask_lock);
 	req = (struct diag_build_mask_req_t *)src_buf;
@@ -681,6 +694,7 @@
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
@@ -700,12 +714,12 @@
 	memcpy(dest_buf, &rsp, sizeof(rsp));
 	write_len += sizeof(rsp);
 	mutex_unlock(&driver->msg_mask_lock);
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	uint32_t mask_size = 0, offset = 0;
 	uint32_t *temp = NULL;
@@ -716,6 +730,10 @@
 	struct diag_msg_build_mask_t rsp;
 	struct diag_mask_info *mask_info = NULL;
 	struct diag_msg_mask_t *mask_next = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -723,11 +741,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -740,6 +760,7 @@
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
 		mutex_unlock(&mask_info->lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
@@ -782,6 +803,7 @@
 				mutex_unlock(&mask->lock);
 				mutex_unlock(&driver->msg_mask_lock);
 				mutex_unlock(&mask_info->lock);
+				mutex_unlock(&driver->md_session_lock);
 				return -ENOMEM;
 			}
 			mask->ptr = temp;
@@ -802,6 +824,7 @@
 	}
 	mutex_unlock(&driver->msg_mask_lock);
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(MSG_MASKS_TYPE);
 
@@ -842,8 +865,7 @@
 }
 
 static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
-				     unsigned char *dest_buf, int dest_len,
-				     struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i, write_len = 0, peripheral;
 	int header_len = sizeof(struct diag_msg_config_rsp_t);
@@ -851,6 +873,10 @@
 	struct diag_msg_config_rsp_t *req = NULL;
 	struct diag_msg_mask_t *mask = NULL;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -858,11 +884,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -877,6 +905,7 @@
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
 		mutex_unlock(&mask_info->lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED :
@@ -889,7 +918,7 @@
 	}
 	mutex_unlock(&driver->msg_mask_lock);
 	mutex_unlock(&mask_info->lock);
-
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(MSG_MASKS_TYPE);
 
@@ -923,8 +952,7 @@
 }
 
 static int diag_cmd_get_event_mask(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int write_len = 0;
 	uint32_t mask_size;
@@ -959,26 +987,30 @@
 }
 
 static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
-				      unsigned char *dest_buf, int dest_len,
-				      struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i, write_len = 0, mask_len = 0, peripheral;
 	int header_len = sizeof(struct diag_event_mask_config_t);
 	struct diag_event_mask_config_t rsp;
 	struct diag_event_mask_config_t *req;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &event_mask : info->event_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	req = (struct diag_event_mask_config_t *)src_buf;
@@ -986,6 +1018,7 @@
 	if (mask_len <= 0 || mask_len > event_mask.mask_len) {
 		pr_err("diag: In %s, invalid event mask len: %d\n", __func__,
 		       mask_len);
+		mutex_unlock(&driver->md_session_lock);
 		return -EIO;
 	}
 
@@ -993,6 +1026,7 @@
 	memcpy(mask_info->ptr, src_buf + header_len, mask_len);
 	mask_info->status = DIAG_CTRL_MASK_VALID;
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 
@@ -1027,25 +1061,29 @@
 }
 
 static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len,
-				  unsigned char *dest_buf, int dest_len,
-				  struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int write_len = 0, i, peripheral;
 	uint8_t toggle = 0;
 	struct diag_event_report_t header;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &event_mask : info->event_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -1059,6 +1097,7 @@
 		memset(mask_info->ptr, 0, mask_info->mask_len);
 	}
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 
@@ -1088,8 +1127,7 @@
 }
 
 static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int status = LOG_STATUS_INVALID;
@@ -1102,6 +1140,10 @@
 	struct diag_log_config_req_t *req;
 	struct diag_log_config_rsp_t rsp;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1109,16 +1151,20 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 
 	req = (struct diag_log_config_req_t *)src_buf;
 	read_len += req_header_len;
@@ -1138,6 +1184,7 @@
 	if (!log_item->ptr) {
 		pr_err("diag: Invalid input in %s, mask: %pK\n",
 			__func__, log_item);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
@@ -1179,28 +1226,27 @@
 	rsp.status = status;
 	memcpy(dest_buf, &rsp, rsp_header_len);
 
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_get_log_range(unsigned char *src_buf, int src_len,
-				  unsigned char *dest_buf, int dest_len,
-				  struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
 	struct diag_log_config_rsp_t rsp;
-	struct diag_mask_info *mask_info = NULL;
 	struct diag_log_mask_t *mask = (struct diag_log_mask_t *)log_mask.ptr;
 
+	if (!mask)
+		return -EINVAL;
+
 	if (!diag_apps_responds())
 		return 0;
 
-	mask_info = (!info) ? &log_mask : info->log_mask;
-	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
-	    !mask_info) {
-		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
-		       __func__, src_buf, src_len, dest_buf, dest_len,
-		       mask_info);
+	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
+		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n",
+		       __func__, src_buf, src_len, dest_buf, dest_len);
 		return -EINVAL;
 	}
 
@@ -1223,7 +1269,7 @@
 
 static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
 				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+				 int pid)
 {
 	int i, peripheral, write_len = 0;
 	int status = LOG_STATUS_SUCCESS;
@@ -1236,6 +1282,10 @@
 	struct diag_log_mask_t *mask = NULL;
 	struct diag_mask_info *mask_info = NULL;
 	unsigned char *temp_buf = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1243,11 +1293,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -1257,6 +1309,7 @@
 	if (!mask->ptr) {
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (req->equip_id >= MAX_EQUIP_ID) {
@@ -1319,6 +1372,7 @@
 		break;
 	}
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
 
@@ -1365,13 +1419,16 @@
 }
 
 static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len,
-				     unsigned char *dest_buf, int dest_len,
-				     struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	struct diag_mask_info *mask_info = NULL;
 	struct diag_log_mask_t *mask = NULL;
 	struct diag_log_config_rsp_t header;
 	int write_len = 0, i, peripheral;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1379,17 +1436,20 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	mask = (struct diag_log_mask_t *)mask_info->ptr;
 	if (!mask->ptr) {
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < MAX_EQUIP_ID; i++, mask++) {
@@ -1398,6 +1458,7 @@
 		mutex_unlock(&mask->lock);
 	}
 	mask_info->status = DIAG_CTRL_MASK_ALL_DISABLED;
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
 
@@ -2144,13 +2205,11 @@
 	}
 }
 
-int diag_process_apps_masks(unsigned char *buf, int len,
-			    struct diag_md_session_t *info)
+int diag_process_apps_masks(unsigned char *buf, int len, int pid)
 {
 	int size = 0, sub_cmd = 0;
 	int (*hdlr)(unsigned char *src_buf, int src_len,
-		    unsigned char *dest_buf, int dest_len,
-		    struct diag_md_session_t *info) = NULL;
+		    unsigned char *dest_buf, int dest_len, int pid) = NULL;
 
 	if (!buf || len <= 0)
 		return -EINVAL;
@@ -2200,7 +2259,7 @@
 
 	if (hdlr)
 		size = hdlr(buf, len, driver->apps_rsp_buf,
-			    DIAG_MAX_RSP_SIZE, info);
+			    DIAG_MAX_RSP_SIZE, pid);
 
 	return (size > 0) ? size : 0;
 }
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 1a52f94..6edeee9 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2018 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
@@ -167,8 +167,7 @@
 void diag_log_mask_free(struct diag_mask_info *mask_info);
 void diag_msg_mask_free(struct diag_mask_info *mask_info);
 void diag_event_mask_free(struct diag_mask_info *mask_info);
-int diag_process_apps_masks(unsigned char *buf, int len,
-			    struct diag_md_session_t *info);
+int diag_process_apps_masks(unsigned char *buf, int len, int pid);
 void diag_send_updates_peripheral(uint8_t peripheral);
 
 extern int diag_create_msg_mask_table_entry(struct diag_msg_mask_t *msg_mask,
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 9cecb03..ce0c7bb 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -129,11 +129,10 @@
 
 int diag_md_write(int id, unsigned char *buf, int len, int ctx)
 {
-	int i;
+	int i, peripheral, pid = 0;
 	uint8_t found = 0;
 	unsigned long flags;
 	struct diag_md_info *ch = NULL;
-	int peripheral;
 	struct diag_md_session_t *session_info = NULL;
 
 	if (id < 0 || id >= NUM_DIAG_MD_DEV || id >= DIAG_NUM_PROC)
@@ -146,10 +145,14 @@
 	if (peripheral < 0)
 		return -EINVAL;
 
-	session_info =
-		diag_md_session_get_peripheral(peripheral);
-	if (!session_info)
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_peripheral(peripheral);
+	if (!session_info) {
+		mutex_unlock(&driver->md_session_lock);
 		return -EIO;
+	}
+	pid = session_info->pid;
+	mutex_unlock(&driver->md_session_lock);
 
 	ch = &diag_md[id];
 	if (!ch)
@@ -192,8 +195,7 @@
 
 	found = 0;
 	for (i = 0; i < driver->num_clients && !found; i++) {
-		if ((driver->client_map[i].pid !=
-		     session_info->pid) ||
+		if ((driver->client_map[i].pid != pid) ||
 		    (driver->client_map[i].pid == 0))
 			continue;
 
diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c
index 1cf7f52..060f03f 100644
--- a/drivers/char/diag/diag_usb.c
+++ b/drivers/char/diag/diag_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, 2018 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
@@ -221,7 +221,7 @@
 
 	if (!atomic_read(&ch->connected) &&
 		driver->usb_connected && diag_mask_param())
-		diag_clear_masks(NULL);
+		diag_clear_masks(0);
 
 	if (ch && ch->ops && ch->ops->close)
 		ch->ops->close(ch->ctxt, DIAG_USB_MODE);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9de40b0..badd12c 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -22,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/device.h>
+#include <soc/qcom/smd.h>
 #include <linux/atomic.h>
 #include "diagfwd_bridge.h"
 
@@ -714,7 +715,7 @@
 void diag_cmd_remove_reg_by_proc(int proc);
 int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
 int diag_mask_param(void);
-void diag_clear_masks(struct diag_md_session_t *info);
+void diag_clear_masks(int pid);
 uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
 int diag_query_pd(char *process_name);
 int diag_search_peripheral_by_pd(uint8_t pd_val);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0158549..e81b01a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -167,7 +167,7 @@
 void *diag_ipc_log;
 #endif
 
-static void diag_md_session_close(struct diag_md_session_t *session_info);
+static void diag_md_session_close(int pid);
 
 /*
  * Returns the next delayed rsp id. If wrapping is enabled,
@@ -243,12 +243,13 @@
 
 	timer_in_progress = 0;
 	mutex_lock(&apps_data_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (!hdlc_disabled)
 		diag_drain_apps_data(&hdlc_data);
 	else
@@ -374,8 +375,8 @@
 	return -ENOMEM;
 
 fail:
-	mutex_unlock(&driver->diagchar_mutex);
 	driver->num_clients--;
+	mutex_unlock(&driver->diagchar_mutex);
 	pr_err_ratelimited("diag: Insufficient memory for new client");
 	return -ENOMEM;
 }
@@ -422,7 +423,7 @@
 {
 	return diag_mask_clear_param;
 }
-void diag_clear_masks(struct diag_md_session_t *info)
+void diag_clear_masks(int pid)
 {
 	int ret;
 	char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0};
@@ -431,14 +432,14 @@
 
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 	"diag: %s: masks clear request upon %s\n", __func__,
-	((info) ? "ODL exit" : "USB Disconnection"));
+	((pid) ? "ODL exit" : "USB Disconnection"));
 
 	ret = diag_process_apps_masks(cmd_disable_log_mask,
-			sizeof(cmd_disable_log_mask), info);
+			sizeof(cmd_disable_log_mask), pid);
 	ret = diag_process_apps_masks(cmd_disable_msg_mask,
-			sizeof(cmd_disable_msg_mask), info);
+			sizeof(cmd_disable_msg_mask), pid);
 	ret = diag_process_apps_masks(cmd_disable_event_mask,
-			sizeof(cmd_disable_event_mask), info);
+			sizeof(cmd_disable_event_mask), pid);
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 	"diag:%s: masks cleared successfully\n", __func__);
 }
@@ -451,21 +452,23 @@
 	struct diag_md_session_t *session_info = NULL;
 	struct diag_logging_mode_param_t params;
 
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_pid(pid);
-	if (!session_info)
+	if (!session_info) {
+		mutex_unlock(&driver->md_session_lock);
 		return;
+	}
+	session_mask = session_info->peripheral_mask;
+	mutex_unlock(&driver->md_session_lock);
 
 	if (diag_mask_clear_param)
-		diag_clear_masks(session_info);
+		diag_clear_masks(pid);
 
 	mutex_lock(&driver->diag_maskclear_mutex);
 	driver->mask_clear = 1;
 	mutex_unlock(&driver->diag_maskclear_mutex);
 
 	mutex_lock(&driver->diagchar_mutex);
-	session_mask = session_info->peripheral_mask;
-	diag_md_session_close(session_info);
-
 	p_mask =
 	diag_translate_kernel_to_user_mask(session_mask);
 
@@ -489,7 +492,9 @@
 			}
 		}
 	}
-
+	mutex_lock(&driver->md_session_lock);
+	diag_md_session_close(pid);
+	mutex_unlock(&driver->md_session_lock);
 	diag_switch_logging(&params);
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -1024,11 +1029,13 @@
 
 	if (driver->hdlc_encode_buf_len != 0)
 		return -EAGAIN;
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled) {
 		if (len < 4) {
 			pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
@@ -1386,15 +1393,16 @@
 	return err;
 }
 
-static void diag_md_session_close(struct diag_md_session_t *session_info)
+static void diag_md_session_close(int pid)
 {
 	int i;
 	uint8_t found = 0;
+	struct diag_md_session_t *session_info = NULL;
 
+	session_info = diag_md_session_get_pid(pid);
 	if (!session_info)
 		return;
 
-	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] != session_info)
 			continue;
@@ -1420,13 +1428,14 @@
 	driver->md_session_mode = (found) ? DIAG_MD_PERIPHERAL : DIAG_MD_NONE;
 	kfree(session_info);
 	session_info = NULL;
-	mutex_unlock(&driver->md_session_lock);
 	DIAG_LOG(DIAG_DEBUG_USERSPACE, "cleared up session\n");
 }
 
 struct diag_md_session_t *diag_md_session_get_pid(int pid)
 {
 	int i;
+	if (pid <= 0)
+		return NULL;
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] &&
 		    driver->md_session_map[i]->pid == pid)
@@ -1442,10 +1451,12 @@
 	return driver->md_session_map[peripheral];
 }
 
-static int diag_md_peripheral_switch(struct diag_md_session_t *session_info,
+static int diag_md_peripheral_switch(int pid,
 				int peripheral_mask, int req_mode) {
 	int i, bit = 0;
+	struct diag_md_session_t *session_info = NULL;
 
+	session_info = diag_md_session_get_pid(pid);
 	if (!session_info)
 		return -EINVAL;
 	if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE)
@@ -1455,25 +1466,20 @@
 	 * check that md_session_map for i == session_info,
 	 * if not then race condition occurred and bail
 	 */
-	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		bit = MD_PERIPHERAL_MASK(i) & peripheral_mask;
 		if (!bit)
 			continue;
 		if (req_mode == DIAG_USB_MODE) {
-			if (driver->md_session_map[i] != session_info) {
-				mutex_unlock(&driver->md_session_lock);
+			if (driver->md_session_map[i] != session_info)
 				return -EINVAL;
-			}
 			driver->md_session_map[i] = NULL;
 			driver->md_session_mask &= ~bit;
 			session_info->peripheral_mask &= ~bit;
 
 		} else {
-			if (driver->md_session_map[i] != NULL) {
-				mutex_unlock(&driver->md_session_lock);
+			if (driver->md_session_map[i] != NULL)
 				return -EINVAL;
-			}
 			driver->md_session_map[i] = session_info;
 			driver->md_session_mask |= bit;
 			session_info->peripheral_mask |= bit;
@@ -1482,7 +1488,6 @@
 	}
 
 	driver->md_session_mode = DIAG_MD_PERIPHERAL;
-	mutex_unlock(&driver->md_session_lock);
 	DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n",
 		peripheral_mask, req_mode);
 }
@@ -1491,7 +1496,7 @@
 				 const struct diag_logging_mode_param_t *param,
 				 uint8_t *change_mode)
 {
-	int i, bit = 0, err = 0;
+	int i, bit = 0, err = 0, peripheral_mask = 0;
 	int change_mask = 0;
 	struct diag_md_session_t *session_info = NULL;
 
@@ -1515,12 +1520,13 @@
 	if (req_mode == DIAG_USB_MODE) {
 		if (curr_mode == DIAG_USB_MODE)
 			return 0;
+		mutex_lock(&driver->md_session_lock);
 		if (driver->md_session_mode == DIAG_MD_NONE
 		    && driver->md_session_mask == 0 && driver->logging_mask) {
 			*change_mode = 1;
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
 		}
-
 		/*
 		 * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE
 		 * Check if requested peripherals are already in usb mode
@@ -1532,8 +1538,10 @@
 			if (bit & driver->logging_mask)
 				change_mask |= bit;
 		}
-		if (!change_mask)
+		if (!change_mask) {
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
+		}
 
 		/*
 		 * Change is needed. Check if this md_session has set all the
@@ -1542,29 +1550,29 @@
 		 * If this session owns all the requested peripherals, then
 		 * call function to switch the modes/masks for the md_session
 		 */
-		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
-
 		if (!session_info) {
 			*change_mode = 1;
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
 		}
-		if ((change_mask & session_info->peripheral_mask)
+		peripheral_mask = session_info->peripheral_mask;
+		if ((change_mask & peripheral_mask)
 							!= change_mask) {
 			DIAG_LOG(DIAG_DEBUG_USERSPACE,
 			    "Another MD Session owns a requested peripheral\n");
+			mutex_unlock(&driver->md_session_lock);
 			return -EINVAL;
 		}
 		*change_mode = 1;
 
 		/* If all peripherals are being set to USB Mode, call close */
-		if (~change_mask & session_info->peripheral_mask) {
-			err = diag_md_peripheral_switch(session_info,
+		if (~change_mask & peripheral_mask) {
+			err = diag_md_peripheral_switch(current->tgid,
 					change_mask, DIAG_USB_MODE);
 		} else
-			diag_md_session_close(session_info);
-
+			diag_md_session_close(current->tgid);
+		mutex_unlock(&driver->md_session_lock);
 		return err;
 
 	} else if (req_mode == DIAG_MEMORY_DEVICE_MODE) {
@@ -1573,21 +1581,23 @@
 		 * been set. Check that requested peripherals already set are
 		 * owned by this md session
 		 */
-		change_mask = driver->md_session_mask & param->peripheral_mask;
 		mutex_lock(&driver->md_session_lock);
+		change_mask = driver->md_session_mask & param->peripheral_mask;
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 
 		if (session_info) {
 			if ((session_info->peripheral_mask & change_mask)
 							!= change_mask) {
 				DIAG_LOG(DIAG_DEBUG_USERSPACE,
 				    "Another MD Session owns a requested peripheral\n");
+				mutex_unlock(&driver->md_session_lock);
 				return -EINVAL;
 			}
-			err = diag_md_peripheral_switch(session_info,
+			err = diag_md_peripheral_switch(current->tgid,
 					change_mask, DIAG_USB_MODE);
+			mutex_unlock(&driver->md_session_lock);
 		} else {
+			mutex_unlock(&driver->md_session_lock);
 			if (change_mask) {
 				DIAG_LOG(DIAG_DEBUG_USERSPACE,
 				    "Another MD Session owns a requested peripheral\n");
@@ -1658,7 +1668,7 @@
 		}
 		if (!param->diag_id ||
 			(param->pd_val < UPD_WLAN) ||
-			(param->pd_val > NUM_MD_SESSIONS)) {
+			(param->pd_val >= NUM_MD_SESSIONS)) {
 			DIAG_LOG(DIAG_DEBUG_USERSPACE,
 			"diag_id support is not present for the pd mask = %d\n",
 			param->pd_mask);
@@ -2047,19 +2057,17 @@
 {
 	uint8_t hdlc_support;
 	struct diag_md_session_t *session_info = NULL;
-	mutex_lock(&driver->md_session_lock);
-	session_info = diag_md_session_get_pid(current->tgid);
-	mutex_unlock(&driver->md_session_lock);
 	if (copy_from_user(&hdlc_support, (void __user *)ioarg,
 				sizeof(uint8_t)))
 		return -EFAULT;
 	mutex_lock(&driver->hdlc_disable_mutex);
-	if (session_info) {
-		mutex_lock(&driver->md_session_lock);
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(current->tgid);
+	if (session_info)
 		session_info->hdlc_disabled = hdlc_support;
-		mutex_unlock(&driver->md_session_lock);
-	} else
+	else
 		driver->hdlc_disabled = hdlc_support;
+	mutex_unlock(&driver->md_session_lock);
 	mutex_unlock(&driver->hdlc_disable_mutex);
 	diag_update_md_clients(HDLC_SUPPORT_TYPE);
 
@@ -2885,7 +2893,6 @@
 	int remote_proc = 0;
 	const int mempool = POOL_TYPE_COPY;
 	unsigned char *user_space_data = NULL;
-	struct diag_md_session_t *info = NULL;
 
 	if (!buf || len <= 0 || len > CALLBACK_BUF_SIZE) {
 		pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
@@ -2936,13 +2943,11 @@
 	} else {
 		wait_event_interruptible(driver->wait_q,
 					 (driver->in_busy_pktdata == 0));
-		mutex_lock(&driver->md_session_lock);
-		info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
-		ret = diag_process_apps_pkt(user_space_data, len, info);
+		ret = diag_process_apps_pkt(user_space_data, len,
+			current->tgid);
 		if (ret == 1)
 			diag_send_error_rsp((void *)(user_space_data), len,
-						info);
+						current->tgid);
 	}
 fail:
 	diagmem_free(driver, user_space_data, mempool);
@@ -3008,24 +3013,25 @@
 	if (!remote_proc) {
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		if (!session_info) {
 			pr_err("diag:In %s request came from invalid md session pid:%d",
 				__func__, current->tgid);
+			mutex_unlock(&driver->md_session_lock);
 			return -EINVAL;
 		}
 		if (session_info)
 			hdlc_disabled = session_info->hdlc_disabled;
 		else
 			hdlc_disabled = driver->hdlc_disabled;
+		mutex_unlock(&driver->md_session_lock);
 		if (!hdlc_disabled)
 			diag_process_hdlc_pkt((void *)
 				(driver->user_space_data_buf),
-				len, session_info);
+				len, current->tgid);
 		else
 			diag_process_non_hdlc_pkt((char *)
 						(driver->user_space_data_buf),
-						len, session_info);
+						len, current->tgid);
 		return 0;
 	}
 
@@ -3102,11 +3108,13 @@
 
 	mutex_lock(&apps_data_mutex);
 	mutex_lock(&driver->hdlc_disable_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled)
 		ret = diag_process_apps_data_non_hdlc(user_space_data, len,
 						      pkt_type);
@@ -3177,9 +3185,9 @@
 		ret += sizeof(int);
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		exit_stat = diag_md_copy_to_user(buf, &ret, count,
 						 session_info);
+		mutex_unlock(&driver->md_session_lock);
 		goto exit;
 	} else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
 		/* In case, the thread wakes up and the logging mode is not
@@ -3199,14 +3207,16 @@
 
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		if (session_info) {
 			COPY_USER_SPACE_OR_ERR(buf+4,
 					session_info->hdlc_disabled,
 					sizeof(uint8_t));
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		}
+		mutex_unlock(&driver->md_session_lock);
 		goto exit;
 	}
 
@@ -3226,12 +3236,16 @@
 	if (driver->data_ready[index] & MSG_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
+		}
 		write_len = diag_copy_to_user_msg_mask(buf + ret, count,
 						       session_info);
+		mutex_unlock(&driver->md_session_lock);
 		if (write_len > 0)
 			ret += write_len;
 		driver->data_ready[index] ^= MSG_MASKS_TYPE;
@@ -3242,25 +3256,32 @@
 	if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
-
+		}
 		if (session_info && session_info->event_mask &&
 		    session_info->event_mask->ptr) {
 			COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
 					*(session_info->event_mask->ptr),
 					session_info->event_mask->mask_len);
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		} else {
 			COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
 						*(event_mask.ptr),
 						event_mask.mask_len);
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		}
+		mutex_unlock(&driver->md_session_lock);
 		driver->data_ready[index] ^= EVENT_MASKS_TYPE;
 		atomic_dec(&driver->data_ready_notif[index]);
 		goto exit;
@@ -3269,13 +3290,17 @@
 	if (driver->data_ready[index] & LOG_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
+		}
 
 		write_len = diag_copy_to_user_log_mask(buf + ret, count,
 						       session_info);
+		mutex_unlock(&driver->md_session_lock);
 		if (write_len > 0)
 			ret += write_len;
 		driver->data_ready[index] ^= LOG_MASKS_TYPE;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 1155087..33048e1 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -242,7 +242,7 @@
 }
 
 static void pack_rsp_and_send(unsigned char *buf, int len,
-				struct diag_md_session_t *info)
+				int pid)
 {
 	int err;
 	int retry_count = 0, i, rsp_ctxt;
@@ -250,6 +250,7 @@
 	unsigned long flags;
 	unsigned char *rsp_ptr = driver->encoded_rsp_buf;
 	struct diag_pkt_frame_t header;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 
 	if (!rsp_ptr || !buf)
 		return;
@@ -260,6 +261,11 @@
 		return;
 	}
 
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(pid);
+	info = (session_info) ? session_info :
+				diag_md_session_get_peripheral(APPS_DATA);
+
 	/*
 	 * Explicitly check for the Peripheral Modem here
 	 * is necessary till a way to identify a peripheral
@@ -279,6 +285,7 @@
 		}
 	} else
 		rsp_ctxt = driver->rsp_buf_ctxt;
+	mutex_unlock(&driver->md_session_lock);
 
 	/*
 	 * Keep trying till we get the buffer back. It should probably
@@ -302,8 +309,11 @@
 		 * draining responses when we are in Memory Device Mode.
 		 */
 		if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
-				driver->logging_mode == DIAG_MULTI_MODE)
+				driver->logging_mode == DIAG_MULTI_MODE) {
+			mutex_lock(&driver->md_session_lock);
 			chk_logging_wakeup();
+			mutex_unlock(&driver->md_session_lock);
+		}
 	}
 	if (driver->rsp_buf_busy) {
 		pr_err("diag: unable to get hold of response buffer\n");
@@ -332,13 +342,14 @@
 }
 
 static void encode_rsp_and_send(unsigned char *buf, int len,
-				struct diag_md_session_t *info)
+				int pid)
 {
 	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 	unsigned char *rsp_ptr = driver->encoded_rsp_buf;
 	int err, i, rsp_ctxt, retry_count = 0;
 	unsigned long flags;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 
 	if (!rsp_ptr || !buf)
 		return;
@@ -349,6 +360,11 @@
 		return;
 	}
 
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(pid);
+	info = (session_info) ? session_info :
+				diag_md_session_get_peripheral(APPS_DATA);
+
 	/*
 	 * Explicitly check for the Peripheral Modem here
 	 * is necessary till a way to identify a peripheral
@@ -368,7 +384,7 @@
 		}
 	} else
 		rsp_ctxt = driver->rsp_buf_ctxt;
-
+	mutex_unlock(&driver->md_session_lock);
 	/*
 	 * Keep trying till we get the buffer back. It should probably
 	 * take one or two iterations. When this loops till UINT_MAX, it
@@ -391,8 +407,11 @@
 		 * draining responses when we are in Memory Device Mode.
 		 */
 		if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
-				driver->logging_mode == DIAG_MULTI_MODE)
+				driver->logging_mode == DIAG_MULTI_MODE) {
+			mutex_lock(&driver->md_session_lock);
 			chk_logging_wakeup();
+			mutex_unlock(&driver->md_session_lock);
+		}
 	}
 
 	if (driver->rsp_buf_busy) {
@@ -424,22 +443,23 @@
 }
 
 static void diag_send_rsp(unsigned char *buf, int len,
-	struct diag_md_session_t *info)
+	int pid)
 {
-	struct diag_md_session_t *session_info = NULL;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 	uint8_t hdlc_disabled;
-
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	session_info = (info) ? info :
 				diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled)
-		pack_rsp_and_send(buf, len, session_info);
+		pack_rsp_and_send(buf, len, pid);
 	else
-		encode_rsp_and_send(buf, len, session_info);
+		encode_rsp_and_send(buf, len, pid);
 }
 
 void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type)
@@ -506,13 +526,14 @@
 	int i, j;
 
 	mutex_lock(&driver->diagchar_mutex);
+	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] != NULL)
 			for (j = 0; j < driver->num_clients; j++) {
 				if (driver->client_map[j].pid != 0 &&
 					driver->client_map[j].pid ==
 					driver->md_session_map[i]->pid) {
-					if (!(driver->data_ready[i] & type)) {
+					if (!(driver->data_ready[j] & type)) {
 						driver->data_ready[j] |= type;
 						atomic_inc(
 						&driver->data_ready_notif[j]);
@@ -521,6 +542,7 @@
 				}
 			}
 	}
+	mutex_unlock(&driver->md_session_lock);
 	wake_up_interruptible(&driver->wait_q);
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -982,7 +1004,7 @@
 }
 
 void diag_send_error_rsp(unsigned char *buf, int len,
-			struct diag_md_session_t *info)
+			int pid)
 {
 	/* -1 to accommodate the first byte 0x13 */
 	if (len > (DIAG_MAX_RSP_SIZE - 1)) {
@@ -992,13 +1014,12 @@
 
 	*(uint8_t *)driver->apps_rsp_buf = DIAG_CMD_ERROR;
 	memcpy((driver->apps_rsp_buf + sizeof(uint8_t)), buf, len);
-	diag_send_rsp(driver->apps_rsp_buf, len + 1, info);
+	diag_send_rsp(driver->apps_rsp_buf, len + 1, pid);
 }
 
-int diag_process_apps_pkt(unsigned char *buf, int len,
-			struct diag_md_session_t *info)
+int diag_process_apps_pkt(unsigned char *buf, int len, int pid)
 {
-	int i;
+	int i, p_mask = 0;
 	int mask_ret;
 	int write_len = 0;
 	unsigned char *temp = NULL;
@@ -1007,14 +1028,15 @@
 	struct diag_cmd_reg_t *reg_item = NULL;
 	struct diagfwd_info *fwd_info = NULL;
 	uint32_t pd_mask = 0;
+	struct diag_md_session_t *info = NULL;
 
 	if (!buf)
 		return -EIO;
 
 	/* Check if the command is a supported mask command */
-	mask_ret = diag_process_apps_masks(buf, len, info);
+	mask_ret = diag_process_apps_masks(buf, len, pid);
 	if (mask_ret > 0) {
-		diag_send_rsp(driver->apps_rsp_buf, mask_ret, info);
+		diag_send_rsp(driver->apps_rsp_buf, mask_ret, pid);
 		return 0;
 	}
 
@@ -1036,7 +1058,7 @@
 						   driver->apps_rsp_buf,
 						   DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 
@@ -1045,18 +1067,22 @@
 	if (temp_entry) {
 		reg_item = container_of(temp_entry, struct diag_cmd_reg_t,
 					entry);
+		mutex_lock(&driver->md_session_lock);
+		info = diag_md_session_get_pid(pid);
 		if (info) {
+			p_mask = info->peripheral_mask;
+			mutex_unlock(&driver->md_session_lock);
 			MD_PERIPHERAL_PD_MASK(TYPE_CMD, reg_item->proc,
 				pd_mask);
 			if ((MD_PERIPHERAL_MASK(reg_item->proc) &
-				info->peripheral_mask) ||
-				(pd_mask & info->peripheral_mask))
+				p_mask) || (pd_mask & p_mask))
 				write_len = diag_send_data(reg_item, buf, len);
 		} else {
+			mutex_unlock(&driver->md_session_lock);
 			if (MD_PERIPHERAL_MASK(reg_item->proc) &
 				driver->logging_mask) {
 				mutex_unlock(&driver->cmd_reg_mutex);
-				diag_send_error_rsp(buf, len, info);
+				diag_send_error_rsp(buf, len, pid);
 				return write_len;
 			}
 			else
@@ -1074,13 +1100,13 @@
 		for (i = 0; i < 4; i++)
 			*(driver->apps_rsp_buf+i) = *(buf+i);
 		*(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE;
-		diag_send_rsp(driver->apps_rsp_buf, 8, info);
+		diag_send_rsp(driver->apps_rsp_buf, 8, pid);
 		return 0;
 	} else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
 		(*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
 		len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
 		if (len > 0) {
-			diag_send_rsp(driver->apps_rsp_buf, len, info);
+			diag_send_rsp(driver->apps_rsp_buf, len, pid);
 			return 0;
 		}
 		return len;
@@ -1093,7 +1119,7 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for time sync switch command */
@@ -1104,7 +1130,7 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for diag id command */
@@ -1115,14 +1141,14 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for download command */
 	else if ((chk_apps_master()) && (*buf == 0x3A)) {
 		/* send response back */
 		driver->apps_rsp_buf[0] = *buf;
-		diag_send_rsp(driver->apps_rsp_buf, 1, info);
+		diag_send_rsp(driver->apps_rsp_buf, 1, pid);
 		msleep(5000);
 		/* call download API */
 		msm_set_restart_mode(RESTART_DLOAD);
@@ -1142,7 +1168,7 @@
 			for (i = 0; i < 13; i++)
 				driver->apps_rsp_buf[i+3] = 0;
 
-			diag_send_rsp(driver->apps_rsp_buf, 16, info);
+			diag_send_rsp(driver->apps_rsp_buf, 16, pid);
 			return 0;
 		}
 	}
@@ -1151,7 +1177,7 @@
 		(*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
 		memcpy(driver->apps_rsp_buf, buf, 4);
 		driver->apps_rsp_buf[4] = wrap_enabled;
-		diag_send_rsp(driver->apps_rsp_buf, 5, info);
+		diag_send_rsp(driver->apps_rsp_buf, 5, pid);
 		return 0;
 	}
 	/* Wrap the Delayed Rsp ID */
@@ -1160,7 +1186,7 @@
 		wrap_enabled = true;
 		memcpy(driver->apps_rsp_buf, buf, 4);
 		driver->apps_rsp_buf[4] = wrap_count;
-		diag_send_rsp(driver->apps_rsp_buf, 6, info);
+		diag_send_rsp(driver->apps_rsp_buf, 6, pid);
 		return 0;
 	}
 	/* Mobile ID Rsp */
@@ -1171,7 +1197,7 @@
 						   driver->apps_rsp_buf,
 						   DIAG_MAX_RSP_SIZE);
 		if (write_len > 0) {
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 			return 0;
 		}
 	}
@@ -1191,7 +1217,7 @@
 			for (i = 0; i < 55; i++)
 				driver->apps_rsp_buf[i] = 0;
 
-			diag_send_rsp(driver->apps_rsp_buf, 55, info);
+			diag_send_rsp(driver->apps_rsp_buf, 55, pid);
 			return 0;
 		}
 		/* respond to 0x7c command */
@@ -1204,14 +1230,14 @@
 							 chk_config_get_id();
 			*(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
 			*(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
-			diag_send_rsp(driver->apps_rsp_buf, 14, info);
+			diag_send_rsp(driver->apps_rsp_buf, 14, pid);
 			return 0;
 		}
 	}
 	write_len = diag_cmd_chk_stats(buf, len, driver->apps_rsp_buf,
 				       DIAG_MAX_RSP_SIZE);
 	if (write_len > 0) {
-		diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+		diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	write_len = diag_cmd_disable_hdlc(buf, len, driver->apps_rsp_buf,
@@ -1223,7 +1249,7 @@
 		 * before disabling HDLC encoding on Apps processor.
 		 */
 		mutex_lock(&driver->hdlc_disable_mutex);
-		diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+		diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		/*
 		 * Set the value of hdlc_disabled after sending the response to
 		 * the tools. This is required since the tools is expecting a
@@ -1231,10 +1257,13 @@
 		 */
 		pr_debug("diag: In %s, disabling HDLC encoding\n",
 		       __func__);
+		mutex_lock(&driver->md_session_lock);
+		info = diag_md_session_get_pid(pid);
 		if (info)
 			info->hdlc_disabled = 1;
 		else
 			driver->hdlc_disabled = 1;
+		mutex_unlock(&driver->md_session_lock);
 		diag_update_md_clients(HDLC_SUPPORT_TYPE);
 		mutex_unlock(&driver->hdlc_disable_mutex);
 		return 0;
@@ -1243,13 +1272,12 @@
 
 	/* We have now come to the end of the function. */
 	if (chk_apps_only())
-		diag_send_error_rsp(buf, len, info);
+		diag_send_error_rsp(buf, len, pid);
 
 	return 0;
 }
 
-void diag_process_hdlc_pkt(void *data, unsigned int len,
-			   struct diag_md_session_t *info)
+void diag_process_hdlc_pkt(void *data, unsigned int len, int pid)
 {
 	int err = 0;
 	int ret = 0;
@@ -1309,7 +1337,7 @@
 		}
 
 		err = diag_process_apps_pkt(driver->hdlc_buf,
-					    driver->hdlc_buf_len, info);
+					    driver->hdlc_buf_len, pid);
 		if (err < 0)
 			goto fail;
 	} else {
@@ -1326,7 +1354,7 @@
 	 * recovery algorithm. Send an error response if the
 	 * packet is not in expected format.
 	 */
-	diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, info);
+	diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, pid);
 	driver->hdlc_buf_len = 0;
 end:
 	mutex_unlock(&driver->diag_hdlc_mutex);
@@ -1423,9 +1451,11 @@
 
 static uint8_t hdlc_reset;
 
-static void hdlc_reset_timer_start(struct diag_md_session_t *info)
+static void hdlc_reset_timer_start(int pid)
 {
+	struct diag_md_session_t *info = NULL;
 	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	if (!hdlc_timer_in_progress) {
 		hdlc_timer_in_progress = 1;
 		if (info)
@@ -1467,15 +1497,16 @@
 }
 
 static void diag_hdlc_start_recovery(unsigned char *buf, int len,
-				     struct diag_md_session_t *info)
+				     int pid)
 {
 	int i;
 	static uint32_t bad_byte_counter;
 	unsigned char *start_ptr = NULL;
 	struct diag_pkt_frame_t *actual_pkt = NULL;
+	struct diag_md_session_t *info = NULL;
 
 	hdlc_reset = 1;
-	hdlc_reset_timer_start(info);
+	hdlc_reset_timer_start(pid);
 
 	actual_pkt = (struct diag_pkt_frame_t *)buf;
 	for (i = 0; i < len; i++) {
@@ -1495,10 +1526,13 @@
 			pr_err("diag: In %s, re-enabling HDLC encoding\n",
 					__func__);
 			mutex_lock(&driver->hdlc_disable_mutex);
+			mutex_lock(&driver->md_session_lock);
+			info = diag_md_session_get_pid(pid);
 			if (info)
 				info->hdlc_disabled = 0;
 			else
 				driver->hdlc_disabled = 0;
+			mutex_unlock(&driver->md_session_lock);
 			mutex_unlock(&driver->hdlc_disable_mutex);
 			diag_update_md_clients(HDLC_SUPPORT_TYPE);
 
@@ -1511,12 +1545,11 @@
 		mutex_lock(&driver->hdlc_recovery_mutex);
 		driver->incoming_pkt.processing = 0;
 		mutex_unlock(&driver->hdlc_recovery_mutex);
-		diag_process_non_hdlc_pkt(start_ptr, len - i, info);
+		diag_process_non_hdlc_pkt(start_ptr, len - i, pid);
 	}
 }
 
-void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
-			       struct diag_md_session_t *info)
+void diag_process_non_hdlc_pkt(unsigned char *buf, int len, int pid)
 {
 	int err = 0;
 	uint16_t pkt_len = 0;
@@ -1572,11 +1605,11 @@
 		if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
 						CONTROL_CHAR) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			mutex_lock(&driver->hdlc_recovery_mutex);
 		}
 		err = diag_process_apps_pkt(data_ptr,
-					    actual_pkt->length, info);
+					    actual_pkt->length, pid);
 		if (err) {
 			pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
 			       __func__, err);
@@ -1598,8 +1631,8 @@
 		pkt_len = actual_pkt->length;
 
 		if (actual_pkt->start != CONTROL_CHAR) {
-			diag_hdlc_start_recovery(buf, len, info);
-			diag_send_error_rsp(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
+			diag_send_error_rsp(buf, len, pid);
 			goto end;
 		}
 		mutex_lock(&driver->hdlc_recovery_mutex);
@@ -1607,7 +1640,7 @@
 			pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
 			       __func__, pkt_len);
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			break;
 		}
 		if ((pkt_len + header_len) > (len - read_bytes)) {
@@ -1624,13 +1657,13 @@
 		if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
 						CONTROL_CHAR) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			mutex_lock(&driver->hdlc_recovery_mutex);
 		}
 		else
 			hdlc_reset = 0;
 		err = diag_process_apps_pkt(data_ptr,
-					    actual_pkt->length, info);
+					    actual_pkt->length, pid);
 		if (err) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
 			break;
@@ -1649,9 +1682,9 @@
 		return -EINVAL;
 
 	if (!driver->hdlc_disabled)
-		diag_process_hdlc_pkt(buf, len, NULL);
+		diag_process_hdlc_pkt(buf, len, 0);
 	else
-		diag_process_non_hdlc_pkt(buf, len, NULL);
+		diag_process_non_hdlc_pkt(buf, len, 0);
 
 	diag_mux_queue_read(ctxt);
 	return 0;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 0e0bf2d..687aeb7 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -30,10 +30,8 @@
 
 int diagfwd_init(void);
 void diagfwd_exit(void);
-void diag_process_hdlc_pkt(void *data, unsigned int len,
-			   struct diag_md_session_t *info);
-void diag_process_non_hdlc_pkt(unsigned char *data, int len,
-			       struct diag_md_session_t *info);
+void diag_process_hdlc_pkt(void *data, unsigned int len, int pid);
+void diag_process_non_hdlc_pkt(unsigned char *data, int len, int pid);
 int chk_config_get_id(void);
 int chk_apps_only(void);
 int chk_apps_master(void);
@@ -45,10 +43,8 @@
 int diag_check_common_cmd(struct diag_pkt_header_t *header);
 void diag_update_userspace_clients(unsigned int type);
 void diag_update_sleeping_process(int process_id, int data_type);
-int diag_process_apps_pkt(unsigned char *buf, int len,
-			  struct diag_md_session_t *info);
-void diag_send_error_rsp(unsigned char *buf, int len,
-			 struct diag_md_session_t *info);
+int diag_process_apps_pkt(unsigned char *buf, int len, int pid);
+void diag_send_error_rsp(unsigned char *buf, int len, int pid);
 void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type);
 int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf);
 void diag_md_hdlc_reset_timer_func(unsigned long pid);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 162d53f..8d47ee38 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -333,8 +333,13 @@
 		if (!(driver->close_transport & PERIPHERAL_MASK(peripheral)))
 			continue;
 		driver->close_transport ^= PERIPHERAL_MASK(peripheral);
+#ifdef CONFIG_DIAG_USES_SMD
+		transport = driver->feature[peripheral].sockets_enabled ?
+					TRANSPORT_SMD : TRANSPORT_SOCKET;
+#else
 		transport = driver->feature[peripheral].sockets_enabled ?
 					TRANSPORT_GLINK : TRANSPORT_SOCKET;
+#endif
 		diagfwd_close_transport(transport, peripheral);
 	}
 	mutex_unlock(&driver->cntl_lock);
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index e9683e0..59e45a7 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -257,7 +257,8 @@
 static void diag_state_open_glink(void *ctxt);
 static void diag_state_close_glink(void *ctxt);
 static int diag_glink_write(void *ctxt, unsigned char *buf, int len);
-static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len);
+static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf);
 static void diag_glink_queue_read(void *ctxt);
 
 static struct diag_peripheral_ops glink_ops = {
@@ -320,7 +321,8 @@
 	return (int)(atomic_read(&info->diag_state));
 }
 
-static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len)
+static int diag_glink_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf)
 {
 	struct diag_glink_info *glink_info =  NULL;
 	int ret_val = 0;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index c7bd2205..f53d9d5 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -26,6 +26,7 @@
 #include "diag_masks.h"
 #include "diag_dci.h"
 #include "diagfwd.h"
+#include "diagfwd_smd.h"
 #include "diagfwd_socket.h"
 #include "diag_mux.h"
 #include "diag_ipc_logging.h"
@@ -343,14 +344,13 @@
 		diag_ws_release();
 		return;
 	}
-
-	session_info =
-		diag_md_session_get_peripheral(peripheral);
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_peripheral(peripheral);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled) {
 		/* The data is raw and and on APPS side HDLC is disabled */
 		if (!buf) {
@@ -633,12 +633,13 @@
 
 	mutex_lock(&driver->hdlc_disable_mutex);
 	mutex_lock(&fwd_info->data_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
 		if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
 			temp_buf = fwd_info->buf_1;
@@ -905,6 +906,8 @@
 			&peripheral_info[TYPE_DCI_CMD][peripheral];
 	}
 
+	_diag_smd_init();
+
 	if (driver->supports_sockets)
 		diag_socket_init();
 	diag_glink_init();
@@ -919,6 +922,8 @@
 	struct diagfwd_info *fwd_info = NULL;
 	int transport = 0;
 
+	_diag_smd_exit();
+
 	diag_socket_exit();
 
 	for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
@@ -1049,6 +1054,74 @@
 	}
 }
 
+#ifdef CONFIG_DIAG_USES_SMD
+void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
+{
+	struct diagfwd_info *fwd_info = NULL;
+	struct diagfwd_info *dest_info = NULL;
+	int (*init_fn)(uint8_t) = NULL;
+	void (*invalidate_fn)(void *, struct diagfwd_info *) = NULL;
+	int (*check_channel_state)(void *) = NULL;
+	uint8_t transport_open = 0;
+	int i = 0;
+
+	if (peripheral >= NUM_PERIPHERALS)
+		return;
+
+	switch (transport) {
+	case TRANSPORT_SMD:
+		transport_open = TRANSPORT_SOCKET;
+		init_fn = diag_socket_init_peripheral;
+		invalidate_fn = diag_socket_invalidate;
+		check_channel_state = diag_socket_check_state;
+		break;
+	case TRANSPORT_SOCKET:
+		if (peripheral == PERIPHERAL_WDSP) {
+		transport_open = TRANSPORT_GLINK;
+		init_fn = diag_glink_init_peripheral;
+		invalidate_fn = diag_glink_invalidate;
+		check_channel_state = diag_glink_check_state;
+		} else {
+			transport_open = TRANSPORT_SMD;
+			init_fn = diag_smd_init_peripheral;
+			invalidate_fn = diag_smd_invalidate;
+			check_channel_state = diag_smd_check_state;
+		}
+		break;
+	default:
+		return;
+
+	}
+
+	mutex_lock(&driver->diagfwd_channel_mutex[peripheral]);
+	fwd_info = &early_init_info[transport][peripheral];
+	if (fwd_info->p_ops && fwd_info->p_ops->close)
+		fwd_info->p_ops->close(fwd_info->ctxt);
+	fwd_info = &early_init_info[transport_open][peripheral];
+	dest_info = &peripheral_info[TYPE_CNTL][peripheral];
+	dest_info->inited = 1;
+	dest_info->ctxt = fwd_info->ctxt;
+	dest_info->p_ops = fwd_info->p_ops;
+	dest_info->c_ops = fwd_info->c_ops;
+	dest_info->ch_open = fwd_info->ch_open;
+	dest_info->read_bytes = fwd_info->read_bytes;
+	dest_info->write_bytes = fwd_info->write_bytes;
+	dest_info->inited = fwd_info->inited;
+	dest_info->buf_1 = fwd_info->buf_1;
+	dest_info->buf_2 = fwd_info->buf_2;
+	dest_info->transport = fwd_info->transport;
+	invalidate_fn(dest_info->ctxt, dest_info);
+	for (i = 0; i < NUM_WRITE_BUFFERS; i++)
+		dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
+	if (!check_channel_state(dest_info->ctxt))
+		diagfwd_late_open(dest_info);
+	diagfwd_cntl_open(dest_info);
+	init_fn(peripheral);
+	mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
+	diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
+	diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
+}
+#else
 void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
 {
 	struct diagfwd_info *fwd_info = NULL;
@@ -1108,6 +1181,7 @@
 	diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
 	diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
 }
+#endif
 
 void *diagfwd_request_write_buf(struct diagfwd_info *fwd_info)
 {
@@ -1212,11 +1286,10 @@
 	 * Logging mode here is reflecting previous mode
 	 * status and will be updated to new mode later.
 	 *
-	 * Keeping the buffers busy for Memory Device Mode.
+	 * Keeping the buffers busy for Memory Device and Multi Mode.
 	 */
 
-	if ((driver->logging_mode != DIAG_USB_MODE) ||
-		driver->usb_connected) {
+	if (driver->logging_mode != DIAG_USB_MODE) {
 		if (fwd_info->buf_1) {
 			atomic_set(&fwd_info->buf_1->in_busy, 0);
 			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -1627,7 +1700,8 @@
 
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "issued a read p: %d t: %d buf: %pK\n",
 		 fwd_info->peripheral, fwd_info->type, read_buf);
-	err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len);
+	err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len,
+			temp_buf);
 	if (err)
 		goto fail_return;
 
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 6ddce32..d8e0b68 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,9 +18,16 @@
 #define MAX_PERIPHERAL_HDLC_BUF_SZ	65539
 
 #define TRANSPORT_UNKNOWN		-1
+#ifdef CONFIG_DIAG_USES_SMD
+#define TRANSPORT_SMD			0
+#define TRANSPORT_SOCKET		1
+#define TRANSPORT_GLINK			2
+#define NUM_TRANSPORT			3
+#else
 #define TRANSPORT_SOCKET		0
 #define TRANSPORT_GLINK			1
 #define NUM_TRANSPORT			2
+#endif
 #define NUM_WRITE_BUFFERS		2
 #define PERIPHERAL_MASK(x)					\
 	((x == PERIPHERAL_MODEM) ? DIAG_CON_MPSS :		\
@@ -58,7 +65,8 @@
 	void (*open)(void *ctxt);
 	void (*close)(void *ctxt);
 	int (*write)(void *ctxt, unsigned char *buf, int len);
-	int (*read)(void *ctxt, unsigned char *buf, int len);
+	int (*read)(void *ctxt, unsigned char *buf, int len,
+			struct diagfwd_buf_t *fwd_buf);
 	void (*queue_read)(void *ctxt);
 };
 
diff --git a/drivers/char/diag/diagfwd_smd.c b/drivers/char/diag/diagfwd_smd.c
new file mode 100644
index 0000000..d530204
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smd.c
@@ -0,0 +1,933 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/diagchar.h>
+#include <linux/of.h>
+#include <linux/kmemleak.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_peripheral.h"
+#include "diagfwd_smd.h"
+#include "diag_ipc_logging.h"
+
+struct diag_smd_info smd_data[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DATA,
+		.name = "MODEM_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DATA,
+		.name = "LPASS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DATA,
+		.name = "WCNSS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DATA,
+		.name = "SENSORS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DATA,
+		.name = "DIAG_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DATA,
+		.name = "CDSP_DATA"
+	}
+};
+
+struct diag_smd_info smd_cntl[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_CNTL,
+		.name = "MODEM_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_CNTL,
+		.name = "LPASS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_CNTL,
+		.name = "WCNSS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_CNTL,
+		.name = "SENSORS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_CNTL,
+		.name = "DIAG_CTRL"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_CNTL,
+		.name = "CDSP_CNTL"
+	}
+};
+
+struct diag_smd_info smd_dci[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DCI,
+		.name = "MODEM_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DCI,
+		.name = "LPASS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DCI,
+		.name = "WCNSS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DCI,
+		.name = "SENSORS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DCI,
+		.name = "DIAG_DCI_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DCI,
+		.name = "CDSP_DCI"
+	}
+};
+
+struct diag_smd_info smd_cmd[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_CMD,
+		.name = "MODEM_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_CMD,
+		.name = "LPASS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_CMD,
+		.name = "WCNSS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_CMD,
+		.name = "SENSORS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_CMD,
+		.name = "DIAG_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_CMD,
+		.name = "CDSP_CMD"
+	}
+};
+
+struct diag_smd_info smd_dci_cmd[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DCI_CMD,
+		.name = "MODEM_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DCI_CMD,
+		.name = "LPASS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DCI_CMD,
+		.name = "WCNSS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DCI_CMD,
+		.name = "SENSORS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DCI_CMD,
+		.name = "DIAG_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DCI_CMD,
+		.name = "CDSP_DCI_CMD"
+	}
+};
+
+static void diag_state_open_smd(void *ctxt);
+static void diag_state_close_smd(void *ctxt);
+static void smd_notify(void *ctxt, unsigned int event);
+static int diag_smd_write(void *ctxt, unsigned char *buf, int len);
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf);
+static void diag_smd_queue_read(void *ctxt);
+
+static struct diag_peripheral_ops smd_ops = {
+	.open = diag_state_open_smd,
+	.close = diag_state_close_smd,
+	.write = diag_smd_write,
+	.read = diag_smd_read,
+	.queue_read = diag_smd_queue_read
+};
+
+static void diag_state_open_smd(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)(ctxt);
+	atomic_set(&smd_info->diag_state, 1);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s setting diag state to 1", smd_info->name);
+}
+
+static void diag_state_close_smd(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)(ctxt);
+	atomic_set(&smd_info->diag_state, 0);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s setting diag state to 0", smd_info->name);
+	wake_up_interruptible(&smd_info->read_wait_q);
+	flush_workqueue(smd_info->wq);
+}
+
+static int smd_channel_probe(struct platform_device *pdev, uint8_t type)
+{
+	int r = 0;
+	int index = -1;
+	const char *channel_name = NULL;
+	struct diag_smd_info *smd_info = NULL;
+
+	switch (pdev->id) {
+	case SMD_APPS_MODEM:
+		index = PERIPHERAL_MODEM;
+		break;
+	case SMD_APPS_QDSP:
+		index = PERIPHERAL_LPASS;
+		break;
+	case SMD_APPS_WCNSS:
+		index = PERIPHERAL_WCNSS;
+		break;
+	case SMD_APPS_DSPS:
+		index = PERIPHERAL_SENSORS;
+		break;
+	default:
+		pr_debug("diag: In %s Received probe for invalid index %d",
+			__func__, pdev->id);
+		return -EINVAL;
+	}
+
+	switch (type) {
+	case TYPE_DATA:
+		smd_info = &smd_data[index];
+		channel_name = "DIAG";
+		break;
+	case TYPE_CNTL:
+		smd_info = &smd_cntl[index];
+		channel_name = "DIAG_CNTL";
+		break;
+	case TYPE_CMD:
+		smd_info = &smd_cmd[index];
+		channel_name = "DIAG_CMD";
+		break;
+	case TYPE_DCI:
+		smd_info = &smd_dci[index];
+		channel_name = "DIAG_2";
+		break;
+	case TYPE_DCI_CMD:
+		smd_info = &smd_dci_cmd[index];
+		channel_name = "DIAG_2_CMD";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (index == PERIPHERAL_WCNSS && type == TYPE_DATA)
+		channel_name = "APPS_RIVA_DATA";
+	else if (index == PERIPHERAL_WCNSS && type == TYPE_CNTL)
+		channel_name = "APPS_RIVA_CTRL";
+
+	if (!channel_name || !smd_info)
+		return -EIO;
+
+	r = smd_named_open_on_edge(channel_name, pdev->id, &smd_info->hdl,
+				   smd_info, smd_notify);
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pr_debug("diag: In %s, SMD port probed %s, id = %d, r = %d\n",
+		 __func__, smd_info->name, pdev->id, r);
+
+	return 0;
+}
+
+static int smd_data_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DATA);
+}
+
+static int smd_cntl_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_CNTL);
+}
+
+static int smd_cmd_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_CMD);
+}
+
+static int smd_dci_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DCI);
+}
+
+static int smd_dci_cmd_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DCI_CMD);
+}
+
+static int smd_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int smd_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops smd_dev_pm_ops = {
+	.runtime_suspend = smd_runtime_suspend,
+	.runtime_resume = smd_runtime_resume,
+};
+
+static struct platform_driver diag_smd_ch_driver = {
+	.probe = smd_data_probe,
+	.driver = {
+		.name = "DIAG",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_driver = {
+	.probe = smd_data_probe,
+	.driver = {
+		.name = "APPS_RIVA_DATA",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_cntl_driver = {
+	.probe = smd_cntl_probe,
+	.driver = {
+		.name = "DIAG_CNTL",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_cntl_driver = {
+	.probe = smd_cntl_probe,
+	.driver = {
+		.name = "APPS_RIVA_CTRL",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_cmd_driver = {
+	.probe = smd_cmd_probe,
+	.driver = {
+		.name = "DIAG_CMD",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	}
+};
+
+static struct platform_driver diag_smd_dci_driver = {
+	.probe = smd_dci_probe,
+	.driver = {
+		.name = "DIAG_2",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_dci_cmd_driver = {
+	.probe = smd_dci_cmd_probe,
+	.driver = {
+		.name = "DIAG_2_CMD",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static void smd_open_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      open_work);
+	if (!smd_info->inited)
+		return;
+
+	diagfwd_channel_open(smd_info->fwd_ctxt);
+	diagfwd_late_open(smd_info->fwd_ctxt);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+static void smd_close_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      close_work);
+	if (!smd_info->inited)
+		return;
+
+	diagfwd_channel_close(smd_info->fwd_ctxt);
+	wake_up_interruptible(&smd_info->read_wait_q);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+static void smd_read_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      read_work);
+	if (!smd_info->inited) {
+		diag_ws_release();
+		return;
+	}
+
+	diagfwd_channel_read(smd_info->fwd_ctxt);
+}
+
+static void diag_smd_late_init_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+							struct diag_smd_info,
+							late_init_work);
+	if (!smd_info || !smd_info->hdl)
+		return;
+	diagfwd_channel_open(smd_info->fwd_ctxt);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "smd late init p: %d t: %d\n",
+			smd_info->peripheral, smd_info->type);
+}
+
+static void diag_smd_queue_read(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (smd_info->inited && atomic_read(&smd_info->opened) &&
+	    smd_info->hdl) {
+		wake_up_interruptible(&smd_info->read_wait_q);
+		queue_work(smd_info->wq, &(smd_info->read_work));
+	}
+}
+int diag_smd_check_state(void *ctxt)
+{
+	struct diag_smd_info *info = NULL;
+
+	if (!ctxt)
+		return 0;
+
+	info = (struct diag_smd_info *)ctxt;
+	return (int)(atomic_read(&info->diag_state));
+}
+void diag_smd_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+	void *prev = NULL;
+
+	if (!ctxt || !fwd_ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	prev = smd_info->fwd_ctxt;
+	smd_info->fwd_ctxt = fwd_ctxt;
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s prev: %pK fwd_ctxt: %pK\n",
+		 smd_info->name, prev, smd_info->fwd_ctxt);
+}
+
+static void __diag_smd_init(struct diag_smd_info *smd_info)
+{
+	char wq_name[DIAG_SMD_NAME_SZ + 10];
+
+	if (!smd_info)
+		return;
+
+	init_waitqueue_head(&smd_info->read_wait_q);
+	mutex_init(&smd_info->lock);
+	strlcpy(wq_name, "DIAG_SMD_", 10);
+	strlcat(wq_name, smd_info->name, sizeof(smd_info->name));
+	smd_info->wq = create_singlethread_workqueue(wq_name);
+	if (!smd_info->wq) {
+		pr_err("diag: In %s, unable to create workqueue for smd channel %s\n",
+		       __func__, smd_info->name);
+		return;
+	}
+	INIT_WORK(&(smd_info->open_work), smd_open_work_fn);
+	INIT_WORK(&(smd_info->close_work), smd_close_work_fn);
+	INIT_WORK(&(smd_info->read_work), smd_read_work_fn);
+	INIT_WORK(&(smd_info->late_init_work), diag_smd_late_init_work_fn);
+	smd_info->fifo_size = 0;
+	smd_info->hdl = NULL;
+	smd_info->fwd_ctxt = NULL;
+	atomic_set(&smd_info->opened, 0);
+	atomic_set(&smd_info->diag_state, 0);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s initialized fwd_ctxt: %pK\n",
+		 smd_info->name, smd_info->fwd_ctxt);
+}
+
+int diag_smd_init(void)
+{
+	uint8_t peripheral;
+	struct diag_smd_info *smd_info = NULL;
+
+	for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
+		if (peripheral == PERIPHERAL_WDSP)
+			continue;
+		smd_info = &smd_cntl[peripheral];
+		__diag_smd_init(smd_info);
+		diagfwd_cntl_register(TRANSPORT_SMD, smd_info->peripheral,
+				      (void *)smd_info, &smd_ops,
+				      &smd_info->fwd_ctxt);
+		smd_info->inited = 1;
+		__diag_smd_init(&smd_data[peripheral]);
+		__diag_smd_init(&smd_cmd[peripheral]);
+		__diag_smd_init(&smd_dci[peripheral]);
+		__diag_smd_init(&smd_dci_cmd[peripheral]);
+	}
+
+	platform_driver_register(&diag_smd_cntl_driver);
+	platform_driver_register(&diag_smd_lite_cntl_driver);
+	platform_driver_register(&diag_smd_ch_driver);
+	platform_driver_register(&diag_smd_lite_driver);
+	platform_driver_register(&diag_smd_lite_cmd_driver);
+	platform_driver_register(&diag_smd_dci_driver);
+	platform_driver_register(&diag_smd_dci_cmd_driver);
+
+	return 0;
+}
+
+static void smd_late_init(struct diag_smd_info *smd_info)
+{
+	struct diagfwd_info *fwd_info = NULL;
+
+	if (!smd_info)
+		return;
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s entering\n",
+		 smd_info->name);
+
+	diagfwd_register(TRANSPORT_SMD, smd_info->peripheral, smd_info->type,
+			 (void *)smd_info, &smd_ops, &smd_info->fwd_ctxt);
+	fwd_info = smd_info->fwd_ctxt;
+	smd_info->inited = 1;
+	/*
+	 * The channel is already open by the probe call as a result of other
+	 * peripheral. Inform the diag fwd layer that the channel is open.
+	 */
+	if (atomic_read(&smd_info->opened))
+		queue_work(smd_info->wq, &(smd_info->late_init_work));
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+int diag_smd_init_peripheral(uint8_t peripheral)
+{
+	if (peripheral >= NUM_PERIPHERALS) {
+		pr_err("diag: In %s, invalid peripheral %d\n",
+		       __func__, peripheral);
+		return -EINVAL;
+	}
+
+	smd_late_init(&smd_data[peripheral]);
+	smd_late_init(&smd_dci[peripheral]);
+	smd_late_init(&smd_cmd[peripheral]);
+	smd_late_init(&smd_dci_cmd[peripheral]);
+
+	return 0;
+}
+
+static void __diag_smd_exit(struct diag_smd_info *smd_info)
+{
+	if (!smd_info)
+		return;
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s entering\n",
+		 smd_info->name);
+
+	diagfwd_deregister(smd_info->peripheral, smd_info->type,
+			   (void *)smd_info);
+	smd_info->fwd_ctxt = NULL;
+	smd_info->hdl = NULL;
+	if (smd_info->wq)
+		destroy_workqueue(smd_info->wq);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+void diag_smd_early_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < NUM_PERIPHERALS; i++) {
+		if (i == PERIPHERAL_WDSP)
+			continue;
+		__diag_smd_exit(&smd_cntl[i]);
+	}
+
+	platform_driver_unregister(&diag_smd_cntl_driver);
+	platform_driver_unregister(&diag_smd_lite_cntl_driver);
+}
+
+void diag_smd_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < NUM_PERIPHERALS; i++) {
+		if (i == PERIPHERAL_WDSP)
+			continue;
+		__diag_smd_exit(&smd_data[i]);
+		__diag_smd_exit(&smd_cmd[i]);
+		__diag_smd_exit(&smd_dci[i]);
+		__diag_smd_exit(&smd_dci_cmd[i]);
+	}
+
+	platform_driver_unregister(&diag_smd_ch_driver);
+	platform_driver_unregister(&diag_smd_lite_driver);
+	platform_driver_unregister(&diag_smd_lite_cmd_driver);
+	platform_driver_unregister(&diag_smd_dci_driver);
+	platform_driver_unregister(&diag_smd_dci_cmd_driver);
+}
+
+static int diag_smd_write_ext(struct diag_smd_info *smd_info,
+			      unsigned char *buf, int len)
+{
+	int err = 0;
+	int offset = 0;
+	int write_len = 0;
+	int retry_count = 0;
+	int max_retries = 3;
+	uint8_t avail = 0;
+
+	if (!smd_info || !buf || len <= 0) {
+		pr_err_ratelimited("diag: In %s, invalid params, smd_info: %pK, buf: %pK, len: %d\n",
+				   __func__, smd_info, buf, len);
+		return -EINVAL;
+	}
+
+	if (!smd_info->inited || !smd_info->hdl ||
+	    !atomic_read(&smd_info->opened))
+		return -ENODEV;
+
+	mutex_lock(&smd_info->lock);
+	err = smd_write_start(smd_info->hdl, len);
+	if (err) {
+		pr_err_ratelimited("diag: In %s, error calling smd_write_start, peripheral: %d, err: %d\n",
+				   __func__, smd_info->peripheral, err);
+		goto fail;
+	}
+
+	while (offset < len) {
+		retry_count = 0;
+		do {
+			if (smd_write_segment_avail(smd_info->hdl)) {
+				avail = 1;
+				break;
+			}
+			/*
+			 * The channel maybe busy - the FIFO can be full. Retry
+			 * after sometime. The value of 10000 was chosen
+			 * emprically as the optimal value for the peripherals
+			 * to read data from the SMD channel.
+			 */
+			usleep_range(10000, 10100);
+			retry_count++;
+		} while (retry_count < max_retries);
+
+		if (!avail) {
+			err = -EAGAIN;
+			goto fail;
+		}
+
+		write_len = smd_write_segment(smd_info->hdl, buf + offset,
+					      (len - offset));
+		offset += write_len;
+		write_len = 0;
+	}
+
+	err = smd_write_end(smd_info->hdl);
+	if (err) {
+		pr_err_ratelimited("diag: In %s, error calling smd_write_end, peripheral: %d, err: %d\n",
+				   __func__, smd_info->peripheral, err);
+		goto fail;
+	}
+
+fail:
+	mutex_unlock(&smd_info->lock);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s wrote to channel, write_len: %d, err: %d\n",
+		 smd_info->name, offset, err);
+	return err;
+}
+
+static int diag_smd_write(void *ctxt, unsigned char *buf, int len)
+{
+	int write_len = 0;
+	int retry_count = 0;
+	int max_retries = 3;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt || !buf)
+		return -EIO;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info || !buf || len <= 0) {
+		pr_err_ratelimited("diag: In %s, invalid params, smd_info: %pK, buf: %pK, len: %d\n",
+				   __func__, smd_info, buf, len);
+		return -EINVAL;
+	}
+
+	if (!smd_info->inited || !smd_info->hdl ||
+	    !atomic_read(&smd_info->opened))
+		return -ENODEV;
+
+	if (len > smd_info->fifo_size)
+		return diag_smd_write_ext(smd_info, buf, len);
+
+	do {
+		mutex_lock(&smd_info->lock);
+		write_len = smd_write(smd_info->hdl, buf, len);
+		mutex_unlock(&smd_info->lock);
+		if (write_len == len)
+			break;
+		/*
+		 * The channel maybe busy - the FIFO can be full. Retry after
+		 * sometime. The value of 10000 was chosen emprically as the
+		 * optimal value for the peripherals to read data from the SMD
+		 * channel.
+		 */
+		usleep_range(10000, 10100);
+		retry_count++;
+	} while (retry_count < max_retries);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s wrote to channel, write_len: %d\n",
+		 smd_info->name, write_len);
+
+	if (write_len != len)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf)
+{
+	int pkt_len = 0;
+	int err = 0;
+	int total_recd_partial = 0;
+	int total_recd = 0;
+	uint8_t buf_full = 0;
+	unsigned char *temp_buf = NULL;
+	uint32_t read_len = 0;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt || !buf || buf_len <= 0 || !fwd_buf)
+		return -EIO;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info->hdl || !smd_info->inited ||
+	    !atomic_read(&smd_info->opened))
+		return -EIO;
+
+	/*
+	 * Always try to read the data if notification is received from smd
+	 * In case if packet size is 0 release the wake source hold earlier
+	 */
+	err = wait_event_interruptible(smd_info->read_wait_q,
+				       (smd_info->hdl != NULL) &&
+				       (atomic_read(&smd_info->opened) == 1));
+	if (err) {
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+		return -ERESTARTSYS;
+	}
+	if (atomic_read(&fwd_buf->in_busy) == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"%s closing read thread. Buffer is already marked freed p: %d t: %d buf_num: %d\n",
+			 smd_info->name, GET_BUF_PERIPHERAL(fwd_buf->ctxt),
+			 GET_BUF_TYPE(fwd_buf->ctxt),
+			 GET_BUF_NUM(fwd_buf->ctxt));
+		diag_ws_release();
+		return 0;
+	}
+	/*
+	 * Reset the buffers. Also release the wake source hold earlier.
+	 */
+	if (atomic_read(&smd_info->diag_state) == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			 "%s closing read thread. diag state is closed\n",
+			 smd_info->name);
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+		return 0;
+	}
+
+	if (!smd_info->hdl || !atomic_read(&smd_info->opened)) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			 "%s stopping read, hdl: %pK, opened: %d\n",
+			 smd_info->name, smd_info->hdl,
+			 atomic_read(&smd_info->opened));
+		goto fail_return;
+	}
+
+	do {
+		total_recd_partial = 0;
+		temp_buf = buf + total_recd;
+		pkt_len = smd_cur_packet_size(smd_info->hdl);
+		if (pkt_len <= 0)
+			break;
+
+		if (total_recd + pkt_len > buf_len) {
+			buf_full = 1;
+			break;
+		}
+
+		while (total_recd_partial < pkt_len) {
+			read_len = smd_read_avail(smd_info->hdl);
+			if (!read_len) {
+				err = wait_event_interruptible(smd_info->
+					read_wait_q,
+					((atomic_read(&smd_info->opened)) &&
+					smd_read_avail(smd_info->hdl)));
+				if (err)
+					goto fail_return;
+
+				if (!smd_info->hdl ||
+				    !atomic_read(&smd_info->opened)) {
+					DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+						"%s exiting from wait",
+						smd_info->name);
+					goto fail_return;
+				}
+			}
+
+			if (pkt_len < read_len)
+				goto fail_return;
+
+			smd_read(smd_info->hdl, temp_buf, read_len);
+			total_recd_partial += read_len;
+			total_recd += read_len;
+			temp_buf += read_len;
+		}
+	} while (pkt_len > 0);
+
+	if ((smd_info->type == TYPE_DATA && pkt_len) || buf_full)
+		err = queue_work(smd_info->wq, &(smd_info->read_work));
+
+	if (total_recd > 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s read total bytes: %d\n",
+			 smd_info->name, total_recd);
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, total_recd);
+	} else {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s error in read, err: %d\n",
+			 smd_info->name, total_recd);
+		goto fail_return;
+	}
+	return 0;
+
+fail_return:
+	diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+	return -EINVAL;
+}
+
+static void smd_notify(void *ctxt, unsigned int event)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info)
+		return;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+		atomic_set(&smd_info->opened, 1);
+		smd_info->fifo_size = smd_write_avail(smd_info->hdl);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s channel opened\n",
+			 smd_info->name);
+		queue_work(smd_info->wq, &(smd_info->open_work));
+		break;
+	case SMD_EVENT_CLOSE:
+		atomic_set(&smd_info->opened, 0);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s channel closed\n",
+			 smd_info->name);
+		queue_work(smd_info->wq, &(smd_info->close_work));
+		break;
+	case SMD_EVENT_DATA:
+		diag_ws_on_notify();
+		queue_work(smd_info->wq, &(smd_info->read_work));
+		break;
+	}
+
+	wake_up_interruptible(&smd_info->read_wait_q);
+}
+
diff --git a/drivers/char/diag/diagfwd_smd.h b/drivers/char/diag/diagfwd_smd.h
new file mode 100644
index 0000000..388014e
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smd.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAGFWD_SMD_H
+#define DIAGFWD_SMD_H
+
+#define DIAG_SMD_NAME_SZ	24
+#define SMD_DRAIN_BUF_SIZE	4096
+
+struct diag_smd_info {
+	uint8_t peripheral;
+	uint8_t type;
+	uint8_t inited;
+	atomic_t opened;
+	atomic_t diag_state;
+	uint32_t fifo_size;
+	smd_channel_t *hdl;
+	char name[DIAG_SMD_NAME_SZ];
+	struct mutex lock;
+	wait_queue_head_t read_wait_q;
+	struct workqueue_struct *wq;
+	struct work_struct open_work;
+	struct work_struct close_work;
+	struct work_struct read_work;
+	struct work_struct late_init_work;
+	struct diagfwd_info *fwd_ctxt;
+};
+
+extern struct diag_smd_info smd_data[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_cntl[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_dci[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_cmd[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_dci_cmd[NUM_PERIPHERALS];
+
+int diag_smd_init_peripheral(uint8_t peripheral);
+void diag_smd_exit(void);
+int diag_smd_init(void);
+void diag_smd_early_exit(void);
+void diag_smd_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt);
+int diag_smd_check_state(void *ctxt);
+
+#ifndef CONFIG_DIAG_USES_SMD
+#define _diag_smd_exit(void)
+#define _diag_smd_init(void)
+#else
+#define _diag_smd_exit(void) diag_smd_exit(void)
+#define _diag_smd_init(void) diag_smd_init(void)
+#endif
+
+#endif
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index f3c587d..401dbb0f 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -224,7 +224,8 @@
 static void diag_state_open_socket(void *ctxt);
 static void diag_state_close_socket(void *ctxt);
 static int diag_socket_write(void *ctxt, unsigned char *buf, int len);
-static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len);
+static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf);
 static void diag_socket_queue_read(void *ctxt);
 static void socket_init_work_fn(struct work_struct *work);
 static int socket_ready_notify(struct notifier_block *nb,
@@ -1062,7 +1063,8 @@
 	}
 }
 
-static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len)
+static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len,
+			struct diagfwd_buf_t *fwd_buf)
 {
 	int err = 0;
 	int pkt_len = 0;
@@ -1082,7 +1084,7 @@
 	if (!info)
 		return -ENODEV;
 
-	if (!buf || !ctxt || buf_len <= 0)
+	if (!buf || !ctxt || buf_len <= 0 || !fwd_buf)
 		return -EINVAL;
 
 	temp = buf;
@@ -1091,13 +1093,17 @@
 	err = wait_event_interruptible(info->read_wait_q,
 				      (info->data_ready > 0) || (!info->hdl) ||
 				      (atomic_read(&info->diag_state) == 0));
-	if (err) {
-		mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
-		diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
-		mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
-		return -ERESTARTSYS;
+	if (err)
+		goto fail;
+	if (atomic_read(&fwd_buf->in_busy) == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			"%s closing read thread. Buffer is already marked freed p: %d t: %d buf_num: %d\n",
+			 info->name, GET_BUF_PERIPHERAL(fwd_buf->ctxt),
+			 GET_BUF_TYPE(fwd_buf->ctxt),
+			 GET_BUF_NUM(fwd_buf->ctxt));
+		diag_ws_release();
+		return 0;
 	}
-
 	/*
 	 * There is no need to continue reading over peripheral in this case.
 	 * Release the wake source hold earlier.
@@ -1106,10 +1112,7 @@
 		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 			 "%s closing read thread. diag state is closed\n",
 			 info->name);
-		mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
-		diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
-		mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
-		return 0;
+		goto fail;
 	}
 
 	if (!info->hdl) {
@@ -1211,7 +1214,7 @@
 	mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
 	diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
 	mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
-	return -EIO;
+	return 0;
 }
 
 static int diag_socket_write(void *ctxt, unsigned char *buf, int len)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 020e8ad..929aef0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
  * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1872,6 +1872,8 @@
 	if (core->flags & CLK_RECALC_NEW_RATES)
 		(void)clk_calc_new_rates(core, core->new_rate);
 
+	if (core->flags & CLK_CHILD_NO_RATE_PROP)
+		return rc;
 	/*
 	 * Use safe iteration, as change_rate can actually swap parents
 	 * for certain clock types.
diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig
index 16f8c32..d881a5d 100644
--- a/drivers/clk/msm/Kconfig
+++ b/drivers/clk/msm/Kconfig
@@ -16,3 +16,5 @@
 	   Generate clock data structures from definitions found in
 	   device tree.
 
+source "drivers/clk/msm/mdss/Kconfig"
+
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index 4176553..9be7b8e 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -16,4 +16,24 @@
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-gcc-8953.o
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-cpu-8953.o
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-rcgwr.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-gcc-8952.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-cpu-8939.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-rcgwr.o
+obj-$(CONFIG_ARCH_MSM8953)	+= clock-cpu-sdm632.o
+
+# MDM9607
+obj-$(CONFIG_ARCH_MDM9607)      +=clock-gcc-mdm9607.o
+
+# MDM9650
+obj-$(CONFIG_ARCH_MDM9650)      += clock-gcc-mdm9650.o
+
+# MSM8909
+obj-$(CONFIG_ARCH_MSM8909)	+= clock-rpm-8909.o
+obj-$(CONFIG_ARCH_MSM8909)	+= clock-gcc-8909.o
+
+# ACPU clock
+obj-$(CONFIG_ARCH_MSM8909)	+= clock-a7.o
 endif
+
+obj-y				+= mdss/
+
diff --git a/drivers/clk/msm/clock-a7.c b/drivers/clk/msm/clock-a7.c
new file mode 100644
index 0000000..1c0b45a
--- /dev/null
+++ b/drivers/clk/msm/clock-a7.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <dt-bindings/clock/msm-clocks-a7.h>
+
+#include "clock.h"
+
+DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
+
+static struct mux_div_clk a7ssmux = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 300000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a7ssmux",
+		.ops = &clk_ops_mux_div_clk,
+		.vdd_class = &vdd_cpu,
+		CLK_INIT(a7ssmux.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+	.en_mask = 1,
+};
+
+static struct clk_lookup clock_tbl_a7[] = {
+	CLK_LIST(a7ssmux),
+	CLK_LOOKUP_OF("cpu0_clk",	a7ssmux, "fe805664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu1_clk",	a7ssmux, "fe805664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu2_clk",	a7ssmux, "fe805664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu3_clk",	a7ssmux, "fe805664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu0_clk",   a7ssmux, "8600664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu1_clk",   a7ssmux, "8600664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu2_clk",   a7ssmux, "8600664.qcom,pm"),
+	CLK_LOOKUP_OF("cpu3_clk",   a7ssmux, "8600664.qcom,pm"),
+};
+
+static void print_opp_table(int a7_cpu)
+{
+	struct dev_pm_opp *oppfmax, *oppfmin;
+	unsigned long apc0_fmax = a7ssmux.c.fmax[a7ssmux.c.num_fmax - 1];
+	unsigned long apc0_fmin = a7ssmux.c.fmax[1];
+
+	rcu_read_lock();
+	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), apc0_fmax,
+						true);
+	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), apc0_fmin,
+						true);
+
+	/* One time information during boot. */
+	pr_info("clock_cpu: a7: OPP voltage for %lu: %ld\n", apc0_fmin,
+			dev_pm_opp_get_voltage(oppfmin));
+	pr_info("clock_cpu: a7: OPP voltage for %lu: %ld\n", apc0_fmax,
+			dev_pm_opp_get_voltage(oppfmax));
+
+	rcu_read_unlock();
+}
+
+static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
+			unsigned long max_rate)
+{
+	unsigned long rate = 0;
+	int level;
+	long ret, uv, corner;
+
+	while (1) {
+		ret = clk_round_rate(c, rate + 1);
+		if (ret < 0) {
+			pr_warn("clock-cpu: round_rate failed at %lu\n", rate);
+			return ret;
+		}
+
+		rate = ret;
+
+		level = find_vdd_level(c, rate);
+		if (level <= 0) {
+			pr_warn("clock-cpu: no uv for %lu.\n", rate);
+			return -EINVAL;
+		}
+
+		uv = corner = c->vdd_class->vdd_uv[level];
+
+		/*
+		 * Populate both CPU and regulator devices with the
+		 * freq-to-corner OPP table to maintain backward
+		 * compatibility.
+		 */
+		ret = dev_pm_opp_add(cpudev, rate, corner);
+		if (ret) {
+			pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+			return ret;
+		}
+
+		ret = dev_pm_opp_add(vregdev, rate, corner);
+		if (ret) {
+			pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+			return ret;
+		}
+
+		if (rate >= max_rate)
+			break;
+	}
+
+	return 0;
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+	struct platform_device *apc_dev;
+	struct device_node *apc_node;
+	unsigned long apc_fmax;
+	int cpu, a7_cpu = 0;
+
+	apc_node = of_parse_phandle(pdev->dev.of_node, "cpu-vdd-supply", 0);
+	if (!apc_node) {
+		pr_err("can't find the apc0 dt node.\n");
+		return;
+	}
+
+	apc_dev = of_find_device_by_node(apc_node);
+	if (!apc_dev) {
+		pr_err("can't find the apc0 device node.\n");
+		return;
+	}
+
+	apc_fmax = a7ssmux.c.fmax[a7ssmux.c.num_fmax - 1];
+
+	for_each_possible_cpu(cpu) {
+		a7_cpu = cpu;
+		if (!get_cpu_device(cpu)) {
+			pr_err("can't find cpu device for attaching OPPs\n");
+			return;
+		}
+
+		WARN(add_opp(&a7ssmux.c, get_cpu_device(cpu),
+					&apc_dev->dev, apc_fmax),
+				"Failed to add OPP levels for A7\n");
+	}
+
+	/* One time print during bootup */
+	pr_info("clock-a7: OPP tables populated (cpu %d)\n", a7_cpu);
+
+	print_opp_table(a7_cpu);
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+								char *prop_name)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int prop_len, i;
+	struct clk_vdd_class *vdd = c->vdd_class;
+	u32 *array;
+
+	if (!of_find_property(of, prop_name, &prop_len)) {
+		dev_err(&pdev->dev, "missing %s\n", prop_name);
+		return -EINVAL;
+	}
+
+	prop_len /= sizeof(u32);
+	if (prop_len % 2) {
+		dev_err(&pdev->dev, "bad length %d\n", prop_len);
+		return -EINVAL;
+	}
+
+	prop_len /= 2;
+	vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+					GFP_KERNEL);
+	if (!vdd->level_votes)
+		return -ENOMEM;
+
+	vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+					GFP_KERNEL);
+	if (!vdd->vdd_uv)
+		return -ENOMEM;
+
+	c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+					GFP_KERNEL);
+	if (!c->fmax)
+		return -ENOMEM;
+
+	array = devm_kzalloc(&pdev->dev,
+			prop_len * sizeof(u32) * 2, GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+	for (i = 0; i < prop_len; i++) {
+		c->fmax[i] = array[2 * i];
+		vdd->vdd_uv[i] = array[2 * i + 1];
+	}
+
+	devm_kfree(&pdev->dev, array);
+	vdd->num_levels = prop_len;
+	vdd->cur_level = prop_len;
+	vdd->use_max_uV = true;
+	c->num_fmax = prop_len;
+	return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin, int *version)
+{
+	struct resource *res;
+	void __iomem *base;
+	u32 pte_efuse, redundant_sel, valid;
+
+	*bin = 0;
+	*version = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	redundant_sel = (pte_efuse >> 24) & 0x7;
+	*bin = pte_efuse & 0x7;
+	valid = (pte_efuse >> 3) & 0x1;
+	*version = (pte_efuse >> 4) & 0x3;
+
+	if (redundant_sel == 1)
+		*bin = (pte_efuse >> 27) & 0x7;
+
+	if (!valid) {
+		dev_info(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+		*bin = 0;
+	} else {
+		dev_info(&pdev->dev, "Speed bin: %d\n", *bin);
+	}
+
+	dev_info(&pdev->dev, "PVS version: %d\n", *version);
+
+}
+
+static void get_speed_bin_b(struct platform_device *pdev, int *bin,
+								int *version)
+{
+	struct resource *res;
+	void __iomem *base;
+	u32 pte_efuse, shift = 2, mask = 0x7;
+
+	*bin = 0;
+	*version = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
+	if (res) {
+		base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+		if (base) {
+			pte_efuse = readl_relaxed(base);
+			devm_iounmap(&pdev->dev, base);
+
+			*version = (pte_efuse >> 18) & 0x3;
+			if (!(*version)) {
+				*bin = (pte_efuse >> 23) & 0x3;
+				if (*bin) {
+					dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n",
+						*bin, *version);
+					return;
+				}
+			}
+		} else {
+			dev_warn(&pdev->dev,
+				"Unable to read efuse1 data. Defaulting to 0!\n");
+			return;
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+				"No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	*bin = (pte_efuse >> shift) & mask;
+
+	dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+								*version);
+}
+
+static int of_get_clk_src(struct platform_device *pdev, struct clk_src *parents)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int num_parents, i, j, index;
+	struct clk *c;
+	char clk_name[] = "clk-x";
+
+	num_parents = of_property_count_strings(of, "clock-names");
+	if (num_parents <= 0 || num_parents > 8) {
+		dev_err(&pdev->dev, "missing clock-names\n");
+		return -EINVAL;
+	}
+
+	j = 0;
+	for (i = 0; i < 8; i++) {
+		snprintf(clk_name, ARRAY_SIZE(clk_name), "clk-%d", i);
+		index = of_property_match_string(of, "clock-names", clk_name);
+		if (IS_ERR_VALUE(index))
+			continue;
+
+		parents[j].sel = i;
+		parents[j].src = c = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(c)) {
+			if (c != ERR_PTR(-EPROBE_DEFER))
+				dev_err(&pdev->dev, "clk_get: %s\n fail",
+						clk_name);
+			return PTR_ERR(c);
+		}
+		j++;
+	}
+
+	return num_parents;
+}
+
+static struct platform_device *cpu_clock_a7_dev;
+
+static int clock_a7_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int speed_bin = 0, version = 0, rc, cpu;
+	unsigned long rate, aux_rate;
+	struct clk *aux_clk, *main_pll;
+	char prop_name[] = "qcom,speedX-bin-vX";
+	const void *prop;
+	bool compat_bin = false;
+	bool compat_bin2 = false;
+	bool opp_enable;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,clock-a53-8916");
+	compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,clock-a7-mdm9607");
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rcg-base");
+	if (!res) {
+		dev_err(&pdev->dev, "missing rcg-base\n");
+		return -EINVAL;
+	}
+	a7ssmux.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!a7ssmux.base) {
+		dev_err(&pdev->dev, "ioremap failed for rcg-base\n");
+		return -ENOMEM;
+	}
+
+	vdd_cpu.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd");
+	if (IS_ERR(vdd_cpu.regulator[0])) {
+		if (PTR_ERR(vdd_cpu.regulator[0]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "unable to get regulator\n");
+		return PTR_ERR(vdd_cpu.regulator[0]);
+	}
+
+	rc = of_get_clk_src(pdev, a7ssmux.parents);
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	a7ssmux.num_parents = rc;
+
+	/* Override the existing safe operating frequency */
+	prop = of_get_property(pdev->dev.of_node, "qcom,safe-freq", NULL);
+	if (prop)
+		a7ssmux.safe_freq = of_read_ulong(prop, 1);
+
+	if (compat_bin || compat_bin2)
+		get_speed_bin_b(pdev, &speed_bin, &version);
+	else
+		get_speed_bin(pdev, &speed_bin, &version);
+
+	snprintf(prop_name, ARRAY_SIZE(prop_name),
+			"qcom,speed%d-bin-v%d", speed_bin, version);
+	rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c, prop_name);
+	if (rc) {
+		/* Fall back to most conservative PVS table */
+		dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+								prop_name);
+		rc = of_get_fmax_vdd_class(pdev, &a7ssmux.c,
+						"qcom,speed0-bin-v0");
+		if (rc) {
+			dev_err(&pdev->dev,
+					"Unable to load safe voltage plan\n");
+			return rc;
+		}
+		dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+	}
+
+	rc = of_msm_clock_register(pdev->dev.of_node,
+			clock_tbl_a7, ARRAY_SIZE(clock_tbl_a7));
+	if (rc) {
+		dev_err(&pdev->dev, "msm_clock_register failed\n");
+		return rc;
+	}
+
+	/* Force a PLL reconfiguration */
+	aux_clk = a7ssmux.parents[0].src;
+	main_pll = a7ssmux.parents[1].src;
+
+	aux_rate = clk_get_rate(aux_clk);
+	rate = clk_get_rate(&a7ssmux.c);
+	clk_set_rate(&a7ssmux.c, aux_rate);
+	clk_set_rate(main_pll, clk_round_rate(main_pll, 1));
+	clk_set_rate(&a7ssmux.c, rate);
+
+	/*
+	 * We don't want the CPU clocks to be turned off at late init
+	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
+	 * that the clocks have already been prepared and enabled by the time
+	 * they take over.
+	 */
+	get_online_cpus();
+	for_each_online_cpu(cpu)
+		WARN(clk_prepare_enable(&a7ssmux.c),
+			"Unable to turn on CPU clock");
+	put_online_cpus();
+
+	opp_enable = of_property_read_bool(pdev->dev.of_node,
+						"qcom,enable-opp");
+	if (opp_enable)
+		cpu_clock_a7_dev = pdev;
+
+	return 0;
+}
+
+static const struct of_device_id clock_a7_match_table[] = {
+	{.compatible = "qcom,clock-a53-8916"},
+	{.compatible = "qcom,clock-a7-9650"},
+	{.compatible = "qcom,clock-a7-mdm9607"},
+	{.compatible = "qcom,clock-a7-sdx20"},
+	{}
+};
+
+static struct platform_driver clock_a7_driver = {
+	.probe = clock_a7_probe,
+	.driver = {
+		.name = "clock-a7",
+		.of_match_table = clock_a7_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clock_a7_init(void)
+{
+	return platform_driver_register(&clock_a7_driver);
+}
+arch_initcall(clock_a7_init);
+
+/* CPU devices are not currently available in arch_initcall */
+static int __init cpu_clock_a7_init_opp(void)
+{
+	if (cpu_clock_a7_dev)
+		populate_opp_table(cpu_clock_a7_dev);
+	return 0;
+}
+module_init(cpu_clock_a7_init_opp);
diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c
index dbe8d8e..37e34d5 100644
--- a/drivers/clk/msm/clock-alpha-pll.c
+++ b/drivers/clk/msm/clock-alpha-pll.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -774,6 +774,13 @@
 		writel_relaxed(regval, USER_CTL_HI_REG(pll));
 	}
 
+	if (masks->cal_l_val_mask && pll->cal_l_val) {
+		regval = readl_relaxed(USER_CTL_HI_REG(pll));
+		regval &= ~masks->cal_l_val_mask;
+		regval |= pll->cal_l_val;
+		writel_relaxed(regval, USER_CTL_HI_REG(pll));
+	}
+
 	if (masks->test_ctl_lo_mask) {
 		regval = readl_relaxed(TEST_CTL_LO_REG(pll));
 		regval &= ~masks->test_ctl_lo_mask;
diff --git a/drivers/clk/msm/clock-cpu-8939.c b/drivers/clk/msm/clock-cpu-8939.c
new file mode 100644
index 0000000..68ea9a1
--- /dev/null
+++ b/drivers/clk/msm/clock-cpu-8939.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/pm.h>
+
+#include "clock.h"
+#include <dt-bindings/clock/msm-cpu-clocks-8939.h>
+
+DEFINE_VDD_REGS_INIT(vdd_cpu_bc, 1);
+DEFINE_VDD_REGS_INIT(vdd_cpu_lc, 1);
+DEFINE_VDD_REGS_INIT(vdd_cpu_cci, 1);
+
+enum {
+	A53SS_MUX_BC,
+	A53SS_MUX_LC,
+	A53SS_MUX_CCI,
+	A53SS_MUX_NUM,
+};
+
+static const char * const mux_names[] = { "c1", "c0", "cci"};
+
+struct cpu_clk_8939 {
+	u32 cpu_reg_mask;
+	cpumask_t cpumask;
+	bool hw_low_power_ctrl;
+	struct pm_qos_request req;
+	struct clk c;
+	struct latency_level latency_lvl;
+	s32 cpu_latency_no_l2_pc_us;
+};
+
+static struct mux_div_clk a53ssmux_bc = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 400000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_bc",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_bc.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static struct mux_div_clk a53ssmux_lc = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 200000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_lc",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_lc.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static struct mux_div_clk a53ssmux_cci = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 200000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_cci",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_cci.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static void do_nothing(void *unused) { }
+
+static inline struct cpu_clk_8939 *to_cpu_clk_8939(struct clk *c)
+{
+	return container_of(c, struct cpu_clk_8939, c);
+}
+
+static enum handoff cpu_clk_8939_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	return HANDOFF_DISABLED_CLK;
+}
+
+static long cpu_clk_8939_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int cpu_clk_8939_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	struct cpu_clk_8939 *cpuclk = to_cpu_clk_8939(c);
+	bool hw_low_power_ctrl = cpuclk->hw_low_power_ctrl;
+
+	if (hw_low_power_ctrl) {
+		memset(&cpuclk->req, 0, sizeof(cpuclk->req));
+		cpumask_copy(&cpuclk->req.cpus_affine,
+				(const struct cpumask *)&cpuclk->cpumask);
+		cpuclk->req.type = PM_QOS_REQ_AFFINE_CORES;
+		pm_qos_add_request(&cpuclk->req, PM_QOS_CPU_DMA_LATENCY,
+				cpuclk->cpu_latency_no_l2_pc_us - 1);
+		smp_call_function_any(&cpuclk->cpumask, do_nothing,
+				NULL, 1);
+	}
+
+	ret = clk_set_rate(c->parent, rate);
+
+	if (hw_low_power_ctrl)
+		pm_qos_remove_request(&cpuclk->req);
+
+	return ret;
+}
+
+static struct clk_ops clk_ops_cpu = {
+	.set_rate = cpu_clk_8939_set_rate,
+	.round_rate = cpu_clk_8939_round_rate,
+	.handoff = cpu_clk_8939_handoff,
+};
+
+static struct cpu_clk_8939 a53_bc_clk = {
+	.cpu_reg_mask = 0x3,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "perf",
+	},
+	.cpu_latency_no_l2_pc_us = 300,
+	.c = {
+		.parent = &a53ssmux_bc.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_bc,
+		.dbg_name = "a53_bc_clk",
+		CLK_INIT(a53_bc_clk.c),
+	},
+};
+
+static struct cpu_clk_8939 a53_lc_clk = {
+	.cpu_reg_mask = 0x103,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "pwr",
+	},
+	.cpu_latency_no_l2_pc_us = 300,
+	.c = {
+		.parent = &a53ssmux_lc.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_lc,
+		.dbg_name = "a53_lc_clk",
+		CLK_INIT(a53_lc_clk.c),
+	},
+};
+
+static struct cpu_clk_8939 cci_clk = {
+	.c = {
+		.parent = &a53ssmux_cci.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_cci,
+		.dbg_name = "cci_clk",
+		CLK_INIT(cci_clk.c),
+	},
+};
+
+static struct clk_lookup cpu_clocks_8939[] = {
+	CLK_LIST(a53ssmux_lc),
+	CLK_LIST(a53ssmux_bc),
+	CLK_LIST(a53ssmux_cci),
+	CLK_LIST(a53_bc_clk),
+	CLK_LIST(a53_lc_clk),
+	CLK_LIST(cci_clk),
+};
+
+static struct clk_lookup cpu_clocks_8939_single_cluster[] = {
+	CLK_LIST(a53ssmux_bc),
+	CLK_LIST(a53_bc_clk),
+};
+
+
+static struct mux_div_clk *a53ssmux[] = {&a53ssmux_bc,
+						&a53ssmux_lc, &a53ssmux_cci};
+
+static struct cpu_clk_8939 *cpuclk[] = { &a53_bc_clk, &a53_lc_clk, &cci_clk};
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+	struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
+	u32 reg;
+
+	/* CPU 0/1/2/3 --> a53_bc_clk and mask = 0x103
+	 * CPU 4/5/6/7 --> a53_lc_clk and mask = 0x3
+	 */
+	if (cpu_node && !of_property_read_u32(cpu_node, "reg", &reg)) {
+		if ((reg | a53_bc_clk.cpu_reg_mask) == a53_bc_clk.cpu_reg_mask)
+			return &a53_lc_clk.c;
+		if ((reg | a53_lc_clk.cpu_reg_mask) == a53_lc_clk.cpu_reg_mask)
+			return &a53_bc_clk.c;
+	}
+
+	return NULL;
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+								char *prop_name)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int prop_len, i;
+	struct clk_vdd_class *vdd = c->vdd_class;
+	u32 *array;
+
+	if (!of_find_property(of, prop_name, &prop_len)) {
+		dev_err(&pdev->dev, "missing %s\n", prop_name);
+		return -EINVAL;
+	}
+
+	prop_len /= sizeof(u32);
+	if (prop_len % 2) {
+		dev_err(&pdev->dev, "bad length %d\n", prop_len);
+		return -EINVAL;
+	}
+
+	prop_len /= 2;
+	vdd->level_votes = devm_kzalloc(&pdev->dev,
+				prop_len * sizeof(*vdd->level_votes),
+					GFP_KERNEL);
+	if (!vdd->level_votes)
+		return -ENOMEM;
+
+	vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+					GFP_KERNEL);
+	if (!vdd->vdd_uv)
+		return -ENOMEM;
+
+	c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+					GFP_KERNEL);
+	if (!c->fmax)
+		return -ENOMEM;
+
+	array = devm_kzalloc(&pdev->dev,
+			prop_len * sizeof(u32) * 2, GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+	for (i = 0; i < prop_len; i++) {
+		c->fmax[i] = array[2 * i];
+		vdd->vdd_uv[i] = array[2 * i + 1];
+	}
+
+	devm_kfree(&pdev->dev, array);
+	vdd->num_levels = prop_len;
+	vdd->cur_level = prop_len;
+	vdd->use_max_uV = true;
+	c->num_fmax = prop_len;
+	return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin,
+								int *version)
+{
+	struct resource *res;
+	void __iomem *base, *base1, *base2;
+	u32 pte_efuse, pte_efuse1, pte_efuse2;
+
+	*bin = 0;
+	*version = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	*bin = (pte_efuse >> 2) & 0x7;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No PVS version available. Defaulting to 0!\n");
+		goto out;
+	}
+
+	base1 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base1) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse1 data. Defaulting to 0!\n");
+		goto out;
+	}
+
+	pte_efuse1 = readl_relaxed(base1);
+	devm_iounmap(&pdev->dev, base1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse2");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No PVS version available. Defaulting to 0!\n");
+		goto out;
+	}
+
+	base2 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base2) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse2 data. Defaulting to 0!\n");
+		goto out;
+	}
+
+	pte_efuse2 = readl_relaxed(base2);
+	devm_iounmap(&pdev->dev, base2);
+
+	*version = ((pte_efuse1 >> 29 & 0x1) | ((pte_efuse2 >> 18 & 0x3) << 1));
+
+out:
+	dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+								*version);
+}
+
+static int of_get_clk_src(struct platform_device *pdev,
+				struct clk_src *parents, int mux_id)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int mux_parents, i, j, index;
+	struct clk *c;
+	char clk_name[] = "clk-xxx-x";
+
+	mux_parents = of_property_count_strings(of, "clock-names");
+	if (mux_parents <= 0) {
+		dev_err(&pdev->dev, "missing clock-names\n");
+		return -EINVAL;
+	}
+	j = 0;
+
+	for (i = 0; i < 8; i++) {
+		snprintf(clk_name, ARRAY_SIZE(clk_name), "clk-%s-%d",
+							mux_names[mux_id], i);
+		index = of_property_match_string(of, "clock-names", clk_name);
+		if (index < 0)
+			continue;
+
+		parents[j].sel = i;
+		parents[j].src = c = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(c)) {
+			if (c != ERR_PTR(-EPROBE_DEFER))
+				dev_err(&pdev->dev, "clk_get: %s\n fail",
+						clk_name);
+			return PTR_ERR(c);
+		}
+		j++;
+	}
+
+	return j;
+}
+
+static int cpu_parse_devicetree(struct platform_device *pdev, int mux_id)
+{
+	struct resource *res;
+	int rc;
+	char rcg_name[] = "apcs-xxx-rcg-base";
+	char vdd_name[] = "vdd-xxx";
+	struct regulator *regulator;
+
+	snprintf(rcg_name, ARRAY_SIZE(rcg_name), "apcs-%s-rcg-base",
+						mux_names[mux_id]);
+	res = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, rcg_name);
+	if (!res) {
+		dev_err(&pdev->dev, "missing %s\n", rcg_name);
+		return -EINVAL;
+	}
+	a53ssmux[mux_id]->base = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!a53ssmux[mux_id]->base) {
+		dev_err(&pdev->dev, "ioremap failed for %s\n", rcg_name);
+		return -ENOMEM;
+	}
+
+	snprintf(vdd_name, ARRAY_SIZE(vdd_name), "vdd-%s", mux_names[mux_id]);
+	regulator = devm_regulator_get(&pdev->dev, vdd_name);
+	if (IS_ERR(regulator)) {
+		if (PTR_ERR(regulator) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "unable to get regulator\n");
+		return PTR_ERR(regulator);
+	}
+	cpuclk[mux_id]->c.vdd_class->regulator[0] = regulator;
+
+	rc = of_get_clk_src(pdev, a53ssmux[mux_id]->parents, mux_id);
+	if (rc < 0)
+		return rc;
+
+	a53ssmux[mux_id]->num_parents = rc;
+
+	return 0;
+}
+
+static long corner_to_voltage(unsigned long corner, struct device *dev)
+{
+	struct dev_pm_opp *oppl;
+	long uv;
+
+	rcu_read_lock();
+	oppl = dev_pm_opp_find_freq_exact(dev, corner, true);
+	rcu_read_unlock();
+	if (IS_ERR_OR_NULL(oppl))
+		return -EINVAL;
+
+	rcu_read_lock();
+	uv = dev_pm_opp_get_voltage(oppl);
+	rcu_read_unlock();
+
+	return uv;
+}
+
+
+static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
+			unsigned long max_rate)
+{
+	unsigned long rate = 0;
+	int level;
+	long ret, uv, corner;
+	bool use_voltages = false;
+	struct dev_pm_opp *oppl;
+	int j = 1;
+
+	rcu_read_lock();
+	/* Check if the regulator driver has already populated OPP tables */
+	oppl = dev_pm_opp_find_freq_exact(vregdev, 2, true);
+	rcu_read_unlock();
+	if (!IS_ERR_OR_NULL(oppl))
+		use_voltages = true;
+
+	while (1) {
+		rate = c->fmax[j++];
+		level = find_vdd_level(c, rate);
+		if (level <= 0) {
+			pr_warn("clock-cpu: no uv for %lu.\n", rate);
+			return -EINVAL;
+		}
+		uv = corner = c->vdd_class->vdd_uv[level];
+		/*
+		 * If corner to voltage mapping is available, populate the OPP
+		 * table with the voltages rather than corners.
+		 */
+		if (use_voltages) {
+			uv = corner_to_voltage(corner, vregdev);
+			if (uv < 0) {
+				pr_warn("clock-cpu: no uv for corner %lu\n",
+					 corner);
+				return uv;
+			}
+			ret = dev_pm_opp_add(cpudev, rate, uv);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					 rate);
+				return ret;
+			}
+
+		} else {
+			/*
+			 * Populate both CPU and regulator devices with the
+			 * freq-to-corner OPP table to maintain backward
+			 * compatibility.
+			 */
+			ret = dev_pm_opp_add(cpudev, rate, corner);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+				return ret;
+			}
+			ret = dev_pm_opp_add(vregdev, rate, corner);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+				return ret;
+			}
+		}
+		if (rate >= max_rate)
+			break;
+	}
+
+	return 0;
+}
+
+static void print_opp_table(int a53_c0_cpu, int a53_c1_cpu, bool single_cluster)
+{
+	struct dev_pm_opp *oppfmax, *oppfmin;
+	unsigned long apc0_fmax, apc1_fmax, apc0_fmin, apc1_fmin;
+
+	if (!single_cluster) {
+		apc0_fmax = a53_lc_clk.c.fmax[a53_lc_clk.c.num_fmax - 1];
+		apc0_fmin = a53_lc_clk.c.fmax[1];
+	}
+	apc1_fmax = a53_bc_clk.c.fmax[a53_bc_clk.c.num_fmax - 1];
+	apc1_fmin = a53_bc_clk.c.fmax[1];
+
+	rcu_read_lock();
+	if (!single_cluster) {
+		oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmax, true);
+		oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmin, true);
+		/*
+		 * One time information during boot. Important to know that this
+		 * looks sane since it can eventually make its way to the
+		 * scheduler.
+		 */
+		pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmin, dev_pm_opp_get_voltage(oppfmin));
+		pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmax, dev_pm_opp_get_voltage(oppfmax));
+	}
+	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmax, true);
+	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmin, true);
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmin,
+		dev_pm_opp_get_voltage(oppfmin));
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmax,
+		dev_pm_opp_get_voltage(oppfmax));
+	rcu_read_unlock();
+}
+
+static void populate_opp_table(struct platform_device *pdev,
+					bool single_cluster)
+{
+	struct platform_device *apc0_dev = 0, *apc1_dev;
+	struct device_node *apc0_node = NULL, *apc1_node;
+	unsigned long apc0_fmax = 0, apc1_fmax = 0;
+	int cpu, a53_c0_cpu = 0, a53_c1_cpu = 0;
+
+	if (!single_cluster)
+		apc0_node = of_parse_phandle(pdev->dev.of_node,
+						"vdd-c0-supply", 0);
+	apc1_node = of_parse_phandle(pdev->dev.of_node, "vdd-c1-supply", 0);
+	if (!apc0_node && !single_cluster) {
+		pr_err("can't find the apc0 dt node.\n");
+		return;
+	}
+	if (!apc1_node) {
+		pr_err("can't find the apc1 dt node.\n");
+		return;
+	}
+	if (!single_cluster)
+		apc0_dev = of_find_device_by_node(apc0_node);
+
+	apc1_dev = of_find_device_by_node(apc1_node);
+	if (!apc1_dev && !single_cluster) {
+		pr_err("can't find the apc0 device node.\n");
+		return;
+	}
+	if (!apc1_dev) {
+		pr_err("can't find the apc1 device node.\n");
+		return;
+	}
+
+	if (!single_cluster)
+		apc0_fmax = a53_lc_clk.c.fmax[a53_lc_clk.c.num_fmax - 1];
+
+	apc1_fmax = a53_bc_clk.c.fmax[a53_bc_clk.c.num_fmax - 1];
+
+	for_each_possible_cpu(cpu) {
+		pr_debug("the CPU number is : %d\n", cpu);
+		if (cpu/4 == 0) {
+			a53_c1_cpu = cpu;
+			WARN(add_opp(&a53_bc_clk.c, get_cpu_device(cpu),
+				     &apc1_dev->dev, apc1_fmax),
+				     "Failed to add OPP levels for A53 big cluster\n");
+		} else if (cpu/4 == 1 && !single_cluster) {
+			a53_c0_cpu = cpu;
+			WARN(add_opp(&a53_lc_clk.c, get_cpu_device(cpu),
+				     &apc0_dev->dev, apc0_fmax),
+				     "Failed to add OPP levels for A53 little cluster\n");
+		}
+	}
+
+	/* One time print during bootup */
+	pr_info("clock-cpu-8939: OPP tables populated (cpu %d and %d)",
+		a53_c0_cpu, a53_c1_cpu);
+
+	print_opp_table(a53_c0_cpu, a53_c1_cpu, single_cluster);
+
+}
+
+static void config_pll(int mux_id)
+{
+	unsigned long rate, aux_rate;
+	struct clk *aux_clk, *main_pll;
+
+	aux_clk = a53ssmux[mux_id]->parents[0].src;
+	main_pll = a53ssmux[mux_id]->parents[1].src;
+
+	aux_rate = clk_get_rate(aux_clk);
+	rate = clk_get_rate(&a53ssmux[mux_id]->c);
+	clk_set_rate(&a53ssmux[mux_id]->c, aux_rate);
+	clk_set_rate(main_pll, clk_round_rate(main_pll, 1));
+	clk_set_rate(&a53ssmux[mux_id]->c, rate);
+
+}
+
+static int clock_8939_pm_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		clk_unprepare(&a53_lc_clk.c);
+		clk_unprepare(&a53_bc_clk.c);
+		clk_unprepare(&cci_clk.c);
+		break;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		clk_prepare(&a53_lc_clk.c);
+		clk_prepare(&a53_bc_clk.c);
+		clk_prepare(&cci_clk.c);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static int clock_8939_pm_event_single_cluster(struct notifier_block *this,
+						unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		clk_unprepare(&a53_bc_clk.c);
+		break;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		clk_prepare(&a53_bc_clk.c);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block clock_8939_pm_notifier = {
+	.notifier_call = clock_8939_pm_event,
+};
+
+static struct notifier_block clock_8939_pm_notifier_single_cluster = {
+	.notifier_call = clock_8939_pm_event_single_cluster,
+};
+
+/**
+ * clock_panic_callback() - panic notification callback function.
+ *		This function is invoked when a kernel panic occurs.
+ * @nfb:	Notifier block pointer
+ * @event:	Value passed unmodified to notifier function
+ * @data:	Pointer passed unmodified to notifier function
+ *
+ * Return: NOTIFY_OK
+ */
+static int clock_panic_callback(struct notifier_block *nfb,
+					unsigned long event, void *data)
+{
+	bool single_cluster = 0;
+	unsigned long rate;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+							"qcom,cpu-clock-8939");
+	if (!ofnode)
+		ofnode = of_find_compatible_node(NULL, NULL,
+						"qcom,cpu-clock-8917");
+	if (ofnode)
+		single_cluster = of_property_read_bool(ofnode,
+							"qcom,num-cluster");
+
+	rate  = (a53_bc_clk.c.count) ? a53_bc_clk.c.rate : 0;
+	pr_err("%s frequency: %10lu Hz\n", a53_bc_clk.c.dbg_name, rate);
+
+	if (!single_cluster) {
+		rate  = (a53_lc_clk.c.count) ? a53_lc_clk.c.rate : 0;
+		pr_err("%s frequency: %10lu Hz\n", a53_lc_clk.c.dbg_name, rate);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block clock_panic_notifier = {
+	.notifier_call = clock_panic_callback,
+	.priority = 1,
+};
+
+static int clock_a53_probe(struct platform_device *pdev)
+{
+	int speed_bin, version, rc, cpu, mux_id, rate;
+	char prop_name[] = "qcom,speedX-bin-vX-XXX";
+	int mux_num;
+	bool single_cluster;
+
+	single_cluster = of_property_read_bool(pdev->dev.of_node,
+						"qcom,num-cluster");
+
+	get_speed_bin(pdev, &speed_bin, &version);
+
+	mux_num = single_cluster ? A53SS_MUX_LC:A53SS_MUX_NUM;
+
+	for (mux_id = 0; mux_id < mux_num; mux_id++) {
+		rc = cpu_parse_devicetree(pdev, mux_id);
+		if (rc)
+			return rc;
+
+		snprintf(prop_name, ARRAY_SIZE(prop_name),
+					"qcom,speed%d-bin-v%d-%s",
+					speed_bin, version, mux_names[mux_id]);
+
+		rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+		if (rc) {
+			/* Fall back to most conservative PVS table */
+			dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+								prop_name);
+
+			snprintf(prop_name, ARRAY_SIZE(prop_name),
+				"qcom,speed0-bin-v0-%s", mux_names[mux_id]);
+			rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+			if (rc) {
+				dev_err(&pdev->dev,
+					"Unable to load safe voltage plan\n");
+				return rc;
+			}
+			dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+		}
+	}
+	if (single_cluster)
+		rc = of_msm_clock_register(pdev->dev.of_node,
+				cpu_clocks_8939_single_cluster,
+				ARRAY_SIZE(cpu_clocks_8939_single_cluster));
+	else
+		rc = of_msm_clock_register(pdev->dev.of_node,
+				cpu_clocks_8939, ARRAY_SIZE(cpu_clocks_8939));
+
+	if (rc) {
+		dev_err(&pdev->dev, "msm_clock_register failed\n");
+		return rc;
+	}
+
+	if (!single_cluster) {
+		rate = clk_get_rate(&cci_clk.c);
+		clk_set_rate(&cci_clk.c, rate);
+	}
+
+	for (mux_id = 0; mux_id < mux_num; mux_id++) {
+		/* Force a PLL reconfiguration */
+		config_pll(mux_id);
+	}
+
+	/*
+	 * We don't want the CPU clocks to be turned off at late init
+	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
+	 * that the clocks have already been prepared and enabled by the time
+	 * they take over.
+	 */
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		WARN(clk_prepare_enable(&cpuclk[cpu/4]->c),
+				"Unable to turn on CPU clock");
+		if (!single_cluster)
+			clk_prepare_enable(&cci_clk.c);
+	}
+	put_online_cpus();
+
+	for_each_possible_cpu(cpu) {
+		if (logical_cpu_to_clk(cpu) == &a53_bc_clk.c)
+			cpumask_set_cpu(cpu, &a53_bc_clk.cpumask);
+		if (logical_cpu_to_clk(cpu) == &a53_lc_clk.c)
+			cpumask_set_cpu(cpu, &a53_lc_clk.cpumask);
+	}
+
+	a53_lc_clk.hw_low_power_ctrl = true;
+	a53_bc_clk.hw_low_power_ctrl = true;
+
+	if (single_cluster)
+		register_pm_notifier(&clock_8939_pm_notifier_single_cluster);
+	else
+		register_pm_notifier(&clock_8939_pm_notifier);
+
+	populate_opp_table(pdev, single_cluster);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&clock_panic_notifier);
+
+	return 0;
+}
+
+static const struct of_device_id clock_a53_match_table[] = {
+	{.compatible = "qcom,cpu-clock-8939"},
+	{.compatible = "qcom,cpu-clock-8917"},
+	{}
+};
+
+static struct platform_driver clock_a53_driver = {
+	.probe = clock_a53_probe,
+	.driver = {
+		.name = "cpu-clock-8939",
+		.of_match_table = clock_a53_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clock_a53_init(void)
+{
+	return platform_driver_register(&clock_a53_driver);
+}
+arch_initcall(clock_a53_init);
+
+static int __init clock_cpu_lpm_get_latency(void)
+{
+	bool single_cluster;
+	int rc = 0;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+					"qcom,cpu-clock-8939");
+
+	if (!ofnode)
+		ofnode = of_find_compatible_node(NULL, NULL,
+					"qcom,cpu-clock-gold");
+
+	if (!ofnode)
+		return 0;
+
+	single_cluster = of_property_read_bool(ofnode,
+					"qcom,num-cluster");
+
+	rc = lpm_get_latency(&a53_bc_clk.latency_lvl,
+			&a53_bc_clk.cpu_latency_no_l2_pc_us);
+	if (rc < 0)
+		pr_err("Failed to get the L2 PC value for perf\n");
+
+	if (!single_cluster) {
+		rc = lpm_get_latency(&a53_lc_clk.latency_lvl,
+				&a53_lc_clk.cpu_latency_no_l2_pc_us);
+		if (rc < 0)
+			pr_err("Failed to get the L2 PC value for pwr\n");
+
+		pr_debug("Latency for pwr/perf cluster %d : %d\n",
+			a53_lc_clk.cpu_latency_no_l2_pc_us,
+			a53_bc_clk.cpu_latency_no_l2_pc_us);
+	} else {
+		pr_debug("Latency for perf cluster %d\n",
+			a53_bc_clk.cpu_latency_no_l2_pc_us);
+	}
+
+	return rc;
+}
+late_initcall(clock_cpu_lpm_get_latency);
+
+#define APCS_C0_PLL			0xb116000
+#define C0_PLL_MODE			0x0
+#define C0_PLL_L_VAL			0x4
+#define C0_PLL_M_VAL			0x8
+#define C0_PLL_N_VAL			0xC
+#define C0_PLL_USER_CTL			0x10
+#define C0_PLL_CONFIG_CTL		0x14
+
+#define APCS_ALIAS0_CMD_RCGR		0xb111050
+#define APCS_ALIAS0_CFG_OFF		0x4
+#define APCS_ALIAS0_CORE_CBCR_OFF	0x8
+#define SRC_SEL				0x4
+#define SRC_DIV				0x3
+
+static void __init configure_enable_sr2_pll(void __iomem *base)
+{
+	/* Disable Mode */
+	writel_relaxed(0x0, base + C0_PLL_MODE);
+
+	/* Configure L/M/N values */
+	writel_relaxed(0x34, base + C0_PLL_L_VAL);
+	writel_relaxed(0x0,  base + C0_PLL_M_VAL);
+	writel_relaxed(0x1,  base + C0_PLL_N_VAL);
+
+	/* Configure USER_CTL and CONFIG_CTL value */
+	writel_relaxed(0x0100000f, base + C0_PLL_USER_CTL);
+	writel_relaxed(0x4c015765, base + C0_PLL_CONFIG_CTL);
+
+	/* Enable PLL now */
+	writel_relaxed(0x2, base + C0_PLL_MODE);
+	udelay(2);
+	writel_relaxed(0x6, base + C0_PLL_MODE);
+	udelay(50);
+	writel_relaxed(0x7, base + C0_PLL_MODE);
+	/* Ensure that the writes go through before enabling
+	 * PLL
+	 */
+	mb();
+}
+
+static int __init cpu_clock_a53_init_little(void)
+{
+	void __iomem  *base;
+	int regval = 0, count;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+							"qcom,cpu-clock-8939");
+	if (!ofnode)
+		return 0;
+
+	base = ioremap_nocache(APCS_C0_PLL, SZ_32);
+	configure_enable_sr2_pll(base);
+	iounmap(base);
+
+	base = ioremap_nocache(APCS_ALIAS0_CMD_RCGR, SZ_8);
+	regval = readl_relaxed(base);
+	/* Source GPLL0 and 1/2 the rate of GPLL0 */
+	regval = (SRC_SEL << 8) | SRC_DIV; /* 0x403 */
+	writel_relaxed(regval, base + APCS_ALIAS0_CFG_OFF);
+	/* Make sure src sel and src div is set before update bit */
+	mb();
+
+	/* update bit */
+	regval = readl_relaxed(base);
+	regval |= BIT(0);
+	writel_relaxed(regval, base);
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		if (!(readl_relaxed(base)) & BIT(0))
+			break;
+		udelay(1);
+	}
+
+	/* Enable the branch */
+	regval =  readl_relaxed(base + APCS_ALIAS0_CORE_CBCR_OFF);
+	regval |= BIT(0);
+	writel_relaxed(regval, base + APCS_ALIAS0_CORE_CBCR_OFF);
+	/* Branch enable should be complete */
+	mb();
+	iounmap(base);
+
+	pr_info("A53 Power clocks configured\n");
+
+	return 0;
+}
+early_initcall(cpu_clock_a53_init_little);
diff --git a/drivers/clk/msm/clock-cpu-sdm632.c b/drivers/clk/msm/clock-cpu-sdm632.c
new file mode 100644
index 0000000..b59739a
--- /dev/null
+++ b/drivers/clk/msm/clock-cpu-sdm632.c
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/pm.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8953.h>
+
+#include "clock.h"
+
+#define APCS_PLL_MODE		0x0
+#define APCS_PLL_L_VAL		0x8
+#define APCS_PLL_ALPHA_VAL	0x10
+#define APCS_PLL_USER_CTL	0x18
+#define APCS_PLL_CONFIG_CTL_LO	0x20
+#define APCS_PLL_CONFIG_CTL_HI	0x24
+#define APCS_PLL_STATUS		0x28
+#define APCS_PLL_TEST_CTL_LO	0x30
+#define APCS_PLL_TEST_CTL_HI	0x34
+
+#define PLL_MODE(x)	(*(x)->base + (unsigned long) (x)->mode_reg)
+
+#define GLB_DIAG	0x0b11101c
+
+static struct clk_ops clk_ops_variable_rate;
+
+DEFINE_EXT_CLK(xo_a_clk, NULL);
+DEFINE_VDD_REGS_INIT(vdd_cpu, 1);
+
+enum {
+	APCS_C0_PLL_BASE,
+	APCS_C1_PLL_BASE,
+	APCS_CCI_PLL_BASE,
+	N_PLL_BASES,
+};
+
+enum vdd_mx_pll_levels {
+	VDD_MX_OFF,
+	VDD_MX_MIN,
+	VDD_MX_LOWER,
+	VDD_MX_SVS,
+	VDD_MX_NUM,
+};
+
+static int vdd_pll_levels[] = {
+	RPM_REGULATOR_LEVEL_NONE,       /* VDD_PLL_OFF */
+	RPM_REGULATOR_LEVEL_MIN_SVS,    /* VDD_PLL_MIN */
+	RPM_REGULATOR_LEVEL_LOW_SVS,    /* VDD_PLL_LOW_SVS */
+	RPM_REGULATOR_LEVEL_SVS,	/* VDD_PLL_SVS */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_MX_NUM, 1,
+					vdd_pll_levels, NULL);
+
+#define VDD_MX_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_mx,                  \
+	.fmax = (unsigned long[VDD_MX_NUM]) {   \
+		[VDD_MX_##l1] = (f1),           \
+		[VDD_MX_##l2] = (f2),           \
+	},                                      \
+	.num_fmax = VDD_MX_NUM
+
+#define VDD_MX_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_mx,                  \
+	.fmax = (unsigned long[VDD_MX_NUM]) {   \
+		[VDD_MX_##l1] = (f1),           \
+	},                                      \
+	.num_fmax = VDD_MX_NUM
+
+static void __iomem *virt_bases[N_PLL_BASES];
+
+/* Power PLL */
+static struct pll_clk apcs_c0_pll = {
+	.mode_reg = (void __iomem *)APCS_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_PLL_L_VAL,
+	.alpha_reg = (void __iomem *)APCS_PLL_ALPHA_VAL,
+	.config_reg = (void __iomem *)APCS_PLL_USER_CTL,
+	.config_ctl_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_LO,
+	.config_ctl_hi_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_HI,
+	.test_ctl_lo_reg = (void __iomem *)APCS_PLL_TEST_CTL_LO,
+	.test_ctl_hi_reg = (void __iomem *)APCS_PLL_TEST_CTL_HI,
+	.status_reg = (void __iomem *)APCS_PLL_MODE,
+	.init_test_ctl = true,
+	.test_ctl_dbg = true,
+	.masks = {
+		.main_output_mask = BIT(0),
+		.early_output_mask = BIT(3),
+		.lock_mask = BIT(31),
+	},
+	.vals = {
+		.config_ctl_val = 0x200D4828,
+		.config_ctl_hi_val = 0x006,
+		.test_ctl_hi_val = 0x00004000,
+		.test_ctl_lo_val = 0x1C000000,
+	},
+	.max_rate = 1785600000UL,
+	.min_rate = 614400000UL,
+	.src_rate =  19200000UL,
+	.base = &virt_bases[APCS_C0_PLL_BASE],
+	.c = {
+		.parent = &xo_a_clk.c,
+		.dbg_name = "apcs_c0_pll",
+		.ops = &clk_ops_variable_rate,
+		VDD_MX_FMAX_MAP2(MIN, 1200000000UL, LOWER, 2400000000UL),
+		CLK_INIT(apcs_c0_pll.c),
+	},
+};
+
+/* Perf PLL */
+static struct pll_clk apcs_c1_pll = {
+	.mode_reg = (void __iomem *)APCS_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_PLL_L_VAL,
+	.alpha_reg = (void __iomem *)APCS_PLL_ALPHA_VAL,
+	.config_reg = (void __iomem *)APCS_PLL_USER_CTL,
+	.config_ctl_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_LO,
+	.config_ctl_hi_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_HI,
+	.test_ctl_lo_reg = (void __iomem *)APCS_PLL_TEST_CTL_LO,
+	.test_ctl_hi_reg = (void __iomem *)APCS_PLL_TEST_CTL_HI,
+	.status_reg = (void __iomem *)APCS_PLL_MODE,
+	.init_test_ctl = true,
+	.test_ctl_dbg = true,
+	.masks = {
+		.main_output_mask = BIT(0),
+		.early_output_mask = BIT(3),
+		.lock_mask = BIT(31),
+	},
+	.vals = {
+		.config_ctl_val = 0x200D4828,
+		.config_ctl_hi_val = 0x006,
+		.test_ctl_hi_val = 0x00004000,
+		.test_ctl_lo_val = 0x1C000000,
+	},
+	.max_rate = 2054400000UL,
+	.min_rate = 633600000UL,
+	.src_rate =  19200000UL,
+	.base = &virt_bases[APCS_C1_PLL_BASE],
+	.c = {
+		.parent = &xo_a_clk.c,
+		.dbg_name = "apcs_c1_pll",
+		.ops = &clk_ops_variable_rate,
+		VDD_MX_FMAX_MAP2(MIN, 1200000000UL, LOWER, 2400000000UL),
+		CLK_INIT(apcs_c1_pll.c),
+	},
+};
+
+static struct alpha_pll_masks pll_masks_p = {
+	.lock_mask = BIT(31),
+	.update_mask = BIT(22),
+	.output_mask = 0xf,
+	.vco_mask = BM(21, 20) >> 20,
+	.vco_shift = 20,
+	.alpha_en_mask = BIT(24),
+	.cal_l_val_mask = BM(31, 16),
+};
+
+static struct alpha_pll_vco_tbl apcs_cci_pll_vco[] = {
+	VCO(2, 500000000, 1000000000),
+};
+
+static struct alpha_pll_clk apcs_cci_pll = {
+	.masks = &pll_masks_p,
+	.offset = 0x1D0000,
+	.vco_tbl = apcs_cci_pll_vco,
+	.num_vco = ARRAY_SIZE(apcs_cci_pll_vco),
+	.enable_config = 0x8,  /* Early output */
+	.slew = true,
+	.config_ctl_val = 0x4001055b,
+	.cal_l_val = 0x27 << 16,  /* Mid of VCO mode - 748.8MHz */
+	.base = &virt_bases[APCS_CCI_PLL_BASE],
+	.c = {
+		.parent = &xo_a_clk.c,
+		.rate = 787200000,
+		.dbg_name = "apcs_cci_pll",
+		.ops = &clk_ops_dyna_alpha_pll,
+		/* TODO: FMAX */
+		VDD_MX_FMAX_MAP1(SVS, 1000000000UL),
+		CLK_INIT(apcs_cci_pll.c),
+	},
+};
+
+enum {
+	A53SS_MUX_PERF,
+	A53SS_MUX_PWR,
+	A53SS_MUX_CCI,
+	A53SS_MUX_NUM,
+};
+
+static const char * const pll_names[] = { "c1", "c0", "cci" };
+static const char * const mux_names[] = { "c1", "c0", "cci" };
+
+struct a53_cpu_clk {
+	u32 cpu_reg_mask;
+	cpumask_t cpumask;
+	bool hw_low_power_ctrl;
+	struct pm_qos_request req;
+	struct clk c;
+	struct latency_level latency_lvl;
+	s32 cpu_latency_no_l2_pc_us;
+};
+
+static struct mux_div_clk a53ssmux_perf = {
+	.ops = &rcg_mux_div_ops,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_perf",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_perf.c),
+	},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+	MUX_SRC_LIST(
+		{ &apcs_c1_pll.c, 5},
+	),
+};
+
+static struct mux_div_clk a53ssmux_pwr = {
+	.ops = &rcg_mux_div_ops,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_pwr",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_pwr.c),
+	},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+	MUX_SRC_LIST(
+		{ &apcs_c0_pll.c, 5},
+	),
+};
+
+static struct mux_div_clk a53ssmux_cci = {
+	.ops = &rcg_mux_div_ops,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_cci",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_cci.c),
+	},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+	MUX_SRC_LIST(
+		{ &apcs_cci_pll.c, 5},
+	),
+};
+
+static struct a53_cpu_clk a53_pwr_clk;
+static struct a53_cpu_clk a53_perf_clk;
+static struct a53_cpu_clk a53_cci_clk;
+
+static void do_nothing(void *unused) { }
+
+static inline struct a53_cpu_clk *to_a53_cpu_clk(struct clk *c)
+{
+	return container_of(c, struct a53_cpu_clk, c);
+}
+
+static enum handoff a53_cpu_clk_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	return HANDOFF_DISABLED_CLK;
+}
+
+static long a53_cpu_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int a53_cpu_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	struct a53_cpu_clk *cpuclk = to_a53_cpu_clk(c);
+	bool hw_low_power_ctrl = cpuclk->hw_low_power_ctrl;
+
+	/*
+	 * If hardware control of the clock tree is enabled during power
+	 * collapse, setup a PM QOS request to prevent power collapse and
+	 * wake up one of the CPUs in this clock domain, to ensure software
+	 * control while the clock rate is being switched.
+	 */
+	if (hw_low_power_ctrl) {
+		memset(&cpuclk->req, 0, sizeof(cpuclk->req));
+		cpumask_copy(&cpuclk->req.cpus_affine,
+				(const struct cpumask *)&cpuclk->cpumask);
+		cpuclk->req.type = PM_QOS_REQ_AFFINE_CORES;
+		pm_qos_add_request(&cpuclk->req, PM_QOS_CPU_DMA_LATENCY,
+				cpuclk->cpu_latency_no_l2_pc_us - 1);
+		smp_call_function_any(&cpuclk->cpumask, do_nothing,
+				NULL, 1);
+	}
+
+	ret = clk_set_rate(c->parent, rate);
+
+	/* Remove PM QOS request */
+	if (hw_low_power_ctrl)
+		pm_qos_remove_request(&cpuclk->req);
+
+	return ret;
+}
+
+static void __iomem *variable_pll_list_registers(struct clk *c, int n,
+				struct clk_register_data **regs, u32 *size)
+{
+	struct pll_clk *pll = to_pll_clk(c);
+	static struct clk_register_data data[] = {
+		{"MODE", 0x0},
+		{"L", 0x8},
+		{"ALPHA", 0x10},
+		{"USER_CTL", 0x18},
+		{"CONFIG_CTL_LO", 0x20},
+		{"CONFIG_CTL_HI", 0x24},
+		{"STATUS", 0x28},
+	};
+	if (n)
+		return ERR_PTR(-EINVAL);
+
+	*regs = data;
+	*size = ARRAY_SIZE(data);
+	return PLL_MODE(pll);
+}
+
+static const struct clk_ops clk_ops_cpu = {
+	.set_rate = a53_cpu_clk_set_rate,
+	.round_rate = a53_cpu_clk_round_rate,
+	.handoff = a53_cpu_clk_handoff,
+};
+
+static struct a53_cpu_clk a53_perf_clk = {
+	.cpu_reg_mask = 0x103,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "perf",
+	},
+	.cpu_latency_no_l2_pc_us = 280,
+	.c = {
+		.parent = &a53ssmux_perf.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu,
+		.dbg_name = "a53_perf_clk",
+		CLK_INIT(a53_perf_clk.c),
+	},
+};
+
+static struct a53_cpu_clk a53_pwr_clk = {
+	.cpu_reg_mask = 0x3,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "pwr",
+	},
+	.cpu_latency_no_l2_pc_us = 280,
+	.c = {
+		.parent = &a53ssmux_pwr.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu,
+		.dbg_name = "a53_pwr_clk",
+		CLK_INIT(a53_pwr_clk.c),
+	},
+};
+
+static struct a53_cpu_clk a53_cci_clk = {
+	.c = {
+		.parent = &a53ssmux_cci.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu,
+		.dbg_name = "a53_cci_clk",
+		CLK_INIT(a53_cci_clk.c),
+	},
+};
+
+static void __iomem *meas_base;
+
+static struct measure_clk apc0_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc0_m_clk",
+		CLK_INIT(apc0_m_clk.c),
+	},
+};
+
+static struct measure_clk apc1_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc1_m_clk",
+		CLK_INIT(apc1_m_clk.c),
+	},
+};
+
+static struct measure_clk cci_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "cci_m_clk",
+		CLK_INIT(cci_m_clk.c),
+	},
+};
+
+static struct mux_clk cpu_debug_ter_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 8,
+	MUX_SRC_LIST(
+		{ &apc0_m_clk.c, 0},
+		{ &apc1_m_clk.c, 1},
+		{ &cci_m_clk.c,  2},
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "cpu_debug_ter_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(cpu_debug_ter_mux.c),
+	},
+};
+
+static struct mux_clk cpu_debug_sec_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x7,
+	.shift = 12,
+	MUX_SRC_LIST(
+		{ &cpu_debug_ter_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&cpu_debug_ter_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "cpu_debug_sec_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(cpu_debug_sec_mux.c),
+	},
+};
+
+static struct mux_clk cpu_debug_pri_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 16,
+	MUX_SRC_LIST(
+		{ &cpu_debug_sec_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&cpu_debug_sec_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "cpu_debug_pri_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(cpu_debug_pri_mux.c),
+	},
+};
+
+static struct clk_lookup a53_cpu_clocks[] = {
+	/* PLLs */
+	CLK_LIST(apcs_c0_pll),
+	CLK_LIST(apcs_c1_pll),
+	CLK_LIST(apcs_cci_pll),
+
+	/* Muxes */
+	CLK_LIST(a53ssmux_pwr),
+	CLK_LIST(a53ssmux_perf),
+	CLK_LIST(a53ssmux_cci),
+
+	/* CPU clocks */
+	CLK_LIST(a53_pwr_clk),
+	CLK_LIST(a53_perf_clk),
+	CLK_LIST(a53_cci_clk),
+
+	/* debug clocks */
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(cci_m_clk),
+	CLK_LIST(cpu_debug_pri_mux),
+};
+
+static struct pll_clk *a53sspll[] = { &apcs_c1_pll, &apcs_c0_pll };
+
+static struct mux_div_clk *a53ssmux[] = { &a53ssmux_perf, &a53ssmux_pwr,
+						&a53ssmux_cci };
+
+static struct a53_cpu_clk *cpuclk[] = { &a53_perf_clk, &a53_pwr_clk,
+						&a53_cci_clk };
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+	struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
+	u32 reg;
+
+	if (cpu_node && !of_property_read_u32(cpu_node, "reg", &reg)) {
+		if ((reg | a53_pwr_clk.cpu_reg_mask) ==
+						a53_pwr_clk.cpu_reg_mask)
+			return &a53_pwr_clk.c;
+		if ((reg | a53_perf_clk.cpu_reg_mask) ==
+						a53_perf_clk.cpu_reg_mask)
+			return &a53_perf_clk.c;
+	}
+
+	return NULL;
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+								char *prop_name)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int prop_len, i;
+	struct clk_vdd_class *vdd = c->vdd_class;
+	u32 *array;
+
+	if (!of_find_property(of, prop_name, &prop_len)) {
+		dev_err(&pdev->dev, "missing %s\n", prop_name);
+		return -EINVAL;
+	}
+
+	prop_len /= sizeof(u32);
+	if (prop_len % 2) {
+		dev_err(&pdev->dev, "bad length %d\n", prop_len);
+		return -EINVAL;
+	}
+
+	prop_len /= 2;
+	vdd->level_votes = devm_kzalloc(&pdev->dev,
+				prop_len * sizeof(*vdd->level_votes),
+					GFP_KERNEL);
+	if (!vdd->level_votes)
+		return -ENOMEM;
+
+	vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+					GFP_KERNEL);
+	if (!vdd->vdd_uv)
+		return -ENOMEM;
+
+	c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+					GFP_KERNEL);
+	if (!c->fmax)
+		return -ENOMEM;
+
+	array = devm_kzalloc(&pdev->dev,
+			prop_len * sizeof(u32) * 2, GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+	for (i = 0; i < prop_len; i++) {
+		c->fmax[i] = array[2 * i];
+		vdd->vdd_uv[i] = array[2 * i + 1];
+	}
+
+	devm_kfree(&pdev->dev, array);
+	vdd->num_levels = prop_len;
+	vdd->cur_level = prop_len;
+	vdd->use_max_uV = true;
+	c->num_fmax = prop_len;
+	return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin,
+								int *version)
+{
+	struct resource *res;
+	void __iomem *base;
+	u32 pte_efuse;
+
+	*bin = 0;
+	*version = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	*bin = (pte_efuse >> 8) & 0x7;
+
+	dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+								*version);
+}
+
+static int cpu_parse_pll_data(struct platform_device *pdev, int pll_count)
+{
+	int pll_num;
+	struct resource *res;
+	struct clk *c;
+	char pll_name[] = "apcs-xxx-pll-base";
+
+	for (pll_num = 0; pll_num < pll_count; pll_num++) {
+		snprintf(pll_name, ARRAY_SIZE(pll_name), "apcs-%s-pll-base",
+						pll_names[pll_num]);
+
+		res = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, pll_name);
+		if (!res) {
+			dev_err(&pdev->dev, "missing %s\n", pll_name);
+			return -EINVAL;
+		}
+
+		if (pll_num < APCS_CCI_PLL_BASE) {
+			a53sspll[pll_num]->base = devm_ioremap(&pdev->dev,
+					res->start, resource_size(res));
+			if (!a53sspll[pll_num]->base) {
+				dev_err(&pdev->dev, "ioremap failed for %s\n",
+								pll_name);
+				return -ENOMEM;
+			}
+		} else {
+			apcs_cci_pll.base = devm_ioremap(&pdev->dev,
+				res->start, resource_size(res));
+			if (!apcs_cci_pll.base) {
+				dev_err(&pdev->dev, "ioremap failed for %s\n",
+					pll_name);
+				return -ENOMEM;
+			}
+		}
+	}
+
+	c = devm_clk_get(&pdev->dev, "xo_a");
+	if (IS_ERR(c)) {
+		if (PTR_ERR(c) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Unable to get xo clock\n");
+		return PTR_ERR(c);
+	}
+	xo_a_clk.c.parent = c;
+
+	return 0;
+}
+
+static int cpu_parse_devicetree(struct platform_device *pdev, int mux_id)
+{
+	struct resource *res;
+	char rcg_name[] = "apcs-xxx-rcg-base";
+	char vdd_name[] = "vdd-xxx";
+	struct regulator *regulator;
+
+	snprintf(rcg_name, ARRAY_SIZE(rcg_name), "apcs-%s-rcg-base",
+						mux_names[mux_id]);
+
+	res = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, rcg_name);
+	if (!res) {
+		dev_err(&pdev->dev, "missing %s\n", rcg_name);
+		return -EINVAL;
+	}
+
+	a53ssmux[mux_id]->base = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!a53ssmux[mux_id]->base) {
+		dev_err(&pdev->dev, "ioremap failed for %s\n", rcg_name);
+		return -ENOMEM;
+	}
+
+	snprintf(vdd_name, ARRAY_SIZE(vdd_name), "vdd-%s", mux_names[mux_id]);
+	regulator = devm_regulator_get(&pdev->dev, vdd_name);
+	if (IS_ERR(regulator)) {
+		if (PTR_ERR(regulator) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "unable to get regulator\n");
+		return PTR_ERR(regulator);
+	}
+
+	cpuclk[mux_id]->c.vdd_class->regulator[0] = regulator;
+
+	return 0;
+}
+
+static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
+			unsigned long max_rate)
+{
+	unsigned long rate = 0;
+	int level;
+	long ret, uv, corner;
+	int j = 1;
+
+	while (1) {
+		rate = c->fmax[j++];
+
+		level = find_vdd_level(c, rate);
+		if (level <= 0) {
+			pr_warn("clock-cpu: no vdd level for %lu.\n", rate);
+			return -EINVAL;
+		}
+
+		corner = c->vdd_class->vdd_uv[level];
+		if (corner < 0)
+			return -EINVAL;
+
+		/* Get actual voltage corresponding to each corner */
+		uv = regulator_list_corner_voltage(c->vdd_class->regulator[0],
+							corner);
+		if (uv < 0) {
+			pr_warn("%s: no uv for corner %ld - err: %ld\n",
+						c->dbg_name, corner, uv);
+			return uv;
+		}
+
+		/*
+		 * Populate both CPU and regulator devices with the
+		 * freq-to-corner OPP table to maintain backward
+		 * compatibility.
+		 */
+		ret = dev_pm_opp_add(cpudev, rate, uv);
+		if (ret) {
+			pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+				rate);
+			return ret;
+		}
+
+		ret = dev_pm_opp_add(vregdev, rate, uv);
+		if (ret) {
+			pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+				rate);
+			return ret;
+		}
+
+		if (rate >= max_rate)
+			break;
+	}
+
+	return 0;
+}
+
+static void print_opp_table(int a53_c0_cpu, int a53_c1_cpu)
+{
+	struct dev_pm_opp *oppfmax, *oppfmin;
+	unsigned long apc0_fmax, apc1_fmax, apc0_fmin, apc1_fmin;
+
+	apc0_fmax = a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1];
+	apc0_fmin = a53_pwr_clk.c.fmax[1];
+	apc1_fmax = a53_perf_clk.c.fmax[a53_perf_clk.c.num_fmax - 1];
+	apc1_fmin = a53_perf_clk.c.fmax[1];
+
+	rcu_read_lock();
+	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmax, true);
+	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmin, true);
+	/*
+	 * One time information during boot. Important to know that this
+	 * looks sane since it can eventually make its way to the
+	 * scheduler.
+	 */
+	pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmin, dev_pm_opp_get_voltage(oppfmin));
+	pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmax, dev_pm_opp_get_voltage(oppfmax));
+
+	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmax, true);
+	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmin, true);
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmin,
+		dev_pm_opp_get_voltage(oppfmin));
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmax,
+		dev_pm_opp_get_voltage(oppfmax));
+	rcu_read_unlock();
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+	struct platform_device *apc0_dev, *apc1_dev;
+	struct device_node *apc0_node = NULL, *apc1_node;
+	unsigned long apc0_fmax, apc1_fmax;
+	int cpu, a53_c0_cpu = 0, a53_c1_cpu = 0;
+
+	apc0_node = of_parse_phandle(pdev->dev.of_node,
+						"vdd-c0-supply", 0);
+	if (!apc0_node) {
+		pr_err("can't find the apc0 dt node.\n");
+		return;
+	}
+
+	apc1_node = of_parse_phandle(pdev->dev.of_node, "vdd-c1-supply", 0);
+	if (!apc1_node) {
+		pr_err("can't find the apc1 dt node.\n");
+		return;
+	}
+
+	apc0_dev = of_find_device_by_node(apc0_node);
+	if (!apc0_dev) {
+		pr_err("can't find the apc0 device node.\n");
+		return;
+	}
+
+	apc1_dev = of_find_device_by_node(apc1_node);
+	if (!apc1_dev) {
+		pr_err("can't find the apc1 device node.\n");
+		return;
+	}
+
+	apc0_fmax = a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1];
+
+	apc1_fmax = a53_perf_clk.c.fmax[a53_perf_clk.c.num_fmax - 1];
+
+	for_each_possible_cpu(cpu) {
+		if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c) {
+			a53_c0_cpu = cpu;
+			WARN(add_opp(&a53_pwr_clk.c, get_cpu_device(cpu),
+			&apc0_dev->dev,		apc0_fmax),
+				"Failed to add OPP levels for %d\n", cpu);
+		}
+		if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c) {
+			a53_c1_cpu = cpu;
+			WARN(add_opp(&a53_perf_clk.c, get_cpu_device(cpu),
+			&apc1_dev->dev,		apc1_fmax),
+				"Failed to add OPP levels for %d\n", cpu);
+		}
+	}
+	/* One time print during bootup */
+	pr_info("clock-cpu: OPP tables populated (cpu %d and %d)",
+		a53_c0_cpu, a53_c1_cpu);
+
+	print_opp_table(a53_c0_cpu, a53_c1_cpu);
+
+}
+
+static int clock_sdm632_pm_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		clk_unprepare(&a53_pwr_clk.c);
+		clk_unprepare(&a53_perf_clk.c);
+		clk_unprepare(&a53_cci_clk.c);
+		break;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		clk_prepare(&a53_pwr_clk.c);
+		clk_prepare(&a53_perf_clk.c);
+		clk_prepare(&a53_cci_clk.c);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block clock_sdm632_pm_notifier = {
+	.notifier_call = clock_sdm632_pm_event,
+};
+
+/**
+ * clock_panic_callback() - panic notification callback function.
+ *		This function is invoked when a kernel panic occurs.
+ * @nfb:	Notifier block pointer
+ * @event:	Value passed unmodified to notifier function
+ * @data:	Pointer passed unmodified to notifier function
+ *
+ * Return: NOTIFY_OK
+ */
+static int clock_panic_callback(struct notifier_block *nfb,
+					unsigned long event, void *data)
+{
+	unsigned long rate;
+
+	rate  = (a53_perf_clk.c.count) ? a53_perf_clk.c.rate : 0;
+	pr_err("%s frequency: %10lu Hz\n", a53_perf_clk.c.dbg_name, rate);
+
+	rate  = (a53_pwr_clk.c.count) ? a53_pwr_clk.c.rate : 0;
+	pr_err("%s frequency: %10lu Hz\n", a53_pwr_clk.c.dbg_name, rate);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block clock_panic_notifier = {
+	.notifier_call = clock_panic_callback,
+	.priority = 1,
+};
+
+/* Configure PLL at Nominal frequency */
+static unsigned long pwrcl_early_boot_rate = 1363200000;
+static unsigned long perfcl_early_boot_rate = 1401600000;
+static unsigned long cci_early_boot_rate = 691200000;
+
+static int clock_a53_probe(struct platform_device *pdev)
+{
+	int speed_bin, version, rc, cpu, mux_id;
+	char prop_name[] = "qcom,speedX-bin-vX-XXX";
+	int mux_num = A53SS_MUX_NUM;
+
+	get_speed_bin(pdev, &speed_bin, &version);
+
+	rc = cpu_parse_pll_data(pdev, N_PLL_BASES);
+	if (rc)
+		return rc;
+
+	/* PLL core logic */
+	vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd-mx");
+	if (IS_ERR(vdd_mx.regulator[0])) {
+		dev_err(&pdev->dev, "Get vdd-mx regulator!!!\n");
+		if (PTR_ERR(vdd_mx.regulator[0]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Unable to get vdd-mx regulator!!!\n");
+		return PTR_ERR(vdd_mx.regulator[0]);
+	}
+
+	for (mux_id = 0; mux_id < mux_num; mux_id++) {
+		rc = cpu_parse_devicetree(pdev, mux_id);
+		if (rc)
+			return rc;
+
+		snprintf(prop_name, ARRAY_SIZE(prop_name),
+					"qcom,speed%d-bin-v%d-%s",
+					speed_bin, version, mux_names[mux_id]);
+
+		rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+		if (rc) {
+			/* Fall back to most conservative PVS table */
+			dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+								prop_name);
+
+			snprintf(prop_name, ARRAY_SIZE(prop_name),
+				"qcom,speed0-bin-v0-%s", mux_names[mux_id]);
+			rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+			if (rc) {
+				dev_err(&pdev->dev,
+					"Unable to load safe voltage plan\n");
+				return rc;
+			}
+			dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+		}
+	}
+
+	/* Debug MUX */
+	meas_base = devm_ioremap(&pdev->dev, GLB_DIAG, SZ_8);
+	if (!meas_base) {
+		dev_err(&pdev->dev, "Failed to ioremap GLB_DIAG registers\n");
+		return -ENOMEM;
+	}
+
+	rc = of_msm_clock_register(pdev->dev.of_node, a53_cpu_clocks,
+						ARRAY_SIZE(a53_cpu_clocks));
+
+	if (rc) {
+		dev_err(&pdev->dev, "msm_clock_register failed\n");
+		return rc;
+	}
+
+	/* Force to move to PLL configuartion */
+	rc = clk_set_rate(&a53_cci_clk.c, cci_early_boot_rate);
+	if (rc)
+		dev_err(&pdev->dev, "Can't set CCI PLL rate for CCI\n");
+
+	rc = clk_set_rate(&a53_pwr_clk.c, pwrcl_early_boot_rate);
+	if (rc)
+		dev_err(&pdev->dev, "Can't set pwr PLL rate for Cluster-0 %ld\n",
+					pwrcl_early_boot_rate);
+
+	rc = clk_set_rate(&a53_perf_clk.c, perfcl_early_boot_rate);
+	if (rc)
+		dev_err(&pdev->dev, "Can't set perf PLL rate for Cluster-1 %ld\n",
+					perfcl_early_boot_rate);
+
+	rc = clock_rcgwr_init(pdev);
+	if (rc)
+		dev_err(&pdev->dev, "Failed to init RCGwR\n");
+
+	/*
+	 * We don't want the CPU clocks to be turned off at late init
+	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
+	 * that the clocks have already been prepared and enabled by the time
+	 * they take over.
+	 */
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		WARN(clk_prepare_enable(&cpuclk[cpu/4]->c),
+				"Unable to turn on CPU clock");
+		WARN(clk_prepare_enable(&a53_cci_clk.c),
+				"Unable to turn on CCI clock");
+	}
+	put_online_cpus();
+
+	for_each_possible_cpu(cpu) {
+		if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c)
+			cpumask_set_cpu(cpu, &a53_perf_clk.cpumask);
+		if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c)
+			cpumask_set_cpu(cpu, &a53_pwr_clk.cpumask);
+	}
+
+	a53_pwr_clk.hw_low_power_ctrl = true;
+	a53_perf_clk.hw_low_power_ctrl = true;
+
+	register_pm_notifier(&clock_sdm632_pm_notifier);
+
+	populate_opp_table(pdev);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&clock_panic_notifier);
+
+	return 0;
+}
+
+static const struct of_device_id clock_a53_match_table[] = {
+	{.compatible = "qcom,cpu-clock-sdm632"},
+	{}
+};
+
+static struct platform_driver clock_a53_driver = {
+	.probe = clock_a53_probe,
+	.driver = {
+		.name = "cpu-clock-sdm632",
+		.of_match_table = clock_a53_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clock_a53_init(void)
+{
+	return platform_driver_register(&clock_a53_driver);
+}
+arch_initcall(clock_a53_init);
+
+static int __init clock_cpu_lpm_get_latency(void)
+{
+	int rc = 0;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+					"qcom,cpu-clock-sdm632");
+
+	if (!ofnode)
+		return 0;
+
+	rc = lpm_get_latency(&a53_perf_clk.latency_lvl,
+			&a53_perf_clk.cpu_latency_no_l2_pc_us);
+	if (rc < 0)
+		pr_err("Failed to get the L2 PC value for perf\n");
+
+	rc = lpm_get_latency(&a53_pwr_clk.latency_lvl,
+			&a53_pwr_clk.cpu_latency_no_l2_pc_us);
+	if (rc < 0)
+		pr_err("Failed to get the L2 PC value for pwr\n");
+
+	pr_debug("Latency for pwr/perf cluster %d : %d\n",
+		a53_pwr_clk.cpu_latency_no_l2_pc_us,
+		a53_perf_clk.cpu_latency_no_l2_pc_us);
+
+	return rc;
+}
+late_initcall(clock_cpu_lpm_get_latency);
+
+#define PWR_PLL_BASE			0xb116000
+#define PERF_PLL_BASE			0xb016000
+#define CCI_PLL_BASE			0xb1d0000
+#define APCS_ALIAS1_CMD_RCGR		0xb011050
+#define APCS_ALIAS1_CFG_OFF		0x4
+#define APCS_ALIAS1_CORE_CBCR_OFF	0x8
+#define SRC_SEL				0x4
+#define SRC_DIV				0x1
+
+static int __init cpu_clock_init(void)
+{
+	void __iomem  *base;
+	int regval = 0, count;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+						"qcom,cpu-clock-sdm632");
+	if (!ofnode)
+		return 0;
+
+	virt_bases[APCS_C0_PLL_BASE] = ioremap_nocache(PWR_PLL_BASE, SZ_1K);
+	virt_bases[APCS_C1_PLL_BASE] = ioremap_nocache(PERF_PLL_BASE, SZ_1K);
+	virt_bases[APCS_CCI_PLL_BASE] = ioremap_nocache(CCI_PLL_BASE, SZ_1K);
+	clk_ops_variable_rate = clk_ops_variable_rate_pll_hwfsm;
+	clk_ops_variable_rate.list_registers = variable_pll_list_registers;
+
+	/* Initialize the PLLs */
+	__variable_rate_pll_init(&apcs_c0_pll.c);
+	__variable_rate_pll_init(&apcs_c1_pll.c);
+	__init_alpha_pll(&apcs_cci_pll.c);
+
+	/* Enable the PLLs */
+	apcs_c0_pll.c.ops->set_rate(&apcs_c0_pll.c, pwrcl_early_boot_rate);
+	clk_ops_variable_rate_pll.enable(&apcs_c0_pll.c);
+
+	apcs_c1_pll.c.ops->set_rate(&apcs_c1_pll.c, perfcl_early_boot_rate);
+	clk_ops_variable_rate_pll.enable(&apcs_c1_pll.c);
+
+	apcs_cci_pll.c.ops->set_rate(&apcs_cci_pll.c, cci_early_boot_rate);
+	clk_ops_dyna_alpha_pll.enable(&apcs_cci_pll.c);
+
+	base = ioremap_nocache(APCS_ALIAS1_CMD_RCGR, SZ_8);
+	regval = readl_relaxed(base);
+
+	/* Source from GPLL0 */
+	regval = (SRC_SEL << 8) | SRC_DIV; /* 0x401 */
+	writel_relaxed(regval, base + APCS_ALIAS1_CFG_OFF);
+	/* Make sure src sel and src div is set before update bit */
+	mb();
+
+	/* update bit */
+	regval = readl_relaxed(base);
+	regval |= BIT(0);
+	writel_relaxed(regval, base);
+	/* Make sure src sel and src div is set before update bit */
+	mb();
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		if (!(readl_relaxed(base)) & BIT(0))
+			break;
+		udelay(1);
+	}
+
+	/* Enable the branch */
+	regval =  readl_relaxed(base + APCS_ALIAS1_CORE_CBCR_OFF);
+	regval |= BIT(0);
+	writel_relaxed(regval, base + APCS_ALIAS1_CORE_CBCR_OFF);
+
+	/* Branch enable should be complete */
+	mb();
+	iounmap(base);
+
+	pr_info("CPU clocks configured\n");
+
+	return 0;
+}
+early_initcall(cpu_clock_init);
diff --git a/drivers/clk/msm/clock-gcc-8909.c b/drivers/clk/msm/clock-gcc-8909.c
new file mode 100644
index 0000000..54d8d56
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-8909.c
@@ -0,0 +1,2919 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-voter.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8909.h>
+
+#include "clock.h"
+#include "reset.h"
+
+enum {
+	GCC_BASE,
+	APCS_PLL_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+#define GPLL0_MODE					0x21000
+#define GPLL0_L_VAL					0x21004
+#define GPLL0_ALPHA_VAL					0x21008
+#define GPLL0_ALPHA_VAL_U				0x2100C
+#define GPLL0_USER_CTL					0x21010
+#define GPLL0_CONFIG_CTL				0x21018
+#define GPLL0_STATUS					0x21024
+#define GPLL1_MODE					0x20000
+#define GPLL1_L_VAL					0x20004
+#define GPLL1_M_VAL					0x20008
+#define GPLL1_N_VAL					0x2000C
+#define GPLL1_USER_CTL					0x20010
+#define GPLL1_CONFIG_CTL				0x20014
+#define GPLL1_STATUS					0x2001C
+#define GPLL2_MODE					0x25000
+#define GPLL2_L_VAL					0x25004
+#define GPLL2_ALPHA_VAL					0x25008
+#define GPLL2_ALPHA_VAL_U				0x2500C
+#define GPLL2_USER_CTL					0x25010
+#define GPLL2_CONFIG_CTL				0x25018
+#define GPLL2_STATUS					0x25024
+#define SNOC_QOSGEN					0x2601C
+#define MSS_CFG_AHB_CBCR				0x49000
+#define MSS_Q6_BIMC_AXI_CBCR				0x49004
+#define QPIC_AHB_CBCR					0x3F01C
+#define USB_HS_BCR					0x41000
+#define USB_HS_SYSTEM_CBCR				0x41004
+#define USB_HS_AHB_CBCR					0x41008
+#define USB_HS_SYSTEM_CMD_RCGR				0x41010
+#define USB2A_PHY_SLEEP_CBCR				0x4102C
+#define USB_HS_PHY_CFG_AHB_CBCR				0x41030
+#define USB2_HS_PHY_ONLY_BCR				0x41034
+#define QUSB2_PHY_BCR					0x4103C
+#define SDCC1_APPS_CMD_RCGR				0x42004
+#define SDCC1_APPS_CBCR					0x42018
+#define SDCC1_AHB_CBCR					0x4201C
+#define SDCC2_APPS_CMD_RCGR				0x43004
+#define SDCC2_APPS_CBCR					0x43018
+#define SDCC2_AHB_CBCR					0x4301C
+#define BLSP1_AHB_CBCR					0x01008
+#define BLSP1_QUP1_SPI_APPS_CBCR			0x02004
+#define BLSP1_QUP1_I2C_APPS_CBCR			0x02008
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR			0x0200C
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR			0x03000
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR			0x04000
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR			0x05000
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR			0x06000
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR			0x07000
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR			0x02024
+#define BLSP1_UART1_APPS_CBCR				0x0203C
+#define BLSP1_UART1_APPS_CMD_RCGR			0x02044
+#define BLSP1_QUP2_SPI_APPS_CBCR			0x0300C
+#define BLSP1_QUP2_I2C_APPS_CBCR			0x03010
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR			0x03014
+#define BLSP1_UART2_APPS_CBCR				0x0302C
+#define BLSP1_UART2_APPS_CMD_RCGR			0x03034
+#define BLSP1_QUP3_SPI_APPS_CBCR			0x0401C
+#define BLSP1_QUP3_I2C_APPS_CBCR			0x04020
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR			0x04024
+#define BLSP1_QUP4_SPI_APPS_CBCR			0x0501C
+#define BLSP1_QUP4_I2C_APPS_CBCR			0x05020
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR			0x05024
+#define BLSP1_QUP5_SPI_APPS_CBCR			0x0601C
+#define BLSP1_QUP5_I2C_APPS_CBCR			0x06020
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR			0x06024
+#define BLSP1_QUP6_SPI_APPS_CBCR			0x0701C
+#define BLSP1_QUP6_I2C_APPS_CBCR			0x07020
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR			0x07024
+#define PDM_AHB_CBCR					0x44004
+#define PDM2_CBCR					0x4400C
+#define PDM2_CMD_RCGR					0x44010
+#define PRNG_AHB_CBCR					0x13004
+#define BOOT_ROM_AHB_CBCR				0x1300C
+#define CRYPTO_CMD_RCGR					0x16004
+#define CRYPTO_CBCR					0x1601C
+#define CRYPTO_AXI_CBCR					0x16020
+#define CRYPTO_AHB_CBCR					0x16024
+#define GCC_XO_DIV4_CBCR				0x30034
+#define GFX_TBU_CBCR					0x12010
+#define VENUS_TBU_CBCR					0x12014
+#define MDP_TBU_CBCR					0x1201C
+#define APSS_TCU_CBCR					0x12018
+#define GFX_TCU_CBCR					0x12020
+#define MSS_TBU_AXI_CBCR				0x12024
+#define MSS_TBU_GSS_AXI_CBCR				0x12028
+#define MSS_TBU_Q6_AXI_CBCR				0x1202C
+#define SMMU_CFG_CBCR					0x12038
+#define VFE_TBU_CBCR					0x1203C
+#define GTCU_AHB_CBCR					0x12044
+#define GTCU_AHB_BRIDGE_CBCR				0x12094
+#define APCS_GPLL_ENA_VOTE				0x45000
+#define APCS_CLOCK_BRANCH_ENA_VOTE			0x45004
+#define APCS_CLOCK_SLEEP_ENA_VOTE			0x45008
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE			0x4500C
+#define APSS_AHB_CMD_RCGR				0x46000
+#define GCC_DEBUG_CLK_CTL				0x74000
+#define CLOCK_FRQ_MEASURE_CTL				0x74004
+#define CLOCK_FRQ_MEASURE_STATUS			0x74008
+#define GCC_PLLTEST_PAD_CFG				0x7400C
+#define GP1_CBCR					0x08000
+#define GP1_CMD_RCGR					0x08004
+#define GP2_CBCR					0x09000
+#define GP2_CMD_RCGR					0x09004
+#define GP3_CBCR					0x0A000
+#define GP3_CMD_RCGR					0x0A004
+#define VCODEC0_CMD_RCGR				0x4C000
+#define VENUS0_VCODEC0_CBCR				0x4C01C
+#define VENUS0_CORE0_VCODEC0_CBCR			0x4C02C
+#define VENUS0_AHB_CBCR					0x4C020
+#define VENUS0_AXI_CBCR					0x4C024
+#define PCLK0_CMD_RCGR					0x4D000
+#define MDP_CMD_RCGR					0x4D014
+#define VSYNC_CMD_RCGR					0x4D02C
+#define BYTE0_CMD_RCGR					0x4D044
+#define ESC0_CMD_RCGR					0x4D05C
+#define MDSS_BCR					0x4D074
+#define MDSS_AHB_CBCR					0x4D07C
+#define MDSS_AXI_CBCR					0x4D080
+#define MDSS_PCLK0_CBCR					0x4D084
+#define MDSS_MDP_CBCR					0x4D088
+#define MDSS_VSYNC_CBCR					0x4D090
+#define MDSS_BYTE0_CBCR					0x4D094
+#define MDSS_ESC0_CBCR					0x4D098
+#define CSI0PHYTIMER_CMD_RCGR				0x4E000
+#define CAMSS_CSI0PHYTIMER_CBCR				0x4E01C
+#define CSI1PHYTIMER_CMD_RCGR				0x4F000
+#define CAMSS_CSI1PHYTIMER_CBCR				0x4F01C
+#define CSI0_CMD_RCGR					0x4E020
+#define CAMSS_CSI0_CBCR					0x4E03C
+#define CAMSS_CSI0_AHB_CBCR				0x4E040
+#define CAMSS_CSI0PHY_CBCR				0x4E048
+#define CAMSS_CSI0RDI_CBCR				0x4E050
+#define CAMSS_CSI0PIX_CBCR				0x4E058
+#define CSI1_CMD_RCGR					0x4F020
+#define CAMSS_CSI1_CBCR					0x4F03C
+#define CAMSS_CSI1_AHB_CBCR				0x4F040
+#define CAMSS_CSI1PHY_CBCR				0x4F048
+#define CAMSS_CSI1RDI_CBCR				0x4F050
+#define CAMSS_CSI1PIX_CBCR				0x4F058
+#define CAMSS_ISPIF_AHB_CBCR				0x50004
+#define CCI_CMD_RCGR					0x51000
+#define CAMSS_CCI_CBCR					0x51018
+#define CAMSS_CCI_AHB_CBCR				0x5101C
+#define MCLK0_CMD_RCGR					0x52000
+#define CAMSS_MCLK0_CBCR				0x52018
+#define MCLK1_CMD_RCGR					0x53000
+#define CAMSS_MCLK1_CBCR				0x53018
+#define CAMSS_GP0_CMD_RCGR				0x54000
+#define CAMSS_GP0_CBCR					0x54018
+#define CAMSS_GP1_CMD_RCGR				0x55000
+#define CAMSS_GP1_CBCR					0x55018
+#define CAMSS_AHB_CBCR					0x5A014
+#define CAMSS_TOP_AHB_CBCR				0x56004
+#define VFE0_CMD_RCGR					0x58000
+#define CAMSS_VFE_BCR					0x58030
+#define CAMSS_VFE0_CBCR					0x58038
+#define CAMSS_VFE_AHB_CBCR				0x58044
+#define CAMSS_VFE_AXI_CBCR				0x58048
+#define CAMSS_CSI_VFE0_CBCR				0x58050
+#define GFX3D_CMD_RCGR					0x59000
+#define OXILI_GFX3D_CBCR				0x59020
+#define OXILI_AHB_CBCR					0x59028
+#define CAMSS_TOP_AHB_CMD_RCGR				0x5A000
+#define BIMC_GFX_CBCR					0x31024
+#define BIMC_GPU_CBCR					0x31040
+
+#define APCS_SH_PLL_MODE				0x00000
+#define APCS_SH_PLL_L_VAL				0x00004
+#define APCS_SH_PLL_M_VAL				0x00008
+#define APCS_SH_PLL_N_VAL				0x0000C
+#define APCS_SH_PLL_USER_CTL				0x00010
+#define APCS_SH_PLL_CONFIG_CTL				0x00014
+#define APCS_SH_PLL_STATUS				0x0001C
+
+/* Mux source select values */
+#define xo_source_val			0
+#define xo_a_source_val			0
+#define gpll0_source_val		1
+#define gpll0_aux_source_val		3
+#define gpll1_e_source_val              3
+#define gpll1_e_gfx3d_source_val	2
+#define gpll2_source_val		3
+#define dsi0_phypll_mm_source_val	1
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_MDSS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_APCS_PLL(f, l, m, n, pre_div, post_div, vco) \
+	{ \
+		.freq_hz = (f), \
+		.l_val = (l), \
+		.m_val = (m), \
+		.n_val = (n), \
+		.pre_div_val = BVAL(12, 12, (pre_div)), \
+		.post_div_val = BVAL(9, 8, (post_div)), \
+		.vco_val = BVAL(29, 28, (vco)), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+		[VDD_DIG_##l3] = (f3),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOWER,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_CORNER_NONE,              /* VDD_DIG_NONE */
+	RPM_REGULATOR_CORNER_SVS_KRAIT,         /* VDD_DIG_LOWER SVS */
+	RPM_REGULATOR_CORNER_SVS_SOC,           /* VDD_DIG_LOW SVS */
+	RPM_REGULATOR_CORNER_NORMAL,            /* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_CORNER_SUPER_TURBO,       /* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+DEFINE_EXT_CLK(xo_clk_src, NULL);
+DEFINE_EXT_CLK(xo_a_clk_src, NULL);
+DEFINE_EXT_CLK(rpm_debug_clk, NULL);
+DEFINE_EXT_CLK(apss_debug_clk, NULL);
+
+DEFINE_CLK_DUMMY(wcnss_m_clk, 0);
+
+enum vdd_sr2_pll_levels {
+	VDD_SR2_PLL_OFF,
+	VDD_SR2_PLL_SVS,
+	VDD_SR2_PLL_NOM,
+	VDD_SR2_PLL_TUR,
+	VDD_SR2_PLL_NUM,
+};
+
+static int vdd_sr2_levels[] = {
+	0,	 RPM_REGULATOR_CORNER_NONE,		/* VDD_SR2_PLL_OFF */
+	1800000, RPM_REGULATOR_CORNER_SVS_SOC,		/* VDD_SR2_PLL_SVS */
+	1800000, RPM_REGULATOR_CORNER_NORMAL,		/* VDD_SR2_PLL_NOM */
+	1800000, RPM_REGULATOR_CORNER_SUPER_TURBO,	/* VDD_SR2_PLL_TUR */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+				vdd_sr2_levels, NULL);
+
+static struct pll_freq_tbl apcs_pll_freq[] = {
+	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1248000000, 65, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1267200000, 66, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1305600000, 68, 0x0, 0x1, 0x0, 0x0, 0x0),
+	PLL_F_END
+};
+
+static struct pll_clk a7sspll = {
+	.mode_reg = (void __iomem *)APCS_SH_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_SH_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_SH_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_SH_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_SH_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_SH_PLL_STATUS,
+	.freq_tbl = apcs_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_PLL_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a7sspll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+			[VDD_SR2_PLL_SVS] = 1000000000,
+			[VDD_SR2_PLL_NOM] = 1900000000,
+		},
+		.num_fmax = VDD_SR2_PLL_NUM,
+		CLK_INIT(a7sspll.c),
+	},
+};
+
+static unsigned int soft_vote_gpll0;
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL0_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll0_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src.c),
+	},
+};
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 614400000,
+		.dbg_name = "gpll1_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll1_clk_src.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll1_e_clk_src, &gpll1_clk_src.c);
+DEFINE_EXT_CLK(gpll1_e_gfx3d_clk_src, &gpll1_clk_src.c);
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL2_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll2_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(3),
+	.status_reg = (void __iomem *)GPLL2_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 792000000,
+		.dbg_name = "gpll2_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_apss_ahb_clk[] = {
+	F( 19200000,	xo_a,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+	.cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_apss_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "apss_ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(apss_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_top_ahb_clk[] = {
+	F(  40000000,	   gpll0,  10,	  1,	2),
+	F(  80000000,	   gpll0,  10,	  0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_top_ahb_clk_src = {
+	.cmd_rcgr_reg = CAMSS_TOP_AHB_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_top_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 40000000, NOMINAL, 80000000),
+		CLK_INIT(camss_top_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_vfe0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000, HIGH,
+					320000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 307200000, gpll1_e,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg =  VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000, HIGH,
+					307200000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup2_spi_apps_clk[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 8000000,	gpll0,	10,	1,	10),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup2_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = {
+	F( 3686400,	gpll0,	1,	72,	15625),
+	F( 7372800,	gpll0,	1,	144,	15625),
+	F( 14745600,	gpll0,	1,	288,	15625),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 24000000,	gpll0,	1,	3,	100),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 32000000,	gpll0,	1,	1,	25),
+	F( 40000000,	gpll0,	1,	1,	20),
+	F( 46400000,	gpll0,	1,	29,	500),
+	F( 48000000,	gpll0,	1,	3,	50),
+	F( 51200000,	gpll0,	1,	8,	125),
+	F( 56000000,	gpll0,	1,	7,	100),
+	F( 58982400,	gpll0,	1,	1152,	15625),
+	F( 60000000,	gpll0,	1,	3,	40),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_gp0_1_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_gp0_clk_src = {
+	.cmd_rcgr_reg =  CAMSS_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(camss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk camss_gp1_clk_src = {
+	.cmd_rcgr_reg =  CAMSS_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(camss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclk0_1_clk[] = {
+	F( 24000000,	gpll2,	1,	1,	33),
+	F( 66670000,	gpll0,	12,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclkm_clk[] = {
+	F( 24000000,	gpll2,	2,	1,	19),
+	F( 66670000,	gpll0,	12,	0,	0),
+	F_END
+};
+
+static unsigned long mclk0_1_fmax[VDD_DIG_NUM] = {
+	0, 0, 0, 66670000, 0,
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg =  MCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg =  MCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_crypto_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+	.cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_crypto_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "crypto_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+		CLK_INIT(crypto_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+	F(   150000,    xo,     1,      1,      128),
+	F( 19200000,	xo,	1,	0,	  0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg =  GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg =  GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg =  GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_mm_source_val),
+	},
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.current_freq = ftbl_gcc_mdss_byte0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_byte,
+		VDD_DIG_FMAX_MAP1(LOWER, 125000000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_esc0_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_esc0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_mdp_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 307200000,	gpll1_e,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 160000000, LOW, 200000000, NOMINAL,
+			      307200000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_mm_source_val)
+					| BVAL(4, 0, 0),
+	},
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
+	.current_freq = ftbl_gcc_mdss_pclk0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_pixel,
+		VDD_DIG_FMAX_MAP1(LOWER, 83333333.33),
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_vsync_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = {
+	F( 19200000,	xo,		1,	0,	0),
+	F( 50000000,	gpll0,		16,	0,	0),
+	F( 80000000,	gpll0,		10,	0,	0),
+	F( 100000000,	gpll0,		8,	0,	0),
+	F( 160000000,	gpll0,		5,	0,	0),
+	F( 177780000,	gpll0,		4.5,	0,	0),
+	F( 200000000,	gpll0,		4,	0,	0),
+	F( 266670000,	gpll0,		3,	0,	0),
+	F( 307200000,	gpll1_e_gfx3d,	4,	0,	0),
+	F( 409600000,	gpll1_e_gfx3d,	3,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_465_clk[] = {
+	F( 19200000,	xo,		1,	0,	0),
+	F( 50000000,	gpll0,		16,	0,	0),
+	F( 80000000,	gpll0,		10,	0,	0),
+	F( 100000000,	gpll0,		8,	0,	0),
+	F( 160000000,	gpll0,		5,	0,	0),
+	F( 177780000,	gpll0,		4.5,	0,	0),
+	F( 200000000,	gpll0,		4,	0,	0),
+	F( 266670000,	gpll0,		3,	0,	0),
+	F( 307200000,	gpll1_e_gfx3d,	4,	0,	0),
+	F( 409600000,	gpll1_e_gfx3d,	3,	0,	0),
+	F( 456000000,	gpll2,		2,	0,	0),
+	F_END
+};
+
+static struct rcg_clk gfx3d_clk_src = {
+	.cmd_rcgr_reg = GFX3D_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_oxili_gfx3d_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gfx3d_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 200000000, NOMINAL, 307200000, HIGH,
+					409600000),
+		CLK_INIT(gfx3d_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F( 64000000,	gpll0,	12.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+	F( 144000,	xo,	16,	3,	25),
+	F( 400000,	xo,	12,	1,	4),
+	F( 20000000,	gpll0,	10,	1,	4),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 177770000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(  57140000,	gpll0,	14,	0,	0),
+	F(  80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	 8,	0,	0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 57140000, NOMINAL, 100000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct branch_clk gcc_bimc_gpu_clk = {
+	.cbcr_reg = BIMC_GPU_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gpu_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gpu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.parent = &blsp1_qup5_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.parent = &blsp1_qup5_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.parent = &blsp1_qup6_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.parent = &blsp1_qup6_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(7),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phy_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0pix_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0rdi_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1phy_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1pix_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1rdi_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp0_clk",
+		.parent = &camss_gp0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp1_clk",
+		.parent = &camss_gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ispif_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk0_clk",
+		.parent = &mclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk1_clk",
+		.parent = &mclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_CSI0PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phytimer_clk",
+		.parent = &csi0phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ahb_clk = {
+	.cbcr_reg = CAMSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_top_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+	.cbcr_reg = CRYPTO_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+	.cbcr_reg = CRYPTO_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+	.cbcr_reg = CRYPTO_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.parent = &gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.parent = &gp2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.parent = &gp3_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_byte0_clk",
+		.parent = &byte0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_esc0_clk",
+		.parent = &esc0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_mdp_clk",
+		.parent = &mdp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_mdp_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_pclk0_clk",
+		.parent = &pclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_vsync_clk",
+		.parent = &vsync_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_bimc_gfx_clk = {
+	.cbcr_reg = BIMC_GFX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gfx_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gfx_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_ahb_clk = {
+	.cbcr_reg = OXILI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_gfx3d_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(8),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+	.cbcr_reg = APSS_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tbu_clk = {
+	.cbcr_reg = GFX_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tcu_clk = {
+	.cbcr_reg = GFX_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_mdp_tbu_clk = {
+	.cbcr_reg = MDP_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdp_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_mdp_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+	.cbcr_reg = SMMU_CFG_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_smmu_cfg_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_smmu_cfg_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_venus_tbu_clk = {
+	.cbcr_reg = VENUS_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_venus_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_vfe_tbu_clk = {
+	.cbcr_reg = VFE_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(9),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_vfe_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_vfe_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gtcu_ahb_clk = {
+	.cbcr_reg = GTCU_AHB_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gtcu_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gtcu_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+	.cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.bcr_reg = USB_HS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+	.reset_reg = USB2_HS_PHY_ONLY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2_hs_phy_only_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+	},
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+	.reset_reg = QUSB2_PHY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qusb2_phy_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_qusb2_phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_core0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_CORE0_VCODEC0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_core0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_core0_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_vcodec0_clk.c),
+	},
+};
+
+static struct gate_clk gcc_snoc_qosgen_clk = {
+	.en_mask = BIT(0),
+	.en_reg = SNOC_QOSGEN,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_snoc_qosgen_clk",
+		.ops = &clk_ops_gate,
+		.flags = CLKFLAG_SKIP_HANDOFF,
+		CLK_INIT(gcc_snoc_qosgen_clk.c),
+	},
+};
+
+static struct mux_clk gcc_debug_mux;
+static struct clk_ops clk_ops_debug_mux;
+
+static struct measure_clk apc0_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc0_m_clk",
+		CLK_INIT(apc0_m_clk.c),
+	},
+};
+
+static struct measure_clk apc1_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc1_m_clk",
+		CLK_INIT(apc1_m_clk.c),
+	},
+};
+
+static struct measure_clk apc2_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc2_m_clk",
+		CLK_INIT(apc2_m_clk.c),
+	},
+};
+
+static struct measure_clk apc3_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc3_m_clk",
+		CLK_INIT(apc3_m_clk.c),
+	},
+};
+
+static struct measure_clk l2_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "l2_m_clk",
+		CLK_INIT(l2_m_clk.c),
+	},
+};
+
+static void __iomem *meas_base;
+
+static struct mux_clk apss_debug_ter_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 8,
+	MUX_SRC_LIST(
+		{&apc0_m_clk.c, 0},
+		{&apc1_m_clk.c, 1},
+		{&apc2_m_clk.c, 2},
+		{&apc3_m_clk.c, 3},
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_ter_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_ter_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_sec_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x7,
+	.shift = 12,
+	MUX_SRC_LIST(
+		{&apss_debug_ter_mux.c, 0},
+		{&l2_m_clk.c, 1},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_ter_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_sec_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_sec_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_pri_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 16,
+	MUX_SRC_LIST(
+		{&apss_debug_sec_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_sec_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_pri_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_pri_mux.c),
+	},
+};
+
+static struct measure_clk_data debug_mux_priv = {
+	.cxo = &xo_clk_src.c,
+	.plltest_reg = GCC_PLLTEST_PAD_CFG,
+	.plltest_val = 0x51A00,
+	.xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+	.ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+	.status_reg = CLOCK_FRQ_MEASURE_STATUS,
+	.base = &virt_bases[GCC_BASE],
+};
+
+static int  gcc_set_mux_sel(struct mux_clk *clk, int sel)
+{
+	u32 regval;
+
+	regval = readl_relaxed(GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+	regval &= 0x1FF;
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	if (sel == 0xFFFF)
+		return 0;
+
+	mux_reg_ops.set_mux_sel(clk, sel);
+
+	return 0;
+};
+
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct mux_clk gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.ops = &gcc_debug_mux_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	MUX_REC_SRC_LIST(
+		&rpm_debug_clk.c,
+		&apss_debug_pri_mux.c,
+	),
+	MUX_SRC_LIST(
+		{ &rpm_debug_clk.c,	0xFFFF},
+		{ &apss_debug_pri_mux.c, 0x016A},
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_bimc_gfx_clk.c, 0x002d },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_mdp_tbu_clk.c, 0x0051 },
+		{ &gcc_gfx_tbu_clk.c, 0x0052 },
+		{ &gcc_gfx_tcu_clk.c, 0x0053 },
+		{ &gcc_venus_tbu_clk.c, 0x0054 },
+		{ &gcc_gtcu_ahb_clk.c, 0x0058 },
+		{ &gcc_vfe_tbu_clk.c, 0x005a },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+		{ &gcc_blsp1_qup5_spi_apps_clk.c, 0x009c },
+		{ &gcc_blsp1_qup5_i2c_apps_clk.c, 0x009d },
+		{ &gcc_blsp1_qup6_spi_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp1_qup6_i2c_apps_clk.c, 0x00a2 },
+		{ &gcc_camss_top_ahb_clk.c, 0x00a8 },
+		{ &gcc_camss_ahb_clk.c, 0x00a9 },
+		{ &gcc_camss_gp0_clk.c, 0x00ab },
+		{ &gcc_camss_gp1_clk.c, 0x00ac },
+		{ &gcc_camss_mclk0_clk.c, 0x00ad },
+		{ &gcc_camss_mclk1_clk.c, 0x00ae },
+		{ &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+		{ &gcc_camss_vfe0_clk.c, 0x00b8 },
+		{ &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+		{ &gcc_camss_vfe_axi_clk.c, 0x00bc },
+		{ &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+		{ &gcc_camss_csi0_clk.c, 0x00c0 },
+		{ &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+		{ &gcc_camss_csi0phy_clk.c, 0x00c2 },
+		{ &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+		{ &gcc_camss_csi0pix_clk.c, 0x00c4 },
+		{ &gcc_camss_csi1_clk.c, 0x00c5 },
+		{ &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+		{ &gcc_camss_csi1phy_clk.c, 0x00c7 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+		{ &gcc_camss_csi1pix_clk.c, 0x00e1 },
+		{ &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+		{ &gcc_venus0_core0_vcodec0_clk.c, 0x00ee },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_bimc_gpu_clk.c, 0x0157 },
+		{ &gcc_oxili_gfx3d_clk.c, 0x01ea },
+		{ &gcc_oxili_ahb_clk.c, 0x01eb },
+		{ &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+		{ &gcc_venus0_axi_clk.c, 0x01f2 },
+		{ &gcc_venus0_ahb_clk.c, 0x01f3 },
+		{ &gcc_mdss_ahb_clk.c, 0x01f6 },
+		{ &gcc_mdss_axi_clk.c, 0x01f7 },
+		{ &gcc_mdss_pclk0_clk.c, 0x01f8 },
+		{ &gcc_mdss_mdp_clk.c, 0x01f9 },
+		{ &gcc_mdss_vsync_clk.c, 0x01fb },
+		{ &gcc_mdss_byte0_clk.c, 0x01fc },
+		{ &gcc_mdss_esc0_clk.c, 0x01fd },
+		{ &wcnss_m_clk.c, 0x0198},
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux.c),
+	},
+};
+
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup[] = {
+	/* PLLs */
+	CLK_LIST(gpll0_clk_src),
+	CLK_LIST(gpll0_ao_clk_src),
+	CLK_LIST(gpll1_clk_src),
+	CLK_LIST(gpll2_clk_src),
+	CLK_LIST(a7sspll),
+
+	/* RCGs */
+	CLK_LIST(apss_ahb_clk_src),
+	CLK_LIST(camss_top_ahb_clk_src),
+	CLK_LIST(csi0_clk_src),
+	CLK_LIST(csi1_clk_src),
+	CLK_LIST(vfe0_clk_src),
+	CLK_LIST(mdp_clk_src),
+	CLK_LIST(gfx3d_clk_src),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup5_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup5_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup6_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup6_spi_apps_clk_src),
+	CLK_LIST(blsp1_uart1_apps_clk_src),
+	CLK_LIST(blsp1_uart2_apps_clk_src),
+	CLK_LIST(camss_gp0_clk_src),
+	CLK_LIST(camss_gp1_clk_src),
+	CLK_LIST(mclk0_clk_src),
+	CLK_LIST(mclk1_clk_src),
+	CLK_LIST(csi0phytimer_clk_src),
+	CLK_LIST(gp1_clk_src),
+	CLK_LIST(gp2_clk_src),
+	CLK_LIST(gp3_clk_src),
+	CLK_LIST(esc0_clk_src),
+	CLK_LIST(vsync_clk_src),
+	CLK_LIST(pdm2_clk_src),
+	CLK_LIST(sdcc1_apps_clk_src),
+	CLK_LIST(sdcc2_apps_clk_src),
+	CLK_LIST(usb_hs_system_clk_src),
+	CLK_LIST(vcodec0_clk_src),
+
+	/* Voteable Clocks */
+	CLK_LIST(gcc_blsp1_ahb_clk),
+	CLK_LIST(gcc_boot_rom_ahb_clk),
+	CLK_LIST(gcc_prng_ahb_clk),
+	CLK_LIST(gcc_apss_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_mdp_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+	CLK_LIST(gcc_smmu_cfg_clk),
+	CLK_LIST(gcc_venus_tbu_clk),
+	CLK_LIST(gcc_vfe_tbu_clk),
+
+	/* Branches */
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup5_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup5_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup6_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup6_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_uart1_apps_clk),
+	CLK_LIST(gcc_blsp1_uart2_apps_clk),
+	CLK_LIST(gcc_camss_csi0_ahb_clk),
+	CLK_LIST(gcc_camss_csi0_clk),
+	CLK_LIST(gcc_camss_csi0phy_clk),
+	CLK_LIST(gcc_camss_csi0pix_clk),
+	CLK_LIST(gcc_camss_csi0rdi_clk),
+	CLK_LIST(gcc_camss_csi1_ahb_clk),
+	CLK_LIST(gcc_camss_csi1_clk),
+	CLK_LIST(gcc_camss_csi1phy_clk),
+	CLK_LIST(gcc_camss_csi1pix_clk),
+	CLK_LIST(gcc_camss_csi1rdi_clk),
+	CLK_LIST(gcc_camss_csi_vfe0_clk),
+	CLK_LIST(gcc_camss_gp0_clk),
+	CLK_LIST(gcc_camss_gp1_clk),
+	CLK_LIST(gcc_camss_ispif_ahb_clk),
+	CLK_LIST(gcc_camss_mclk0_clk),
+	CLK_LIST(gcc_camss_mclk1_clk),
+	CLK_LIST(gcc_camss_csi0phytimer_clk),
+	CLK_LIST(gcc_camss_ahb_clk),
+	CLK_LIST(gcc_camss_top_ahb_clk),
+	CLK_LIST(gcc_camss_vfe0_clk),
+	CLK_LIST(gcc_camss_vfe_ahb_clk),
+	CLK_LIST(gcc_camss_vfe_axi_clk),
+	CLK_LIST(gcc_gp1_clk),
+	CLK_LIST(gcc_gp2_clk),
+	CLK_LIST(gcc_gp3_clk),
+	CLK_LIST(gcc_mdss_ahb_clk),
+	CLK_LIST(gcc_mdss_axi_clk),
+	CLK_LIST(gcc_mdss_esc0_clk),
+	CLK_LIST(gcc_mdss_mdp_clk),
+	CLK_LIST(gcc_mdss_vsync_clk),
+	CLK_LIST(gcc_mss_cfg_ahb_clk),
+	CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+	CLK_LIST(gcc_oxili_ahb_clk),
+	CLK_LIST(gcc_oxili_gfx3d_clk),
+	CLK_LIST(gcc_pdm2_clk),
+	CLK_LIST(gcc_pdm_ahb_clk),
+	CLK_LIST(gcc_sdcc1_ahb_clk),
+	CLK_LIST(gcc_sdcc1_apps_clk),
+	CLK_LIST(gcc_sdcc2_ahb_clk),
+	CLK_LIST(gcc_sdcc2_apps_clk),
+	CLK_LIST(gcc_usb2a_phy_sleep_clk),
+	CLK_LIST(gcc_usb_hs_ahb_clk),
+	CLK_LIST(gcc_usb_hs_system_clk),
+	CLK_LIST(gcc_venus0_ahb_clk),
+	CLK_LIST(gcc_venus0_axi_clk),
+	CLK_LIST(gcc_venus0_vcodec0_clk),
+	CLK_LIST(gcc_bimc_gfx_clk),
+	CLK_LIST(gcc_bimc_gpu_clk),
+	CLK_LIST(gcc_venus0_core0_vcodec0_clk),
+	CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+	CLK_LIST(wcnss_m_clk),
+
+	/* Crypto clocks */
+	CLK_LIST(gcc_crypto_clk),
+	CLK_LIST(gcc_crypto_ahb_clk),
+	CLK_LIST(gcc_crypto_axi_clk),
+	CLK_LIST(crypto_clk_src),
+
+	/* Reset clocks */
+	CLK_LIST(gcc_usb2_hs_phy_only_clk),
+	CLK_LIST(gcc_qusb2_phy_clk),
+
+	/* QoS Reference clock */
+	CLK_LIST(gcc_snoc_qosgen_clk),
+};
+
+static const struct msm_reset_map gcc_8909_resets[] = {
+	[GCC_USB_HS_BCR] = {0x41000},
+	[GCC_USB2_HS_PHY_ONLY_BCR] = {0x41034},
+	[GCC_QUSB2_PHY_BCR] = {0x4103C},
+};
+
+static int add_dev_opp(struct clk *c, struct device *dev,
+				unsigned long max_rate)
+{
+	unsigned long rate = 0;
+	int level;
+	long ret;
+
+	while (1) {
+		ret = clk_round_rate(c, rate + 1);
+		if (ret < 0) {
+			pr_warn("round_rate failed at %lu\n", rate);
+			return ret;
+		}
+		rate = ret;
+		level = find_vdd_level(c, rate);
+		if (level <= 0) {
+			pr_warn("no uv for %lu.\n", rate);
+			return -EINVAL;
+		}
+		ret = dev_pm_opp_add(dev, rate, c->vdd_class->vdd_uv[level]);
+		if (ret) {
+			pr_warn("failed to add OPP for %lu\n", rate);
+			return ret;
+		}
+		if (rate >= max_rate)
+			break;
+	}
+	return 0;
+}
+
+static void register_opp_for_dev(struct platform_device *pdev)
+{
+	struct clk *opp_clk, *opp_clk_src;
+	unsigned long dev_fmax;
+
+	opp_clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(opp_clk)) {
+		pr_err("Error getting core clk: %lu\n", PTR_ERR(opp_clk));
+		return;
+	}
+	opp_clk_src = opp_clk;
+	if (opp_clk->num_fmax <= 0) {
+		if (opp_clk->parent && opp_clk->parent->num_fmax > 0)
+			opp_clk_src = opp_clk->parent;
+		else
+			return;
+	}
+
+	dev_fmax = opp_clk_src->fmax[opp_clk_src->num_fmax - 1];
+	WARN(add_dev_opp(opp_clk_src, &pdev->dev, dev_fmax),
+		"Failed to add OPP levels for dev\n");
+}
+
+static void gcc_gfx3d_fmax(struct platform_device *pdev)
+{
+	void __iomem *base;
+	u32 pte_efuse, bin, shift = 2, mask = 0x7;
+
+	base = devm_ioremap(&pdev->dev, 0x0005c00c, 0x8);
+	if (IS_ERR(base)) {
+		pr_err("Failed to map raw base address\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+	bin = (pte_efuse >> shift) & mask;
+	if (bin != 0)
+		return;
+
+	pr_debug("%s, bin: %d\n", __func__, bin);
+
+	gpll2_clk_src.c.rate = 912000000;
+
+	gfx3d_clk_src.c.fmax[VDD_DIG_HIGH] = 456000000;
+	gfx3d_clk_src.freq_tbl = ftbl_gcc_oxili_gfx3d_465_clk;
+
+	mclk0_clk_src.freq_tbl = ftbl_gcc_camss_mclkm_clk;
+	mclk0_clk_src.c.fmax = mclk0_1_fmax;
+	mclk1_clk_src.freq_tbl = ftbl_gcc_camss_mclkm_clk;
+	mclk1_clk_src.c.fmax = mclk0_1_fmax;
+}
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct clk *xo_gcc;
+	int ret, node = 0;
+	u32 regval;
+	struct device_node *opp_dev_node = NULL;
+	struct platform_device *opp_dev = NULL;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[GCC_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+	if (!res) {
+		dev_err(&pdev->dev, "APCS PLL Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[APCS_PLL_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[APCS_PLL_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap APCS PLL registers\n");
+		return -ENOMEM;
+	}
+
+	vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+					"Unable to get vdd_dig regulator!!!\n");
+		return PTR_ERR(vdd_dig.regulator[0]);
+	}
+
+	vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_pll");
+	if (IS_ERR(vdd_sr2_pll.regulator[0])) {
+		if (!(PTR_ERR(vdd_sr2_pll.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_pll regulator!!!\n");
+		return PTR_ERR(vdd_sr2_pll.regulator[0]);
+	}
+
+	vdd_sr2_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_dig");
+	if (IS_ERR(vdd_sr2_pll.regulator[1])) {
+		if (!(PTR_ERR(vdd_sr2_pll.regulator[1]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_dig regulator!!!\n");
+		return PTR_ERR(vdd_sr2_pll.regulator[1]);
+	}
+
+	xo_gcc = xo_clk_src.c.parent = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_gcc)) {
+		if (!(PTR_ERR(xo_gcc) == -EPROBE_DEFER))
+			dev_err(&pdev->dev, "Unable to get XO clock!!!\n");
+		return PTR_ERR(xo_gcc);
+	}
+
+	 /*Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	xo_a_clk_src.c.parent = clk_get(&pdev->dev, "xo_a");
+	if (IS_ERR(xo_a_clk_src.c.parent)) {
+		if (!(PTR_ERR(xo_a_clk_src.c.parent) == -EPROBE_DEFER))
+			dev_err(&pdev->dev, "Unable to get xo_a clock!!!\n");
+		return PTR_ERR(xo_a_clk_src.c.parent);
+	}
+
+	gcc_gfx3d_fmax(pdev);
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_lookup,
+				ARRAY_SIZE(msm_clocks_lookup));
+	if (ret)
+		return ret;
+
+	clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+	clk_prepare_enable(&apss_ahb_clk_src.c);
+
+	opp_dev_node = of_parse_phandle(pdev->dev.of_node, "qcom,dev-opp-list",
+					node);
+	while (opp_dev_node) {
+		opp_dev = of_find_device_by_node(opp_dev_node);
+		if (!opp_dev) {
+			pr_err("cant find device for node\n");
+			return -EINVAL;
+		}
+		register_opp_for_dev(opp_dev);
+		node++;
+		opp_dev_node = of_parse_phandle(pdev->dev.of_node,
+					"qcom,dev-opp-list", node);
+	}
+
+	msm_reset_controller_register(pdev, gcc_8909_resets,
+					ARRAY_SIZE(gcc_8909_resets),
+					virt_bases[GCC_BASE]);
+
+	dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+	{ .compatible = "qcom,gcc-8909" },
+	{},
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+	.probe = msm_gcc_probe,
+	.driver = {
+		.name = "qcom,gcc-8909",
+		.of_match_table = msm_clock_gcc_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_init);
+
+static struct clk_lookup msm_clocks_measure[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(apc2_m_clk),
+	CLK_LIST(apc3_m_clk),
+	CLK_LIST(l2_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+	if (!res) {
+		dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+		return -EINVAL;
+	}
+
+	meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!meas_base) {
+		dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+		return -ENOMEM;
+	}
+
+	clk_ops_debug_mux = clk_ops_gen_mux;
+	clk_ops_debug_mux.get_rate = measure_get_rate;
+
+	gcc_debug_mux_ops = mux_reg_ops;
+	gcc_debug_mux_ops.set_mux_sel = gcc_set_mux_sel;
+
+	rpm_debug_clk.c.parent = clk_get(&pdev->dev, "rpm_debug_mux");
+	if (IS_ERR(rpm_debug_clk.c.parent)) {
+		dev_err(&pdev->dev, "Failed to get RPM debug Mux\n");
+		return PTR_ERR(rpm_debug_clk.c.parent);
+	}
+
+	ret =  of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure,
+					ARRAY_SIZE(msm_clocks_measure));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register debug Mux\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+	return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+	{ .compatible = "qcom,cc-debug-8909" },
+	{}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+	.probe = msm_clock_debug_probe,
+	.driver = {
+		.name = "qcom,cc-debug-8909",
+		.of_match_table = msm_clock_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_clock_debug_init(void)
+{
+	return platform_driver_register(&msm_clock_debug_driver);
+}
+late_initcall(msm_clock_debug_init);
+
+/* MDSS DSI_PHY_PLL */
+static struct clk_lookup msm_clocks_gcc_mdss[] = {
+	CLK_LIST(byte0_clk_src),
+	CLK_LIST(pclk0_clk_src),
+	CLK_LIST(gcc_mdss_pclk0_clk),
+	CLK_LIST(gcc_mdss_byte0_clk),
+};
+
+static int msm_gcc_mdss_probe(struct platform_device *pdev)
+{
+	int counter = 0, ret = 0;
+
+	pclk0_clk_src.c.parent = devm_clk_get(&pdev->dev, "pclk0_src");
+	if (IS_ERR(pclk0_clk_src.c.parent)) {
+		dev_err(&pdev->dev, "Failed to get pclk0 source.\n");
+		return PTR_ERR(pclk0_clk_src.c.parent);
+	}
+
+	for (counter = 0; counter < (sizeof(ftbl_gcc_mdss_pclk0_clk)/
+				sizeof(struct clk_freq_tbl)); counter++)
+		ftbl_gcc_mdss_pclk0_clk[counter].src_clk =
+					pclk0_clk_src.c.parent;
+
+	byte0_clk_src.c.parent = devm_clk_get(&pdev->dev, "byte0_src");
+	if (IS_ERR(byte0_clk_src.c.parent)) {
+		dev_err(&pdev->dev, "Failed to get byte0 source.\n");
+		devm_clk_put(&pdev->dev, pclk0_clk_src.c.parent);
+		return PTR_ERR(byte0_clk_src.c.parent);
+	}
+
+	for (counter = 0; counter < (sizeof(ftbl_gcc_mdss_byte0_clk)/
+				sizeof(struct clk_freq_tbl)); counter++)
+		ftbl_gcc_mdss_byte0_clk[counter].src_clk =
+					byte0_clk_src.c.parent;
+
+	ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_gcc_mdss,
+					ARRAY_SIZE(msm_clocks_gcc_mdss));
+	if (ret)
+		return ret;
+
+	dev_info(&pdev->dev, "Registered GCC MDSS clocks.\n");
+
+	return ret;
+}
+
+static const struct of_device_id msm_clock_mdss_match_table[] = {
+	{ .compatible = "qcom,gcc-mdss-8909" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_mdss_driver = {
+	.probe = msm_gcc_mdss_probe,
+	.driver = {
+		.name = "gcc-mdss-8909",
+		.of_match_table = msm_clock_mdss_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_mdss_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_mdss_driver);
+}
+fs_initcall_sync(msm_gcc_mdss_init);
diff --git a/drivers/clk/msm/clock-gcc-8952.c b/drivers/clk/msm/clock-gcc-8952.c
new file mode 100644
index 0000000..7da217c
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-8952.c
@@ -0,0 +1,4867 @@
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/rpm-smd.h>
+#include <soc/qcom/clock-rpm.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8952.h>
+#include <dt-bindings/clock/msm-clocks-hwio-8952.h>
+
+#include "clock.h"
+#include "reset.h"
+
+enum {
+	GCC_BASE,
+	APCS_C1_PLL_BASE,
+	APCS_C0_PLL_BASE,
+	APCS_CCI_PLL_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+/* SMD clocks */
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src, RPM_MISC_CLK_TYPE,
+				CXO_CLK_SRC_ID, 19200000);
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_gpu_clk, bimc_gpu_a_clk, RPM_MEM_CLK_TYPE,
+						BIMC_GPU_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(sysmmnoc_clk, sysmmnoc_a_clk, RPM_BUS_CLK_TYPE,
+						SYSMMNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(ipa_clk, ipa_a_clk, RPM_IPA_CLK_TYPE, IPA_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_CLK_ID);
+
+/* SMD_XO_BUFFER */
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk2, div_clk2_a, DIV_CLK2_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID);
+
+/* Voter clocks */
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sysmmnoc_msmbus_clk,  &sysmmnoc_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sysmmnoc_msmbus_a_clk,  &sysmmnoc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_usb_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_usb_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_clk, &bimc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(snoc_wcnss_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_wcnss_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+/* Branch Voter clocks */
+static DEFINE_CLK_BRANCH_VOTER(xo_gcc, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_lpass_clk, &xo_clk_src.c);
+
+DEFINE_CLK_DUMMY(wcnss_m_clk, 0);
+
+enum vdd_sr2_pll_levels {
+	VDD_SR2_PLL_OFF,
+	VDD_SR2_PLL_SVS,
+	VDD_SR2_PLL_NOM,
+	VDD_SR2_PLL_TUR,
+	VDD_SR2_PLL_SUPER_TUR,
+	VDD_SR2_PLL_NUM,
+};
+
+static int vdd_sr2_levels[] = {
+	0,	 RPM_REGULATOR_LEVEL_NONE,	/* VDD_SR2_PLL_OFF */
+	1800000, RPM_REGULATOR_LEVEL_SVS,	/* VDD_SR2_PLL_SVS */
+	1800000, RPM_REGULATOR_LEVEL_NOM,	/* VDD_SR2_PLL_NOM */
+	1800000, RPM_REGULATOR_LEVEL_TURBO,	/* VDD_SR2_PLL_TUR */
+	1800000, RPM_REGULATOR_LEVEL_BINNING,	/* VDD_SR2_PLL_SUPER_TUR */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+				vdd_sr2_levels, NULL);
+
+enum vdd_hf_pll_levels {
+	VDD_HF_PLL_OFF,
+	VDD_HF_PLL_SVS,
+	VDD_HF_PLL_NOM,
+	VDD_HF_PLL_TUR,
+	VDD_HF_PLL_SUPER_TUR,
+	VDD_HF_PLL_NUM,
+};
+
+static int vdd_hf_levels[] = {
+	0,	 RPM_REGULATOR_LEVEL_NONE,	/* VDD_HF_PLL_OFF */
+	1800000, RPM_REGULATOR_LEVEL_SVS,	/* VDD_HF_PLL_SVS */
+	1800000, RPM_REGULATOR_LEVEL_NOM,	/* VDD_HF_PLL_NOM */
+	1800000, RPM_REGULATOR_LEVEL_TURBO,	/* VDD_HF_PLL_TUR */
+	1800000, RPM_REGULATOR_LEVEL_BINNING,	/* VDD_HF_PLL_SUPER_TUR */
+};
+static DEFINE_VDD_REGULATORS(vdd_hf_pll, VDD_HF_PLL_NUM, 2,
+				vdd_hf_levels, NULL);
+
+static struct pll_freq_tbl apcs_cci_pll_freq[] = {
+	F_APCS_PLL(307200000, 16, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(600000000, 31, 0x1, 0x4, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_cci_pll = {
+	.mode_reg = (void __iomem *)APCS_CCI_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_CCI_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_CCI_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_CCI_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_CCI_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_CCI_PLL_STATUS,
+	.freq_tbl = apcs_cci_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_CCI_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x40,
+		.event_bit = 0x0,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_cci_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+			[VDD_SR2_PLL_SVS] = 1000000000,
+			[VDD_SR2_PLL_NOM] = 1900000000,
+		},
+		.num_fmax = VDD_SR2_PLL_NUM,
+		CLK_INIT(a53ss_cci_pll.c),
+	},
+};
+
+static struct pll_freq_tbl apcs_c0_pll_freq[] = {
+	F_APCS_PLL( 249600000,  13, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 307200000,  16, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 345600000,  18, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 384000000,  20, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 460800000,  24, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 499200000,  26, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 518400000,  27, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 768000000,  40, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 806400000,  42, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 844800000,  44, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 883200000,  46, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 902400000,  47, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 921600000,  48, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 998400000,  52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000,  57, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1209600000,  63, 0x0, 0x1, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_c0_pll = {
+	.mode_reg = (void __iomem *)APCS_C0_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_C0_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_C0_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_C0_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_C0_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_C0_PLL_STATUS,
+	.freq_tbl = apcs_c0_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_C0_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x50,
+		.event_bit = 0x4,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_c0_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+			[VDD_SR2_PLL_SVS] = 1000000000,
+			[VDD_SR2_PLL_NOM] = 1900000000,
+		},
+		.num_fmax = VDD_SR2_PLL_NUM,
+		CLK_INIT(a53ss_c0_pll.c),
+	},
+};
+
+static struct pll_freq_tbl apcs_c1_pll_freq[] = {
+	F_APCS_PLL( 345600000, 18, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 422400000, 22, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 499200000, 26, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 652800000, 34, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 729600000, 38, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 806400000, 42, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 844800000, 44, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 883200000, 46, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 960000000, 50, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1036800000, 54, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1113600000, 58, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1209600000, 63, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1248000000, 65, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1267200000, 66, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1344000000, 70, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1401000000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1420800000, 74, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1440000000, 75, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1459200000, 76, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1516800000, 79, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1536000000, 80, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1651200000, 86, 0x0, 0x1, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_c1_pll = {
+	.mode_reg = (void __iomem *)APCS_C1_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_C1_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_C1_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_C1_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_C1_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_C1_PLL_STATUS,
+	.freq_tbl = apcs_c1_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_C1_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x50,
+		.event_bit = 0x4,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_c1_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_hf_pll,
+		.fmax = (unsigned long [VDD_HF_PLL_NUM]) {
+			[VDD_HF_PLL_SVS] = 1000000000,
+			[VDD_HF_PLL_NOM] = 2000000000,
+		},
+		.num_fmax = VDD_HF_PLL_NUM,
+		CLK_INIT(a53ss_c1_pll.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_sleep_clk_src = {
+	.en_reg = (void __iomem *)APCS_CLOCK_SLEEP_ENA_VOTE,
+	.en_mask = BIT(23),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_sleep_clk_src",
+		.ops = &clk_ops_pll_sleep_vote,
+		CLK_INIT(gpll0_sleep_clk_src.c),
+	},
+};
+
+static unsigned int soft_vote_gpll0;
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL0_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll0_clk_src_8952 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src_8952",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src_8952.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_clk_src_8937 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gpll0_sleep_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src_8937",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src_8937.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll0_clk_src, NULL);
+DEFINE_EXT_CLK(gpll0_ao_clk_src, NULL);
+DEFINE_EXT_CLK(gpll0_out_aux_clk_src, &gpll0_clk_src.c);
+DEFINE_EXT_CLK(gpll0_out_main_clk_src, &gpll0_clk_src.c);
+DEFINE_EXT_CLK(ext_pclk0_clk_src, NULL);
+DEFINE_EXT_CLK(ext_byte0_clk_src, NULL);
+DEFINE_EXT_CLK(ext_pclk1_clk_src, NULL);
+DEFINE_EXT_CLK(ext_byte1_clk_src, NULL);
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao_clk_src_8952 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src_8952",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src_8952.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_ao_clk_src_8937 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src_8937",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src_8937.c),
+	},
+};
+
+static struct pll_vote_clk gpll6_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(7),
+	.status_reg = (void __iomem *)GPLL6_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 1080000000,
+		.dbg_name = "gpll6_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll6_clk_src.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll6_aux_clk_src, &gpll6_clk_src.c);
+DEFINE_EXT_CLK(gpll6_out_main_clk_src, &gpll6_clk_src.c);
+
+static struct alpha_pll_masks pll_masks_p = {
+	.lock_mask = BIT(31),
+	.active_mask = BIT(30),
+	.vco_mask = BM(21, 20) >> 20,
+	.vco_shift = 20,
+	.alpha_en_mask = BIT(24),
+	.output_mask = 0xf,
+	.update_mask = BIT(22),
+	.post_div_mask = BM(11, 8),
+	.test_ctl_lo_mask = BM(31, 0),
+	.test_ctl_hi_mask = BM(31, 0),
+};
+
+/* Slewing plls won't allow to change vco_sel.
+ * Hence will have only one vco table entry
+ */
+static struct alpha_pll_vco_tbl p_vco[] = {
+	VCO(0,  700000000, 1400000000),
+};
+
+/* Slewing plls won't allow to change vco_sel.
+ * Hence will have only one vco table entry
+ */
+static struct alpha_pll_vco_tbl p_vco_8937[] = {
+	VCO(1,  525000000, 1066000000),
+};
+
+static struct alpha_pll_clk gpll3_clk_src = {
+	.masks = &pll_masks_p,
+	.base = &virt_bases[GCC_BASE],
+	.offset = GPLL3_MODE,
+	.vco_tbl = p_vco,
+	.num_vco = ARRAY_SIZE(p_vco),
+	.enable_config = 1,
+	/*
+	 * gpll3 is dedicated to oxili and has a fuse implementation for
+	 * post divider to limit frequency. HW with fuse blown has a divider
+	 * value set to 2. So lets stick to divide by 2 in software to avoid
+	 * conflicts.
+	 */
+	.post_div_config = 1 << 8,
+	.slew = true,
+	.config_ctl_val = 0x4001055b,
+	.test_ctl_hi_val = 0x40000600,
+	.c = {
+		.rate = 1050000000,
+		.parent = &xo_clk_src.c,
+		.dbg_name = "gpll3_clk_src",
+		.ops = &clk_ops_dyna_alpha_pll,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1400000000),
+		CLK_INIT(gpll3_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll4_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(5),
+	.status_reg = (void __iomem *)GPLL4_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate =  1152000000,
+		.parent = &xo_clk_src.c,
+		.dbg_name = "gpll4_clk_src",
+		.ops = &clk_ops_pll_vote,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1400000000),
+		CLK_INIT(gpll4_clk_src.c),
+	},
+};
+DEFINE_EXT_CLK(gpll4_out_clk_src, &gpll4_clk_src.c);
+
+static struct clk_freq_tbl ftbl_gcc_camss_top_ahb_clk[] = {
+	F( 40000000,	gpll0,	10,	1,	2),
+	F( 61540000,	gpll0,	13,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_top_ahb_clk_src = {
+	.cmd_rcgr_reg =  CAMSS_TOP_AHB_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_top_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 40000000, LOW, 61540000,
+				  NOMINAL, 80000000),
+		CLK_INIT(camss_top_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_apss_ahb_clk[] = {
+	F( 19200000,	xo_a,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+	.cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_apss_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "apss_ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(apss_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_2_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_2_clk_8937[] = {
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F_END
+};
+
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2_clk_src = {
+	.cmd_rcgr_reg = CSI2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 180000000,	gpll6,	6,	0,	0),
+	F( 228570000,	gpll0,	3.5,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk_8937[] = {
+	F( 166150000,          gpll6,  6.5,    0,     0),
+	F( 240000000,          gpll6,  4.5,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk_8917[] = {
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 270000000,          gpll6,    4,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 329140000,          gpll4_out,  3.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg =  VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 180000000,
+				  NOMINAL, 228570000, NOM_PLUS, 266670000,
+				  HIGH, 308570000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F( 360000000,	gpll6,	3,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk_8937[] = {
+	F(  50000000,          gpll0,   16,    0,     0),
+	F(  80000000,          gpll0,   10,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 177780000,          gpll0,  4.5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F( 400000000,          gpll0,    2,    0,     0),
+	F( 432000000,          gpll6,  2.5,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk_8917[] = {
+	F(  50000000,          gpll0,   16,    0,     0),
+	F(  80000000,          gpll0,   10,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 177780000,          gpll0,  4.5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 329140000,          gpll4_out,  3.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 266670000,
+				  NOMINAL, 308570000, NOM_PLUS, 320000000,
+				  HIGH, 360000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct rcg_clk vfe1_clk_src = {
+	.cmd_rcgr_reg = VFE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vfe1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 266670000,
+				  NOMINAL, 308570000, NOM_PLUS, 320000000,
+				  HIGH, 360000000),
+		CLK_INIT(vfe1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 465000000, 930000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 500000000, 1000000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8937[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,      0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8937_475MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 475000000, 950000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8940_500MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 475000000, 950000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 500000000, 1000000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_aux,	4,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 484800000, 969600000,	  gpll3,	1,	0,	0),
+	F_SLEW( 523200000, 1046400000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 598000000, 1196000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917_650MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_aux,	4,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 484800000, 969600000,	  gpll3,	1,	0,	0),
+	F_SLEW( 523200000, 1046400000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 598000000, 1196000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 650000000, 1300000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct  rcg_clk gfx3d_clk_src = {
+	.cmd_rcgr_reg = GFX3D_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_oxili_gfx3d_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gfx3d_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 240000000, LOW, 400000000,
+				  NOMINAL, 465000000, NOM_PLUS, 500000000,
+				  HIGH, 550000000),
+		CLK_INIT(gfx3d_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 40000000,	gpll0,	10,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_2_apps_clk[] = {
+	F( 3686400,	gpll0,	1,	72,	15625),
+	F( 7372800,	gpll0,	1,	144,	15625),
+	F( 14745600,	gpll0,	1,	288,	15625),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 24000000,	gpll0,	1,	3,	100),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 32000000,	gpll0,	1,	1,	25),
+	F( 40000000,	gpll0,	1,	1,	20),
+	F( 46400000,	gpll0,	1,	29,	500),
+	F( 48000000,	gpll0,	1,	3,	50),
+	F( 51200000,	gpll0,	1,	8,	125),
+	F( 56000000,	gpll0,	1,	7,	100),
+	F( 58982400,	gpll0,	1,	1152,	15625),
+	F( 60000000,	gpll0,	1,	3,	40),
+	F( 64000000,	gpll0,  1,	2,	25),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp2_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp2_uart2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cci_clk[] = {
+	F( 19200000,	xo,		1,	0,	0),
+	F( 37500000,	gpll0_out_aux,	1,	3,	64),
+	F_END
+};
+
+static struct rcg_clk cci_clk_src = {
+	.cmd_rcgr_reg =  CCI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_cci_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "cci_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 37500000),
+		CLK_INIT(cci_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 180000000,	gpll6,	6,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk_8937[] = {
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266666667,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk_8917[] = {
+	F( 133330000,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk cpp_clk_src = {
+	.cmd_rcgr_reg = CPP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_cpp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "cpp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 180000000,
+				  NOMINAL, 266670000, NOM_PLUS, 308570000,
+				  HIGH, 320000000),
+		CLK_INIT(cpp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_gp0_1_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_gp0_clk_src = {
+	.cmd_rcgr_reg =  MM_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(camss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk camss_gp1_clk_src = {
+	.cmd_rcgr_reg =  MM_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(camss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_jpeg0_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_jpeg0_clk_8937[] = {
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266666667,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk jpeg0_clk_src = {
+	.cmd_rcgr_reg = JPEG0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_jpeg0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "jpeg0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclk0_2_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F( 24000000,	gpll6,	1,	1,	45),
+	F( 66670000,	gpll0,	12,	0,	0),
+	F_END
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg =  MCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg =  MCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk2_clk_src = {
+	.cmd_rcgr_reg =  MCLK2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk_8917[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_crypto_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+	.cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_crypto_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "crypto_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+		CLK_INIT(crypto_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg =  GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg =  GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg =  GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk_8937[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte1_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.current_freq = ftbl_gcc_mdss_byte0_clk,
+	.freq_tbl = ftbl_gcc_mdss_byte0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_byte_multiparent,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		VDD_DIG_FMAX_MAP2(LOWER, 120000000, NOMINAL, 187500000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte1_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte1_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk byte1_clk_src = {
+		.cmd_rcgr_reg = BYTE1_CMD_RCGR,
+		.set_rate = set_rate_hid,
+		.current_freq = ftbl_gcc_mdss_byte1_clk,
+		.freq_tbl = ftbl_gcc_mdss_byte1_clk,
+		.base = &virt_bases[GCC_BASE],
+		.c = {
+			.dbg_name = "byte1_clk_src",
+			.ops = &clk_ops_byte_multiparent,
+			.flags = CLKFLAG_NO_RATE_CACHE,
+			VDD_DIG_FMAX_MAP2(LOWER, 125000000, NOMINAL, 187500000),
+			CLK_INIT(byte1_clk_src.c),
+		},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_esc0_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_esc0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_esc1_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk esc1_clk_src = {
+	.cmd_rcgr_reg = ESC1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_esc1_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "esc1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(esc1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_mdp_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 145450000,	gpll0,	5.5,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 160000000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk_8937[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk1_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg =  PCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.current_freq = ftbl_gcc_mdss_pclk0_clk,
+	.freq_tbl = ftbl_gcc_mdss_pclk0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_pixel_multiparent,
+		VDD_DIG_FMAX_MAP2(LOWER, 160000000, NOMINAL, 250000000),
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk1_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk1_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk pclk1_clk_src = {
+	.cmd_rcgr_reg = PCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.current_freq = ftbl_gcc_mdss_pclk1_clk,
+	.freq_tbl = ftbl_gcc_mdss_pclk1_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pclk1_clk_src",
+		.ops = &clk_ops_pixel_multiparent,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		VDD_DIG_FMAX_MAP2(LOWER, 166670000, NOMINAL, 250000000),
+		CLK_INIT(pclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_vsync_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F( 64000000,	gpll0,	12.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
+	F( 144000,	xo,	16,	3,	25),
+	F( 400000,	xo,	12,	1,	4),
+	F( 20000000,	gpll0,	10,	1,	4),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 177770000,	gpll0,	4.5,	0,	0),
+	F( 192000000,	gpll4,	6,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 384000000,	gpll4,	3,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 384000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_ice_core_clk[] = {
+	F( 100000000,	gpll0_out_main,	8,	0,	0),
+	F( 200000000,	gpll0_out_main,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_ice_core_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_ICE_CORE_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_ice_core_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_ice_core_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_ice_core_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_apps_clk[] = {
+	F( 144000,	xo,	16,	3,	25),
+	F( 400000,	xo,	12,	1,	4),
+	F( 20000000,	gpll0,	10,	1,	4),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 177770000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_fs_ic_clk[] = {
+	F( 60000000,	gpll6_out_main,	9,	1,	2),
+	F_END
+};
+
+static struct rcg_clk usb_fs_ic_clk_src = {
+	.cmd_rcgr_reg =  USB_FS_IC_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb_fs_ic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_fs_ic_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 60000000),
+		CLK_INIT(usb_fs_ic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_fs_system_clk[] = {
+	F( 64000000,	gpll0_out_aux,	12.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk usb_fs_system_clk_src = {
+	.cmd_rcgr_reg =  USB_FS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb_fs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_fs_system_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(usb_fs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F( 57140000,	gpll0,	14,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk_8917[] = {
+	F( 80000000,	gpll0,	 10,	0,	0),
+	F( 100000000,	gpll0,	  8,	0,	0),
+	F( 133330000,	gpll0,	  6,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 57140000, NOMINAL, 133330000,
+				  HIGH, 177780000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct branch_clk gcc_bimc_gpu_clk = {
+	.cbcr_reg = BIMC_GPU_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gpu_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gpu_clk.c),
+	},
+};
+
+static struct branch_clk gcc_dcc_clk = {
+	.cbcr_reg = DCC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_dcc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_dcc_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp2_ahb_clk = {
+	.cbcr_reg = BLSP2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(20),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
+		.parent = &blsp2_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
+		.parent = &blsp2_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
+		.parent = &blsp2_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
+		.parent = &blsp2_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
+		.parent = &blsp2_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
+		.parent = &blsp2_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
+		.parent = &blsp2_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
+		.parent = &blsp2_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart1_apps_clk = {
+	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart1_apps_clk",
+		.parent = &blsp2_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart2_apps_clk = {
+	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart2_apps_clk",
+		.parent = &blsp2_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(7),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cci_ahb_clk = {
+	.cbcr_reg = CAMSS_CCI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cci_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cci_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cci_clk = {
+	.cbcr_reg = CAMSS_CCI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cci_clk",
+		.parent = &cci_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cci_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_ahb_clk = {
+	.cbcr_reg = CAMSS_CPP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_axi_clk = {
+	.cbcr_reg = CAMSS_CPP_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_clk = {
+	.cbcr_reg = CAMSS_CPP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_clk",
+		.parent = &cpp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phy_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0pix_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0rdi_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1phy_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1pix_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1rdi_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2_clk = {
+	.cbcr_reg = CAMSS_CSI2_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2phy_clk = {
+	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2phy_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2pix_clk = {
+	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2pix_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2rdi_clk = {
+	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2rdi_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi_vfe1_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp0_clk",
+		.parent = &camss_gp0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp1_clk",
+		.parent = &camss_gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ispif_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg0_clk = {
+	.cbcr_reg = CAMSS_JPEG0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg0_clk",
+		.parent = &jpeg0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg_ahb_clk = {
+	.cbcr_reg = CAMSS_JPEG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg_axi_clk = {
+	.cbcr_reg = CAMSS_JPEG_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk0_clk",
+		.parent = &mclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk1_clk",
+		.parent = &mclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk2_clk = {
+	.cbcr_reg = CAMSS_MCLK2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk2_clk",
+		.parent = &mclk2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_micro_ahb_clk = {
+	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
+	.bcr_reg =  CAMSS_MICRO_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_micro_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_micro_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_CSI0PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phytimer_clk",
+		.parent = &csi0phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1phytimer_clk = {
+	.cbcr_reg = CAMSS_CSI1PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1phytimer_clk",
+		.parent = &csi1phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ahb_clk = {
+	.cbcr_reg = CAMSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_top_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_axi_clk = {
+	.cbcr_reg = CAMSS_VFE1_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_clk = {
+	.cbcr_reg = CAMSS_VFE1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+	.cbcr_reg = CRYPTO_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_ahb_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+	.cbcr_reg = CRYPTO_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+	.cbcr_reg = CRYPTO_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_clk.c),
+	},
+};
+
+static struct gate_clk gcc_oxili_gmem_clk = {
+	.en_reg = OXILI_GMEM_CBCR,
+	.en_mask = BIT(0),
+	.delay_us = 50,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_gmem_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_oxili_gmem_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.parent = &gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.parent = &gp2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.parent = &gp3_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_byte0_clk",
+		.parent = &byte0_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_byte1_clk = {
+	.cbcr_reg = MDSS_BYTE1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_byte1_clk",
+		.parent = &byte1_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_byte1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_esc0_clk",
+		.parent = &esc0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_esc1_clk = {
+	.cbcr_reg = MDSS_ESC1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_esc1_clk",
+		.parent = &esc1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_esc1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_mdp_clk",
+		.parent = &mdp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_mdp_clk.c),
+	},
+};
+
+static DEFINE_CLK_VOTER(mdss_mdp_vote_clk, &gcc_mdss_mdp_clk.c, 0);
+static DEFINE_CLK_VOTER(mdss_rotator_vote_clk, &gcc_mdss_mdp_clk.c, 0);
+
+static struct branch_clk gcc_mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_pclk0_clk",
+		.parent = &pclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_pclk1_clk = {
+	.cbcr_reg = MDSS_PCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_pclk1_clk",
+		.parent = &pclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_pclk1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_vsync_clk",
+		.parent = &vsync_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk;
+static struct branch_clk gcc_bimc_gfx_clk = {
+	.cbcr_reg = BIMC_GFX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gfx_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gfx_clk.c),
+		.depends = &gcc_apss_tcu_clk.c,
+	},
+};
+
+static struct branch_clk gcc_oxili_ahb_clk = {
+	.cbcr_reg = OXILI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_gfx3d_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_timer_clk = {
+	.cbcr_reg = OXILI_TIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_timer_clk",
+		.parent = &xo_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_timer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_aon_clk = {
+	.cbcr_reg = OXILI_AON_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_aon_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_aon_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(8),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_qdss_dap_clk = {
+	.cbcr_reg = QDSS_DAP_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(21),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qdss_dap_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_qdss_dap_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ice_core_clk = {
+	.cbcr_reg = SDCC1_ICE_CORE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ice_core_clk",
+		.parent = &sdcc1_ice_core_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ice_core_clk.c),
+	}
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_cpp_tbu_clk = {
+	.cbcr_reg = CPP_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(14),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_cpp_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_cpp_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tbu_clk = {
+	.cbcr_reg = GFX_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tcu_clk = {
+	.cbcr_reg = GFX_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+	.cbcr_reg = APSS_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gtcu_ahb_clk = {
+	.cbcr_reg = GTCU_AHB_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gtcu_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gtcu_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ipa_tbu_clk = {
+	.cbcr_reg = IPA_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ipa_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ipa_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_jpeg_tbu_clk = {
+	.cbcr_reg = JPEG_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_jpeg_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_jpeg_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_mdp_tbu_clk = {
+	.cbcr_reg = MDP_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdp_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_mdp_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+	.cbcr_reg = SMMU_CFG_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_smmu_cfg_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_smmu_cfg_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_venus_tbu_clk = {
+	.cbcr_reg = VENUS_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_venus_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_vfe1_tbu_clk = {
+	.cbcr_reg = VFE1_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_vfe1_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_vfe1_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_vfe_tbu_clk = {
+	.cbcr_reg = VFE_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(9),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_vfe_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_vfe_tbu_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+	.cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_ahb_clk = {
+	.cbcr_reg = USB_FS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_ic_clk = {
+	.cbcr_reg = USB_FS_IC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_ic_clk",
+		.parent = &usb_fs_ic_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_ic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_system_clk = {
+	.cbcr_reg = USB_FS_SYSTEM_CBCR,
+	.bcr_reg  = USB_FS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_system_clk",
+		.parent = &usb_fs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.bcr_reg = USB_HS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+	.reset_reg = USB2_HS_PHY_ONLY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2_hs_phy_only_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+	},
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+	.reset_reg = QUSB2_PHY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qusb2_phy_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_qusb2_phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_core0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_CORE0_VCODEC0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_core0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_core0_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_core1_vcodec0_clk = {
+	.cbcr_reg = VENUS0_CORE1_VCODEC0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_core1_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_core1_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_vcodec0_clk.c),
+	},
+};
+
+static struct clk_ops clk_ops_debug_mux;
+
+static void __iomem *meas_base;
+
+static struct measure_clk apc0_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc0_m_clk",
+		CLK_INIT(apc0_m_clk.c),
+	},
+};
+
+static struct measure_clk apc1_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc1_m_clk",
+		CLK_INIT(apc1_m_clk.c),
+	},
+};
+
+static struct measure_clk cci_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "cci_m_clk",
+		CLK_INIT(cci_m_clk.c),
+	},
+};
+
+static struct mux_clk apss_debug_ter_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 8,
+	MUX_SRC_LIST(
+		{&apc0_m_clk.c, 0},
+		{&apc1_m_clk.c, 1},
+		{&cci_m_clk.c, 2},
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_ter_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_ter_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_sec_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x7,
+	.shift = 12,
+	MUX_SRC_LIST(
+		{&apss_debug_ter_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_ter_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_sec_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_sec_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_pri_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 16,
+	MUX_SRC_LIST(
+		{&apss_debug_sec_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_sec_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_pri_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_pri_mux.c),
+	},
+};
+
+static struct measure_clk_data debug_mux_priv = {
+	.cxo = &xo_clk_src.c,
+	.plltest_reg = GCC_PLLTEST_PAD_CFG,
+	.plltest_val = 0x51A00,
+	.xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+	.ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+	.status_reg = CLOCK_FRQ_MEASURE_STATUS,
+	.base = &virt_bases[GCC_BASE],
+};
+
+static struct mux_clk gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.ops = &mux_reg_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	MUX_REC_SRC_LIST(
+		&apss_debug_pri_mux.c,
+	),
+	MUX_SRC_LIST(
+		{ &apss_debug_pri_mux.c, 0x016A},
+		{ &snoc_clk.c,  0x0000 },
+		{ &sysmmnoc_clk.c,  0x0001 },
+		{ &pnoc_clk.c, 0x0008 },
+		{ &bimc_clk.c,  0x0154 },
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_bimc_gfx_clk.c, 0x002d },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_mdp_tbu_clk.c, 0x0051 },
+		{ &gcc_gfx_tbu_clk.c, 0x0052 },
+		{ &gcc_gfx_tcu_clk.c, 0x0053 },
+		{ &gcc_venus_tbu_clk.c, 0x0054 },
+		{ &gcc_gtcu_ahb_clk.c, 0x0058 },
+		{ &gcc_vfe_tbu_clk.c, 0x005a },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_jpeg_tbu_clk.c, 0x005c },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc1_ice_core_clk.c, 0x006a },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0096 },
+		{ &gcc_blsp2_ahb_clk.c, 0x0098 },
+		{ &gcc_blsp2_qup1_spi_apps_clk.c, 0x009a },
+		{ &gcc_blsp2_qup1_i2c_apps_clk.c, 0x009b },
+		{ &gcc_blsp2_uart1_apps_clk.c, 0x009c },
+		{ &gcc_blsp2_qup2_spi_apps_clk.c, 0x009e },
+		{ &gcc_blsp2_qup2_i2c_apps_clk.c, 0x00a0 },
+		{ &gcc_blsp2_uart2_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp2_qup3_spi_apps_clk.c, 0x00a3 },
+		{ &gcc_blsp2_qup3_i2c_apps_clk.c, 0x00a4 },
+		{ &gcc_blsp2_qup4_spi_apps_clk.c, 0x00a5 },
+		{ &gcc_blsp2_qup4_i2c_apps_clk.c, 0x00a6 },
+		{ &gcc_camss_ahb_clk.c, 0x00a8 },
+		{ &gcc_camss_top_ahb_clk.c, 0x00a9 },
+		{ &gcc_camss_micro_ahb_clk.c, 0x00aa },
+		{ &gcc_camss_gp0_clk.c, 0x00ab },
+		{ &gcc_camss_gp1_clk.c, 0x00ac },
+		{ &gcc_camss_mclk0_clk.c, 0x00ad },
+		{ &gcc_camss_mclk1_clk.c, 0x00ae },
+		{ &gcc_camss_cci_clk.c, 0x00af },
+		{ &gcc_camss_cci_ahb_clk.c, 0x00b0 },
+		{ &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+		{ &gcc_camss_csi1phytimer_clk.c, 0x00b2 },
+		{ &gcc_camss_jpeg0_clk.c, 0x00b3 },
+		{ &gcc_camss_jpeg_ahb_clk.c, 0x00b4 },
+		{ &gcc_camss_jpeg_axi_clk.c, 0x00b5 },
+		{ &gcc_camss_vfe0_clk.c, 0x00b8 },
+		{ &gcc_camss_cpp_clk.c, 0x00b9 },
+		{ &gcc_camss_cpp_ahb_clk.c, 0x00ba },
+		{ &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+		{ &gcc_camss_vfe_axi_clk.c, 0x00bc },
+		{ &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+		{ &gcc_camss_csi0_clk.c, 0x00c0 },
+		{ &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+		{ &gcc_camss_csi0phy_clk.c, 0x00c2 },
+		{ &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+		{ &gcc_camss_csi0pix_clk.c, 0x00c4 },
+		{ &gcc_camss_csi1_clk.c, 0x00c5 },
+		{ &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+		{ &gcc_camss_csi1phy_clk.c, 0x00c7 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+		{ &gcc_camss_csi1pix_clk.c, 0x00e1 },
+		{ &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+		{ &gcc_camss_csi2_clk.c, 0x00e3 },
+		{ &gcc_camss_csi2_ahb_clk.c, 0x00e4 },
+		{ &gcc_camss_csi2phy_clk.c, 0x00e5 },
+		{ &gcc_camss_csi2rdi_clk.c, 0x00e6 },
+		{ &gcc_camss_csi2pix_clk.c, 0x00e7 },
+		{ &gcc_cpp_tbu_clk.c, 0x00e9 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_usb_fs_ahb_clk.c, 0x00f1 },
+		{ &gcc_usb_fs_ic_clk.c, 0x00f4 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_bimc_gpu_clk.c, 0x0157 },
+		{ &gcc_ipa_tbu_clk.c, 0x0198 },
+		{ &gcc_vfe1_tbu_clk.c, 0x0199 },
+		{ &gcc_camss_csi_vfe1_clk.c, 0x01a0 },
+		{ &gcc_camss_vfe1_clk.c, 0x01a1 },
+		{ &gcc_camss_vfe1_ahb_clk.c, 0x01a2 },
+		{ &gcc_camss_vfe1_axi_clk.c, 0x01a3 },
+		{ &gcc_venus0_core0_vcodec0_clk.c, 0x01b8 },
+		{ &gcc_venus0_core1_vcodec0_clk.c, 0x01b9 },
+		{ &gcc_camss_mclk2_clk.c, 0x01bd },
+		{ &gcc_oxili_timer_clk.c, 0x01e9 },
+		{ &gcc_oxili_gfx3d_clk.c, 0x01ea },
+		{ &gcc_oxili_ahb_clk.c, 0x01eb },
+		{ &gcc_oxili_gmem_clk.c, 0x01f0 },
+		{ &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+		{ &gcc_venus0_axi_clk.c, 0x01f2 },
+		{ &gcc_venus0_ahb_clk.c, 0x01f3 },
+		{ &gcc_mdss_ahb_clk.c, 0x01f6 },
+		{ &gcc_mdss_axi_clk.c, 0x01f7 },
+		{ &gcc_mdss_pclk0_clk.c, 0x01f8 },
+		{ &gcc_mdss_mdp_clk.c, 0x01f9 },
+		{ &gcc_mdss_vsync_clk.c, 0x01fb },
+		{ &gcc_mdss_byte0_clk.c, 0x01fc },
+		{ &gcc_mdss_esc0_clk.c, 0x01fd },
+		{ &wcnss_m_clk.c, 0x0ec },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux.c),
+	},
+};
+
+static struct mux_clk gcc_debug_mux_8937 = {
+	.priv = &debug_mux_priv,
+	.ops = &mux_reg_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	MUX_REC_SRC_LIST(
+		&apss_debug_pri_mux.c,
+	),
+	MUX_SRC_LIST(
+		{ &apss_debug_pri_mux.c, 0x016A},
+		{ &snoc_clk.c,  0x0000 },
+		{ &sysmmnoc_clk.c,  0x0001 },
+		{ &pnoc_clk.c, 0x0008 },
+		{ &bimc_clk.c,  0x015A },
+		{ &ipa_clk.c, 0x1B0 },
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_bimc_gfx_clk.c, 0x002d },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_qdss_dap_clk.c, 0x0049 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_mdp_tbu_clk.c, 0x0051 },
+		{ &gcc_gfx_tbu_clk.c, 0x0052 },
+		{ &gcc_gfx_tcu_clk.c, 0x0053 },
+		{ &gcc_venus_tbu_clk.c, 0x0054 },
+		{ &gcc_gtcu_ahb_clk.c, 0x0058 },
+		{ &gcc_vfe_tbu_clk.c, 0x005a },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_jpeg_tbu_clk.c, 0x005c },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc1_ice_core_clk.c, 0x006a },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0096 },
+		{ &gcc_blsp2_ahb_clk.c, 0x0098 },
+		{ &gcc_blsp2_qup1_spi_apps_clk.c, 0x009a },
+		{ &gcc_blsp2_qup1_i2c_apps_clk.c, 0x009b },
+		{ &gcc_blsp2_uart1_apps_clk.c, 0x009c },
+		{ &gcc_blsp2_qup2_spi_apps_clk.c, 0x009e },
+		{ &gcc_blsp2_qup2_i2c_apps_clk.c, 0x00a0 },
+		{ &gcc_blsp2_uart2_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp2_qup3_spi_apps_clk.c, 0x00a3 },
+		{ &gcc_blsp2_qup3_i2c_apps_clk.c, 0x00a4 },
+		{ &gcc_blsp2_qup4_spi_apps_clk.c, 0x00a5 },
+		{ &gcc_blsp2_qup4_i2c_apps_clk.c, 0x00a6 },
+		{ &gcc_camss_ahb_clk.c, 0x00a8 },
+		{ &gcc_camss_top_ahb_clk.c, 0x00a9 },
+		{ &gcc_camss_micro_ahb_clk.c, 0x00aa },
+		{ &gcc_camss_gp0_clk.c, 0x00ab },
+		{ &gcc_camss_gp1_clk.c, 0x00ac },
+		{ &gcc_camss_mclk0_clk.c, 0x00ad },
+		{ &gcc_camss_mclk1_clk.c, 0x00ae },
+		{ &gcc_camss_cci_clk.c, 0x00af },
+		{ &gcc_camss_cci_ahb_clk.c, 0x00b0 },
+		{ &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+		{ &gcc_camss_csi1phytimer_clk.c, 0x00b2 },
+		{ &gcc_camss_jpeg0_clk.c, 0x00b3 },
+		{ &gcc_camss_jpeg_ahb_clk.c, 0x00b4 },
+		{ &gcc_camss_jpeg_axi_clk.c, 0x00b5 },
+		{ &gcc_camss_vfe0_clk.c, 0x00b8 },
+		{ &gcc_camss_cpp_clk.c, 0x00b9 },
+		{ &gcc_camss_cpp_ahb_clk.c, 0x00ba },
+		{ &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+		{ &gcc_camss_vfe_axi_clk.c, 0x00bc },
+		{ &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+		{ &gcc_camss_csi0_clk.c, 0x00c0 },
+		{ &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+		{ &gcc_camss_csi0phy_clk.c, 0x00c2 },
+		{ &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+		{ &gcc_camss_csi0pix_clk.c, 0x00c4 },
+		{ &gcc_camss_csi1_clk.c, 0x00c5 },
+		{ &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+		{ &gcc_camss_csi1phy_clk.c, 0x00c7 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+		{ &gcc_camss_csi1pix_clk.c, 0x00e1 },
+		{ &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+		{ &gcc_camss_csi2_clk.c, 0x00e3 },
+		{ &gcc_camss_csi2_ahb_clk.c, 0x00e4 },
+		{ &gcc_camss_csi2phy_clk.c, 0x00e5 },
+		{ &gcc_camss_csi2rdi_clk.c, 0x00e6 },
+		{ &gcc_camss_csi2pix_clk.c, 0x00e7 },
+		{ &gcc_cpp_tbu_clk.c, 0x00e9 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_bimc_gpu_clk.c, 0x0157 },
+		{ &gcc_ipa_tbu_clk.c, 0x0198 },
+		{ &gcc_vfe1_tbu_clk.c, 0x0199 },
+		{ &gcc_camss_csi_vfe1_clk.c, 0x01a0 },
+		{ &gcc_camss_vfe1_clk.c, 0x01a1 },
+		{ &gcc_camss_vfe1_ahb_clk.c, 0x01a2 },
+		{ &gcc_camss_vfe1_axi_clk.c, 0x01a3 },
+		{ &gcc_camss_cpp_axi_clk.c, 0x01a4 },
+		{ &gcc_venus0_core0_vcodec0_clk.c, 0x01b8 },
+		{ &gcc_dcc_clk.c, 0x01b9 },
+		{ &gcc_camss_mclk2_clk.c, 0x01bd },
+		{ &gcc_oxili_timer_clk.c, 0x01e9 },
+		{ &gcc_oxili_gfx3d_clk.c, 0x01ea },
+		{ &gcc_oxili_aon_clk.c, 0x00ee },
+		{ &gcc_oxili_ahb_clk.c, 0x01eb },
+		{ &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+		{ &gcc_venus0_axi_clk.c, 0x01f2 },
+		{ &gcc_venus0_ahb_clk.c, 0x01f3 },
+		{ &gcc_mdss_ahb_clk.c, 0x01f6 },
+		{ &gcc_mdss_axi_clk.c, 0x01f7 },
+		{ &gcc_mdss_pclk0_clk.c, 0x01f8 },
+		{ &gcc_mdss_pclk1_clk.c, 0x01e3 },
+		{ &gcc_mdss_mdp_clk.c, 0x01f9 },
+		{ &gcc_mdss_vsync_clk.c, 0x01fb },
+		{ &gcc_mdss_byte0_clk.c, 0x01fc },
+		{ &gcc_mdss_byte1_clk.c, 0x01e4 },
+		{ &gcc_mdss_esc0_clk.c, 0x01fd },
+		{ &gcc_mdss_esc1_clk.c, 0x01e5 },
+		{ &wcnss_m_clk.c, 0x0ec },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux_8937",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux_8937.c),
+	},
+};
+
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup_common[] = {
+	/* RPM clocks */
+	CLK_LIST(xo_clk_src),
+	CLK_LIST(xo_a_clk_src),
+	CLK_LIST(xo_otg_clk),
+	CLK_LIST(xo_lpm_clk),
+	CLK_LIST(xo_pil_mss_clk),
+	CLK_LIST(xo_pil_pronto_clk),
+	CLK_LIST(xo_wlan_clk),
+	CLK_LIST(xo_pil_lpass_clk),
+
+	CLK_LIST(sysmmnoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_a_clk),
+	CLK_LIST(sysmmnoc_msmbus_a_clk),
+	CLK_LIST(pnoc_msmbus_clk),
+	CLK_LIST(pnoc_msmbus_a_clk),
+	CLK_LIST(bimc_msmbus_clk),
+	CLK_LIST(bimc_msmbus_a_clk),
+	CLK_LIST(pnoc_keepalive_a_clk),
+
+	CLK_LIST(pnoc_usb_a_clk),
+	CLK_LIST(snoc_usb_a_clk),
+	CLK_LIST(bimc_usb_a_clk),
+	CLK_LIST(pnoc_usb_clk),
+	CLK_LIST(snoc_usb_clk),
+	CLK_LIST(bimc_usb_clk),
+
+	CLK_LIST(snoc_wcnss_a_clk),
+	CLK_LIST(bimc_wcnss_a_clk),
+
+	CLK_LIST(qdss_clk),
+	CLK_LIST(qdss_a_clk),
+
+	CLK_LIST(snoc_clk),
+	CLK_LIST(sysmmnoc_clk),
+	CLK_LIST(pnoc_clk),
+	CLK_LIST(bimc_clk),
+	CLK_LIST(snoc_a_clk),
+	CLK_LIST(sysmmnoc_a_clk),
+	CLK_LIST(pnoc_a_clk),
+	CLK_LIST(bimc_a_clk),
+
+	CLK_LIST(bb_clk1),
+	CLK_LIST(bb_clk1_a),
+	CLK_LIST(bb_clk2),
+	CLK_LIST(bb_clk2_a),
+	CLK_LIST(rf_clk2),
+	CLK_LIST(rf_clk2_a),
+	CLK_LIST(div_clk2),
+	CLK_LIST(div_clk2_a),
+
+	CLK_LIST(bb_clk1_pin),
+	CLK_LIST(bb_clk1_a_pin),
+	CLK_LIST(bb_clk2_pin),
+	CLK_LIST(bb_clk2_a_pin),
+
+	CLK_LIST(gpll0_clk_src),
+	CLK_LIST(gpll0_ao_clk_src),
+	CLK_LIST(gpll6_clk_src),
+	CLK_LIST(gpll4_clk_src),
+	CLK_LIST(gpll3_clk_src),
+	CLK_LIST(a53ss_c1_pll),
+	CLK_LIST(gcc_blsp1_ahb_clk),
+	CLK_LIST(gcc_blsp2_ahb_clk),
+	CLK_LIST(gcc_boot_rom_ahb_clk),
+	CLK_LIST(gcc_crypto_ahb_clk),
+	CLK_LIST(gcc_crypto_axi_clk),
+	CLK_LIST(gcc_crypto_clk),
+	CLK_LIST(gcc_prng_ahb_clk),
+	CLK_LIST(gcc_cpp_tbu_clk),
+	CLK_LIST(gcc_apss_tcu_clk),
+	CLK_LIST(gcc_jpeg_tbu_clk),
+	CLK_LIST(gcc_mdp_tbu_clk),
+	CLK_LIST(gcc_smmu_cfg_clk),
+	CLK_LIST(gcc_venus_tbu_clk),
+	CLK_LIST(gcc_vfe1_tbu_clk),
+	CLK_LIST(gcc_vfe_tbu_clk),
+	CLK_LIST(camss_top_ahb_clk_src),
+	CLK_LIST(apss_ahb_clk_src),
+	CLK_LIST(csi0_clk_src),
+	CLK_LIST(csi1_clk_src),
+	CLK_LIST(csi2_clk_src),
+	CLK_LIST(vcodec0_clk_src),
+	CLK_LIST(vfe0_clk_src),
+	CLK_LIST(vfe1_clk_src),
+	CLK_LIST(gfx3d_clk_src),
+	CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+	CLK_LIST(blsp1_uart1_apps_clk_src),
+	CLK_LIST(blsp1_uart2_apps_clk_src),
+	CLK_LIST(blsp2_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup1_spi_apps_clk_src),
+	CLK_LIST(blsp2_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp2_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp2_uart1_apps_clk_src),
+	CLK_LIST(blsp2_uart2_apps_clk_src),
+	CLK_LIST(cci_clk_src),
+	CLK_LIST(cpp_clk_src),
+	CLK_LIST(camss_gp0_clk_src),
+	CLK_LIST(camss_gp1_clk_src),
+	CLK_LIST(jpeg0_clk_src),
+	CLK_LIST(mclk0_clk_src),
+	CLK_LIST(mclk1_clk_src),
+	CLK_LIST(mclk2_clk_src),
+	CLK_LIST(csi0phytimer_clk_src),
+	CLK_LIST(csi1phytimer_clk_src),
+	CLK_LIST(crypto_clk_src),
+	CLK_LIST(gp1_clk_src),
+	CLK_LIST(gp2_clk_src),
+	CLK_LIST(gp3_clk_src),
+	CLK_LIST(esc0_clk_src),
+	CLK_LIST(mdp_clk_src),
+	CLK_LIST(vsync_clk_src),
+	CLK_LIST(pdm2_clk_src),
+	CLK_LIST(sdcc1_apps_clk_src),
+	CLK_LIST(sdcc1_ice_core_clk_src),
+	CLK_LIST(sdcc2_apps_clk_src),
+	CLK_LIST(usb_hs_system_clk_src),
+	CLK_LIST(gcc_bimc_gpu_clk),
+	CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_uart1_apps_clk),
+	CLK_LIST(gcc_blsp1_uart2_apps_clk),
+	CLK_LIST(gcc_blsp2_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup1_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_uart1_apps_clk),
+	CLK_LIST(gcc_blsp2_uart2_apps_clk),
+	CLK_LIST(gcc_camss_cci_ahb_clk),
+	CLK_LIST(gcc_camss_cci_clk),
+	CLK_LIST(gcc_camss_cpp_ahb_clk),
+	CLK_LIST(gcc_camss_cpp_axi_clk),
+	CLK_LIST(gcc_camss_cpp_clk),
+	CLK_LIST(gcc_camss_csi0_ahb_clk),
+	CLK_LIST(gcc_camss_csi0_clk),
+	CLK_LIST(gcc_camss_csi0phy_clk),
+	CLK_LIST(gcc_camss_csi0pix_clk),
+	CLK_LIST(gcc_camss_csi0rdi_clk),
+	CLK_LIST(gcc_camss_csi1_ahb_clk),
+	CLK_LIST(gcc_camss_csi1_clk),
+	CLK_LIST(gcc_camss_csi1phy_clk),
+	CLK_LIST(gcc_camss_csi1pix_clk),
+	CLK_LIST(gcc_camss_csi1rdi_clk),
+	CLK_LIST(gcc_camss_csi2_ahb_clk),
+	CLK_LIST(gcc_camss_csi2_clk),
+	CLK_LIST(gcc_camss_csi2phy_clk),
+	CLK_LIST(gcc_camss_csi2pix_clk),
+	CLK_LIST(gcc_camss_csi2rdi_clk),
+	CLK_LIST(gcc_camss_csi_vfe0_clk),
+	CLK_LIST(gcc_camss_csi_vfe1_clk),
+	CLK_LIST(gcc_camss_gp0_clk),
+	CLK_LIST(gcc_camss_gp1_clk),
+	CLK_LIST(gcc_camss_ispif_ahb_clk),
+	CLK_LIST(gcc_camss_jpeg0_clk),
+	CLK_LIST(gcc_camss_jpeg_ahb_clk),
+	CLK_LIST(gcc_camss_jpeg_axi_clk),
+	CLK_LIST(gcc_camss_mclk0_clk),
+	CLK_LIST(gcc_camss_mclk1_clk),
+	CLK_LIST(gcc_camss_mclk2_clk),
+	CLK_LIST(gcc_camss_micro_ahb_clk),
+	CLK_LIST(gcc_camss_csi0phytimer_clk),
+	CLK_LIST(gcc_camss_csi1phytimer_clk),
+	CLK_LIST(gcc_camss_ahb_clk),
+	CLK_LIST(gcc_camss_top_ahb_clk),
+	CLK_LIST(gcc_camss_vfe0_clk),
+	CLK_LIST(gcc_camss_vfe_ahb_clk),
+	CLK_LIST(gcc_camss_vfe_axi_clk),
+	CLK_LIST(gcc_camss_vfe1_ahb_clk),
+	CLK_LIST(gcc_camss_vfe1_axi_clk),
+	CLK_LIST(gcc_camss_vfe1_clk),
+	CLK_LIST(gcc_gp1_clk),
+	CLK_LIST(gcc_gp2_clk),
+	CLK_LIST(gcc_gp3_clk),
+	CLK_LIST(gcc_mdss_ahb_clk),
+	CLK_LIST(gcc_mdss_axi_clk),
+	CLK_LIST(gcc_mdss_esc0_clk),
+	CLK_LIST(gcc_mdss_mdp_clk),
+	CLK_LIST(gcc_mdss_vsync_clk),
+	CLK_LIST(gcc_mss_cfg_ahb_clk),
+	CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+	CLK_LIST(gcc_bimc_gfx_clk),
+	CLK_LIST(gcc_oxili_ahb_clk),
+	CLK_LIST(gcc_oxili_gfx3d_clk),
+	CLK_LIST(gcc_pdm2_clk),
+	CLK_LIST(gcc_pdm_ahb_clk),
+	CLK_LIST(gcc_sdcc1_ahb_clk),
+	CLK_LIST(gcc_sdcc1_apps_clk),
+	CLK_LIST(gcc_sdcc1_ice_core_clk),
+	CLK_LIST(gcc_sdcc2_ahb_clk),
+	CLK_LIST(gcc_sdcc2_apps_clk),
+	CLK_LIST(gcc_usb2a_phy_sleep_clk),
+	CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+	CLK_LIST(gcc_usb_hs_ahb_clk),
+	CLK_LIST(gcc_usb_hs_system_clk),
+	CLK_LIST(gcc_venus0_ahb_clk),
+	CLK_LIST(gcc_venus0_axi_clk),
+	CLK_LIST(gcc_venus0_core0_vcodec0_clk),
+	CLK_LIST(gcc_venus0_vcodec0_clk),
+
+	/* Reset clks */
+	CLK_LIST(gcc_usb2_hs_phy_only_clk),
+	CLK_LIST(gcc_qusb2_phy_clk),
+
+	/* WCNSS Debug */
+	CLK_LIST(wcnss_m_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8952[] = {
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(a53ss_cci_pll),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gpll0_clk_src_8952),
+	CLK_LIST(gpll0_ao_clk_src_8952),
+	CLK_LIST(gcc_oxili_gmem_clk),
+	CLK_LIST(usb_fs_ic_clk_src),
+	CLK_LIST(gcc_usb_fs_ic_clk),
+	CLK_LIST(usb_fs_system_clk_src),
+	CLK_LIST(gcc_usb_fs_system_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+	CLK_LIST(gcc_usb_fs_ahb_clk),
+	CLK_LIST(gcc_venus0_core1_vcodec0_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8937[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(esc1_clk_src),
+	CLK_LIST(gcc_mdss_esc1_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_oxili_aon_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8917[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(bimc_gpu_clk),
+	CLK_LIST(bimc_gpu_a_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8920[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(bimc_gpu_clk),
+	CLK_LIST(bimc_gpu_a_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8940[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(esc1_clk_src),
+	CLK_LIST(gcc_mdss_esc1_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_oxili_aon_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+};
+
+/* Please note that the order of reg-names is important */
+static int get_mmio_addr(struct platform_device *pdev, u32 nbases)
+{
+	int i, count;
+	const char *str;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	count = of_property_count_strings(dev->of_node, "reg-names");
+	if (count < nbases) {
+		dev_err(dev, "missing reg-names property, expected %d strings\n",
+				nbases);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < nbases; i++) {
+		of_property_read_string_index(dev->of_node, "reg-names", i,
+						&str);
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, str);
+		if (!res) {
+			dev_err(dev, "Unable to retrieve register base.\n");
+			return -ENOMEM;
+		}
+
+		virt_bases[i] = devm_ioremap(dev, res->start,
+							resource_size(res));
+		if (!virt_bases[i]) {
+			dev_err(dev, "Failed to map in CC registers.\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static const struct msm_reset_map gcc_8952_resets[] = {
+	[GCC_CAMSS_MICRO_BCR] = {0x56008},
+	[GCC_USB_FS_BCR] = {0x3F000},
+	[GCC_USB_HS_BCR] = {0x41000},
+	[GCC_USB2_HS_PHY_ONLY_BCR] = {0x41034},
+	[GCC_QUSB2_PHY_BCR] = {0x4103C},
+};
+
+static void override_for_8917(int speed_bin)
+{
+	gpll3_clk_src.c.rate = 930000000;
+
+	OVERRIDE_FMAX3(csi0,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi0, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi1,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi1, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi2,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi2, ftbl_gcc_camss_csi0_2_clk, 8937);
+
+	OVERRIDE_FMAX5(vfe0,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FTABLE(vfe0, ftbl_gcc_camss_vfe0_1_clk, 8917);
+	OVERRIDE_FMAX5(vfe1,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FTABLE(vfe1, ftbl_gcc_camss_vfe0_1_clk, 8917);
+	OVERRIDE_FTABLE(vcodec0, ftbl_gcc_venus0_vcodec0_clk, 8917);
+	OVERRIDE_FMAX5(vcodec0,
+		LOWER, 200000000, LOW, 270000000, NOMINAL, 308570000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FMAX4(cpp,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 360000000);
+	OVERRIDE_FTABLE(cpp, ftbl_gcc_camss_cpp_clk, 8917);
+	OVERRIDE_FMAX5(jpeg0,
+		LOWER, 133330000, LOW, 200000000, NOMINAL, 266670000,
+		NOM_PLUS, 308570000, HIGH, 320000000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(jpeg0, ftbl_gcc_camss_jpeg0_clk, 8937);
+
+	if (speed_bin) {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 270000000, LOW, 400000000, NOMINAL, 484800000,
+			NOM_PLUS, 523200000, HIGH, 650000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8917_650MHz);
+	} else {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 270000000, LOW, 400000000, NOMINAL, 484800000,
+			NOM_PLUS, 523200000, HIGH, 598000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8917);
+	}
+
+	OVERRIDE_FMAX1(cci, LOWER, 37500000);
+
+	OVERRIDE_FTABLE(csi0phytimer, ftbl_gcc_camss_csi0_1phytimer_clk, 8917);
+	OVERRIDE_FMAX3(csi0phytimer, LOWER, 100000000, LOW, 200000000,
+			NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi1phytimer, ftbl_gcc_camss_csi0_1phytimer_clk, 8917);
+	OVERRIDE_FMAX3(csi1phytimer, LOWER, 100000000, LOW, 200000000,
+			NOMINAL, 266670000);
+	OVERRIDE_FMAX2(gp1, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp2, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp3, LOWER, 100000000, NOMINAL, 200000000);
+
+	OVERRIDE_FMAX2(byte0, LOWER, 125000000, NOMINAL, 187500000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(byte0, ftbl_gcc_mdss_byte0_clk, 8937);
+	byte0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+
+	OVERRIDE_FMAX2(pclk0, LOWER, 166670000, NOMINAL, 250000000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(pclk0, ftbl_gcc_mdss_pclk0_clk, 8937);
+	pclk0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+
+	OVERRIDE_FMAX2(sdcc1_apps, LOWER, 200000000, NOMINAL, 400000000);
+	OVERRIDE_FTABLE(usb_hs_system, ftbl_gcc_usb_hs_system_clk, 8917);
+	OVERRIDE_FMAX3(usb_hs_system, LOWER, 800000000, NOMINAL, 133333000,
+			HIGH, 177780000);
+}
+
+static void override_for_8937(int speed_bin)
+{
+	gpll3_clk_src.c.rate = 900000000;
+	gpll3_clk_src.vco_tbl = p_vco_8937;
+	gpll3_clk_src.num_vco = ARRAY_SIZE(p_vco_8937);
+	OVERRIDE_FMAX2(gpll3, LOW, 800000000, NOMINAL, 1066000000);
+
+	OVERRIDE_FMAX1(cci, LOWER, 37500000);
+	OVERRIDE_FMAX3(csi0,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi0, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi1,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi1, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi2,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi2, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX4(vfe0,
+		LOWER, 160000000, LOW, 308570000, NOMINAL, 400000000,
+		NOM_PLUS, 432000000);
+	OVERRIDE_FTABLE(vfe0, ftbl_gcc_camss_vfe0_1_clk, 8937);
+	OVERRIDE_FMAX4(vfe1,
+		LOWER, 160000000, LOW, 308570000, NOMINAL, 400000000,
+		NOM_PLUS, 432000000);
+	OVERRIDE_FTABLE(vfe1, ftbl_gcc_camss_vfe0_1_clk, 8937);
+
+	if (speed_bin) {
+		OVERRIDE_FMAX6(gfx3d,
+			LOWER, 216000000, LOW, 300000000,
+			NOMINAL, 375000000, NOM_PLUS, 400000000,
+			HIGH, 450000000, SUPER_TUR, 475000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8937_475MHz);
+	} else {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 216000000, LOW, 300000000,
+			NOMINAL, 375000000, NOM_PLUS, 400000000,
+			HIGH, 450000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8937);
+	}
+
+	OVERRIDE_FMAX5(cpp,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 342860000, HIGH, 360000000);
+	OVERRIDE_FTABLE(cpp, ftbl_gcc_camss_cpp_clk, 8937);
+	OVERRIDE_FMAX5(jpeg0,
+		LOWER, 133330000, LOW, 200000000, NOMINAL, 266670000,
+		NOM_PLUS, 308570000, HIGH, 320000000);
+	OVERRIDE_FTABLE(jpeg0, ftbl_gcc_camss_jpeg0_clk, 8937);
+	OVERRIDE_FMAX2(csi0phytimer, LOWER, 100000000, LOW, 200000000);
+	OVERRIDE_FMAX2(csi1phytimer, LOWER, 100000000, LOW, 200000000);
+	OVERRIDE_FMAX2(gp1, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp2, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp3, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(byte0, LOWER, 125000000, NOMINAL, 187500000);
+	OVERRIDE_FTABLE(byte0, ftbl_gcc_mdss_byte0_clk, 8937);
+	OVERRIDE_FMAX2(byte1, LOWER, 125000000, NOMINAL, 187500000);
+	byte0_clk_src.current_freq = ftbl_gcc_mdss_byte0_clk_8937;
+	OVERRIDE_FMAX2(pclk0, LOWER, 166670000, NOMINAL, 250000000);
+	OVERRIDE_FTABLE(pclk0, ftbl_gcc_mdss_pclk0_clk, 8937);
+	OVERRIDE_FMAX2(pclk1, LOWER, 166670000, NOMINAL, 250000000);
+	pclk0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+	OVERRIDE_FTABLE(vcodec0, ftbl_gcc_venus0_vcodec0_clk, 8937);
+	OVERRIDE_FMAX5(vcodec0,
+		LOWER, 166150000, LOW, 240000000, NOMINAL, 308570000,
+		NOM_PLUS, 320000000, HIGH, 360000000);
+	OVERRIDE_FMAX2(sdcc1_apps, LOWER, 100000000,
+		NOMINAL, 400000000);
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin)
+{
+	struct resource *res;
+	void __iomem *base;
+	u32 config_efuse;
+
+	*bin = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			"No GPU speed binning available. Defaulting to 0.\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			"Unable to ioremap efuse reg address. Defaulting to 0.\n");
+		return;
+	}
+
+	config_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+	*bin = (config_efuse >> 31) & 0x1;
+
+	dev_info(&pdev->dev, "GPU speed bin: %d\n", *bin);
+}
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	int speed_bin;
+	u32 regval, nbases = N_BASES;
+	bool compat_bin = false;
+	bool compat_bin2 = false;
+	bool compat_bin3 = false;
+	bool compat_bin4 = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8937");
+
+	compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8917");
+
+	compat_bin3 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8940");
+
+	compat_bin4 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8920");
+
+	ret = vote_bimc(&bimc_clk, INT_MAX);
+	if (ret < 0)
+		return ret;
+
+	if (compat_bin2 || compat_bin4)
+		nbases = APCS_C0_PLL_BASE;
+
+	ret = get_mmio_addr(pdev, nbases);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[GCC_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+		return -ENOMEM;
+	}
+
+	vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+					"Unable to get vdd_dig regulator!!!\n");
+		return PTR_ERR(vdd_dig.regulator[0]);
+	}
+
+	if (!compat_bin2 && !compat_bin4) {
+		vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_pll");
+		if (IS_ERR(vdd_sr2_pll.regulator[0])) {
+			if (PTR_ERR(vdd_sr2_pll.regulator[0]) != -EPROBE_DEFER)
+				dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_pll regulator!!!\n");
+			return PTR_ERR(vdd_sr2_pll.regulator[0]);
+		}
+
+		vdd_sr2_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_dig");
+		if (IS_ERR(vdd_sr2_pll.regulator[1])) {
+			if (PTR_ERR(vdd_sr2_pll.regulator[1]) != -EPROBE_DEFER)
+				dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_dig regulator!!!\n");
+			return PTR_ERR(vdd_sr2_pll.regulator[1]);
+		}
+	}
+
+	vdd_hf_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_hf_pll");
+	if (IS_ERR(vdd_hf_pll.regulator[0])) {
+		if (PTR_ERR(vdd_hf_pll.regulator[0]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_pll regulator!!!\n");
+		return PTR_ERR(vdd_hf_pll.regulator[0]);
+	}
+
+	vdd_hf_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+							"vdd_hf_dig");
+	if (IS_ERR(vdd_hf_pll.regulator[1])) {
+		if (PTR_ERR(vdd_hf_pll.regulator[1]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Unable to get vdd_hf_dig regulator!!!\n");
+		return PTR_ERR(vdd_hf_pll.regulator[1]);
+	}
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	if (compat_bin || compat_bin3) {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c;
+		/* Oxili Ocmem in GX rail: OXILI_GMEM_CLAMP_IO */
+		regval = readl_relaxed(GCC_REG_BASE(GX_DOMAIN_MISC));
+		regval &= ~BIT(0);
+		writel_relaxed(regval, GCC_REG_BASE(GX_DOMAIN_MISC));
+		get_speed_bin(pdev, &speed_bin);
+		override_for_8937(speed_bin);
+
+		if (compat_bin3) {
+			if (speed_bin) {
+				gfx3d_clk_src.freq_tbl =
+					ftbl_gcc_oxili_gfx3d_clk_8940_500MHz;
+				gfx3d_clk_src.c.fmax[VDD_DIG_SUPER_TUR] =
+								500000000;
+			} else {
+				gfx3d_clk_src.freq_tbl =
+					ftbl_gcc_oxili_gfx3d_clk_8937_475MHz;
+				gfx3d_clk_src.c.fmax[VDD_DIG_SUPER_TUR] =
+								475000000;
+			}
+		}
+	} else if (compat_bin2 || compat_bin4) {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c;
+		vdd_dig.num_levels = VDD_DIG_NUM_8917;
+		vdd_dig.cur_level = VDD_DIG_NUM_8917;
+		vdd_hf_pll.num_levels = VDD_HF_PLL_NUM_8917;
+		vdd_hf_pll.cur_level = VDD_HF_PLL_NUM_8917;
+		get_speed_bin(pdev, &speed_bin);
+		override_for_8917(speed_bin);
+
+		if (compat_bin2) {
+			blsp1_qup2_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp1_qup3_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp1_qup4_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup1_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup2_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup3_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+		}
+	} else {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8952.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8952.c;
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_lookup_common,
+				ARRAY_SIZE(msm_clocks_lookup_common));
+	if (ret)
+		return ret;
+
+	if (compat_bin)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8937,
+					ARRAY_SIZE(msm_clocks_lookup_8937));
+	else if (compat_bin2)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8917,
+					ARRAY_SIZE(msm_clocks_lookup_8917));
+	else if (compat_bin3)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8940,
+					ARRAY_SIZE(msm_clocks_lookup_8940));
+	else if (compat_bin4)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8920,
+					ARRAY_SIZE(msm_clocks_lookup_8920));
+	else
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8952,
+					ARRAY_SIZE(msm_clocks_lookup_8952));
+	if (ret)
+		return ret;
+
+	ret = enable_rpm_scaling();
+	if (ret)
+		return ret;
+
+	clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+	clk_prepare_enable(&apss_ahb_clk_src.c);
+
+	/*
+	 *  Hold an active set vote for PCNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pnoc_keepalive_a_clk.c);
+
+	clk_prepare_enable(&xo_a_clk_src.c);
+	clk_prepare_enable(&gcc_blsp1_ahb_clk.c);
+	clk_prepare_enable(&gcc_blsp2_ahb_clk.c);
+	clk_prepare_enable(&gcc_blsp1_uart2_apps_clk.c);
+	clk_prepare_enable(&gcc_blsp1_uart1_apps_clk.c);
+	clk_prepare_enable(&gcc_bimc_gpu_clk.c);
+	clk_prepare_enable(&sysmmnoc_msmbus_a_clk.c);
+	clk_prepare_enable(&sysmmnoc_a_clk.c);
+
+	if (!compat_bin && !compat_bin3) {
+		/* Configure Sleep and Wakeup cycles for GMEM clock */
+		regval = readl_relaxed(GCC_REG_BASE(OXILI_GMEM_CBCR));
+		regval ^= 0xFF0;
+		regval |= CLKFLAG_WAKEUP_CYCLES << 8;
+		regval |= CLKFLAG_SLEEP_CYCLES << 4;
+		writel_relaxed(regval, GCC_REG_BASE(OXILI_GMEM_CBCR));
+	} else {
+		/* Configure Sleep and Wakeup cycles for OXILI clock */
+		regval = readl_relaxed(GCC_REG_BASE(OXILI_GFX3D_CBCR));
+		regval &= ~0xF0;
+		regval |= CLKFLAG_SLEEP_CYCLES << 4;
+		writel_relaxed(regval, GCC_REG_BASE(OXILI_GFX3D_CBCR));
+	}
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		return ret;
+
+	msm_reset_controller_register(pdev, gcc_8952_resets,
+			ARRAY_SIZE(gcc_8952_resets), virt_bases[GCC_BASE]);
+
+	dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+	{ .compatible = "qcom,gcc-8952" },
+	{ .compatible = "qcom,gcc-8937" },
+	{ .compatible = "qcom,gcc-8917" },
+	{ .compatible = "qcom,gcc-8940" },
+	{ .compatible = "qcom,gcc-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+	.probe = msm_gcc_probe,
+	.driver = {
+		.name = "qcom,gcc-8952",
+		.of_match_table = msm_clock_gcc_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int msm_gcc_spm_probe(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	bool compat_bin = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,spm-8952");
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spm_c0_base");
+	if (!res) {
+		dev_err(&pdev->dev, "SPM register base not defined for c0\n");
+		return -ENOMEM;
+	}
+
+	a53ss_c0_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+	if (!a53ss_c0_pll.spm_ctrl.spm_base) {
+		dev_err(&pdev->dev, "Failed to ioremap c0 spm registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spm_c1_base");
+	if (!res) {
+		dev_err(&pdev->dev, "SPM register base not defined for c1\n");
+		return -ENOMEM;
+	}
+
+	a53ss_c1_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+	if (!a53ss_c1_pll.spm_ctrl.spm_base) {
+		dev_err(&pdev->dev, "Failed to ioremap c1 spm registers\n");
+		return -ENOMEM;
+	}
+
+	if (compat_bin) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"spm_cci_base");
+		if (!res) {
+			dev_err(&pdev->dev, "SPM register base not defined for cci\n");
+			return -ENOMEM;
+		}
+
+		a53ss_cci_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev,
+						res->start, resource_size(res));
+		if (!a53ss_cci_pll.spm_ctrl.spm_base) {
+			dev_err(&pdev->dev, "Failed to ioremap cci spm registers\n");
+			return -ENOMEM;
+		}
+	}
+
+	dev_info(&pdev->dev, "Registered GCC SPM clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_spm_match_table[] = {
+	{ .compatible = "qcom,gcc-spm-8952" },
+	{ .compatible = "qcom,gcc-spm-8937" },
+	{}
+};
+
+static struct platform_driver msm_clock_spm_driver = {
+	.probe = msm_gcc_spm_probe,
+	.driver = {
+		.name = "qcom,gcc-spm-8952",
+		.of_match_table = msm_clock_spm_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&msm_clock_gcc_driver);
+	if (!ret)
+		ret = platform_driver_register(&msm_clock_spm_driver);
+
+	return ret;
+}
+
+static struct clk_lookup msm_clocks_measure[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(cci_m_clk),
+};
+
+static struct clk_lookup msm_clocks_measure_8937[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux_8937, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(cci_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+	bool compat_bin = false, compat_bin2 = false;
+	bool compat_bin3 = false;
+	bool compat_bin4 = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8937");
+
+	compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8917");
+
+	compat_bin3 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8940");
+
+	compat_bin4 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8920");
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+	if (!res) {
+		dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+		return -EINVAL;
+	}
+
+	meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!meas_base) {
+		dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+		return -ENOMEM;
+	}
+
+	clk_ops_debug_mux = clk_ops_gen_mux;
+	clk_ops_debug_mux.get_rate = measure_get_rate;
+
+	if (compat_bin2)
+		gcc_debug_mux_8937.post_div = 0x3;
+
+	if (!compat_bin && !compat_bin2 && !compat_bin3 && !compat_bin4)
+		ret =  of_msm_clock_register(pdev->dev.of_node,
+			msm_clocks_measure, ARRAY_SIZE(msm_clocks_measure));
+	else
+		ret =  of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_measure_8937,
+				ARRAY_SIZE(msm_clocks_measure_8937));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register debug Mux\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+	return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+	{ .compatible = "qcom,cc-debug-8952" },
+	{ .compatible = "qcom,cc-debug-8937" },
+	{ .compatible = "qcom,cc-debug-8917" },
+	{ .compatible = "qcom,cc-debug-8940" },
+	{ .compatible = "qcom,cc-debug-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+	.probe = msm_clock_debug_probe,
+	.driver = {
+		.name = "qcom,cc-debug-8952",
+		.of_match_table = msm_clock_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_clock_debug_init(void)
+{
+	return platform_driver_register(&msm_clock_debug_driver);
+}
+
+/* MDSS DSI_PHY_PLL */
+static struct clk_lookup msm_clocks_gcc_mdss_common[] = {
+	CLK_LIST(ext_pclk0_clk_src),
+	CLK_LIST(ext_byte0_clk_src),
+	CLK_LIST(byte0_clk_src),
+	CLK_LIST(pclk0_clk_src),
+	CLK_LIST(gcc_mdss_pclk0_clk),
+	CLK_LIST(gcc_mdss_byte0_clk),
+	CLK_LIST(mdss_mdp_vote_clk),
+	CLK_LIST(mdss_rotator_vote_clk),
+};
+
+static struct clk_lookup msm_clocks_gcc_mdss_8937[] = {
+	CLK_LIST(ext_pclk1_clk_src),
+	CLK_LIST(ext_byte1_clk_src),
+	CLK_LIST(byte1_clk_src),
+	CLK_LIST(pclk1_clk_src),
+	CLK_LIST(gcc_mdss_pclk1_clk),
+	CLK_LIST(gcc_mdss_byte1_clk),
+};
+
+static int msm_gcc_mdss_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct clk *curr_p;
+	bool compat_bin = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+				"qcom,gcc-mdss-8937");
+	if (!compat_bin)
+		compat_bin = of_device_is_compatible(pdev->dev.of_node,
+				"qcom,gcc-mdss-8940");
+
+	curr_p = ext_pclk0_clk_src.c.parent = devm_clk_get(&pdev->dev,
+								"pclk0_src");
+	if (IS_ERR(curr_p)) {
+		dev_err(&pdev->dev, "Failed to get pclk0 source.\n");
+		return PTR_ERR(curr_p);
+	}
+
+	curr_p = ext_byte0_clk_src.c.parent = devm_clk_get(&pdev->dev,
+								"byte0_src");
+	if (IS_ERR(curr_p)) {
+		dev_err(&pdev->dev, "Failed to get byte source.\n");
+		ret = PTR_ERR(curr_p);
+		goto byte0_fail;
+	}
+
+	ext_pclk0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+	ext_byte0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+
+	if (compat_bin) {
+		curr_p = ext_pclk1_clk_src.c.parent = devm_clk_get(&pdev->dev,
+									"pclk1_src");
+		if (IS_ERR(curr_p)) {
+			dev_err(&pdev->dev, "Failed to get pclk1 source.\n");
+			ret = PTR_ERR(curr_p);
+			goto fail;
+		}
+
+		curr_p = ext_byte1_clk_src.c.parent = devm_clk_get(&pdev->dev,
+									"byte1_src");
+		if (IS_ERR(curr_p)) {
+			dev_err(&pdev->dev, "Failed to get byte1 source.\n");
+			ret = PTR_ERR(curr_p);
+			goto byte1_fail;
+		}
+
+		ext_pclk1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+		ext_byte1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+			msm_clocks_gcc_mdss_common,
+			ARRAY_SIZE(msm_clocks_gcc_mdss_common));
+	if (ret)
+		goto fail;
+
+	if (compat_bin) {
+		ret = of_msm_clock_register(pdev->dev.of_node,
+		msm_clocks_gcc_mdss_8937,
+		ARRAY_SIZE(msm_clocks_gcc_mdss_8937));
+		if (ret)
+			goto fail_8937;
+	}
+
+	dev_info(&pdev->dev, "Registered GCC MDSS clocks.\n");
+
+	return ret;
+fail_8937:
+	devm_clk_put(&pdev->dev, ext_byte1_clk_src.c.parent);
+byte1_fail:
+	devm_clk_put(&pdev->dev, ext_pclk1_clk_src.c.parent);
+fail:
+	devm_clk_put(&pdev->dev, ext_byte0_clk_src.c.parent);
+byte0_fail:
+	devm_clk_put(&pdev->dev, ext_pclk0_clk_src.c.parent);
+	return ret;
+
+}
+
+static const struct of_device_id msm_clock_mdss_match_table[] = {
+	{ .compatible = "qcom,gcc-mdss-8952" },
+	{ .compatible = "qcom,gcc-mdss-8937" },
+	{ .compatible = "qcom,gcc-mdss-8917" },
+	{ .compatible = "qcom,gcc-mdss-8940" },
+	{ .compatible = "qcom,gcc-mdss-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_mdss_driver = {
+	.probe = msm_gcc_mdss_probe,
+	.driver = {
+		.name = "gcc-mdss-8952",
+		.of_match_table = msm_clock_mdss_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_mdss_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_mdss_driver);
+}
+arch_initcall(msm_gcc_init);
+fs_initcall_sync(msm_gcc_mdss_init);
+late_initcall(msm_clock_debug_init);
diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c
index b2dc3d26..57adebf 100644
--- a/drivers/clk/msm/clock-gcc-8953.c
+++ b/drivers/clk/msm/clock-gcc-8953.c
@@ -3797,13 +3797,6 @@
 	clk_set_rate(&apss_ahb_clk_src.c, 19200000);
 	clk_prepare_enable(&apss_ahb_clk_src.c);
 
-	clk_prepare_enable(&gcc_blsp1_ahb_clk.c);
-	clk_prepare_enable(&gcc_usb30_master_clk.c);
-	clk_prepare_enable(&gcc_usb30_mock_utmi_clk.c);
-	clk_prepare_enable(&gcc_blsp1_uart1_apps_clk.c);
-	clk_prepare_enable(&gcc_apss_ahb_clk.c);
-	clk_prepare_enable(&gcc_crypto_ahb_clk.c);
-	clk_prepare_enable(&gcc_crypto_axi_clk.c);
 	/*
 	 * Hold an active set vote for PCNOC AHB source. Sleep set
 	 * vote is 0.
@@ -3822,6 +3815,7 @@
 
 static const struct of_device_id msm_clock_gcc_match_table[] = {
 	{ .compatible = "qcom,gcc-8953" },
+	{ .compatible = "qcom,gcc-sdm632" },
 	{},
 };
 
@@ -3871,6 +3865,7 @@
 
 static const struct of_device_id msm_clock_debug_match_table[] = {
 	{ .compatible = "qcom,cc-debug-8953" },
+	{ .compatible = "qcom,cc-debug-sdm632" },
 	{}
 };
 
@@ -3983,6 +3978,7 @@
 
 static const struct of_device_id msm_clock_mdss_match_table[] = {
 	{ .compatible = "qcom,gcc-mdss-8953" },
+	{ .compatible = "qcom,gcc-mdss-sdm632" },
 	{}
 };
 
@@ -4131,6 +4127,7 @@
 static const struct of_device_id msm_clock_gfx_match_table[] = {
 	{ .compatible = "qcom,gcc-gfx-8953" },
 	{ .compatible = "qcom,gcc-gfx-sdm450" },
+	{ .compatible = "qcom,gcc-gfx-sdm632" },
 	{}
 };
 
diff --git a/drivers/clk/msm/clock-gcc-mdm9607.c b/drivers/clk/msm/clock-gcc-mdm9607.c
new file mode 100644
index 0000000..3900b08
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-mdm9607.c
@@ -0,0 +1,1954 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/mdm-clocks-9607.h>
+#include <dt-bindings/clock/mdm-clocks-hwio-9607.h>
+
+#include "clock.h"
+
+enum {
+	GCC_BASE,
+	DEBUG_BASE,
+	APCS_PLL_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src,
+				RPM_MISC_CLK_TYPE, XO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE, PCNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_usb_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_usb_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+
+#define F_APCS_STROMER_PLL(f, l, m, pre_div, post_div, vco) \
+	{ \
+		.freq_hz = (f), \
+		.l_val = (l), \
+		.a_val = (m), \
+		.pre_div_val = BVAL(14, 12, (pre_div)), \
+		.post_div_val = BVAL(11, 8, (post_div)), \
+		.vco_val = BVAL(21, 20, (vco)), \
+	}
+
+static DEFINE_VDD_REGULATORS(vdd_stromer_pll, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+static struct alpha_pll_masks pll_masks_p = {
+	.lock_mask = BIT(31),
+	.active_mask = BIT(30),
+	.vco_mask = BM(21, 20) >> 20,
+	.vco_shift = 20,
+	.alpha_en_mask = BIT(24),
+	.output_mask = 0xf,
+	.update_mask = BIT(22),
+	.post_div_mask = BM(11, 8),
+};
+
+static struct alpha_pll_vco_tbl p_vco[] = {
+	VCO(0,  700000000, 1400000000),
+};
+
+static struct alpha_pll_clk a7sspll = {
+	.masks = &pll_masks_p,
+	.vco_tbl = p_vco,
+	.num_vco = ARRAY_SIZE(p_vco),
+	.base = &virt_bases[APCS_PLL_BASE],
+	.offset = APCS_MODE,
+	.slew = true,
+	.enable_config = 1,
+	.post_div_config = 0,
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a7sspll",
+		.ops = &clk_ops_dyna_alpha_pll,
+		VDD_STROMER_FMAX_MAP1(LOW, 1400000000),
+		CLK_INIT(a7sspll.c),
+	},
+};
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_ao_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll2_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(3),
+	.status_reg = (void __iomem *)GPLL2_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 480000000,
+		.dbg_name = "gpll2_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll2_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 614400000,
+		.dbg_name = "gpll1_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src[] = {
+	F(  19200000,           xo_a,    1,    0,     0),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+	.cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_apss_ahb_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "apss_ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(apss_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_emac_0_125m_clk_src[] = {
+	F(      19200000,                   xo,    1,    0,     0),
+	F_EXT(  25000000,      emac_0_125m_clk,    5,    0,     0),
+	F_EXT( 125000000,      emac_0_125m_clk,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk emac_0_125m_clk_src = {
+	.cmd_rcgr_reg = EMAC_0_125M_CMD_RCGR,
+	.current_freq = ftbl_emac_0_125m_clk_src,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_emac_0_125m_clk_src,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "emac_0_125m_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+		CLK_INIT(emac_0_125m_clk_src.c),
+		},
+};
+
+static struct clk_freq_tbl ftbl_emac_0_sys_25m_clk_src[] = {
+	F(      19200000,                   xo,    1,    0,     0),
+	F_EXT(	25000000,      emac_0_125m_clk,    5,    0,     0),
+	F_EXT( 125000000,      emac_0_125m_clk,    1,    0,     0),
+	F_END
+};
+static struct rcg_clk emac_0_sys_25m_clk_src = {
+	.cmd_rcgr_reg = EMAC_0_SYS_25M_CMD_RCGR,
+	.current_freq = ftbl_emac_0_sys_25m_clk_src,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_emac_0_sys_25m_clk_src,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "emac_0_sys_25m_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+		CLK_INIT(emac_0_sys_25m_clk_src.c),
+		},
+};
+
+static struct clk_freq_tbl ftbl_emac_0_tx_clk_src[] = {
+	F(      19200000,                   xo,    1,    0,     0),
+	F_EXT( 125000000,        emac_0_tx_clk,    1,    0,     0),
+	F_END
+};
+static struct rcg_clk emac_0_tx_clk_src = {
+	.cmd_rcgr_reg = EMAC_0_TX_CMD_RCGR,
+	.current_freq = ftbl_emac_0_tx_clk_src,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_emac_0_tx_clk_src,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "emac_0_tx_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 125000000),
+		CLK_INIT(emac_0_tx_clk_src.c),
+		},
+};
+
+static struct clk_freq_tbl ftbl_blsp_i2c_apps_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup2_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup3_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  18180000,          gpll0,    1,    1,    44),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  36360000,          gpll0,    1,    1,    22),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup3_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 18180000, NOMINAL, 36360000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup4_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup4_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup5_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup5_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup6_spi_apps_clk_src[] = {
+	F(    960000,             xo,   10,    1,     2),
+	F(   4800000,             xo,    4,    0,     0),
+	F(   9600000,             xo,    2,    0,     0),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup6_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
+	F(   3686400,          gpll0,    1,   72, 15625),
+	F(   7372800,          gpll0,    1,  144, 15625),
+	F(  14745600,          gpll0,    1,  288, 15625),
+	F(  16000000,          gpll0,   10,    1,     5),
+	F(  19200000,             xo,    1,    0,     0),
+	F(  24000000,          gpll0,    1,    3,   100),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  32000000,          gpll0,    1,    1,    25),
+	F(  40000000,          gpll0,    1,    1,    20),
+	F(  46400000,          gpll0,    1,   29,   500),
+	F(  48000000,          gpll0,    1,    3,    50),
+	F(  51200000,          gpll0,    1,    8,   125),
+	F(  56000000,          gpll0,    1,    7,   100),
+	F(  58982400,          gpll0,    1, 1152, 15625),
+	F(  60000000,          gpll0,    1,    3,    40),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 48480000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_crypto_clk_src[] = {
+	F(  50000000,          gpll0,   16,    0,     0),
+	F(  80000000,          gpll0,   10,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+	.cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_crypto_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "crypto_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+		CLK_INIT(crypto_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gp_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg = GP1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg = GP2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg = GP3_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_pdm2_clk_src[] = {
+	F(  64000000,          gpll0, 12.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_sdcc_apps_clk[] = {
+	F(    144000,             xo,   16,    3,    25),
+	F(    400000,             xo,   12,    1,     4),
+	F(  20000000,          gpll0,   10,    1,     4),
+	F(  25000000,          gpll0,   16,    1,     2),
+	F(  50000000,          gpll0,   16,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 177777778,          gpll0,  4.5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_sdcc_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_sdcc_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb_hs_system_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F(  57140000,          gpll0,   14,    0,     0),
+	F(  69565000,          gpll0, 11.5,    0,     0),
+	F( 133330000,          gpll0,    6,    0,     0),
+	F( 177778000,          gpll0,  4.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_usb_hs_system_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 69570000, NOMINAL, 133330000,
+						HIGH, 177780000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_clk_src[] = {
+	F( 480000000,          gpll2,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_usb_hsic_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 480000000),
+		CLK_INIT(usb_hsic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_io_cal_clk_src[] = {
+	F(   9600000,             xo,    2,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_usb_hsic_io_cal_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_io_cal_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 9600000),
+		CLK_INIT(usb_hsic_io_cal_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb_hsic_system_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F(  57140000,          gpll0,   14,    0,     0),
+	F( 133330000,          gpll0,    6,    0,     0),
+	F( 177778000,          gpll0,  4.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_usb_hsic_system_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 57140000, NOMINAL, 133330000,
+							HIGH, 177778000),
+		CLK_INIT(usb_hsic_system_clk_src.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_ahb_clk = {
+	.cbcr_reg = APSS_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(14),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_axi_clk = {
+	.cbcr_reg = APSS_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(7),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+	.cbcr_reg = CRYPTO_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+	.cbcr_reg = CRYPTO_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+	.cbcr_reg = CRYPTO_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+	.cbcr_reg = APSS_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(8),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+	.cbcr_reg = SMMU_CFG_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_smmu_cfg_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_smmu_cfg_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_qdss_dap_clk = {
+	.cbcr_reg = QDSS_DAP_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(19),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qdss_dap_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_qdss_dap_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.parent = &blsp1_qup5_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.parent = &blsp1_qup5_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.parent = &blsp1_qup6_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.parent = &blsp1_qup6_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.parent = &blsp1_uart5_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.parent = &blsp1_uart6_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.parent = &gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.parent = &gp2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.parent = &gp3_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_125m_clk = {
+	.cbcr_reg = EMAC_0_125M_CBCR,
+	.has_sibling = 0,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_125m_clk",
+		.parent = &emac_0_125m_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_125m_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_ahb_clk = {
+	.cbcr_reg = EMAC_0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_axi_clk = {
+	.cbcr_reg = EMAC_0_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_sys_25m_clk = {
+	.cbcr_reg = EMAC_0_SYS_25M_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_sys_25m_clk",
+		.parent = &emac_0_sys_25m_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_sys_25m_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_sys_clk = {
+	.cbcr_reg = EMAC_0_SYS_CBCR,
+	.has_sibling = 1,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_sys_clk",
+		.parent = &emac_0_125m_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_sys_clk.c),
+	},
+};
+
+static struct branch_clk gcc_emac_0_tx_clk = {
+	.cbcr_reg = EMAC_0_TX_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_tx_clk",
+		.parent = &emac_0_tx_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_emac_0_tx_clk.c),
+	},
+};
+
+static struct gate_clk gcc_emac_0_rx_clk = {
+	.en_reg = EMAC_0_RX_CBCR,
+	.en_mask = BIT(0),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_emac_0_rx_clk",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_emac_0_rx_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+	.cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.bcr_reg = USB_HS_BCR,
+	.has_sibling = 0,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+	.cbcr_reg = USB_HSIC_AHB_CBCR,
+	.has_sibling = 1,
+	.toggle_memory = true,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+	.cbcr_reg = USB_HSIC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_clk",
+		.parent = &usb_hsic_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_clk",
+		.parent = &usb_hsic_io_cal_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+	.bcr_reg  = USB_HS_HSIC_BCR,
+	.toggle_memory = true,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_system_clk",
+		.parent = &usb_hsic_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_system_clk.c),
+	},
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+	.reset_reg = USB2_HS_PHY_ONLY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2_hs_phy_only_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+	},
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+	.reset_reg = QUSB2_PHY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qusb2_phy_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_qusb2_phy_clk.c),
+	},
+};
+
+static struct measure_clk apc0_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc0_m_clk",
+		CLK_INIT(apc0_m_clk.c),
+	},
+};
+
+static struct measure_clk l2_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "l2_m_clk",
+		CLK_INIT(l2_m_clk.c),
+	},
+};
+
+static void __iomem *meas_base;
+
+static struct mux_clk apss_debug_pri_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x7,
+	.shift = 3,
+	MUX_SRC_LIST(
+		{&apc0_m_clk.c, 3},
+		{&l2_m_clk.c, 2},
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_pri_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_pri_mux.c),
+	},
+};
+
+static int  gcc_set_mux_sel(struct mux_clk *clk, int sel)
+{
+	u32 regval;
+
+	regval = readl_relaxed(GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+	regval &= 0x1FF;
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	if (sel == 0xFFFF)
+		return 0;
+	mux_reg_ops.set_mux_sel(clk, sel);
+
+	return 0;
+}
+
+static struct measure_clk_data debug_mux_priv = {
+	.cxo = &xo_clk_src.c,
+	.plltest_reg = PLLTEST_PAD_CFG,
+	.plltest_val = 0x51A00,
+	.xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+	.ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+	.status_reg = CLOCK_FRQ_MEASURE_STATUS,
+	.base = &virt_bases[DEBUG_BASE],
+};
+static struct clk_ops clk_ops_debug_mux;
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct mux_clk gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.ops = &gcc_debug_mux_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[DEBUG_BASE],
+	MUX_SRC_LIST(
+		{ &pcnoc_clk.c, 0x0008 },
+		{ &bimc_clk.c, 0x155 },
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_qdss_dap_clk.c, 0x0049 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_uart3_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+		{ &gcc_blsp1_uart4_apps_clk.c, 0x009a },
+		{ &gcc_blsp1_qup5_spi_apps_clk.c, 0x009c },
+		{ &gcc_blsp1_qup5_i2c_apps_clk.c, 0x009d },
+		{ &gcc_blsp1_uart5_apps_clk.c, 0x009e },
+		{ &gcc_blsp1_qup6_spi_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp1_qup6_i2c_apps_clk.c, 0x00a2 },
+		{ &gcc_blsp1_uart6_apps_clk.c, 0x00a3 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_apss_ahb_clk.c, 0x0168 },
+		{ &gcc_apss_axi_clk.c, 0x0169 },
+		{ &gcc_usb_hsic_ahb_clk.c, 0x0198 },
+		{ &gcc_usb_hsic_system_clk.c, 0x0199 },
+		{ &gcc_usb_hsic_clk.c, 0x019a },
+		{ &gcc_usb_hsic_io_cal_clk.c, 0x019b },
+		{ &gcc_usb_hsic_io_cal_sleep_clk.c, 0x019c },
+		{ &gcc_emac_0_axi_clk.c, 0x01b8 },
+		{ &gcc_emac_0_ahb_clk.c, 0x01b9 },
+		{ &gcc_emac_0_sys_25m_clk.c, 0x01ba },
+		{ &gcc_emac_0_tx_clk.c, 0x01bb },
+		{ &gcc_emac_0_125m_clk.c, 0x01bc },
+		{ &gcc_emac_0_rx_clk.c, 0x01bd },
+		{ &gcc_emac_0_sys_clk.c, 0x01be },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux.c),
+	},
+};
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup[] = {
+	 CLK_LIST(gpll0_clk_src),
+	 CLK_LIST(gpll0_ao_clk_src),
+	 CLK_LIST(gpll2_clk_src),
+	 CLK_LIST(gpll1_clk_src),
+	 CLK_LIST(a7sspll),
+
+	 CLK_LIST(pcnoc_clk),
+	 CLK_LIST(pcnoc_a_clk),
+	 CLK_LIST(pcnoc_msmbus_clk),
+	 CLK_LIST(pcnoc_msmbus_a_clk),
+	 CLK_LIST(pcnoc_keepalive_a_clk),
+	 CLK_LIST(pcnoc_usb_clk),
+	 CLK_LIST(pcnoc_usb_a_clk),
+	 CLK_LIST(bimc_clk),
+	 CLK_LIST(bimc_a_clk),
+	 CLK_LIST(bimc_msmbus_clk),
+	 CLK_LIST(bimc_msmbus_a_clk),
+	 CLK_LIST(bimc_usb_clk),
+	 CLK_LIST(bimc_usb_a_clk),
+	 CLK_LIST(qdss_clk),
+	 CLK_LIST(qdss_a_clk),
+	 CLK_LIST(qpic_clk),
+	 CLK_LIST(qpic_a_clk),
+	 CLK_LIST(xo_clk_src),
+	 CLK_LIST(xo_a_clk_src),
+	 CLK_LIST(xo_otg_clk),
+	 CLK_LIST(xo_lpm_clk),
+	 CLK_LIST(xo_pil_mss_clk),
+
+	 CLK_LIST(bb_clk1),
+	 CLK_LIST(bb_clk1_pin),
+
+	 CLK_LIST(gcc_apss_ahb_clk),
+	 CLK_LIST(gcc_apss_axi_clk),
+	 CLK_LIST(gcc_blsp1_ahb_clk),
+	 CLK_LIST(gcc_boot_rom_ahb_clk),
+	 CLK_LIST(gcc_crypto_ahb_clk),
+	 CLK_LIST(gcc_crypto_axi_clk),
+	 CLK_LIST(gcc_crypto_clk),
+	 CLK_LIST(gcc_prng_ahb_clk),
+	 CLK_LIST(gcc_apss_tcu_clk),
+	 CLK_LIST(gcc_qdss_dap_clk),
+	 CLK_LIST(gcc_smmu_cfg_clk),
+	 CLK_LIST(apss_ahb_clk_src),
+	 CLK_LIST(emac_0_125m_clk_src),
+	 CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	 CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+	 CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+	 CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+	 CLK_LIST(blsp1_qup5_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup5_spi_apps_clk_src),
+	 CLK_LIST(blsp1_qup6_i2c_apps_clk_src),
+	 CLK_LIST(blsp1_qup6_spi_apps_clk_src),
+	 CLK_LIST(blsp1_uart1_apps_clk_src),
+	 CLK_LIST(blsp1_uart2_apps_clk_src),
+	 CLK_LIST(blsp1_uart3_apps_clk_src),
+	 CLK_LIST(blsp1_uart4_apps_clk_src),
+	 CLK_LIST(blsp1_uart5_apps_clk_src),
+	 CLK_LIST(blsp1_uart6_apps_clk_src),
+	 CLK_LIST(crypto_clk_src),
+	 CLK_LIST(gp1_clk_src),
+	 CLK_LIST(gp2_clk_src),
+	 CLK_LIST(gp3_clk_src),
+	 CLK_LIST(pdm2_clk_src),
+	 CLK_LIST(sdcc1_apps_clk_src),
+	 CLK_LIST(sdcc2_apps_clk_src),
+	 CLK_LIST(emac_0_sys_25m_clk_src),
+	 CLK_LIST(emac_0_tx_clk_src),
+	 CLK_LIST(usb_hs_system_clk_src),
+	 CLK_LIST(usb_hsic_clk_src),
+	 CLK_LIST(usb_hsic_io_cal_clk_src),
+	 CLK_LIST(usb_hsic_system_clk_src),
+	 CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup5_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup5_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup6_i2c_apps_clk),
+	 CLK_LIST(gcc_blsp1_qup6_spi_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart1_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart2_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart3_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart4_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart5_apps_clk),
+	 CLK_LIST(gcc_blsp1_uart6_apps_clk),
+	 CLK_LIST(gcc_gp1_clk),
+	 CLK_LIST(gcc_gp2_clk),
+	 CLK_LIST(gcc_gp3_clk),
+	 CLK_LIST(gcc_mss_cfg_ahb_clk),
+	 CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+	 CLK_LIST(gcc_pdm2_clk),
+	 CLK_LIST(gcc_pdm_ahb_clk),
+	 CLK_LIST(gcc_sdcc1_ahb_clk),
+	 CLK_LIST(gcc_sdcc1_apps_clk),
+	 CLK_LIST(gcc_sdcc2_ahb_clk),
+	 CLK_LIST(gcc_sdcc2_apps_clk),
+	 CLK_LIST(gcc_emac_0_125m_clk),
+	 CLK_LIST(gcc_emac_0_ahb_clk),
+	 CLK_LIST(gcc_emac_0_axi_clk),
+	 CLK_LIST(gcc_emac_0_sys_25m_clk),
+	 CLK_LIST(gcc_emac_0_sys_clk),
+	 CLK_LIST(gcc_emac_0_tx_clk),
+	 CLK_LIST(gcc_emac_0_rx_clk),
+	 CLK_LIST(gcc_usb2a_phy_sleep_clk),
+	 CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+	 CLK_LIST(gcc_usb_hs_ahb_clk),
+	 CLK_LIST(gcc_usb_hs_system_clk),
+	 CLK_LIST(gcc_usb_hsic_ahb_clk),
+	 CLK_LIST(gcc_usb_hsic_clk),
+	 CLK_LIST(gcc_usb_hsic_io_cal_clk),
+	 CLK_LIST(gcc_usb_hsic_io_cal_sleep_clk),
+	 CLK_LIST(gcc_usb_hsic_system_clk),
+	 CLK_LIST(gcc_usb2_hs_phy_only_clk),
+	 CLK_LIST(gcc_qusb2_phy_clk),
+};
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	u32 regval;
+
+	ret = vote_bimc(&bimc_clk, INT_MAX);
+	if (ret < 0)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[GCC_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+	if (!res) {
+		dev_err(&pdev->dev, "APCS PLL Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[APCS_PLL_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[APCS_PLL_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap APCS PLL registers\n");
+		return -ENOMEM;
+	}
+
+	vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+					"Unable to get vdd_dig regulator!!!\n");
+		return PTR_ERR(vdd_dig.regulator[0]);
+	}
+
+	vdd_stromer_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_stromer_dig");
+	if (IS_ERR(vdd_stromer_pll.regulator[0])) {
+		if (!(PTR_ERR(vdd_stromer_pll.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_stromer_dig regulator!!!\n");
+		return PTR_ERR(vdd_stromer_pll.regulator[0]);
+	}
+
+	 /*Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_lookup,
+				ARRAY_SIZE(msm_clocks_lookup));
+	if (ret)
+		return ret;
+
+	ret = enable_rpm_scaling();
+	if (ret)
+		return ret;
+
+	clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+	clk_prepare_enable(&apss_ahb_clk_src.c);
+	/*
+	 * Hold an active set vote for PCNOC AHB source. Sleep set
+	 * vote is 0.
+	 */
+	clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+	clk_prepare_enable(&xo_a_clk_src.c);
+
+	dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+	{ .compatible = "qcom,gcc-mdm9607" },
+	{},
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+	.probe = msm_gcc_probe,
+	.driver = {
+		.name = "qcom,gcc-mdm9607",
+		.of_match_table = msm_clock_gcc_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_init);
+
+static struct clk_lookup msm_clocks_measure[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(l2_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	clk_ops_debug_mux = clk_ops_gen_mux;
+	clk_ops_debug_mux.get_rate = measure_get_rate;
+
+	gcc_debug_mux_ops = mux_reg_ops;
+	gcc_debug_mux_ops.set_mux_sel = gcc_set_mux_sel;
+
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[DEBUG_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[DEBUG_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap debug cc registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+	if (!res) {
+		dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+		return -EINVAL;
+	}
+
+	meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!meas_base) {
+		dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+		return -ENOMEM;
+	}
+
+	ret =  of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure,
+					ARRAY_SIZE(msm_clocks_measure));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register debug Mux\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+	return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+	{ .compatible = "qcom,cc-debug-mdm9607" },
+	{}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+	.probe = msm_clock_debug_probe,
+	.driver = {
+		.name = "qcom,cc-debug-mdm9607",
+		.of_match_table = msm_clock_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_clock_debug_init(void)
+{
+	return platform_driver_register(&msm_clock_debug_driver);
+}
+
+late_initcall(msm_clock_debug_init);
diff --git a/drivers/clk/msm/clock-gcc-mdm9650.c b/drivers/clk/msm/clock-gcc-mdm9650.c
new file mode 100644
index 0000000..ea351a1
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-mdm9650.c
@@ -0,0 +1,1862 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/mdm-clocks-9650.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include "vdd-level-9650.h"
+
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+#define RPM_IPA_CLK_TYPE	0x617069
+#define RPM_CE_CLK_TYPE		0x6563
+#define RPM_QPIC_CLK_TYPE	0x63697071
+
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+
+#define CXO_CLK_SRC_ID		0x0
+#define QDSS_CLK_ID		0x1
+#define PCNOC_CLK_ID		0x0
+#define SNOC_CLK_ID		0x1
+#define BIMC_CLK_ID		0x0
+#define IPA_CLK_ID		0x0
+#define QPIC_CLK_ID		0x0
+#define CE_CLK_ID		0x0
+#define XO_ID			0x0
+#define MSS_CFG_AHB_CLK_ID	0x0
+
+#define RF_CLK1_ID		0x4
+#define RF_CLK2_ID		0x5
+#define RF_CLK3_ID		0x6
+#define LN_BB_CLK_ID		0x8
+#define DIV_CLK1_ID		0xb
+
+#define RF_CLK1_PIN_ID		0x4
+#define RF_CLK2_PIN_ID		0x5
+#define RF_CLK3_PIN_ID		0x6
+
+static void __iomem *virt_base;
+static void __iomem *virt_dbgbase;
+static void __iomem *virt_apcsbase;
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_base + (x))
+
+#define xo_source_val 0
+#define xo_a_clk_source_val 0
+#define gpll0_out_main_cgc_source_val 1
+#define gpll0_ao_out_main_cgc_source_val 1
+#define gpll0_out_main_div2_cgc_source_val 2
+
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_EXT(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+static DEFINE_VDD_REGULATORS(vdd_dig_ao, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define GPLL0_MODE                                       (0x21000)
+#define MSS_Q6_BIMC_AXI_CBCR                             (0x49004)
+#define QUSB2A_PHY_BCR                                   (0x41028)
+#define SDCC1_APPS_CMD_RCGR                              (0x42004)
+#define SDCC1_APPS_CBCR                                  (0x42018)
+#define SDCC1_AHB_CBCR                                   (0x4201C)
+#define BLSP1_AHB_CBCR                                   (0x1008)
+#define BLSP1_QUP1_SPI_APPS_CBCR                         (0x2004)
+#define BLSP1_QUP1_I2C_APPS_CBCR                         (0x2008)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR                     (0x200C)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR                     (0x3000)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR                     (0x4000)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR                     (0x5000)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR                     (0x2024)
+#define BLSP1_UART1_APPS_CBCR                            (0x203C)
+#define BLSP1_UART1_APPS_CMD_RCGR                        (0x2044)
+#define BLSP1_QUP2_SPI_APPS_CBCR                         (0x300C)
+#define BLSP1_QUP2_I2C_APPS_CBCR                         (0x3010)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR                     (0x3014)
+#define BLSP1_UART2_APPS_CBCR                            (0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR                        (0x3034)
+#define BLSP1_QUP3_SPI_APPS_CBCR                         (0x401C)
+#define BLSP1_QUP3_I2C_APPS_CBCR                         (0x4020)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR                     (0x4024)
+#define BLSP1_UART3_APPS_CBCR                            (0x403C)
+#define BLSP1_UART3_APPS_CMD_RCGR                        (0x4044)
+#define BLSP1_QUP4_SPI_APPS_CBCR                         (0x501C)
+#define BLSP1_QUP4_I2C_APPS_CBCR                         (0x5020)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR                     (0x5024)
+#define BLSP1_UART4_APPS_CBCR                            (0x503C)
+#define BLSP1_UART4_APPS_CMD_RCGR                        (0x5044)
+#define PDM_AHB_CBCR                                     (0x44004)
+#define PDM2_CBCR                                        (0x4400C)
+#define PDM2_CMD_RCGR                                    (0x44010)
+#define PRNG_AHB_CBCR                                    (0x13004)
+#define BOOT_ROM_AHB_CBCR                                (0x1300C)
+#define RPM_MISC                                         (0x2D028)
+#define GCC_XO_CMD_RCGR                                  (0x30018)
+#define GCC_XO_DIV4_CBCR                                 (0x30034)
+#define APSS_TCU_CBCR                                    (0x12018)
+#define SMMU_CFG_CBCR                                    (0x12038)
+#define APCS_GPLL_ENA_VOTE                               (0x45000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE                       (0x45004)
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE                  (0x4500C)
+#define APSS_AHB_CMD_RCGR                                (0x46000)
+#define GCC_DEBUG_CLK_CTL                                (0x74000)
+#define CLOCK_FRQ_MEASURE_CTL                            (0x74004)
+#define CLOCK_FRQ_MEASURE_STATUS                         (0x74008)
+#define PLLTEST_PAD_CFG                                  (0x7400C)
+#define GP1_CBCR                                         (0x8000)
+#define GP1_CMD_RCGR                                     (0x8004)
+#define GP2_CBCR                                         (0x9000)
+#define GP2_CMD_RCGR                                     (0x9004)
+#define GP3_CBCR                                         (0xA000)
+#define GP3_CMD_RCGR                                     (0xA004)
+#define PCIE_CFG_AHB_CBCR                                (0x5D008)
+#define PCIE_PIPE_CBCR                                   (0x5D00C)
+#define PCIE_AXI_CBCR                                    (0x5D010)
+#define PCIE_SLEEP_CBCR                                  (0x5D014)
+#define PCIE_AXI_MSTR_CBCR                               (0x5D018)
+#define PCIE_AUX_CMD_RCGR                                (0x5D030)
+#define PCIEPHY_PHY_BCR                                  (0x5D048)
+#define PCIE_REF_CLK_EN                                  (0x5D04C)
+#define PCIE_PHY_BCR                                     (0x5D050)
+#define USB_SS_REF_CLK_EN                                (0x5E07C)
+#define USB_PHY_CFG_AHB_CBCR                             (0x5E080)
+#define SYS_NOC_USB3_AXI_CBCR                            (0x5E084)
+#define USB_30_BCR                                       (0x5E070)
+#define USB30_MASTER_CBCR                                (0x5E000)
+#define USB30_SLEEP_CBCR                                 (0x5E004)
+#define USB30_MOCK_UTMI_CBCR                             (0x5E008)
+#define USB30_MASTER_CMD_RCGR                            (0x5E00C)
+#define USB30_MOCK_UTMI_CMD_RCGR                         (0x5E020)
+#define USB3_PHY_BCR                                     (0x5E034)
+#define USB3PHY_PHY_BCR                                  (0x5E03C)
+#define USB3_PIPE_CBCR                                   (0x5E040)
+#define USB3_AUX_CBCR                                    (0x5E044)
+#define USB3_AUX_CMD_RCGR                                (0x5E05C)
+#define USB3_AXI_TBU_CBCR                                (0x12060)
+#define PCIE_AXI_TBU_CBCR                                (0x12064)
+#define QUSB_REF_CLK_EN                                  (0x41030)
+#define DCC_CBCR                                         (0x77004)
+#define MSS_CFG_AHB_CBCR				 (0x49000)
+
+/* sdx20 */
+#define PCIE_AUX_CBCR						(0x5D024)
+#define PCIE_AUX_PHY_CMD_RCGR		(0x5D030)
+#define PCIE_BCR					(0x5D004)
+#define PCIE_AUX_CLK_SEL			(0x5D028)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE,
+			  XO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD(ce_clk, ce_a_clk, RPM_CE_CLK_TYPE,
+		   CE_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE,
+		   PCNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE,
+		   BIMC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE,
+		   SNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(ipa_clk, ipa_a_clk, RPM_IPA_CLK_TYPE,
+		   IPA_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE,
+		   QPIC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE,
+			QDSS_CLK_ID);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(mcd_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_pm_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_sps_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(qcedev_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(qcrypto_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(qseecom_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(scm_ce_clk, &ce_clk.c, 85710000);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_lpm_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk1, div_clk1_ao, DIV_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(ln_bb_clk, ln_bb_a_clk, LN_BB_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk1, rf_clk1_ao, RF_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_ao, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk3, rf_clk3_ao, RF_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk1_pin, rf_clk1_pin_ao,
+				     RF_CLK1_PIN_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_pin_ao,
+				     RF_CLK2_PIN_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk3_pin, rf_clk3_pin_ao,
+				     RF_CLK3_PIN_ID);
+
+static struct alpha_pll_masks alpha_pll_masks_20nm_p = {
+	.lock_mask = BIT(31),
+	.update_mask = BIT(22),
+	.vco_mask = BM(21, 20) >> 20,
+	.vco_shift = 20,
+	.alpha_en_mask = BIT(24),
+};
+
+static struct alpha_pll_vco_tbl alpha_pll_vco_20nm_p[] = {
+	VCO(3,  250000000,  500000000),
+	VCO(2,  500000000, 1000000000),
+	VCO(1, 1000000000, 1500000000),
+	VCO(0, 1500000000, 2000000000),
+};
+
+static struct alpha_pll_clk a7pll_clk = {
+	.masks = &alpha_pll_masks_20nm_p,
+	.base = &virt_apcsbase,
+	.vco_tbl = alpha_pll_vco_20nm_p,
+	.num_vco = ARRAY_SIZE(alpha_pll_vco_20nm_p),
+	.c = {
+		.parent = &xo_a_clk.c,
+		.dbg_name = "a7pll_clk",
+		.ops = &clk_ops_alpha_pll,
+		VDD_DIG_FMAX_MAP2_AO(LOW, 1000000000, NOMINAL, 2000000000),
+		CLK_INIT(a7pll_clk.c),
+	},
+};
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_base,
+	.c = {
+		.rate = 600000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll0",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_ao = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_base,
+	.c = {
+		.rate = 600000000,
+		.parent = &xo_a_clk.c,
+		.dbg_name = "gpll0_ao",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll0_out_main_cgc, &gpll0.c);
+DEFINE_EXT_CLK(gpll0_ao_out_main_cgc, &gpll0_ao.c);
+
+DEFINE_FIXED_DIV_CLK(gpll0_out_main_div2_cgc, 2, &gpll0.c);
+
+static struct gate_clk gpll0_out_msscc = {
+	.en_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(18),
+	.delay_us = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gpll0_out_msscc",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gpll0_out_msscc.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src[] = {
+	F(  19200000,         xo_a_clk,    1,    0,     0),
+	F(  50000000, gpll0_ao_out_main_cgc,   12,    0,     0),
+	F( 100000000, gpll0_ao_out_main_cgc,    6,    0,     0),
+	F( 133333333, gpll0_ao_out_main_cgc,  4.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+	.cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_apss_ahb_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "apss_ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP4(LOWER, 19200000, LOW, 50000000,
+				  NOMINAL, 100000000, HIGH, 133333333),
+		CLK_INIT(apss_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb30_master_clk_src[] = {
+	F(  60000000, gpll0_out_main_div2_cgc,    5,    0,     0),
+	F( 120000000, gpll0_out_main_cgc,    5,    0,     0),
+	F( 171430000, gpll0_out_main_cgc,  3.5,    0,     0),
+	F( 200000000, gpll0_out_main_cgc,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+	.cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_usb30_master_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "usb30_master_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP4(LOWER, 60000000, LOW, 120000000,
+				  NOMINAL, 171430000, HIGH, 200000000),
+		CLK_INIT(usb30_master_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp_i2c_apps_clk_src[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F(  50000000, gpll0_out_main_cgc,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000, gpll0_out_main_cgc,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000, gpll0_out_main_cgc, 12.5,    1,     2),
+	F(  25000000, gpll0_out_main_cgc,   12,    1,     2),
+	F(  50000000, gpll0_out_main_cgc,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+				  NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup2_spi_apps_clk_src[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000, gpll0_out_main_cgc,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000, gpll0_out_main_cgc, 12.5,    1,     2),
+	F(  25000000, gpll0_out_main_cgc,   12,    1,     2),
+	F(  50000000, gpll0_out_main_cgc,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+				  NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup3_spi_apps_clk_src[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000, gpll0_out_main_cgc,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000, gpll0_out_main_cgc, 12.5,    1,     2),
+	F(  25000000, gpll0_out_main_cgc,   12,    1,     2),
+	F(  50000000, gpll0_out_main_cgc,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup3_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+				  NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_blsp_i2c_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp1_qup4_spi_apps_clk_src[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000, gpll0_out_main_cgc,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000, gpll0_out_main_cgc, 12.5,    1,     2),
+	F(  25000000, gpll0_out_main_cgc,   12,    1,     2),
+	F(  50000000, gpll0_out_main_cgc,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp1_qup4_spi_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 12500000, LOW, 25000000,
+				  NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
+	F(   3686400, gpll0_out_main_div2_cgc,    1,  192, 15625),
+	F(   7372800, gpll0_out_main_div2_cgc,    1,  384, 15625),
+	F(  14745600, gpll0_out_main_div2_cgc,    1,  768, 15625),
+	F(  16000000, gpll0_out_main_div2_cgc,    1,    4,    75),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000, gpll0_out_main_cgc,    5,    1,     5),
+	F(  32000000, gpll0_out_main_cgc,    1,    4,    75),
+	F(  40000000, gpll0_out_main_cgc,   15,    0,     0),
+	F(  46400000, gpll0_out_main_cgc,    1,   29,   375),
+	F(  48000000, gpll0_out_main_cgc, 12.5,    0,     0),
+	F(  51200000, gpll0_out_main_cgc,    1,   32,   375),
+	F(  56000000, gpll0_out_main_cgc,    1,    7,    75),
+	F(  58982400, gpll0_out_main_cgc,    1, 1536, 15625),
+	F(  60000000, gpll0_out_main_cgc,   10,    0,     0),
+	F(  63157895, gpll0_out_main_cgc,  9.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+				  NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+				  NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+				  NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_blsp_uart_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 48000000,
+				  NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gp_clk_src[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F(  50000000, gpll0_out_main_div2_cgc,    6,    0,     0),
+	F( 100000000, gpll0_out_main_cgc,    6,    0,     0),
+	F( 200000000, gpll0_out_main_cgc,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg = GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg = GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg = GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gp_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_pcie_aux_clk_src[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pcie_aux_clk_src = {
+	.cmd_rcgr_reg = PCIE_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_pcie_aux_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "pcie_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(pcie_aux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_pdm2_clk_src[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F(  60000000, gpll0_out_main_cgc,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+	F(    144000,         xo,   16,    3,    25),
+	F(    400000,         xo,   12,    1,     4),
+	F(  20000000, gpll0_out_main_div2_cgc,   15,    0,     0),
+	F(  25000000, gpll0_out_main_div2_cgc,   12,    0,     0),
+	F(  50000000, gpll0_out_main_div2_cgc,    6,    0,     0),
+	F( 100000000, gpll0_out_main_cgc,    6,    0,     0),
+	F( 200000000, gpll0_out_main_cgc,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F(  30000000, gpll0_out_main_div2_cgc,   10,    0,     0),
+	F(  60000000, gpll0_out_main_cgc,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+	.cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "usb30_mock_utmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 30000000, LOW, 60000000),
+		CLK_INIT(usb30_mock_utmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_usb3_aux_clk_src[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F_END
+};
+
+static struct rcg_clk usb3_aux_clk_src = {
+	.cmd_rcgr_reg = USB3_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_usb3_aux_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "usb3_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(usb3_aux_clk_src.c),
+	},
+};
+
+static struct reset_clk gcc_pcie_phy_reset = {
+	.reset_reg = PCIE_PHY_BCR,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_phy_reset",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_pcie_phy_reset.c),
+	},
+};
+
+static struct reset_clk gcc_qusb2a_phy_reset = {
+	.reset_reg = QUSB2A_PHY_BCR,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_qusb2a_phy_reset",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_qusb2a_phy_reset.c),
+	},
+};
+
+static struct reset_clk gcc_usb3phy_phy_reset = {
+	.reset_reg = USB3PHY_PHY_BCR,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb3phy_phy_reset",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb3phy_phy_reset.c),
+	},
+};
+
+static struct reset_clk gcc_usb3_phy_reset = {
+	.reset_reg = USB3_PHY_BCR,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb3_phy_reset",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb3_phy_reset.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(7),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_dcc_clk = {
+	.cbcr_reg = DCC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_dcc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_dcc_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.parent = &gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.parent = &gp2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.parent = &gp3_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_clk = {
+	.cbcr_reg = PCIE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_mstr_clk = {
+	.cbcr_reg = PCIE_AXI_MSTR_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_axi_mstr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_mstr_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_cfg_ahb_clk = {
+	.cbcr_reg = PCIE_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_pipe_clk = {
+	.cbcr_reg = PCIE_PIPE_CBCR,
+	.bcr_reg = PCIEPHY_PHY_BCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.halt_check = DELAY,
+	.c = {
+		.dbg_name = "gcc_pcie_pipe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_sleep_clk = {
+	.cbcr_reg = PCIE_SLEEP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_sleep_clk",
+		.parent = &pcie_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(8),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+	.cbcr_reg = APSS_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_apss_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_pcie_axi_tbu_clk = {
+	.cbcr_reg = PCIE_AXI_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(16),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_axi_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_pcie_axi_tbu_clk.c),
+	},
+};
+
+static struct gate_clk gcc_pcie_ref_clk = {
+	.en_reg = PCIE_REF_CLK_EN,
+	.en_mask = BIT(0),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_pcie_ref_clk",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_pcie_ref_clk.c),
+	},
+};
+
+static struct gate_clk gcc_usb_ss_ref_clk = {
+	.en_reg = USB_SS_REF_CLK_EN,
+	.en_mask = BIT(0),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb_ss_ref_clk",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_usb_ss_ref_clk.c),
+	},
+};
+
+static struct gate_clk gcc_qusb_ref_clk = {
+	.en_reg = QUSB_REF_CLK_EN,
+	.en_mask = BIT(0),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_qusb_ref_clk",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_qusb_ref_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+	.cbcr_reg = SMMU_CFG_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_smmu_cfg_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_smmu_cfg_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_usb3_axi_tbu_clk = {
+	.cbcr_reg = USB3_AXI_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(15),
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb3_axi_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_usb3_axi_tbu_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+	.cbcr_reg = USB30_MASTER_CBCR,
+	.bcr_reg = USB_30_BCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb30_master_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_master_clk.c),
+		.depends = &gcc_sys_noc_usb3_axi_clk.c,
+	},
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb30_mock_utmi_clk",
+		.parent = &usb30_mock_utmi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_sleep_clk = {
+	.cbcr_reg = USB30_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb30_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb3_aux_clk = {
+	.cbcr_reg = USB3_AUX_CBCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb3_aux_clk",
+		.parent = &usb3_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb3_aux_clk.c),
+	},
+};
+
+static struct gate_clk gcc_usb3_pipe_clk = {
+	.en_reg = USB3_PIPE_CBCR,
+	.en_mask = BIT(0),
+	.delay_us = 50,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb3_pipe_clk",
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_usb3_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_phy_cfg_ahb_clk = {
+	.cbcr_reg = USB_PHY_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_usb_phy_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_phy_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct mux_clk gcc_debug_mux;
+static struct clk_ops clk_ops_debug_mux;
+static struct clk_mux_ops gcc_debug_mux_ops;
+static struct branch_clk gcc_pcie_aux_clk;
+
+static struct measure_clk_data debug_mux_priv = {
+	.cxo = &xo.c,
+	.plltest_reg = PLLTEST_PAD_CFG,
+	.plltest_val = 0x51A00,
+	.xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+	.ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+	.status_reg = CLOCK_FRQ_MEASURE_STATUS,
+	.base = &virt_base,
+};
+
+static struct mux_clk gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.ops = &gcc_debug_mux_ops,
+	.en_mask = BIT(16),
+	.mask = 0x3FF,
+	.base = &virt_dbgbase,
+	MUX_REC_SRC_LIST(
+	),
+	MUX_SRC_LIST(
+		{ &snoc_clk.c, 0x0000 },
+		{ &gcc_sys_noc_usb3_axi_clk.c, 0x0001 },
+		{ &pcnoc_clk.c, 0x0008 },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &qdss_clk.c, 0x0042 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_uart3_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0098 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0099 },
+		{ &gcc_blsp1_uart4_apps_clk.c, 0x009a },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &ce_clk.c, 0x0138 },
+		{ &bimc_clk.c, 0x0155 },
+		{ &gcc_usb3_axi_tbu_clk.c, 0x0203 },
+		{ &gcc_pcie_axi_tbu_clk.c, 0x0204 },
+		{ &ipa_clk.c, 0x0218 },
+		{ &qpic_clk.c, 0x0220 },
+		{ &gcc_usb30_master_clk.c, 0x0230 },
+		{ &gcc_usb30_sleep_clk.c, 0x0231 },
+		{ &gcc_usb30_mock_utmi_clk.c, 0x0232 },
+		{ &gcc_usb_phy_cfg_ahb_clk.c, 0x0233 },
+		{ &gcc_usb3_pipe_clk.c, 0x0234 },
+		{ &gcc_usb3_aux_clk.c, 0x0235 },
+		{ &gcc_pcie_cfg_ahb_clk.c, 0x0238 },
+		{ &gcc_pcie_pipe_clk.c, 0x0239 },
+		{ &gcc_pcie_axi_clk.c, 0x023a },
+		{ &gcc_pcie_sleep_clk.c, 0x023b },
+		{ &gcc_pcie_axi_mstr_clk.c, 0x023c },
+		{ &gcc_dcc_clk.c, 0x0278 },
+		{&gcc_pcie_aux_clk.c, 0x023d },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux.c),
+	},
+};
+
+static struct clk_lookup msm_clocks_rpm_9650[] = {
+	CLK_LIST(xo),
+	CLK_LIST(xo_a_clk),
+	CLK_LIST(ce_clk),
+	CLK_LIST(ce_a_clk),
+	CLK_LIST(pcnoc_clk),
+	CLK_LIST(pcnoc_a_clk),
+	CLK_LIST(bimc_clk),
+	CLK_LIST(bimc_a_clk),
+	CLK_LIST(snoc_clk),
+	CLK_LIST(snoc_a_clk),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(qpic_clk),
+	CLK_LIST(qpic_a_clk),
+	CLK_LIST(qdss_clk),
+	CLK_LIST(qdss_a_clk),
+	CLK_LIST(bimc_msmbus_clk),
+	CLK_LIST(bimc_msmbus_a_clk),
+	CLK_LIST(mcd_ce_clk),
+	CLK_LIST(pcnoc_keepalive_a_clk),
+	CLK_LIST(pcnoc_msmbus_clk),
+	CLK_LIST(pcnoc_msmbus_a_clk),
+	CLK_LIST(pcnoc_pm_clk),
+	CLK_LIST(pcnoc_sps_clk),
+	CLK_LIST(qcedev_ce_clk),
+	CLK_LIST(qcrypto_ce_clk),
+	CLK_LIST(qseecom_ce_clk),
+	CLK_LIST(scm_ce_clk),
+	CLK_LIST(snoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_a_clk),
+	CLK_LIST(cxo_dwc3_clk),
+	CLK_LIST(cxo_lpm_clk),
+	CLK_LIST(cxo_otg_clk),
+	CLK_LIST(div_clk1),
+	CLK_LIST(div_clk1_ao),
+	CLK_LIST(ln_bb_clk),
+	CLK_LIST(ln_bb_a_clk),
+	CLK_LIST(rf_clk1),
+	CLK_LIST(rf_clk1_ao),
+	CLK_LIST(rf_clk2),
+	CLK_LIST(rf_clk2_ao),
+	CLK_LIST(rf_clk3),
+	CLK_LIST(rf_clk3_ao),
+	CLK_LIST(rf_clk1_pin),
+	CLK_LIST(rf_clk1_pin_ao),
+	CLK_LIST(rf_clk2_pin),
+	CLK_LIST(rf_clk2_pin_ao),
+	CLK_LIST(rf_clk3_pin),
+	CLK_LIST(rf_clk3_pin_ao),
+};
+
+static struct clk_lookup msm_clocks_gcc_9650[] = {
+	CLK_LIST(gpll0),
+	CLK_LIST(gpll0_ao),
+	CLK_LIST(gpll0_out_main_cgc),
+	CLK_LIST(gpll0_out_main_div2_cgc),
+	CLK_LIST(gpll0_out_msscc),
+	CLK_LIST(apss_ahb_clk_src),
+	CLK_LIST(usb30_master_clk_src),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+	CLK_LIST(blsp1_uart1_apps_clk_src),
+	CLK_LIST(blsp1_uart2_apps_clk_src),
+	CLK_LIST(blsp1_uart3_apps_clk_src),
+	CLK_LIST(blsp1_uart4_apps_clk_src),
+	CLK_LIST(gp1_clk_src),
+	CLK_LIST(gp2_clk_src),
+	CLK_LIST(gp3_clk_src),
+	CLK_LIST(pcie_aux_clk_src),
+	CLK_LIST(pdm2_clk_src),
+	CLK_LIST(sdcc1_apps_clk_src),
+	CLK_LIST(usb30_mock_utmi_clk_src),
+	CLK_LIST(usb3_aux_clk_src),
+	CLK_LIST(gcc_pcie_phy_reset),
+	CLK_LIST(gcc_qusb2a_phy_reset),
+	CLK_LIST(gcc_usb3phy_phy_reset),
+	CLK_LIST(gcc_usb3_phy_reset),
+	CLK_LIST(gcc_blsp1_ahb_clk),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_uart1_apps_clk),
+	CLK_LIST(gcc_blsp1_uart2_apps_clk),
+	CLK_LIST(gcc_blsp1_uart3_apps_clk),
+	CLK_LIST(gcc_blsp1_uart4_apps_clk),
+	CLK_LIST(gcc_boot_rom_ahb_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_gp1_clk),
+	CLK_LIST(gcc_gp2_clk),
+	CLK_LIST(gcc_gp3_clk),
+	CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+	CLK_LIST(gcc_pcie_axi_clk),
+	CLK_LIST(gcc_pcie_axi_mstr_clk),
+	CLK_LIST(gcc_pcie_cfg_ahb_clk),
+	CLK_LIST(gcc_pcie_pipe_clk),
+	CLK_LIST(gcc_pcie_sleep_clk),
+	CLK_LIST(gcc_pdm2_clk),
+	CLK_LIST(gcc_pdm_ahb_clk),
+	CLK_LIST(gcc_prng_ahb_clk),
+	CLK_LIST(gcc_sdcc1_ahb_clk),
+	CLK_LIST(gcc_sdcc1_apps_clk),
+	CLK_LIST(gcc_apss_tcu_clk),
+	CLK_LIST(gcc_pcie_axi_tbu_clk),
+	CLK_LIST(gcc_pcie_ref_clk),
+	CLK_LIST(gcc_usb_ss_ref_clk),
+	CLK_LIST(gcc_qusb_ref_clk),
+	CLK_LIST(gcc_smmu_cfg_clk),
+	CLK_LIST(gcc_usb3_axi_tbu_clk),
+	CLK_LIST(gcc_sys_noc_usb3_axi_clk),
+	CLK_LIST(gcc_usb30_master_clk),
+	CLK_LIST(gcc_usb30_mock_utmi_clk),
+	CLK_LIST(gcc_usb30_sleep_clk),
+	CLK_LIST(gcc_usb3_aux_clk),
+	CLK_LIST(gcc_usb3_pipe_clk),
+	CLK_LIST(gcc_usb_phy_cfg_ahb_clk),
+	CLK_LIST(gcc_mss_cfg_ahb_clk),
+	CLK_LIST(a7pll_clk),
+};
+
+/* sdx20 */
+/* Fractional Val offset from PLL base */
+#define APCS_CPU_PLL_FRAC_OFF	0x40
+
+static int set_pcie_aux_mux_sel(struct mux_clk *clk, int sel);
+static int get_pcie_aux_mux_sel(struct mux_clk *clk);
+
+static struct alpha_pll_masks fabia_pll_masks_p = {
+	.lock_mask = BIT(31),
+	.active_mask = BIT(30),
+	.update_mask = BIT(22),
+	.output_mask = 0xf,
+};
+
+static struct alpha_pll_vco_tbl fabia_pll_vco_p[] = {
+	VCO(0,  250000000,  2000000000),
+	VCO(1,  125000000,  1000000000),
+};
+
+static struct rcg_clk pcie_aux_phy_clk_src = {
+	.cmd_rcgr_reg = PCIE_AUX_PHY_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_pcie_aux_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "pcie_aux_phy_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(pcie_aux_phy_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_apss_ahb_clk_src_sdx20[] = {
+	F(  50000000, gpll0_ao_out_main_cgc,   12,    0,     0),
+	F( 100000000, gpll0_ao_out_main_cgc,    6,    0,     0),
+	F( 133333333, gpll0_ao_out_main_cgc,  4.5,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_usb30_mock_utmi_clk_src_sdx20[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+DEFINE_CLK_DUMMY(pcie20_phy_aux_clk, 16600000);
+
+static struct clk_mux_ops pcie_aux_mux_ops = {
+	.set_mux_sel = set_pcie_aux_mux_sel,
+	.get_mux_sel = get_pcie_aux_mux_sel
+};
+
+static struct mux_clk pcie_aux_mux_clk  = {
+	.num_parents = 2,
+	.offset = PCIE_AUX_CLK_SEL,
+	.parents = (struct clk_src[]) {
+		{&pcie20_phy_aux_clk.c, 0},
+		{&xo.c, 2},
+	},
+	.ops = &pcie_aux_mux_ops,
+	.mask = 0x3,
+	.shift = 0,
+	.base = &virt_base,
+	.c = {
+		.dbg_name = "pcie_aux_mux_clk",
+		.ops = &clk_ops_gen_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(pcie_aux_mux_clk.c),
+	}
+};
+
+static struct branch_clk gcc_pcie_aux_clk = {
+	.cbcr_reg = PCIE_AUX_CBCR,
+	.bcr_reg = PCIE_BCR,
+	.has_sibling = 0,
+	.base = &virt_base,
+	.c = {
+		.parent = &pcie_aux_mux_clk.c,
+		.dbg_name = "gcc_pcie_aux_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_aux_clk.c),
+	},
+};
+
+static struct clk_lookup msm_clocks_gcc_sdx20[] = {
+	CLK_LIST(gcc_pcie_aux_clk),
+	CLK_LIST(pcie_aux_phy_clk_src),
+	CLK_LIST(pcie20_phy_aux_clk),
+	CLK_LIST(pcie_aux_mux_clk),
+};
+
+static int set_pcie_aux_mux_sel(struct mux_clk *clk, int sel)
+{
+	u32 regval;
+
+	regval = readl_relaxed(*clk->base + clk->offset);
+	regval &= ~(clk->mask << clk->shift);
+	regval |= (sel & clk->mask) << clk->shift;
+	writel_relaxed(regval, *clk->base + clk->offset);
+
+	return 0;
+}
+
+static int get_pcie_aux_mux_sel(struct mux_clk *clk)
+{
+	u32 regval;
+
+	regval = readl_relaxed(*clk->base + clk->offset);
+	return (regval >> clk->shift) & clk->mask;
+}
+
+static void msm_clocks_gcc_sdx20_fixup(void)
+{
+	gcc_pcie_sleep_clk.c.parent =  &pcie_aux_phy_clk_src.c;
+
+	a7pll_clk.fabia_frac_offset = APCS_CPU_PLL_FRAC_OFF;
+	a7pll_clk.masks = &fabia_pll_masks_p;
+	a7pll_clk.vco_tbl =  fabia_pll_vco_p;
+	a7pll_clk.num_vco =  ARRAY_SIZE(fabia_pll_vco_p);
+	a7pll_clk.c.ops = &clk_ops_fabia_alpha_pll;
+	a7pll_clk.is_fabia = true;
+
+	apss_ahb_clk_src.freq_tbl = ftbl_apss_ahb_clk_src_sdx20;
+	usb30_mock_utmi_clk_src.freq_tbl =
+		ftbl_usb30_mock_utmi_clk_src_sdx20;
+
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_MIN] = 25000000;
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOWER] = 50000000;
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 1000000000;
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 2000000000;
+
+	blsp1_qup1_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+	blsp1_qup1_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+	blsp1_qup2_i2c_apps_clk_src.c.fmax[VDD_DIG_MIN] = 9600000;
+	blsp1_qup2_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+	blsp1_qup3_i2c_apps_clk_src.c.fmax[VDD_DIG_MIN] = 9600000;
+	blsp1_qup3_spi_apps_clk_src.c.fmax[VDD_DIG_MIN] = 6250000;
+
+	pcie_aux_clk_src.c.ops = &clk_ops_dummy;
+}
+
+static int msm_gcc_9650_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	bool for_sdx20 = false;
+
+	ret = vote_bimc(&bimc_clk, INT_MAX);
+	if (ret < 0)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get CC base.\n");
+		return -EINVAL;
+	}
+	virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!virt_base) {
+		dev_err(&pdev->dev, "Failed to map in CC registers.\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get APCS base.\n");
+		return -EINVAL;
+	}
+	virt_apcsbase = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+	if (!virt_apcsbase) {
+		dev_err(&pdev->dev, "Failed to map in APCS registers.\n");
+		return -ENOMEM;
+	}
+
+	vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev, "Unable to get vdd_dig regulator!");
+		return PTR_ERR(vdd_dig.regulator[0]);
+	}
+
+	vdd_dig_ao.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_ao");
+	if (IS_ERR(vdd_dig_ao.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig_ao.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev, "Unable to get vdd_dig_ao regulator!");
+		return PTR_ERR(vdd_dig_ao.regulator[0]);
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				    msm_clocks_rpm_9650,
+				    ARRAY_SIZE(msm_clocks_rpm_9650));
+	if (ret)
+		return ret;
+
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-9650")) {
+		vdd_dig.use_max_uV = true;
+		vdd_dig_ao.use_max_uV = true;
+	}
+
+	for_sdx20 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-sdx20");
+
+	ret = enable_rpm_scaling();
+	if (ret < 0)
+		return ret;
+
+	dev_info(&pdev->dev, "Registered RPM clocks.\n");
+
+	/*
+	 * Update for sdx20 clocks.
+	 */
+	if (for_sdx20)
+		msm_clocks_gcc_sdx20_fixup();
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				    msm_clocks_gcc_9650,
+				    ARRAY_SIZE(msm_clocks_gcc_9650));
+	if (ret)
+		return ret;
+
+	/*
+	 * Register sdx20 clocks.
+	 */
+	if (for_sdx20)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+				    msm_clocks_gcc_sdx20,
+				    ARRAY_SIZE(msm_clocks_gcc_sdx20));
+	if (ret)
+		return ret;
+
+	/*
+	 * Hold an active set vote for the PCNOC AHB source.
+	 * Sleep set vote is 0.
+	 */
+	clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+	clk_prepare_enable(&xo_a_clk.c);
+
+	dev_info(&pdev->dev, "Registered GCC clocks.\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+	{ .compatible = "qcom,gcc-9650" },
+	{ .compatible = "qcom,gcc-sdx20" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+	.probe = msm_gcc_9650_probe,
+	.driver = {
+		.name = "qcom,gcc-9650",
+		.of_match_table = msm_clock_gcc_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+int __init msm_gcc_9650_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_driver);
+}
+arch_initcall(msm_gcc_9650_init);
+
+/* ======== Clock Debug Controller ======== */
+static struct clk_lookup msm_clocks_measure_9650[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+};
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+	{ .compatible = "qcom,cc-debug-9650" },
+	{}
+};
+
+static int msm_clock_debug_9650_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+
+	clk_ops_debug_mux = clk_ops_gen_mux;
+	clk_ops_debug_mux.get_rate = measure_get_rate;
+
+	gcc_debug_mux_ops = mux_reg_ops;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get CC base.\n");
+		return -EINVAL;
+	}
+	virt_dbgbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!virt_dbgbase) {
+		dev_err(&pdev->dev, "Failed to map in CC registers.\n");
+		return -ENOMEM;
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				    msm_clocks_measure_9650,
+				    ARRAY_SIZE(msm_clocks_measure_9650));
+	if (ret)
+		return ret;
+
+	dev_info(&pdev->dev, "Registered debug mux.\n");
+	return ret;
+}
+
+static struct platform_driver msm_clock_debug_driver = {
+	.probe = msm_clock_debug_9650_probe,
+	.driver = {
+		.name = "qcom,cc-debug-9650",
+		.of_match_table = msm_clock_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+int __init msm_clock_debug_9650_init(void)
+{
+	return platform_driver_register(&msm_clock_debug_driver);
+}
+late_initcall(msm_clock_debug_9650_init);
diff --git a/drivers/clk/msm/clock-rpm-8909.c b/drivers/clk/msm/clock-rpm-8909.c
new file mode 100644
index 0000000..6730ad1
--- /dev/null
+++ b/drivers/clk/msm/clock-rpm-8909.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-rpm.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/rpm-smd.h>
+
+#include <linux/clk/msm-clock-generic.h>
+
+#include <dt-bindings/clock/msm-clocks-8909.h>
+
+#include "clock.h"
+
+#define GCC_DEBUG_CLK_CTL	0x74000
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+#define RPM_QPIC_CLK_TYPE	0x63697071
+
+#define CXO_ID			0x0
+#define QDSS_ID			0x1
+#define BUS_SCALING		0x2
+
+#define PCNOC_ID		0x0
+#define SNOC_ID			0x1
+#define BIMC_ID			0x0
+#define QPIC_ID			0x0
+
+/* XO clock */
+#define BB_CLK1_ID		1
+#define BB_CLK2_ID		2
+#define BB_CLK3_ID		3
+#define RF_CLK2_ID		5
+
+static void __iomem *virt_base;
+
+/* SMD clocks */
+DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE, PCNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src,
+				RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+/* SMD_XO_BUFFER */
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk3, bb_clk3_a, BB_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk3_pin, bb_clk3_a_pin, BB_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_a_pin, RF_CLK2_ID);
+
+/* Voter clocks */
+static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk,  &snoc_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk,  &bimc_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_mm_msmbus_clk,  &snoc_clk.c,  LONG_MAX);
+
+static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk,  &snoc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk,  &bimc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_mm_msmbus_a_clk,  &snoc_a_clk.c,  LONG_MAX);
+
+static DEFINE_CLK_VOTER(pcnoc_usb_a_clk, &pcnoc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_a_clk,  &snoc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk,  &bimc_a_clk.c,  LONG_MAX);
+
+/* Branch Voter clocks */
+static DEFINE_CLK_BRANCH_VOTER(xo_gcc, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo_clk_src.c);
+
+static struct mux_clk rpm_debug_mux = {
+	.ops = &mux_reg_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_base,
+	MUX_SRC_LIST(
+	{&snoc_clk.c,  0x0000},
+	{&pcnoc_clk.c, 0x0008},
+	/* BIMC_CLK is 2x clock to the BIMC Core as well as DDR, while the
+	 * axi clock is for the BIMC AXI interface. The AXI clock is 1/2 of
+	 * the BIMC Clock. measure the gcc_bimc_apss_axi_clk.
+	 */
+	{&bimc_clk.c,  0x0155},
+	),
+	.c = {
+		.dbg_name = "rpm_debug_mux",
+		.ops = &clk_ops_gen_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(rpm_debug_mux.c),
+	},
+};
+
+/* Lookup Table */
+static struct clk_lookup msm_clocks_rpm[] = {
+	CLK_LIST(xo_clk_src),
+	CLK_LIST(xo_a_clk_src),
+	CLK_LIST(xo_otg_clk),
+	CLK_LIST(xo_lpm_clk),
+	CLK_LIST(xo_pil_mss_clk),
+	CLK_LIST(xo_pil_pronto_clk),
+	CLK_LIST(xo_wlan_clk),
+
+	CLK_LIST(snoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_a_clk),
+	CLK_LIST(snoc_mm_msmbus_clk),
+	CLK_LIST(snoc_mm_msmbus_a_clk),
+	CLK_LIST(pcnoc_msmbus_clk),
+	CLK_LIST(pcnoc_msmbus_a_clk),
+	CLK_LIST(bimc_msmbus_clk),
+	CLK_LIST(bimc_msmbus_a_clk),
+	CLK_LIST(pcnoc_keepalive_a_clk),
+
+	CLK_LIST(pcnoc_usb_a_clk),
+	CLK_LIST(snoc_usb_a_clk),
+	CLK_LIST(bimc_usb_a_clk),
+
+	/* CoreSight clocks */
+	CLK_LIST(qdss_clk),
+	CLK_LIST(qdss_a_clk),
+
+	CLK_LIST(snoc_clk),
+	CLK_LIST(pcnoc_clk),
+	CLK_LIST(bimc_clk),
+	CLK_LIST(snoc_a_clk),
+	CLK_LIST(pcnoc_a_clk),
+	CLK_LIST(bimc_a_clk),
+	CLK_LIST(qpic_clk),
+	CLK_LIST(qpic_a_clk),
+
+	CLK_LIST(bb_clk1),
+	CLK_LIST(bb_clk2),
+	CLK_LIST(rf_clk2),
+
+	CLK_LIST(bb_clk1_pin),
+	CLK_LIST(bb_clk2_pin),
+	CLK_LIST(rf_clk2_pin),
+
+	/* RPM debug Mux*/
+	CLK_LIST(rpm_debug_mux),
+};
+
+/* Lookup Table for MSM8909w-PM660 */
+static struct clk_lookup msm_clocks_rpm_8909_pm660[] = {
+	CLK_LIST(xo_clk_src),
+	CLK_LIST(xo_a_clk_src),
+	CLK_LIST(xo_otg_clk),
+	CLK_LIST(xo_lpm_clk),
+	CLK_LIST(xo_pil_mss_clk),
+	CLK_LIST(xo_pil_pronto_clk),
+	CLK_LIST(xo_wlan_clk),
+
+	CLK_LIST(snoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_a_clk),
+	CLK_LIST(snoc_mm_msmbus_clk),
+	CLK_LIST(snoc_mm_msmbus_a_clk),
+	CLK_LIST(pcnoc_msmbus_clk),
+	CLK_LIST(pcnoc_msmbus_a_clk),
+	CLK_LIST(bimc_msmbus_clk),
+	CLK_LIST(bimc_msmbus_a_clk),
+	CLK_LIST(pcnoc_keepalive_a_clk),
+
+	CLK_LIST(pcnoc_usb_a_clk),
+	CLK_LIST(snoc_usb_a_clk),
+	CLK_LIST(bimc_usb_a_clk),
+
+	/* CoreSight clocks */
+	CLK_LIST(qdss_clk),
+	CLK_LIST(qdss_a_clk),
+
+	CLK_LIST(snoc_clk),
+	CLK_LIST(pcnoc_clk),
+	CLK_LIST(bimc_clk),
+	CLK_LIST(snoc_a_clk),
+	CLK_LIST(pcnoc_a_clk),
+	CLK_LIST(bimc_a_clk),
+	CLK_LIST(qpic_clk),
+	CLK_LIST(qpic_a_clk),
+
+	CLK_LIST(bb_clk1),
+	CLK_LIST(bb_clk2),
+	CLK_LIST(bb_clk3),
+	CLK_LIST(rf_clk2),
+
+	CLK_LIST(bb_clk1_pin),
+	CLK_LIST(bb_clk2_pin),
+	CLK_LIST(bb_clk3_pin),
+	CLK_LIST(rf_clk2_pin),
+
+	/* RPM debug Mux*/
+	CLK_LIST(rpm_debug_mux),
+};
+
+static int msm_rpmcc_8909_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret, is_8909_pm660 = 0;
+
+	ret = enable_rpm_scaling();
+	if (ret)
+		return ret;
+
+	is_8909_pm660 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,rpmcc-8909-pm660");
+
+	res =  platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Unable to get register base\n");
+		return -ENOMEM;
+	}
+
+	virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!virt_base) {
+		dev_err(&pdev->dev, "Failed to map CC registers\n");
+		return -ENOMEM;
+	}
+
+	if (is_8909_pm660)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_rpm_8909_pm660,
+				ARRAY_SIZE(msm_clocks_rpm_8909_pm660));
+	else
+		ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_rpm,
+					ARRAY_SIZE(msm_clocks_rpm));
+
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to register RPM clocks\n");
+		return ret;
+	}
+
+	/*
+	 *  Hold an active set vote for PCNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pcnoc_keepalive_a_clk.c);
+
+	clk_prepare_enable(&xo_a_clk_src.c);
+
+	dev_info(&pdev->dev, "Registered RPM clocks.\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clk_rpm_match_table[] = {
+	{ .compatible = "qcom,rpmcc-8909" },
+	{ .compatible = "qcom,rpmcc-8909-pm660" },
+	{}
+};
+
+static struct platform_driver msm_clock_rpm_driver = {
+	.probe = msm_rpmcc_8909_probe,
+	.driver = {
+		.name = "qcom,rpmcc-8909",
+		.of_match_table = msm_clk_rpm_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_rpmcc_8909_init(void)
+{
+	return platform_driver_register(&msm_clock_rpm_driver);
+}
+arch_initcall(msm_rpmcc_8909_init);
diff --git a/drivers/clk/msm/mdss/Kconfig b/drivers/clk/msm/mdss/Kconfig
new file mode 100644
index 0000000..229780e
--- /dev/null
+++ b/drivers/clk/msm/mdss/Kconfig
@@ -0,0 +1,6 @@
+config MSM_MDSS_PLL
+	bool "MDSS pll programming"
+	---help---
+	It provides support for DSI, eDP and HDMI interface pll programming on MDSS
+	hardware. It also handles the pll specific resources and turn them on/off when
+	mdss pll client tries to enable/disable pll clocks.
diff --git a/drivers/clk/msm/mdss/Makefile b/drivers/clk/msm/mdss/Makefile
new file mode 100644
index 0000000..6285714
--- /dev/null
+++ b/drivers/clk/msm/mdss/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-28lpm.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c b/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c
new file mode 100644
index 0000000..17ff52e
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <dt-bindings/clock/msm-clocks-8952.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+
+#define VCO_DELAY_USEC			1000
+
+static struct clk_div_ops fixed_2div_ops;
+static struct clk_ops byte_mux_clk_ops;
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_postdiv_clk_ops;
+static struct lpfr_cfg lpfr_lut_struct[] = {
+	{479500000, 8},
+	{480000000, 11},
+	{575500000, 8},
+	{576000000, 12},
+	{610500000, 8},
+	{659500000, 9},
+	{671500000, 10},
+	{672000000, 14},
+	{708500000, 10},
+	{750000000, 11},
+};
+
+static int vco_set_rate_lpm(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/*
+	 * DSI PLL software reset. Add HW recommended delays after toggling
+	 * the software reset bit off and back on.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+	udelay(1000);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+	udelay(1000);
+
+	rc = vco_set_rate(vco, rate);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+static void dsi_pll_sw_reset_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	/*
+	 * DSI PLL software reset. Add HW recommended delays after toggling
+	 * the software reset bit off and back on.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+	ndelay(500);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+}
+
+static void dsi_pll_toggle_lock_detect_8916(
+				struct mdss_pll_resources *dsi_pll_res)
+{
+	/* DSI PLL toggle lock detect setting */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x04);
+	ndelay(500);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+	udelay(512);
+}
+
+static int dsi_pll_check_lock_status_8916(
+				struct mdss_pll_resources *dsi_pll_res)
+{
+	int rc = 0;
+
+	rc = dsi_pll_lock_status(dsi_pll_res);
+	if (rc)
+		pr_debug("PLL Locked\n");
+	else
+		pr_err("PLL failed to lock\n");
+
+	return rc;
+}
+
+
+static int gf_2_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+
+	/*
+	 * GF PART 2 PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x04);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(3);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int gf_1_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+	/*
+	 * GF PART 1 PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x14);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(3);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int tsmc_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+	/*
+	 * TSMC PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+/* Op structures */
+
+static const struct clk_ops clk_ops_dsi_vco = {
+	.set_rate = vco_set_rate_lpm,
+	.round_rate = vco_round_rate,
+	.handoff = vco_handoff,
+	.prepare = vco_prepare,
+	.unprepare = vco_unprepare,
+};
+
+
+static struct clk_div_ops fixed_4div_ops = {
+	.set_div = fixed_4div_set_div,
+	.get_div = fixed_4div_get_div,
+};
+
+static struct clk_div_ops analog_postdiv_ops = {
+	.set_div = analog_set_div,
+	.get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+	.set_div = digital_set_div,
+	.get_div = digital_get_div,
+};
+
+static struct clk_mux_ops byte_mux_ops = {
+	.set_mux_sel = set_byte_mux_sel,
+	.get_mux_sel = get_byte_mux_sel,
+};
+
+/* DSI PLL0 clock structures */
+static struct dsi_pll_vco_clk dsi_pll0_vco_clk = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 9,
+	.pll_enable_seqs[0] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[1] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[2] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[3] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[4] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[5] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[6] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[7] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[8] = gf_2_dsi_pll_enable_seq_8916,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = lpfr_lut_struct,
+	.c = {
+		.dbg_name = "dsi_pll0_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_pll0_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_analog_postdiv_clk = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_analog_postdiv_clk",
+		.ops = &analog_postdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_analog_postdiv_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_indirect_path_div2_clk = {
+	.ops = &fixed_2div_ops,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi_pll0_analog_postdiv_clk.c,
+		.dbg_name = "dsi_pll0_indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_indirect_path_div2_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_pixel_clk_src = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi_pll0_byte_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_pll0_vco_clk.c, 0},
+		{&dsi_pll0_indirect_path_div2_clk.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(dsi_pll0_byte_mux.c),
+	},
+};
+
+static struct div_clk dsi_pll0_byte_clk_src = {
+	.ops = &fixed_4div_ops,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
+	.c = {
+		.parent = &dsi_pll0_byte_mux.c,
+		.dbg_name = "dsi_pll0_byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(dsi_pll0_byte_clk_src.c),
+	},
+};
+
+/* DSI PLL1 clock structures */
+static struct dsi_pll_vco_clk dsi_pll1_vco_clk = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 9,
+	.pll_enable_seqs[0] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[1] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[2] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[3] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[4] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[5] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[6] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[7] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[8] = gf_2_dsi_pll_enable_seq_8916,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = lpfr_lut_struct,
+	.c = {
+		.dbg_name = "dsi_pll1_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_pll1_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_analog_postdiv_clk = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_analog_postdiv_clk",
+		.ops = &analog_postdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_analog_postdiv_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_indirect_path_div2_clk = {
+	.ops = &fixed_2div_ops,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi_pll1_analog_postdiv_clk.c,
+		.dbg_name = "dsi_pll1_indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_indirect_path_div2_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_pixel_clk_src = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi_pll1_byte_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_pll1_vco_clk.c, 0},
+		{&dsi_pll1_indirect_path_div2_clk.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(dsi_pll1_byte_mux.c),
+	},
+};
+
+static struct div_clk dsi_pll1_byte_clk_src = {
+	.ops = &fixed_4div_ops,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
+	.c = {
+		.parent = &dsi_pll1_byte_mux.c,
+		.dbg_name = "dsi_pll1_byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(dsi_pll1_byte_clk_src.c),
+	},
+};
+
+static struct clk_lookup dsi_pll0_cc[] = {
+	CLK_LIST(dsi_pll0_pixel_clk_src),
+	CLK_LIST(dsi_pll0_byte_clk_src),
+};
+
+static struct clk_lookup dsi_pll1_cc[] = {
+	CLK_LIST(dsi_pll1_pixel_clk_src),
+	CLK_LIST(dsi_pll1_byte_clk_src),
+};
+
+int dsi_pll_clock_register_lpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc;
+	int const ssc_freq_min = 30000; /* min. recommended freq. value */
+	int const ssc_freq_max = 33000; /* max. recommended freq. value */
+	int const ssc_ppm_max = 5000; /* max. recommended ppm */
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pll_res || !pll_res->pll_base) {
+		pr_err("Invalid PLL resources\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* Set client data to mux, div and vco clocks */
+	if (!pll_res->index) {
+		dsi_pll0_byte_clk_src.priv = pll_res;
+		dsi_pll0_pixel_clk_src.priv = pll_res;
+		dsi_pll0_byte_mux.priv = pll_res;
+		dsi_pll0_indirect_path_div2_clk.priv = pll_res;
+		dsi_pll0_analog_postdiv_clk.priv = pll_res;
+		dsi_pll0_vco_clk.priv = pll_res;
+	} else {
+		dsi_pll1_byte_clk_src.priv = pll_res;
+		dsi_pll1_pixel_clk_src.priv = pll_res;
+		dsi_pll1_byte_mux.priv = pll_res;
+		dsi_pll1_indirect_path_div2_clk.priv = pll_res;
+		dsi_pll1_analog_postdiv_clk.priv = pll_res;
+		dsi_pll1_vco_clk.priv = pll_res;
+	}
+
+	pll_res->vco_delay = VCO_DELAY_USEC;
+
+	/* Set clock source operations */
+	pixel_clk_src_ops = clk_ops_slave_div;
+	pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	analog_postdiv_clk_ops = clk_ops_div;
+	analog_postdiv_clk_ops.prepare = dsi_pll_div_prepare;
+
+	byte_clk_src_ops = clk_ops_div;
+	byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	byte_mux_clk_ops = clk_ops_gen_mux;
+	byte_mux_clk_ops.prepare = dsi_pll_mux_prepare;
+
+	if (pll_res->ssc_en) {
+		if (!pll_res->ssc_freq || (pll_res->ssc_freq < ssc_freq_min) ||
+			(pll_res->ssc_freq > ssc_freq_max)) {
+			pll_res->ssc_freq = ssc_freq_min;
+			pr_debug("SSC frequency out of recommended range. Set to default=%d\n",
+				pll_res->ssc_freq);
+		}
+
+		if (!pll_res->ssc_ppm || (pll_res->ssc_ppm > ssc_ppm_max)) {
+			pll_res->ssc_ppm = ssc_ppm_max;
+			pr_debug("SSC PPM out of recommended range. Set to default=%d\n",
+				pll_res->ssc_ppm);
+		}
+	}
+
+	if ((pll_res->target_id == MDSS_PLL_TARGET_8952) ||
+		(pll_res->target_id == MDSS_PLL_TARGET_8937) ||
+		(pll_res->target_id == MDSS_PLL_TARGET_8909)) {
+		if (!pll_res->index)
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				dsi_pll0_cc, ARRAY_SIZE(dsi_pll0_cc));
+		else
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				dsi_pll1_cc, ARRAY_SIZE(dsi_pll1_cc));
+		if (rc) {
+			pr_err("Clock register failed\n");
+			rc = -EPROBE_DEFER;
+		}
+	} else {
+		pr_err("Invalid target ID\n");
+		rc = -EINVAL;
+	}
+
+	if (!rc)
+		pr_info("Registered DSI PLL:%d clocks successfully\n",
+				pll_res->index);
+
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
new file mode 100644
index 0000000..20b8e34
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
@@ -0,0 +1,1240 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-8996.h"
+
+#define DSI_PLL_POLL_MAX_READS                  15
+#define DSI_PLL_POLL_TIMEOUT_US                 1000
+#define MSM8996_DSI_PLL_REVISION_2		2
+
+#define DSI_PHY_SPARE_VAL	0x6a
+#define DSI_PLL_DEFAULT_POSTDIV	1
+
+#define CEIL(x, y)		(((x) + ((y)-1)) / (y))
+static void pll_db_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb);
+
+int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel)
+{
+	return 0;
+}
+
+int get_mdss_byte_mux_sel_8996(struct mux_clk *clk)
+{
+	return 0;
+}
+
+int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel)
+{
+	return 0;
+}
+
+int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk)
+{
+	return 0;
+}
+
+int post_n1_div_set_div(struct div_clk *clk, int div)
+{
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	int rc;
+	u32 n1div = 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	pout = &pdb->out;
+
+	/*
+	 * vco rate = bit_clk * postdiv * n1div
+	 * vco range from 1300 to 2600 Mhz
+	 * postdiv = 1
+	 * n1div = 1 to 15
+	 * n1div = roundup(1300Mhz / bit_clk)
+	 * support bit_clk above 86.67Mhz
+	 */
+
+	/* this is for vco/bit clock */
+	pout->pll_postdiv = DSI_PLL_DEFAULT_POSTDIV;
+	pout->pll_n1div  = div;
+
+	n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n1div &= ~0xf;
+	n1div |= (div & 0xf);
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n1div);
+	/* ensure n1 divider is programed */
+	wmb();
+	pr_debug("ndx=%d div=%d postdiv=%x n1div=%x\n",
+			pll->index, div, pout->pll_postdiv, pout->pll_n1div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return 0;
+}
+
+int post_n1_div_get_div(struct div_clk *clk)
+{
+	u32  div;
+	int rc;
+	struct mdss_pll_resources *pll = clk->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/*
+	 * postdiv = 1/2/4/8
+	 * n1div = 1 - 15
+	 * fot the time being, assume postdiv = 1
+	 */
+
+	div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	div &= 0xF;
+	pr_debug("n1 div = %d\n", div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return div;
+}
+
+int n2_div_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	u32 n2div;
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	struct mdss_pll_resources *slave;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	pout = &pdb->out;
+
+	/* this is for pixel_clock */
+	n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n2div &= ~0xf0;	/* bits 4 to 7 */
+	n2div |= (div << 4);
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n2div);
+
+	/* commit slave if split display is enabled */
+	slave = pll->slave;
+	if (slave)
+		MDSS_PLL_REG_W(slave->pll_base, DSIPHY_CMN_CLK_CFG0, n2div);
+
+	pout->pll_n2div = div;
+
+	/* set dsiclk_sel=1 so that n2div *= 2 */
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG1, 1);
+	pr_debug("ndx=%d div=%d n2div=%x\n", pll->index, div, n2div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return rc;
+}
+
+int shadow_n2_div_set_div(struct div_clk *clk, int div)
+{
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	u32 data;
+
+	pdb = pll->priv;
+	pout = &pdb->out;
+
+	pout->pll_n2div = div;
+
+	data = (pout->pll_n1div | (pout->pll_n2div << 4));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+			DSI_DYNAMIC_REFRESH_PLL_CTRL19,
+			DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_CLK_CFG1,
+			data, 1);
+	return 0;
+}
+
+int n2_div_get_div(struct div_clk *clk)
+{
+	int rc;
+	u32 n2div;
+	struct mdss_pll_resources *pll = clk->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d resources\n",
+						pll->index);
+		return rc;
+	}
+
+	n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n2div >>= 4;
+	n2div &= 0x0f;
+
+	mdss_pll_resource_enable(pll, false);
+
+	pr_debug("ndx=%d div=%d\n", pll->index, n2div);
+
+	return n2div;
+}
+
+static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll)
+{
+	u32 status;
+	bool pll_locked;
+
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_atomic((pll->pll_base +
+			DSIPHY_PLL_RESET_SM_READY_STATUS),
+			status,
+			((status & BIT(5)) > 0),
+			DSI_PLL_POLL_MAX_READS,
+			DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_err("DSI PLL ndx=%d status=%x failed to Lock\n",
+			pll->index, status);
+		pll_locked = false;
+	} else if (readl_poll_timeout_atomic((pll->pll_base +
+				DSIPHY_PLL_RESET_SM_READY_STATUS),
+				status,
+				((status & BIT(0)) > 0),
+				DSI_PLL_POLL_MAX_READS,
+				DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_err("DSI PLL ndx=%d status=%x PLl not ready\n",
+			pll->index, status);
+		pll_locked = false;
+	} else {
+		pll_locked = true;
+	}
+
+	return pll_locked;
+}
+
+static void dsi_pll_start_8996(void __iomem *pll_base)
+{
+	pr_debug("start PLL at base=%pk\n", pll_base);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VREF_CFG1, 0x10);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1);
+	wmb();	/* make sure register committed */
+}
+
+static void dsi_pll_stop_8996(void __iomem *pll_base)
+{
+	pr_debug("stop PLL at base=%pk\n", pll_base);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+	wmb();	/* make sure register committed */
+}
+
+static inline bool pll_use_precal(struct mdss_pll_resources *pll)
+{
+	bool ret = true;
+	u32 spare = MDSS_PLL_REG_R(pll->pll_base,
+		DSIPHY_CMN_GLBL_DIGTOP_SPARE2);
+
+	if (!pll->cache_pll_trim_codes[0] || /* kvco code */
+	    !pll->cache_pll_trim_codes[1] || /* vco tune */
+	    !pll->cache_pll_trim_codes_rate ||
+	    (pll->cache_pll_trim_codes_rate != pll->vco_current_rate) ||
+	    (spare != DSI_PHY_SPARE_VAL)) /* phy reset */
+		ret = false;
+
+	pr_debug("ndx:%d kvco:%d vco_tune:%d spare:0x%x rate:%llu old:%llu ret:%d\n",
+		pll->index, pll->cache_pll_trim_codes[0],
+		pll->cache_pll_trim_codes[1], spare,
+		pll->cache_pll_trim_codes_rate,
+		pll->vco_current_rate, ret);
+
+	return ret;
+}
+
+int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll)
+{
+	int rc = 0;
+	struct dsi_pll_db *pdb;
+	struct mdss_pll_resources *slave;
+
+	if (!pll) {
+		pr_err("Invalid PLL resources\n");
+		return -EINVAL;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	if (!pdb) {
+		pr_err("No priv found\n");
+		return -EINVAL;
+	}
+
+	dsi_pll_start_8996(pll->pll_base);
+
+	/*
+	 * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL
+	 * enabled at mdss_dsi_8996_phy_config()
+	 */
+
+	if (!pll_is_pll_locked_8996(pll)) {
+		pr_err("DSI PLL ndx=%d lock failed, retry full sequence!\n",
+			pll->index);
+		slave = pll->slave;
+
+		/* commit slave if split display is enabled */
+		if (slave)
+			pll_db_commit_8996(slave, pdb);
+
+		/* commit master itself */
+		pll_db_commit_8996(pll, pdb);
+
+		dsi_pll_start_8996(pll->pll_base);
+		if (!pll_is_pll_locked_8996(pll)) {
+			pr_err("DSI PLL ndx=%d lock failed!!!\n",
+				pll->index);
+			rc = -EINVAL;
+			goto init_lock_err;
+		}
+	}
+
+	if (!pll_use_precal(pll)) {
+		/* cache vco settings */
+		pll->cache_pll_trim_codes[0] = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_CORE_KVCO_CODE_STATUS);
+		pll->cache_pll_trim_codes[1] = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_CORE_VCO_TUNE_STATUS);
+		pll->cache_pll_trim_codes_rate = pll->vco_current_rate;
+
+		/* write spare */
+		MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_GLBL_DIGTOP_SPARE2,
+			DSI_PHY_SPARE_VAL);
+	}
+
+	pr_debug("DSI PLL ndx:%d Locked! kvco=0x%x vco_tune=0x%x rate=%llu\n",
+		pll->index, pll->cache_pll_trim_codes[0],
+		pll->cache_pll_trim_codes[1],
+		pll->cache_pll_trim_codes_rate);
+
+init_lock_err:
+	return rc;
+}
+
+static int dsi_pll_enable(struct clk *c)
+{
+	int i, rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	/* Try all enable sequences until one succeeds */
+	for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+		rc = vco->pll_enable_seqs[i](pll);
+		pr_debug("DSI PLL %s after sequence #%d\n",
+			rc ? "unlocked" : "locked", i + 1);
+		if (!rc)
+			break;
+	}
+
+	if (rc)
+		pr_err("ndx=%d DSI PLL failed to lock\n", pll->index);
+	else
+		pll->pll_on = true;
+
+	return rc;
+}
+
+static void dsi_pll_disable(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct mdss_pll_resources *slave;
+
+	if (!pll->pll_on &&
+		mdss_pll_resource_enable(pll, true)) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return;
+	}
+
+	pll->handoff_resources = false;
+	slave = pll->slave;
+
+	dsi_pll_stop_8996(pll->pll_base);
+
+	mdss_pll_resource_enable(pll, false);
+
+	pll->pll_on = false;
+
+	pr_debug("DSI PLL ndx=%d Disabled\n", pll->index);
+}
+
+static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	pdb->in.fref = 19200000;	/* 19.2 Mhz*/
+	pdb->in.fdata = 0;		/* bit clock rate */
+	pdb->in.dsiclk_sel = 1;		/* 1, reg: 0x0014 */
+	pdb->in.ssc_en = pll->ssc_en;		/* 1, reg: 0x0494, bit 0 */
+	pdb->in.ldo_en = 0;		/* 0,  reg: 0x004c, bit 0 */
+
+	/* fixed  input */
+	pdb->in.refclk_dbler_en = 0;	/* 0, reg: 0x04c0, bit 1 */
+	pdb->in.vco_measure_time = 5;	/* 5, unknown */
+	pdb->in.kvco_measure_time = 5;	/* 5, unknown */
+	pdb->in.bandgap_timer = 4;	/* 4, reg: 0x0430, bit 3 - 5 */
+	pdb->in.pll_wakeup_timer = 5;	/* 5, reg: 0x043c, bit 0 - 2 */
+	pdb->in.plllock_cnt = 1;	/* 1, reg: 0x0488, bit 1 - 2 */
+	pdb->in.plllock_rng = 0;	/* 0, reg: 0x0488, bit 3 - 4 */
+	pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */
+	pdb->in.ssc_adj_period = 37;	/* 37, reg: 0x498, bit 0 - 9 */
+	pdb->in.ssc_spread = pll->ssc_ppm / 1000;
+	pdb->in.ssc_freq = pll->ssc_freq;
+
+	pdb->in.pll_ie_trim = 4;	/* 4, reg: 0x0400 */
+	pdb->in.pll_ip_trim = 4;	/* 4, reg: 0x0404 */
+	pdb->in.pll_cpcset_cur = 1;	/* 1, reg: 0x04f0, bit 0 - 2 */
+	pdb->in.pll_cpmset_cur = 1;	/* 1, reg: 0x04f0, bit 3 - 5 */
+	pdb->in.pll_icpmset = 4;	/* 4, reg: 0x04fc, bit 3 - 5 */
+	pdb->in.pll_icpcset = 4;	/* 4, reg: 0x04fc, bit 0 - 2 */
+	pdb->in.pll_icpmset_p = 0;	/* 0, reg: 0x04f4, bit 0 - 2 */
+	pdb->in.pll_icpmset_m = 0;	/* 0, reg: 0x04f4, bit 3 - 5 */
+	pdb->in.pll_icpcset_p = 0;	/* 0, reg: 0x04f8, bit 0 - 2 */
+	pdb->in.pll_icpcset_m = 0;	/* 0, reg: 0x04f8, bit 3 - 5 */
+	pdb->in.pll_lpf_res1 = 3;	/* 3, reg: 0x0504, bit 0 - 3 */
+	pdb->in.pll_lpf_cap1 = 11;	/* 11, reg: 0x0500, bit 0 - 3 */
+	pdb->in.pll_lpf_cap2 = 1;	/* 1, reg: 0x0500, bit 4 - 7 */
+	pdb->in.pll_iptat_trim = 7;
+	pdb->in.pll_c3ctrl = 2;		/* 2 */
+	pdb->in.pll_r3ctrl = 1;		/* 1 */
+}
+
+static void pll_8996_ssc_calc(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb)
+{
+	u32 period, ssc_period;
+	u32 ref, rem;
+	s64 step_size;
+
+	pr_debug("%s: vco=%lld ref=%lld\n", __func__,
+		pll->vco_current_rate, pll->vco_ref_clk_rate);
+
+	ssc_period = pdb->in.ssc_freq / 500;
+	period = (unsigned long)pll->vco_ref_clk_rate / 1000;
+	ssc_period  = CEIL(period, ssc_period);
+	ssc_period -= 1;
+	pdb->out.ssc_period = ssc_period;
+
+	pr_debug("%s: ssc, freq=%d spread=%d period=%d\n", __func__,
+	pdb->in.ssc_freq, pdb->in.ssc_spread, pdb->out.ssc_period);
+
+	step_size = (u32)pll->vco_current_rate;
+	ref = pll->vco_ref_clk_rate;
+	ref /= 1000;
+	step_size = div_s64(step_size, ref);
+	step_size <<= 20;
+	step_size = div_s64(step_size, 1000);
+	step_size *= pdb->in.ssc_spread;
+	step_size = div_s64(step_size, 1000);
+	step_size *= (pdb->in.ssc_adj_period + 1);
+
+	rem = 0;
+	step_size = div_s64_rem(step_size, ssc_period + 1, &rem);
+	if (rem)
+		step_size++;
+
+	pr_debug("%s: step_size=%lld\n", __func__, step_size);
+
+	step_size &= 0x0ffff;	/* take lower 16 bits */
+
+	pdb->out.ssc_step_size = step_size;
+}
+
+static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb)
+{
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	s64 multiplier = BIT(20);
+	s64 dec_start_multiple, dec_start;
+	u64 pll_comp_val;
+	s32 duration, div_frac_start;
+	s64 vco_clk_rate = pll->vco_current_rate;
+	s64 fref = pll->vco_ref_clk_rate;
+
+	pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n",
+				vco_clk_rate, fref);
+
+	dec_start_multiple = div_s64(vco_clk_rate * multiplier, fref);
+	div_s64_rem(dec_start_multiple, multiplier, &div_frac_start);
+
+	dec_start = div_s64(dec_start_multiple, multiplier);
+
+	pout->dec_start = (u32)dec_start;
+	pout->div_frac_start = div_frac_start;
+
+	if (pin->plllock_cnt == 0)
+		duration = 1024;
+	else if (pin->plllock_cnt == 1)
+		duration = 256;
+	else if (pin->plllock_cnt == 2)
+		duration = 128;
+	else
+		duration = 32;
+
+	pll_comp_val =  duration * dec_start_multiple;
+	pll_comp_val =  div_s64(pll_comp_val, multiplier);
+	do_div(pll_comp_val, 10);
+
+	pout->plllock_cmp = (u32)pll_comp_val;
+
+	pout->pll_txclk_en = 1;
+	if (pll->revision == MSM8996_DSI_PLL_REVISION_2)
+		pout->cmn_ldo_cntrl = 0x3c;
+	else
+		pout->cmn_ldo_cntrl = 0x1c;
+}
+
+static u32 pll_8996_kvco_slop(u32 vrate)
+{
+	u32 slop = 0;
+
+	if (vrate > 1300000000UL && vrate <= 1800000000UL)
+		slop =  600;
+	else if (vrate > 1800000000UL && vrate < 2300000000UL)
+		slop = 400;
+	else if (vrate > 2300000000UL && vrate < 2600000000UL)
+		slop = 280;
+
+	return slop;
+}
+
+static inline u32 pll_8996_calc_kvco_code(s64 vco_clk_rate)
+{
+	u32 kvco_code;
+
+	if ((vco_clk_rate >= 2300000000ULL) &&
+	    (vco_clk_rate <= 2600000000ULL))
+		kvco_code = 0x2f;
+	else if ((vco_clk_rate >= 1800000000ULL) &&
+		 (vco_clk_rate < 2300000000ULL))
+		kvco_code = 0x2c;
+	else
+		kvco_code = 0x28;
+
+	pr_debug("rate: %llu kvco_code: 0x%x\n",
+		vco_clk_rate, kvco_code);
+	return kvco_code;
+}
+
+static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb,
+			 s64 vco_clk_rate, s64 fref)
+{
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	u64 data;
+	u64 cnt;
+
+	data = fref * pin->vco_measure_time;
+	do_div(data, 1000000);
+	data &= 0x03ff;	/* 10 bits */
+	data -= 2;
+	pout->pll_vco_div_ref = data;
+
+	data = (unsigned long)vco_clk_rate / 1000000;	/* unit is Mhz */
+	data *= pin->vco_measure_time;
+	do_div(data, 10);
+	pout->pll_vco_count = data; /* reg: 0x0474, 0x0478 */
+
+	data = fref * pin->kvco_measure_time;
+	do_div(data, 1000000);
+	data &= 0x03ff;	/* 10 bits */
+	data -= 1;
+	pout->pll_kvco_div_ref = data;
+
+	cnt = pll_8996_kvco_slop(vco_clk_rate);
+	cnt *= 2;
+	do_div(cnt, 100);
+	cnt *= pin->kvco_measure_time;
+	pout->pll_kvco_count = cnt;
+
+	pout->pll_misc1 = 16;
+	pout->pll_resetsm_cntrl = 48;
+	pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3;
+	pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer;
+	pout->pll_kvco_code = pll_8996_calc_kvco_code(vco_clk_rate);
+}
+
+static void pll_db_commit_ssc(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	data = pin->ssc_adj_period;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER1, data);
+	data = (pin->ssc_adj_period >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER2, data);
+
+	data = pout->ssc_period;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER1, data);
+	data = (pout->ssc_period >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER2, data);
+
+	data = pout->ssc_step_size;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE1, data);
+	data = (pout->ssc_step_size >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE2, data);
+
+	data = (pin->ssc_center & 0x01);
+	data <<= 1;
+	data |= 0x01; /* enable */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_EN_CENTER, data);
+
+	wmb();	/* make sure register committed */
+}
+
+static int pll_precal_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	/*
+	 * if pre-calibrated values cannot be used, return
+	 * error, so we use full sequence.
+	 */
+	if (!pll_use_precal(pll)) {
+		pr_debug("cannot use precal sequence ndx:%d\n", pll->index);
+		return -EINVAL;
+	}
+
+	data = pout->cmn_ldo_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data);
+
+	/* stop pll */
+	data = 0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, data);
+
+	data = 0x7f;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	data = 0x20;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, data);
+
+	data = 0x38;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data);
+
+	data = BIT(7);
+	data |= pll->cache_pll_trim_codes[1]; /* vco tune */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_VCO_TUNE, data);
+
+	data = BIT(5);
+	data |= pll->cache_pll_trim_codes[0]; /* kvco code */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, data);
+
+	data = 0xff; /* data, clk, pll normal operation */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	data = 0x0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, data);
+	wmb();	/* make sure register committed */
+
+	return 0;
+}
+
+static void pll_db_commit_common(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	/* confgiure the non frequency dependent pll registers */
+	data = 0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SYSCLK_EN_RESET, data);
+
+	/* DSIPHY_PLL_CLKBUFLR_EN updated at dsi phy */
+
+	data = pout->pll_txclk_en;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_TXCLK_EN, data);
+
+	data = pout->pll_resetsm_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data);
+	data = pout->pll_resetsm_cntrl2;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL2, data);
+	data = pout->pll_resetsm_cntrl5;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL5, data);
+
+	data = pout->pll_vco_div_ref;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF1, data);
+	data = (pout->pll_vco_div_ref >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF2, data);
+
+	data = pout->pll_kvco_div_ref;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF1, data);
+	data = (pout->pll_kvco_div_ref >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF2, data);
+
+	data = pout->pll_misc1;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_MISC1, data);
+
+	data = pin->pll_ie_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IE_TRIM, data);
+
+	data = pin->pll_ip_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IP_TRIM, data);
+
+	data = ((pin->pll_cpmset_cur << 3) | pin->pll_cpcset_cur);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CP_SET_CUR, data);
+
+	data = ((pin->pll_icpcset_p << 3) | pin->pll_icpcset_m);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPCSET, data);
+
+	data = ((pin->pll_icpmset_p << 3) | pin->pll_icpcset_m);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPMSET, data);
+
+	data = ((pin->pll_icpmset << 3) | pin->pll_icpcset);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICP_SET, data);
+
+	data = ((pdb->in.pll_lpf_cap2 << 4) | pdb->in.pll_lpf_cap1);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF1, data);
+
+	data = pin->pll_iptat_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IPTAT_TRIM, data);
+
+	data = (pdb->in.pll_c3ctrl | (pdb->in.pll_r3ctrl << 4));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data);
+}
+
+static void pll_db_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	data = pout->cmn_ldo_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data);
+
+	pll_db_commit_common(pll, pdb);
+
+	/* de assert pll start and apply pll sw reset */
+	/* stop pll */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+
+	/* pll sw reset */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0x20);
+	wmb();	/* make sure register committed */
+	udelay(10);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0);
+	wmb();	/* make sure register committed */
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_VCO_TUNE, 0);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, 0);
+	wmb(); /* make sure register committed */
+
+	data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1  */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data);
+
+	data = 0xff; /* data, clk, pll normal operation */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	/* configure the frequency dependent pll registers */
+	data = pout->dec_start;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DEC_START, data);
+
+	data = pout->div_frac_start;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START1, data);
+	data = (pout->div_frac_start >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START2, data);
+	data = (pout->div_frac_start >> 16);
+	data &= 0x0f;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START3, data);
+
+	data = pout->plllock_cmp;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP1, data);
+	data = (pout->plllock_cmp >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP2, data);
+	data = (pout->plllock_cmp >> 16);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP3, data);
+
+	data = ((pin->plllock_cnt << 1) | (pin->plllock_rng << 3));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP_EN, data);
+
+	data = pout->pll_vco_count;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT1, data);
+	data = (pout->pll_vco_count >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT2, data);
+
+	data = pout->pll_kvco_count;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT1, data);
+	data = (pout->pll_kvco_count >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT2, data);
+
+	data = (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF2_POSTDIV, data);
+
+	data = pout->pll_kvco_code;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, data);
+	pr_debug("kvco_code:0x%x\n", data);
+
+	data = (pout->pll_n1div | (pout->pll_n2div << 4));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data);
+
+	if (pll->ssc_en)
+		pll_db_commit_ssc(pll, pdb);
+
+	pr_debug("pll:%d\n", pll->index);
+	wmb();	/* make sure register committed */
+}
+
+/*
+ * pll_source_finding:
+ * Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured
+ * at mdss_dsi_8996_phy_config()
+ */
+static int pll_source_finding(struct mdss_pll_resources *pll)
+{
+	u32 clk_buf_en;
+	u32 glbl_test_ctrl;
+
+	glbl_test_ctrl = MDSS_PLL_REG_R(pll->pll_base,
+				DSIPHY_CMN_GLBL_TEST_CTRL);
+	clk_buf_en = MDSS_PLL_REG_R(pll->pll_base,
+				DSIPHY_PLL_CLKBUFLR_EN);
+
+	glbl_test_ctrl &= BIT(2);
+	glbl_test_ctrl >>= 2;
+
+	pr_debug("%s: pll=%d clk_buf_en=%x glbl_test_ctrl=%x\n",
+		__func__, pll->index, clk_buf_en, glbl_test_ctrl);
+
+	clk_buf_en &= (PLL_OUTPUT_RIGHT | PLL_OUTPUT_LEFT);
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) &&
+			(clk_buf_en == PLL_OUTPUT_BOTH))
+		return PLL_MASTER;
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_RIGHT) &&
+			(clk_buf_en == PLL_OUTPUT_NONE))
+		return PLL_SLAVE;
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) &&
+			(clk_buf_en == PLL_OUTPUT_RIGHT))
+		return PLL_STANDALONE;
+
+	pr_debug("%s: Error pll setup, clk_buf_en=%x glbl_test_ctrl=%x\n",
+			__func__, clk_buf_en, glbl_test_ctrl);
+
+	return PLL_UNKNOWN;
+}
+
+static void pll_source_setup(struct mdss_pll_resources *pll)
+{
+	int status;
+	struct dsi_pll_db *pdb = (struct dsi_pll_db *)pll->priv;
+	struct mdss_pll_resources *other;
+
+	if (pdb->source_setup_done)
+		return;
+
+	pdb->source_setup_done++;
+
+	status = pll_source_finding(pll);
+
+	if (status == PLL_STANDALONE || status == PLL_UNKNOWN)
+		return;
+
+	other = pdb->next->pll;
+	if (!other)
+		return;
+
+	pr_debug("%s: status=%d pll=%d other=%d\n", __func__,
+			status, pll->index, other->index);
+
+	if (status == PLL_MASTER)
+		pll->slave = other;
+	else
+		other->slave = pll;
+}
+
+int pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct mdss_pll_resources *slave;
+	struct dsi_pll_db *pdb;
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	if (!pdb) {
+		pr_err("No prov found\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	pll_source_setup(pll);
+
+	pr_debug("%s: ndx=%d base=%pk rate=%lu slave=%pk\n", __func__,
+				pll->index, pll->pll_base, rate, pll->slave);
+
+	pll->vco_current_rate = rate;
+	pll->vco_ref_clk_rate = vco->ref_clk_rate;
+
+	mdss_dsi_pll_8996_input_init(pll, pdb);
+	/*
+	 * tx_band = pll_postdiv
+	 * 0: divided by 1 <== for now
+	 * 1: divided by 2
+	 * 2: divided by 4
+	 * 3: divided by 8
+	 */
+	pdb->out.pll_postdiv = DSI_PLL_DEFAULT_POSTDIV;
+
+	pll_8996_dec_frac_calc(pll, pdb);
+
+	if (pll->ssc_en)
+		pll_8996_ssc_calc(pll, pdb);
+
+	pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+					pll->vco_ref_clk_rate);
+
+	/* precal sequence, only for the master */
+	if (pll_precal_commit_8996(pll, pdb)) {
+		pr_debug("retry full sequence\n");
+		slave = pll->slave;
+
+		/* commit slave if split display is enabled */
+		if (slave)
+			pll_db_commit_8996(slave, pdb);
+
+		/* commit master itself */
+		pll_db_commit_8996(pll, pdb);
+	}
+
+	mdss_pll_resource_enable(pll, false);
+
+	return rc;
+}
+
+static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb, int *pll_trim_codes)
+{
+	struct dsi_pll_output *pout = &pdb->out;
+
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL20,
+		DSIPHY_CMN_CTRL_0, DSIPHY_PLL_SYSCLK_EN_RESET,
+		0xFF, 0x0);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL21,
+		DSIPHY_PLL_DEC_START, DSIPHY_PLL_DIV_FRAC_START1,
+		pout->dec_start, (pout->div_frac_start & 0x0FF));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL22,
+		DSIPHY_PLL_DIV_FRAC_START2, DSIPHY_PLL_DIV_FRAC_START3,
+		((pout->div_frac_start >> 8) & 0x0FF),
+		((pout->div_frac_start >> 16) & 0x0F));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL23,
+		DSIPHY_PLL_PLLLOCK_CMP1, DSIPHY_PLL_PLLLOCK_CMP2,
+		(pout->plllock_cmp & 0x0FF),
+		((pout->plllock_cmp >> 8) & 0x0FF));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL24,
+		DSIPHY_PLL_PLLLOCK_CMP3, DSIPHY_PLL_PLL_VCO_TUNE,
+		((pout->plllock_cmp >> 16) & 0x03),
+		(pll_trim_codes[1] | BIT(7))); /* VCO tune*/
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL25,
+		DSIPHY_PLL_KVCO_CODE, DSIPHY_PLL_RESETSM_CNTRL,
+		(pll_trim_codes[0] | BIT(5)), 0x38);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL26,
+		DSIPHY_PLL_PLL_LPF2_POSTDIV, DSIPHY_CMN_PLL_CNTRL,
+		(((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1), 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL27,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL28,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL29,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, 0x0000001E);
+	MDSS_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0x001FFE00);
+
+	pr_debug("core_kvco_code=0x%x core_vco_tune=0x%x\n",
+			pll_trim_codes[0], pll_trim_codes[1]);
+
+	/*
+	 * Ensure all the dynamic refresh registers are written before
+	 * dynamic refresh to change the fps is triggered
+	 */
+	wmb();
+}
+
+int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct dsi_pll_db *pdb;
+	int pll_trim_codes[2] = {0, 0};
+
+	if (!pll) {
+		pr_err("PLL data not found\n");
+		return -EINVAL;
+	}
+
+	pdb = pll->priv;
+	if (!pdb) {
+		pr_err("No priv data found\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	pr_debug("%s: ndx=%d base=%pk rate=%lu\n", __func__,
+			pll->index, pll->pll_base, rate);
+
+	pll->vco_current_rate = rate;
+	pll->vco_ref_clk_rate = vco->ref_clk_rate;
+
+	mdss_dsi_pll_8996_input_init(pll, pdb);
+
+	pll_8996_dec_frac_calc(pll, pdb);
+
+	pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+			pll->vco_ref_clk_rate);
+
+	shadow_pll_dynamic_refresh_8996(pll, pdb, pll_trim_codes);
+
+	rc = mdss_pll_resource_enable(pll, false);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	return rc;
+}
+
+static unsigned long pll_vco_get_rate_8996(struct clk *c)
+{
+	u64 vco_rate, multiplier = BIT(20);
+	s32 div_frac_start;
+	u32 dec_start;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	u64 ref_clk = vco->ref_clk_rate;
+	int rc;
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return rc;
+	}
+
+	dec_start = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DEC_START);
+	dec_start &= 0x0ff;
+	pr_debug("dec_start = 0x%x\n", dec_start);
+
+	div_frac_start = (MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16;
+	div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8;
+	div_frac_start |= MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff;
+	pr_debug("div_frac_start = 0x%x\n", div_frac_start);
+
+	vco_rate = ref_clk * dec_start;
+	vco_rate += ((ref_clk * div_frac_start) / multiplier);
+
+	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return (unsigned long)vco_rate;
+}
+
+long pll_vco_round_rate_8996(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	u32 div;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	div = vco->min_rate / rate;
+	if (div > 15) {
+		/* rate < 86.67 Mhz */
+		pr_err("rate=%lu NOT supportted\n", rate);
+		return -EINVAL;
+	}
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	return rrate;
+}
+
+enum handoff pll_vco_handoff_8996(struct clk *c)
+{
+	int rc;
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (is_gdsc_disabled(pll))
+		return HANDOFF_DISABLED_CLK;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return ret;
+	}
+
+	if (pll_is_pll_locked_8996(pll)) {
+		pll->handoff_resources = true;
+		pll->pll_on = true;
+		c->rate = pll_vco_get_rate_8996(c);
+		ret = HANDOFF_ENABLED_CLK;
+	} else {
+		mdss_pll_resource_enable(pll, false);
+	}
+
+	return ret;
+}
+
+enum handoff shadow_pll_vco_handoff_8996(struct clk *c)
+{
+	return HANDOFF_DISABLED_CLK;
+}
+
+int pll_vco_prepare_8996(struct clk *c)
+{
+	int rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (!pll) {
+		pr_err("Dsi pll resources are not available\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("ndx=%d Failed to enable mdss dsi pll resources\n",
+							pll->index);
+		return rc;
+	}
+
+	if ((pll->vco_cached_rate != 0)
+	    && (pll->vco_cached_rate == c->rate)) {
+		rc = c->ops->set_rate(c, pll->vco_cached_rate);
+		if (rc) {
+			pr_err("index=%d vco_set_rate failed. rc=%d\n",
+					rc, pll->index);
+			mdss_pll_resource_enable(pll, false);
+			goto error;
+		}
+	}
+
+	rc = dsi_pll_enable(c);
+
+	if (rc) {
+		mdss_pll_resource_enable(pll, false);
+		pr_err("ndx=%d failed to enable dsi pll\n", pll->index);
+	}
+
+error:
+	return rc;
+}
+
+void pll_vco_unprepare_8996(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (!pll) {
+		pr_err("Dsi pll resources are not available\n");
+		return;
+	}
+
+	pll->vco_cached_rate = c->rate;
+	dsi_pll_disable(c);
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c
new file mode 100644
index 0000000..6423342
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c
@@ -0,0 +1,572 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/workqueue.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-8996.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-8996.h"
+
+#define VCO_DELAY_USEC		1
+
+static struct dsi_pll_db pll_db[DSI_PLL_NUM];
+
+static struct clk_ops n2_clk_src_ops;
+static struct clk_ops shadow_n2_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops post_n1_div_clk_src_ops;
+static struct clk_ops shadow_post_n1_div_clk_src_ops;
+
+static struct clk_ops clk_ops_gen_mux_dsi;
+
+/* Op structures */
+static const struct clk_ops clk_ops_dsi_vco = {
+	.set_rate = pll_vco_set_rate_8996,
+	.round_rate = pll_vco_round_rate_8996,
+	.handoff = pll_vco_handoff_8996,
+	.prepare = pll_vco_prepare_8996,
+	.unprepare = pll_vco_unprepare_8996,
+};
+
+static struct clk_div_ops post_n1_div_ops = {
+	.set_div = post_n1_div_set_div,
+	.get_div = post_n1_div_get_div,
+};
+
+static struct clk_div_ops n2_div_ops = {	/* hr_oclk3 */
+	.set_div = n2_div_set_div,
+	.get_div = n2_div_get_div,
+};
+
+static struct clk_mux_ops mdss_byte_mux_ops = {
+	.set_mux_sel = set_mdss_byte_mux_sel_8996,
+	.get_mux_sel = get_mdss_byte_mux_sel_8996,
+};
+
+static struct clk_mux_ops mdss_pixel_mux_ops = {
+	.set_mux_sel = set_mdss_pixel_mux_sel_8996,
+	.get_mux_sel = get_mdss_pixel_mux_sel_8996,
+};
+
+/* Shadow ops for dynamic refresh */
+static const struct clk_ops clk_ops_shadow_dsi_vco = {
+	.set_rate = shadow_pll_vco_set_rate_8996,
+	.round_rate = pll_vco_round_rate_8996,
+	.handoff = shadow_pll_vco_handoff_8996,
+};
+
+static struct clk_div_ops shadow_post_n1_div_ops = {
+	.set_div = post_n1_div_set_div,
+};
+
+static struct clk_div_ops shadow_n2_div_ops = {
+	.set_div = shadow_n2_div_set_div,
+};
+
+static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
+	.ref_clk_rate = 19200000UL,
+	.min_rate = 1300000000UL,
+	.max_rate = 2600000000UL,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi0pll_vco_clk_8996",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi0pll_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
+	.ref_clk_rate = 19200000u,
+	.min_rate = 1300000000u,
+	.max_rate = 2600000000u,
+	.c = {
+		.dbg_name = "dsi0pll_shadow_vco_clk",
+		.ops = &clk_ops_shadow_dsi_vco,
+		CLK_INIT(dsi0pll_shadow_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
+	.ref_clk_rate = 19200000UL,
+	.min_rate = 1300000000UL,
+	.max_rate = 2600000000UL,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi1pll_vco_clk_8996",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi1pll_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
+	.ref_clk_rate = 19200000u,
+	.min_rate = 1300000000u,
+	.max_rate = 2600000000u,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi1pll_shadow_vco_clk",
+		.ops = &clk_ops_shadow_dsi_vco,
+		CLK_INIT(dsi1pll_shadow_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &post_n1_div_ops,
+	.c = {
+		.parent = &dsi0pll_vco_clk.c,
+		.dbg_name = "dsi0pll_post_n1_div_clk",
+		.ops = &post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_post_n1_div_ops,
+	.c = {
+		.parent = &dsi0pll_shadow_vco_clk.c,
+		.dbg_name = "dsi0pll_shadow_post_n1_div_clk",
+		.ops = &shadow_post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &post_n1_div_ops,
+	.c = {
+		.parent = &dsi1pll_vco_clk.c,
+		.dbg_name = "dsi1pll_post_n1_div_clk",
+		.ops = &post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_post_n1_div_ops,
+	.c = {
+		.parent = &dsi1pll_shadow_vco_clk.c,
+		.dbg_name = "dsi1pll_shadow_post_n1_div_clk",
+		.ops = &shadow_post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &n2_div_ops,
+	.c = {
+		.parent = &dsi0pll_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_n2_div_clk",
+		.ops = &n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_n2_div_ops,
+	.c = {
+		.parent = &dsi0pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_n2_div_clk",
+		.ops = &shadow_n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &n2_div_ops,
+	.c = {
+		.parent = &dsi1pll_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_n2_div_clk",
+		.ops = &n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_n2_div_ops,
+	.c = {
+		.parent = &dsi1pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_n2_div_clk",
+		.ops = &shadow_n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi0pll_n2_div_clk.c,
+		.dbg_name = "dsi0pll_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi0pll_shadow_n2_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi1pll_n2_div_clk.c,
+		.dbg_name = "dsi1pll_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi1pll_shadow_n2_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi0pll_pixel_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi0pll_pixel_clk_src.c, 0},
+		{&dsi0pll_shadow_pixel_clk_src.c, 1},
+	},
+	.ops = &mdss_pixel_mux_ops,
+	.c = {
+		.parent = &dsi0pll_pixel_clk_src.c,
+		.dbg_name = "dsi0pll_pixel_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_pixel_clk_mux.c),
+	}
+};
+
+static struct mux_clk dsi1pll_pixel_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi1pll_pixel_clk_src.c, 0},
+		{&dsi1pll_shadow_pixel_clk_src.c, 1},
+	},
+	.ops = &mdss_pixel_mux_ops,
+	.c = {
+		.parent = &dsi1pll_pixel_clk_src.c,
+		.dbg_name = "dsi1pll_pixel_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_pixel_clk_mux.c),
+	}
+};
+
+static struct div_clk dsi0pll_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi0pll_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi0pll_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi0pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi0pll_shadow_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi1pll_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi1pll_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi1pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi1pll_shadow_byte_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi0pll_byte_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi0pll_byte_clk_src.c, 0},
+		{&dsi0pll_shadow_byte_clk_src.c, 1},
+	},
+	.ops = &mdss_byte_mux_ops,
+	.c = {
+		.parent = &dsi0pll_byte_clk_src.c,
+		.dbg_name = "dsi0pll_byte_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_byte_clk_mux.c),
+	}
+};
+static struct mux_clk dsi1pll_byte_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi1pll_byte_clk_src.c, 0},
+		{&dsi1pll_shadow_byte_clk_src.c, 1},
+	},
+	.ops = &mdss_byte_mux_ops,
+	.c = {
+		.parent = &dsi1pll_byte_clk_src.c,
+		.dbg_name = "dsi1pll_byte_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_byte_clk_mux.c),
+	}
+};
+
+static struct clk_lookup mdss_dsi_pllcc_8996[] = {
+	CLK_LIST(dsi0pll_byte_clk_mux),
+	CLK_LIST(dsi0pll_byte_clk_src),
+	CLK_LIST(dsi0pll_pixel_clk_mux),
+	CLK_LIST(dsi0pll_pixel_clk_src),
+	CLK_LIST(dsi0pll_n2_div_clk),
+	CLK_LIST(dsi0pll_post_n1_div_clk),
+	CLK_LIST(dsi0pll_vco_clk),
+	CLK_LIST(dsi0pll_shadow_byte_clk_src),
+	CLK_LIST(dsi0pll_shadow_pixel_clk_src),
+	CLK_LIST(dsi0pll_shadow_n2_div_clk),
+	CLK_LIST(dsi0pll_shadow_post_n1_div_clk),
+	CLK_LIST(dsi0pll_shadow_vco_clk),
+};
+
+static struct clk_lookup mdss_dsi_pllcc_8996_1[] = {
+	CLK_LIST(dsi1pll_byte_clk_mux),
+	CLK_LIST(dsi1pll_byte_clk_src),
+	CLK_LIST(dsi1pll_pixel_clk_mux),
+	CLK_LIST(dsi1pll_pixel_clk_src),
+	CLK_LIST(dsi1pll_n2_div_clk),
+	CLK_LIST(dsi1pll_post_n1_div_clk),
+	CLK_LIST(dsi1pll_vco_clk),
+	CLK_LIST(dsi1pll_shadow_byte_clk_src),
+	CLK_LIST(dsi1pll_shadow_pixel_clk_src),
+	CLK_LIST(dsi1pll_shadow_n2_div_clk),
+	CLK_LIST(dsi1pll_shadow_post_n1_div_clk),
+	CLK_LIST(dsi1pll_shadow_vco_clk),
+};
+
+int dsi_pll_clock_register_8996(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0, ndx;
+	int const ssc_freq_default = 31500; /* default h/w recommended value */
+	int const ssc_ppm_default = 5000; /* default h/w recommended value */
+	struct dsi_pll_db *pdb;
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pll_res || !pll_res->pll_base) {
+		pr_err("Invalid PLL resources\n");
+		return -EPROBE_DEFER;
+	}
+
+	if (pll_res->index >= DSI_PLL_NUM) {
+		pr_err("pll ndx=%d is NOT supported\n", pll_res->index);
+		return -EINVAL;
+	}
+
+	ndx = pll_res->index;
+	pdb = &pll_db[ndx];
+	pll_res->priv = pdb;
+	pdb->pll = pll_res;
+	ndx++;
+	ndx %= DSI_PLL_NUM;
+	pdb->next = &pll_db[ndx];
+
+	/* Set clock source operations */
+
+	/* hr_oclk3, pixel_clock */
+	n2_clk_src_ops = clk_ops_slave_div;
+	n2_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	shadow_n2_clk_src_ops = clk_ops_slave_div;
+
+	/* hr_ockl2, byte, vco pll */
+	post_n1_div_clk_src_ops = clk_ops_div;
+	post_n1_div_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	shadow_post_n1_div_clk_src_ops = clk_ops_div;
+
+	byte_clk_src_ops = clk_ops_div;
+	byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	clk_ops_gen_mux_dsi = clk_ops_gen_mux;
+	clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
+	clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
+
+	if (pll_res->ssc_en) {
+		if (!pll_res->ssc_freq)
+			pll_res->ssc_freq = ssc_freq_default;
+		if (!pll_res->ssc_ppm)
+			pll_res->ssc_ppm = ssc_ppm_default;
+	}
+
+	/* Set client data to mux, div and vco clocks.  */
+	if (pll_res->index == DSI_PLL_1) {
+		dsi1pll_byte_clk_src.priv = pll_res;
+		dsi1pll_pixel_clk_src.priv = pll_res;
+		dsi1pll_post_n1_div_clk.priv = pll_res;
+		dsi1pll_n2_div_clk.priv = pll_res;
+		dsi1pll_vco_clk.priv = pll_res;
+
+		dsi1pll_shadow_byte_clk_src.priv = pll_res;
+		dsi1pll_shadow_pixel_clk_src.priv = pll_res;
+		dsi1pll_shadow_post_n1_div_clk.priv = pll_res;
+		dsi1pll_shadow_n2_div_clk.priv = pll_res;
+		dsi1pll_shadow_vco_clk.priv = pll_res;
+
+		pll_res->vco_delay = VCO_DELAY_USEC;
+		if ((pll_res->target_id == MDSS_PLL_TARGET_8996) ||
+			(pll_res->target_id == MDSS_PLL_TARGET_8953)) {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				mdss_dsi_pllcc_8996_1,
+				ARRAY_SIZE(mdss_dsi_pllcc_8996_1));
+		}
+	} else {
+		dsi0pll_byte_clk_src.priv = pll_res;
+		dsi0pll_pixel_clk_src.priv = pll_res;
+		dsi0pll_post_n1_div_clk.priv = pll_res;
+		dsi0pll_n2_div_clk.priv = pll_res;
+		dsi0pll_vco_clk.priv = pll_res;
+
+		dsi0pll_shadow_byte_clk_src.priv = pll_res;
+		dsi0pll_shadow_pixel_clk_src.priv = pll_res;
+		dsi0pll_shadow_post_n1_div_clk.priv = pll_res;
+		dsi0pll_shadow_n2_div_clk.priv = pll_res;
+		dsi0pll_shadow_vco_clk.priv = pll_res;
+
+		pll_res->vco_delay = VCO_DELAY_USEC;
+		if ((pll_res->target_id == MDSS_PLL_TARGET_8996) ||
+			(pll_res->target_id == MDSS_PLL_TARGET_8953)) {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				mdss_dsi_pllcc_8996,
+				ARRAY_SIZE(mdss_dsi_pllcc_8996));
+		}
+	}
+
+	if (!rc) {
+		pr_info("Registered DSI PLL ndx=%d clocks successfully\n",
+						pll_res->index);
+	}
+
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h
new file mode 100644
index 0000000..57700e8
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h
@@ -0,0 +1,224 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MDSS_DSI_PLL_8996_H
+#define MDSS_DSI_PLL_8996_H
+
+#define DSIPHY_CMN_CLK_CFG0		0x0010
+#define DSIPHY_CMN_CLK_CFG1		0x0014
+#define DSIPHY_CMN_GLBL_TEST_CTRL	0x0018
+
+#define DSIPHY_CMN_PLL_CNTRL		0x0048
+#define DSIPHY_CMN_CTRL_0		0x001c
+#define DSIPHY_CMN_CTRL_1		0x0020
+
+#define DSIPHY_CMN_LDO_CNTRL		0x004c
+#define DSIPHY_CMN_GLBL_DIGTOP_SPARE2	0x005c
+
+#define DSIPHY_PLL_IE_TRIM		0x0400
+#define DSIPHY_PLL_IP_TRIM		0x0404
+
+#define DSIPHY_PLL_IPTAT_TRIM		0x0410
+
+#define DSIPHY_PLL_CLKBUFLR_EN		0x041c
+
+#define DSIPHY_PLL_SYSCLK_EN_RESET	0x0428
+#define DSIPHY_PLL_RESETSM_CNTRL	0x042c
+#define DSIPHY_PLL_RESETSM_CNTRL2	0x0430
+#define DSIPHY_PLL_RESETSM_CNTRL3	0x0434
+#define DSIPHY_PLL_RESETSM_CNTRL4	0x0438
+#define DSIPHY_PLL_RESETSM_CNTRL5	0x043c
+#define DSIPHY_PLL_KVCO_DIV_REF1	0x0440
+#define DSIPHY_PLL_KVCO_DIV_REF2	0x0444
+#define DSIPHY_PLL_KVCO_COUNT1		0x0448
+#define DSIPHY_PLL_KVCO_COUNT2		0x044c
+#define DSIPHY_PLL_VREF_CFG1		0x045c
+
+#define DSIPHY_PLL_KVCO_CODE		0x0458
+#define DSIPHY_PLL_CORE_VCO_TUNE_STATUS	0x4D0
+#define DSIPHY_PLL_CORE_KVCO_CODE_STATUS	0x4D4
+
+#define DSIPHY_PLL_VCO_DIV_REF1		0x046c
+#define DSIPHY_PLL_VCO_DIV_REF2		0x0470
+#define DSIPHY_PLL_VCO_COUNT1		0x0474
+#define DSIPHY_PLL_VCO_COUNT2		0x0478
+#define DSIPHY_PLL_PLLLOCK_CMP1		0x047c
+#define DSIPHY_PLL_PLLLOCK_CMP2		0x0480
+#define DSIPHY_PLL_PLLLOCK_CMP3		0x0484
+#define DSIPHY_PLL_PLLLOCK_CMP_EN	0x0488
+#define DSIPHY_PLL_PLL_VCO_TUNE		0x048C
+#define DSIPHY_PLL_DEC_START		0x0490
+#define DSIPHY_PLL_SSC_EN_CENTER	0x0494
+#define DSIPHY_PLL_SSC_ADJ_PER1		0x0498
+#define DSIPHY_PLL_SSC_ADJ_PER2		0x049c
+#define DSIPHY_PLL_SSC_PER1		0x04a0
+#define DSIPHY_PLL_SSC_PER2		0x04a4
+#define DSIPHY_PLL_SSC_STEP_SIZE1	0x04a8
+#define DSIPHY_PLL_SSC_STEP_SIZE2	0x04ac
+#define DSIPHY_PLL_DIV_FRAC_START1	0x04b4
+#define DSIPHY_PLL_DIV_FRAC_START2	0x04b8
+#define DSIPHY_PLL_DIV_FRAC_START3	0x04bc
+#define DSIPHY_PLL_TXCLK_EN		0x04c0
+#define DSIPHY_PLL_PLL_CRCTRL		0x04c4
+
+#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc
+
+#define DSIPHY_PLL_PLL_MISC1		0x04e8
+
+#define DSIPHY_PLL_CP_SET_CUR		0x04f0
+#define DSIPHY_PLL_PLL_ICPMSET		0x04f4
+#define DSIPHY_PLL_PLL_ICPCSET		0x04f8
+#define DSIPHY_PLL_PLL_ICP_SET		0x04fc
+#define DSIPHY_PLL_PLL_LPF1		0x0500
+#define DSIPHY_PLL_PLL_LPF2_POSTDIV	0x0504
+#define DSIPHY_PLL_PLL_BANDGAP	0x0508
+
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL15		0x050
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL19		0x060
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL20		0x064
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL21		0x068
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL22		0x06C
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL23		0x070
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL24		0x074
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL25		0x078
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL26		0x07C
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL27		0x080
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL28		0x084
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL29		0x088
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR	0x094
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2	0x098
+
+struct dsi_pll_input {
+	u32 fref;	/* 19.2 Mhz, reference clk */
+	u32 fdata;	/* bit clock rate */
+	u32 dsiclk_sel; /* 1, reg: 0x0014 */
+	u32 n2div;	/* 1, reg: 0x0010, bit 4-7 */
+	u32 ssc_en;	/* 1, reg: 0x0494, bit 0 */
+	u32 ldo_en;	/* 0,  reg: 0x004c, bit 0 */
+
+	/* fixed  */
+	u32 refclk_dbler_en;	/* 0, reg: 0x04c0, bit 1 */
+	u32 vco_measure_time;	/* 5, unknown */
+	u32 kvco_measure_time;	/* 5, unknown */
+	u32 bandgap_timer;	/* 4, reg: 0x0430, bit 3 - 5 */
+	u32 pll_wakeup_timer;	/* 5, reg: 0x043c, bit 0 - 2 */
+	u32 plllock_cnt;	/* 1, reg: 0x0488, bit 1 - 2 */
+	u32 plllock_rng;	/* 1, reg: 0x0488, bit 3 - 4 */
+	u32 ssc_center;		/* 0, reg: 0x0494, bit 1 */
+	u32 ssc_adj_period;	/* 37, reg: 0x498, bit 0 - 9 */
+	u32 ssc_spread;		/* 0.005  */
+	u32 ssc_freq;		/* unknown */
+	u32 pll_ie_trim;	/* 4, reg: 0x0400 */
+	u32 pll_ip_trim;	/* 4, reg: 0x0404 */
+	u32 pll_iptat_trim;	/* reg: 0x0410 */
+	u32 pll_cpcset_cur;	/* 1, reg: 0x04f0, bit 0 - 2 */
+	u32 pll_cpmset_cur;	/* 1, reg: 0x04f0, bit 3 - 5 */
+
+	u32 pll_icpmset;	/* 4, reg: 0x04fc, bit 3 - 5 */
+	u32 pll_icpcset;	/* 4, reg: 0x04fc, bit 0 - 2 */
+
+	u32 pll_icpmset_p;	/* 0, reg: 0x04f4, bit 0 - 2 */
+	u32 pll_icpmset_m;	/* 0, reg: 0x04f4, bit 3 - 5 */
+
+	u32 pll_icpcset_p;	/* 0, reg: 0x04f8, bit 0 - 2 */
+	u32 pll_icpcset_m;	/* 0, reg: 0x04f8, bit 3 - 5 */
+
+	u32 pll_lpf_res1;	/* 3, reg: 0x0504, bit 0 - 3 */
+	u32 pll_lpf_cap1;	/* 11, reg: 0x0500, bit 0 - 3 */
+	u32 pll_lpf_cap2;	/* 1, reg: 0x0500, bit 4 - 7 */
+	u32 pll_c3ctrl;		/* 2, reg: 0x04c4 */
+	u32 pll_r3ctrl;		/* 1, reg: 0x04c4 */
+};
+
+struct dsi_pll_output {
+	u32 pll_txclk_en;	/* reg: 0x04c0 */
+	u32 dec_start;		/* reg: 0x0490 */
+	u32 div_frac_start;	/* reg: 0x04b4, 0x4b8, 0x04bc */
+	u32 ssc_period;		/* reg: 0x04a0, 0x04a4 */
+	u32 ssc_step_size;	/* reg: 0x04a8, 0x04ac */
+	u32 plllock_cmp;	/* reg: 0x047c, 0x0480, 0x0484 */
+	u32 pll_vco_div_ref;	/* reg: 0x046c, 0x0470 */
+	u32 pll_vco_count;	/* reg: 0x0474, 0x0478 */
+	u32 pll_kvco_div_ref;	/* reg: 0x0440, 0x0444 */
+	u32 pll_kvco_count;	/* reg: 0x0448, 0x044c */
+	u32 pll_misc1;		/* reg: 0x04e8 */
+	u32 pll_lpf2_postdiv;	/* reg: 0x0504 */
+	u32 pll_resetsm_cntrl;	/* reg: 0x042c */
+	u32 pll_resetsm_cntrl2;	/* reg: 0x0430 */
+	u32 pll_resetsm_cntrl5;	/* reg: 0x043c */
+	u32 pll_kvco_code;		/* reg: 0x0458 */
+
+	u32 cmn_clk_cfg0;	/* reg: 0x0010 */
+	u32 cmn_clk_cfg1;	/* reg: 0x0014 */
+	u32 cmn_ldo_cntrl;	/* reg: 0x004c */
+
+	u32 pll_postdiv;	/* vco */
+	u32 pll_n1div;		/* vco */
+	u32 pll_n2div;		/* hr_oclk3, pixel_clock */
+	u32 fcvo;
+};
+
+enum {
+	DSI_PLL_0,
+	DSI_PLL_1,
+	DSI_PLL_NUM
+};
+
+struct dsi_pll_db {
+	struct dsi_pll_db *next;
+	struct mdss_pll_resources *pll;
+	struct dsi_pll_input in;
+	struct dsi_pll_output out;
+	int source_setup_done;
+};
+
+enum {
+	PLL_OUTPUT_NONE,
+	PLL_OUTPUT_RIGHT,
+	PLL_OUTPUT_LEFT,
+	PLL_OUTPUT_BOTH
+};
+
+enum {
+	PLL_SOURCE_FROM_LEFT,
+	PLL_SOURCE_FROM_RIGHT
+};
+
+enum {
+	PLL_UNKNOWN,
+	PLL_STANDALONE,
+	PLL_SLAVE,
+	PLL_MASTER
+};
+
+int pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
+long pll_vco_round_rate_8996(struct clk *c, unsigned long rate);
+enum handoff pll_vco_handoff_8996(struct clk *c);
+enum handoff shadow_pll_vco_handoff_8996(struct clk *c);
+int shadow_post_n1_div_set_div(struct div_clk *clk, int div);
+int shadow_post_n1_div_get_div(struct div_clk *clk);
+int shadow_n2_div_set_div(struct div_clk *clk, int div);
+int shadow_n2_div_get_div(struct div_clk *clk);
+int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
+int pll_vco_prepare_8996(struct clk *c);
+void pll_vco_unprepare_8996(struct clk *c);
+int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel);
+int get_mdss_byte_mux_sel_8996(struct mux_clk *clk);
+int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel);
+int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk);
+int post_n1_div_set_div(struct div_clk *clk, int div);
+int post_n1_div_get_div(struct div_clk *clk);
+int n2_div_set_div(struct div_clk *clk, int div);
+int n2_div_get_div(struct div_clk *clk);
+int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll);
+
+#endif  /* MDSS_DSI_PLL_8996_H */
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-util.c
new file mode 100644
index 0000000..3bc7564
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-util.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+
+#define DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG	(0x0)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG	(0x0004)
+#define DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG	(0x0008)
+#define DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG	(0x000C)
+#define DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG		(0x0010)
+#define DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG	(0x0014)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG	(0x0024)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG	(0x0028)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG		(0x002C)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG	(0x0030)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG	(0x0034)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0		(0x0038)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1		(0x003C)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2		(0x0040)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3		(0x0044)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4		(0x0048)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0		(0x004C)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1		(0x0050)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2		(0x0054)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3		(0x0058)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0		(0x006C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG2		(0x0074)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3		(0x0078)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4		(0x007C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG5		(0x0080)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6		(0x0084)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7		(0x0088)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8		(0x008C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9		(0x0090)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10	(0x0094)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11	(0x0098)
+#define DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG	(0x009C)
+#define DSI_PHY_PLL_UNIPHY_PLL_STATUS		(0x00C0)
+
+#define DSI_PLL_POLL_DELAY_US			50
+#define DSI_PLL_POLL_TIMEOUT_US			500
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel)
+{
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	pr_debug("byte mux set to %s mode\n", sel ? "indirect" : "direct");
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, (sel << 1));
+
+	return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+	int mux_mode, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	mux_mode = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG) & BIT(1);
+
+	pr_debug("byte mux mode = %s", mux_mode ? "indirect" : "direct");
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return !!mux_mode;
+}
+
+int dsi_pll_div_prepare(struct clk *c)
+{
+	struct div_clk *div = to_div_clk(c);
+	/* Restore the divider's value */
+	return div->ops->set_div(div, div->data.div);
+}
+
+int dsi_pll_mux_prepare(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int i, rc, sel = 0;
+	struct mdss_pll_resources *dsi_pll_res = mux->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	for (i = 0; i < mux->num_parents; i++)
+		if (mux->parents[i].src == c->parent) {
+			sel = mux->parents[i].sel;
+			break;
+		}
+
+	if (i == mux->num_parents) {
+		pr_err("Failed to select the parent clock\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* Restore the mux source select value */
+	rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG, (div - 1));
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int fixed_4div_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return div + 1;
+}
+
+int digital_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, (div - 1));
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int digital_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+					DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return div + 1;
+}
+
+int analog_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, div - 1);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int analog_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(clk->priv, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+		DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return div;
+}
+
+int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res)
+{
+	u32 status;
+	int pll_locked;
+
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_atomic((dsi_pll_res->pll_base +
+			DSI_PHY_PLL_UNIPHY_PLL_STATUS),
+			status,
+			((status & BIT(0)) == 1),
+			DSI_PLL_POLL_DELAY_US,
+			DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_debug("DSI PLL status=%x failed to Lock\n", status);
+		pll_locked = 0;
+	} else {
+		pll_locked = 1;
+	}
+
+	return pll_locked;
+}
+
+static int pll_28nm_vco_rate_calc(struct dsi_pll_vco_clk *vco,
+		struct mdss_dsi_vco_calc *vco_calc, unsigned long vco_clk_rate)
+{
+	s32 rem;
+	s64 frac_n_mode, ref_doubler_en_b;
+	s64 ref_clk_to_pll, div_fb, frac_n_value;
+	int i;
+
+	/* Configure the Loop filter resistance */
+	for (i = 0; i < vco->lpfr_lut_size; i++)
+		if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+			break;
+	if (i == vco->lpfr_lut_size) {
+		pr_err("unable to get loop filter resistance. vco=%ld\n",
+			vco_clk_rate);
+		return -EINVAL;
+	}
+	vco_calc->lpfr_lut_res = vco->lpfr_lut[i].r;
+
+	div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+	if (rem) {
+		vco_calc->refclk_cfg = 0x1;
+		frac_n_mode = 1;
+		ref_doubler_en_b = 0;
+	} else {
+		vco_calc->refclk_cfg = 0x0;
+		frac_n_mode = 0;
+		ref_doubler_en_b = 1;
+	}
+
+	pr_debug("refclk_cfg = %lld\n", vco_calc->refclk_cfg);
+
+	ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (vco_calc->refclk_cfg))
+			  + (ref_doubler_en_b * vco->ref_clk_rate));
+
+	div_fb = div_s64_rem(vco_clk_rate, ref_clk_to_pll, &rem);
+	frac_n_value = div_s64(((s64)rem * (1 << 16)), ref_clk_to_pll);
+	vco_calc->gen_vco_clk = vco_clk_rate;
+
+	pr_debug("ref_clk_to_pll = %lld\n", ref_clk_to_pll);
+	pr_debug("div_fb = %lld\n", div_fb);
+	pr_debug("frac_n_value = %lld\n", frac_n_value);
+
+	pr_debug("Generated VCO Clock: %lld\n", vco_calc->gen_vco_clk);
+	rem = 0;
+	if (frac_n_mode) {
+		vco_calc->sdm_cfg0 = 0;
+		vco_calc->sdm_cfg1 = (div_fb & 0x3f) - 1;
+		vco_calc->sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+		vco_calc->sdm_cfg2 = rem;
+	} else {
+		vco_calc->sdm_cfg0 = (0x1 << 5);
+		vco_calc->sdm_cfg0 |= (div_fb & 0x3f) - 1;
+		vco_calc->sdm_cfg1 = 0;
+		vco_calc->sdm_cfg2 = 0;
+		vco_calc->sdm_cfg3 = 0;
+	}
+
+	pr_debug("sdm_cfg0=%lld\n", vco_calc->sdm_cfg0);
+	pr_debug("sdm_cfg1=%lld\n", vco_calc->sdm_cfg1);
+	pr_debug("sdm_cfg2=%lld\n", vco_calc->sdm_cfg2);
+	pr_debug("sdm_cfg3=%lld\n", vco_calc->sdm_cfg3);
+
+	vco_calc->cal_cfg11 = div_s64_rem(vco_calc->gen_vco_clk,
+			256 * 1000000, &rem);
+	vco_calc->cal_cfg10 = rem / 1000000;
+	pr_debug("cal_cfg10=%lld, cal_cfg11=%lld\n",
+		vco_calc->cal_cfg10, vco_calc->cal_cfg11);
+
+	return 0;
+}
+
+static void pll_28nm_ssc_param_calc(struct dsi_pll_vco_clk *vco,
+		struct mdss_dsi_vco_calc *vco_calc)
+{
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+	s64 ppm_freq, incr, spread_freq, div_rf, frac_n_value;
+	s32 rem;
+
+	if (!dsi_pll_res->ssc_en) {
+		pr_debug("DSI PLL SSC not enabled\n");
+		return;
+	}
+
+	vco_calc->ssc.kdiv = DIV_ROUND_CLOSEST(vco->ref_clk_rate,
+			1000000) - 1;
+	vco_calc->ssc.triang_steps = DIV_ROUND_CLOSEST(vco->ref_clk_rate,
+			dsi_pll_res->ssc_freq * (vco_calc->ssc.kdiv + 1));
+	ppm_freq = div_s64(vco_calc->gen_vco_clk * dsi_pll_res->ssc_ppm,
+			1000000);
+	incr = div64_s64(ppm_freq * 65536, vco->ref_clk_rate * 2 *
+			vco_calc->ssc.triang_steps);
+
+	vco_calc->ssc.triang_inc_7_0 = incr & 0xff;
+	vco_calc->ssc.triang_inc_9_8 = (incr >> 8) & 0x3;
+
+	if (!dsi_pll_res->ssc_center)
+		spread_freq = vco_calc->gen_vco_clk - ppm_freq;
+	else
+		spread_freq = vco_calc->gen_vco_clk - (ppm_freq / 2);
+
+	div_rf = div_s64(spread_freq, 2 * vco->ref_clk_rate);
+	vco_calc->ssc.dc_offset = (div_rf - 1);
+
+	div_s64_rem(spread_freq, 2 * vco->ref_clk_rate, &rem);
+	frac_n_value = div_s64((s64)rem * 65536, 2 * vco->ref_clk_rate);
+
+	vco_calc->ssc.freq_seed_7_0 = frac_n_value & 0xff;
+	vco_calc->ssc.freq_seed_15_8 = (frac_n_value >> 8) & 0xff;
+}
+
+static void pll_28nm_vco_config(void __iomem *pll_base,
+		struct mdss_dsi_vco_calc *vco_calc,
+		u32 vco_delay_us, bool ssc_en)
+{
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG,
+		vco_calc->lpfr_lut_res);
+
+	/* Loop filter capacitance values : c1 and c2 */
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
+
+	if (!ssc_en) {
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+			(u32)(vco_calc->sdm_cfg1 & 0xff));
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+			(u32)(vco_calc->sdm_cfg2 & 0xff));
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+			(u32)(vco_calc->sdm_cfg3 & 0xff));
+	} else {
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+			(u32)vco_calc->ssc.dc_offset);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+			(u32)vco_calc->ssc.freq_seed_7_0);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+			(u32)vco_calc->ssc.freq_seed_15_8);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0,
+			(u32)vco_calc->ssc.kdiv);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1,
+			(u32)vco_calc->ssc.triang_inc_7_0);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2,
+			(u32)vco_calc->ssc.triang_inc_9_8);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3,
+			(u32)vco_calc->ssc.triang_steps);
+	}
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
+
+	/* Add hardware recommended delay for correct PLL configuration */
+	if (vco_delay_us)
+		udelay(vco_delay_us);
+
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+		(u32)vco_calc->refclk_cfg);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
+		(u32)vco_calc->sdm_cfg0);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+		(u32)(vco_calc->cal_cfg10 & 0xff));
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+		(u32)(vco_calc->cal_cfg11 & 0xff));
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+}
+
+int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
+{
+	struct mdss_dsi_vco_calc vco_calc = {0};
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+	int rc = 0;
+
+	rc = pll_28nm_vco_rate_calc(vco, &vco_calc, rate);
+	if (rc) {
+		pr_err("vco rate calculation failed\n");
+		return rc;
+	}
+
+	pll_28nm_ssc_param_calc(vco, &vco_calc);
+	pll_28nm_vco_config(dsi_pll_res->pll_base, &vco_calc,
+		dsi_pll_res->vco_delay, dsi_pll_res->ssc_en);
+
+	return 0;
+}
+
+unsigned long vco_get_rate(struct clk *c)
+{
+	u32 sdm0, doubler, sdm_byp_div;
+	u64 vco_rate;
+	u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	u64 ref_clk = vco->ref_clk_rate;
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/* Check to see if the ref clk doubler is enabled */
+	doubler = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				 DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0);
+	ref_clk += (doubler * vco->ref_clk_rate);
+
+	/* see if it is integer mode or sdm mode */
+	sdm0 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+					DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+	if (sdm0 & BIT(6)) {
+		/* integer mode */
+		sdm_byp_div = (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+		vco_rate = ref_clk * sdm_byp_div;
+	} else {
+		/* sdm mode */
+		sdm_dc_off = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+		pr_debug("sdm_dc_off = %d\n", sdm_dc_off);
+		sdm2 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+		sdm3 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+		sdm_freq_seed = (sdm3 << 8) | sdm2;
+		pr_debug("sdm_freq_seed = %d\n", sdm_freq_seed);
+
+		vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+			mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+		pr_debug("vco rate = %lld", vco_rate);
+	}
+
+	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return (unsigned long)vco_rate;
+}
+
+static int dsi_pll_enable(struct clk *c)
+{
+	int i, rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/* Try all enable sequences until one succeeds */
+	for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+		rc = vco->pll_enable_seqs[i](dsi_pll_res);
+		pr_debug("DSI PLL %s after sequence #%d\n",
+			rc ? "unlocked" : "locked", i + 1);
+		if (!rc)
+			break;
+	}
+
+	if (rc) {
+		mdss_pll_resource_enable(dsi_pll_res, false);
+		pr_err("DSI PLL failed to lock\n");
+	}
+	dsi_pll_res->pll_on = true;
+
+	return rc;
+}
+
+static void dsi_pll_disable(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res->pll_on &&
+		mdss_pll_resource_enable(dsi_pll_res, true)) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return;
+	}
+
+	dsi_pll_res->handoff_resources = false;
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	dsi_pll_res->pll_on = false;
+
+	pr_debug("DSI PLL Disabled\n");
+}
+
+long vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	return rrate;
+}
+
+enum handoff vco_handoff(struct clk *c)
+{
+	int rc;
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return ret;
+	}
+
+	if (dsi_pll_lock_status(dsi_pll_res)) {
+		dsi_pll_res->handoff_resources = true;
+		dsi_pll_res->pll_on = true;
+		c->rate = vco_get_rate(c);
+		ret = HANDOFF_ENABLED_CLK;
+	} else {
+		mdss_pll_resource_enable(dsi_pll_res, false);
+	}
+
+	return ret;
+}
+
+int vco_prepare(struct clk *c)
+{
+	int rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res) {
+		pr_err("Dsi pll resources are not available\n");
+		return -EINVAL;
+	}
+
+	if ((dsi_pll_res->vco_cached_rate != 0)
+	    && (dsi_pll_res->vco_cached_rate == c->rate)) {
+		rc = c->ops->set_rate(c, dsi_pll_res->vco_cached_rate);
+		if (rc) {
+			pr_err("vco_set_rate failed. rc=%d\n", rc);
+			goto error;
+		}
+	}
+
+	rc = dsi_pll_enable(c);
+
+error:
+	return rc;
+}
+
+void vco_unprepare(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res) {
+		pr_err("Dsi pll resources are not available\n");
+		return;
+	}
+
+	dsi_pll_res->vco_cached_rate = c->rate;
+	dsi_pll_disable(c);
+}
+
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll.h b/drivers/clk/msm/mdss/mdss-dsi-pll.h
new file mode 100644
index 0000000..4a9bb64
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDSS_DSI_PLL_H
+#define __MDSS_DSI_PLL_H
+
+#define MAX_DSI_PLL_EN_SEQS	10
+
+#define DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG		(0x0020)
+#define DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2	(0x0064)
+#define DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG		(0x0068)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1		(0x0070)
+
+/* Register offsets for 20nm PHY PLL */
+#define MMSS_DSI_PHY_PLL_PLL_CNTRL		(0x0014)
+#define MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN	(0x002C)
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN		(0x009C)
+
+struct lpfr_cfg {
+	unsigned long vco_rate;
+	u32 r;
+};
+
+struct dsi_pll_vco_clk {
+	unsigned long	ref_clk_rate;
+	unsigned long	min_rate;
+	unsigned long	max_rate;
+	u32		pll_en_seq_cnt;
+	struct lpfr_cfg *lpfr_lut;
+	u32		lpfr_lut_size;
+	void		*priv;
+
+	struct clk	c;
+
+	int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])
+			(struct mdss_pll_resources *dsi_pll_Res);
+};
+
+struct ssc_params {
+	s32 kdiv;
+	s64 triang_inc_7_0;
+	s64 triang_inc_9_8;
+	s64 triang_steps;
+	s64 dc_offset;
+	s64 freq_seed_7_0;
+	s64 freq_seed_15_8;
+};
+
+struct mdss_dsi_vco_calc {
+	s64 sdm_cfg0;
+	s64 sdm_cfg1;
+	s64 sdm_cfg2;
+	s64 sdm_cfg3;
+	s64 cal_cfg10;
+	s64 cal_cfg11;
+	s64 refclk_cfg;
+	s64 gen_vco_clk;
+	u32 lpfr_lut_res;
+	struct ssc_params ssc;
+};
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+int dsi_pll_clock_register_hpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_20nm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_lpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_8996(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel);
+int get_byte_mux_sel(struct mux_clk *clk);
+int dsi_pll_div_prepare(struct clk *c);
+int dsi_pll_mux_prepare(struct clk *c);
+int fixed_4div_set_div(struct div_clk *clk, int div);
+int fixed_4div_get_div(struct div_clk *clk);
+int digital_set_div(struct div_clk *clk, int div);
+int digital_get_div(struct div_clk *clk);
+int analog_set_div(struct div_clk *clk, int div);
+int analog_get_div(struct div_clk *clk);
+int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
+int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
+unsigned long vco_get_rate(struct clk *c);
+long vco_round_rate(struct clk *c, unsigned long rate);
+enum handoff vco_handoff(struct clk *c);
+int vco_prepare(struct clk *c);
+void vco_unprepare(struct clk *c);
+
+/* APIs for 20nm PHY PLL */
+int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
+int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
+				unsigned long rate);
+long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
+enum handoff pll_20nm_vco_handoff(struct clk *c);
+int pll_20nm_vco_prepare(struct clk *c);
+void pll_20nm_vco_unprepare(struct clk *c);
+int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res);
+
+int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
+int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
+int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
+int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
+int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
+int fixed_hr_oclk2_get_div(struct div_clk *clk);
+int hr_oclk3_set_div(struct div_clk *clk, int div);
+int shadow_hr_oclk3_set_div(struct div_clk *clk, int div);
+int hr_oclk3_get_div(struct div_clk *clk);
+int ndiv_set_div(struct div_clk *clk, int div);
+int shadow_ndiv_set_div(struct div_clk *clk, int div);
+int ndiv_get_div(struct div_clk *clk);
+void __dsi_pll_disable(void __iomem *pll_base);
+
+int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
+int get_mdss_pixel_mux_sel(struct mux_clk *clk);
+int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel);
+int get_mdss_byte_mux_sel(struct mux_clk *clk);
+
+#endif
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c
new file mode 100644
index 0000000..0f2d61e
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c
@@ -0,0 +1,2689 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-8996.h>
+
+#include "mdss-pll.h"
+#include "mdss-hdmi-pll.h"
+
+/* CONSTANTS */
+#define HDMI_BIT_CLK_TO_PIX_CLK_RATIO            10
+#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD         3400000000UL
+#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD          1500000000UL
+#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD          750000000
+#define HDMI_CLKS_PLL_DIVSEL                     0
+#define HDMI_CORECLK_DIV                         5
+#define HDMI_REF_CLOCK                           19200000
+#define HDMI_64B_ERR_VAL                         0xFFFFFFFFFFFFFFFFULL
+#define HDMI_VERSION_8996_V1                     1
+#define HDMI_VERSION_8996_V2                     2
+#define HDMI_VERSION_8996_V3                     3
+#define HDMI_VERSION_8996_V3_1_8                 4
+
+#define HDMI_VCO_MAX_FREQ                        12000000000UL
+#define HDMI_VCO_MIN_FREQ                        8000000000UL
+#define HDMI_2400MHZ_BIT_CLK_HZ                  2400000000UL
+#define HDMI_2250MHZ_BIT_CLK_HZ                  2250000000UL
+#define HDMI_2000MHZ_BIT_CLK_HZ                  2000000000UL
+#define HDMI_1700MHZ_BIT_CLK_HZ                  1700000000UL
+#define HDMI_1200MHZ_BIT_CLK_HZ                  1200000000UL
+#define HDMI_1334MHZ_BIT_CLK_HZ                  1334000000UL
+#define HDMI_1000MHZ_BIT_CLK_HZ                  1000000000UL
+#define HDMI_850MHZ_BIT_CLK_HZ                   850000000
+#define HDMI_667MHZ_BIT_CLK_HZ                   667000000
+#define HDMI_600MHZ_BIT_CLK_HZ                   600000000
+#define HDMI_500MHZ_BIT_CLK_HZ                   500000000
+#define HDMI_450MHZ_BIT_CLK_HZ                   450000000
+#define HDMI_334MHZ_BIT_CLK_HZ                   334000000
+#define HDMI_300MHZ_BIT_CLK_HZ                   300000000
+#define HDMI_282MHZ_BIT_CLK_HZ                   282000000
+#define HDMI_250MHZ_BIT_CLK_HZ                   250000000
+#define HDMI_KHZ_TO_HZ                           1000
+
+/* PLL REGISTERS */
+#define QSERDES_COM_ATB_SEL1                     (0x000)
+#define QSERDES_COM_ATB_SEL2                     (0x004)
+#define QSERDES_COM_FREQ_UPDATE                  (0x008)
+#define QSERDES_COM_BG_TIMER                     (0x00C)
+#define QSERDES_COM_SSC_EN_CENTER                (0x010)
+#define QSERDES_COM_SSC_ADJ_PER1                 (0x014)
+#define QSERDES_COM_SSC_ADJ_PER2                 (0x018)
+#define QSERDES_COM_SSC_PER1                     (0x01C)
+#define QSERDES_COM_SSC_PER2                     (0x020)
+#define QSERDES_COM_SSC_STEP_SIZE1               (0x024)
+#define QSERDES_COM_SSC_STEP_SIZE2               (0x028)
+#define QSERDES_COM_POST_DIV                     (0x02C)
+#define QSERDES_COM_POST_DIV_MUX                 (0x030)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN          (0x034)
+#define QSERDES_COM_CLK_ENABLE1                  (0x038)
+#define QSERDES_COM_SYS_CLK_CTRL                 (0x03C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE            (0x040)
+#define QSERDES_COM_PLL_EN                       (0x044)
+#define QSERDES_COM_PLL_IVCO                     (0x048)
+#define QSERDES_COM_LOCK_CMP1_MODE0              (0x04C)
+#define QSERDES_COM_LOCK_CMP2_MODE0              (0x050)
+#define QSERDES_COM_LOCK_CMP3_MODE0              (0x054)
+#define QSERDES_COM_LOCK_CMP1_MODE1              (0x058)
+#define QSERDES_COM_LOCK_CMP2_MODE1              (0x05C)
+#define QSERDES_COM_LOCK_CMP3_MODE1              (0x060)
+#define QSERDES_COM_LOCK_CMP1_MODE2              (0x064)
+#define QSERDES_COM_CMN_RSVD0                    (0x064)
+#define QSERDES_COM_LOCK_CMP2_MODE2              (0x068)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL         (0x068)
+#define QSERDES_COM_LOCK_CMP3_MODE2              (0x06C)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS       (0x06C)
+#define QSERDES_COM_BG_TRIM                      (0x070)
+#define QSERDES_COM_CLK_EP_DIV                   (0x074)
+#define QSERDES_COM_CP_CTRL_MODE0                (0x078)
+#define QSERDES_COM_CP_CTRL_MODE1                (0x07C)
+#define QSERDES_COM_CP_CTRL_MODE2                (0x080)
+#define QSERDES_COM_CMN_RSVD1                    (0x080)
+#define QSERDES_COM_PLL_RCTRL_MODE0              (0x084)
+#define QSERDES_COM_PLL_RCTRL_MODE1              (0x088)
+#define QSERDES_COM_PLL_RCTRL_MODE2              (0x08C)
+#define QSERDES_COM_CMN_RSVD2                    (0x08C)
+#define QSERDES_COM_PLL_CCTRL_MODE0              (0x090)
+#define QSERDES_COM_PLL_CCTRL_MODE1              (0x094)
+#define QSERDES_COM_PLL_CCTRL_MODE2              (0x098)
+#define QSERDES_COM_CMN_RSVD3                    (0x098)
+#define QSERDES_COM_PLL_CNTRL                    (0x09C)
+#define QSERDES_COM_PHASE_SEL_CTRL               (0x0A0)
+#define QSERDES_COM_PHASE_SEL_DC                 (0x0A4)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL         (0x0A8)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM          (0x0A8)
+#define QSERDES_COM_SYSCLK_EN_SEL                (0x0AC)
+#define QSERDES_COM_CML_SYSCLK_SEL               (0x0B0)
+#define QSERDES_COM_RESETSM_CNTRL                (0x0B4)
+#define QSERDES_COM_RESETSM_CNTRL2               (0x0B8)
+#define QSERDES_COM_RESTRIM_CTRL                 (0x0BC)
+#define QSERDES_COM_RESTRIM_CTRL2                (0x0C0)
+#define QSERDES_COM_RESCODE_DIV_NUM              (0x0C4)
+#define QSERDES_COM_LOCK_CMP_EN                  (0x0C8)
+#define QSERDES_COM_LOCK_CMP_CFG                 (0x0CC)
+#define QSERDES_COM_DEC_START_MODE0              (0x0D0)
+#define QSERDES_COM_DEC_START_MODE1              (0x0D4)
+#define QSERDES_COM_DEC_START_MODE2              (0x0D8)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL          (0x0D8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0        (0x0DC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0        (0x0E0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0        (0x0E4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1        (0x0E8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1        (0x0EC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1        (0x0F0)
+#define QSERDES_COM_DIV_FRAC_START1_MODE2        (0x0F4)
+#define QSERDES_COM_VCO_TUNE_MINVAL1             (0x0F4)
+#define QSERDES_COM_DIV_FRAC_START2_MODE2        (0x0F8)
+#define QSERDES_COM_VCO_TUNE_MINVAL2             (0x0F8)
+#define QSERDES_COM_DIV_FRAC_START3_MODE2        (0x0FC)
+#define QSERDES_COM_CMN_RSVD4                    (0x0FC)
+#define QSERDES_COM_INTEGLOOP_INITVAL            (0x100)
+#define QSERDES_COM_INTEGLOOP_EN                 (0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0        (0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0        (0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1        (0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1        (0x114)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2        (0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1             (0x118)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2        (0x11C)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2             (0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2            (0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL                (0x124)
+#define QSERDES_COM_VCO_TUNE_MAP                 (0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0              (0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0              (0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1              (0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1              (0x138)
+#define QSERDES_COM_VCO_TUNE1_MODE2              (0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL1            (0x13C)
+#define QSERDES_COM_VCO_TUNE2_MODE2              (0x140)
+#define QSERDES_COM_VCO_TUNE_INITVAL2            (0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1              (0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2              (0x148)
+#define QSERDES_COM_SAR                          (0x14C)
+#define QSERDES_COM_SAR_CLK                      (0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS          (0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS        (0x158)
+#define QSERDES_COM_CMN_STATUS                   (0x15C)
+#define QSERDES_COM_RESET_SM_STATUS              (0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS          (0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS          (0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS          (0x16C)
+#define QSERDES_COM_BG_CTRL                      (0x170)
+#define QSERDES_COM_CLK_SELECT                   (0x174)
+#define QSERDES_COM_HSCLK_SEL                    (0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS     (0x17C)
+#define QSERDES_COM_PLL_ANALOG                   (0x180)
+#define QSERDES_COM_CORECLK_DIV                  (0x184)
+#define QSERDES_COM_SW_RESET                     (0x188)
+#define QSERDES_COM_CORE_CLK_EN                  (0x18C)
+#define QSERDES_COM_C_READY_STATUS               (0x190)
+#define QSERDES_COM_CMN_CONFIG                   (0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE            (0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL             (0x19C)
+#define QSERDES_COM_DEBUG_BUS0                   (0x1A0)
+#define QSERDES_COM_DEBUG_BUS1                   (0x1A4)
+#define QSERDES_COM_DEBUG_BUS2                   (0x1A8)
+#define QSERDES_COM_DEBUG_BUS3                   (0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL                (0x1B0)
+#define QSERDES_COM_CMN_MISC1                    (0x1B4)
+#define QSERDES_COM_CMN_MISC2                    (0x1B8)
+#define QSERDES_COM_CORECLK_DIV_MODE1            (0x1BC)
+#define QSERDES_COM_CORECLK_DIV_MODE2            (0x1C0)
+#define QSERDES_COM_CMN_RSVD5                    (0x1C0)
+
+/* Tx Channel base addresses */
+#define HDMI_TX_L0_BASE_OFFSET                   (0x400)
+#define HDMI_TX_L1_BASE_OFFSET                   (0x600)
+#define HDMI_TX_L2_BASE_OFFSET                   (0x800)
+#define HDMI_TX_L3_BASE_OFFSET                   (0xA00)
+
+/* Tx Channel PHY registers */
+#define QSERDES_TX_L0_BIST_MODE_LANENO                    (0x000)
+#define QSERDES_TX_L0_BIST_INVERT                         (0x004)
+#define QSERDES_TX_L0_CLKBUF_ENABLE                       (0x008)
+#define QSERDES_TX_L0_CMN_CONTROL_ONE                     (0x00C)
+#define QSERDES_TX_L0_CMN_CONTROL_TWO                     (0x010)
+#define QSERDES_TX_L0_CMN_CONTROL_THREE                   (0x014)
+#define QSERDES_TX_L0_TX_EMP_POST1_LVL                    (0x018)
+#define QSERDES_TX_L0_TX_POST2_EMPH                       (0x01C)
+#define QSERDES_TX_L0_TX_BOOST_LVL_UP_DN                  (0x020)
+#define QSERDES_TX_L0_HP_PD_ENABLES                       (0x024)
+#define QSERDES_TX_L0_TX_IDLE_LVL_LARGE_AMP               (0x028)
+#define QSERDES_TX_L0_TX_DRV_LVL                          (0x02C)
+#define QSERDES_TX_L0_TX_DRV_LVL_OFFSET                   (0x030)
+#define QSERDES_TX_L0_RESET_TSYNC_EN                      (0x034)
+#define QSERDES_TX_L0_PRE_STALL_LDO_BOOST_EN              (0x038)
+#define QSERDES_TX_L0_TX_BAND                             (0x03C)
+#define QSERDES_TX_L0_SLEW_CNTL                           (0x040)
+#define QSERDES_TX_L0_INTERFACE_SELECT                    (0x044)
+#define QSERDES_TX_L0_LPB_EN                              (0x048)
+#define QSERDES_TX_L0_RES_CODE_LANE_TX                    (0x04C)
+#define QSERDES_TX_L0_RES_CODE_LANE_RX                    (0x050)
+#define QSERDES_TX_L0_RES_CODE_LANE_OFFSET                (0x054)
+#define QSERDES_TX_L0_PERL_LENGTH1                        (0x058)
+#define QSERDES_TX_L0_PERL_LENGTH2                        (0x05C)
+#define QSERDES_TX_L0_SERDES_BYP_EN_OUT                   (0x060)
+#define QSERDES_TX_L0_DEBUG_BUS_SEL                       (0x064)
+#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN    (0x068)
+#define QSERDES_TX_L0_TX_POL_INV                          (0x06C)
+#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN          (0x070)
+#define QSERDES_TX_L0_BIST_PATTERN1                       (0x074)
+#define QSERDES_TX_L0_BIST_PATTERN2                       (0x078)
+#define QSERDES_TX_L0_BIST_PATTERN3                       (0x07C)
+#define QSERDES_TX_L0_BIST_PATTERN4                       (0x080)
+#define QSERDES_TX_L0_BIST_PATTERN5                       (0x084)
+#define QSERDES_TX_L0_BIST_PATTERN6                       (0x088)
+#define QSERDES_TX_L0_BIST_PATTERN7                       (0x08C)
+#define QSERDES_TX_L0_BIST_PATTERN8                       (0x090)
+#define QSERDES_TX_L0_LANE_MODE                           (0x094)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE                  (0x098)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION    (0x09C)
+#define QSERDES_TX_L0_ATB_SEL1                            (0x0A0)
+#define QSERDES_TX_L0_ATB_SEL2                            (0x0A4)
+#define QSERDES_TX_L0_RCV_DETECT_LVL                      (0x0A8)
+#define QSERDES_TX_L0_RCV_DETECT_LVL_2                    (0x0AC)
+#define QSERDES_TX_L0_PRBS_SEED1                          (0x0B0)
+#define QSERDES_TX_L0_PRBS_SEED2                          (0x0B4)
+#define QSERDES_TX_L0_PRBS_SEED3                          (0x0B8)
+#define QSERDES_TX_L0_PRBS_SEED4                          (0x0BC)
+#define QSERDES_TX_L0_RESET_GEN                           (0x0C0)
+#define QSERDES_TX_L0_RESET_GEN_MUXES                     (0x0C4)
+#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN                    (0x0C8)
+#define QSERDES_TX_L0_TX_INTERFACE_MODE                   (0x0CC)
+#define QSERDES_TX_L0_PWM_CTRL                            (0x0D0)
+#define QSERDES_TX_L0_PWM_ENCODED_OR_DATA                 (0x0D4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND2            (0x0D8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND2            (0x0DC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND2            (0x0E0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND2            (0x0E4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND0_1          (0x0E8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND0_1          (0x0EC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND0_1          (0x0F0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND0_1          (0x0F4)
+#define QSERDES_TX_L0_VMODE_CTRL1                         (0x0F8)
+#define QSERDES_TX_L0_VMODE_CTRL2                         (0x0FC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL              (0x100)
+#define QSERDES_TX_L0_BIST_STATUS                         (0x104)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT1                   (0x108)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT2                   (0x10C)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV                   (0x110)
+
+/* HDMI PHY REGISTERS */
+#define HDMI_PHY_BASE_OFFSET                  (0xC00)
+
+#define HDMI_PHY_CFG                          (0x00)
+#define HDMI_PHY_PD_CTL                       (0x04)
+#define HDMI_PHY_MODE                         (0x08)
+#define HDMI_PHY_MISR_CLEAR                   (0x0C)
+#define HDMI_PHY_TX0_TX1_BIST_CFG0            (0x10)
+#define HDMI_PHY_TX0_TX1_BIST_CFG1            (0x14)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0      (0x18)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1      (0x1C)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN0        (0x20)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN1        (0x24)
+#define HDMI_PHY_TX2_TX3_BIST_CFG0            (0x28)
+#define HDMI_PHY_TX2_TX3_BIST_CFG1            (0x2C)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0      (0x30)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1      (0x34)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN0        (0x38)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN1        (0x3C)
+#define HDMI_PHY_DEBUG_BUS_SEL                (0x40)
+#define HDMI_PHY_TXCAL_CFG0                   (0x44)
+#define HDMI_PHY_TXCAL_CFG1                   (0x48)
+#define HDMI_PHY_TX0_TX1_LANE_CTL             (0x4C)
+#define HDMI_PHY_TX2_TX3_LANE_CTL             (0x50)
+#define HDMI_PHY_LANE_BIST_CONFIG             (0x54)
+#define HDMI_PHY_CLOCK                        (0x58)
+#define HDMI_PHY_MISC1                        (0x5C)
+#define HDMI_PHY_MISC2                        (0x60)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS0         (0x64)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS1         (0x68)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS2         (0x6C)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS0         (0x70)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS1         (0x74)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS2         (0x78)
+#define HDMI_PHY_PRE_MISR_STATUS0             (0x7C)
+#define HDMI_PHY_PRE_MISR_STATUS1             (0x80)
+#define HDMI_PHY_PRE_MISR_STATUS2             (0x84)
+#define HDMI_PHY_PRE_MISR_STATUS3             (0x88)
+#define HDMI_PHY_POST_MISR_STATUS0            (0x8C)
+#define HDMI_PHY_POST_MISR_STATUS1            (0x90)
+#define HDMI_PHY_POST_MISR_STATUS2            (0x94)
+#define HDMI_PHY_POST_MISR_STATUS3            (0x98)
+#define HDMI_PHY_STATUS                       (0x9C)
+#define HDMI_PHY_MISC3_STATUS                 (0xA0)
+#define HDMI_PHY_MISC4_STATUS                 (0xA4)
+#define HDMI_PHY_DEBUG_BUS0                   (0xA8)
+#define HDMI_PHY_DEBUG_BUS1                   (0xAC)
+#define HDMI_PHY_DEBUG_BUS2                   (0xB0)
+#define HDMI_PHY_DEBUG_BUS3                   (0xB4)
+#define HDMI_PHY_PHY_REVISION_ID0             (0xB8)
+#define HDMI_PHY_PHY_REVISION_ID1             (0xBC)
+#define HDMI_PHY_PHY_REVISION_ID2             (0xC0)
+#define HDMI_PHY_PHY_REVISION_ID3             (0xC4)
+
+#define HDMI_PLL_POLL_MAX_READS                100
+#define HDMI_PLL_POLL_TIMEOUT_US               1500
+
+enum hdmi_pll_freqs {
+	HDMI_PCLK_25200_KHZ,
+	HDMI_PCLK_27027_KHZ,
+	HDMI_PCLK_27000_KHZ,
+	HDMI_PCLK_74250_KHZ,
+	HDMI_PCLK_148500_KHZ,
+	HDMI_PCLK_154000_KHZ,
+	HDMI_PCLK_268500_KHZ,
+	HDMI_PCLK_297000_KHZ,
+	HDMI_PCLK_594000_KHZ,
+	HDMI_PCLK_MAX
+};
+
+struct hdmi_8996_phy_pll_reg_cfg {
+	u32 tx_l0_lane_mode;
+	u32 tx_l2_lane_mode;
+	u32 tx_l0_tx_band;
+	u32 tx_l1_tx_band;
+	u32 tx_l2_tx_band;
+	u32 tx_l3_tx_band;
+	u32 com_svs_mode_clk_sel;
+	u32 com_hsclk_sel;
+	u32 com_pll_cctrl_mode0;
+	u32 com_pll_rctrl_mode0;
+	u32 com_cp_ctrl_mode0;
+	u32 com_dec_start_mode0;
+	u32 com_div_frac_start1_mode0;
+	u32 com_div_frac_start2_mode0;
+	u32 com_div_frac_start3_mode0;
+	u32 com_integloop_gain0_mode0;
+	u32 com_integloop_gain1_mode0;
+	u32 com_lock_cmp_en;
+	u32 com_lock_cmp1_mode0;
+	u32 com_lock_cmp2_mode0;
+	u32 com_lock_cmp3_mode0;
+	u32 com_core_clk_en;
+	u32 com_coreclk_div;
+	u32 com_restrim_ctrl;
+	u32 com_vco_tune_ctrl;
+
+	u32 tx_l0_tx_drv_lvl;
+	u32 tx_l0_tx_emp_post1_lvl;
+	u32 tx_l1_tx_drv_lvl;
+	u32 tx_l1_tx_emp_post1_lvl;
+	u32 tx_l2_tx_drv_lvl;
+	u32 tx_l2_tx_emp_post1_lvl;
+	u32 tx_l3_tx_drv_lvl;
+	u32 tx_l3_tx_emp_post1_lvl;
+	u32 tx_l0_vmode_ctrl1;
+	u32 tx_l0_vmode_ctrl2;
+	u32 tx_l1_vmode_ctrl1;
+	u32 tx_l1_vmode_ctrl2;
+	u32 tx_l2_vmode_ctrl1;
+	u32 tx_l2_vmode_ctrl2;
+	u32 tx_l3_vmode_ctrl1;
+	u32 tx_l3_vmode_ctrl2;
+	u32 tx_l0_res_code_lane_tx;
+	u32 tx_l1_res_code_lane_tx;
+	u32 tx_l2_res_code_lane_tx;
+	u32 tx_l3_res_code_lane_tx;
+
+	u32 phy_mode;
+};
+
+struct hdmi_8996_v3_post_divider {
+	u64 vco_freq;
+	u64 hsclk_divsel;
+	u64 vco_ratio;
+	u64 tx_band_sel;
+	u64 half_rate_mode;
+};
+
+static inline struct hdmi_pll_vco_clk *to_hdmi_8996_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct hdmi_pll_vco_clk, c);
+}
+
+static inline u64 hdmi_8996_v1_get_post_div_lt_2g(u64 bclk)
+{
+	if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_1700MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_1200MHZ_BIT_CLK_HZ)
+		return 4;
+	else if (bclk >= HDMI_850MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_600MHZ_BIT_CLK_HZ)
+		return 4;
+	else if (bclk >= HDMI_450MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_300MHZ_BIT_CLK_HZ)
+		return 4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_post_div_lt_2g(u64 bclk, u64 vco_range)
+{
+	u64 hdmi_8ghz = vco_range;
+	u64 tmp_calc;
+
+	hdmi_8ghz <<= 2;
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 6U);
+
+	if (bclk >= vco_range)
+		return 2;
+	else if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 1)
+		return 4;
+
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 12U);
+	if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 2)
+		return 4;
+
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 24U);
+	if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 3)
+		return 4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_post_div_gt_2g(u64 hsclk)
+{
+	if (hsclk >= 0 && hsclk <= 3)
+		return hsclk + 1;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_get_coreclk_div_lt_2g(u64 bclk)
+{
+	if (bclk >= HDMI_1334MHZ_BIT_CLK_HZ)
+		return 1;
+	else if (bclk >= HDMI_1000MHZ_BIT_CLK_HZ)
+		return 1;
+	else if (bclk >= HDMI_667MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_500MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_334MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_250MHZ_BIT_CLK_HZ)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_get_coreclk_div_ratio(u64 clks_pll_divsel,
+						  u64 coreclk_div)
+{
+	if (clks_pll_divsel == 0)
+		return coreclk_div*2;
+	else if (clks_pll_divsel == 1)
+		return coreclk_div*4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v1_get_tx_band(u64 bclk)
+{
+	if (bclk >= 2400000000UL)
+		return 0;
+	if (bclk >= 1200000000UL)
+		return 1;
+	if (bclk >= 600000000UL)
+		return 2;
+	if (bclk >= 300000000UL)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_tx_band(u64 bclk, u64 vco_range)
+{
+	if (bclk >= vco_range)
+		return 0;
+	else if (bclk >= vco_range >> 1)
+		return 1;
+	else if (bclk >= vco_range >> 2)
+		return 2;
+	else if (bclk >= vco_range >> 3)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v1_get_hsclk(u64 fdata)
+{
+	if (fdata >= 9600000000UL)
+		return 0;
+	else if (fdata >= 4800000000UL)
+		return 1;
+	else if (fdata >= 3200000000UL)
+		return 2;
+	else if (fdata >= 2400000000UL)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_hsclk(u64 fdata, u64 vco_range)
+{
+	u64 tmp_calc = vco_range;
+
+	tmp_calc <<= 2;
+	do_div(tmp_calc, 3U);
+	if (fdata >= (vco_range << 2))
+		return 0;
+	else if (fdata >= (vco_range << 1))
+		return 1;
+	else if (fdata >= tmp_calc)
+		return 2;
+	else if (fdata >= vco_range)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+
+}
+
+static inline u64 hdmi_8996_v2_get_vco_freq(u64 bclk, u64 vco_range)
+{
+	u64 tx_band_div_ratio = 1U << hdmi_8996_v2_get_tx_band(bclk, vco_range);
+	u64 pll_post_div_ratio;
+
+	if (bclk >= vco_range) {
+		u64 hsclk = hdmi_8996_v2_get_hsclk(bclk, vco_range);
+
+		pll_post_div_ratio = hdmi_8996_v2_get_post_div_gt_2g(hsclk);
+	} else {
+		pll_post_div_ratio = hdmi_8996_v2_get_post_div_lt_2g(bclk,
+								vco_range);
+	}
+
+	return bclk * (pll_post_div_ratio * tx_band_div_ratio);
+}
+
+static inline u64 hdmi_8996_v2_get_fdata(u64 bclk, u64 vco_range)
+{
+	if (bclk >= vco_range)
+		return bclk;
+
+	{
+		u64 tmp_calc = hdmi_8996_v2_get_vco_freq(bclk, vco_range);
+		u64 pll_post_div_ratio_lt_2g = hdmi_8996_v2_get_post_div_lt_2g(
+							bclk, vco_range);
+		if (pll_post_div_ratio_lt_2g == HDMI_64B_ERR_VAL)
+			return HDMI_64B_ERR_VAL;
+
+		do_div(tmp_calc, pll_post_div_ratio_lt_2g);
+		return tmp_calc;
+	}
+}
+
+static inline u64 hdmi_8996_get_cpctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) ||
+	    (gen_ssc == true))
+		/*
+		 * This should be ROUND(11/(19.2/20))).
+		 * Since ref clock does not change, hardcoding to 11
+		 */
+		return 0xB;
+
+	return 0x23;
+}
+
+static inline u64 hdmi_8996_get_rctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x16;
+
+	return 0x10;
+}
+
+static inline u64 hdmi_8996_get_cctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x28;
+
+	return 0x1;
+}
+
+static inline u64 hdmi_8996_get_integloop_gain(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x80;
+
+	return 0xC4;
+}
+
+static inline u64 hdmi_8996_v3_get_integloop_gain(u64 frac_start, u64 bclk,
+							bool gen_ssc)
+{
+	u64 digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2;
+	u64 base = ((frac_start != 0) || (gen_ssc == true)) ? 0x40 : 0xC4;
+
+	base <<= digclk_divsel;
+
+	return (base <= 2046 ? base : 0x7FE);
+}
+
+static inline u64 hdmi_8996_get_vco_tune(u64 fdata, u64 div)
+{
+	u64 vco_tune;
+
+	vco_tune = fdata * div;
+	do_div(vco_tune, 1000000);
+	vco_tune = 13000 - vco_tune - 256;
+	do_div(vco_tune, 5);
+
+	return vco_tune;
+}
+
+static inline u64 hdmi_8996_get_pll_cmp(u64 pll_cmp_cnt, u64 core_clk)
+{
+	u64 pll_cmp;
+	u64 rem;
+
+	pll_cmp = pll_cmp_cnt * core_clk;
+	rem = do_div(pll_cmp, HDMI_REF_CLOCK);
+	if (rem > (HDMI_REF_CLOCK >> 1))
+		pll_cmp++;
+	pll_cmp -= 1;
+
+	return pll_cmp;
+}
+
+static inline u64 hdmi_8996_v3_get_pll_cmp(u64 pll_cmp_cnt, u64 fdata)
+{
+	u64 dividend = pll_cmp_cnt * fdata;
+	u64 divisor = HDMI_REF_CLOCK * 10;
+	u64 rem;
+
+	rem = do_div(dividend, divisor);
+	if (rem > (divisor >> 1))
+		dividend++;
+
+	return dividend - 1;
+}
+
+static int hdmi_8996_v3_get_post_div(struct hdmi_8996_v3_post_divider *pd,
+						u64 bclk)
+{
+	u32 ratio[] = {2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35};
+	u32 tx_band_sel[] = {0, 1, 2, 3};
+	u64 vco_freq[60];
+	u64 vco, vco_optimal, half_rate_mode = 0;
+	int vco_optimal_index, vco_freq_index;
+	int i, j, k, x;
+
+	for (i = 0; i <= 1; i++) {
+		vco_optimal = HDMI_VCO_MAX_FREQ;
+		vco_optimal_index = -1;
+		vco_freq_index = 0;
+		for (j = 0; j < 15; j++) {
+			for (k = 0; k < 4; k++) {
+				u64 ratio_mult = ratio[j] << tx_band_sel[k];
+
+				vco = bclk >> half_rate_mode;
+				vco *= ratio_mult;
+				vco_freq[vco_freq_index++] = vco;
+			}
+		}
+
+		for (x = 0; x < 60; x++) {
+			u64 vco_tmp = vco_freq[x];
+
+			if ((vco_tmp >= HDMI_VCO_MIN_FREQ) &&
+					(vco_tmp <= vco_optimal)) {
+				vco_optimal = vco_tmp;
+				vco_optimal_index = x;
+			}
+		}
+
+		if (vco_optimal_index == -1) {
+			if (!half_rate_mode)
+				half_rate_mode++;
+			else
+				return -EINVAL;
+		} else {
+			pd->vco_freq = vco_optimal;
+			pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4];
+			pd->vco_ratio = ratio[vco_optimal_index / 4];
+			break;
+		}
+	}
+
+	switch (pd->vco_ratio) {
+	case 2:
+		pd->hsclk_divsel = 0;
+		break;
+	case 3:
+		pd->hsclk_divsel = 4;
+		break;
+	case 4:
+		pd->hsclk_divsel = 8;
+		break;
+	case 5:
+		pd->hsclk_divsel = 12;
+		break;
+	case 6:
+		pd->hsclk_divsel = 1;
+		break;
+	case 9:
+		pd->hsclk_divsel = 5;
+		break;
+	case 10:
+		pd->hsclk_divsel = 2;
+		break;
+	case 12:
+		pd->hsclk_divsel = 9;
+		break;
+	case 14:
+		pd->hsclk_divsel = 3;
+		break;
+	case 15:
+		pd->hsclk_divsel = 13;
+		break;
+	case 20:
+		pd->hsclk_divsel = 10;
+		break;
+	case 21:
+		pd->hsclk_divsel = 7;
+		break;
+	case 25:
+		pd->hsclk_divsel = 14;
+		break;
+	case 28:
+		pd->hsclk_divsel = 11;
+		break;
+	case 35:
+		pd->hsclk_divsel = 15;
+		break;
+	};
+
+	return 0;
+}
+
+static int hdmi_8996_v1_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	u64 fdata, clk_divtx, tmds_clk;
+	u64 bclk;
+	u64 post_div_gt_2g;
+	u64 post_div_lt_2g;
+	u64 coreclk_div1_lt_2g;
+	u64 core_clk_div_ratio;
+	u64 core_clk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 tx_band_div_ratio;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_tune;
+	u64 vco_freq;
+	u64 rem;
+
+	/* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = bclk/4;
+	else
+		tmds_clk = bclk;
+
+	post_div_lt_2g = hdmi_8996_v1_get_post_div_lt_2g(bclk);
+	if (post_div_lt_2g == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	coreclk_div1_lt_2g = hdmi_8996_get_coreclk_div_lt_2g(bclk);
+
+	core_clk_div_ratio = hdmi_8996_get_coreclk_div_ratio(
+				HDMI_CLKS_PLL_DIVSEL, HDMI_CORECLK_DIV);
+
+	tx_band = hdmi_8996_v1_get_tx_band(bclk);
+	if (tx_band == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	tx_band_div_ratio = 1 << tx_band;
+
+	if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) {
+		fdata = bclk;
+		hsclk = hdmi_8996_v1_get_hsclk(fdata);
+		if (hsclk == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL;
+		if (post_div_gt_2g == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		vco_freq = bclk * (post_div_gt_2g * tx_band_div_ratio);
+		clk_divtx = vco_freq;
+		do_div(clk_divtx, post_div_gt_2g);
+	} else {
+		vco_freq = bclk * (post_div_lt_2g * tx_band_div_ratio);
+		fdata = vco_freq;
+		do_div(fdata, post_div_lt_2g);
+		hsclk = hdmi_8996_v1_get_hsclk(fdata);
+		if (hsclk == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		clk_divtx = vco_freq;
+		do_div(clk_divtx, post_div_lt_2g);
+		post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL;
+		if (post_div_gt_2g == HDMI_64B_ERR_VAL)
+			goto fail;
+	}
+
+	/* Decimal and fraction values */
+	dec_start = fdata * post_div_gt_2g;
+	do_div(dec_start, pll_divisor);
+	frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) -
+			(fdata * post_div_gt_2g))) * (1 << 20));
+	rem = do_div(frac_start, pll_divisor);
+	/* Round off frac_start to closest integer */
+	if (rem >= (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false);
+	vco_tune = hdmi_8996_get_vco_tune(fdata, post_div_gt_2g);
+
+	core_clk = clk_divtx;
+	do_div(core_clk, core_clk_div_ratio);
+	pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk);
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_lane_mode = 0x3;
+	cfg->tx_l2_lane_mode = 0x3;
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+	cfg->tx_l0_res_code_lane_tx = 0x33;
+	cfg->tx_l1_res_code_lane_tx = 0x33;
+	cfg->tx_l2_res_code_lane_tx = 0x33;
+	cfg->tx_l3_res_code_lane_tx = 0x33;
+	cfg->com_restrim_ctrl = 0x0;
+	cfg->com_vco_tune_ctrl = 0x1C;
+
+	cfg->com_svs_mode_clk_sel =
+			(bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2);
+	cfg->com_hsclk_sel = (0x28 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4));
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->com_restrim_ctrl = 0x0;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->com_restrim_ctrl = 0x0;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+		cfg->com_restrim_ctrl = 0xD8;
+	}
+
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+	DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n",	cfg->com_restrim_ctrl);
+
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l0_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l1_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l2_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l3_res_code_lane_tx);
+
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_v2_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	u64 fdata, clk_divtx, tmds_clk;
+	u64 bclk;
+	u64 post_div;
+	u64 core_clk_div;
+	u64 core_clk_div_ratio;
+	u64 core_clk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 tx_band_div_ratio;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_tune;
+	u64 vco_freq;
+	u64 vco_range;
+	u64 rem;
+
+	/* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = pix_clk >> 2;
+	else
+		tmds_clk = pix_clk;
+
+	vco_range = bclk < HDMI_282MHZ_BIT_CLK_HZ ? HDMI_2000MHZ_BIT_CLK_HZ :
+				HDMI_2250MHZ_BIT_CLK_HZ;
+
+	fdata = hdmi_8996_v2_get_fdata(bclk, vco_range);
+	if (fdata == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	hsclk = hdmi_8996_v2_get_hsclk(fdata, vco_range);
+	if (hsclk == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	if (bclk >= vco_range)
+		post_div = hdmi_8996_v2_get_post_div_gt_2g(hsclk);
+	else
+		post_div = hdmi_8996_v2_get_post_div_lt_2g(bclk, vco_range);
+
+	if (post_div == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	core_clk_div = 5;
+	core_clk_div_ratio = core_clk_div * 2;
+
+	tx_band = hdmi_8996_v2_get_tx_band(bclk, vco_range);
+	if (tx_band == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	tx_band_div_ratio = 1 << tx_band;
+
+	vco_freq = hdmi_8996_v2_get_vco_freq(bclk, vco_range);
+	clk_divtx = vco_freq;
+	do_div(clk_divtx, post_div);
+
+	/* Decimal and fraction values */
+	dec_start = fdata * post_div;
+	do_div(dec_start, pll_divisor);
+	frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) -
+			(fdata * post_div))) * (1 << 20));
+	rem = do_div(frac_start, pll_divisor);
+	/* Round off frac_start to closest integer */
+	if (rem >= (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false);
+	vco_tune = hdmi_8996_get_vco_tune(fdata, post_div);
+
+	core_clk = clk_divtx;
+	do_div(core_clk, core_clk_div_ratio);
+	pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk);
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_lane_mode = 0x3;
+	cfg->tx_l2_lane_mode = 0x3;
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+
+	if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
+		cfg->com_svs_mode_clk_sel = 1;
+	else
+		cfg->com_svs_mode_clk_sel = 2;
+
+	cfg->com_hsclk_sel = (0x28 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4));
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+	cfg->com_vco_tune_ctrl = 0x0;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->tx_l0_res_code_lane_tx = 0x3F;
+		cfg->tx_l1_res_code_lane_tx = 0x3F;
+		cfg->tx_l2_res_code_lane_tx = 0x3F;
+		cfg->tx_l3_res_code_lane_tx = 0x3F;
+		cfg->com_restrim_ctrl = 0x0;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->tx_l0_res_code_lane_tx = 0x39;
+		cfg->tx_l1_res_code_lane_tx = 0x39;
+		cfg->tx_l2_res_code_lane_tx = 0x39;
+		cfg->tx_l3_res_code_lane_tx = 0x39;
+		cfg->com_restrim_ctrl = 0x0;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+		cfg->tx_l0_res_code_lane_tx = 0x3F;
+		cfg->tx_l1_res_code_lane_tx = 0x3F;
+		cfg->tx_l2_res_code_lane_tx = 0x3F;
+		cfg->tx_l3_res_code_lane_tx = 0x3F;
+		cfg->com_restrim_ctrl = 0xD8;
+	}
+
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_vco_tune_ctrl = 0x%x\n",
+						cfg->com_vco_tune_ctrl);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l0_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l1_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l2_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l3_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n",	cfg->com_restrim_ctrl);
+
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_v3_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	struct hdmi_8996_v3_post_divider pd;
+	u64 fdata, tmds_clk;
+	u64 bclk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_freq;
+	u64 rem;
+
+	/* FDATA, HSCLK, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = pix_clk >> 2;
+	else
+		tmds_clk = pix_clk;
+
+	if (hdmi_8996_v3_get_post_div(&pd, bclk) || pd.vco_ratio <= 0 ||
+			pd.vco_freq <= 0)
+		goto fail;
+
+	vco_freq = pd.vco_freq;
+	fdata = pd.vco_freq;
+	do_div(fdata, pd.vco_ratio);
+
+	hsclk = pd.hsclk_divsel;
+	dec_start = vco_freq;
+	do_div(dec_start, pll_divisor);
+
+	frac_start = vco_freq * (1 << 20);
+	rem = do_div(frac_start, pll_divisor);
+	frac_start -= dec_start * (1 << 20);
+	if (rem > (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_v3_get_integloop_gain(frac_start, bclk,
+									false);
+	pll_cmp = hdmi_8996_v3_get_pll_cmp(1024, fdata);
+	tx_band = pd.tx_band_sel;
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+
+	if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
+		cfg->com_svs_mode_clk_sel = 1;
+	else
+		cfg->com_svs_mode_clk_sel = 2;
+
+	cfg->com_hsclk_sel = (0x20 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_lock_cmp_en = 0x04;
+	cfg->com_core_clk_en = 0x2C;
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	cfg->com_vco_tune_ctrl = 0x0;
+
+	cfg->tx_l0_lane_mode = 0x43;
+	cfg->tx_l2_lane_mode = 0x43;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+	}
+
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg, u32 ver)
+{
+	switch (ver) {
+	case HDMI_VERSION_8996_V3:
+	case HDMI_VERSION_8996_V3_1_8:
+		return hdmi_8996_v3_calculate(pix_clk, cfg);
+	case HDMI_VERSION_8996_V2:
+		return hdmi_8996_v2_calculate(pix_clk, cfg);
+	default:
+		return hdmi_8996_v1_calculate(pix_clk, cfg);
+	}
+}
+
+static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	struct hdmi_8996_phy_pll_reg_cfg cfg = {0};
+
+	rc = hdmi_8996_calculate(tmds_clk, &cfg, ver);
+	if (rc) {
+		DEV_ERR("%s: PLL calculation failed\n", __func__);
+		return rc;
+	}
+
+	/* Initially shut down PHY */
+	DEV_DBG("%s: Disabling PHY\n", __func__);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x0);
+	udelay(500);
+
+	/* Power up sequence */
+	switch (ver) {
+	case HDMI_VERSION_8996_V2:
+	case HDMI_VERSION_8996_V3:
+	case HDMI_VERSION_8996_V3_1_8:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x04);
+		break;
+	};
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX0_TX1_LANE_CTL, 0x0F);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX2_TX3_LANE_CTL, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		     QSERDES_TX_L0_LANE_MODE, cfg.tx_l0_lane_mode);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		     QSERDES_TX_L0_LANE_MODE, cfg.tx_l2_lane_mode);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l0_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l1_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l2_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l3_tx_band);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0E);
+	if (ver == HDMI_VERSION_8996_V1)
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06);
+
+	/* Bypass VCO calibration */
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL,
+					cfg.com_svs_mode_clk_sel);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_TRIM, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IVCO, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_CTRL,
+			cfg.com_vco_tune_ctrl);
+
+	switch (ver) {
+	case HDMI_VERSION_8996_V1:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL,
+					cfg.com_svs_mode_clk_sel);
+		break;
+	default:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06);
+	}
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_SELECT, 0x30);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_HSCLK_SEL,
+		       cfg.com_hsclk_sel);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_EN,
+		       cfg.com_lock_cmp_en);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CCTRL_MODE0,
+		       cfg.com_pll_cctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_RCTRL_MODE0,
+		       cfg.com_pll_rctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CP_CTRL_MODE0,
+		       cfg.com_cp_ctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START_MODE0,
+		       cfg.com_dec_start_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START1_MODE0,
+		       cfg.com_div_frac_start1_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START2_MODE0,
+		       cfg.com_div_frac_start2_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START3_MODE0,
+		       cfg.com_div_frac_start3_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN0_MODE0,
+			cfg.com_integloop_gain0_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN1_MODE0,
+			cfg.com_integloop_gain1_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0,
+			cfg.com_lock_cmp1_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0,
+			cfg.com_lock_cmp2_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0,
+			cfg.com_lock_cmp3_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_MAP, 0x00);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORE_CLK_EN,
+		       cfg.com_core_clk_en);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORECLK_DIV,
+		       cfg.com_coreclk_div);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_CONFIG, 0x02);
+
+	if (ver == HDMI_VERSION_8996_V3 || ver == HDMI_VERSION_8996_V3_1_8)
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESCODE_DIV_NUM, 0x15);
+
+	/* TX lanes setup (TX 0/1/2/3) */
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l0_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l0_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l1_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l1_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l2_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l2_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000020);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l3_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l3_tx_emp_post1_lvl);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l0_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL2,
+		       cfg.tx_l0_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l1_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL2,
+		       cfg.tx_l1_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l2_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_VMODE_CTRL2,
+			cfg.tx_l2_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l3_vmode_ctrl1);
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_VMODE_CTRL2,
+				0x0000000D);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_VMODE_CTRL2,
+				cfg.tx_l3_vmode_ctrl2);
+	}
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+
+	if (ver < HDMI_VERSION_8996_V3) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l0_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l1_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l2_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l3_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL,
+			       cfg.com_restrim_ctrl);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00);
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05);
+	}
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, cfg.phy_mode);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x03);
+
+	if (ver == HDMI_VERSION_8996_V2) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x01);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x01);
+	}
+	/*
+	 * Ensure that vco configuration gets flushed to hardware before
+	 * enabling the PLL
+	 */
+	wmb();
+	return 0;
+}
+
+static int hdmi_8996_phy_ready_status(struct mdss_pll_resources *io)
+{
+	u32 status = 0;
+	int phy_ready = 0;
+	int rc;
+	u32 read_count = 0;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return rc;
+	}
+
+	DEV_DBG("%s: Waiting for PHY Ready\n", __func__);
+
+	/* Poll for PHY read status */
+	while (read_count < HDMI_PLL_POLL_MAX_READS) {
+		status = MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS);
+		if ((status & BIT(0)) == 1) {
+			phy_ready = 1;
+			DEV_DBG("%s: PHY READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == HDMI_PLL_POLL_MAX_READS) {
+		phy_ready = 0;
+		DEV_DBG("%s: PHY READY TIMEOUT\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	return phy_ready;
+}
+
+static int hdmi_8996_pll_lock_status(struct mdss_pll_resources *io)
+{
+	u32 status;
+	int pll_locked = 0;
+	int rc;
+	u32 read_count = 0;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return rc;
+	}
+
+	DEV_DBG("%s: Waiting for PLL lock\n", __func__);
+
+	while (read_count < HDMI_PLL_POLL_MAX_READS) {
+		status = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_C_READY_STATUS);
+		if ((status & BIT(0)) == 1) {
+			pll_locked = 1;
+			DEV_DBG("%s: C READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == HDMI_PLL_POLL_MAX_READS) {
+		pll_locked = 0;
+		DEV_DBG("%s: C READY TIMEOUT\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	return pll_locked;
+}
+
+static int hdmi_8996_v1_perform_sw_calibration(struct clk *c)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	u32 max_code = 0x190;
+	u32 min_code = 0x0;
+	u32 max_cnt = 0;
+	u32 min_cnt = 0;
+	u32 expected_counter_value = 0;
+	u32 step = 0;
+	u32 dbus_all = 0;
+	u32 dbus_sel = 0;
+	u32 vco_code = 0;
+	u32 val = 0;
+
+	vco_code = 0xC8;
+
+	DEV_DBG("%s: Starting SW calibration with vco_code = %d\n", __func__,
+		 vco_code);
+
+	expected_counter_value =
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0) << 16) |
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0) << 8) |
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0));
+
+	DEV_DBG("%s: expected_counter_value = %d\n", __func__,
+		 expected_counter_value);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(4);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(3);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x4);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+	val |= BIT(1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+	udelay(60);
+
+	while (1) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0,
+			       vco_code & 0xFF);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0,
+			       (vco_code >> 8) & 0x3);
+
+		udelay(20);
+
+		val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+		val &= ~BIT(1);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+		udelay(60);
+
+		val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+		val |= BIT(1);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+		udelay(60);
+
+		dbus_all =
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS3) << 24) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS2) << 16) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS1) << 8) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS0));
+
+		dbus_sel = (dbus_all >> 9) & 0x3FFFF;
+		DEV_DBG("%s: loop[%d], dbus_all = 0x%x, dbus_sel = 0x%x\n",
+			__func__, step, dbus_all, dbus_sel);
+		if (dbus_sel == 0)
+			DEV_ERR("%s: CHECK HDMI REF CLK\n", __func__);
+
+		if (dbus_sel == expected_counter_value) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			min_code = vco_code;
+			min_cnt = dbus_sel;
+		} else if (dbus_sel == 0) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		} else if (dbus_sel > expected_counter_value) {
+			min_code = vco_code;
+			min_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		} else if (dbus_sel < expected_counter_value) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		}
+
+		step++;
+
+		if ((vco_code == 0) || (vco_code == 0x3FF) || (step > 0x3FF)) {
+			DEV_ERR("%s: VCO tune code search failed\n", __func__);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if ((max_code - min_code) <= 1) {
+			if ((max_code - min_code) == 1) {
+				if (abs((int)(max_cnt - expected_counter_value))
+				    < abs((int)(min_cnt - expected_counter_value
+					))) {
+					vco_code = max_code;
+				} else {
+					vco_code = min_code;
+				}
+			}
+			break;
+		}
+		DEV_DBG("%s: loop[%d], new vco_code = %d\n", __func__, step,
+			 vco_code);
+	}
+
+	DEV_DBG("%s: CALIB done. vco_code = %d\n", __func__, vco_code);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0,
+		       vco_code & 0xFF);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0,
+		       (vco_code >> 8) & 0x3);
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+	val &= ~BIT(1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(4);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val &= ~BIT(3);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	return rc;
+}
+
+static int hdmi_8996_v2_perform_sw_calibration(struct clk *c)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	u32 vco_code1, vco_code2, integral_loop, ready_poll;
+	u32 read_count = 0;
+
+	while (read_count < (HDMI_PLL_POLL_MAX_READS << 1)) {
+		ready_poll = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_C_READY_STATUS);
+		if ((ready_poll & BIT(0)) == 1) {
+			ready_poll = 1;
+			DEV_DBG("%s: C READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == (HDMI_PLL_POLL_MAX_READS << 1)) {
+		ready_poll = 0;
+		DEV_DBG("%s: C READY TIMEOUT, TRYING SW CALIBRATION\n",
+								__func__);
+	}
+
+	vco_code1 = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_PLLCAL_CODE1_STATUS);
+	vco_code2 = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_PLLCAL_CODE2_STATUS);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x5);
+	integral_loop = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DEBUG_BUS0);
+
+	if (((ready_poll & 0x1) == 0) || (((ready_poll & 1) == 1) &&
+			(vco_code1 == 0xFF) && ((vco_code2 & 0x3) == 0x1) &&
+			(integral_loop > 0xC0))) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x04);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x00);
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x17);
+		udelay(100);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x11);
+		udelay(100);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+	}
+	return rc;
+}
+
+static int hdmi_8996_perform_sw_calibration(struct clk *c, u32 ver)
+{
+	switch (ver) {
+	case HDMI_VERSION_8996_V1:
+		return hdmi_8996_v1_perform_sw_calibration(c);
+	case HDMI_VERSION_8996_V2:
+		return hdmi_8996_v2_perform_sw_calibration(c);
+	}
+	return 0;
+}
+
+static int hdmi_8996_vco_enable(struct clk *c, u32 ver)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x1);
+	udelay(100);
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+	udelay(100);
+
+	rc = hdmi_8996_perform_sw_calibration(c, ver);
+	if (rc) {
+		DEV_ERR("%s: software calibration failed\n", __func__);
+		return rc;
+	}
+
+	rc = hdmi_8996_pll_lock_status(io);
+	if (!rc) {
+		DEV_ERR("%s: PLL not locked\n", __func__);
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+
+	/* Disable SSC */
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER1, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER2, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE1, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE2, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_EN_CENTER, 0x2);
+
+	rc = hdmi_8996_phy_ready_status(io);
+	if (!rc) {
+		DEV_ERR("%s: PHY not READY\n", __func__);
+		return rc;
+	}
+
+	/* Restart the retiming buffer */
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x18);
+	udelay(1);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+
+	io->pll_on = true;
+	return 0;
+}
+
+static int hdmi_8996_v1_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3_1_8);
+}
+
+static int hdmi_8996_vco_get_lock_range(struct clk *c, unsigned long pixel_clk)
+{
+	u32 rng = 64, cmp_cnt = 1024;
+	u32 coreclk_div = 5, clks_pll_divsel = 2;
+	u32 vco_freq, vco_ratio, ppm_range;
+	u64 bclk;
+	struct hdmi_8996_v3_post_divider pd;
+
+	bclk = ((u64)pixel_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	DEV_DBG("%s: rate=%ld\n", __func__, pixel_clk);
+
+	if (hdmi_8996_v3_get_post_div(&pd, bclk) ||
+		pd.vco_ratio <= 0 || pd.vco_freq <= 0) {
+		DEV_ERR("%s: couldn't get post div\n", __func__);
+		return -EINVAL;
+	}
+
+	do_div(pd.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ);
+
+	vco_freq  = (u32) pd.vco_freq;
+	vco_ratio = (u32) pd.vco_ratio;
+
+	DEV_DBG("%s: freq %d, ratio %d\n", __func__,
+		vco_freq, vco_ratio);
+
+	ppm_range = (rng * HDMI_REF_CLOCK) / cmp_cnt;
+	ppm_range /= vco_freq / vco_ratio;
+	ppm_range *= coreclk_div * clks_pll_divsel;
+
+	DEV_DBG("%s: ppm range: %d\n", __func__, ppm_range);
+
+	return ppm_range;
+}
+
+static int hdmi_8996_vco_rate_atomic_update(struct clk *c,
+	unsigned long rate, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	void __iomem *pll;
+	struct hdmi_8996_phy_pll_reg_cfg cfg = {0};
+	int rc = 0;
+
+	rc = hdmi_8996_calculate(rate, &cfg, ver);
+	if (rc) {
+		DEV_ERR("%s: PLL calculation failed\n", __func__);
+		goto end;
+	}
+
+	pll = io->pll_base;
+
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DEC_START_MODE0,
+		       cfg.com_dec_start_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START1_MODE0,
+		       cfg.com_div_frac_start1_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START2_MODE0,
+		       cfg.com_div_frac_start2_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START3_MODE0,
+		       cfg.com_div_frac_start3_mode0);
+
+	MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x01);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x00);
+
+	DEV_DBG("%s: updated to rate %ld\n", __func__, rate);
+end:
+	return rc;
+}
+
+static int hdmi_8996_vco_set_rate(struct clk *c, unsigned long rate, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	unsigned int set_power_dwn = 0;
+	bool atomic_update = false;
+	int rc, pll_lock_range;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return rc;
+	}
+
+	DEV_DBG("%s: rate %ld\n", __func__, rate);
+
+	if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0) &&
+		MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) {
+		pll_lock_range = hdmi_8996_vco_get_lock_range(c, vco->rate);
+
+		if (pll_lock_range > 0 && vco->rate) {
+			u32 range_limit;
+
+			range_limit  = vco->rate *
+				(pll_lock_range / HDMI_KHZ_TO_HZ);
+			range_limit /= HDMI_KHZ_TO_HZ;
+
+			DEV_DBG("%s: range limit %d\n", __func__, range_limit);
+
+			if (abs(rate - vco->rate) < range_limit)
+				atomic_update = true;
+		}
+	}
+
+	if (io->pll_on && !atomic_update)
+		set_power_dwn = 1;
+
+	if (atomic_update) {
+		hdmi_8996_vco_rate_atomic_update(c, rate, ver);
+	} else {
+		rc = hdmi_8996_phy_pll_set_clk_rate(c, rate, ver);
+		if (rc)
+			DEV_ERR("%s: Failed to set clk rate\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	if (set_power_dwn)
+		hdmi_8996_vco_enable(c, ver);
+
+	vco->rate = rate;
+	vco->rate_set = true;
+
+	return 0;
+}
+
+static int hdmi_8996_v1_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3_1_8);
+}
+
+static unsigned long hdmi_get_hsclk_sel_divisor(unsigned long hsclk_sel)
+{
+	unsigned long divisor;
+
+	switch (hsclk_sel) {
+	case 0:
+		divisor = 2;
+		break;
+	case 1:
+		divisor = 6;
+		break;
+	case 2:
+		divisor = 10;
+		break;
+	case 3:
+		divisor = 14;
+		break;
+	case 4:
+		divisor = 3;
+		break;
+	case 5:
+		divisor = 9;
+		break;
+	case 6:
+	case 13:
+		divisor = 15;
+		break;
+	case 7:
+		divisor = 21;
+		break;
+	case 8:
+		divisor = 4;
+		break;
+	case 9:
+		divisor = 12;
+		break;
+	case 10:
+		divisor = 20;
+		break;
+	case 11:
+		divisor = 28;
+		break;
+	case 12:
+		divisor = 5;
+		break;
+	case 14:
+		divisor = 25;
+		break;
+	case 15:
+		divisor = 35;
+		break;
+	default:
+		divisor = 1;
+		DEV_ERR("%s: invalid hsclk_sel value = %lu",
+				__func__, hsclk_sel);
+		break;
+	}
+
+	return divisor;
+}
+
+static unsigned long hdmi_8996_vco_get_rate(struct clk *c)
+{
+	unsigned long freq = 0, hsclk_sel = 0, tx_band = 0, dec_start = 0,
+		      div_frac_start = 0, vco_clock_freq = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	if (mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return freq;
+	}
+
+	dec_start = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEC_START_MODE0);
+
+	div_frac_start =
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START1_MODE0) |
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START2_MODE0) << 8 |
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START3_MODE0) << 16;
+
+	vco_clock_freq = (dec_start + (div_frac_start / (1 << 20)))
+		* 4 * (HDMI_REF_CLOCK);
+
+	hsclk_sel = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_HSCLK_SEL) & 0x15;
+	hsclk_sel = hdmi_get_hsclk_sel_divisor(hsclk_sel);
+	tx_band = MDSS_PLL_REG_R(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_TX_BAND) & 0x3;
+
+	freq = vco_clock_freq / (10 * hsclk_sel * (1 << tx_band));
+
+	mdss_pll_resource_enable(io, false);
+
+	DEV_DBG("%s: freq = %lu\n", __func__, freq);
+
+	return freq;
+}
+
+static long hdmi_8996_vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+
+	DEV_DBG("rrate=%ld\n", rrate);
+
+	return rrate;
+}
+
+static int hdmi_8996_vco_prepare(struct clk *c, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	int ret = 0;
+
+	DEV_DBG("rate=%ld\n", vco->rate);
+
+	if (!vco->rate_set && vco->rate)
+		ret = hdmi_8996_vco_set_rate(c, vco->rate, ver);
+
+	if (!ret) {
+		ret = mdss_pll_resource_enable(io, true);
+		if (ret)
+			DEV_ERR("pll resource can't be enabled\n");
+	}
+
+	return ret;
+}
+
+static int hdmi_8996_v1_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3_1_8);
+}
+
+static void hdmi_8996_vco_unprepare(struct clk *c)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	vco->rate_set = false;
+
+	if (!io) {
+		DEV_ERR("Invalid input parameter\n");
+		return;
+	}
+
+	if (!io->pll_on &&
+		mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return;
+	}
+
+	io->handoff_resources = false;
+	mdss_pll_resource_enable(io, false);
+	io->pll_on = false;
+}
+
+static enum handoff hdmi_8996_vco_handoff(struct clk *c)
+{
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	if (is_gdsc_disabled(io))
+		return HANDOFF_DISABLED_CLK;
+
+	if (mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return ret;
+	}
+
+	io->handoff_resources = true;
+
+	if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0)) {
+		if (MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) {
+			io->pll_on = true;
+			c->rate = hdmi_8996_vco_get_rate(c);
+			vco->rate = c->rate;
+			ret = HANDOFF_ENABLED_CLK;
+		} else {
+			io->handoff_resources = false;
+			mdss_pll_resource_enable(io, false);
+			DEV_DBG("%s: PHY not ready\n", __func__);
+		}
+	} else {
+		io->handoff_resources = false;
+		mdss_pll_resource_enable(io, false);
+		DEV_DBG("%s: PLL not locked\n", __func__);
+	}
+
+	DEV_DBG("done, ret=%d\n", ret);
+	return ret;
+}
+
+static const struct clk_ops hdmi_8996_v1_vco_clk_ops = {
+	.enable = hdmi_8996_v1_vco_enable,
+	.set_rate = hdmi_8996_v1_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v1_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v2_vco_clk_ops = {
+	.enable = hdmi_8996_v2_vco_enable,
+	.set_rate = hdmi_8996_v2_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v2_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v3_vco_clk_ops = {
+	.enable = hdmi_8996_v3_vco_enable,
+	.set_rate = hdmi_8996_v3_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v3_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v3_1p8_vco_clk_ops = {
+	.enable = hdmi_8996_v3_1p8_vco_enable,
+	.set_rate = hdmi_8996_v3_1p8_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v3_1p8_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+
+static struct hdmi_pll_vco_clk hdmi_vco_clk = {
+	.c = {
+		.dbg_name = "hdmi_8996_vco_clk",
+		.ops = &hdmi_8996_v1_vco_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmi_vco_clk.c),
+	},
+};
+
+static struct clk_lookup hdmipllcc_8996[] = {
+	CLK_LIST(hdmi_vco_clk),
+};
+
+int hdmi_8996_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res, u32 ver)
+{
+	int rc = -ENOTSUPP;
+
+	if (!pll_res || !pll_res->phy_base || !pll_res->pll_base) {
+		DEV_ERR("%s: Invalid input parameters\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	/* Set client data for vco, mux and div clocks */
+	hdmi_vco_clk.priv = pll_res;
+
+	switch (ver) {
+	case HDMI_VERSION_8996_V2:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v2_vco_clk_ops;
+		break;
+	case HDMI_VERSION_8996_V3:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v3_vco_clk_ops;
+		break;
+	case HDMI_VERSION_8996_V3_1_8:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v3_1p8_vco_clk_ops;
+		break;
+	default:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v1_vco_clk_ops;
+		break;
+	};
+
+	rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8996,
+					ARRAY_SIZE(hdmipllcc_8996));
+	if (rc) {
+		DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
+		rc = -EPROBE_DEFER;
+	} else {
+		DEV_DBG("%s SUCCESS\n", __func__);
+	}
+
+	return rc;
+}
+
+int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V1);
+}
+
+int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V2);
+}
+
+int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V3);
+}
+
+int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V3_1_8);
+}
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll.h b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
new file mode 100644
index 0000000..1f21d79
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDSS_HDMI_PLL_H
+#define __MDSS_HDMI_PLL_H
+
+struct hdmi_pll_cfg {
+	unsigned long vco_rate;
+	u32 reg;
+};
+
+struct hdmi_pll_vco_clk {
+	unsigned long	rate;	/* current vco rate */
+	unsigned long	min_rate;	/* min vco rate */
+	unsigned long	max_rate;	/* max vco rate */
+	bool		rate_set;
+	struct hdmi_pll_cfg *ip_seti;
+	struct hdmi_pll_cfg *cp_seti;
+	struct hdmi_pll_cfg *ip_setp;
+	struct hdmi_pll_cfg *cp_setp;
+	struct hdmi_pll_cfg *crctrl;
+	void		*priv;
+
+	struct clk	c;
+};
+
+int hdmi_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int hdmi_20nm_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+#endif
diff --git a/drivers/clk/msm/mdss/mdss-pll-util.c b/drivers/clk/msm/mdss/mdss-pll-util.c
new file mode 100644
index 0000000..7f7da9b
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll-util.c
@@ -0,0 +1,364 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/vmalloc.h>
+#include <linux/memblock.h>
+
+#include "mdss-pll.h"
+
+int mdss_pll_util_resource_init(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	rc = msm_mdss_config_vreg(&pdev->dev,
+				mp->vreg_config, mp->num_vreg, 1);
+	if (rc) {
+		pr_err("Vreg config failed rc=%d\n", rc);
+		goto vreg_err;
+	}
+
+	rc = msm_mdss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
+	if (rc) {
+		pr_err("Clock get failed rc=%d\n", rc);
+		goto clk_err;
+	}
+
+	return rc;
+
+clk_err:
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
+vreg_err:
+	return rc;
+}
+
+/**
+ * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name
+ *@pll_res: Pointer to the PLL resource
+ *@name: Regulator name as specified in the pll dtsi
+ *
+ * This is a helper function to retrieve the regulator information
+ * for each pll resource.
+ */
+struct mdss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
+		, char *name)
+{
+
+	struct mdss_vreg *regulator = NULL;
+	int i;
+
+	if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) {
+		pr_err("%s Invalid PLL resource\n", __func__);
+		goto error;
+	}
+
+	regulator = pll_res->mp.vreg_config;
+
+	for (i = 0; i < pll_res->mp.num_vreg; i++) {
+		if (!strcmp(name, regulator->vreg_name)) {
+			pr_debug("Found regulator match for %s\n", name);
+			break;
+		}
+		regulator++;
+	}
+
+error:
+	return regulator;
+}
+
+void mdss_pll_util_resource_deinit(struct platform_device *pdev,
+					 struct mdss_pll_resources *pll_res)
+{
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	msm_mdss_put_clk(mp->clk_config, mp->num_clk);
+
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
+}
+
+void mdss_pll_util_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	devm_kfree(&pdev->dev, mp->clk_config);
+	devm_kfree(&pdev->dev, mp->vreg_config);
+	mp->num_vreg = 0;
+	mp->num_clk = 0;
+}
+
+int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
+								bool enable)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	if (enable) {
+		rc = msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg,
+					  enable);
+		if (rc) {
+			pr_err("Failed to enable vregs rc=%d\n", rc);
+			goto vreg_err;
+		}
+
+		rc = msm_mdss_clk_set_rate(mp->clk_config, mp->num_clk);
+		if (rc) {
+			pr_err("Failed to set clock rate rc=%d\n", rc);
+			goto clk_err;
+		}
+
+		rc = msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
+		if (rc) {
+			pr_err("clock enable failed rc:%d\n", rc);
+			goto clk_err;
+		}
+	} else {
+		msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
+
+		msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
+	}
+
+	return rc;
+
+clk_err:
+	msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
+vreg_err:
+	return rc;
+}
+
+static int mdss_pll_util_parse_dt_supply(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *of_node = NULL, *supply_root_node = NULL;
+	struct device_node *supply_node = NULL;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	of_node = pdev->dev.of_node;
+
+	mp->num_vreg = 0;
+	supply_root_node = of_get_child_by_name(of_node,
+						"qcom,platform-supply-entries");
+	if (!supply_root_node) {
+		pr_err("no supply entry present\n");
+		return rc;
+	}
+
+	for_each_child_of_node(supply_root_node, supply_node) {
+		mp->num_vreg++;
+	}
+
+	if (mp->num_vreg == 0) {
+		pr_debug("no vreg\n");
+		return rc;
+	}
+	pr_debug("vreg found. count=%d\n", mp->num_vreg);
+
+	mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct mdss_vreg) *
+						mp->num_vreg, GFP_KERNEL);
+	if (!mp->vreg_config) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	for_each_child_of_node(supply_root_node, supply_node) {
+
+		const char *st = NULL;
+
+		rc = of_property_read_string(supply_node,
+						"qcom,supply-name", &st);
+		if (rc) {
+			pr_err(":error reading name. rc=%d\n", rc);
+			goto error;
+		}
+
+		strlcpy(mp->vreg_config[i].vreg_name, st,
+					sizeof(mp->vreg_config[i].vreg_name));
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-min-voltage", &tmp);
+		if (rc) {
+			pr_err(": error reading min volt. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].min_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-max-voltage", &tmp);
+		if (rc) {
+			pr_err(": error reading max volt. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].max_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-enable-load", &tmp);
+		if (rc) {
+			pr_err(": error reading enable load. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-disable-load", &tmp);
+		if (rc) {
+			pr_err(": error reading disable load. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-ulp-load", &tmp);
+		if (rc)
+			pr_warn(": error reading ulp load. rc=%d\n", rc);
+
+		mp->vreg_config[i].load[DSS_REG_MODE_ULP] = (!rc ? tmp :
+			mp->vreg_config[i].load[DSS_REG_MODE_ENABLE]);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-pre-on-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply pre sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-pre-off-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply pre sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-post-on-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply post sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-post-off-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply post sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+		pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, ulp=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+			mp->vreg_config[i].vreg_name,
+			mp->vreg_config[i].min_voltage,
+			mp->vreg_config[i].max_voltage,
+			mp->vreg_config[i].load[DSS_REG_MODE_ENABLE],
+			mp->vreg_config[i].load[DSS_REG_MODE_DISABLE],
+			mp->vreg_config[i].load[DSS_REG_MODE_ULP],
+			mp->vreg_config[i].pre_on_sleep,
+			mp->vreg_config[i].post_on_sleep,
+			mp->vreg_config[i].pre_off_sleep,
+			mp->vreg_config[i].post_off_sleep);
+		++i;
+
+		rc = 0;
+	}
+
+	return rc;
+
+error:
+	if (mp->vreg_config) {
+		devm_kfree(&pdev->dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+		mp->num_vreg = 0;
+	}
+
+	return rc;
+}
+
+static int mdss_pll_util_parse_dt_clock(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	u32 i = 0, rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+	const char *clock_name;
+	u32 clock_rate;
+
+	mp->num_clk = of_property_count_strings(pdev->dev.of_node,
+							"clock-names");
+	if (mp->num_clk <= 0) {
+		pr_err("clocks are not defined\n");
+		goto clk_err;
+	}
+
+	mp->clk_config = devm_kzalloc(&pdev->dev,
+			sizeof(struct mdss_clk) * mp->num_clk, GFP_KERNEL);
+	if (!mp->clk_config) {
+		rc = -ENOMEM;
+		mp->num_clk = 0;
+		goto clk_err;
+	}
+
+	for (i = 0; i < mp->num_clk; i++) {
+		of_property_read_string_index(pdev->dev.of_node, "clock-names",
+							i, &clock_name);
+		strlcpy(mp->clk_config[i].clk_name, clock_name,
+				sizeof(mp->clk_config[i].clk_name));
+
+		of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
+							i, &clock_rate);
+		mp->clk_config[i].rate = clock_rate;
+
+		if (!clock_rate)
+			mp->clk_config[i].type = DSS_CLK_AHB;
+		else
+			mp->clk_config[i].type = DSS_CLK_PCLK;
+	}
+
+clk_err:
+	return rc;
+}
+
+int mdss_pll_util_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	rc = mdss_pll_util_parse_dt_supply(pdev, pll_res);
+	if (rc) {
+		pr_err("vreg parsing failed rc=%d\n", rc);
+		goto end;
+	}
+
+	rc = mdss_pll_util_parse_dt_clock(pdev, pll_res);
+	if (rc) {
+		pr_err("clock name parsing failed rc=%d", rc);
+		goto clk_err;
+	}
+
+	return rc;
+
+clk_err:
+	devm_kfree(&pdev->dev, mp->vreg_config);
+	mp->num_vreg = 0;
+end:
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
new file mode 100644
index 0000000..49f3d7b
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -0,0 +1,439 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-hdmi-pll.h"
+
+int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
+{
+	int rc = 0;
+	int changed = 0;
+
+	if (!pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Don't turn off resources during handoff or add more than
+	 * 1 refcount.
+	 */
+	if (pll_res->handoff_resources &&
+		(!enable || (enable & pll_res->resource_enable))) {
+		pr_debug("Do not turn on/off pll resources during handoff case\n");
+		return rc;
+	}
+
+	if (enable) {
+		if (pll_res->resource_ref_cnt == 0)
+			changed++;
+		pll_res->resource_ref_cnt++;
+	} else {
+		if (pll_res->resource_ref_cnt) {
+			pll_res->resource_ref_cnt--;
+			if (pll_res->resource_ref_cnt == 0)
+				changed++;
+		} else {
+			pr_err("PLL Resources already OFF\n");
+		}
+	}
+
+	if (changed) {
+		rc = mdss_pll_util_resource_enable(pll_res, enable);
+		if (rc)
+			pr_err("Resource update failed rc=%d\n", rc);
+		else
+			pll_res->resource_enable = enable;
+	}
+
+	return rc;
+}
+
+static int mdss_pll_resource_init(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	return mdss_pll_util_resource_init(pdev, pll_res);
+}
+
+static void mdss_pll_resource_deinit(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return;
+	}
+
+	mdss_pll_util_resource_deinit(pdev, pll_res);
+}
+
+static void mdss_pll_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return;
+	}
+
+	mdss_pll_util_resource_release(pdev, pll_res);
+}
+
+static int mdss_pll_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	const char *compatible_stream;
+
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_util_resource_parse(pdev, pll_res);
+	if (rc) {
+		pr_err("Failed to parse the resources rc=%d\n", rc);
+		goto end;
+	}
+
+	compatible_stream = of_get_property(pdev->dev.of_node,
+				"compatible", NULL);
+	if (!compatible_stream) {
+		pr_err("Failed to parse the compatible stream\n");
+		goto err;
+	}
+
+	if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8952")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8952;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8937")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8937;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8909")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8909;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8996;
+		pll_res->revision = 1;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996_v2")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8996;
+		pll_res->revision = 2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8953")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8953;
+		pll_res->revision = 2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v3")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3;
+	} else if (!strcmp(compatible_stream,
+				"qcom,mdss_hdmi_pll_8996_v3_1p8")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3_1_8;
+	} else {
+		goto err;
+	}
+
+	return rc;
+
+err:
+	mdss_pll_resource_release(pdev, pll_res);
+end:
+	return rc;
+}
+
+static int mdss_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc;
+
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	switch (pll_res->pll_interface_type) {
+	case MDSS_DSI_PLL_LPM:
+		rc = dsi_pll_clock_register_lpm(pdev, pll_res);
+		break;
+	case MDSS_DSI_PLL_8996:
+		rc = dsi_pll_clock_register_8996(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996:
+		rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V2:
+		rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V3:
+		rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V3_1_8:
+		rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_UNKNOWN_PLL:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc) {
+		pr_err("Pll ndx=%d clock register failed rc=%d\n",
+				pll_res->index, rc);
+	}
+
+	return rc;
+}
+
+static int mdss_pll_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	const char *label;
+	struct resource *pll_base_reg;
+	struct resource *phy_base_reg;
+	struct resource *dynamic_pll_base_reg;
+	struct resource *gdsc_base_reg;
+	struct mdss_pll_resources *pll_res;
+
+	if (!pdev->dev.of_node) {
+		pr_err("MDSS pll driver only supports device tree probe\n");
+		rc = -ENOTSUPP;
+		goto error;
+	}
+
+	label = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!label)
+		pr_info("%d: MDSS pll label not specified\n", __LINE__);
+	else
+		pr_info("MDSS pll label = %s\n", label);
+
+	pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources),
+								GFP_KERNEL);
+	if (!pll_res) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	platform_set_drvdata(pdev, pll_res);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
+			&pll_res->index);
+	if (rc) {
+		pr_err("Unable to get the cell-index rc=%d\n", rc);
+		pll_res->index = 0;
+	}
+
+	pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
+						"qcom,dsi-pll-ssc-en");
+
+	if (pll_res->ssc_en) {
+		pr_info("%s: label=%s PLL SSC enabled\n", __func__, label);
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+			"qcom,ssc-frequency-hz", &pll_res->ssc_freq);
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+			"qcom,ssc-ppm", &pll_res->ssc_ppm);
+
+		pll_res->ssc_center = false;
+
+		label = of_get_property(pdev->dev.of_node,
+			"qcom,dsi-pll-ssc-mode", NULL);
+
+		if (label && !strcmp(label, "center-spread"))
+			pll_res->ssc_center = true;
+	}
+
+	pll_base_reg = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "pll_base");
+	if (!pll_base_reg) {
+		pr_err("Unable to get the pll base resources\n");
+		rc = -ENOMEM;
+		goto io_error;
+	}
+
+	pll_res->pll_base = ioremap(pll_base_reg->start,
+						resource_size(pll_base_reg));
+	if (!pll_res->pll_base) {
+		pr_err("Unable to remap pll base resources\n");
+		rc = -ENOMEM;
+		goto io_error;
+	}
+
+	pr_debug("%s: ndx=%d base=%p\n", __func__,
+			pll_res->index, pll_res->pll_base);
+
+	rc = mdss_pll_resource_parse(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll resource parsing from dt failed rc=%d\n", rc);
+		goto res_parse_error;
+	}
+
+	phy_base_reg = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "phy_base");
+	if (phy_base_reg) {
+		pll_res->phy_base = ioremap(phy_base_reg->start,
+						resource_size(phy_base_reg));
+		if (!pll_res->phy_base) {
+			pr_err("Unable to remap pll phy base resources\n");
+			rc = -ENOMEM;
+			goto phy_io_error;
+		}
+	}
+
+	dynamic_pll_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "dynamic_pll_base");
+	if (dynamic_pll_base_reg) {
+		pll_res->dyn_pll_base = ioremap(dynamic_pll_base_reg->start,
+				resource_size(dynamic_pll_base_reg));
+		if (!pll_res->dyn_pll_base) {
+			pr_err("Unable to remap dynamic pll base resources\n");
+			rc = -ENOMEM;
+			goto dyn_pll_io_error;
+		}
+	}
+
+	gdsc_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "gdsc_base");
+	if (!gdsc_base_reg) {
+		pr_err("Unable to get the gdsc base resource\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+	pll_res->gdsc_base = ioremap(gdsc_base_reg->start,
+			resource_size(gdsc_base_reg));
+	if (!pll_res->gdsc_base) {
+		pr_err("Unable to remap gdsc base resources\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+
+	rc = mdss_pll_resource_init(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll ndx=%d resource init failed rc=%d\n",
+				pll_res->index, rc);
+		goto res_init_error;
+	}
+
+	rc = mdss_pll_clock_register(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll ndx=%d clock register failed rc=%d\n",
+			pll_res->index, rc);
+		goto clock_register_error;
+	}
+
+	return rc;
+
+clock_register_error:
+	mdss_pll_resource_deinit(pdev, pll_res);
+res_init_error:
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
+gdsc_io_error:
+	if (pll_res->dyn_pll_base)
+		iounmap(pll_res->dyn_pll_base);
+dyn_pll_io_error:
+	if (pll_res->phy_base)
+		iounmap(pll_res->phy_base);
+phy_io_error:
+	mdss_pll_resource_release(pdev, pll_res);
+res_parse_error:
+	iounmap(pll_res->pll_base);
+io_error:
+	devm_kfree(&pdev->dev, pll_res);
+error:
+	return rc;
+}
+
+static int mdss_pll_remove(struct platform_device *pdev)
+{
+	struct mdss_pll_resources *pll_res;
+
+	pll_res = platform_get_drvdata(pdev);
+	if (!pll_res) {
+		pr_err("Invalid PLL resource data");
+		return 0;
+	}
+
+	mdss_pll_resource_deinit(pdev, pll_res);
+	if (pll_res->phy_base)
+		iounmap(pll_res->phy_base);
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
+	mdss_pll_resource_release(pdev, pll_res);
+	iounmap(pll_res->pll_base);
+	devm_kfree(&pdev->dev, pll_res);
+	return 0;
+}
+
+static const struct of_device_id mdss_pll_dt_match[] = {
+	{.compatible = "qcom,mdss_dsi_pll_8996"},
+	{.compatible = "qcom,mdss_dsi_pll_8996_v2"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v2"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v3"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
+	{.compatible = "qcom,mdss_dsi_pll_8952"},
+	{.compatible = "qcom,mdss_dsi_pll_8937"},
+	{.compatible = "qcom,mdss_dsi_pll_8909"},
+	{.compatible = "qcom,mdss_dsi_pll_8953"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mdss_clock_dt_match);
+
+static struct platform_driver mdss_pll_driver = {
+	.probe = mdss_pll_probe,
+	.remove = mdss_pll_remove,
+	.driver = {
+		.name = "mdss_pll",
+		.of_match_table = mdss_pll_dt_match,
+	},
+};
+
+static int __init mdss_pll_driver_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&mdss_pll_driver);
+	if (rc)
+		pr_err("mdss_register_pll_driver() failed!\n");
+
+	return rc;
+}
+subsys_initcall(mdss_pll_driver_init);
+
+static void __exit mdss_pll_driver_deinit(void)
+{
+	platform_driver_unregister(&mdss_pll_driver);
+}
+module_exit(mdss_pll_driver_deinit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdss pll driver");
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
new file mode 100644
index 0000000..1fa5cff
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -0,0 +1,197 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDSS_PLL_H
+#define __MDSS_PLL_H
+
+#include <linux/mdss_io_util.h>
+#include <linux/io.h>
+
+#define MDSS_PLL_REG_W(base, offset, data)	\
+				writel_relaxed((data), (base) + (offset))
+#define MDSS_PLL_REG_R(base, offset)	readl_relaxed((base) + (offset))
+
+#define PLL_CALC_DATA(addr0, addr1, data0, data1)      \
+	(((data1) << 24) | ((((addr1) / 4) & 0xFF) << 16) | \
+	 ((data0) << 8) | (((addr0) / 4) & 0xFF))
+
+#define MDSS_DYN_PLL_REG_W(base, offset, addr0, addr1, data0, data1)   \
+		writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
+			(base) + (offset))
+
+enum {
+	MDSS_DSI_PLL_LPM,
+	MDSS_DSI_PLL_8996,
+	MDSS_HDMI_PLL_8996,
+	MDSS_HDMI_PLL_8996_V2,
+	MDSS_HDMI_PLL_8996_V3,
+	MDSS_HDMI_PLL_8996_V3_1_8,
+	MDSS_UNKNOWN_PLL,
+};
+
+enum {
+	MDSS_PLL_TARGET_8996,
+	MDSS_PLL_TARGET_8952,
+	MDSS_PLL_TARGET_8937,
+	MDSS_PLL_TARGET_8953,
+	MDSS_PLL_TARGET_8909,
+};
+
+struct mdss_pll_resources {
+
+	/* Pll specific resources like GPIO, power supply, clocks, etc*/
+	struct mdss_module_power mp;
+
+	/*
+	 * dsi/edp/hmdi plls' base register, phy, gdsc and dynamic refresh
+	 * register mapping
+	 */
+	void __iomem	*pll_base;
+	void __iomem	*phy_base;
+	void __iomem	*gdsc_base;
+	void __iomem	*dyn_pll_base;
+
+	bool	is_init_locked;
+	s64	vco_current_rate;
+	s64	vco_locking_rate;
+	s64	vco_ref_clk_rate;
+
+	/*
+	 * Certain pll's needs to update the same vco rate after resume in
+	 * suspend/resume scenario. Cached the vco rate for such plls.
+	 */
+	unsigned long	vco_cached_rate;
+
+	/* dsi/edp/hmdi pll interface type */
+	u32		pll_interface_type;
+
+	/*
+	 * Target ID. Used in pll_register API for valid target check before
+	 * registering the PLL clocks.
+	 */
+	u32		target_id;
+
+	/* HW recommended delay during configuration of vco clock rate */
+	u32		vco_delay;
+
+	/* Ref-count of the PLL resources */
+	u32		resource_ref_cnt;
+
+	/*
+	 * Keep track to resource status to avoid updating same status for the
+	 * pll from different paths
+	 */
+	bool		resource_enable;
+
+	/*
+	 * Certain plls' do not allow vco rate update if it is on. Keep track of
+	 * status for them to turn on/off after set rate success.
+	 */
+	bool		pll_on;
+
+	/*
+	 * handoff_status is true of pll is already enabled by bootloader with
+	 * continuous splash enable case. Clock API will call the handoff API
+	 * to enable the status. It is disabled if continuous splash
+	 * feature is disabled.
+	 */
+	bool		handoff_resources;
+
+	/*
+	 * caching the pll trim codes in the case of dynamic refresh
+	 * or cmd mode idle screen.
+	 */
+	int		cache_pll_trim_codes[2];
+
+	/*
+	 * caching the pll trim codes rate
+	 */
+	s64		cache_pll_trim_codes_rate;
+
+	/*
+	 * for maintaining the status of saving trim codes
+	 */
+	bool		reg_upd;
+
+	/*
+	 * Notifier callback for MDSS gdsc regulator events
+	 */
+	struct notifier_block gdsc_cb;
+
+	/*
+	 * Worker function to call PLL off event
+	 */
+	struct work_struct pll_off;
+
+	/*
+	 * PLL index if multiple index are available. Eg. in case of
+	 * DSI we have 2 plls.
+	 */
+	uint32_t index;
+
+	bool ssc_en;	/* share pll with master */
+	bool ssc_center;	/* default is down spread */
+	u32 ssc_freq;
+	u32 ssc_ppm;
+
+	struct mdss_pll_resources *slave;
+
+	/*
+	 * target pll revision information
+	 */
+	int		revision;
+
+	void *priv;
+
+	/*
+	 * dynamic refresh pll codes stored in this structure
+	 */
+	struct dfps_info *dfps;
+
+};
+
+struct mdss_pll_vco_calc {
+	s32 div_frac_start1;
+	s32 div_frac_start2;
+	s32 div_frac_start3;
+	s64 dec_start1;
+	s64 dec_start2;
+	s64 pll_plllock_cmp1;
+	s64 pll_plllock_cmp2;
+	s64 pll_plllock_cmp3;
+};
+
+static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res)
+{
+	if (!pll_res->gdsc_base) {
+		WARN(1, "gdsc_base register is not defined\n");
+		return true;
+	}
+
+	return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
+		(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
+}
+
+int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable);
+int mdss_pll_util_resource_init(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res);
+void mdss_pll_util_resource_deinit(struct platform_device *pdev,
+					 struct mdss_pll_resources *pll_res);
+void mdss_pll_util_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res);
+int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
+								bool enable);
+int mdss_pll_util_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+struct mdss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
+		, char *name);
+#endif
diff --git a/drivers/clk/msm/vdd-level-9650.h b/drivers/clk/msm/vdd-level-9650.h
new file mode 100644
index 0000000..d8f95b0
--- /dev/null
+++ b/drivers/clk/msm/vdd-level-9650.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_9650_H
+#define __DRIVERS_CLK_QCOM_VDD_LEVEL_9650_H
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <linux/regulator/consumer.h>
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+		[VDD_DIG_##l4] = (f4),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig_ao,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_GPU_PLL_FMAX_MAP2(l1, f1, l2, f2)	\
+	.vdd_class = &vdd_gpucc_mx,		\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_GPU_PLL_FMAX_MAP3(l1, f1, l2, f2, l3, f3)	\
+	.vdd_class = &vdd_gpucc_mx,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {		\
+		[VDD_DIG_##l1] = (f1),			\
+		[VDD_DIG_##l2] = (f2),			\
+		[VDD_DIG_##l3] = (f3),			\
+	},						\
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_MIN,		/* MIN SVS */
+	VDD_DIG_LOWER,		/* SVS2 */
+	VDD_DIG_LOW,		/* SVS */
+	VDD_DIG_NOMINAL,	/* NOM */
+	VDD_DIG_HIGH,		/* TURBO */
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_LEVEL_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_LEVEL_MIN_SVS,		/* VDD_DIG_MIN */
+	RPM_REGULATOR_LEVEL_LOW_SVS,		/* VDD_DIG_LOWER */
+	RPM_REGULATOR_LEVEL_SVS,		/* VDD_DIG_LOW */
+	RPM_REGULATOR_LEVEL_NOM,		/* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_LEVEL_TURBO,		/* VDD_DIG_HIGH */
+};
+
+#endif
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 87d067a..79739bc 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -252,4 +252,13 @@
 	Say Y if you want to support CPU clock scaling using
 	CPUfreq drivers for dyanmic power management.
 
+config MDM_DEBUGCC_SDXPOORWILLS
+	tristate "SDXPOORWILLS Debug Clock Controller"
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the debug clock controller on sdxpoorwills
+	  based devices.
+	  Say Y if you want to support the clock measurement
+	  functionality.
+
 source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 8cb46a7..0cd2e94 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
 obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
 obj-$(CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS) += clk-cpu-a7.o
+obj-$(CONFIG_MDM_DEBUGCC_SDXPOORWILLS) += debugcc-sdxpoorwills.o
 obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o
 obj-$(CONFIG_MDM_GCC_SDXPOORWILLS) += gcc-sdxpoorwills.o
 obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index b6204cb..f53d1ee 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -31,6 +31,7 @@
 #include <linux/sched.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 #include <dt-bindings/clock/qcom,cpucc-sdm845.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
@@ -47,6 +48,7 @@
 #define MAX_CLUSTER_CNT			3
 #define MAX_MEM_ACC_VAL_PER_LEVEL	3
 #define CORE_COUNT_VAL(val)		((val & GENMASK(18, 16)) >> 16)
+#define CURRENT_LVAL(val)		((val & GENMASK(23, 16)) >> 16)
 
 #define OSM_REG_SIZE			32
 
@@ -54,6 +56,7 @@
 #define FREQ_REG			0x110
 #define VOLT_REG			0x114
 #define CORE_DCVS_CTRL			0xbc
+#define PSTATE_STATUS			0x700
 
 #define DCVS_PERF_STATE_DESIRED_REG_0_V1	0x780
 #define DCVS_PERF_STATE_DESIRED_REG_0_V2	0x920
@@ -74,6 +77,7 @@
 	u16 virtual_corner;
 	u16 open_loop_volt;
 	long frequency;
+	u32 lval;
 	u16 ccount;
 };
 
@@ -205,7 +209,7 @@
 	struct clk_osm *c = to_clk_osm(hw);
 	struct clk_hw *p_hw = clk_hw_get_parent(hw);
 	struct clk_osm *parent = to_clk_osm(p_hw);
-	int index = 0;
+	int core_num, index = 0;
 
 	if (!c || !parent)
 		return -EINVAL;
@@ -217,8 +221,9 @@
 		return -EINVAL;
 	}
 
+	core_num = parent->per_core_dcvs ? c->core_num : 0;
 	clk_osm_write_reg(parent, index,
-				DCVS_PERF_STATE_DESIRED_REG(c->core_num,
+				DCVS_PERF_STATE_DESIRED_REG(core_num,
 							is_sdm845v1));
 
 	/* Make sure the write goes through before proceeding */
@@ -227,19 +232,52 @@
 	return 0;
 }
 
+static int clk_pwrcl_set_rate(struct clk_hw *hw, unsigned long rate,
+						unsigned long parent_rate)
+{
+	struct clk_hw *p_hw = clk_hw_get_parent(hw);
+	struct clk_osm *parent = to_clk_osm(p_hw);
+	int ret, index = 0, count = 40;
+	u32 curr_lval;
+
+	ret = clk_cpu_set_rate(hw, rate, parent_rate);
+	if (ret)
+		return ret;
+
+	index = clk_osm_search_table(parent->osm_table,
+					parent->num_entries, rate);
+	if (index < 0)
+		return -EINVAL;
+
+	/*
+	 * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to
+	 * check if the L_VAL has been updated.
+	 */
+	while (count-- > 0) {
+		curr_lval = CURRENT_LVAL(clk_osm_read_reg(parent,
+								PSTATE_STATUS));
+		if (curr_lval <= parent->osm_table[index].lval)
+			return 0;
+		udelay(50);
+	}
+	pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
+	return -ETIMEDOUT;
+}
+
 static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
 					unsigned long parent_rate)
 {
 	struct clk_osm *c = to_clk_osm(hw);
 	struct clk_hw *p_hw = clk_hw_get_parent(hw);
 	struct clk_osm *parent = to_clk_osm(p_hw);
-	int index = 0;
+	int core_num, index = 0;
 
 	if (!c || !parent)
 		return -EINVAL;
 
+	core_num = parent->per_core_dcvs ? c->core_num : 0;
 	index = clk_osm_read_reg(parent,
-				DCVS_PERF_STATE_DESIRED_REG(c->core_num,
+				DCVS_PERF_STATE_DESIRED_REG(core_num,
 							is_sdm845v1));
 	return parent->osm_table[index].frequency;
 }
@@ -262,6 +300,8 @@
 	struct clk_osm *cpuclk = to_clk_osm(hw);
 	int index = 0;
 	unsigned long r_rate;
+	int count = 40;
+	u32 curr_lval;
 
 	if (!cpuclk)
 		return -EINVAL;
@@ -288,6 +328,25 @@
 	/* Make sure the write goes through before proceeding */
 	clk_osm_mb(cpuclk);
 
+	/*
+	 * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to
+	 * check if the L_VAL has been updated.
+	 */
+	if (cpuclk->rate >= cpuclk->mx_turbo_freq &&
+					rate < cpuclk->mx_turbo_freq) {
+		while (count-- > 0) {
+			curr_lval = CURRENT_LVAL(clk_osm_read_reg(cpuclk,
+								PSTATE_STATUS));
+			if (curr_lval <= cpuclk->osm_table[index].lval) {
+				cpuclk->rate = rate;
+				return 0;
+			}
+			udelay(50);
+		}
+		pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
+		return -ETIMEDOUT;
+	}
+	cpuclk->rate = rate;
 	return 0;
 }
 
@@ -318,7 +377,14 @@
 	.debug_init = clk_debug_measure_add,
 };
 
-static const struct clk_ops clk_ops_core = {
+static const struct clk_ops clk_ops_pwrcl_core = {
+	.set_rate = clk_pwrcl_set_rate,
+	.round_rate = clk_cpu_round_rate,
+	.recalc_rate = clk_cpu_recalc_rate,
+	.debug_init = clk_debug_measure_add,
+};
+
+static const struct clk_ops clk_ops_perfcl_core = {
 	.set_rate = clk_cpu_set_rate,
 	.round_rate = clk_cpu_round_rate,
 	.recalc_rate = clk_cpu_recalc_rate,
@@ -338,6 +404,7 @@
 		.name = "l3_clk",
 		.parent_names = (const char *[]){ "bi_tcxo_ao" },
 		.num_parents = 1,
+		.flags = CLK_CHILD_NO_RATE_PROP,
 		.ops = &clk_ops_l3_osm,
 		.vdd_class = &vdd_l3_mx_ao,
 	},
@@ -365,6 +432,7 @@
 static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0);
 static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0);
 static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0);
+static DEFINE_CLK_VOTER(l3_gpu_vote_clk, l3_clk, 0);
 
 static struct clk_osm pwrcl_clk = {
 	.cluster_num = 1,
@@ -381,7 +449,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -394,7 +462,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -407,7 +475,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -420,7 +488,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -433,7 +501,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -446,7 +514,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -466,7 +534,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -479,7 +547,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -492,7 +560,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -505,7 +573,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -514,6 +582,7 @@
 	[L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw,
 	[L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw,
 	[L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw,
+	[L3_GPU_VOTE_CLK] = &l3_gpu_vote_clk.hw,
 	[PWRCL_CLK] = &pwrcl_clk.hw,
 	[CPU0_PWRCL_CLK] = &cpu0_pwrcl_clk.hw,
 	[CPU1_PWRCL_CLK] = &cpu1_pwrcl_clk.hw,
@@ -974,6 +1043,7 @@
 		src = ((data & GENMASK(31, 30)) >> 30);
 		lval = (data & GENMASK(7, 0));
 		c->osm_table[i].ccount = CORE_COUNT_VAL(data);
+		c->osm_table[i].lval = lval;
 
 		if (!src)
 			c->osm_table[i].frequency = OSM_INIT_RATE;
@@ -1277,6 +1347,8 @@
 			"clk: Failed to enable cluster1 clock for L3\n");
 	WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk),
 			"clk: Failed to enable misc clock for L3\n");
+	WARN(clk_prepare_enable(l3_gpu_vote_clk.hw.clk),
+			"clk: Failed to enable iocoherent bwmon clock for L3\n");
 
 	/*
 	 * Call clk_prepare_enable for the silver clock explicitly in order to
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
index d366ad4..d101536 100644
--- a/drivers/clk/qcom/clk-debug.c
+++ b/drivers/clk/qcom/clk-debug.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -275,7 +275,7 @@
 	if (clk_set_parent(measure->clk, hw->clk))
 		return 0;
 
-	debugfs_create_file("clk_measure", 0x444, dentry, hw,
+	debugfs_create_file("clk_measure", 0444, dentry, hw,
 					&clk_measure_fops);
 	return 0;
 }
diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h
index aa8d97b..a9f71b4 100644
--- a/drivers/clk/qcom/clk-debug.h
+++ b/drivers/clk/qcom/clk-debug.h
@@ -44,6 +44,7 @@
 	GPU_CC,
 	VIDEO_CC,
 	CPU,
+	MAX_NUM_CC,
 };
 
 /**
diff --git a/drivers/clk/qcom/debugcc-sdxpoorwills.c b/drivers/clk/qcom/debugcc-sdxpoorwills.c
new file mode 100644
index 0000000..d66a623
--- /dev/null
+++ b/drivers/clk/qcom/debugcc-sdxpoorwills.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-debug.h"
+
+static struct measure_clk_data debug_mux_priv = {
+	.ctl_reg = 0x79004,
+	.status_reg = 0x79008,
+	.xo_div4_cbcr = 0x22008,
+};
+
+static const char *const debug_mux_parent_names[] = {
+	"gcc_blsp1_ahb_clk",
+	"gcc_blsp1_qup1_i2c_apps_clk",
+	"gcc_blsp1_qup1_spi_apps_clk",
+	"gcc_blsp1_qup2_i2c_apps_clk",
+	"gcc_blsp1_qup2_spi_apps_clk",
+	"gcc_blsp1_qup3_i2c_apps_clk",
+	"gcc_blsp1_qup3_spi_apps_clk",
+	"gcc_blsp1_qup4_i2c_apps_clk",
+	"gcc_blsp1_qup4_spi_apps_clk",
+	"gcc_blsp1_sleep_clk",
+	"gcc_blsp1_uart1_apps_clk",
+	"gcc_blsp1_uart2_apps_clk",
+	"gcc_blsp1_uart3_apps_clk",
+	"gcc_blsp1_uart4_apps_clk",
+	"gcc_boot_rom_ahb_clk",
+	"gcc_ce1_ahb_clk",
+	"gcc_ce1_axi_clk",
+	"gcc_ce1_clk",
+	"gcc_cpuss_ahb_clk",
+	"gcc_cpuss_gnoc_clk",
+	"gcc_cpuss_rbcpr_clk",
+	"gcc_eth_axi_clk",
+	"gcc_eth_ptp_clk",
+	"gcc_eth_rgmii_clk",
+	"gcc_eth_slave_ahb_clk",
+	"gcc_gp1_clk",
+	"gcc_gp2_clk",
+	"gcc_gp3_clk",
+	"gcc_pcie_aux_clk",
+	"gcc_pcie_cfg_ahb_clk",
+	"gcc_pcie_mstr_axi_clk",
+	"gcc_pcie_phy_refgen_clk",
+	"gcc_pcie_pipe_clk",
+	"gcc_pcie_sleep_clk",
+	"gcc_pcie_slv_axi_clk",
+	"gcc_pcie_slv_q2a_axi_clk",
+	"gcc_pdm2_clk",
+	"gcc_pdm_ahb_clk",
+	"gcc_pdm_xo4_clk",
+	"gcc_prng_ahb_clk",
+	"gcc_sdcc1_ahb_clk",
+	"gcc_sdcc1_apps_clk",
+	"gcc_spmi_fetcher_ahb_clk",
+	"gcc_spmi_fetcher_clk",
+	"gcc_sys_noc_cpuss_ahb_clk",
+	"gcc_sys_noc_usb3_clk",
+	"gcc_usb30_master_clk",
+	"gcc_usb30_mock_utmi_clk",
+	"gcc_usb30_sleep_clk",
+	"gcc_usb3_phy_aux_clk",
+	"gcc_usb3_phy_pipe_clk",
+	"gcc_usb_phy_cfg_ahb2phy_clk",
+	"gcc_xo_div4_clk",
+	"measure_only_ipa_2x_clk",
+};
+
+static struct clk_debug_mux gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.debug_offset = 0x79000,
+	.post_div_offset = 0x29000,
+	.cbcr_offset = 0x29004,
+	.src_sel_mask = 0x3FF,
+	.src_sel_shift = 0,
+	.post_div_mask = 0xF,
+	.post_div_shift = 0,
+	MUX_SRC_LIST(
+		{ "gcc_blsp1_ahb_clk", 0x34, 4, GCC,
+			0x34, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup1_i2c_apps_clk", 0x37, 4, GCC,
+			0x37, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup1_spi_apps_clk", 0x36, 4, GCC,
+			0x36, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup2_i2c_apps_clk", 0x3B, 4, GCC,
+			0x3B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup2_spi_apps_clk", 0x3A, 4, GCC,
+			0x3A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup3_i2c_apps_clk", 0x3F, 4, GCC,
+			0x3F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup3_spi_apps_clk", 0x3E, 4, GCC,
+			0x3E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup4_i2c_apps_clk", 0x43, 4, GCC,
+			0x43, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_qup4_spi_apps_clk", 0x42, 4, GCC,
+			0x42, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_sleep_clk", 0x35, 4, GCC,
+			0x35, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_uart1_apps_clk", 0x38, 4, GCC,
+			0x38, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_uart2_apps_clk", 0x3C, 4, GCC,
+			0x3C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_uart3_apps_clk", 0x40, 4, GCC,
+			0x40, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_blsp1_uart4_apps_clk", 0x44, 4, GCC,
+			0x44, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_boot_rom_ahb_clk", 0x4B, 4, GCC,
+			0x4B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_ce1_ahb_clk", 0x60, 4, GCC,
+			0x60, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_ce1_axi_clk", 0x5F, 4, GCC,
+			0x5F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_ce1_clk", 0x5E, 4, GCC,
+			0x5E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_cpuss_ahb_clk", 0x74, 4, GCC,
+			0x74, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_cpuss_gnoc_clk", 0x75, 4, GCC,
+			0x75, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_cpuss_rbcpr_clk", 0x76, 4, GCC,
+			0x76, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_eth_axi_clk", 0xCB, 4, GCC,
+			0xCB, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_eth_ptp_clk", 0xFD, 4, GCC,
+			0xFD, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_eth_rgmii_clk", 0xC9, 4, GCC,
+			0xC9, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_eth_slave_ahb_clk", 0xCA, 4, GCC,
+			0xCA, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_gp1_clk", 0x85, 4, GCC,
+			0x85, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_gp2_clk", 0x86, 4, GCC,
+			0x86, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_gp3_clk", 0x87, 4, GCC,
+			0x87, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_aux_clk", 0x99, 4, GCC,
+			0x99, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_cfg_ahb_clk", 0x98, 4, GCC,
+			0x98, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_mstr_axi_clk", 0x97, 4, GCC,
+			0x97, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_phy_refgen_clk", 0x104, 4, GCC,
+			0x104, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_pipe_clk", 0x9A, 4, GCC,
+			0x9A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_sleep_clk", 0x9C, 4, GCC,
+			0x9C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_slv_axi_clk", 0x96, 4, GCC,
+			0x96, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pcie_slv_q2a_axi_clk", 0x95, 4, GCC,
+			0x95, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pdm2_clk", 0x48, 4, GCC,
+			0x48, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pdm_ahb_clk", 0x46, 4, GCC,
+			0x46, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_pdm_xo4_clk", 0x47, 4, GCC,
+			0x47, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_prng_ahb_clk", 0x49, 4, GCC,
+			0x49, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_sdcc1_ahb_clk", 0x33, 4, GCC,
+			0x33, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_sdcc1_apps_clk", 0x32, 4, GCC,
+			0x32, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_spmi_fetcher_ahb_clk", 0xB5, 4, GCC,
+			0xB5, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_spmi_fetcher_clk", 0xB4, 4, GCC,
+			0xB4, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_sys_noc_cpuss_ahb_clk", 0x10B, 4, GCC,
+			0x10B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_sys_noc_usb3_clk", 0xB, 4, GCC,
+			0xB, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb30_master_clk", 0x28, 4, GCC,
+			0x28, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb30_mock_utmi_clk", 0x2A, 4, GCC,
+			0x2A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb30_sleep_clk", 0x29, 4, GCC,
+			0x29, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb3_phy_aux_clk", 0x2B, 4, GCC,
+			0x2B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb3_phy_pipe_clk", 0x2D, 4, GCC,
+			0x2D, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_usb_phy_cfg_ahb2phy_clk", 0x31, 4, GCC,
+			0x31, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "gcc_xo_div4_clk", 0x63, 4, GCC,
+			0x63, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+		{ "measure_only_ipa_2x_clk", 0xAC, 4, GCC,
+			0xAC, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 },
+	),
+	.hw.init = &(struct clk_init_data){
+		.name = "gcc_debug_mux",
+		.ops = &clk_debug_mux_ops,
+		.parent_names = debug_mux_parent_names,
+		.num_parents = ARRAY_SIZE(debug_mux_parent_names),
+		.flags = CLK_IS_MEASURE,
+	},
+};
+
+static const struct of_device_id clk_debug_match_table[] = {
+	{ .compatible = "qcom,debugcc-sdxpoorwills" },
+	{ }
+};
+
+static int clk_debug_sdxpoorwills_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	int ret = 0;
+
+	clk = devm_clk_get(&pdev->dev, "xo_clk_src");
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Unable to get xo clock\n");
+		return PTR_ERR(clk);
+	}
+
+	debug_mux_priv.cxo = clk;
+
+	gcc_debug_mux.regmap = devm_kcalloc(&pdev->dev, MAX_NUM_CC,
+				sizeof(*gcc_debug_mux.regmap), GFP_KERNEL);
+	if (!gcc_debug_mux.regmap)
+		return -ENOMEM;
+
+	if (!of_get_property(pdev->dev.of_node, "qcom,gcc", NULL))
+		return -ENODEV;
+
+	gcc_debug_mux.regmap[GCC] =
+		syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,gcc");
+	if (IS_ERR(gcc_debug_mux.regmap[GCC])) {
+		pr_err("Failed to map qcom,gcc\n");
+		return PTR_ERR(gcc_debug_mux.regmap[GCC]);
+	}
+
+	clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Unable to register GCC debug mux\n");
+		return PTR_ERR(clk);
+	}
+
+	ret = clk_debug_measure_register(&gcc_debug_mux.hw);
+	if (ret)
+		dev_err(&pdev->dev, "Could not register Measure clock\n");
+
+	return ret;
+}
+
+static struct platform_driver clk_debug_driver = {
+	.probe = clk_debug_sdxpoorwills_probe,
+	.driver = {
+		.name = "debugcc-sdxpoorwills",
+		.of_match_table = clk_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clk_debug_sdxpoorwills_init(void)
+{
+	return platform_driver_register(&clk_debug_driver);
+}
+fs_initcall(clk_debug_sdxpoorwills_init);
+
+MODULE_DESCRIPTION("QTI DEBUG CC SDXPOORWILLS Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:debugcc-sdxpoorwills");
diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c
index c6e8faa..4050683 100644
--- a/drivers/clk/qcom/gcc-sdxpoorwills.c
+++ b/drivers/clk/qcom/gcc-sdxpoorwills.c
@@ -1711,6 +1711,19 @@
 	},
 };
 
+/* Measure-only clock for gcc_ipa_2x_clk. */
+static struct clk_dummy measure_only_ipa_2x_clk = {
+	.rrate = 1000,
+	.hw.init = &(struct clk_init_data){
+		.name = "measure_only_ipa_2x_clk",
+		.ops = &clk_dummy_ops,
+	},
+};
+
+static struct clk_hw *gcc_sdxpoorwills_hws[] = {
+	[MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw,
+};
+
 static struct clk_regmap *gcc_sdxpoorwills_clocks[] = {
 	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
 	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
@@ -1826,6 +1839,7 @@
 	[GCC_USB30_BCR] = { 0xb000 },
 	[GCC_USB3_PHY_BCR] = { 0xc000 },
 	[GCC_USB3PHY_PHY_BCR] = { 0xc004 },
+	[GCC_QUSB2PHY_BCR] = { 0xd000 },
 	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 },
 };
 
@@ -1854,7 +1868,8 @@
 
 static int gcc_sdxpoorwills_probe(struct platform_device *pdev)
 {
-	int ret = 0;
+	int i, ret = 0;
+	struct clk *clk;
 	struct regmap *regmap;
 
 	regmap = qcom_cc_map(pdev, &gcc_sdxpoorwills_desc);
@@ -1869,6 +1884,13 @@
 		return PTR_ERR(vdd_cx.regulator[0]);
 	}
 
+	/* Register the dummy measurement clocks */
+	for (i = 0; i < ARRAY_SIZE(gcc_sdxpoorwills_hws); i++) {
+		clk = devm_clk_register(&pdev->dev, gcc_sdxpoorwills_hws[i]);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+	}
+
 	ret = qcom_cc_really_probe(pdev, &gcc_sdxpoorwills_desc, regmap);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register GCC clocks\n");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 3f9fcd9..874c229 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,8 @@
 #include "mdss-dsi-pll.h"
 #include "mdss-pll.h"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+#define CREATE_TRACE_POINTS
+#include "mdss_pll_trace.h"
 
 #define VCO_DELAY_USEC 1
 
@@ -890,8 +892,13 @@
 		MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE,
 					pll->cached_outdiv);
 	}
-
+	MDSS_PLL_ATRACE_BEGIN("pll_lock");
+	trace_mdss_pll_lock_start((u64)pll->vco_cached_rate,
+			pll->vco_current_rate,
+			pll->cached_cfg0, pll->cached_cfg1,
+			pll->cached_outdiv, pll->resource_ref_cnt);
 	rc = dsi_pll_enable(vco);
+	MDSS_PLL_ATRACE_END("pll_lock");
 	if (rc) {
 		mdss_pll_resource_enable(pll, false);
 		pr_err("pll(%d) enable failed, rc=%d\n", pll->index, rc);
@@ -918,6 +925,11 @@
 	if (!vco->priv)
 		pr_err("vco priv is null\n");
 
+	if (!pll) {
+		pr_err("pll is null\n");
+		return 0;
+	}
+
 	/*
 	 * Calculate the vco rate from HW registers only for handoff cases.
 	 * For other cases where a vco_10nm_set_rate() has already been
diff --git a/drivers/clk/qcom/mdss/mdss_pll_trace.h b/drivers/clk/qcom/mdss/mdss_pll_trace.h
new file mode 100644
index 0000000..cd4fda6
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss_pll_trace.h
@@ -0,0 +1,116 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#if !defined(_MDSS_PLL_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MDSS_PLL_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mdss_pll
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mdss_pll_trace
+
+
+TRACE_EVENT(mdss_pll_lock_start,
+	TP_PROTO(
+			u64 vco_cached_rate,
+			s64 vco_current_rate,
+			u32 cached_cfg0,
+			u32 cached_cfg1,
+			u32 cached_outdiv,
+			u32 resource_ref_cnt),
+	TP_ARGS(
+			vco_cached_rate,
+			vco_current_rate,
+			cached_cfg0,
+			cached_cfg1,
+			cached_outdiv,
+			resource_ref_cnt),
+	TP_STRUCT__entry(
+			__field(u64, vco_cached_rate)
+			__field(s64, vco_current_rate)
+			__field(u32, cached_cfg0)
+			__field(u32, cached_cfg1)
+			__field(u32, cached_outdiv)
+			__field(u32, resource_ref_cnt)
+
+	),
+	TP_fast_assign(
+			__entry->vco_cached_rate = vco_cached_rate;
+			__entry->vco_current_rate = vco_current_rate;
+			__entry->cached_cfg0 = cached_cfg0;
+			__entry->cached_cfg1 = cached_cfg1;
+			__entry->cached_outdiv = cached_outdiv;
+			__entry->resource_ref_cnt = resource_ref_cnt;
+	),
+	 TP_printk(
+		"vco_cached_rate=%llu vco_current_rate=%lld cached_cfg0=%d cached_cfg1=%d cached_outdiv=%d resource_ref_cnt=%d",
+			__entry->vco_cached_rate,
+			__entry->vco_current_rate,
+			__entry->cached_cfg0,
+			__entry->cached_cfg1,
+			__entry->cached_outdiv,
+			__entry->resource_ref_cnt)
+);
+
+TRACE_EVENT(pll_tracing_mark_write,
+	TP_PROTO(int pid, const char *name, bool trace_begin),
+	TP_ARGS(pid, name, trace_begin),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(trace_name, name)
+			__field(bool, trace_begin)
+	),
+	TP_fast_assign(
+			__entry->pid = pid;
+			__assign_str(trace_name, name);
+			__entry->trace_begin = trace_begin;
+	),
+	TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E",
+		__entry->pid, __get_str(trace_name))
+)
+
+TRACE_EVENT(mdss_pll_trace_counter,
+	TP_PROTO(int pid, char *name, int value),
+	TP_ARGS(pid, name, value),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(counter_name, name)
+			__field(int, value)
+	),
+	TP_fast_assign(
+			__entry->pid = current->tgid;
+			__assign_str(counter_name, name);
+			__entry->value = value;
+	),
+	TP_printk("%d|%s|%d", __entry->pid,
+			__get_str(counter_name), __entry->value)
+)
+
+#define MDSS_PLL_ATRACE_END(name) trace_pll_tracing_mark_write(current->tgid,\
+		name, 0)
+#define MDSS_PLL_ATRACE_BEGIN(name) trace_pll_tracing_mark_write(current->tgid,\
+		name, 1)
+#define MDSS_PLL_ATRACE_FUNC() MDSS_PLL_ATRACE_BEGIN(__func__)
+#define MDSS_PLL_ATRACE_INT(name, value) \
+	trace_mdss_pll_trace_counter(current->tgid, name, value)
+
+
+#endif /* _MDSS_PLL_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 1b2574c..b167cc6 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,7 @@
 #include <linux/of_irq.h>
 #include <linux/clk.h>
 #include <linux/reset.h>
+#include <linux/slab.h>
 
 #define TIM_CR1		0x00
 #define TIM_DIER	0x0c
@@ -106,6 +107,10 @@
 	unsigned long rate, max_delta;
 	int irq, ret, bits, prescaler = 1;
 
+	data = kmemdup(&clock_event_ddata, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	clk = of_clk_get(np, 0);
 	if (IS_ERR(clk)) {
 		ret = PTR_ERR(clk);
@@ -156,8 +161,8 @@
 
 	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
 	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
-	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
 	writel_relaxed(0, data->base + TIM_SR);
+	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
 
 	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
 
@@ -184,6 +189,7 @@
 err_clk_enable:
 	clk_put(clk);
 err_clk_get:
+	kfree(data);
 	return ret;
 }
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 18b2c18..597aa57 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -310,6 +310,7 @@
 if MIPS
 config LOONGSON2_CPUFREQ
 	tristate "Loongson2 CPUFreq Driver"
+	depends on LEMOTE_MACH2F
 	help
 	  This option adds a CPUFreq driver for loongson processors which
 	  support software configurable cpu frequency.
@@ -322,6 +323,7 @@
 
 config LOONGSON1_CPUFREQ
 	tristate "Loongson1 CPUFreq Driver"
+	depends on LOONGSON1_LS1B
 	help
 	  This option adds a CPUFreq driver for loongson1 processors which
 	  support software configurable cpu frequency.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 7937471..8059ef9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -772,6 +772,9 @@
 									\
 	memcpy(&new_policy, policy, sizeof(*policy));			\
 									\
+	new_policy.min = new_policy.user_policy.min;			\
+	new_policy.max = new_policy.user_policy.max;			\
+									\
 	ret = sscanf(buf, "%u", &new_policy.object);			\
 	if (ret != 1)							\
 		return -EINVAL;						\
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 19fe223..786ba01 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -37,8 +37,8 @@
 #include <linux/cpuhotplug.h>
 #include <soc/qcom/pm.h>
 #include <soc/qcom/event_timer.h>
+#include <soc/qcom/lpm_levels.h>
 #include <soc/qcom/lpm-stats.h>
-#include <soc/qcom/system_pm.h>
 #include <soc/qcom/minidump.h>
 #include <asm/arch_timer.h>
 #include <asm/suspend.h>
@@ -82,6 +82,9 @@
 	uint32_t arg4;
 };
 
+static struct system_pm_ops *sys_pm_ops;
+
+
 struct lpm_cluster *lpm_root_node;
 
 #define MAXSAMPLES 5
@@ -126,11 +129,6 @@
 		const struct cpumask *cpu, int child_idx, bool from_idle,
 		int64_t time);
 
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, 0664);
-static uint64_t suspend_wake_time;
-
 static bool print_parsed_dt;
 module_param_named(print_parsed_dt, print_parsed_dt, bool, 0664);
 
@@ -148,20 +146,15 @@
 }
 EXPORT_SYMBOL(msm_cpuidle_get_deep_idle_latency);
 
-void lpm_suspend_wake_time(uint64_t wakeup_time)
+uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops)
 {
-	if (wakeup_time <= 0) {
-		suspend_wake_time = msm_pm_sleep_time_override;
-		return;
-	}
+	if (sys_pm_ops)
+		return -EUSERS;
 
-	if (msm_pm_sleep_time_override &&
-		(msm_pm_sleep_time_override < wakeup_time))
-		suspend_wake_time = msm_pm_sleep_time_override;
-	else
-		suspend_wake_time = wakeup_time;
+	sys_pm_ops = pm_ops;
+
+	return 0;
 }
-EXPORT_SYMBOL(lpm_suspend_wake_time);
 
 static uint32_t least_cluster_latency(struct lpm_cluster *cluster,
 					struct latency_level *lat_level)
@@ -706,28 +699,40 @@
 	return best_level;
 }
 
+static unsigned int get_next_online_cpu(bool from_idle)
+{
+	unsigned int cpu;
+	ktime_t next_event;
+	unsigned int next_cpu = raw_smp_processor_id();
+
+	if (!from_idle)
+		return next_cpu;
+	next_event.tv64 = KTIME_MAX;
+	for_each_online_cpu(cpu) {
+		ktime_t *next_event_c;
+
+		next_event_c = get_next_event_cpu(cpu);
+		if (next_event_c->tv64 < next_event.tv64) {
+			next_event.tv64 = next_event_c->tv64;
+			next_cpu = cpu;
+		}
+	}
+	return next_cpu;
+}
+
 static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster,
-		struct cpumask *mask, bool from_idle, uint32_t *pred_time)
+		bool from_idle, uint32_t *pred_time)
 {
 	int cpu;
-	int next_cpu = raw_smp_processor_id();
 	ktime_t next_event;
 	struct cpumask online_cpus_in_cluster;
 	struct lpm_history *history;
 	int64_t prediction = LONG_MAX;
 
-	next_event.tv64 = KTIME_MAX;
-	if (!suspend_wake_time)
-		suspend_wake_time =  msm_pm_sleep_time_override;
-	if (!from_idle) {
-		if (mask)
-			cpumask_copy(mask, cpumask_of(raw_smp_processor_id()));
-		if (!suspend_wake_time)
-			return ~0ULL;
-		else
-			return USEC_PER_SEC * suspend_wake_time;
-	}
+	if (!from_idle)
+		return ~0ULL;
 
+	next_event.tv64 = KTIME_MAX;
 	cpumask_and(&online_cpus_in_cluster,
 			&cluster->num_children_in_sync, cpu_online_mask);
 
@@ -737,7 +742,6 @@
 		next_event_c = get_next_event_cpu(cpu);
 		if (next_event_c->tv64 < next_event.tv64) {
 			next_event.tv64 = next_event_c->tv64;
-			next_cpu = cpu;
 		}
 
 		if (from_idle && lpm_prediction) {
@@ -747,9 +751,6 @@
 		}
 	}
 
-	if (mask)
-		cpumask_copy(mask, cpumask_of(next_cpu));
-
 	if (from_idle && lpm_prediction) {
 		if (prediction > ktime_to_us(ktime_get()))
 			*pred_time = prediction - ktime_to_us(ktime_get());
@@ -932,7 +933,7 @@
 	if (!cluster)
 		return -EINVAL;
 
-	sleep_us = (uint32_t)get_cluster_sleep_time(cluster, NULL,
+	sleep_us = (uint32_t)get_cluster_sleep_time(cluster,
 						from_idle, &cpupred_us);
 
 	if (from_idle) {
@@ -983,8 +984,12 @@
 		if (suspend_in_progress && from_idle && level->notify_rpm)
 			continue;
 
-		if (level->notify_rpm && !system_sleep_allowed())
-			continue;
+		if (level->notify_rpm) {
+			if (!(sys_pm_ops && sys_pm_ops->sleep_allowed))
+				continue;
+			if (!sys_pm_ops->sleep_allowed())
+				continue;
+		}
 
 		best_level = i;
 
@@ -1018,7 +1023,8 @@
 		bool from_idle, int predicted)
 {
 	struct lpm_cluster_level *level = &cluster->levels[idx];
-	struct cpumask online_cpus;
+	struct cpumask online_cpus, cpumask;
+	unsigned int cpu;
 
 	cpumask_and(&online_cpus, &cluster->num_children_in_sync,
 					cpu_online_mask);
@@ -1043,10 +1049,13 @@
 	}
 
 	if (level->notify_rpm) {
+		cpu = get_next_online_cpu(from_idle);
+		cpumask_copy(&cpumask, cpumask_of(cpu));
 		clear_predict_history();
 		clear_cl_predict_history();
-		if (system_sleep_enter())
-			return -EBUSY;
+		if (sys_pm_ops && sys_pm_ops->enter)
+			if ((sys_pm_ops->enter(&cpumask)))
+				return -EBUSY;
 	}
 	/* Notify cluster enter event after successfully config completion */
 	cluster_notify(cluster, level, true);
@@ -1177,7 +1186,8 @@
 	level = &cluster->levels[cluster->last_level];
 
 	if (level->notify_rpm)
-		system_sleep_exit();
+		if (sys_pm_ops && sys_pm_ops->exit)
+			sys_pm_ops->exit();
 
 	update_debug_pc_event(CLUSTER_EXIT, cluster->last_level,
 			cluster->num_children_in_sync.bits[0],
@@ -1230,7 +1240,8 @@
 		cpu_pm_exit();
 }
 
-int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl)
+static int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl,
+				bool from_idle)
 {
 	int state_id = 0;
 
@@ -1243,7 +1254,7 @@
 				&cluster->child_cpus))
 		goto unlock_and_return;
 
-	state_id |= get_cluster_id(cluster->parent, aff_lvl);
+	state_id |= get_cluster_id(cluster->parent, aff_lvl, from_idle);
 
 	if (cluster->last_level != cluster->default_level) {
 		struct lpm_cluster_level *level
@@ -1251,14 +1262,16 @@
 
 		state_id |= (level->psci_id & cluster->psci_mode_mask)
 					<< cluster->psci_mode_shift;
-		(*aff_lvl)++;
 
 		/*
 		 * We may have updated the broadcast timers, update
 		 * the wakeup value by reading the bc timer directly.
 		 */
 		if (level->notify_rpm)
-			system_sleep_update_wakeup();
+			if (sys_pm_ops && sys_pm_ops->update_wakeup)
+				sys_pm_ops->update_wakeup(from_idle);
+		if (level->psci_id)
+			(*aff_lvl)++;
 	}
 unlock_and_return:
 	spin_unlock(&cluster->sync_lock);
@@ -1285,7 +1298,7 @@
 			return success;
 	}
 
-	state_id = get_cluster_id(cpu->parent, &affinity_level);
+	state_id = get_cluster_id(cpu->parent, &affinity_level, from_idle);
 	power_state = PSCI_POWER_STATE(cpu->levels[idx].is_reset);
 	affinity_level = PSCI_AFFINITY_LEVEL(affinity_level);
 	state_id |= power_state | affinity_level | cpu->levels[idx].psci_id;
@@ -1358,11 +1371,6 @@
 	const struct cpumask *cpumask = get_cpu_mask(dev->cpu);
 	ktime_t start = ktime_get();
 	uint64_t start_time = ktime_to_ns(start), end_time;
-	struct power_params *pwr_params;
-
-	pwr_params = &cpu->levels[idx].pwr;
-	sched_set_cpu_cstate(dev->cpu, idx + 1,
-			pwr_params->energy_overhead, pwr_params->latency_us);
 
 	cpu_prepare(cpu, idx, true);
 	cluster_prepare(cpu->parent, cpumask, idx, true, start_time);
@@ -1381,7 +1389,6 @@
 
 	cluster_unprepare(cpu->parent, cpumask, idx, true, end_time);
 	cpu_unprepare(cpu, idx, true);
-	sched_set_cpu_cstate(smp_processor_id(), 0, 0, 0);
 	dev->last_residency = ktime_us_delta(ktime_get(), start);
 	update_history(dev, idx);
 	trace_cpu_idle_exit(idx, success);
@@ -1731,6 +1738,18 @@
 {
 	int rc;
 
+#ifdef CONFIG_ARM
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		rc = arm_cpuidle_init(cpu);
+		if (rc) {
+			pr_err("CPU%d ARM CPUidle init failed (%d)\n", cpu, rc);
+			return rc;
+		}
+	}
+#endif
+
 	rc = platform_driver_register(&lpm_driver);
 	if (rc) {
 		pr_info("Error registering %s\n", lpm_driver.driver.name);
diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h
index 2f7a55d..1ff69c8 100644
--- a/drivers/cpuidle/lpm-levels.h
+++ b/drivers/cpuidle/lpm-levels.h
@@ -109,8 +109,6 @@
 	struct hrtimer histtimer;
 };
 
-void lpm_suspend_wake_time(uint64_t wakeup_time);
-
 struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev);
 void free_cluster_node(struct lpm_cluster *cluster);
 void cluster_dt_walkthrough(struct lpm_cluster *cluster);
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 98468b9..2ca101a 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -228,12 +228,16 @@
 		 * without any error (HW optimizations for later
 		 * CAAM eras), then try again.
 		 */
-		rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
-		if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
-		    !(rdsta_val & (1 << sh_idx)))
-			ret = -EAGAIN;
 		if (ret)
 			break;
+
+		rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+		if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
+		    !(rdsta_val & (1 << sh_idx))) {
+			ret = -EAGAIN;
+			break;
+		}
+
 		dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
 		/* Clear the contents before recreating the descriptor */
 		memset(desc, 0x00, CAAM_CMD_SZ * 7);
diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c
index 4e49d5b..d39ff73 100644
--- a/drivers/devfreq/devfreq_spdm_debugfs.c
+++ b/drivers/devfreq/devfreq_spdm_debugfs.c
@@ -34,7 +34,7 @@
 	int i;
 	int next_idx;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
@@ -42,6 +42,8 @@
 		size = -EINVAL;
 	}
 
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u\n", &i) != 1) {
 		size = -EINVAL;
 		goto err;
@@ -105,7 +107,7 @@
 	int ext_status = 0;
 	int i;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
@@ -113,6 +115,8 @@
 		goto out;
 	}
 
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0],
 	       &spdm_data->config_data.pl_freqs[1]) != 2) {
 		size = -EINVAL;
@@ -164,7 +168,7 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
@@ -172,6 +176,8 @@
 		goto out;
 	}
 
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0],
 	       &spdm_data->config_data.reject_rate[1]) != 2) {
 		size = -EINVAL;
@@ -224,13 +230,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2],
 	       &spdm_data->config_data.reject_rate[3]) != 2) {
 		size = -EINVAL;
@@ -282,13 +291,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4],
 	       &spdm_data->config_data.reject_rate[5]) != 2) {
 		size = -EINVAL;
@@ -340,13 +352,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0],
 	       &spdm_data->config_data.response_time_us[1]) != 2) {
 		size = -EINVAL;
@@ -398,13 +413,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2],
 	       &spdm_data->config_data.response_time_us[3]) != 2) {
 		size = -EINVAL;
@@ -456,13 +474,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4],
 	       &spdm_data->config_data.response_time_us[5]) != 2) {
 		size = -EINVAL;
@@ -515,13 +536,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n",
 		   &spdm_data->config_data.cci_response_time_us[0],
 		   &spdm_data->config_data.cci_response_time_us[1]) != 2) {
@@ -575,13 +599,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n",
 		   &spdm_data->config_data.cci_response_time_us[2],
 		   &spdm_data->config_data.cci_response_time_us[3]) != 2) {
@@ -635,13 +662,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u\n",
 		   &spdm_data->config_data.cci_response_time_us[4],
 		   &spdm_data->config_data.cci_response_time_us[5]) != 2){
@@ -694,13 +724,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq) != 1) {
 		size = -EINVAL;
 		goto out;
@@ -748,13 +781,16 @@
 	struct spdm_args desc = { { 0 } };
 	int ext_status = 0;
 
-	if (size > sizeof(buf))
+	if (size > sizeof(buf) - 1)
 		return -EINVAL;
 
 	if (copy_from_user(buf, data, size)) {
 		size = -EINVAL;
 		goto out;
 	}
+
+	buf[size] = '\0';
+
 	if (sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep,
 	       &spdm_data->config_data.downstep,
 	       &spdm_data->config_data.max_vote,
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index 3026bc2..cb04014 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 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
@@ -171,7 +171,7 @@
 #define MAX_MS	500U
 
 /* Returns MBps of read/writes for the sampling window. */
-static unsigned int bytes_to_mbps(long long bytes, unsigned int us)
+static unsigned long bytes_to_mbps(unsigned long long bytes, unsigned int us)
 {
 	bytes *= USEC_PER_SEC;
 	do_div(bytes, us);
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index e0bd578..ebe72a4 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -339,7 +339,7 @@
 {
 	struct dmatest_done *done = arg;
 	struct dmatest_thread *thread =
-		container_of(arg, struct dmatest_thread, done_wait);
+		container_of(done, struct dmatest_thread, test_done);
 	if (!thread->done) {
 		done->done = true;
 		wake_up_all(done->wait);
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
index cda6dab..6b65a10 100644
--- a/drivers/edac/octeon_edac-lmc.c
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -79,6 +79,7 @@
 	if (!pvt->inject)
 		int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
 	else {
+		int_reg.u64 = 0;
 		if (pvt->error_type == 1)
 			int_reg.s.sec_err = 1;
 		if (pvt->error_type == 2)
diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
index b8cde09..41245d8 100644
--- a/drivers/extcon/extcon-qcom-spmi-misc.c
+++ b/drivers/extcon/extcon-qcom-spmi-misc.c
@@ -1,6 +1,6 @@
 /**
  * extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID
- *				detection based on extcon-usb-gpio.c.
+ *			and VBUS detection based on extcon-usb-gpio.c.
  *
  * Copyright (C) 2016 Linaro, Ltd.
  * Stephen Boyd <stephen.boyd@linaro.org>
@@ -28,30 +28,56 @@
 
 struct qcom_usb_extcon_info {
 	struct extcon_dev *edev;
-	int irq;
+	int id_irq;
+	int vbus_irq;
 	struct delayed_work wq_detcable;
 	unsigned long debounce_jiffies;
 };
 
 static const unsigned int qcom_usb_extcon_cable[] = {
+	EXTCON_USB,
 	EXTCON_USB_HOST,
 	EXTCON_NONE,
 };
 
 static void qcom_usb_extcon_detect_cable(struct work_struct *work)
 {
-	bool id;
+	bool state = 0;
 	int ret;
+	union extcon_property_value val;
 	struct qcom_usb_extcon_info *info = container_of(to_delayed_work(work),
 						    struct qcom_usb_extcon_info,
 						    wq_detcable);
 
-	/* check ID and update cable state */
-	ret = irq_get_irqchip_state(info->irq, IRQCHIP_STATE_LINE_LEVEL, &id);
-	if (ret)
-		return;
+	if (info->id_irq > 0) {
+		/* check ID and update cable state */
+		ret = irq_get_irqchip_state(info->id_irq,
+				IRQCHIP_STATE_LINE_LEVEL, &state);
+		if (ret)
+			return;
 
-	extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id);
+		if (!state) {
+			val.intval = true;
+			extcon_set_property(info->edev, EXTCON_USB_HOST,
+						EXTCON_PROP_USB_SS, val);
+		}
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !state);
+	}
+
+	if (info->vbus_irq > 0) {
+		/* check VBUS and update cable state */
+		ret = irq_get_irqchip_state(info->vbus_irq,
+				IRQCHIP_STATE_LINE_LEVEL, &state);
+		if (ret)
+			return;
+
+		if (state) {
+			val.intval = true;
+			extcon_set_property(info->edev, EXTCON_USB,
+						EXTCON_PROP_USB_SS, val);
+		}
+		extcon_set_cable_state_(info->edev, EXTCON_USB, state);
+	}
 }
 
 static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id)
@@ -86,21 +112,48 @@
 		return ret;
 	}
 
+	ret = extcon_set_property_capability(info->edev,
+			EXTCON_USB, EXTCON_PROP_USB_SS);
+	ret |= extcon_set_property_capability(info->edev,
+			EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+	if (ret) {
+		dev_err(dev, "failed to register extcon props rc=%d\n",
+						ret);
+		return ret;
+	}
+
 	info->debounce_jiffies = msecs_to_jiffies(USB_ID_DEBOUNCE_MS);
 	INIT_DELAYED_WORK(&info->wq_detcable, qcom_usb_extcon_detect_cable);
 
-	info->irq = platform_get_irq_byname(pdev, "usb_id");
-	if (info->irq < 0)
-		return info->irq;
-
-	ret = devm_request_threaded_irq(dev, info->irq, NULL,
+	info->id_irq = platform_get_irq_byname(pdev, "usb_id");
+	if (info->id_irq > 0) {
+		ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
 					qcom_usb_irq_handler,
 					IRQF_TRIGGER_RISING |
 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 					pdev->name, info);
-	if (ret < 0) {
-		dev_err(dev, "failed to request handler for ID IRQ\n");
-		return ret;
+		if (ret < 0) {
+			dev_err(dev, "failed to request handler for ID IRQ\n");
+			return ret;
+		}
+	}
+
+	info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus");
+	if (info->vbus_irq > 0) {
+		ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
+					qcom_usb_irq_handler,
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					pdev->name, info);
+		if (ret < 0) {
+			dev_err(dev, "failed to request handler for VBUS IRQ\n");
+			return ret;
+		}
+	}
+
+	if (info->id_irq < 0 && info->vbus_irq < 0) {
+		dev_err(dev, "ID and VBUS IRQ not found\n");
+		return -EINVAL;
 	}
 
 	platform_set_drvdata(pdev, info);
@@ -127,8 +180,12 @@
 	struct qcom_usb_extcon_info *info = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (device_may_wakeup(dev))
-		ret = enable_irq_wake(info->irq);
+	if (device_may_wakeup(dev)) {
+		if (info->id_irq > 0)
+			ret = enable_irq_wake(info->id_irq);
+		if (info->vbus_irq > 0)
+			ret = enable_irq_wake(info->vbus_irq);
+	}
 
 	return ret;
 }
@@ -138,8 +195,12 @@
 	struct qcom_usb_extcon_info *info = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (device_may_wakeup(dev))
-		ret = disable_irq_wake(info->irq);
+	if (device_may_wakeup(dev)) {
+		if (info->id_irq > 0)
+			ret = disable_irq_wake(info->id_irq);
+		if (info->vbus_irq > 0)
+			ret = disable_irq_wake(info->vbus_irq);
+	}
 
 	return ret;
 }
@@ -150,6 +211,7 @@
 
 static const struct of_device_id qcom_usb_extcon_dt_match[] = {
 	{ .compatible = "qcom,pm8941-misc", },
+	{ .compatible = "qcom,pmd-vbus-det", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, qcom_usb_extcon_dt_match);
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 2b6b112..3d50bae 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -249,8 +249,9 @@
 }
 
 #ifdef CONFIG_CPU_IDLE
-static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+static __maybe_unused DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
 
+#ifdef CONFIG_DT_IDLE_STATES
 static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
 {
 	int i, ret, count = 0;
@@ -303,6 +304,10 @@
 	kfree(psci_states);
 	return ret;
 }
+#else
+static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
+{ return 0; }
+#endif
 
 #ifdef CONFIG_ACPI
 #include <acpi/processor.h>
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index dc37dbe..a83e97e 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -323,3 +323,6 @@
 };
 
 module_platform_driver(ath79_gpio_driver);
+
+MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index 98c7ff2..8d62db4 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -58,3 +58,7 @@
 	return platform_driver_register(&iop3xx_gpio_driver);
 }
 arch_initcall(iop3xx_gpio_init);
+
+MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors");
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index adba614..abb5a27 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -190,6 +190,16 @@
 	};
 	int i, j;
 
+	/*
+	 * STMPE1600: to be able to get IRQ from pins,
+	 * a read must be done on GPMR register, or a write in
+	 * GPSR or GPCR registers
+	 */
+	if (stmpe->partnum == STMPE1600) {
+		stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_LSB]);
+		stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_CSB]);
+	}
+
 	for (i = 0; i < CACHE_NR_REGS; i++) {
 		/* STMPE801 and STMPE1600 don't have RE and FE registers */
 		if ((stmpe->partnum == STMPE801 ||
@@ -227,21 +237,11 @@
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
-	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = BIT(offset % 8);
 
 	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
-
-	/*
-	 * STMPE1600 workaround: to be able to get IRQ from pins,
-	 * a read must be done on GPMR register, or a write in
-	 * GPSR or GPCR registers
-	 */
-	if (stmpe->partnum == STMPE1600)
-		stmpe_reg_read(stmpe,
-			       stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]);
 }
 
 static void stmpe_dbg_show_one(struct seq_file *s,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 063d176..f3c3680 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -705,6 +705,9 @@
 	struct gpioevent_data ge;
 	int ret, level;
 
+	/* Do not leak kernel stack to userspace */
+	memset(&ge, 0, sizeof(ge));
+
 	ge.timestamp = ktime_get_real_ns();
 	level = gpiod_get_value_cansleep(le->desc);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
index 1a0a5f7..47951f4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
@@ -367,29 +367,50 @@
 {
 	struct amdgpu_device *adev = get_amdgpu_device(kgd);
 	struct cik_sdma_rlc_registers *m;
+	unsigned long end_jiffies;
 	uint32_t sdma_base_addr;
+	uint32_t data;
 
 	m = get_sdma_mqd(mqd);
 	sdma_base_addr = get_sdma_base_addr(m);
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
-			m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		m->sdma_rlc_rb_cntl & (~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK));
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE,
-			m->sdma_rlc_rb_base);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
-			m->sdma_rlc_rb_base_hi);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
-			m->sdma_rlc_rb_rptr_addr_lo);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
-			m->sdma_rlc_rb_rptr_addr_hi);
+	end_jiffies = msecs_to_jiffies(2000) + jiffies;
+	while (true) {
+		data = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
+		if (data & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
+			break;
+		if (time_after(jiffies, end_jiffies))
+			return -ETIME;
+		usleep_range(500, 1000);
+	}
+	if (m->sdma_engine_id) {
+		data = RREG32(mmSDMA1_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA1_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA1_GFX_CONTEXT_CNTL, data);
+	} else {
+		data = RREG32(mmSDMA0_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA0_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA0_GFX_CONTEXT_CNTL, data);
+	}
 
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL,
-			m->sdma_rlc_doorbell);
-
+				m->sdma_rlc_doorbell);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
+				m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, m->sdma_rlc_rb_base);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
+			m->sdma_rlc_rb_base_hi);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
+			m->sdma_rlc_rb_rptr_addr_lo);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
+			m->sdma_rlc_rb_rptr_addr_hi);
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
 			m->sdma_rlc_rb_cntl);
 
@@ -493,9 +514,9 @@
 	}
 
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL) |
+		SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index f26d1fd..cb505f6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -416,6 +416,10 @@
 		if (candidate == lobj)
 			break;
 
+		/* We can't move pinned BOs here */
+		if (bo->pin_count)
+			continue;
+
 		other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
 
 		/* Check if this BO is in one of the domains we need space for */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
index d83de98..8577a56 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -215,8 +215,8 @@
 	BUG_ON(!mm || !mqd || !q);
 
 	m = get_sdma_mqd(mqd);
-	m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) <<
-			SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
+	m->sdma_rlc_rb_cntl = (ffs(q->queue_size / sizeof(unsigned int)) - 1)
+			<< SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
 			q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT |
 			1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT |
 			6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index e1fb40b..5425c68 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -205,6 +205,24 @@
 
 	switch (type) {
 	case KFD_QUEUE_TYPE_SDMA:
+		if (dev->dqm->queue_count >=
+			CIK_SDMA_QUEUES_PER_ENGINE * CIK_SDMA_ENGINE_NUM) {
+			pr_err("Over-subscription is not allowed for SDMA.\n");
+			retval = -EPERM;
+			goto err_create_queue;
+		}
+
+		retval = create_cp_queue(pqm, dev, &q, properties, f, *qid);
+		if (retval != 0)
+			goto err_create_queue;
+		pqn->q = q;
+		pqn->kq = NULL;
+		retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
+						&q->properties.vmid);
+		pr_debug("DQM returned %d for create_queue\n", retval);
+		print_queue(q);
+		break;
+
 	case KFD_QUEUE_TYPE_COMPUTE:
 		/* check if there is over subscription */
 		if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 10e12e7..688c776 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -74,6 +74,15 @@
 	---help---
 	  Toshiba TC358767 eDP bridge chip driver.
 
+config DRM_LT_LT9611
+	bool "LT LT9611 DSI/HDMI Bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select REGMAP_I2C
+	select DRM_MIPI_DSI
+	help
+	  Support for the LT Devices LT9611 DSI to HDMI encoder.
+
 source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index cdf3a3c..68cf605 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
 obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
+obj-$(CONFIG_DRM_LT_LT9611) += lt9611.o
diff --git a/drivers/gpu/drm/bridge/lt9611.c b/drivers/gpu/drm/bridge/lt9611.c
new file mode 100644
index 0000000..887dd6f
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lt9611.c
@@ -0,0 +1,2166 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/hdmi.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
+
+
+#define CFG_HPD_INTERRUPTS BIT(0)
+#define CFG_EDID_INTERRUPTS BIT(1)
+#define CFG_CEC_INTERRUPTS BIT(2)
+#define CFG_VID_CHK_INTERRUPTS BIT(3)
+
+#define EDID_SEG_SIZE 256
+
+struct lt9611_reg_cfg {
+	u8 reg;
+	u8 val;
+	int sleep_in_ms;
+};
+
+struct lt9611_vreg {
+	struct regulator *vreg; /* vreg handle */
+	char vreg_name[32];
+	int min_voltage;
+	int max_voltage;
+	int enable_load;
+	int disable_load;
+	int pre_on_sleep;
+	int post_on_sleep;
+	int pre_off_sleep;
+	int post_off_sleep;
+};
+
+struct lt9611_video_cfg {
+	u32 h_active;
+	u32 h_front_porch;
+	u32 h_pulse_width;
+	u32 h_back_porch;
+	bool h_polarity;
+	u32 v_active;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 v_back_porch;
+	bool v_polarity;
+	u32 pclk_khz;
+	bool interlaced;
+	u32 vic;
+	enum hdmi_picture_aspect ar;
+	u32 num_of_lanes;
+	u32 num_of_intfs;
+	u8 scaninfo;
+};
+
+struct lt9611 {
+	struct device *dev;
+	struct drm_bridge bridge;
+
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+
+	u8 i2c_addr;
+	int irq;
+	bool ac_mode;
+
+	u32 irq_gpio;
+	u32 reset_gpio;
+	u32 hdmi_ps_gpio;
+	u32 hdmi_en_gpio;
+
+	unsigned int num_vreg;
+	struct lt9611_vreg *vreg_config;
+
+	struct i2c_client *i2c_client;
+
+	enum drm_connector_status status;
+	bool power_on;
+
+	/* get display modes from device tree */
+	bool non_pluggable;
+	u32 num_of_modes;
+	struct list_head mode_list;
+
+	struct drm_display_mode curr_mode;
+	struct lt9611_video_cfg video_cfg;
+
+	u8 edid_buf[EDID_SEG_SIZE];
+	bool hdmi_mode;
+};
+
+static struct lt9611_reg_cfg lt9611_init_setup[] = {
+	/* LT9611_System_Init */
+	{0xFF, 0x81, 0},
+	{0x01, 0x18, 0}, /* sel xtal clock */
+
+	/* timer for frequency meter */
+	{0xff, 0x82, 0},
+	{0x1b, 0x69, 0}, /*timer 2*/
+	{0x1c, 0x78, 0},
+	{0xcb, 0x69, 0}, /*timer 1 */
+	{0xcc, 0x78, 0},
+
+	/* irq init */
+	{0xff, 0x82, 0},
+	{0x51, 0x01, 0},
+	{0x58, 0x0a, 0}, /* hpd irq */
+	{0x59, 0x80, 0}, /* hpd debounce width */
+	{0x9e, 0xf7, 0}, /* video check irq */
+
+	/* power consumption for work */
+	{0xff, 0x80, 0},
+	{0x04, 0xf0, 0},
+	{0x06, 0xf0, 0},
+	{0x0a, 0x80, 0},
+	{0x0b, 0x40, 0},
+	{0x0d, 0xef, 0},
+	{0x11, 0xfa, 0},
+};
+
+struct lt9611_timing_info {
+	u16 xres;
+	u16 yres;
+	u8 bpp;
+	u8 fps;
+	u8 lanes;
+	u8 intfs;
+};
+
+static struct lt9611_timing_info lt9611_supp_timing_cfg[] = {
+	{3840, 2160, 24, 30, 4, 2}, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+	{1920, 1080, 24, 60, 4, 1}, /* 1080P 24bit 60Hz 4lane 1port */
+	{1920, 1080, 24, 30, 3, 1}, /* 1080P 24bit 30Hz 3lane 1port */
+	{1920, 1080, 24, 24, 3, 1},
+	{720, 480, 24, 60, 2, 1},
+	{720, 576, 24, 50, 2, 1},
+	{640, 480, 24, 60, 2, 1},
+	{0xffff, 0xffff, 0xff, 0xff, 0xff},
+};
+
+static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct lt9611, bridge);
+}
+
+static struct lt9611 *connector_to_lt9611(struct drm_connector *connector)
+{
+	WARN_ON(!connector->private);
+
+	return bridge_to_lt9611(connector->private);
+}
+
+static int lt9611_write(struct lt9611 *pdata, u8 reg, u8 val)
+{
+	struct i2c_client *client = pdata->i2c_client;
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = client->addr,
+		.flags = 0,
+		.len = 2,
+		.buf = buf,
+	};
+
+	if (i2c_transfer(client->adapter, &msg, 1) < 1) {
+		pr_err("i2c write failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int lt9611_read(struct lt9611 *pdata, u8 reg, char *buf, u32 size)
+{
+	struct i2c_client *client = pdata->i2c_client;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		pr_err("i2c read failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int lt9611_write_array(struct lt9611 *pdata,
+	struct lt9611_reg_cfg *cfg, int size)
+{
+	int ret = 0;
+	int i;
+
+	size = size / sizeof(struct lt9611_reg_cfg);
+	for (i = 0; i < size; i++) {
+		ret = lt9611_write(pdata, cfg[i].reg, cfg[i].val);
+
+		if (ret != 0) {
+			pr_err("reg writes failed. Last write %02X to %02X\n",
+				cfg[i].val, cfg[i].reg);
+			goto w_regs_fail;
+		}
+
+		if (cfg[i].sleep_in_ms)
+			msleep(cfg[i].sleep_in_ms);
+	}
+
+w_regs_fail:
+	if (ret != 0)
+		pr_err("exiting with ret = %d after %d writes\n", ret, i);
+
+	return ret;
+}
+
+static int lt9611_parse_dt_modes(struct device_node *np,
+					struct list_head *head,
+					u32 *num_of_modes)
+{
+	int rc = 0;
+	struct drm_display_mode *mode;
+	u32 mode_count = 0;
+	struct device_node *node = NULL;
+	struct device_node *root_node = NULL;
+	u32 h_front_porch, h_pulse_width, h_back_porch;
+	u32 v_front_porch, v_pulse_width, v_back_porch;
+	bool h_active_high, v_active_high;
+	u32 flags = 0;
+
+	root_node = of_get_child_by_name(np, "lt,customize-modes");
+	if (!root_node) {
+		root_node = of_parse_phandle(np, "lt,customize-modes", 0);
+		if (!root_node) {
+			pr_info("No entry present for lt,customize-modes");
+			goto end;
+		}
+	}
+
+	for_each_child_of_node(root_node, node) {
+		rc = 0;
+		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+		if (!mode) {
+			pr_err("Out of memory\n");
+			rc =  -ENOMEM;
+			continue;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-active",
+						&mode->hdisplay);
+		if (rc) {
+			pr_err("failed to read h-active, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-front-porch",
+						&h_front_porch);
+		if (rc) {
+			pr_err("failed to read h-front-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-pulse-width",
+						&h_pulse_width);
+		if (rc) {
+			pr_err("failed to read h-pulse-width, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-back-porch",
+						&h_back_porch);
+		if (rc) {
+			pr_err("failed to read h-back-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		h_active_high = of_property_read_bool(node,
+						"lt,mode-h-active-high");
+
+		rc = of_property_read_u32(node, "lt,mode-v-active",
+						&mode->vdisplay);
+		if (rc) {
+			pr_err("failed to read v-active, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-front-porch",
+						&v_front_porch);
+		if (rc) {
+			pr_err("failed to read v-front-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-pulse-width",
+						&v_pulse_width);
+		if (rc) {
+			pr_err("failed to read v-pulse-width, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-back-porch",
+						&v_back_porch);
+		if (rc) {
+			pr_err("failed to read v-back-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		v_active_high = of_property_read_bool(node,
+						"lt,mode-v-active-high");
+
+		rc = of_property_read_u32(node, "lt,mode-refresh-rate",
+						&mode->vrefresh);
+		if (rc) {
+			pr_err("failed to read refresh-rate, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-clock-in-khz",
+						&mode->clock);
+		if (rc) {
+			pr_err("failed to read clock, rc=%d\n", rc);
+			goto fail;
+		}
+
+		mode->hsync_start = mode->hdisplay + h_front_porch;
+		mode->hsync_end = mode->hsync_start + h_pulse_width;
+		mode->htotal = mode->hsync_end + h_back_porch;
+		mode->vsync_start = mode->vdisplay + v_front_porch;
+		mode->vsync_end = mode->vsync_start + v_pulse_width;
+		mode->vtotal = mode->vsync_end + v_back_porch;
+		if (h_active_high)
+			flags |= DRM_MODE_FLAG_PHSYNC;
+		else
+			flags |= DRM_MODE_FLAG_NHSYNC;
+		if (v_active_high)
+			flags |= DRM_MODE_FLAG_PVSYNC;
+		else
+			flags |= DRM_MODE_FLAG_NVSYNC;
+		mode->flags = flags;
+
+		if (!rc) {
+			mode_count++;
+			list_add_tail(&mode->head, head);
+		}
+
+		drm_mode_set_name(mode);
+
+		pr_debug("mode[%s] h[%d,%d,%d,%d] v[%d,%d,%d,%d] %d %x %dkHZ\n",
+			mode->name, mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal, mode->vdisplay,
+			mode->vsync_start, mode->vsync_end, mode->vtotal,
+			mode->vrefresh, mode->flags, mode->clock);
+fail:
+		if (rc) {
+			kfree(mode);
+			continue;
+		}
+	}
+
+	if (num_of_modes)
+		*num_of_modes = mode_count;
+
+end:
+	return rc;
+}
+
+
+static int lt9611_parse_dt(struct device *dev,
+	struct lt9611 *pdata)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *end_node;
+	int ret = 0;
+
+	end_node = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
+	if (!end_node) {
+		pr_err("remote endpoint not found\n");
+		return -ENODEV;
+	}
+
+	pdata->host_node = of_graph_get_remote_port_parent(end_node);
+	of_node_put(end_node);
+	if (!pdata->host_node) {
+		pr_err("remote node not found\n");
+		return -ENODEV;
+	}
+	of_node_put(pdata->host_node);
+
+	pdata->irq_gpio =
+		of_get_named_gpio(np, "lt,irq-gpio", 0);
+	if (!gpio_is_valid(pdata->irq_gpio)) {
+		pr_err("irq gpio not specified\n");
+		ret = -EINVAL;
+	}
+	pr_debug("irq_gpio=%d\n", pdata->irq_gpio);
+
+	pdata->reset_gpio =
+		of_get_named_gpio(np, "lt,reset-gpio", 0);
+	if (!gpio_is_valid(pdata->reset_gpio)) {
+		pr_err("reset gpio not specified\n");
+		ret = -EINVAL;
+	}
+	pr_debug("reset_gpio=%d\n", pdata->reset_gpio);
+
+	pdata->hdmi_ps_gpio =
+		of_get_named_gpio(np, "lt,hdmi-ps-gpio", 0);
+	if (!gpio_is_valid(pdata->hdmi_ps_gpio))
+		pr_debug("hdmi ps gpio not specified\n");
+	else
+		pr_debug("hdmi_ps_gpio=%d\n", pdata->hdmi_ps_gpio);
+
+	pdata->hdmi_en_gpio =
+		of_get_named_gpio(np, "lt,hdmi-en-gpio", 0);
+	if (!gpio_is_valid(pdata->hdmi_en_gpio))
+		pr_debug("hdmi en gpio not specified\n");
+	else
+		pr_debug("hdmi_en_gpio=%d\n", pdata->hdmi_en_gpio);
+
+	pdata->ac_mode = of_property_read_bool(np, "lt,ac-mode");
+	pr_debug("ac_mode=%d\n", pdata->ac_mode);
+
+	pdata->non_pluggable = of_property_read_bool(np, "lt,non-pluggable");
+	pr_debug("non_pluggable = %d\n", pdata->non_pluggable);
+	if (pdata->non_pluggable) {
+		INIT_LIST_HEAD(&pdata->mode_list);
+		ret = lt9611_parse_dt_modes(np,
+			&pdata->mode_list, &pdata->num_of_modes);
+	}
+
+	return ret;
+}
+
+static int lt9611_gpio_configure(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+
+	if (on) {
+		ret = gpio_request(pdata->reset_gpio,
+			"lt9611-reset-gpio");
+		if (ret) {
+			pr_err("lt9611 reset gpio request failed\n");
+			goto error;
+		}
+
+		ret = gpio_direction_output(pdata->reset_gpio, 0);
+		if (ret) {
+			pr_err("lt9611 reset gpio direction failed\n");
+			goto reset_error;
+		}
+
+		if (gpio_is_valid(pdata->hdmi_en_gpio)) {
+			ret = gpio_request(pdata->hdmi_en_gpio,
+					"lt9611-hdmi-en-gpio");
+			if (ret) {
+				pr_err("lt9611 hdmi en gpio request failed\n");
+				goto reset_error;
+			}
+
+			ret = gpio_direction_output(pdata->hdmi_en_gpio, 1);
+			if (ret) {
+				pr_err("lt9611 hdmi en gpio direction failed\n");
+				goto hdmi_en_error;
+			}
+		}
+
+		if (gpio_is_valid(pdata->hdmi_ps_gpio)) {
+			ret = gpio_request(pdata->hdmi_ps_gpio,
+				"lt9611-hdmi-ps-gpio");
+			if (ret) {
+				pr_err("lt9611 hdmi ps gpio request failed\n");
+				goto hdmi_en_error;
+			}
+
+			ret = gpio_direction_input(pdata->hdmi_ps_gpio);
+			if (ret) {
+				pr_err("lt9611 hdmi ps gpio direction failed\n");
+				goto hdmi_ps_error;
+			}
+		}
+
+		ret = gpio_request(pdata->irq_gpio, "lt9611-irq-gpio");
+		if (ret) {
+			pr_err("lt9611 irq gpio request failed\n");
+			goto hdmi_ps_error;
+		}
+
+		ret = gpio_direction_input(pdata->irq_gpio);
+		if (ret) {
+			pr_err("lt9611 irq gpio direction failed\n");
+			goto irq_error;
+		}
+	} else {
+		gpio_free(pdata->irq_gpio);
+		if (gpio_is_valid(pdata->hdmi_ps_gpio))
+			gpio_free(pdata->hdmi_ps_gpio);
+		if (gpio_is_valid(pdata->hdmi_en_gpio))
+			gpio_free(pdata->hdmi_en_gpio);
+		gpio_free(pdata->reset_gpio);
+	}
+
+	return ret;
+
+
+irq_error:
+	gpio_free(pdata->irq_gpio);
+hdmi_ps_error:
+	if (gpio_is_valid(pdata->hdmi_ps_gpio))
+		gpio_free(pdata->hdmi_ps_gpio);
+hdmi_en_error:
+	if (gpio_is_valid(pdata->hdmi_en_gpio))
+		gpio_free(pdata->hdmi_en_gpio);
+reset_error:
+	gpio_free(pdata->reset_gpio);
+error:
+	return ret;
+}
+
+static int lt9611_read_device_rev(struct lt9611 *pdata)
+{
+	u8 rev = 0;
+	int ret = 0;
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0xee, 0x01);
+
+	ret = lt9611_read(pdata, 0x02, &rev, 1);
+
+	if (ret == 0)
+		pr_info("LT9611 revsion: 0x%x\n", rev);
+
+	return ret;
+}
+
+static int lt9611_mipi_input_analog(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x81, 0},
+		{0x06, 0x40, 0}, /*port A rx current*/
+		{0x0a, 0xfe, 0}, /*port A ldo voltage set*/
+		{0x0b, 0xbf, 0}, /*enable port A lprx*/
+		{0x11, 0x40, 0}, /*port B rx current*/
+		{0x15, 0xfe, 0}, /*port B ldo voltage set*/
+		{0x16, 0xbf, 0}, /*enable port B lprx*/
+
+		{0x1c, 0x03, 0}, /*PortA clk lane no-LP mode*/
+		{0x20, 0x03, 0}, /*PortB clk lane with-LP mode*/
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return 0;
+}
+
+static int lt9611_mipi_input_digital(struct lt9611 *pdata,
+	struct lt9611_video_cfg *cfg)
+{
+	u8 lanes = 0;
+	u8 ports = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x82, 0},
+		{0x4f, 0x80, 0},
+		{0x50, 0x10, 0},
+		{0xff, 0x83, 0},
+
+		{0x02, 0x0a, 0},
+		{0x06, 0x0a, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	lanes = cfg->num_of_lanes;
+	ports = cfg->num_of_intfs;
+
+	lt9611_write(pdata, 0xff, 0x83);
+	if (lanes == 4)
+		lt9611_write(pdata, 0x00, 0x00);
+	else if (lanes < 4)
+		lt9611_write(pdata, 0x00, lanes);
+	else {
+		pr_err("invalid lane count\n");
+		return -EINVAL;
+	}
+
+	if (ports == 1)
+		lt9611_write(pdata, 0x0a, 0x00);
+	else if (ports == 2)
+		lt9611_write(pdata, 0x0a, 0x03);
+	else {
+		pr_err("invalid port count\n");
+		return -EINVAL;
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return 0;
+}
+
+static void lt9611_mipi_video_setup(struct lt9611 *pdata,
+	struct lt9611_video_cfg *cfg)
+{
+	u32 h_total, h_act, hpw, hfp, hss;
+	u32 v_total, v_act, vpw, vfp, vss;
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	h_total = cfg->h_active + cfg->h_front_porch +
+	      cfg->h_pulse_width + cfg->h_back_porch;
+	v_total = cfg->v_active + cfg->v_front_porch +
+	      cfg->v_pulse_width + cfg->v_back_porch;
+
+	h_act = cfg->h_active;
+	hpw = cfg->h_pulse_width;
+	hfp = cfg->h_front_porch;
+	hss = cfg->h_pulse_width + cfg->h_back_porch;
+
+	v_act = cfg->v_active;
+	vpw = cfg->v_pulse_width;
+	vfp = cfg->v_front_porch;
+	vss = cfg->v_pulse_width + cfg->v_back_porch;
+
+	pr_debug("h_total=%d, h_active=%d, hfp=%d, hpw=%d, hbp=%d\n",
+		h_total, cfg->h_active, cfg->h_front_porch,
+		cfg->h_pulse_width, cfg->h_back_porch);
+
+	pr_debug("v_total=%d, v_active=%d, vfp=%d, vpw=%d, vbp=%d\n",
+		v_total, cfg->v_active, cfg->v_front_porch,
+		cfg->v_pulse_width, cfg->v_back_porch);
+
+	lt9611_write(pdata, 0xff, 0x83);
+
+	lt9611_write(pdata, 0x0d, (u8)(v_total / 256));
+	lt9611_write(pdata, 0x0e, (u8)(v_total % 256));
+
+	lt9611_write(pdata, 0x0f, (u8)(v_act / 256));
+	lt9611_write(pdata, 0x10, (u8)(v_act % 256));
+
+	lt9611_write(pdata, 0x11, (u8)(h_total / 256));
+	lt9611_write(pdata, 0x12, (u8)(h_total % 256));
+
+	lt9611_write(pdata, 0x13, (u8)(h_act / 256));
+	lt9611_write(pdata, 0x14, (u8)(h_act % 256));
+
+	lt9611_write(pdata, 0x15, (u8)(vpw % 256));
+	lt9611_write(pdata, 0x16, (u8)(hpw % 256));
+
+	lt9611_write(pdata, 0x17, (u8)(vfp % 256));
+
+	lt9611_write(pdata, 0x18, (u8)(vss % 256));
+
+	lt9611_write(pdata, 0x19, (u8)(hfp % 256));
+
+	lt9611_write(pdata, 0x1a, (u8)(hss / 256));
+	lt9611_write(pdata, 0x1b, (u8)(hss % 256));
+}
+
+static int lt9611_pcr_setup(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	u32 h_act = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x83, 0},
+		{0x0b, 0x01, 0},
+		{0x0c, 0x10, 0},
+		{0x48, 0x00, 0},
+		{0x49, 0x81, 0},
+
+		/* stage 1 */
+		{0x21, 0x4a, 0},
+		{0x24, 0x71, 0},
+		{0x25, 0x30, 0},
+		{0x2a, 0x01, 0},
+
+		/* stage 2 */
+		{0x4a, 0x40, 0},
+		{0x1d, 0x10, 0},
+
+		/* MK limit */
+		{0x2d, 0x38, 0},
+		{0x31, 0x08, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	h_act = cfg->h_active;
+
+	if (h_act == 1920) {
+		lt9611_write(pdata, 0x26, 0x37);
+	} else if (h_act == 3840) {
+		lt9611_write(pdata, 0x0b, 0x03);
+		lt9611_write(pdata, 0x0c, 0xd0);
+		lt9611_write(pdata, 0x48, 0x03);
+		lt9611_write(pdata, 0x49, 0xe0);
+		lt9611_write(pdata, 0x24, 0x72);
+		lt9611_write(pdata, 0x25, 0x00);
+		lt9611_write(pdata, 0x2a, 0x01);
+		lt9611_write(pdata, 0x4a, 0x10);
+		lt9611_write(pdata, 0x1d, 0x10);
+		lt9611_write(pdata, 0x26, 0x37);
+	} else if (h_act == 640) {
+		lt9611_write(pdata, 0x26, 0x14);
+	}
+
+	/* pcr rst */
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0x11, 0x5a);
+	lt9611_write(pdata, 0x11, 0xfa);
+
+	return 0;
+}
+
+static int lt9611_pll_setup(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	u32 pclk = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		/* txpll init */
+		{0xff, 0x81, 0},
+		{0x23, 0x40, 0},
+		{0x24, 0x64, 0},
+		{0x25, 0x80, 0},
+		{0x26, 0x55, 0},
+		{0x2c, 0x37, 0},
+		{0x2f, 0x01, 0},
+		{0x26, 0x55, 0},
+		{0x27, 0x66, 0},
+		{0x28, 0x88, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	pclk = cfg->pclk_khz;
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	if (pclk > 150000)
+		lt9611_write(pdata, 0x2d, 0x88);
+	else if (pclk > 70000)
+		lt9611_write(pdata, 0x2d, 0x99);
+	else
+		lt9611_write(pdata, 0x2d, 0xaa);
+
+	lt9611_write(pdata, 0xff, 0x82);
+	pclk = pclk / 2;
+	lt9611_write(pdata, 0xe3, pclk/65536); /* pclk[19:16] */
+	pclk = pclk % 65536;
+	lt9611_write(pdata, 0xe4, pclk/256);   /* pclk[15:8]  */
+	lt9611_write(pdata, 0xe5, pclk%256);   /* pclk[7:0]   */
+
+	lt9611_write(pdata, 0xde, 0x20);
+	lt9611_write(pdata, 0xde, 0xe0);
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0x16, 0xf1);
+	lt9611_write(pdata, 0x16, 0xf3);
+
+	return 0;
+}
+
+static int lt9611_video_check(struct lt9611 *pdata)
+{
+	int ret = 0;
+	u32 v_total, v_act, h_act_a, h_act_b, h_total_sysclk;
+	u8 temp = 0;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	/* top module video check */
+	lt9611_write(pdata, 0xff, 0x82);
+
+	/* v_act */
+	ret = lt9611_read(pdata, 0x82, &temp, 1);
+	if (ret)
+		goto end;
+
+	v_act = temp << 8;
+	ret = lt9611_read(pdata, 0x83, &temp, 1);
+	if (ret)
+		goto end;
+	v_act = v_act + temp;
+
+	/* v_total */
+	ret = lt9611_read(pdata, 0x6c, &temp, 1);
+	if (ret)
+		goto end;
+	v_total = temp << 8;
+	ret = lt9611_read(pdata, 0x6d, &temp, 1);
+	if (ret)
+		goto end;
+	v_total = v_total + temp;
+
+	/* h_total_sysclk */
+	ret = lt9611_read(pdata, 0x86, &temp, 1);
+	if (ret)
+		goto end;
+	h_total_sysclk = temp << 8;
+	ret = lt9611_read(pdata, 0x87, &temp, 1);
+	if (ret)
+		goto end;
+	h_total_sysclk = h_total_sysclk + temp;
+
+	/* h_act_a */
+	lt9611_write(pdata, 0xff, 0x83);
+	ret = lt9611_read(pdata, 0x82, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_a = temp << 8;
+	ret = lt9611_read(pdata, 0x83, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_a = (h_act_a + temp)/3;
+
+	/* h_act_b */
+	lt9611_write(pdata, 0xff, 0x83);
+	ret = lt9611_read(pdata, 0x86, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_b = temp << 8;
+	ret = lt9611_read(pdata, 0x87, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_b = (h_act_b + temp)/3;
+
+	pr_info("video check: h_act_a=%d, h_act_b=%d, v_act=%d, v_total=%d, h_total_sysclk=%d\n",
+		h_act_a, h_act_b, v_act, v_total, h_total_sysclk);
+
+	return 0;
+
+end:
+	pr_err("read video check error\n");
+	return ret;
+}
+
+static int lt9611_hdmi_tx_digital(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	int ret = -EINVAL;
+	u32 checksum, vic;
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return ret;
+	}
+
+	vic = cfg->vic;
+	checksum = 0x46 - vic;
+
+	lt9611_write(pdata, 0xff, 0x84);
+	lt9611_write(pdata, 0x43, checksum);
+	lt9611_write(pdata, 0x44, 0x84);
+	lt9611_write(pdata, 0x47, vic);
+
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xd6, 0x8c);
+	lt9611_write(pdata, 0xd7, 0x04);
+
+	return ret;
+}
+
+static int lt9611_hdmi_tx_phy(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	int ret = -EINVAL;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x81, 0},
+		{0x30, 0x6a, 0},
+		{0x31, 0x44, 0}, /* HDMI DC mode */
+		{0x32, 0x4a, 0},
+		{0x33, 0x0b, 0},
+		{0x34, 0x00, 0},
+		{0x35, 0x00, 0},
+		{0x36, 0x00, 0},
+		{0x37, 0x44, 0},
+		{0x3f, 0x0f, 0},
+		{0x40, 0xa0, 0},
+		{0x41, 0xa0, 0},
+		{0x42, 0xa0, 0},
+		{0x43, 0xa0, 0},
+		{0x44, 0x0a, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return ret;
+	}
+
+	/* HDMI AC mode */
+	if (pdata->ac_mode)
+		reg_cfg[2].val = 0x73;
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return ret;
+}
+
+static void lt9611_hdmi_output_enable(struct lt9611 *pdata)
+{
+	lt9611_write(pdata, 0xff, 0x81);
+	lt9611_write(pdata, 0x30, 0xea);
+}
+
+static void lt9611_hdmi_output_disable(struct lt9611 *pdata)
+{
+	lt9611_write(pdata, 0xff, 0x81);
+	lt9611_write(pdata, 0x30, 0x6a);
+}
+
+static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id)
+{
+	struct lt9611 *pdata = dev_id;
+	u8 irq_flag0 = 0;
+	u8 irq_flag3 = 0;
+
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_read(pdata, 0x0f, &irq_flag3, 1);
+	lt9611_read(pdata, 0x0c, &irq_flag0, 1);
+
+	 /* hpd changed low */
+	if (irq_flag3 & 0x80) {
+		pr_info("hdmi cable disconnected\n");
+
+		lt9611_write(pdata, 0xff, 0x82); /* irq 3 clear flag */
+		lt9611_write(pdata, 0x07, 0xbf);
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+	 /* hpd changed high */
+	if (irq_flag3 & 0x40) {
+		pr_info("hdmi cable connected\n");
+
+		lt9611_write(pdata, 0xff, 0x82); /* irq 3 clear flag */
+		lt9611_write(pdata, 0x07, 0x7f);
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+
+	/* video input changed */
+	if (irq_flag0 & 0x01) {
+		pr_info("video input changed\n");
+		lt9611_write(pdata, 0xff, 0x82); /* irq 0 clear flag */
+		lt9611_write(pdata, 0x9e, 0xff);
+		lt9611_write(pdata, 0x9e, 0xf7);
+		lt9611_write(pdata, 0x04, 0xff);
+		lt9611_write(pdata, 0x04, 0xfe);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int lt9611_enable_interrupts(struct lt9611 *pdata, int interrupts)
+{
+	int ret = 0;
+	u8 reg_val = 0;
+	u8 init_reg_val;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		goto end;
+	}
+
+	if (interrupts & CFG_VID_CHK_INTERRUPTS) {
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x00, &reg_val, 1);
+
+		if (reg_val & 0x01) {
+			init_reg_val = reg_val & 0xfe;
+			pr_debug("enabling video check interrupts\n");
+			lt9611_write(pdata, 0x00, init_reg_val);
+		}
+		lt9611_write(pdata, 0x04, 0xff); /* clear */
+		lt9611_write(pdata, 0x04, 0xfe);
+	}
+
+	if (interrupts & CFG_HPD_INTERRUPTS) {
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x03, &reg_val, 1);
+
+		if (reg_val & 0xc0) { //reg_val | 0xc0???
+			init_reg_val = reg_val & 0x3f;
+			pr_debug("enabling hpd interrupts\n");
+			lt9611_write(pdata, 0x03, init_reg_val);
+		}
+
+		lt9611_write(pdata, 0x07, 0xff); //clear
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+
+end:
+	return ret;
+}
+
+static void lt9611_pcr_mk_debug(struct lt9611 *pdata)
+{
+	u8 m = 0, k1 = 0, k2 = 0, k3 = 0;
+
+	lt9611_write(pdata, 0xff, 0x83);
+	lt9611_read(pdata, 0xb4, &m, 1);
+	lt9611_read(pdata, 0xb5, &k1, 1);
+	lt9611_read(pdata, 0xb6, &k2, 1);
+	lt9611_read(pdata, 0xb7, &k3, 1);
+
+	pr_info("pcr mk:0x%x 0x%x 0x%x 0x%x\n",
+			m, k1, k2, k3);
+}
+
+static void lt9611_sleep_setup(struct lt9611 *pdata)
+{
+	struct lt9611_reg_cfg sleep_setup[] = {
+		{0xff, 0x80, 0}, //register I2C addr
+		{0x24, 0x76, 0},
+		{0x23, 0x01, 0},
+		{0xff, 0x81, 0}, //set addr pin as output
+		{0x57, 0x03, 0},
+		{0x49, 0x0b, 0},
+		{0xff, 0x81, 0}, //anlog power down
+		{0x51, 0x30, 0}, //disable IRQ
+		{0x02, 0x48, 0}, //MIPI Rx power down
+		{0x23, 0x80, 0},
+		{0x30, 0x00, 0},
+		{0x00, 0x01, 0}, //bandgap power down
+		{0x01, 0x00, 0}, //system clk power down
+	};
+
+	pr_err("sleep\n");
+
+	lt9611_write_array(pdata, sleep_setup, sizeof(sleep_setup));
+}
+
+static int lt9611_power_on(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+
+	pr_debug("power_on: on=%d\n", on);
+
+	if (on && !pdata->power_on) {
+		lt9611_write_array(pdata, lt9611_init_setup,
+			sizeof(lt9611_init_setup));
+
+		ret = lt9611_enable_interrupts(pdata, CFG_HPD_INTERRUPTS);
+		if (ret) {
+			pr_err("Failed to enable HPD intr %d\n", ret);
+			return ret;
+		}
+		pdata->power_on = true;
+	} else if (!on) {
+		lt9611_write(pdata, 0xff, 0x81);
+		lt9611_write(pdata, 0x30, 0x6a);
+
+		pdata->power_on = false;
+	}
+
+	return ret;
+}
+
+static int lt9611_video_on(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+	struct lt9611_video_cfg *cfg = &pdata->video_cfg;
+
+	pr_debug("on=%d\n", on);
+
+	if (on) {
+		lt9611_mipi_input_analog(pdata, cfg);
+		lt9611_mipi_input_digital(pdata, cfg);
+		lt9611_pll_setup(pdata, cfg);
+		lt9611_mipi_video_setup(pdata, cfg);
+		lt9611_pcr_setup(pdata, cfg);
+		lt9611_hdmi_tx_digital(pdata, cfg);
+		lt9611_hdmi_tx_phy(pdata, cfg);
+
+		msleep(500);
+
+		lt9611_video_check(pdata);
+		lt9611_hdmi_output_enable(pdata);
+	} else {
+		lt9611_hdmi_output_disable(pdata);
+	}
+
+	return ret;
+}
+
+static void lt9611_mipi_byte_clk_debug(struct lt9611 *pdata)
+{
+	u8 reg_val = 0;
+	u32 byte_clk;
+
+	/* port A byte clk meter */
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xc7, 0x03); /* port A */
+	msleep(50);
+	lt9611_read(pdata, 0xcd, &reg_val, 1);
+
+	if ((reg_val & 0x60) == 0x60) {
+		byte_clk =  (reg_val & 0x0f) * 65536;
+		lt9611_read(pdata, 0xce, &reg_val, 1);
+		byte_clk = byte_clk + reg_val * 256;
+		lt9611_read(pdata, 0xcf, &reg_val, 1);
+		byte_clk = byte_clk + reg_val;
+
+		pr_info("port A byte clk = %d khz,\n", byte_clk);
+	} else
+		pr_info("port A byte clk unstable\n");
+
+	/* port B byte clk meter */
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xc7, 0x04); /* port B */
+	msleep(50);
+	lt9611_read(pdata, 0xcd, &reg_val, 1);
+
+	if ((reg_val & 0x60) == 0x60) {
+		byte_clk =  (reg_val & 0x0f) * 65536;
+		lt9611_read(pdata, 0xce, &reg_val, 1);
+		byte_clk = byte_clk + reg_val * 256;
+		lt9611_read(pdata, 0xcf, &reg_val, 1);
+		byte_clk = byte_clk + reg_val;
+
+		pr_info("port B byte clk = %d khz,\n", byte_clk);
+	} else
+		pr_info("port B byte clk unstable\n");
+}
+
+static void lt9611_reset(struct lt9611 *pdata)
+{
+	gpio_set_value(pdata->reset_gpio, 1);
+	msleep(20);
+	gpio_set_value(pdata->reset_gpio, 0);
+	msleep(20);
+	gpio_set_value(pdata->reset_gpio, 1);
+	msleep(20);
+}
+
+static void lt9611_assert_5v(struct lt9611 *pdata)
+{
+	if (gpio_is_valid(pdata->hdmi_en_gpio)) {
+		gpio_set_value(pdata->hdmi_en_gpio, 1);
+		msleep(20);
+	}
+}
+
+static int lt9611_config_vreg(struct device *dev,
+	struct lt9611_vreg *in_vreg, int num_vreg, bool config)
+{
+	int i = 0, rc = 0;
+	struct lt9611_vreg *curr_vreg = NULL;
+
+	if (!in_vreg || !num_vreg)
+		return rc;
+
+	if (config) {
+		for (i = 0; i < num_vreg; i++) {
+			curr_vreg = &in_vreg[i];
+			curr_vreg->vreg = regulator_get(dev,
+					curr_vreg->vreg_name);
+			rc = PTR_RET(curr_vreg->vreg);
+			if (rc) {
+				pr_err("%s get failed. rc=%d\n",
+						curr_vreg->vreg_name, rc);
+				curr_vreg->vreg = NULL;
+				goto vreg_get_fail;
+			}
+
+			rc = regulator_set_voltage(
+					curr_vreg->vreg,
+					curr_vreg->min_voltage,
+					curr_vreg->max_voltage);
+			if (rc < 0) {
+				pr_err("%s set vltg fail\n",
+						curr_vreg->vreg_name);
+				goto vreg_set_voltage_fail;
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--) {
+			curr_vreg = &in_vreg[i];
+			if (curr_vreg->vreg) {
+				regulator_set_voltage(curr_vreg->vreg,
+						0, curr_vreg->max_voltage);
+
+				regulator_put(curr_vreg->vreg);
+				curr_vreg->vreg = NULL;
+			}
+		}
+	}
+	return 0;
+
+vreg_unconfig:
+	regulator_set_load(curr_vreg->vreg, 0);
+
+vreg_set_voltage_fail:
+	regulator_put(curr_vreg->vreg);
+	curr_vreg->vreg = NULL;
+
+vreg_get_fail:
+	for (i--; i >= 0; i--) {
+		curr_vreg = &in_vreg[i];
+		goto vreg_unconfig;
+	}
+	return rc;
+}
+
+static int lt9611_get_dt_supply(struct device *dev,
+		struct lt9611 *pdata)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *of_node = NULL, *supply_root_node = NULL;
+	struct device_node *supply_node = NULL;
+
+	if (!dev || !pdata) {
+		pr_err("invalid input param dev:%pK pdata:%pK\n", dev, pdata);
+		return -EINVAL;
+	}
+
+	of_node = dev->of_node;
+
+	pdata->num_vreg = 0;
+	supply_root_node = of_get_child_by_name(of_node,
+			"lt,supply-entries");
+	if (!supply_root_node) {
+		pr_info("no supply entry present\n");
+		return 0;
+	}
+
+	pdata->num_vreg = of_get_available_child_count(supply_root_node);
+	if (pdata->num_vreg == 0) {
+		pr_info("no vreg present\n");
+		return 0;
+	}
+
+	pr_debug("vreg found. count=%d\n", pdata->num_vreg);
+	pdata->vreg_config = devm_kzalloc(dev, sizeof(struct lt9611_vreg) *
+			pdata->num_vreg, GFP_KERNEL);
+	if (!pdata->vreg_config)
+		return -ENOMEM;
+
+	for_each_available_child_of_node(supply_root_node, supply_node) {
+		const char *st = NULL;
+
+		rc = of_property_read_string(supply_node,
+				"lt,supply-name", &st);
+		if (rc) {
+			pr_err("error reading name. rc=%d\n", rc);
+			goto error;
+		}
+
+		strlcpy(pdata->vreg_config[i].vreg_name, st,
+				sizeof(pdata->vreg_config[i].vreg_name));
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-min-voltage", &tmp);
+		if (rc) {
+			pr_err("error reading min volt. rc=%d\n", rc);
+			goto error;
+		}
+		pdata->vreg_config[i].min_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-max-voltage", &tmp);
+		if (rc) {
+			pr_err("error reading max volt. rc=%d\n", rc);
+			goto error;
+		}
+		pdata->vreg_config[i].max_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-enable-load", &tmp);
+		if (rc)
+			pr_debug("no supply enable load value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].enable_load = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-disable-load", &tmp);
+		if (rc)
+			pr_debug("no supply disable load value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].disable_load = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-pre-on-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply pre on sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-pre-off-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply pre off sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-post-on-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply post on sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-post-off-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply post off sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+		pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+				pdata->vreg_config[i].vreg_name,
+				pdata->vreg_config[i].min_voltage,
+				pdata->vreg_config[i].max_voltage,
+				pdata->vreg_config[i].enable_load,
+				pdata->vreg_config[i].disable_load,
+				pdata->vreg_config[i].pre_on_sleep,
+				pdata->vreg_config[i].post_on_sleep,
+				pdata->vreg_config[i].pre_off_sleep,
+				pdata->vreg_config[i].post_off_sleep);
+		++i;
+
+		rc = 0;
+	}
+
+	rc = lt9611_config_vreg(dev,
+			pdata->vreg_config, pdata->num_vreg, true);
+	if (rc)
+		goto error;
+
+	return rc;
+
+error:
+	if (pdata->vreg_config) {
+		devm_kfree(dev, pdata->vreg_config);
+		pdata->vreg_config = NULL;
+		pdata->num_vreg = 0;
+	}
+
+	return rc;
+}
+
+static void lt9611_put_dt_supply(struct device *dev,
+		struct lt9611 *pdata)
+{
+	if (!dev || !pdata) {
+		pr_err("invalid input param dev:%pK pdata:%pK\n", dev, pdata);
+		return;
+	}
+
+	lt9611_config_vreg(dev,
+			pdata->vreg_config, pdata->num_vreg, false);
+
+	if (pdata->vreg_config) {
+		devm_kfree(dev, pdata->vreg_config);
+		pdata->vreg_config = NULL;
+	}
+	pdata->num_vreg = 0;
+}
+
+static int lt9611_enable_vreg(struct lt9611 *pdata, int enable)
+{
+	int i = 0, rc = 0;
+	bool need_sleep;
+	struct lt9611_vreg *in_vreg = pdata->vreg_config;
+	int num_vreg = pdata->num_vreg;
+
+	if (enable) {
+		for (i = 0; i < num_vreg; i++) {
+			rc = PTR_RET(in_vreg[i].vreg);
+			if (rc) {
+				pr_err("%s regulator error. rc=%d\n",
+						in_vreg[i].vreg_name, rc);
+				goto vreg_set_opt_mode_fail;
+			}
+			need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
+			if (in_vreg[i].pre_on_sleep && need_sleep)
+				usleep_range(in_vreg[i].pre_on_sleep * 1000,
+						in_vreg[i].pre_on_sleep * 1000);
+			rc = regulator_set_load(in_vreg[i].vreg,
+					in_vreg[i].enable_load);
+			if (rc < 0) {
+				pr_err("%s set opt m fail\n",
+						in_vreg[i].vreg_name);
+				goto vreg_set_opt_mode_fail;
+			}
+			rc = regulator_enable(in_vreg[i].vreg);
+			if (in_vreg[i].post_on_sleep && need_sleep)
+				usleep_range(in_vreg[i].post_on_sleep * 1000,
+					in_vreg[i].post_on_sleep * 1000);
+			if (rc < 0) {
+				pr_err("%s enable failed\n",
+						in_vreg[i].vreg_name);
+				goto disable_vreg;
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--) {
+			if (in_vreg[i].pre_off_sleep)
+				usleep_range(in_vreg[i].pre_off_sleep * 1000,
+					in_vreg[i].pre_off_sleep * 1000);
+			regulator_set_load(in_vreg[i].vreg,
+					in_vreg[i].disable_load);
+			regulator_disable(in_vreg[i].vreg);
+			if (in_vreg[i].post_off_sleep)
+				usleep_range(in_vreg[i].post_off_sleep * 1000,
+					in_vreg[i].post_off_sleep * 1000);
+		}
+	}
+	return rc;
+
+disable_vreg:
+	regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load);
+
+vreg_set_opt_mode_fail:
+	for (i--; i >= 0; i--) {
+		if (in_vreg[i].pre_off_sleep)
+			usleep_range(in_vreg[i].pre_off_sleep * 1000,
+					in_vreg[i].pre_off_sleep * 1000);
+		regulator_set_load(in_vreg[i].vreg,
+				in_vreg[i].disable_load);
+		regulator_disable(in_vreg[i].vreg);
+		if (in_vreg[i].post_off_sleep)
+			usleep_range(in_vreg[i].post_off_sleep * 1000,
+					in_vreg[i].post_off_sleep * 1000);
+	}
+
+	return rc;
+}
+
+static struct lt9611_timing_info *lt9611_get_supported_timing(
+		struct drm_display_mode *mode) {
+	int i = 0;
+
+	while (lt9611_supp_timing_cfg[i].xres != 0xffff) {
+		if (lt9611_supp_timing_cfg[i].xres == mode->hdisplay &&
+			lt9611_supp_timing_cfg[i].yres == mode->vdisplay &&
+			lt9611_supp_timing_cfg[i].fps ==
+					drm_mode_vrefresh(mode)) {
+			return &lt9611_supp_timing_cfg[i];
+		}
+		i++;
+	}
+
+	return NULL;
+}
+
+/* TODO: intf/lane number needs info from both DSI host and client */
+static int lt9611_get_intf_num(struct lt9611 *pdata,
+	struct drm_display_mode *mode)
+{
+	int num_of_intfs = 0;
+	struct lt9611_timing_info *timing =
+			lt9611_get_supported_timing(mode);
+
+	if (timing)
+		num_of_intfs = timing->intfs;
+	else {
+		pr_err("interface number not defined by bridge chip\n");
+		num_of_intfs = 0;
+	}
+
+	return num_of_intfs;
+}
+
+static int lt9611_get_lane_num(struct lt9611 *pdata,
+	struct drm_display_mode *mode)
+{
+	int num_of_lanes = 0;
+	struct lt9611_timing_info *timing =
+				lt9611_get_supported_timing(mode);
+
+	if (timing)
+		num_of_lanes = timing->lanes;
+	else {
+		pr_err("lane number not defined by bridge chip\n");
+		num_of_lanes = 0;
+	}
+
+	return num_of_lanes;
+}
+
+static void lt9611_get_video_cfg(struct lt9611 *pdata,
+	struct drm_display_mode *mode,
+	struct lt9611_video_cfg *video_cfg)
+{
+	int rc = 0;
+	struct hdmi_avi_infoframe avi_frame;
+
+	memset(&avi_frame, 0, sizeof(avi_frame));
+
+	video_cfg->h_active = mode->hdisplay;
+	video_cfg->v_active = mode->vdisplay;
+	video_cfg->h_front_porch = mode->hsync_start - mode->hdisplay;
+	video_cfg->v_front_porch = mode->vsync_start - mode->vdisplay;
+	video_cfg->h_back_porch = mode->htotal - mode->hsync_end;
+	video_cfg->v_back_porch = mode->vtotal - mode->vsync_end;
+	video_cfg->h_pulse_width = mode->hsync_end - mode->hsync_start;
+	video_cfg->v_pulse_width = mode->vsync_end - mode->vsync_start;
+	video_cfg->pclk_khz = mode->clock;
+
+	video_cfg->h_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	video_cfg->v_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	video_cfg->num_of_lanes = lt9611_get_lane_num(pdata, mode);
+	video_cfg->num_of_intfs = lt9611_get_intf_num(pdata, mode);
+
+	pr_debug("video=h[%d,%d,%d,%d] v[%d,%d,%d,%d] pclk=%d lane=%d intf=%d\n",
+		video_cfg->h_active, video_cfg->h_front_porch,
+		video_cfg->h_pulse_width, video_cfg->h_back_porch,
+		video_cfg->v_active, video_cfg->v_front_porch,
+		video_cfg->v_pulse_width, video_cfg->v_back_porch,
+		video_cfg->pclk_khz, video_cfg->num_of_lanes,
+		video_cfg->num_of_intfs);
+
+	rc = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, mode);
+	if (rc) {
+		pr_err("get avi frame failed ret=%d\n", rc);
+	} else {
+		video_cfg->scaninfo = avi_frame.scan_mode;
+		video_cfg->ar = avi_frame.picture_aspect;
+		video_cfg->vic = avi_frame.video_code;
+		pr_debug("scaninfo=%d ar=%d vic=%d\n",
+			video_cfg->scaninfo, video_cfg->ar, video_cfg->vic);
+	}
+}
+
+/* connector funcs */
+static enum drm_connector_status
+lt9611_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct lt9611 *pdata = connector_to_lt9611(connector);
+
+	if (!pdata->non_pluggable) {
+		u8 reg_val = 0;
+		int connected = 0;
+
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x5e, &reg_val, 1);
+		connected  = (reg_val & BIT(2));
+		pr_debug("connected = %x\n", connected);
+
+		pdata->status = connected ?  connector_status_connected :
+					connector_status_disconnected;
+	} else
+		pdata->status = connector_status_connected;
+
+	return pdata->status;
+}
+
+static int lt9611_read_edid(struct lt9611 *pdata)
+{
+	int ret = 0;
+	u8 i, j;
+	u8 temp = 0;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	memset(pdata->edid_buf, 0, EDID_SEG_SIZE);
+
+	lt9611_write(pdata, 0xff, 0x85);
+	lt9611_write(pdata, 0x03, 0xc9);
+	lt9611_write(pdata, 0x04, 0xa0); /* 0xA0 is EDID device address */
+	lt9611_write(pdata, 0x05, 0x00); /* 0x00 is EDID offset address */
+	lt9611_write(pdata, 0x06, 0x20); /* length for read */
+	lt9611_write(pdata, 0x14, 0x7f);
+
+	for (i = 0 ; i < 8 ; i++) {
+		lt9611_write(pdata, 0x05, i * 32); /* offset address */
+		lt9611_write(pdata, 0x07, 0x36);
+		lt9611_write(pdata, 0x07, 0x31);
+		lt9611_write(pdata, 0x07, 0x37);
+		usleep_range(5000, 10000);
+
+		lt9611_read(pdata, 0x40, &temp, 1);
+
+		if (temp & 0x02) {  /*KEY_DDC_ACCS_DONE=1*/
+			for (j = 0; j < 32; j++) {
+				lt9611_read(pdata, 0x83,
+					&(pdata->edid_buf[i*32+j]), 1);
+			}
+		} else if (temp & 0x50) { /* DDC No Ack or Abitration lost */
+			pr_err("read edid failed: no ack\n");
+			ret = -EIO;
+			goto end;
+		} else {
+			pr_err("read edid failed: access not done\n");
+			ret = -EIO;
+			goto end;
+		}
+	}
+
+	pr_debug("read edid succeeded, checksum = 0x%x\n",
+		pdata->edid_buf[255]);
+
+end:
+	lt9611_write(pdata, 0x07, 0x1f);
+	return ret;
+}
+
+/* TODO: add support for more extenstion blocks */
+static int lt9611_get_edid_block(void *data, u8 *buf, unsigned int block,
+				  size_t len)
+{
+	struct lt9611 *pdata = data;
+	int ret = 0;
+
+	pr_debug("get edid block: block=%d, len=%d\n", block, (int)len);
+
+	if (len > 128)
+		return -EINVAL;
+
+	/* support up to 1 extension block */
+	if (block > 1)
+		return -EINVAL;
+
+	if (block == 0) {
+		/* always read 2 edid blocks once */
+		ret = lt9611_read_edid(pdata);
+		if (ret) {
+			pr_err("edid read failed\n");
+			return ret;
+		}
+	}
+
+	if (block % 2 == 0)
+		memcpy(buf, pdata->edid_buf, len);
+	else
+		memcpy(buf, pdata->edid_buf + 128, len);
+
+	return 0;
+}
+
+static int lt9611_connector_get_modes(struct drm_connector *connector)
+{
+	struct lt9611 *pdata = connector_to_lt9611(connector);
+	struct drm_display_mode *mode, *m;
+	unsigned int count = 0;
+
+	pr_debug("get modes\n");
+
+	if (pdata->non_pluggable) {
+		list_for_each_entry(mode, &pdata->mode_list, head) {
+			m = drm_mode_duplicate(connector->dev, mode);
+			if (!m) {
+				pr_err("failed to add hdmi mode %dx%d\n",
+					mode->hdisplay, mode->vdisplay);
+				break;
+			}
+			drm_mode_probed_add(connector, m);
+		}
+		count = pdata->num_of_modes;
+	} else {
+		struct edid *edid;
+
+		if (!pdata->power_on)
+			lt9611_power_on(pdata, true);
+		edid = drm_do_get_edid(connector, lt9611_get_edid_block, pdata);
+
+		drm_mode_connector_update_edid_property(connector, edid);
+		count = drm_add_edid_modes(connector, edid);
+
+		pdata->hdmi_mode = drm_detect_hdmi_monitor(edid);
+		pr_debug("hdmi_mode = %d\n", pdata->hdmi_mode);
+
+		/* TODO: this should not be hard coded */
+		drm_set_preferred_mode(connector, 1920, 1080);
+
+		kfree(edid);
+	}
+
+	return count;
+}
+
+static enum drm_mode_status lt9611_connector_mode_valid(
+	struct drm_connector *connector, struct drm_display_mode *mode)
+{
+	struct lt9611_timing_info *timing =
+			lt9611_get_supported_timing(mode);
+
+	return timing ? MODE_OK : MODE_BAD;
+}
+
+/* bridge funcs */
+static void lt9611_bridge_enable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge enable\n");
+
+	if (lt9611_power_on(pdata, true)) {
+		pr_err("power on failed\n");
+		return;
+	}
+
+	if (lt9611_video_on(pdata, true)) {
+		pr_err("video on failed\n");
+		return;
+	}
+}
+
+static void lt9611_bridge_disable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge disable\n");
+
+	if (lt9611_video_on(pdata, false)) {
+		pr_err("video on failed\n");
+		return;
+	}
+
+	if (lt9611_power_on(pdata, false)) {
+		pr_err("power on failed\n");
+		return;
+	}
+}
+
+static void lt9611_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adj_mode)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+	struct lt9611_video_cfg *video_cfg = &pdata->video_cfg;
+	int ret = 0;
+
+	pr_debug("bridge mode_set: hdisplay=%d, vdisplay=%d, vrefresh=%d, clock=%d\n",
+		adj_mode->hdisplay, adj_mode->vdisplay,
+		adj_mode->vrefresh, adj_mode->clock);
+
+	drm_mode_copy(&pdata->curr_mode, adj_mode);
+
+	memset(video_cfg, 0, sizeof(struct lt9611_video_cfg));
+	lt9611_get_video_cfg(pdata, adj_mode, video_cfg);
+
+	/* TODO: update intf number of host */
+	if (video_cfg->num_of_lanes != pdata->dsi->lanes) {
+		mipi_dsi_detach(pdata->dsi);
+		pdata->dsi->lanes = video_cfg->num_of_lanes;
+		ret = mipi_dsi_attach(pdata->dsi);
+		if (ret)
+			pr_err("failed to change host lanes\n");
+	}
+}
+
+static int lt9611_bridge_attach(struct drm_bridge *bridge)
+{
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *dsi;
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "lt9611",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+
+	pr_debug("bridge attach\n");
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	host = of_find_mipi_dsi_host_by_node(pdata->host_node);
+	if (!host) {
+		pr_err("failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		pr_err("failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_BLLP |
+			  MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		pr_err("failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	pdata->dsi = dsi;
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+	return ret;
+}
+
+static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge pre_enable\n");
+
+	lt9611_reset(pdata);
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0xee, 0x01);
+}
+
+static bool lt9611_bridge_mode_fixup(struct drm_bridge *bridge,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	pr_debug("bridge mode_fixup\n");
+
+	return true;
+}
+
+static void lt9611_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge post_disable\n");
+
+	lt9611_sleep_setup(pdata);
+}
+
+static struct drm_connector_funcs override_funcs;
+static struct drm_connector_helper_funcs override_helper_private;
+
+static int lt9611_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector)
+{
+	pr_debug("bridge connector_init\n");
+
+	if (connector->encoder != bridge->encoder) {
+		pr_err("bridge and connector need attach to the same encoder\n");
+		return -EINVAL;
+	}
+
+	connector->private = bridge;
+
+	/*
+	 * Make a copy of drm_connector_funcs and drm_connector_helper_funcs. To
+	 * make sure other KMS components won't be broken. For example, if other
+	 * connectors share the implementation for ->funs, overwriting this will
+	 * break other connectors.
+	 */
+	override_funcs = *connector->funcs;
+	override_funcs.detect = lt9611_connector_detect;
+	connector->funcs = &override_funcs;
+
+	override_helper_private = *connector->helper_private;
+	override_helper_private.get_modes = lt9611_connector_get_modes;
+	override_helper_private.mode_valid = lt9611_connector_mode_valid;
+	connector->helper_private = &override_helper_private;
+
+	return 0;
+}
+
+static const struct drm_bridge_funcs lt9611_bridge_funcs = {
+	.attach = lt9611_bridge_attach,
+	.mode_fixup   = lt9611_bridge_mode_fixup,
+	.pre_enable   = lt9611_bridge_pre_enable,
+	.enable = lt9611_bridge_enable,
+	.disable = lt9611_bridge_disable,
+	.post_disable = lt9611_bridge_post_disable,
+	.mode_set = lt9611_bridge_mode_set,
+	.connector_init = lt9611_bridge_connector_init,
+};
+
+/* sysfs */
+static int lt9611_dump_debug_info(struct lt9611 *pdata)
+{
+	if (!pdata->power_on) {
+		pr_err("device is not power on\n");
+		return -EINVAL;
+	}
+
+	lt9611_video_check(pdata);
+
+	lt9611_pcr_mk_debug(pdata);
+
+	lt9611_mipi_byte_clk_debug(pdata);
+
+	return 0;
+}
+
+static ssize_t lt9611_dump_info_wta_attr(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t count)
+{
+	struct lt9611 *pdata = dev_get_drvdata(dev);
+
+	if (!pdata) {
+		pr_err("pdata is NULL\n");
+		return -EINVAL;
+	}
+
+	lt9611_dump_debug_info(pdata);
+
+	return count;
+}
+
+static DEVICE_ATTR(dump_info, 0200, NULL, lt9611_dump_info_wta_attr);
+
+static struct attribute *lt9611_sysfs_attrs[] = {
+	&dev_attr_dump_info.attr,
+	NULL,
+};
+
+static struct attribute_group lt9611_sysfs_attr_grp = {
+	.attrs = lt9611_sysfs_attrs,
+};
+
+static int lt9611_sysfs_init(struct device *dev)
+{
+	int rc = 0;
+
+	if (!dev) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = sysfs_create_group(&dev->kobj, &lt9611_sysfs_attr_grp);
+	if (rc)
+		pr_err("%s: sysfs group creation failed %d\n", __func__, rc);
+
+	return rc;
+}
+
+static void lt9611_sysfs_remove(struct device *dev)
+{
+	if (!dev) {
+		pr_err("%s: Invalid params\n", __func__);
+		return;
+	}
+
+	sysfs_remove_group(&dev->kobj, &lt9611_sysfs_attr_grp);
+}
+
+static int lt9611_probe(struct i2c_client *client,
+	 const struct i2c_device_id *id)
+{
+	struct lt9611 *pdata;
+	int ret = 0;
+
+	if (!client || !client->dev.of_node) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("device doesn't support I2C\n");
+		return -ENODEV;
+	}
+
+	pdata = devm_kzalloc(&client->dev,
+		sizeof(struct lt9611), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	ret = lt9611_parse_dt(&client->dev, pdata);
+	if (ret) {
+		pr_err("failed to parse device tree\n");
+		goto err_dt_parse;
+	}
+
+	ret = lt9611_get_dt_supply(&client->dev, pdata);
+	if (ret) {
+		pr_err("failed to get dt supply\n");
+		goto err_dt_parse;
+	}
+
+	pdata->dev = &client->dev;
+	pdata->i2c_client = client;
+	pr_debug("I2C address is %x\n", client->addr);
+
+	ret = lt9611_gpio_configure(pdata, true);
+	if (ret) {
+		pr_err("failed to configure GPIOs\n");
+		goto err_dt_supply;
+	}
+
+	lt9611_assert_5v(pdata);
+
+	ret = lt9611_enable_vreg(pdata, true);
+	if (ret) {
+		pr_err("failed to enable vreg\n");
+		goto err_dt_supply;
+	}
+
+	lt9611_reset(pdata);
+
+	ret = lt9611_read_device_rev(pdata);
+	if (ret) {
+		pr_err("failed to read chip rev\n");
+		goto err_i2c_prog;
+	}
+
+	pdata->irq = gpio_to_irq(pdata->irq_gpio);
+	ret = request_threaded_irq(pdata->irq, NULL, lt9611_irq_thread_handler,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lt9611", pdata);
+	if (ret) {
+		pr_err("failed to request irq\n");
+		goto err_i2c_prog;
+	}
+
+	i2c_set_clientdata(client, pdata);
+	dev_set_drvdata(&client->dev, pdata);
+
+	ret = lt9611_sysfs_init(&client->dev);
+	if (ret) {
+		pr_err("sysfs init failed\n");
+		goto err_sysfs_init;
+	}
+
+	pdata->bridge.funcs = &lt9611_bridge_funcs;
+	pdata->bridge.of_node = client->dev.of_node;
+
+	drm_bridge_add(&pdata->bridge);
+
+	return ret;
+
+err_sysfs_init:
+	disable_irq(pdata->irq);
+	free_irq(pdata->irq, pdata);
+err_i2c_prog:
+	lt9611_gpio_configure(pdata, false);
+err_dt_supply:
+	lt9611_put_dt_supply(&client->dev, pdata);
+err_dt_parse:
+	devm_kfree(&client->dev, pdata);
+	return ret;
+}
+
+static int lt9611_remove(struct i2c_client *client)
+{
+	int ret = -EINVAL;
+	struct lt9611 *pdata = i2c_get_clientdata(client);
+	struct drm_display_mode *mode, *n;
+
+	if (!pdata)
+		goto end;
+
+	mipi_dsi_detach(pdata->dsi);
+	mipi_dsi_device_unregister(pdata->dsi);
+
+	drm_bridge_remove(&pdata->bridge);
+
+	lt9611_sysfs_remove(&client->dev);
+
+	disable_irq(pdata->irq);
+	free_irq(pdata->irq, pdata);
+
+	ret = lt9611_gpio_configure(pdata, false);
+
+	lt9611_put_dt_supply(&client->dev, pdata);
+
+	if (pdata->non_pluggable) {
+		list_for_each_entry_safe(mode, n, &pdata->mode_list, head) {
+			list_del(&mode->head);
+			kfree(mode);
+		}
+	}
+
+	devm_kfree(&client->dev, pdata);
+
+end:
+	return ret;
+}
+
+
+static struct i2c_device_id lt9611_id[] = {
+	{ "lt,lt9611", 0},
+	{}
+};
+
+static const struct of_device_id lt9611_match_table[] = {
+	{.compatible = "lt,lt9611"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, lt9611_match_table);
+
+static struct i2c_driver lt9611_driver = {
+	.driver = {
+		.name = "lt9611",
+		.owner = THIS_MODULE,
+		.of_match_table = lt9611_match_table,
+	},
+	.probe = lt9611_probe,
+	.remove = lt9611_remove,
+	.id_table = lt9611_id,
+};
+
+static int __init lt9611_init(void)
+{
+	return i2c_add_driver(&lt9611_driver);
+}
+
+static void __exit lt9611_exit(void)
+{
+	i2c_del_driver(&lt9611_driver);
+}
+
+module_init(lt9611_init);
+module_exit(lt9611_exit);
+
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 44d476e..f64f35c 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -97,7 +97,7 @@
 #define DP0_ACTIVEVAL		0x0650
 #define DP0_SYNCVAL		0x0654
 #define DP0_MISC		0x0658
-#define TU_SIZE_RECOMMENDED		(0x3f << 16) /* LSCLK cycles per TU */
+#define TU_SIZE_RECOMMENDED		(63) /* LSCLK cycles per TU */
 #define BPC_6				(0 << 5)
 #define BPC_8				(1 << 5)
 
@@ -318,7 +318,7 @@
 				tmp = (tmp << 8) | buf[i];
 			i++;
 			if (((i % 4) == 0) || (i == size)) {
-				tc_write(DP0_AUXWDATA(i >> 2), tmp);
+				tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
 				tmp = 0;
 			}
 		}
@@ -603,8 +603,15 @@
 	ret = drm_dp_link_probe(&tc->aux, &tc->link.base);
 	if (ret < 0)
 		goto err_dpcd_read;
-	if ((tc->link.base.rate != 162000) && (tc->link.base.rate != 270000))
-		goto err_dpcd_inval;
+	if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) {
+		dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n");
+		tc->link.base.rate = 270000;
+	}
+
+	if (tc->link.base.num_lanes > 2) {
+		dev_dbg(tc->dev, "Falling to 2 lanes\n");
+		tc->link.base.num_lanes = 2;
+	}
 
 	ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp);
 	if (ret < 0)
@@ -637,9 +644,6 @@
 err_dpcd_read:
 	dev_err(tc->dev, "failed to read DPCD: %d\n", ret);
 	return ret;
-err_dpcd_inval:
-	dev_err(tc->dev, "invalid DPCD\n");
-	return -EINVAL;
 }
 
 static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)
@@ -655,6 +659,14 @@
 	int lower_margin = mode->vsync_start - mode->vdisplay;
 	int vsync_len = mode->vsync_end - mode->vsync_start;
 
+	/*
+	 * Recommended maximum number of symbols transferred in a transfer unit:
+	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
+	 *              (output active video bandwidth in bytes))
+	 * Must be less than tu_size.
+	 */
+	max_tu_symbol = TU_SIZE_RECOMMENDED - 1;
+
 	dev_dbg(tc->dev, "set mode %dx%d\n",
 		mode->hdisplay, mode->vdisplay);
 	dev_dbg(tc->dev, "H margin %d,%d sync %d\n",
@@ -664,13 +676,18 @@
 	dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal);
 
 
-	/* LCD Ctl Frame Size */
-	tc_write(VPCTRL0, (0x40 << 20) /* VSDELAY */ |
+	/*
+	 * LCD Ctl Frame Size
+	 * datasheet is not clear of vsdelay in case of DPI
+	 * assume we do not need any delay when DPI is a source of
+	 * sync signals
+	 */
+	tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
 		 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-	tc_write(HTIM01, (left_margin << 16) |		/* H back porch */
-			 (hsync_len << 0));		/* Hsync */
-	tc_write(HTIM02, (right_margin << 16) |		/* H front porch */
-			 (mode->hdisplay << 0));	/* width */
+	tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
+			 (ALIGN(hsync_len, 2) << 0));	 /* Hsync */
+	tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
+			 (ALIGN(mode->hdisplay, 2) << 0)); /* width */
 	tc_write(VTIM01, (upper_margin << 16) |		/* V back porch */
 			 (vsync_len << 0));		/* Vsync */
 	tc_write(VTIM02, (lower_margin << 16) |		/* V front porch */
@@ -689,7 +706,7 @@
 	/* DP Main Stream Attributes */
 	vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
 	tc_write(DP0_VIDSYNCDELAY,
-		 (0x003e << 16) |	/* thresh_dly */
+		 (max_tu_symbol << 16) |	/* thresh_dly */
 		 (vid_sync_dly << 0));
 
 	tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal));
@@ -705,14 +722,8 @@
 	tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
 		 DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
 
-	/*
-	 * Recommended maximum number of symbols transferred in a transfer unit:
-	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
-	 *              (output active video bandwidth in bytes))
-	 * Must be less than tu_size.
-	 */
-	max_tu_symbol = TU_SIZE_RECOMMENDED - 1;
-	tc_write(DP0_MISC, (max_tu_symbol << 23) | TU_SIZE_RECOMMENDED | BPC_8);
+	tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) |
+			   BPC_8);
 
 	return 0;
 err:
@@ -808,8 +819,6 @@
 	unsigned int rate;
 	u32 dp_phy_ctrl;
 	int timeout;
-	bool aligned;
-	bool ready;
 	u32 value;
 	int ret;
 	u8 tmp[8];
@@ -954,16 +963,15 @@
 		ret = drm_dp_dpcd_read_link_status(aux, tmp + 2);
 		if (ret < 0)
 			goto err_dpcd_read;
-		ready = (tmp[2] == ((DP_CHANNEL_EQ_BITS << 4) | /* Lane1 */
-				     DP_CHANNEL_EQ_BITS));      /* Lane0 */
-		aligned = tmp[4] & DP_INTERLANE_ALIGN_DONE;
-	} while ((--timeout) && !(ready && aligned));
+	} while ((--timeout) &&
+		 !(drm_dp_channel_eq_ok(tmp + 2,  tc->link.base.num_lanes)));
 
 	if (timeout == 0) {
 		/* Read DPCD 0x200-0x201 */
 		ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2);
 		if (ret < 0)
 			goto err_dpcd_read;
+		dev_err(dev, "channel(s) EQ not ok\n");
 		dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]);
 		dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n",
 			 tmp[1]);
@@ -974,10 +982,6 @@
 		dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n",
 			 tmp[6]);
 
-		if (!ready)
-			dev_err(dev, "Lane0/1 not ready\n");
-		if (!aligned)
-			dev_err(dev, "Lane0/1 not aligned\n");
 		return -EAGAIN;
 	}
 
@@ -1105,7 +1109,10 @@
 static int tc_connector_mode_valid(struct drm_connector *connector,
 				   struct drm_display_mode *mode)
 {
-	/* Accept any mode */
+	/* DPI interface clock limitation: upto 154 MHz */
+	if (mode->clock > 154000)
+		return MODE_CLOCK_HIGH;
+
 	return MODE_OK;
 }
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b..70e8414 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -149,6 +149,32 @@
 EXPORT_SYMBOL(drm_bridge_detach);
 
 /**
+ * drm_bridge_connector_init - call bridge's connector_init callback to allow
+ *                     the bridge to update connector's behavior.
+ * @bridge: bridge control structure
+ * @connector: connector control structure
+ *
+ * Calls ->connector_init() &drm_bridge_funcs op for the bridge.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector)
+{
+	int ret = 0;
+
+	if (!bridge || !connector)
+		return -EINVAL;
+
+	if (bridge->funcs->connector_init)
+		ret = bridge->funcs->connector_init(bridge, connector);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_bridge_connector_init);
+
+/**
  * DOC: bridge callbacks
  *
  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 7fdc42e..74163a9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5063,6 +5063,12 @@
 	 */
 	final->t8 = 1;
 	final->t9 = 1;
+
+	/*
+	 * HW has only a 100msec granularity for t11_t12 so round it up
+	 * accordingly.
+	 */
+	final->t11_t12 = roundup(final->t11_t12, 100 * 10);
 }
 
 static void
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 79f2ec9..630b5fb 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -29,24 +29,54 @@
 	struct dp_aux dp_aux;
 	struct dp_catalog_aux *catalog;
 	struct dp_aux_cfg *cfg;
-
 	struct mutex mutex;
 	struct completion comp;
+	struct drm_dp_aux drm_aux;
 
-	u32 aux_error_num;
-	u32 retry_cnt;
 	bool cmd_busy;
 	bool native;
 	bool read;
 	bool no_send_addr;
 	bool no_send_stop;
+
 	u32 offset;
 	u32 segment;
+	u32 aux_error_num;
+	u32 retry_cnt;
+
 	atomic_t aborted;
 
-	struct drm_dp_aux drm_aux;
+	u8 *dpcd;
+	u8 *edid;
 };
 
+#ifdef CONFIG_DYNAMIC_DEBUG
+static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	DEFINE_DYNAMIC_DEBUG_METADATA(ddm, "dp aux tracker");
+
+	if (unlikely(ddm.flags & _DPRINTK_FLAGS_PRINT)) {
+		u8 buf[SZ_64];
+		struct dp_aux_private *aux = container_of(drm_aux,
+			struct dp_aux_private, drm_aux);
+
+		snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ",
+			aux->native ? "NATIVE" : "I2C",
+			aux->read ? "READ" : "WRITE",
+			msg->address, msg->size);
+
+		print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE,
+			8, 1, msg->buffer, msg->size, false);
+	}
+}
+#else
+static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+}
+#endif
+
 static char *dp_aux_get_error(u32 aux_error)
 {
 	switch (aux_error) {
@@ -320,6 +350,7 @@
  *
  * @aux: DP AUX private structure
  * @input_msg: input message from DRM upstream APIs
+ * @send_seg: send the seg to sink
  *
  * return: void
  *
@@ -327,7 +358,7 @@
  * sinks that do not handle the i2c middle-of-transaction flag correctly.
  */
 static void dp_aux_transfer_helper(struct dp_aux_private *aux,
-		struct drm_dp_aux_msg *input_msg)
+		struct drm_dp_aux_msg *input_msg, bool send_seg)
 {
 	struct drm_dp_aux_msg helper_msg;
 	u32 const message_size = 0x10;
@@ -346,7 +377,7 @@
 	 * duplicate AUX transactions related to this while reading the
 	 * first 16 bytes of each block.
 	 */
-	if (!(aux->offset % edid_block_length))
+	if (!(aux->offset % edid_block_length) || !send_seg)
 		goto end;
 
 	aux->read = false;
@@ -388,6 +419,110 @@
 		aux->segment = 0x0; /* reset segment at end of block */
 }
 
+static int dp_aux_transfer_ready(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg, bool send_seg)
+{
+	int ret = 0;
+	int const aux_cmd_native_max = 16;
+	int const aux_cmd_i2c_max = 128;
+
+	if (atomic_read(&aux->aborted)) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		goto error;
+	}
+
+	/* msg sanity check */
+	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+		(msg->size > aux_cmd_i2c_max)) {
+		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
+			__func__, msg->size, msg->request);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	dp_aux_update_offset_and_segment(aux, msg);
+
+	dp_aux_transfer_helper(aux, msg, send_seg);
+
+	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+	if (aux->read) {
+		aux->no_send_addr = true;
+		aux->no_send_stop = false;
+	} else {
+		aux->no_send_addr = true;
+		aux->no_send_stop = true;
+	}
+
+	aux->cmd_busy = true;
+error:
+	return ret;
+}
+
+static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u32 timeout;
+	ssize_t ret;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
+
+	ret = dp_aux_transfer_ready(aux, msg, false);
+	if (ret)
+		goto end;
+
+	aux->aux_error_num = DP_AUX_ERR_NONE;
+
+	if (aux->native) {
+		if (aux->read && ((msg->address + msg->size) < SZ_1K)) {
+			aux->dp_aux.reg = msg->address;
+
+			reinit_completion(&aux->comp);
+			timeout = wait_for_completion_timeout(&aux->comp, HZ);
+			if (!timeout)
+				pr_err("aux timeout for 0x%x\n", msg->address);
+
+			aux->dp_aux.reg = 0xFFFF;
+
+			memcpy(msg->buffer, aux->dpcd + msg->address,
+				msg->size);
+			aux->aux_error_num = DP_AUX_ERR_NONE;
+		} else {
+			memset(msg->buffer, 0, msg->size);
+		}
+	} else {
+		if (aux->read && msg->address == 0x50) {
+			memcpy(msg->buffer,
+				aux->edid + aux->offset - 16,
+				msg->size);
+		}
+	}
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		dp_aux_hex_dump(drm_aux, msg);
+
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+	}
+
+	ret = msg->size;
+end:
+	return ret;
+}
+
 /*
  * This function does the real job to process an AUX transaction.
  * It will call aux_reset() function to reset the AUX channel,
@@ -397,52 +532,21 @@
 		struct drm_dp_aux_msg *msg)
 {
 	ssize_t ret;
-	int const aux_cmd_native_max = 16;
-	int const aux_cmd_i2c_max = 128;
 	int const retry_count = 5;
 	struct dp_aux_private *aux = container_of(drm_aux,
 		struct dp_aux_private, drm_aux);
 
 	mutex_lock(&aux->mutex);
 
-	if (atomic_read(&aux->aborted)) {
-		ret = -ETIMEDOUT;
+	ret = dp_aux_transfer_ready(aux, msg, true);
+	if (ret)
 		goto unlock_exit;
-	}
 
-	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
-
-	/* Ignore address only message */
-	if ((msg->size == 0) || (msg->buffer == NULL)) {
-		msg->reply = aux->native ?
-			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	if (!aux->cmd_busy) {
 		ret = msg->size;
 		goto unlock_exit;
 	}
 
-	/* msg sanity check */
-	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
-		(msg->size > aux_cmd_i2c_max)) {
-		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
-			__func__, msg->size, msg->request);
-		ret = -EINVAL;
-		goto unlock_exit;
-	}
-
-	dp_aux_update_offset_and_segment(aux, msg);
-	dp_aux_transfer_helper(aux, msg);
-
-	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
-	aux->cmd_busy = true;
-
-	if (aux->read) {
-		aux->no_send_addr = true;
-		aux->no_send_stop = false;
-	} else {
-		aux->no_send_addr = true;
-		aux->no_send_stop = true;
-	}
-
 	ret = dp_aux_cmd_fifo_tx(aux, msg);
 	if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) {
 		aux->retry_cnt++;
@@ -459,6 +563,8 @@
 		if (aux->read)
 			dp_aux_cmd_fifo_rx(aux, msg);
 
+		dp_aux_hex_dump(drm_aux, msg);
+
 		msg->reply = aux->native ?
 			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 	} else {
@@ -558,6 +664,41 @@
 	drm_dp_aux_unregister(&aux->drm_aux);
 }
 
+static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	complete(&aux->comp);
+}
+
+static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
+		u8 *edid, u8 *dpcd)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->edid = edid;
+	aux->dpcd = dpcd;
+
+	if (en)
+		aux->drm_aux.transfer = dp_aux_transfer_debug;
+	else
+		aux->drm_aux.transfer = dp_aux_transfer;
+}
+
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
 		struct dp_aux_cfg *aux_cfg)
 {
@@ -586,6 +727,7 @@
 	aux->cfg = aux_cfg;
 	dp_aux = &aux->dp_aux;
 	aux->retry_cnt = 0;
+	aux->dp_aux.reg = 0xFFFF;
 
 	dp_aux->isr     = dp_aux_isr;
 	dp_aux->init    = dp_aux_init;
@@ -594,6 +736,8 @@
 	dp_aux->drm_aux_deregister = dp_aux_deregister;
 	dp_aux->reconfig = dp_aux_reconfig;
 	dp_aux->abort = dp_aux_abort_transaction;
+	dp_aux->dpcd_updated = dp_aux_dpcd_updated;
+	dp_aux->set_sim_mode = dp_aux_set_sim_mode;
 
 	return dp_aux;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index e8cb1cc..bf52d57 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,19 @@
 #include "dp_catalog.h"
 #include "drm_dp_helper.h"
 
+#define DP_STATE_NOTIFICATION_SENT          BIT(0)
+#define DP_STATE_TRAIN_1_STARTED            BIT(1)
+#define DP_STATE_TRAIN_1_SUCCEEDED          BIT(2)
+#define DP_STATE_TRAIN_1_FAILED             BIT(3)
+#define DP_STATE_TRAIN_2_STARTED            BIT(4)
+#define DP_STATE_TRAIN_2_SUCCEEDED          BIT(5)
+#define DP_STATE_TRAIN_2_FAILED             BIT(6)
+#define DP_STATE_CTRL_POWERED_ON            BIT(7)
+#define DP_STATE_CTRL_POWERED_OFF           BIT(8)
+#define DP_STATE_LINK_MAINTENANCE_STARTED   BIT(9)
+#define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10)
+#define DP_STATE_LINK_MAINTENANCE_FAILED    BIT(11)
+
 enum dp_aux_error {
 	DP_AUX_ERR_NONE	= 0,
 	DP_AUX_ERR_ADDR	= -1,
@@ -29,6 +42,9 @@
 };
 
 struct dp_aux {
+	u32 reg;
+	u32 state;
+
 	struct drm_dp_aux *drm_aux;
 	int (*drm_aux_register)(struct dp_aux *aux);
 	void (*drm_aux_deregister)(struct dp_aux *aux);
@@ -37,6 +53,8 @@
 	void (*deinit)(struct dp_aux *aux);
 	void (*reconfig)(struct dp_aux *aux);
 	void (*abort)(struct dp_aux *aux);
+	void (*dpcd_updated)(struct dp_aux *aux);
+	void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd);
 };
 
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index cfb4436..56a41b5 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,15 +23,12 @@
 #define DP_GET_MSB(x)	(x >> 8)
 #define DP_GET_LSB(x)	(x & 0xff)
 
-#define dp_read(offset) readl_relaxed((offset))
-#define dp_write(offset, data) writel_relaxed((data), (offset))
-
-#define dp_catalog_get_priv(x) { \
+#define dp_catalog_get_priv(x) ({ \
 	struct dp_catalog *dp_catalog; \
 	dp_catalog = container_of(x, struct dp_catalog, x); \
-	catalog = container_of(dp_catalog, struct dp_catalog_private, \
+	container_of(dp_catalog, struct dp_catalog_private, \
 				dp_catalog); \
-}
+})
 
 #define DP_INTERRUPT_STATUS1 \
 	(DP_INTR_AUX_I2C_DONE| \
@@ -48,6 +45,14 @@
 
 #define DP_INTR_MASK2		(DP_INTERRUPT_STATUS2 << 2)
 
+#define dp_catalog_fill_io(x) { \
+	catalog->io.x = parser->get_io(parser, #x); \
+}
+
+#define dp_catalog_fill_io_buf(x) { \
+	parser->get_io_buf(parser, #x); \
+}
+
 static u8 const vm_pre_emphasis[4][4] = {
 	{0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
 	{0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
@@ -63,30 +68,77 @@
 	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
 };
 
+struct dp_catalog_io {
+	struct dp_io_data *dp_ahb;
+	struct dp_io_data *dp_aux;
+	struct dp_io_data *dp_link;
+	struct dp_io_data *dp_p0;
+	struct dp_io_data *dp_phy;
+	struct dp_io_data *dp_ln_tx0;
+	struct dp_io_data *dp_ln_tx1;
+	struct dp_io_data *dp_mmss_cc;
+	struct dp_io_data *dp_pll;
+	struct dp_io_data *usb3_dp_com;
+	struct dp_io_data *hdcp_physical;
+};
+
 /* audio related catalog functions */
 struct dp_catalog_private {
 	struct device *dev;
-	struct dp_io *io;
+	struct dp_catalog_io io;
+	struct dp_parser *parser;
 
 	u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
 	struct dp_catalog dp_catalog;
+
+	char exe_mode[SZ_4];
 };
 
+static u32 dp_read(struct dp_catalog_private *catalog,
+		struct dp_io_data *io_data, u32 offset)
+{
+	u32 data = 0;
+
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		data = readl_relaxed(io_data->io.base + offset);
+	} else if (!strcmp(catalog->exe_mode, "sw")) {
+		if (io_data->buf)
+			memcpy(&data, io_data->buf + offset, sizeof(offset));
+	}
+
+	return data;
+}
+
+static void dp_write(struct dp_catalog_private *catalog,
+		struct dp_io_data *io_data, u32 offset, u32 data)
+{
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all"))
+		writel_relaxed(data, io_data->io.base + offset);
+
+	if (!strcmp(catalog->exe_mode, "sw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		if (io_data->buf)
+			memcpy(io_data->buf + offset, &data, sizeof(data));
+	}
+}
+
 /* aux related catalog functions */
 static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	return dp_read(base + DP_AUX_DATA);
+	return dp_read(catalog, io_data, DP_AUX_DATA);
 end:
 	return 0;
 }
@@ -95,7 +147,7 @@
 {
 	int rc = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -103,10 +155,10 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	dp_write(base + DP_AUX_DATA, aux->data);
+	dp_write(catalog, io_data, DP_AUX_DATA, aux->data);
 end:
 	return rc;
 }
@@ -115,7 +167,7 @@
 {
 	int rc = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -123,10 +175,10 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	dp_write(base + DP_AUX_TRANS_CTRL, aux->data);
+	dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, aux->data);
 end:
 	return rc;
 }
@@ -136,7 +188,7 @@
 	int rc = 0;
 	u32 data = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -144,15 +196,15 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
 	if (read) {
-		data = dp_read(base + DP_AUX_TRANS_CTRL);
+		data = dp_read(catalog, io_data, DP_AUX_TRANS_CTRL);
 		data &= ~BIT(9);
-		dp_write(base + DP_AUX_TRANS_CTRL, data);
+		dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, data);
 	} else {
-		dp_write(base + DP_AUX_TRANS_CTRL, 0);
+		dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, 0);
 	}
 end:
 	return rc;
@@ -161,7 +213,7 @@
 static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *phy_base;
+	struct dp_io_data *io_data;
 	u32 data = 0;
 
 	if (!aux) {
@@ -169,17 +221,16 @@
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	phy_base = catalog->io->phy_io.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_phy;
 
-	data = dp_read(phy_base + DP_PHY_AUX_INTERRUPT_STATUS);
-	pr_debug("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data);
+	data = dp_read(catalog, io_data, DP_PHY_AUX_INTERRUPT_STATUS);
 
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
 	wmb(); /* make sure 0x1f is written before next write */
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
 	wmb(); /* make sure 0x9f is written before next write */
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0);
 	wmb(); /* make sure register is cleared */
 }
 
@@ -187,24 +238,25 @@
 {
 	u32 aux_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	aux_ctrl = dp_read(base + DP_AUX_CTRL);
+	aux_ctrl = dp_read(catalog, io_data, DP_AUX_CTRL);
 
 	aux_ctrl |= BIT(1);
-	dp_write(base + DP_AUX_CTRL, aux_ctrl);
+	dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	usleep_range(1000, 1010); /* h/w recommended delay */
 
 	aux_ctrl &= ~BIT(1);
-	dp_write(base + DP_AUX_CTRL, aux_ctrl);
+
+	dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	wmb(); /* make sure AUX reset is done here */
 }
 
@@ -212,27 +264,27 @@
 {
 	u32 aux_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
-
+	struct dp_io_data *io_data;
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	aux_ctrl = dp_read(base + DP_AUX_CTRL);
+	aux_ctrl = dp_read(catalog, io_data, DP_AUX_CTRL);
 
 	if (enable) {
 		aux_ctrl |= BIT(0);
-		dp_write(base + DP_AUX_CTRL, aux_ctrl);
+		dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 		wmb(); /* make sure AUX module is enabled */
-		dp_write(base + DP_TIMEOUT_COUNT, 0xffff);
-		dp_write(base + DP_AUX_LIMITS, 0xffff);
+
+		dp_write(catalog, io_data, DP_TIMEOUT_COUNT, 0xffff);
+		dp_write(catalog, io_data, DP_AUX_LIMITS, 0xffff);
 	} else {
 		aux_ctrl &= ~BIT(0);
-		dp_write(base + DP_AUX_CTRL, aux_ctrl);
+		dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	}
 }
 
@@ -241,13 +293,16 @@
 {
 	struct dp_catalog_private *catalog;
 	u32 new_index = 0, current_index = 0;
+	struct dp_io_data *io_data;
 
 	if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
+	catalog = dp_catalog_get_priv(aux);
+
+	io_data = catalog->io.dp_phy;
 
 	current_index = cfg[type].current_index;
 	new_index = (current_index + 1) % cfg[type].cfg_cnt;
@@ -255,8 +310,7 @@
 		dp_phy_aux_config_type_to_string(type),
 	cfg[type].lut[current_index], cfg[type].lut[new_index]);
 
-	dp_write(catalog->io->phy_io.base + cfg[type].offset,
-			cfg[type].lut[new_index]);
+	dp_write(catalog, io_data, cfg[type].offset, cfg[type].lut[new_index]);
 	cfg[type].current_index = new_index;
 }
 
@@ -264,6 +318,7 @@
 		struct dp_aux_cfg *cfg)
 {
 	struct dp_catalog_private *catalog;
+	struct dp_io_data *io_data;
 	int i = 0;
 
 	if (!aux || !cfg) {
@@ -271,25 +326,32 @@
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
+	catalog = dp_catalog_get_priv(aux);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65);
+	io_data = catalog->io.dp_phy;
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x65);
 	wmb(); /* make sure PD programming happened */
 
 	/* Turn on BIAS current for PHY/PLL */
-	dp_write(catalog->io->dp_pll_io.base +
-		QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
+	io_data = catalog->io.dp_pll;
+	dp_write(catalog, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
+
+	io_data = catalog->io.dp_phy;
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x02);
+	wmb(); /* make sure PD programming happened */
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x7d);
+
+	/* Turn on BIAS current for PHY/PLL */
+	io_data = catalog->io.dp_pll;
+	dp_write(catalog, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
 
 	/* DP AUX CFG register programming */
-	for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
-		pr_debug("%s: offset=0x%08x, value=0x%08x\n",
-			dp_phy_aux_config_type_to_string(i),
-			cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
-		dp_write(catalog->io->phy_io.base + cfg[i].offset,
-			cfg[i].lut[cfg[i].current_index]);
-	}
+	io_data = catalog->io.dp_phy;
+	for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+		dp_write(catalog, io_data, cfg[i].offset,
+				cfg[i].lut[cfg[i].current_index]);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
 	wmb(); /* make sure AUX configuration is done before enabling it */
 }
 
@@ -297,46 +359,46 @@
 {
 	u32 ack;
 	struct dp_catalog_private *catalog;
-	void __iomem *ahb_base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	ahb_base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_ahb;
 
-	aux->isr = dp_read(ahb_base + DP_INTR_STATUS);
+	aux->isr = dp_read(catalog, io_data, DP_INTR_STATUS);
 	aux->isr &= ~DP_INTR_MASK1;
 	ack = aux->isr & DP_INTERRUPT_STATUS1;
 	ack <<= 1;
 	ack |= DP_INTR_MASK1;
-	dp_write(ahb_base + DP_INTR_STATUS, ack);
+	dp_write(catalog, io_data, DP_INTR_STATUS, ack);
 }
 
 /* controller related catalog functions */
 static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return -EINVAL;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	return dp_read(base + DP_HDCP_STATUS);
+	return dp_read(catalog, io_data, DP_HDCP_STATUS);
 }
 
 static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
 	struct drm_msm_ext_hdr_metadata *hdr;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 header, parity, data;
 	u8 buf[SZ_128], off = 0;
 
@@ -345,16 +407,16 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
+	catalog = dp_catalog_get_priv(panel);
 	hdr = &panel->hdr_data.hdr_meta;
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
 	/* HEADER BYTE 1 */
 	header = panel->hdr_data.vscext_header_byte1;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_1_BIT)
 			| (parity << PARITY_BYTE_1_BIT));
-	dp_write(base + MMSS_DP_VSCEXT_0, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_0, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -363,22 +425,22 @@
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_2_BIT)
 			| (parity << PARITY_BYTE_2_BIT));
-	dp_write(base + MMSS_DP_VSCEXT_1, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_1, data);
 
 	/* HEADER BYTE 3 */
 	header = panel->hdr_data.vscext_header_byte3;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_3_BIT)
 			| (parity << PARITY_BYTE_3_BIT));
-	data |= dp_read(base + MMSS_DP_VSCEXT_1);
-	dp_write(base + MMSS_DP_VSCEXT_1, data);
+	data |= dp_read(catalog, io_data, MMSS_DP_VSCEXT_1);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_1, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = panel->hdr_data.version;
 	data |= panel->hdr_data.length << 8;
 	data |= hdr->eotf << 16;
-	dp_write(base + MMSS_DP_VSCEXT_2, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_2, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -386,7 +448,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[0]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[0]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[0]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_3, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_3, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -394,7 +456,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[1]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[1]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[1]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_4, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_4, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -402,7 +464,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[2]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[2]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[2]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_5, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_5, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -410,7 +472,7 @@
 		(DP_GET_MSB(hdr->white_point_x) << 8) |
 		(DP_GET_LSB(hdr->white_point_y) << 16) |
 		(DP_GET_MSB(hdr->white_point_y) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_6, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_6, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -418,7 +480,7 @@
 		(DP_GET_MSB(hdr->max_luminance) << 8) |
 		(DP_GET_LSB(hdr->min_luminance) << 16) |
 		(DP_GET_MSB(hdr->min_luminance) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_7, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_7, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -426,12 +488,12 @@
 		(DP_GET_MSB(hdr->max_content_light_level) << 8) |
 		(DP_GET_LSB(hdr->max_average_light_level) << 16) |
 		(DP_GET_MSB(hdr->max_average_light_level) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_8, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_8, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_VSCEXT_9, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_9, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -442,7 +504,7 @@
 static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 header, parity, data;
 	u8 bpc, off = 0;
 	u8 buf[SZ_128];
@@ -452,15 +514,15 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	/* HEADER BYTE 1 */
 	header = panel->hdr_data.vsc_header_byte1;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_1_BIT)
 			| (parity << PARITY_BYTE_1_BIT));
-	dp_write(base + MMSS_DP_GENERIC0_0, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_0, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -469,32 +531,32 @@
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_2_BIT)
 			| (parity << PARITY_BYTE_2_BIT));
-	dp_write(base + MMSS_DP_GENERIC0_1, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_1, data);
 
 	/* HEADER BYTE 3 */
 	header = panel->hdr_data.vsc_header_byte3;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_3_BIT)
 			| (parity << PARITY_BYTE_3_BIT));
-	data |= dp_read(base + MMSS_DP_GENERIC0_1);
-	dp_write(base + MMSS_DP_GENERIC0_1, data);
+	data |= dp_read(catalog, io_data, MMSS_DP_GENERIC0_1);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_1, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_GENERIC0_2, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_2, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_3, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_3, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_4, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_4, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_5, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_5, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -517,20 +579,20 @@
 		((panel->hdr_data.dynamic_range & 0x1) << 15) |
 		((panel->hdr_data.content_type & 0x7) << 16);
 
-	dp_write(base + MMSS_DP_GENERIC0_6, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_6, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_GENERIC0_7, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_7, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_8, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_8, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_9, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_9, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -541,7 +603,7 @@
 static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 cfg, cfg2, misc;
 
 	if (!panel) {
@@ -549,21 +611,21 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
-	cfg = dp_read(base + MMSS_DP_SDP_CFG);
-	cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
-	misc = dp_read(base + DP_MISC1_MISC0);
+	cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
+	cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
+	misc = dp_read(catalog, io_data, DP_MISC1_MISC0);
 
 	if (en) {
 		/* VSCEXT_SDP_EN, GEN0_SDP_EN */
 		cfg |= BIT(16) | BIT(17);
-		dp_write(base + MMSS_DP_SDP_CFG, cfg);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG, cfg);
 
 		/* EXTN_SDPSIZE GENERIC0_SDPSIZE */
 		cfg2 |= BIT(15) | BIT(16);
-		dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, cfg2);
 
 		dp_catalog_panel_setup_vsc_sdp(panel);
 		dp_catalog_panel_setup_infoframe_sdp(panel);
@@ -578,11 +640,11 @@
 	} else {
 		/* VSCEXT_SDP_EN, GEN0_SDP_EN */
 		cfg &= ~BIT(16) & ~BIT(17);
-		dp_write(base + MMSS_DP_SDP_CFG, cfg);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG, cfg);
 
 		/* EXTN_SDPSIZE GENERIC0_SDPSIZE */
 		cfg2 &= ~BIT(15) & ~BIT(16);
-		dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, cfg2);
 
 		/* switch back to MSA */
 		misc &= ~BIT(14);
@@ -590,78 +652,78 @@
 		pr_debug("Disabled\n");
 	}
 
-	dp_write(base + DP_MISC1_MISC0, misc);
+	dp_write(catalog, io_data, DP_MISC1_MISC0, misc);
 
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x01);
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x00);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x01);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x00);
 }
 
 static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_VALID_BOUNDARY, ctrl->valid_boundary);
-	dp_write(base + DP_TU, ctrl->dp_tu);
-	dp_write(base + DP_VALID_BOUNDARY_2, ctrl->valid_boundary2);
+	dp_write(catalog, io_data, DP_VALID_BOUNDARY, ctrl->valid_boundary);
+	dp_write(catalog, io_data, DP_TU, ctrl->dp_tu);
+	dp_write(catalog, io_data, DP_VALID_BOUNDARY_2, ctrl->valid_boundary2);
 }
 
 static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_STATE_CTRL, state);
+	dp_write(catalog, io_data, DP_STATE_CTRL, state);
 }
 
 static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *link_base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	link_base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
 
-	dp_write(link_base + DP_CONFIGURATION_CTRL, cfg);
+	dp_write(catalog, io_data, DP_CONFIGURATION_CTRL, cfg);
 }
 
 static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4);
+	dp_write(catalog, io_data, DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4);
 }
 
 static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
@@ -669,29 +731,29 @@
 {
 	u32 mainlink_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	if (enable) {
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000000);
 		wmb(); /* make sure mainlink is turned off before reset */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000002);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000002);
 		wmb(); /* make sure mainlink entered reset */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000000);
 		wmb(); /* make sure mainlink reset done */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000001);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000001);
 		wmb(); /* make sure mainlink turned on */
 	} else {
-		mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL);
+		mainlink_ctrl = dp_read(catalog, io_data, DP_MAINLINK_CTRL);
 		mainlink_ctrl &= ~BIT(0);
-		dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, mainlink_ctrl);
 	}
 }
 
@@ -700,21 +762,23 @@
 {
 	u32 misc_val = cc;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
+	misc_val = dp_read(catalog, io_data, DP_MISC1_MISC0);
+	misc_val |= cc;
 	misc_val |= (tb << 5);
 	misc_val |= BIT(0); /* Configure clock to synchronous mode */
 
 	pr_debug("misc settings = 0x%x\n", misc_val);
-	dp_write(base + DP_MISC1_MISC0, misc_val);
+	dp_write(catalog, io_data, DP_MISC1_MISC0, misc_val);
 }
 
 static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl,
@@ -728,14 +792,14 @@
 	u32 const link_rate_hbr2 = 540000;
 	u32 const link_rate_hbr3 = 810000;
 	struct dp_catalog_private *catalog;
-	void __iomem *base_cc, *base_ctrl;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 	if (fixed_nvid) {
 		pr_debug("use fixed NVID=0x%x\n", nvid_fixed);
 		nvid = nvid_fixed;
@@ -756,10 +820,10 @@
 		 */
 		mvid = (u32) mvid_calc;
 	} else {
-		base_cc = catalog->io->dp_cc_io.base;
+		io_data = catalog->io.dp_mmss_cc;
 
-		pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M);
-		pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N);
+		pixel_m = dp_read(catalog, io_data, MMSS_DP_PIXEL_M);
+		pixel_n = dp_read(catalog, io_data, MMSS_DP_PIXEL_N);
 		pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
 
 		mvid = (pixel_m & 0xFFFF) * 5;
@@ -774,10 +838,10 @@
 			nvid *= 3;
 	}
 
-	base_ctrl = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 	pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
-	dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid);
-	dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid);
+	dp_write(catalog, io_data, DP_SOFTWARE_MVID, mvid);
+	dp_write(catalog, io_data, DP_SOFTWARE_NVID, nvid);
 }
 
 static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl,
@@ -786,26 +850,26 @@
 	int bit, cnt = 10;
 	u32 data;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	bit = 1;
 	bit <<= (pattern - 1);
 	pr_debug("hw: bit=%d train=%d\n", bit, pattern);
-	dp_write(base + DP_STATE_CTRL, bit);
+	dp_write(catalog, io_data, DP_STATE_CTRL, bit);
 
 	bit = 8;
 	bit <<= (pattern - 1);
 
 	while (cnt--) {
-		data = dp_read(base + DP_MAINLINK_READY);
+		data = dp_read(catalog, io_data, DP_MAINLINK_READY);
 		if (data & bit)
 			break;
 	}
@@ -817,35 +881,35 @@
 static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->usb3_dp_com.base;
+	io_data = catalog->io.usb3_dp_com;
 
-	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
-	dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02);
-	dp_write(base + USB3_DP_COM_SW_RESET, 0x01);
+	dp_write(catalog, io_data, USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
+	dp_write(catalog, io_data, USB3_DP_COM_PHY_MODE_CTRL, 0x02);
+	dp_write(catalog, io_data, USB3_DP_COM_SW_RESET, 0x01);
 	/* make sure usb3 com phy software reset is done */
 	wmb();
 
 	if (!flip) /* CC1 */
-		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02);
+		dp_write(catalog, io_data, USB3_DP_COM_TYPEC_CTRL, 0x02);
 	else /* CC2 */
-		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03);
+		dp_write(catalog, io_data, USB3_DP_COM_TYPEC_CTRL, 0x03);
 
-	dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00);
-	dp_write(base + USB3_DP_COM_SW_RESET, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_SWI_CTRL, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_SW_RESET, 0x00);
 	/* make sure the software reset is done */
 	wmb();
 
-	dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
-	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
+	dp_write(catalog, io_data, USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
 	/* make sure phy is brought out of reset */
 	wmb();
 }
@@ -854,50 +918,53 @@
 	bool enable)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!panel) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_p0.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_p0;
 
 	if (!enable) {
-		dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x0);
-		dp_write(base + MMSS_DP_BIST_ENABLE, 0x0);
-		dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_TPG_MAIN_CONTROL, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_BIST_ENABLE, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_TIMING_ENGINE_EN, 0x0);
 		wmb(); /* ensure Timing generator is turned off */
 		return;
 	}
 
-	dp_write(base + MMSS_DP_INTF_CONFIG, 0x0);
-	dp_write(base + MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F0, panel->vsync_period *
-			panel->hsync_period);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, panel->v_sync_width *
-			panel->hsync_period);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_HCTL, panel->display_hctl);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_HCTL, 0);
-	dp_write(base + MMSS_INTF_DISPLAY_V_START_F0, panel->display_v_start);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F0, panel->display_v_end);
-	dp_write(base + MMSS_INTF_DISPLAY_V_START_F1, 0);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
-	dp_write(base + MMSS_DP_INTF_POLARITY_CTL, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_CONFIG, 0x0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PERIOD_F0,
+			panel->vsync_period * panel->hsync_period);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0,
+			panel->v_sync_width * panel->hsync_period);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_HCTL,
+			panel->display_hctl);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_HCTL, 0);
+	dp_write(catalog, io_data, MMSS_INTF_DISPLAY_V_START_F0,
+			panel->display_v_start);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_V_END_F0,
+			panel->display_v_end);
+	dp_write(catalog, io_data, MMSS_INTF_DISPLAY_V_START_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_POLARITY_CTL, 0);
 	wmb(); /* ensure TPG registers are programmed */
 
-	dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x100);
-	dp_write(base + MMSS_DP_TPG_VIDEO_CONFIG, 0x5);
+	dp_write(catalog, io_data, MMSS_DP_TPG_MAIN_CONTROL, 0x100);
+	dp_write(catalog, io_data, MMSS_DP_TPG_VIDEO_CONFIG, 0x5);
 	wmb(); /* ensure TPG config is programmed */
-	dp_write(base + MMSS_DP_BIST_ENABLE, 0x1);
-	dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_BIST_ENABLE, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_TIMING_ENGINE_EN, 0x1);
 	wmb(); /* ensure Timing generator is turned on */
 }
 
@@ -905,24 +972,24 @@
 {
 	u32 sw_reset;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	sw_reset = dp_read(base + DP_SW_RESET);
+	sw_reset = dp_read(catalog, io_data, DP_SW_RESET);
 
 	sw_reset |= BIT(0);
-	dp_write(base + DP_SW_RESET, sw_reset);
+	dp_write(catalog, io_data, DP_SW_RESET, sw_reset);
 	usleep_range(1000, 1010); /* h/w recommended delay */
 
 	sw_reset &= ~BIT(0);
-	dp_write(base + DP_SW_RESET, sw_reset);
+	dp_write(catalog, io_data, DP_SW_RESET, sw_reset);
 }
 
 static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl)
@@ -930,19 +997,19 @@
 	u32 data;
 	int cnt = 10;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	while (--cnt) {
 		/* DP_MAINLINK_READY */
-		data = dp_read(base + DP_MAINLINK_READY);
+		data = dp_read(catalog, io_data, DP_MAINLINK_READY);
 		if (data & BIT(0))
 			return true;
 
@@ -957,52 +1024,51 @@
 						bool enable)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
 	if (enable) {
-		dp_write(base + DP_INTR_STATUS, DP_INTR_MASK1);
-		dp_write(base + DP_INTR_STATUS2, DP_INTR_MASK2);
+		dp_write(catalog, io_data, DP_INTR_STATUS, DP_INTR_MASK1);
+		dp_write(catalog, io_data, DP_INTR_STATUS2, DP_INTR_MASK2);
 	} else {
-		dp_write(base + DP_INTR_STATUS, 0x00);
-		dp_write(base + DP_INTR_STATUS2, 0x00);
+		dp_write(catalog, io_data, DP_INTR_STATUS, 0x00);
+		dp_write(catalog, io_data, DP_INTR_STATUS2, 0x00);
 	}
 }
 
 static void dp_catalog_ctrl_hpd_config(struct dp_catalog_ctrl *ctrl, bool en)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_aux;
 
 	if (en) {
-		u32 reftimer = dp_read(base + DP_DP_HPD_REFTIMER);
+		u32 reftimer = dp_read(catalog, io_data, DP_DP_HPD_REFTIMER);
 
-		dp_write(base + DP_DP_HPD_INT_ACK, 0xF);
-		dp_write(base + DP_DP_HPD_INT_MASK, 0xF);
-
+		dp_write(catalog, io_data, DP_DP_HPD_INT_ACK, 0xF);
+		dp_write(catalog, io_data, DP_DP_HPD_INT_MASK, 0xF);
 		/* Enabling REFTIMER */
 		reftimer |= BIT(16);
-		dp_write(base + DP_DP_HPD_REFTIMER, 0xF);
+		dp_write(catalog, io_data, DP_DP_HPD_REFTIMER, 0xF);
 		/* Enable HPD */
-		dp_write(base + DP_DP_HPD_CTRL, 0x1);
+		dp_write(catalog, io_data, DP_DP_HPD_CTRL, 0x1);
 	} else {
 		/*Disable HPD */
-		dp_write(base + DP_DP_HPD_CTRL, 0x0);
+		dp_write(catalog, io_data, DP_DP_HPD_CTRL, 0x0);
 	}
 }
 
@@ -1010,40 +1076,40 @@
 {
 	u32 ack = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	ctrl->isr = dp_read(base + DP_INTR_STATUS2);
+	ctrl->isr = dp_read(catalog, io_data, DP_INTR_STATUS2);
 	ctrl->isr &= ~DP_INTR_MASK2;
 	ack = ctrl->isr & DP_INTERRUPT_STATUS2;
 	ack <<= 1;
 	ack |= DP_INTR_MASK2;
-	dp_write(base + DP_INTR_STATUS2, ack);
+	dp_write(catalog, io_data, DP_INTR_STATUS2, ack);
 }
 
 static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	dp_write(base + DP_PHY_CTRL, 0x5); /* bit 0 & 2 */
+	dp_write(catalog, io_data, DP_PHY_CTRL, 0x5); /* bit 0 & 2 */
 	usleep_range(1000, 1010); /* h/w recommended delay */
-	dp_write(base + DP_PHY_CTRL, 0x0);
+	dp_write(catalog, io_data, DP_PHY_CTRL, 0x0);
 	wmb(); /* make sure PHY reset done */
 }
 
@@ -1052,6 +1118,7 @@
 {
 	u32 info = 0x0;
 	struct dp_catalog_private *catalog;
+	struct dp_io_data *io_data;
 	u8 orientation = BIT(!!flipped);
 
 	if (!ctrl) {
@@ -1059,20 +1126,22 @@
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
+
+	io_data = catalog->io.dp_phy;
 
 	info |= (ln_cnt & 0x0F);
 	info |= ((orientation & 0x0F) << 4);
 	pr_debug("Shared Info = 0x%x\n", info);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_SPARE0, info);
+	dp_write(catalog, io_data, DP_PHY_SPARE0, info);
 }
 
 static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
 		u8 v_level, u8 p_level)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base0, *base1;
+	struct dp_io_data *io_data;
 	u8 value0, value1;
 
 	if (!ctrl) {
@@ -1080,9 +1149,7 @@
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base0 = catalog->io->ln_tx0_io.base;
-	base1 = catalog->io->ln_tx1_io.base;
+	catalog = dp_catalog_get_priv(ctrl);
 
 	pr_debug("hw: v=%d p=%d\n", v_level, p_level);
 
@@ -1090,10 +1157,14 @@
 	value1 = vm_pre_emphasis[v_level][p_level];
 
 	/* program default setting first */
-	dp_write(base0 + TXn_TX_DRV_LVL, 0x2A);
-	dp_write(base1 + TXn_TX_DRV_LVL, 0x2A);
-	dp_write(base0 + TXn_TX_EMP_POST1_LVL, 0x20);
-	dp_write(base1 + TXn_TX_EMP_POST1_LVL, 0x20);
+
+	io_data = catalog->io.dp_ln_tx0;
+	dp_write(catalog, io_data, TXn_TX_DRV_LVL, 0x2A);
+	dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
+
+	io_data = catalog->io.dp_ln_tx1;
+	dp_write(catalog, io_data, TXn_TX_DRV_LVL, 0x2A);
+	dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
 
 	/* Enable MUX to use Cursor values from these registers */
 	value0 |= BIT(5);
@@ -1101,10 +1172,13 @@
 
 	/* Configure host and panel only if both values are allowed */
 	if (value0 != 0xFF && value1 != 0xFF) {
-		dp_write(base0 + TXn_TX_DRV_LVL, value0);
-		dp_write(base1 + TXn_TX_DRV_LVL, value0);
-		dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1);
-		dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1);
+		io_data = catalog->io.dp_ln_tx0;
+		dp_write(catalog, io_data, TXn_TX_DRV_LVL, value0);
+		dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, value1);
+
+		io_data = catalog->io.dp_ln_tx1;
+		dp_write(catalog, io_data, TXn_TX_DRV_LVL, value0);
+		dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, value1);
 
 		pr_debug("hw: vx_value=0x%x px_value=0x%x\n",
 			value0, value1);
@@ -1119,54 +1193,61 @@
 {
 	struct dp_catalog_private *catalog;
 	u32 value = 0x0;
-	void __iomem *base = NULL;
+	struct dp_io_data *io_data = NULL;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_STATE_CTRL, 0x0);
+	dp_write(catalog, io_data, DP_STATE_CTRL, 0x0);
 
 	switch (pattern) {
 	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
-		dp_write(base + DP_STATE_CTRL, 0x1);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x1);
 		break;
 	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
 		value &= ~(1 << 16);
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
 		value |= 0xFC;
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
-		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
-		dp_write(base + DP_STATE_CTRL, 0x10);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
+		dp_write(catalog, io_data, DP_MAINLINK_LEVELS, 0x2);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x10);
 		break;
 	case DP_TEST_PHY_PATTERN_PRBS7:
-		dp_write(base + DP_STATE_CTRL, 0x20);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x20);
 		break;
 	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
-		dp_write(base + DP_STATE_CTRL, 0x40);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x40);
 		/* 00111110000011111000001111100000 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG0,
+			0x3E0F83E0);
 		/* 00001111100000111110000011111000 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG1,
+			0x0F83E0F8);
 		/* 1111100000111110 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG2,
+			0x0000F83E);
 		break;
 	case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1:
 		value = BIT(16);
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
 		value |= 0xFC;
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
-		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
-		dp_write(base + DP_STATE_CTRL, 0x10);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
+		dp_write(catalog, io_data, DP_MAINLINK_LEVELS, 0x2);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x10);
 		break;
 	case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3:
-		dp_write(base + DP_MAINLINK_CTRL, 0x11);
-		dp_write(base + DP_STATE_CTRL, 0x8);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x11);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x8);
 		break;
 	default:
 		pr_debug("No valid test pattern requested: 0x%x\n", pattern);
@@ -1180,38 +1261,101 @@
 static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base = NULL;
+	struct dp_io_data *io_data = NULL;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return 0;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
-	return dp_read(base + DP_MAINLINK_READY);
+	return dp_read(catalog, io_data, DP_MAINLINK_READY);
+}
+
+static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog,
+		char *name, u8 **out_buf, u32 *out_buf_len)
+{
+	int ret = 0;
+	u8 *buf;
+	u32 len;
+	struct dp_io_data *io_data;
+	struct dp_catalog_private *catalog;
+	struct dp_parser *parser;
+
+	if (!dp_catalog) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	catalog = container_of(dp_catalog, struct dp_catalog_private,
+		dp_catalog);
+
+	parser = catalog->parser;
+	parser->get_io_buf(parser, name);
+	io_data = parser->get_io(parser, name);
+	if (!io_data) {
+		pr_err("IO %s not found\n", name);
+		ret = -EINVAL;
+		goto end;
+	}
+
+	buf = io_data->buf;
+	len = io_data->io.len;
+
+	if (!buf || !len) {
+		pr_err("no buffer available\n");
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		u32 i, data;
+		u32 const rowsize = 4;
+		void __iomem *addr = io_data->io.base;
+
+		memset(buf, 0, len);
+
+		for (i = 0; i < len / rowsize; i++) {
+			data = readl_relaxed(addr);
+			memcpy(buf + (rowsize * i), &data, sizeof(u32));
+
+			addr += rowsize;
+		}
+	}
+
+	*out_buf = buf;
+	*out_buf_len = len;
+end:
+	if (ret)
+		parser->clear_io_buf(parser);
+
+	return ret;
 }
 
 /* panel related catalog functions */
 static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!panel) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_TOTAL_HOR_VER, panel->total);
-	dp_write(base + DP_START_HOR_VER_FROM_SYNC, panel->sync_start);
-	dp_write(base + DP_HSYNC_VSYNC_WIDTH_POLARITY, panel->width_blanking);
-	dp_write(base + DP_ACTIVE_HOR_VER, panel->dp_active);
+	dp_write(catalog, io_data, DP_TOTAL_HOR_VER, panel->total);
+	dp_write(catalog, io_data, DP_START_HOR_VER_FROM_SYNC,
+			panel->sync_start);
+	dp_write(catalog, io_data, DP_HSYNC_VSYNC_WIDTH_POLARITY,
+		panel->width_blanking);
+	dp_write(catalog, io_data, DP_ACTIVE_HOR_VER, panel->dp_active);
 end:
 	return 0;
 }
@@ -1250,7 +1394,7 @@
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
 	catalog->audio_map = sdp_map;
 }
@@ -1258,17 +1402,17 @@
 static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 sdp_cfg = 0;
 	u32 sdp_cfg2 = 0;
 
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(audio);
+	io_data = catalog->io.dp_link;
 
-	sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG);
+	sdp_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
 
 	/* AUDIO_TIMESTAMP_SDP_EN */
 	sdp_cfg |= BIT(1);
@@ -1282,44 +1426,44 @@
 	sdp_cfg |= BIT(20);
 
 	pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
-	dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG, sdp_cfg);
 
-	sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+	sdp_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
 	/* IFRM_REGSRC -> Do not use reg values */
 	sdp_cfg2 &= ~BIT(0);
 	/* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
 	sdp_cfg2 &= ~BIT(1);
 
 	pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
-	dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, sdp_cfg2);
 }
 
 static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
 	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	enum dp_catalog_audio_sdp_type sdp;
 	enum dp_catalog_audio_header_type header;
 
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base    = catalog->io->dp_link.base;
+	io_data    = catalog->io.dp_link;
 	sdp_map = catalog->audio_map;
 	sdp     = audio->sdp_type;
 	header  = audio->sdp_header;
 
-	audio->data = dp_read(base + sdp_map[sdp][header]);
+	audio->data = dp_read(catalog, io_data, sdp_map[sdp][header]);
 }
 
 static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
 	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	enum dp_catalog_audio_sdp_type sdp;
 	enum dp_catalog_audio_header_type header;
 	u32 data;
@@ -1327,69 +1471,69 @@
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base    = catalog->io->dp_link.base;
+	io_data    = catalog->io.dp_link;
 	sdp_map = catalog->audio_map;
 	sdp     = audio->sdp_type;
 	header  = audio->sdp_header;
 	data    = audio->data;
 
-	dp_write(base + sdp_map[sdp][header], data);
+	dp_write(catalog, io_data, sdp_map[sdp][header], data);
 }
 
 static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 acr_ctrl, select;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
 	select = audio->data;
-	base   = catalog->io->dp_link.base;
+	io_data   = catalog->io.dp_link;
 
 	acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
 
 	pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
 
-	dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
+	dp_write(catalog, io_data, MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
 }
 
 static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 mainlink_levels, safe_to_exit_level;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base   = catalog->io->dp_link.base;
+	io_data   = catalog->io.dp_link;
 	safe_to_exit_level = audio->data;
 
-	mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
+	mainlink_levels = dp_read(catalog, io_data, DP_MAINLINK_LEVELS);
 	mainlink_levels &= 0xFE0;
 	mainlink_levels |= safe_to_exit_level;
 
 	pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
 			mainlink_levels, safe_to_exit_level);
 
-	dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
+	dp_write(catalog, io_data, DP_MAINLINK_LEVELS, mainlink_levels);
 }
 
 static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	bool enable;
 	u32 audio_ctrl;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base   = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 	enable = !!audio->data;
 
-	audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
+	audio_ctrl = dp_read(catalog, io_data, MMSS_DP_AUDIO_CFG);
 
 	if (enable)
 		audio_ctrl |= BIT(0);
@@ -1397,7 +1541,7 @@
 		audio_ctrl &= ~BIT(0);
 
 	pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
-	dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
+	dp_write(catalog, io_data, MMSS_DP_AUDIO_CFG, audio_ctrl);
 
 	/* make sure audio engine is disabled */
 	wmb();
@@ -1406,18 +1550,18 @@
 static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 value, new_value;
 	u8 parity_byte;
 
 	if (!panel)
 		return;
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	/* Config header and parity byte 1 */
-	value = dp_read(base + MMSS_DP_GENERIC1_0);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_0);
 
 	new_value = 0x83;
 	parity_byte = dp_header_get_parity(new_value);
@@ -1425,10 +1569,10 @@
 			| (parity_byte << PARITY_BYTE_1_BIT));
 	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
 			value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_0, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_0, value);
 
 	/* Config header and parity byte 2 */
-	value = dp_read(base + MMSS_DP_GENERIC1_1);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_1);
 
 	new_value = 0x1b;
 	parity_byte = dp_header_get_parity(new_value);
@@ -1436,10 +1580,10 @@
 			| (parity_byte << PARITY_BYTE_2_BIT));
 	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
 			value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_1, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_1, value);
 
 	/* Config header and parity byte 3 */
-	value = dp_read(base + MMSS_DP_GENERIC1_1);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_1);
 
 	new_value = (0x0 | (0x12 << 2));
 	parity_byte = dp_header_get_parity(new_value);
@@ -1447,13 +1591,13 @@
 			| (parity_byte << PARITY_BYTE_3_BIT));
 	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
 			new_value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_1, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_1, value);
 }
 
 static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 spd_cfg = 0, spd_cfg2 = 0;
 	u8 *vendor = NULL, *product = NULL;
 	/*
@@ -1479,56 +1623,110 @@
 	if (!panel)
 		return;
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	dp_catalog_config_spd_header(panel);
 
 	vendor = panel->spd_vendor_name;
 	product = panel->spd_product_description;
 
-	dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) |
 				((vendor[1] & 0x7f) << 8) |
 				((vendor[2] & 0x7f) << 16) |
 				((vendor[3] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) |
 				((vendor[5] & 0x7f) << 8) |
 				((vendor[6] & 0x7f) << 16) |
 				((vendor[7] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) |
 			((product[1] & 0x7f) << 8) |
 			((product[2] & 0x7f) << 16) |
 			((product[3] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) |
 			((product[5] & 0x7f) << 8) |
 			((product[6] & 0x7f) << 16) |
 			((product[7] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) |
 			((product[9] & 0x7f) << 8) |
 			((product[10] & 0x7f) << 16) |
 			((product[11] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) |
 			((product[13] & 0x7f) << 8) |
 			((product[14] & 0x7f) << 16) |
 			((product[15] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_8, device_type);
-	dp_write(base + MMSS_DP_GENERIC1_9, 0x00);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_8, device_type);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_9, 0x00);
 
-	spd_cfg = dp_read(base + MMSS_DP_SDP_CFG);
+	spd_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
 	/* GENERIC1_SDP for SPD Infoframe */
 	spd_cfg |= BIT(18);
-	dp_write(base + MMSS_DP_SDP_CFG, spd_cfg);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG, spd_cfg);
 
-	spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+	spd_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
 	/* 28 data bytes for SPD Infoframe with GENERIC1 set */
 	spd_cfg2 |= BIT(17);
-	dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, spd_cfg2);
 
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x1);
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x0);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x0);
 }
 
-struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
+static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog)
+{
+	struct dp_parser *parser = catalog->parser;
+
+	dp_catalog_fill_io_buf(dp_ahb);
+	dp_catalog_fill_io_buf(dp_aux);
+	dp_catalog_fill_io_buf(dp_link);
+	dp_catalog_fill_io_buf(dp_p0);
+	dp_catalog_fill_io_buf(dp_phy);
+	dp_catalog_fill_io_buf(dp_ln_tx0);
+	dp_catalog_fill_io_buf(dp_ln_tx1);
+	dp_catalog_fill_io_buf(dp_pll);
+	dp_catalog_fill_io_buf(usb3_dp_com);
+	dp_catalog_fill_io_buf(dp_mmss_cc);
+	dp_catalog_fill_io_buf(hdcp_physical);
+}
+
+static void dp_catalog_get_io(struct dp_catalog_private *catalog)
+{
+	struct dp_parser *parser = catalog->parser;
+
+	dp_catalog_fill_io(dp_ahb);
+	dp_catalog_fill_io(dp_aux);
+	dp_catalog_fill_io(dp_link);
+	dp_catalog_fill_io(dp_p0);
+	dp_catalog_fill_io(dp_phy);
+	dp_catalog_fill_io(dp_ln_tx0);
+	dp_catalog_fill_io(dp_ln_tx1);
+	dp_catalog_fill_io(dp_pll);
+	dp_catalog_fill_io(usb3_dp_com);
+	dp_catalog_fill_io(dp_mmss_cc);
+	dp_catalog_fill_io(hdcp_physical);
+}
+
+static void dp_catalog_set_exe_mode(struct dp_catalog *dp_catalog, char *mode)
+{
+	struct dp_catalog_private *catalog;
+
+	if (!dp_catalog) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	catalog = container_of(dp_catalog, struct dp_catalog_private,
+		dp_catalog);
+
+	strlcpy(catalog->exe_mode, mode, sizeof(catalog->exe_mode));
+
+	if (!strcmp(catalog->exe_mode, "hw"))
+		catalog->parser->clear_io_buf(catalog->parser);
+	else
+		dp_catalog_get_io_buf(catalog);
+}
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
 {
 	int rc = 0;
 	struct dp_catalog *dp_catalog;
@@ -1583,7 +1781,7 @@
 		.config_spd = dp_catalog_panel_config_spd,
 	};
 
-	if (!io) {
+	if (!dev || !parser) {
 		pr_err("invalid input\n");
 		rc = -EINVAL;
 		goto error;
@@ -1596,7 +1794,11 @@
 	}
 
 	catalog->dev = dev;
-	catalog->io = io;
+	catalog->parser = parser;
+
+	dp_catalog_get_io(catalog);
+
+	strlcpy(catalog->exe_mode, "hw", sizeof(catalog->exe_mode));
 
 	dp_catalog = &catalog->dp_catalog;
 
@@ -1605,6 +1807,9 @@
 	dp_catalog->audio = audio;
 	dp_catalog->panel = panel;
 
+	dp_catalog->set_exe_mode = dp_catalog_set_exe_mode;
+	dp_catalog->get_reg_dump = dp_catalog_reg_dump;
+
 	return dp_catalog;
 error:
 	return ERR_PTR(rc);
@@ -1620,5 +1825,6 @@
 	catalog = container_of(dp_catalog, struct dp_catalog_private,
 				dp_catalog);
 
+	catalog->parser->clear_io_buf(catalog->parser);
 	devm_kfree(catalog->dev, catalog);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index d03be6a..743468d 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -181,6 +181,10 @@
 	struct dp_catalog_ctrl ctrl;
 	struct dp_catalog_audio audio;
 	struct dp_catalog_panel panel;
+
+	void (*set_exe_mode)(struct dp_catalog *dp_catalog, char *mode);
+	int (*get_reg_dump)(struct dp_catalog *dp_catalog,
+		char *mode, u8 **out_buf, u32 *out_buf_len);
 };
 
 static inline u8 dp_ecc_get_g0_value(u8 data)
@@ -248,7 +252,7 @@
 	return parity_byte;
 }
 
-struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io);
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser);
 void dp_catalog_put(struct dp_catalog *catalog);
 
 #endif /* _DP_CATALOG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index cb54b5f..2e2887e 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -820,6 +820,10 @@
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	int const maximum_retries = 5;
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -829,13 +833,13 @@
 		DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	tries = 0;
@@ -879,6 +883,13 @@
 			break;
 		}
 	}
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED;
 
 	return ret;
 }
@@ -922,6 +933,10 @@
 	int const maximum_retries = 5;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -934,14 +949,14 @@
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
 	ret = dp_ctrl_train_pattern_set(ctrl,
 		pattern | DP_RECOVERED_CLOCK_OUT_EN);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	do  {
@@ -968,7 +983,13 @@
 			break;
 		}
 	} while (!atomic_read(&ctrl->aborted));
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
 
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED;
 	return ret;
 }
 
@@ -1109,8 +1130,7 @@
 	return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
 }
 
-static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl,
-	bool flip, bool multi_func)
+static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
 {
 	struct dp_ctrl_private *ctrl;
 	struct dp_catalog_ctrl *catalog;
@@ -1125,7 +1145,7 @@
 	ctrl->orientation = flip;
 	catalog = ctrl->catalog;
 
-	if (!multi_func) {
+	if (reset) {
 		catalog->usb_reset(ctrl->catalog, flip);
 		catalog->phy_reset(ctrl->catalog);
 	}
@@ -1192,6 +1212,10 @@
 		return -EINVAL;
 	}
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
+	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
+
 	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
 	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
 
@@ -1231,6 +1255,13 @@
 		ret = dp_ctrl_setup_main_link(ctrl, true);
 	} while (ret == -EAGAIN);
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 229c779..31d8f07 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,7 @@
 #include "dp_catalog.h"
 
 struct dp_ctrl {
-	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func);
+	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
 	void (*deinit)(struct dp_ctrl *dp_ctrl);
 	int (*on)(struct dp_ctrl *dp_ctrl);
 	void (*off)(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 054b3c8..78bea02 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -16,7 +16,6 @@
 
 #include <linux/debugfs.h>
 
-#include "dp_parser.h"
 #include "dp_power.h"
 #include "dp_catalog.h"
 #include "dp_aux.h"
@@ -36,15 +35,56 @@
 	u8 *dpcd;
 	u32 dpcd_size;
 
+	int vdo;
+
+	char exe_mode[SZ_32];
+	char reg_dump[SZ_32];
+
 	struct dp_usbpd *usbpd;
 	struct dp_link *link;
 	struct dp_panel *panel;
+	struct dp_aux *aux;
+	struct dp_catalog *catalog;
 	struct drm_connector **connector;
 	struct device *dev;
-
+	struct work_struct sim_work;
 	struct dp_debug dp_debug;
 };
 
+static int dp_debug_get_edid_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->edid) {
+		debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL);
+		if (!debug->edid) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->edid_size = SZ_256;
+	}
+end:
+	return rc;
+}
+
+static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->dpcd) {
+		debug->dpcd = devm_kzalloc(debug->dev, SZ_1K, GFP_KERNEL);
+		if (!debug->dpcd) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->dpcd_size = SZ_1K;
+	}
+end:
+	return rc;
+}
+
 static ssize_t dp_debug_write_edid(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -75,7 +115,8 @@
 	edid_size = size / char_to_nib;
 	buf_t = buf;
 
-	memset(debug->edid, 0, debug->edid_size);
+	if (dp_debug_get_edid_buf(debug))
+		goto bail;
 
 	if (edid_size != debug->edid_size) {
 		pr_debug("clearing debug edid\n");
@@ -100,13 +141,13 @@
 		buf_t += char_to_nib;
 	}
 
-	print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE,
-		16, 1, debug->edid, debug->edid_size, false);
-
 	edid = debug->edid;
 bail:
 	kfree(buf);
-	debug->panel->set_edid(debug->panel, edid);
+
+	if (!debug->dp_debug.sim_mode)
+		debug->panel->set_edid(debug->panel, edid);
+
 	return rc;
 }
 
@@ -119,8 +160,8 @@
 	size_t dpcd_size = 0;
 	size_t size = 0, dpcd_buf_index = 0;
 	ssize_t rc = count;
-
-	pr_debug("count=%zu\n", count);
+	char offset_ch[5];
+	u32 offset;
 
 	if (!debug)
 		return -ENODEV;
@@ -128,7 +169,7 @@
 	if (*ppos)
 		goto bail;
 
-	size = min_t(size_t, count, SZ_32);
+	size = min_t(size_t, count, SZ_2K);
 
 	buf = kzalloc(size, GFP_KERNEL);
 	if (!buf) {
@@ -139,16 +180,30 @@
 	if (copy_from_user(buf, user_buff, size))
 		goto bail;
 
-	dpcd_size = size / char_to_nib;
-	buf_t = buf;
+	memcpy(offset_ch, buf, 4);
+	offset_ch[4] = '\0';
 
-	memset(debug->dpcd, 0, debug->dpcd_size);
-
-	if (dpcd_size != debug->dpcd_size) {
-		pr_debug("clearing debug dpcd\n");
+	if (kstrtoint(offset_ch, 16, &offset)) {
+		pr_err("offset kstrtoint error\n");
 		goto bail;
 	}
 
+	if (dp_debug_get_dpcd_buf(debug))
+		goto bail;
+
+	if (offset == 0xFFFF) {
+		pr_err("clearing dpcd\n");
+		memset(debug->dpcd, 0, debug->dpcd_size);
+		goto bail;
+	}
+
+	size -= 4;
+
+	dpcd_size = size / char_to_nib;
+	buf_t = buf + 4;
+
+	dpcd_buf_index = offset;
+
 	while (dpcd_size--) {
 		char t[3];
 		int d;
@@ -167,16 +222,39 @@
 		buf_t += char_to_nib;
 	}
 
-	print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE,
-		8, 1, debug->dpcd, debug->dpcd_size, false);
-
 	dpcd = debug->dpcd;
 bail:
 	kfree(buf);
-	debug->panel->set_dpcd(debug->panel, dpcd);
+	if (debug->dp_debug.sim_mode)
+		debug->aux->dpcd_updated(debug->aux);
+	else
+		debug->panel->set_dpcd(debug->panel, dpcd);
+
 	return rc;
 }
 
+static ssize_t dp_debug_read_dpcd(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	u32 len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+	return len;
+}
+
 static ssize_t dp_debug_write_hpd(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -323,6 +401,36 @@
 	return len;
 }
 
+static ssize_t dp_debug_write_exe_mode(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char *buf;
+	size_t len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len = min_t(size_t, count, SZ_32 - 1);
+	buf = memdup_user(user_buff, len);
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%3s", debug->exe_mode) != 1)
+		goto end;
+
+	if (strcmp(debug->exe_mode, "hw") &&
+	    strcmp(debug->exe_mode, "sw") &&
+	    strcmp(debug->exe_mode, "all"))
+		goto end;
+
+	debug->catalog->set_exe_mode(debug->catalog, debug->exe_mode);
+end:
+	return len;
+}
+
 static ssize_t dp_debug_read_connected(struct file *file,
 		char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -421,7 +529,6 @@
 	struct dp_debug_private *debug = file->private_data;
 	char *buf;
 	u32 len = 0, rc = 0;
-	u64 lclk = 0;
 	u32 max_size = SZ_4K;
 
 	if (!debug)
@@ -434,124 +541,60 @@
 	if (!buf)
 		return -ENOMEM;
 
-	rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+	rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel\n\t\tmax_pclk_khz = %d\n",
-		debug->panel->max_pclk_khz);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdrm_dp_link\n\t\trate = %u\n",
+	rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n",
 		debug->panel->link_info.rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tnum_lanes = %u\n",
+	rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n",
 		debug->panel->link_info.num_lanes);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tcapabilities = %lu\n",
-		debug->panel->link_info.capabilities);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel_info:\n\t\tactive = %dx%d\n",
+	rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n",
 		debug->panel->pinfo.h_active,
-		debug->panel->pinfo.v_active);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tback_porch = %dx%d\n",
-		debug->panel->pinfo.h_back_porch,
-		debug->panel->pinfo.v_back_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tfront_porch = %dx%d\n",
-		debug->panel->pinfo.h_front_porch,
-		debug->panel->pinfo.v_front_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tsync_width = %dx%d\n",
-		debug->panel->pinfo.h_sync_width,
-		debug->panel->pinfo.v_sync_width);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tactive_low = %dx%d\n",
-		debug->panel->pinfo.h_active_low,
-		debug->panel->pinfo.v_active_low);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\th_skew = %d\n",
-		debug->panel->pinfo.h_skew);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\trefresh rate = %d\n",
+		debug->panel->pinfo.v_active,
 		debug->panel->pinfo.refresh_rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tpixel clock khz = %d\n",
+	rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n",
 		debug->panel->pinfo.pixel_clk_khz);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tbpp = %d\n",
+	rc = snprintf(buf + len, max_size, "\tbpp=%d\n",
 		debug->panel->pinfo.bpp);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	/* Link Information */
-	rc = snprintf(buf + len, max_size,
-		"\tdp_link:\n\t\ttest_requested = %d\n",
-		debug->link->sink_request);
+	rc = snprintf(buf + len, max_size, "\ttest_req=%s\n",
+		dp_link_get_test_name(debug->link->sink_request));
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tlane_count = %d\n", debug->link->link_params.lane_count);
+		"\tlane_count=%d\n", debug->link->link_params.lane_count);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tbw_code = %d\n", debug->link->link_params.bw_code);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	lclk = drm_dp_bw_code_to_link_rate(
-			debug->link->link_params.bw_code) * 1000;
-	rc = snprintf(buf + len, max_size,
-		"\t\tlclk = %lld\n", lclk);
+		"\tbw_code=%d\n", debug->link->link_params.bw_code);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tv_level = %d\n", debug->link->phy_params.v_level);
+		"\tv_level=%d\n", debug->link->phy_params.v_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tp_level = %d\n", debug->link->phy_params.p_level);
+		"\tp_level=%d\n", debug->link->phy_params.p_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
@@ -816,6 +859,155 @@
 	return rc;
 }
 
+static ssize_t dp_debug_write_sim(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	int sim;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &sim) != 0)
+		goto end;
+
+	if (sim) {
+		if (dp_debug_get_edid_buf(debug))
+			goto end;
+
+		if (dp_debug_get_dpcd_buf(debug))
+			goto error;
+	} else {
+		if (debug->edid) {
+			devm_kfree(debug->dev, debug->edid);
+			debug->edid = NULL;
+		}
+
+		if (debug->dpcd) {
+			devm_kfree(debug->dev, debug->dpcd);
+			debug->dpcd = NULL;
+		}
+	}
+
+	debug->dp_debug.sim_mode = !!sim;
+
+	debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode,
+			debug->edid, debug->dpcd);
+end:
+	return len;
+error:
+	devm_kfree(debug->dev, debug->edid);
+	return len;
+}
+
+static ssize_t dp_debug_write_attention(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	int vdo;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &vdo) != 0)
+		goto end;
+
+	debug->vdo = vdo;
+
+	schedule_work(&debug->sim_work);
+end:
+	return len;
+}
+
+static ssize_t dp_debug_write_dump(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_32];
+	size_t len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_32 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%31s", debug->reg_dump) != 1)
+		goto end;
+
+	/* qfprom register dump not supported */
+	if (!strcmp(debug->reg_dump, "qfprom_physical"))
+		strlcpy(debug->reg_dump, "clear", sizeof(debug->reg_dump));
+end:
+	return len;
+}
+
+static ssize_t dp_debug_read_dump(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	int rc = 0;
+	struct dp_debug_private *debug = file->private_data;
+	u8 *buf = NULL;
+	u32 len = 0;
+	char prefix[SZ_32];
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (!debug->usbpd->hpd_high || !strlen(debug->reg_dump))
+		goto end;
+
+	rc = debug->catalog->get_reg_dump(debug->catalog,
+		debug->reg_dump, &buf, &len);
+	if (rc)
+		goto end;
+
+	snprintf(prefix, sizeof(prefix), "%s: ", debug->reg_dump);
+	print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE,
+		16, 4, buf, len, false);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+end:
+	return len;
+}
+
 static const struct file_operations dp_debug_fops = {
 	.open = simple_open,
 	.read = dp_debug_read_info,
@@ -840,6 +1032,7 @@
 static const struct file_operations dpcd_fops = {
 	.open = simple_open,
 	.write = dp_debug_write_dpcd,
+	.read = dp_debug_read_dpcd,
 };
 
 static const struct file_operations connected_fops = {
@@ -852,6 +1045,10 @@
 	.read = dp_debug_bw_code_read,
 	.write = dp_debug_bw_code_write,
 };
+static const struct file_operations exe_mode_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_exe_mode,
+};
 
 static const struct file_operations tpg_fops = {
 	.open = simple_open,
@@ -865,6 +1062,22 @@
 	.read = dp_debug_read_hdr,
 };
 
+static const struct file_operations sim_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_sim,
+};
+
+static const struct file_operations attention_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_attention,
+};
+
+static const struct file_operations dump_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_dump,
+	.read = dp_debug_read_dump,
+};
+
 static int dp_debug_init(struct dp_debug *dp_debug)
 {
 	int rc = 0;
@@ -927,7 +1140,14 @@
 		rc = PTR_ERR(file);
 		pr_err("[%s] debugfs max_bw_code failed, rc=%d\n",
 		       DEBUG_NAME, rc);
-		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("exe_mode", 0644, dir,
+			debug, &exe_mode_fops);
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs register failed, rc=%d\n",
+		       DEBUG_NAME, rc);
 	}
 
 	file = debugfs_create_file("edid", 0644, dir,
@@ -967,6 +1187,36 @@
 		goto error_remove_dir;
 	}
 
+	file = debugfs_create_file("sim", 0644, dir,
+		debug, &sim_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs sim failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("attention", 0644, dir,
+		debug, &attention_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs attention failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("dump", 0644, dir,
+		debug, &dump_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs dump failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
 	return 0;
 
 error_remove_dir:
@@ -977,15 +1227,24 @@
 	return rc;
 }
 
+static void dp_debug_sim_work(struct work_struct *work)
+{
+	struct dp_debug_private *debug =
+		container_of(work, typeof(*debug), sim_work);
+
+	debug->usbpd->simulate_attention(debug->usbpd, debug->vdo);
+}
+
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector)
+			struct dp_aux *aux, struct drm_connector **connector,
+			struct dp_catalog *catalog)
 {
 	int rc = 0;
 	struct dp_debug_private *debug;
 	struct dp_debug *dp_debug;
 
-	if (!dev || !panel || !usbpd || !link) {
+	if (!dev || !panel || !usbpd || !link || !catalog) {
 		pr_err("invalid input\n");
 		rc = -EINVAL;
 		goto error;
@@ -997,30 +1256,16 @@
 		goto error;
 	}
 
-	debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL);
-	if (!debug->edid) {
-		rc = -ENOMEM;
-		kfree(debug);
-		goto error;
-	}
-
-	debug->edid_size = SZ_256;
-
-	debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL);
-	if (!debug->dpcd) {
-		rc = -ENOMEM;
-		kfree(debug);
-		goto error;
-	}
-
-	debug->dpcd_size = SZ_16;
+	INIT_WORK(&debug->sim_work, dp_debug_sim_work);
 
 	debug->dp_debug.debug_en = false;
 	debug->usbpd = usbpd;
 	debug->link = link;
 	debug->panel = panel;
+	debug->aux = aux;
 	debug->dev = dev;
 	debug->connector = connector;
+	debug->catalog = catalog;
 
 	dp_debug = &debug->dp_debug;
 	dp_debug->vdisplay = 0;
@@ -1063,7 +1308,11 @@
 
 	dp_debug_deinit(dp_debug);
 
-	devm_kfree(debug->dev, debug->edid);
-	devm_kfree(debug->dev, debug->dpcd);
+	if (debug->edid)
+		devm_kfree(debug->dev, debug->edid);
+
+	if (debug->dpcd)
+		devm_kfree(debug->dev, debug->dpcd);
+
 	devm_kfree(debug->dev, debug);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
index 3b2d23e..2643f70 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.h
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
 #include "dp_panel.h"
 #include "dp_link.h"
 #include "dp_usbpd.h"
+#include "dp_aux.h"
 
 /**
  * struct dp_debug
@@ -29,6 +30,7 @@
  */
 struct dp_debug {
 	bool debug_en;
+	bool sim_mode;
 	bool psm_enabled;
 	int aspect_ratio;
 	int vdisplay;
@@ -45,6 +47,7 @@
  * @usbpd: instance of usbpd module
  * @link: instance of link module
  * @connector: double pointer to display connector
+ * @catalog: instance of catalog module
  * return: pointer to allocated debug module data
  *
  * This function sets up the debug module and provides a way
@@ -52,7 +55,8 @@
  */
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector);
+			struct dp_aux *aux, struct drm_connector **connector,
+			struct dp_catalog *catalog);
 /**
  * dp_debug_put()
  *
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 96d4c9c..bf903b9 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -48,11 +48,6 @@
 	void *hdcp1;
 	void *hdcp2;
 
-	int enc_lvl;
-
-	bool auth_state;
-	bool hdcp1_present;
-	bool hdcp2_present;
 	bool feature_enabled;
 };
 
@@ -65,6 +60,8 @@
 	bool power_on;
 	bool audio_supported;
 
+	atomic_t aborted;
+
 	struct platform_device *pdev;
 	struct dentry *root;
 	struct completion notification_comp;
@@ -93,7 +90,6 @@
 	struct work_struct attention_work;
 	struct mutex hdcp_mutex;
 	struct mutex session_lock;
-	int hdcp_status;
 	unsigned long audio_status;
 };
 
@@ -109,9 +105,8 @@
 
 static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
 {
-	return dp->hdcp.feature_enabled &&
-		(dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
-		dp->hdcp.ops;
+	return dp->hdcp.feature_enabled && dp->link->hdcp_status.hdcp_version
+		&& dp->hdcp.ops;
 }
 
 static irqreturn_t dp_display_irq(int irq, void *dev_id)
@@ -156,32 +151,25 @@
 
 	ops = dp->hdcp.ops;
 
-	switch (dp->hdcp_status) {
-	case HDCP_STATE_AUTHENTICATING:
-		pr_debug("start authenticaton\n");
+	pr_debug("%s: %s\n",
+		sde_hdcp_version(dp->link->hdcp_status.hdcp_version),
+		sde_hdcp_state_name(dp->link->hdcp_status.hdcp_state));
 
+	switch (dp->link->hdcp_status.hdcp_state) {
+	case HDCP_STATE_AUTHENTICATING:
 		if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
 			rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
-
-		break;
-	case HDCP_STATE_AUTHENTICATED:
-		pr_debug("hdcp authenticated\n");
-		dp->hdcp.auth_state = true;
 		break;
 	case HDCP_STATE_AUTH_FAIL:
-		dp->hdcp.auth_state = false;
-
 		if (dp->power_on) {
-			pr_debug("Reauthenticating\n");
 			if (ops && ops->reauthenticate) {
 				rc = ops->reauthenticate(dp->hdcp.data);
 				if (rc)
-					pr_err("reauth failed rc=%d\n", rc);
+					pr_err("failed rc=%d\n", rc);
 			}
 		} else {
 			pr_debug("not reauthenticating, cable disconnected\n");
 		}
-
 		break;
 	default:
 		break;
@@ -189,7 +177,7 @@
 }
 
 static void dp_display_notify_hdcp_status_cb(void *ptr,
-		enum sde_hdcp_states status)
+		enum sde_hdcp_state state)
 {
 	struct dp_display_private *dp = ptr;
 
@@ -198,7 +186,7 @@
 		return;
 	}
 
-	dp->hdcp_status = status;
+	dp->link->hdcp_status.hdcp_state = state;
 
 	if (dp->dp_display.is_connected)
 		queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
@@ -214,12 +202,16 @@
 {
 	void *fd = NULL;
 	struct sde_hdcp_ops *ops = NULL;
+	bool hdcp2_present = false, hdcp1_present = false;
 
 	if (!dp) {
 		pr_err("invalid input\n");
 		return;
 	}
 
+	dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
+	dp->link->hdcp_status.hdcp_version = HDCP_VERSION_NONE;
+
 	if (!dp->hdcp.feature_enabled) {
 		pr_debug("feature not enabled\n");
 		return;
@@ -230,26 +222,29 @@
 		ops = sde_dp_hdcp2p2_start(fd);
 
 	if (ops && ops->feature_supported)
-		dp->hdcp.hdcp2_present = ops->feature_supported(fd);
+		hdcp2_present = ops->feature_supported(fd);
 	else
-		dp->hdcp.hdcp2_present = false;
+		hdcp2_present = false;
 
 	pr_debug("hdcp2p2: %s\n",
-			dp->hdcp.hdcp2_present ? "supported" : "not supported");
+			hdcp2_present ? "supported" : "not supported");
 
-	if (!dp->hdcp.hdcp2_present) {
-		dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
+	if (!hdcp2_present) {
+		hdcp1_present = hdcp1_check_if_supported_load_app();
 
-		if (dp->hdcp.hdcp1_present) {
+		if (hdcp1_present) {
 			fd = dp->hdcp.hdcp1;
 			ops = sde_hdcp_1x_start(fd);
+			dp->link->hdcp_status.hdcp_version = HDCP_VERSION_1X;
 		}
+	} else {
+		dp->link->hdcp_status.hdcp_version = HDCP_VERSION_2P2;
 	}
 
 	pr_debug("hdcp1x: %s\n",
-			dp->hdcp.hdcp1_present ? "supported" : "not supported");
+			hdcp1_present ? "supported" : "not supported");
 
-	if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
+	if (hdcp2_present || hdcp1_present) {
 		dp->hdcp.data = fd;
 		dp->hdcp.ops = ops;
 	} else {
@@ -274,6 +269,7 @@
 static int dp_display_initialize_hdcp(struct dp_display_private *dp)
 {
 	struct sde_hdcp_init_data hdcp_init_data;
+	struct dp_parser *parser;
 	int rc = 0;
 
 	if (!dp) {
@@ -281,23 +277,26 @@
 		return -EINVAL;
 	}
 
+	parser = dp->parser;
+
 	mutex_init(&dp->hdcp_mutex);
 
 	hdcp_init_data.client_id     = HDCP_CLIENT_DP;
 	hdcp_init_data.drm_aux       = dp->aux->drm_aux;
 	hdcp_init_data.cb_data       = (void *)dp;
 	hdcp_init_data.workq         = dp->wq;
-	hdcp_init_data.mutex         = &dp->hdcp_mutex;
 	hdcp_init_data.sec_access    = true;
 	hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
-	hdcp_init_data.core_io       = &dp->parser->io.ctrl_io;
-	hdcp_init_data.dp_ahb        = &dp->parser->io.dp_ahb;
-	hdcp_init_data.dp_aux        = &dp->parser->io.dp_aux;
-	hdcp_init_data.dp_link       = &dp->parser->io.dp_link;
-	hdcp_init_data.dp_p0         = &dp->parser->io.dp_p0;
-	hdcp_init_data.qfprom_io     = &dp->parser->io.qfprom_io;
-	hdcp_init_data.hdcp_io       = &dp->parser->io.hdcp_io;
+	hdcp_init_data.dp_ahb        = &parser->get_io(parser, "dp_ahb")->io;
+	hdcp_init_data.dp_aux        = &parser->get_io(parser, "dp_aux")->io;
+	hdcp_init_data.dp_link       = &parser->get_io(parser, "dp_link")->io;
+	hdcp_init_data.dp_p0         = &parser->get_io(parser, "dp_p0")->io;
+	hdcp_init_data.qfprom_io     = &parser->get_io(parser,
+						"qfprom_physical")->io;
+	hdcp_init_data.hdcp_io       = &parser->get_io(parser,
+						"hdcp_physical")->io;
 	hdcp_init_data.revision      = &dp->panel->link_info.revision;
+	hdcp_init_data.msm_hdcp_dev  = dp->parser->msm_hdcp_dev;
 
 	dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
 	if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
@@ -466,6 +465,7 @@
 		bool hpd)
 {
 	u32 timeout_sec;
+	int ret = 0;
 
 	dp->dp_display.is_connected = hpd;
 
@@ -474,16 +474,20 @@
 	else
 		timeout_sec = 10;
 
+	dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
+
 	reinit_completion(&dp->notification_comp);
 	dp_display_send_hpd_event(dp);
 
 	if (!wait_for_completion_timeout(&dp->notification_comp,
 						HZ * timeout_sec)) {
 		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
-		return -EINVAL;
+		ret = -EINVAL;
 	}
 
-	return 0;
+	dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
+
+	return ret;
 }
 
 static int dp_display_process_hpd_high(struct dp_display_private *dp)
@@ -532,6 +536,7 @@
 static void dp_display_host_init(struct dp_display_private *dp)
 {
 	bool flip = false;
+	bool reset;
 
 	if (dp->core_initialized) {
 		pr_debug("DP core already initialized\n");
@@ -541,8 +546,10 @@
 	if (dp->usbpd->orientation == ORIENTATION_CC2)
 		flip = true;
 
+	reset = dp->debug->sim_mode ? false : !dp->usbpd->multi_func;
+
 	dp->power->init(dp->power, flip);
-	dp->ctrl->init(dp->ctrl, flip, dp->usbpd->multi_func);
+	dp->ctrl->init(dp->ctrl, flip, reset);
 	enable_irq(dp->irq);
 	dp->core_initialized = true;
 }
@@ -558,6 +565,7 @@
 	dp->power->deinit(dp->power);
 	disable_irq(dp->irq);
 	dp->core_initialized = false;
+	dp->aux->state = 0;
 }
 
 static int dp_display_process_hpd_low(struct dp_display_private *dp)
@@ -614,7 +622,7 @@
 static void dp_display_clean(struct dp_display_private *dp)
 {
 	if (dp_display_is_hdcp_enabled(dp)) {
-		dp->hdcp_status = HDCP_STATE_INACTIVE;
+		dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
 
 		cancel_delayed_work_sync(&dp->hdcp_cb_work);
 		if (dp->hdcp.ops->off)
@@ -633,6 +641,11 @@
 	int rc;
 
 	rc = dp_display_process_hpd_low(dp);
+	if (rc) {
+		/* cancel any pending request */
+		dp->ctrl->abort(dp->ctrl);
+		dp->aux->abort(dp->aux);
+	}
 
 	mutex_lock(&dp->session_lock);
 	if (rc && dp->power_on)
@@ -675,6 +688,7 @@
 		dp->link->psm_config(dp->link, &dp->panel->link_info, true);
 
 	/* cancel any pending request */
+	atomic_set(&dp->aborted, 1);
 	dp->ctrl->abort(dp->ctrl);
 	dp->aux->abort(dp->aux);
 
@@ -683,6 +697,7 @@
 	flush_workqueue(dp->wq);
 
 	dp_display_handle_disconnect(dp);
+	atomic_set(&dp->aborted, 0);
 end:
 	return rc;
 }
@@ -766,6 +781,12 @@
 		return -ENODEV;
 	}
 
+	/* check if framework is ready */
+	if (!dp_display_framework_ready(dp)) {
+		pr_err("framework not ready\n");
+		return -ENODEV;
+	}
+
 	if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high &&
 	    dp->power_on) {
 		dp->link->process_request(dp->link);
@@ -774,6 +795,7 @@
 		queue_delayed_work(dp->wq, &dp->connect_work, 0);
 	} else {
 		/* cancel any pending request */
+		atomic_set(&dp->aborted, 1);
 		dp->ctrl->abort(dp->ctrl);
 		dp->aux->abort(dp->aux);
 
@@ -782,6 +804,7 @@
 		flush_workqueue(dp->wq);
 
 		dp_display_handle_disconnect(dp);
+		atomic_set(&dp->aborted, 0);
 	}
 
 	return 0;
@@ -793,11 +816,16 @@
 	struct dp_display_private *dp = container_of(dw,
 			struct dp_display_private, connect_work);
 
-	if (dp->dp_display.is_connected) {
+	if (dp->dp_display.is_connected && dp_display_framework_ready(dp)) {
 		pr_debug("HPD already on\n");
 		return;
 	}
 
+	if (atomic_read(&dp->aborted)) {
+		pr_err("aborted\n");
+		return;
+	}
+
 	dp_display_process_hpd_high(dp);
 }
 
@@ -844,7 +872,7 @@
 		goto error_catalog;
 	}
 
-	dp->catalog = dp_catalog_get(dev, &dp->parser->io);
+	dp->catalog = dp_catalog_get(dev, dp->parser);
 	if (IS_ERR(dp->catalog)) {
 		rc = PTR_ERR(dp->catalog);
 		pr_err("failed to initialize catalog, rc = %d\n", rc);
@@ -936,7 +964,8 @@
 	}
 
 	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
-				dp->link, &dp->dp_display.connector);
+				dp->link, dp->aux, &dp->dp_display.connector,
+				dp->catalog);
 	if (IS_ERR(dp->debug)) {
 		rc = PTR_ERR(dp->debug);
 		pr_err("failed to initialize debug, rc = %d\n", rc);
@@ -1049,8 +1078,18 @@
 		goto end;
 	}
 
+	if (atomic_read(&dp->aborted)) {
+		pr_err("aborted\n");
+		goto end;
+	}
+
 	dp->aux->init(dp->aux, dp->parser->aux_cfg);
 
+	if (dp->debug->psm_enabled) {
+		dp->link->psm_config(dp->link, &dp->panel->link_info, false);
+		dp->debug->psm_enabled = false;
+	}
+
 	rc = dp->ctrl->on(dp->ctrl);
 
 	if (dp->debug->tpg_state)
@@ -1081,6 +1120,11 @@
 		goto end;
 	}
 
+	if (atomic_read(&dp->aborted)) {
+		pr_err("aborted\n");
+		goto end;
+	}
+
 	dp->panel->spd_config(dp->panel);
 
 	if (dp->audio_supported) {
@@ -1094,7 +1138,7 @@
 	if (dp_display_is_hdcp_enabled(dp)) {
 		cancel_delayed_work_sync(&dp->hdcp_cb_work);
 
-		dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+		dp->link->hdcp_status.hdcp_state = HDCP_STATE_AUTHENTICATING;
 		queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
 	}
 
@@ -1102,6 +1146,7 @@
 end:
 	/* clear framework event notifier */
 	dp_display->post_open = NULL;
+	dp->aux->state |= DP_STATE_CTRL_POWERED_ON;
 
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
@@ -1127,7 +1172,7 @@
 	}
 
 	if (dp_display_is_hdcp_enabled(dp)) {
-		dp->hdcp_status = HDCP_STATE_INACTIVE;
+		dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
 
 		cancel_delayed_work_sync(&dp->hdcp_cb_work);
 		if (dp->hdcp.ops->off)
@@ -1187,12 +1232,11 @@
 	 * any notification from driver. Initialize post_open callback to notify
 	 * DP connection once framework restarts.
 	 */
-	if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
+	if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done)
 		dp_display->post_open = dp_display_post_open;
-		dp->dp_display.is_connected = false;
-	}
-	dp->power_on = false;
 
+	dp->power_on = false;
+	dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
 end:
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
@@ -1355,6 +1399,7 @@
 	dp->pdev = pdev;
 	dp->name = "drm_dp";
 	dp->audio_status = -ENODEV;
+	atomic_set(&dp->aborted, 0);
 
 	rc = dp_display_create_workqueue(dp);
 	if (rc) {
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index b834230..7c817d3 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -184,7 +184,12 @@
 	bridge = to_dp_bridge(drm_bridge);
 	dp = bridge->display;
 
-	if (dp && dp->connector)
+	if (!dp) {
+		pr_err("dp is null\n");
+		return;
+	}
+
+	if (dp->connector)
 		sde_connector_helper_bridge_disable(dp->connector);
 
 	rc = dp->pre_disable(dp);
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
index 0e1490f..2b7b217 100644
--- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/kthread.h>
 #include <linux/hdcp_qseecom.h>
+#include <linux/msm_hdcp.h>
 #include <drm/drm_dp_helper.h>
 
 #include "sde_hdcp.h"
@@ -320,35 +321,16 @@
 	struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx;
 	struct hdcp_lib_wakeup_data cdata = {
 		HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
-	bool enc_notify = true;
-	int enc_lvl;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	switch (min_enc_level) {
-	case 0:
-		enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
-		break;
-	case 1:
-		enc_lvl = HDCP_STATE_AUTH_ENC_1X;
-		break;
-	case 2:
-		enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
-		break;
-	default:
-		enc_notify = false;
-	}
-
 	pr_debug("enc level changed %d\n", min_enc_level);
 
 	cdata.context = ctrl->lib_ctx;
 	dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
-
-	if (enc_notify && ctrl->init_data.notify_status)
-		ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
 }
 
 static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
@@ -812,7 +794,6 @@
 
 	static struct hdcp_client_ops client_ops = {
 		.wakeup = dp_hdcp2p2_wakeup,
-		.notify_lvl_change = dp_hdcp2p2_min_level_change,
 	};
 	static struct dp_hdcp2p2_int_set int_set1[] = {
 		{BIT(17), "authentication successful", NULL},
@@ -867,6 +848,9 @@
 		goto error;
 	}
 
+	msm_hdcp_register_cb(init_data->msm_hdcp_dev, ctrl,
+		dp_hdcp2p2_min_level_change);
+
 	kthread_init_worker(&ctrl->worker);
 
 	kthread_init_work(&ctrl->auth,     dp_hdcp2p2_auth_work);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 3ca247c..05629dd 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -724,24 +724,6 @@
 	return ret;
 }
 
-static char *dp_link_get_test_name(u32 test_requested)
-{
-	switch (test_requested) {
-	case DP_TEST_LINK_TRAINING:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
-	case DP_TEST_LINK_VIDEO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
-	case DP_TEST_LINK_EDID_READ:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
-	case DP_TEST_LINK_PHY_TEST_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
-	case DP_TEST_LINK_AUDIO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
-	default:
-		return "unknown";
-	}
-}
-
 /**
  * dp_link_is_video_audio_test_requested() - checks for audio/video link request
  * @link: link requested by the sink
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 6f79b6a..d14b881 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -72,6 +72,11 @@
 	u32 test_audio_period_ch_8;
 };
 
+struct dp_link_hdcp_status {
+	int hdcp_state;
+	int hdcp_version;
+};
+
 struct dp_link_phy_params {
 	u32 phy_test_pattern_sel;
 	u8 v_level;
@@ -83,6 +88,24 @@
 	u32 bw_code;
 };
 
+static inline char *dp_link_get_test_name(u32 test_requested)
+{
+	switch (test_requested) {
+	case DP_TEST_LINK_TRAINING:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
+	case DP_TEST_LINK_VIDEO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
+	case DP_TEST_LINK_EDID_READ:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
+	case DP_TEST_LINK_PHY_TEST_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
+	case DP_TEST_LINK_AUDIO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
+	default:
+		return "unknown";
+	}
+}
+
 struct dp_link {
 	u32 sink_request;
 	u32 test_response;
@@ -92,6 +115,7 @@
 	struct dp_link_test_audio test_audio;
 	struct dp_link_phy_params phy_params;
 	struct dp_link_params link_params;
+	struct dp_link_hdcp_status hdcp_status;
 
 	u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
 	int (*process_request)(struct dp_link *dp_link);
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index e0aedc0..7132699 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -136,9 +136,6 @@
 
 			goto end;
 		}
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ",
-			DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
 	}
 
 	rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
@@ -275,35 +272,31 @@
 static int dp_panel_read_edid(struct dp_panel *dp_panel,
 	struct drm_connector *connector)
 {
+	int ret = 0;
 	struct dp_panel_private *panel;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto end;
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
 	if (panel->custom_edid) {
 		pr_debug("skip edid read in debug mode\n");
-		return 0;
+		goto end;
 	}
 
 	sde_get_edid(connector, &panel->aux->drm_aux->ddc,
 		(void **)&dp_panel->edid_ctrl);
 	if (!dp_panel->edid_ctrl->edid) {
 		pr_err("EDID read failed\n");
-	} else {
-		u8 *buf = (u8 *)dp_panel->edid_ctrl->edid;
-		u32 size = buf[0x7E] ? 256 : 128;
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK EDID: ",
-			DUMP_PREFIX_NONE, 16, 1, buf, size, false);
-
-		return 0;
+		ret = -EINVAL;
+		goto end;
 	}
-
-	return -EINVAL;
+end:
+	return ret;
 }
 
 static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index c112cdc..0174ea10 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,106 +15,51 @@
 #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
 
 #include <linux/of_gpio.h>
+#include <linux/of_platform.h>
 
 #include "dp_parser.h"
 
 static void dp_parser_unmap_io_resources(struct dp_parser *parser)
 {
+	int i = 0;
 	struct dp_io *io = &parser->io;
 
-	msm_dss_iounmap(&io->dp_ahb);
-	msm_dss_iounmap(&io->dp_aux);
-	msm_dss_iounmap(&io->dp_link);
-	msm_dss_iounmap(&io->dp_p0);
-	msm_dss_iounmap(&io->phy_io);
-	msm_dss_iounmap(&io->ln_tx0_io);
-	msm_dss_iounmap(&io->ln_tx0_io);
-	msm_dss_iounmap(&io->dp_pll_io);
-	msm_dss_iounmap(&io->dp_cc_io);
-	msm_dss_iounmap(&io->usb3_dp_com);
-	msm_dss_iounmap(&io->qfprom_io);
-	msm_dss_iounmap(&io->hdcp_io);
+	for (i = 0; i < io->len; i++)
+		msm_dss_iounmap(&io->data[i].io);
 }
 
-static int dp_parser_ctrl_res(struct dp_parser *parser)
+static int dp_parser_reg(struct dp_parser *parser)
 {
-	int rc = 0;
-	u32 index;
+	int rc = 0, i = 0;
+	u32 reg_count;
 	struct platform_device *pdev = parser->pdev;
-	struct device_node *of_node = parser->pdev->dev.of_node;
 	struct dp_io *io = &parser->io;
+	struct device *dev = &pdev->dev;
 
-	rc = of_property_read_u32(of_node, "cell-index", &index);
-	if (rc) {
-		pr_err("cell-index not specified, rc=%d\n", rc);
-		goto err;
+	reg_count = of_property_count_strings(dev->of_node, "reg-names");
+	if (reg_count <= 0) {
+		pr_err("no reg defined\n");
+		return -EINVAL;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_ahb, "dp_ahb");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
+	io->len = reg_count;
+	io->data = devm_kzalloc(dev, sizeof(struct dp_io_data) * reg_count,
+			GFP_KERNEL);
+	if (!io->data)
+		return -ENOMEM;
+
+	for (i = 0; i < reg_count; i++) {
+		of_property_read_string_index(dev->of_node,
+				"reg-names", i,	&io->data[i].name);
+		rc = msm_dss_ioremap_byname(pdev, &io->data[i].io,
+			io->data[i].name);
+		if (rc) {
+			pr_err("unable to remap %s resources\n",
+				io->data[i].name);
+			goto err;
+		}
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_aux, "dp_aux");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_link, "dp_link");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_p0, "dp_p0");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy");
-	if (rc) {
-		pr_err("unable to remap dp PHY resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0");
-	if (rc) {
-		pr_err("unable to remap dp TX0 resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1");
-	if (rc) {
-		pr_err("unable to remap dp TX1 resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll");
-	if (rc) {
-		pr_err("unable to remap DP PLL resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com");
-	if (rc) {
-		pr_err("unable to remap USB3 DP com resources\n");
-		goto err;
-	}
-
-	if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
-		pr_err("unable to remap dp MMSS_CC resources\n");
-		goto err;
-	}
-
-	if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical"))
-		pr_warn("unable to remap dp qfprom resources\n");
-
-	if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical"))
-		pr_warn("unable to remap dp hdcp resources\n");
-
 	return 0;
 err:
 	dp_parser_unmap_io_resources(parser);
@@ -215,6 +160,30 @@
 	return 0;
 }
 
+static int dp_parser_msm_hdcp_dev(struct dp_parser *parser)
+{
+	struct device_node *node;
+	struct platform_device *pdev;
+
+	node = of_find_compatible_node(NULL, NULL, "qcom,msm-hdcp");
+	if (!node) {
+		// This is a non-fatal error, module initialization can proceed
+		pr_warn("couldn't find msm-hdcp node\n");
+		return 0;
+	}
+
+	pdev = of_find_device_by_node(node);
+	if (!pdev) {
+		// This is a non-fatal error, module initialization can proceed
+		pr_warn("couldn't find msm-hdcp pdev\n");
+		return 0;
+	}
+
+	parser->msm_hdcp_dev = &pdev->dev;
+
+	return 0;
+}
+
 static int dp_parser_pinctrl(struct dp_parser *parser)
 {
 	int rc = 0;
@@ -618,7 +587,7 @@
 		goto err;
 	}
 
-	rc = dp_parser_ctrl_res(parser);
+	rc = dp_parser_reg(parser);
 	if (rc)
 		goto err;
 
@@ -643,10 +612,82 @@
 		goto err;
 
 	rc = dp_parser_pinctrl(parser);
+	if (rc)
+		goto err;
+
+	rc = dp_parser_msm_hdcp_dev(parser);
 err:
 	return rc;
 }
 
+static struct dp_io_data *dp_parser_get_io(struct dp_parser *dp_parser,
+				char *name)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		goto err;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (!strcmp(data->name, name))
+			return data;
+	}
+err:
+	return NULL;
+}
+
+static void dp_parser_get_io_buf(struct dp_parser *dp_parser, char *name)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (!strcmp(data->name, name)) {
+			if (!data->buf)
+				data->buf = devm_kzalloc(&dp_parser->pdev->dev,
+					data->io.len, GFP_KERNEL);
+		}
+	}
+}
+
+static void dp_parser_clear_io_buf(struct dp_parser *dp_parser)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (data->buf)
+			devm_kfree(&dp_parser->pdev->dev, data->buf);
+
+		data->buf = NULL;
+	}
+}
+
 struct dp_parser *dp_parser_get(struct platform_device *pdev)
 {
 	struct dp_parser *parser;
@@ -656,6 +697,9 @@
 		return ERR_PTR(-ENOMEM);
 
 	parser->parse = dp_parser_parse;
+	parser->get_io = dp_parser_get_io;
+	parser->get_io_buf = dp_parser_get_io_buf;
+	parser->clear_io_buf = dp_parser_clear_io_buf;
 	parser->pdev = pdev;
 
 	return parser;
@@ -679,5 +723,7 @@
 		dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]);
 	}
 
+	dp_parser_clear_io_buf(parser);
+	devm_kfree(&parser->pdev->dev, parser->io.data);
 	devm_kfree(&parser->pdev->dev, parser);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index 72da381..a768ca3 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -56,35 +56,25 @@
 };
 
 /**
- * struct dp_ctrl_resource - controller's IO related data
- *
- * @dp_ahb: controller's ahb mapped memory address
- * @dp_aux: controller's aux mapped memory address
- * @dp_link: controller's link mapped memory address
- * @dp_p0: controller's p0 mapped memory address
- * @phy_io: phy's mapped memory address
- * @ln_tx0_io: USB-DP lane TX0's mapped memory address
- * @ln_tx1_io: USB-DP lane TX1's mapped memory address
- * @dp_cc_io: DP cc's mapped memory address
- * @qfprom_io: qfprom's mapped memory address
- * @dp_pll_io: DP PLL mapped memory address
- * @usb3_dp_com: USB3 DP PHY combo mapped memory address
- * @hdcp_io: hdcp's mapped memory address
+ * struct dp_io_data - data structure to store DP IO related info
+ * @name: name of the IO
+ * @buf: buffer corresponding to IO for debugging
+ * @io: io data which give len and mapped address
+ */
+struct dp_io_data {
+	const char *name;
+	u8 *buf;
+	struct dss_io_data io;
+};
+
+/**
+ * struct dp_io - data struct to store array of DP IO info
+ * @len: total number of IOs
+ * @data: pointer to an array of DP IO data structures.
  */
 struct dp_io {
-	struct dss_io_data ctrl_io;
-	struct dss_io_data dp_ahb;
-	struct dss_io_data dp_aux;
-	struct dss_io_data dp_link;
-	struct dss_io_data dp_p0;
-	struct dss_io_data phy_io;
-	struct dss_io_data ln_tx0_io;
-	struct dss_io_data ln_tx1_io;
-	struct dss_io_data dp_cc_io;
-	struct dss_io_data qfprom_io;
-	struct dss_io_data dp_pll_io;
-	struct dss_io_data usb3_dp_com;
-	struct dss_io_data hdcp_io;
+	u32 len;
+	struct dp_io_data *data;
 };
 
 /**
@@ -166,14 +156,19 @@
  * struct dp_parser - DP parser's data exposed to clients
  *
  * @pdev: platform data of the client
+ * @msm_hdcp_dev: device pointer for the HDCP driver
  * @mp: gpio, regulator and clock related data
  * @pinctrl: pin-control related data
  * @ctrl_resouce: controller's register address realated data
  * @disp_data: controller's display related data
  * @parse: function to be called by client to parse device tree.
+ * @get_io: function to be called by client to get io data.
+ * @get_io_buf: function to be called by client to get io buffers.
+ * @clear_io_buf: function to be called by client to clear io buffers.
  */
 struct dp_parser {
 	struct platform_device *pdev;
+	struct device *msm_hdcp_dev;
 	struct dss_module_power mp[DP_MAX_PM];
 	struct dp_pinctrl pinctrl;
 	struct dp_io io;
@@ -184,6 +179,9 @@
 	u32 max_pclk_khz;
 
 	int (*parse)(struct dp_parser *parser);
+	struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name);
+	void (*get_io_buf)(struct dp_parser *parser, char *name);
+	void (*clear_io_buf)(struct dp_parser *parser);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 2bd3bd4..42eb9b0 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -426,6 +426,28 @@
 	return rc;
 }
 
+static int dp_usbpd_simulate_attention(struct dp_usbpd *dp_usbpd, int vdo)
+{
+	int rc = 0;
+	struct dp_usbpd_private *pd;
+
+	if (!dp_usbpd) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+	pd->vdo = vdo;
+	dp_usbpd_get_status(pd);
+
+	if (pd->dp_cb && pd->dp_cb->attention)
+		pd->dp_cb->attention(pd->dev);
+error:
+	return rc;
+}
+
 struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
 {
 	int rc = 0;
@@ -475,6 +497,7 @@
 
 	dp_usbpd = &usbpd->dp_usbpd;
 	dp_usbpd->simulate_connect = dp_usbpd_simulate_connect;
+	dp_usbpd->simulate_attention = dp_usbpd_simulate_attention;
 
 	return dp_usbpd;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index e70ad7d..0a7efd9 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -50,6 +50,7 @@
  * @alt_mode_cfg_done: bool to specify alt mode status
  * @debug_en: bool to specify debug mode
  * @simulate_connect: simulate disconnect or connect for debug mode
+ * @simulate_attention: simulate attention messages for debug mode
  */
 struct dp_usbpd {
 	enum dp_usbpd_port port;
@@ -65,6 +66,7 @@
 	bool debug_en;
 
 	int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd);
+	int (*simulate_attention)(struct dp_usbpd *dp_usbpd, int vdo);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index 1fd10d9..fa80317 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -239,8 +239,7 @@
  *
  * return: error code in case of failure or 0 for success.
  */
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state);
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state);
 
 /**
  * dsi_clk_set_link_frequencies() - set frequencies for link clks
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 38eba8d..bff8627 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -1071,8 +1071,7 @@
 
 DEFINE_MUTEX(dsi_mngr_clk_mutex);
 
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
 {
 	int rc = 0;
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index bfbcf54..5b8c910 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -401,6 +401,21 @@
 	return rc;
 }
 
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl)
+{
+	struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
+
+	if (!state) {
+		pr_err("Invalid host state for DSI controller\n");
+		return -EINVAL;
+	}
+
+	if (!state->host_initialized)
+		return true;
+
+	return false;
+}
+
 static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl,
 				  enum dsi_ctrl_driver_ops op,
 				  u32 op_state)
@@ -1072,10 +1087,10 @@
 
 		cmdbuf = (u8 *)(dsi_ctrl->vaddr);
 
+		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		for (cnt = 0; cnt < length; cnt++)
 			cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt];
 
-		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		dsi_ctrl->cmd_len += length;
 
 		if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
@@ -1401,8 +1416,7 @@
 	u32 lanes = 0;
 	u32 ulps_lanes;
 
-	if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
-		lanes = dsi_ctrl->host_config.common_config.data_lanes;
+	lanes = dsi_ctrl->host_config.common_config.data_lanes;
 
 	rc = dsi_ctrl->hw.ops.wait_for_lane_idle(&dsi_ctrl->hw, lanes);
 	if (rc) {
@@ -1443,9 +1457,7 @@
 		return 0;
 	}
 
-	if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
-		lanes = dsi_ctrl->host_config.common_config.data_lanes;
-
+	lanes = dsi_ctrl->host_config.common_config.data_lanes;
 	lanes |= DSI_CLOCK_LANE;
 
 	ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw);
@@ -2087,11 +2099,14 @@
 	}
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
-	if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) {
+	if ((!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) ||
+			dsi_ctrl->modeupdated) {
 		*changed = true;
 		memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi));
+		dsi_ctrl->modeupdated = false;
 	} else
 		*changed = false;
+
 	mutex_unlock(&dsi_ctrl->ctrl_lock);
 	return rc;
 }
@@ -2421,6 +2436,31 @@
 }
 
 /**
+ * dsi_ctrl_update_host_init_state() - Update the host initialization state.
+ * @dsi_ctrl:        DSI controller handle.
+ * @enable:        boolean signifying host state.
+ *
+ * Update the host initialization status only while exiting from ulps during
+ * suspend state.
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool enable)
+{
+	int rc = 0;
+	u32 state = enable ? 0x1 : 0x0;
+
+	rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
+	if (rc) {
+		pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
+		       dsi_ctrl->cell_index, rc);
+		return rc;
+	}
+	dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
+	return rc;
+}
+
+/**
  * dsi_ctrl_host_init() - Initialize DSI host hardware.
  * @dsi_ctrl:        DSI controller handle.
  * @is_splash_enabled:        boolean signifying splash status.
@@ -2647,6 +2687,7 @@
 	ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active;
 	ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active;
 	memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds));
+	ctrl->modeupdated = true;
 	ctrl->roi.x = 0;
 error:
 	mutex_unlock(&ctrl->ctrl_lock);
@@ -2673,9 +2714,6 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&dsi_ctrl->ctrl_lock);
-	mutex_unlock(&dsi_ctrl->ctrl_lock);
-
 	return rc;
 }
 
@@ -3293,6 +3331,25 @@
 	return misr;
 }
 
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl)
+{
+	if (!dsi_ctrl || !dsi_ctrl->hw.ops.error_intr_ctrl
+			|| !dsi_ctrl->hw.ops.clear_error_status) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	/*
+	 * Mask DSI error status interrupts and clear error status
+	 * register
+	 */
+	mutex_lock(&dsi_ctrl->ctrl_lock);
+	dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false);
+	dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					DSI_ERROR_INTERRUPT_COUNT);
+	mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
 /**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index ca58896..ed3d0eb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -211,6 +211,7 @@
  *                          dsi controller and run only dsi controller.
  * @null_insertion_enabled:  A boolean property to allow dsi controller to
  *                           insert null packet.
+ * @modeupdated:	  Boolean to send new roi if mode is updated.
  */
 struct dsi_ctrl {
 	struct platform_device *pdev;
@@ -258,6 +259,7 @@
 
 	bool phy_isolation_enabled;
 	bool null_insertion_enabled;
+	bool modeupdated;
 };
 
 /**
@@ -547,6 +549,16 @@
 				  enum dsi_engine_state state);
 
 /**
+ * dsi_ctrl_validate_host_state() - validate DSI ctrl host state
+ * @dsi_ctrl:            DSI Controller handle.
+ *
+ * Validate DSI cotroller host state
+ *
+ * Return: boolean indicating whether host is not initalized.
+ */
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_set_vid_engine_state() - set video engine state
  * @dsi_ctrl:            DSI Controller handle.
  * @state:               Engine state.
@@ -711,6 +723,13 @@
 void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
 
 /**
+ * dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status
+ *                                           interrupts
+ * @dsi_ctrl:              DSI controller handle.
+ */
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
  * @dsi_ctrl:              DSI controller handle.
@@ -724,4 +743,9 @@
 int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl,
 		bool *state);
 
+/**
+ * dsi_ctrl_update_host_init_state() - Set the host initialization state
+ */
+int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool en);
+
 #endif /* _DSI_CTRL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index c8edb09..1682e61 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -16,6 +16,8 @@
 
 #include <linux/list.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_gpio.h>
 #include <linux/err.h>
 
 #include "msm_drv.h"
@@ -35,6 +37,7 @@
 #define NO_OVERRIDE -1
 
 #define MISR_BUFF_SIZE	256
+#define ESD_MODE_STRING_MAX_LEN 256
 
 #define MAX_NAME_SIZE	64
 
@@ -51,6 +54,40 @@
 
 static struct dsi_display *main_display;
 
+static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_mask_error_status_interrupts(ctrl->ctrl);
+	}
+}
+
+static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_irq_update(ctrl->ctrl, en);
+	}
+}
+
 void dsi_rect_intersect(const struct dsi_rect *r1,
 		const struct dsi_rect *r2,
 		struct dsi_rect *result)
@@ -88,8 +125,11 @@
 
 	panel = dsi_display->panel;
 
-	if (!dsi_panel_initialized(panel))
-		return -EINVAL;
+	mutex_lock(&panel->panel_lock);
+	if (!dsi_panel_initialized(panel)) {
+		rc = -EINVAL;
+		goto error;
+	}
 
 	panel->bl_config.bl_level = bl_lvl;
 
@@ -124,6 +164,7 @@
 	}
 
 error:
+	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -270,6 +311,89 @@
 	dsi_panel_release_panel_lock(display->panel);
 }
 
+static irqreturn_t dsi_display_panel_te_irq_handler(int irq, void *data)
+{
+	struct dsi_display *display = (struct dsi_display *)data;
+
+	/*
+	 * This irq handler is used for sole purpose of identifying
+	 * ESD attacks on panel and we can safely assume IRQ_HANDLED
+	 * in case of display not being initalized yet
+	 */
+	if (!display)
+		return IRQ_HANDLED;
+
+	complete_all(&display->esd_te_gate);
+	return IRQ_HANDLED;
+}
+
+static void dsi_display_change_te_irq_status(struct dsi_display *display,
+					bool enable)
+{
+	if (!display) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	/* Handle unbalanced irq enable/disbale calls */
+	if (enable && !display->is_te_irq_enabled) {
+		enable_irq(gpio_to_irq(display->disp_te_gpio));
+		display->is_te_irq_enabled = true;
+	} else if (!enable && display->is_te_irq_enabled) {
+		disable_irq(gpio_to_irq(display->disp_te_gpio));
+		display->is_te_irq_enabled = false;
+	}
+}
+
+static void dsi_display_register_te_irq(struct dsi_display *display)
+{
+	int rc;
+	struct platform_device *pdev;
+	struct device *dev;
+
+	pdev = display->pdev;
+	if (!pdev) {
+		pr_err("invalid platform device\n");
+		return;
+	}
+
+	dev = &pdev->dev;
+	if (!dev) {
+		pr_err("invalid device\n");
+		return;
+	}
+
+	rc = devm_request_irq(dev, gpio_to_irq(display->disp_te_gpio),
+			dsi_display_panel_te_irq_handler, IRQF_TRIGGER_FALLING,
+			"TE_GPIO", display);
+	if (rc) {
+		pr_err("TE request_irq failed for ESD rc:%d\n", rc);
+		return;
+	}
+
+	init_completion(&display->esd_te_gate);
+
+	disable_irq(gpio_to_irq(display->disp_te_gpio));
+	display->is_te_irq_enabled = false;
+}
+
+static bool dsi_display_is_te_based_esd(struct dsi_display *display)
+{
+	u32 status_mode = 0;
+
+	if (!display->panel) {
+		pr_err("Invalid panel data\n");
+		return false;
+	}
+
+	status_mode = display->panel->esd_config.status_mode;
+
+	if (status_mode == ESD_MODE_PANEL_TE &&
+			gpio_is_valid(display->disp_te_gpio))
+		return true;
+	return false;
+}
+
 /* Allocate memory for cmd dma tx buffer */
 static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
 {
@@ -382,6 +506,27 @@
 	return false;
 }
 
+static void dsi_display_parse_te_gpio(struct dsi_display *display)
+{
+	struct platform_device *pdev;
+	struct device *dev;
+
+	pdev = display->pdev;
+	if (!pdev) {
+		pr_err("Inavlid platform device\n");
+		return;
+	}
+
+	dev = &pdev->dev;
+	if (!dev) {
+		pr_err("Inavlid platform device\n");
+		return;
+	}
+
+	display->disp_te_gpio = of_get_named_gpio(dev->of_node,
+					"qcom,platform-te-gpio", 0);
+}
+
 static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
 		struct dsi_panel *panel)
 {
@@ -390,9 +535,17 @@
 	struct dsi_cmd_desc *cmds;
 	u32 flags = 0;
 
-	if (!panel)
+	if (!panel || !ctrl || !ctrl->ctrl)
 		return -EINVAL;
 
+	/*
+	 * When DSI controller is not in initialized state, we do not want to
+	 * report a false ESD failure and hence we defer until next read
+	 * happen.
+	 */
+	if (dsi_ctrl_validate_host_state(ctrl->ctrl))
+		return 1;
+
 	/* acquire panel_lock to make sure no commands are in progress */
 	dsi_panel_acquire_panel_lock(panel);
 
@@ -497,6 +650,11 @@
 		}
 	}
 exit:
+	if (rc <= 0) {
+		dsi_display_ctrl_irq_update(display, false);
+		dsi_display_mask_ctrl_error_interrupts(display);
+	}
+
 	dsi_display_cmd_engine_disable(display);
 done:
 	return rc;
@@ -514,10 +672,19 @@
 
 static int dsi_display_status_check_te(struct dsi_display *display)
 {
-	int rc = 0;
+	int rc = 1;
+	int const esd_te_timeout = msecs_to_jiffies(3*20);
 
-	pr_debug(" ++\n");
-	/* TODO: wait for TE interrupt from panel */
+	dsi_display_change_te_irq_status(display, true);
+
+	reinit_completion(&display->esd_te_gate);
+	if (!wait_for_completion_timeout(&display->esd_te_gate,
+				esd_te_timeout)) {
+		pr_err("ESD check failed\n");
+		rc = -EINVAL;
+	}
+
+	dsi_display_change_te_irq_status(display, false);
 
 	return rc;
 }
@@ -930,6 +1097,191 @@
 	return len;
 }
 
+static ssize_t debugfs_esd_trigger_check(struct file *file,
+				  const char __user *user_buf,
+				  size_t user_len,
+				  loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	char *buf;
+	int rc = 0;
+	u32 esd_trigger;
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (user_len > sizeof(u32))
+		return -EINVAL;
+
+	buf = kzalloc(user_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, user_len)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	buf[user_len] = '\0'; /* terminate the string */
+
+	if (kstrtouint(buf, 10, &esd_trigger)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (esd_trigger != 1) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	display->esd_trigger = esd_trigger;
+
+	if (display->esd_trigger) {
+		rc = dsi_panel_trigger_esd_attack(display->panel);
+		if (rc) {
+			pr_err("Failed to trigger ESD attack\n");
+			return rc;
+		}
+	}
+
+	rc = user_len;
+error:
+	kfree(buf);
+	return rc;
+}
+
+static ssize_t debugfs_alter_esd_check_mode(struct file *file,
+				  const char __user *user_buf,
+				  size_t user_len,
+				  loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	struct drm_panel_esd_config *esd_config;
+	char *buf;
+	int rc = 0;
+	size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, user_len)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	buf[len] = '\0'; /* terminate the string */
+	if (!display->panel) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	esd_config = &display->panel->esd_config;
+	if (!esd_config) {
+		pr_err("Invalid panel esd config\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!esd_config->esd_enabled)
+		goto error;
+
+	if (!strcmp(buf, "te_signal_check\n")) {
+		esd_config->status_mode = ESD_MODE_PANEL_TE;
+		dsi_display_change_te_irq_status(display, true);
+	}
+
+	if (!strcmp(buf, "reg_read\n")) {
+		rc = dsi_panel_parse_esd_reg_read_configs(display->panel,
+						display->panel_of);
+		if (rc) {
+			pr_err("failed to alter esd check mode,rc=%d\n",
+						rc);
+			rc = user_len;
+			goto error;
+		}
+		esd_config->status_mode = ESD_MODE_REG_READ;
+		if (dsi_display_is_te_based_esd(display))
+			dsi_display_change_te_irq_status(display, false);
+	}
+
+	rc = len;
+error:
+	kfree(buf);
+	return rc;
+}
+
+static ssize_t debugfs_read_esd_check_mode(struct file *file,
+				 char __user *user_buf,
+				 size_t user_len,
+				 loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	struct drm_panel_esd_config *esd_config;
+	char *buf;
+	int rc = 0;
+	size_t len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN);
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (!display->panel) {
+		pr_err("invalid panel data\n");
+		return -EINVAL;
+	}
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	esd_config = &display->panel->esd_config;
+	if (!esd_config) {
+		pr_err("Invalid panel esd config\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!esd_config->esd_enabled) {
+		rc = snprintf(buf, len, "ESD feature not enabled");
+		goto output_mode;
+	}
+
+	if (esd_config->status_mode == ESD_MODE_REG_READ)
+		rc = snprintf(buf, len, "reg_read");
+
+	if (esd_config->status_mode == ESD_MODE_PANEL_TE)
+		rc = snprintf(buf, len, "te_signal_check");
+
+output_mode:
+	if (!rc) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (copy_to_user(user_buf, buf, len)) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	*ppos += len;
+
+error:
+	kfree(buf);
+	return len;
+}
+
 static const struct file_operations dump_info_fops = {
 	.open = simple_open,
 	.read = debugfs_dump_info_read,
@@ -941,6 +1293,17 @@
 	.write = debugfs_misr_setup,
 };
 
+static const struct file_operations esd_trigger_fops = {
+	.open = simple_open,
+	.write = debugfs_esd_trigger_check,
+};
+
+static const struct file_operations esd_check_mode_fops = {
+	.open = simple_open,
+	.write = debugfs_alter_esd_check_mode,
+	.read = debugfs_read_esd_check_mode,
+};
+
 static int dsi_display_debugfs_init(struct dsi_display *display)
 {
 	int rc = 0;
@@ -968,6 +1331,30 @@
 		goto error_remove_dir;
 	}
 
+	dump_file = debugfs_create_file("esd_trigger",
+					0644,
+					dir,
+					display,
+					&esd_trigger_fops);
+	if (IS_ERR_OR_NULL(dump_file)) {
+		rc = PTR_ERR(dump_file);
+		pr_err("[%s] debugfs for esd trigger file failed, rc=%d\n",
+		       display->name, rc);
+		goto error_remove_dir;
+	}
+
+	dump_file = debugfs_create_file("esd_check_mode",
+					0644,
+					dir,
+					display,
+					&esd_check_mode_fops);
+	if (IS_ERR_OR_NULL(dump_file)) {
+		rc = PTR_ERR(dump_file);
+		pr_err("[%s] debugfs for esd check mode failed, rc=%d\n",
+		       display->name, rc);
+		goto error_remove_dir;
+	}
+
 	misr_data = debugfs_create_file("misr_data",
 					0600,
 					dir,
@@ -1808,18 +2195,34 @@
 	int i;
 	struct dsi_display_ctrl *ctrl;
 
-	for (i = 0 ; i < display->ctrl_count; i++) {
-		ctrl = &display->ctrl[i];
-		rc = dsi_ctrl_host_init(ctrl->ctrl,
-				display->is_cont_splash_enabled);
-		if (rc) {
-			pr_err("[%s] failed to init host_%d, rc=%d\n",
-			       display->name, i, rc);
-			goto error_host_deinit;
+	/* when ULPS suspend feature is enabled, we will keep the lanes in
+	 * ULPS during suspend state and clamp DSI phy. Hence while resuming
+	 * we will programe DSI controller as part of core clock enable.
+	 * After that we should not re-configure DSI controller again here for
+	 * usecases where we are resuming from ulps suspend as it might put
+	 * the HW in bad state.
+	 */
+	if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) {
+		for (i = 0 ; i < display->ctrl_count; i++) {
+			ctrl = &display->ctrl[i];
+			rc = dsi_ctrl_host_init(ctrl->ctrl,
+					display->is_cont_splash_enabled);
+			if (rc) {
+				pr_err("[%s] failed to init host_%d, rc=%d\n",
+				       display->name, i, rc);
+				goto error_host_deinit;
+			}
+		}
+	} else {
+		for (i = 0 ; i < display->ctrl_count; i++) {
+			ctrl = &display->ctrl[i];
+			rc = dsi_ctrl_update_host_init_state(ctrl->ctrl, true);
+			if (rc)
+				pr_debug("host init update failed rc=%d\n", rc);
 		}
 	}
 
-	return 0;
+	return rc;
 error_host_deinit:
 	for (i = i - 1; i >= 0; i--) {
 		ctrl = &display->ctrl[i];
@@ -2162,15 +2565,111 @@
 	return rc;
 }
 
+/* initialize dsi_panel using ext bridge's setting */
+static int dsi_display_populate_ext_bridge_config(struct dsi_display *display,
+	struct mipi_dsi_device *dsi)
+{
+	struct dsi_panel *panel = display->panel;
+
+	if (!panel) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("DSI[%s]: channel=%d, lanes=%d, format=%d, mode_flags=%lx\n",
+		dsi->name, dsi->channel, dsi->lanes,
+		dsi->format, dsi->mode_flags);
+
+	panel->host_config.data_lanes = 0;
+	if (dsi->lanes > 0)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_0;
+	if (dsi->lanes > 1)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_1;
+	if (dsi->lanes > 2)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_2;
+	if (dsi->lanes > 3)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_3;
+
+	switch (dsi->format) {
+	case MIPI_DSI_FMT_RGB888:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB888;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666_LOOSE;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+	default:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB565;
+		break;
+	}
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		panel->panel_mode = DSI_OP_VIDEO_MODE;
+
+		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_BURST_MODE;
+		else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_PULSES;
+		else
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS;
+
+		panel->video_config.hsa_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA;
+		panel->video_config.hbp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP;
+		panel->video_config.hfp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP;
+		panel->video_config.pulse_mode_hsa_he =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE;
+		panel->video_config.bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BLLP;
+		panel->video_config.eof_bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+	} else {
+		panel->panel_mode = DSI_OP_CMD_MODE;
+		pr_err("command mode not supported by ext bridge\n");
+		return -ENOTSUPP;
+	}
+
+	/* TODO: add calc for these 2 values */
+	panel->host_config.t_clk_post = 0x03;
+	panel->host_config.t_clk_pre = 0x24;
+
+	panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN;
+
+	return 0;
+}
+
 static int dsi_host_attach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
-	return 0;
+	struct dsi_display *display = to_dsi_display(host);
+	int ret = 0;
+
+	if (!host || !dsi) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("host attach\n");
+
+	if (dsi_display_has_ext_bridge(display))
+		ret = dsi_display_populate_ext_bridge_config(display, dsi);
+
+	return ret;
 }
 
+
 static int dsi_host_detach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
+	pr_debug("host detach\n");
 	return 0;
 }
 
@@ -2468,23 +2967,6 @@
 	}
 }
 
-static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
-{
-	int i;
-	struct dsi_display_ctrl *ctrl;
-
-	if (!display)
-		return;
-
-	for (i = 0; (i < display->ctrl_count) &&
-			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
-		ctrl = &display->ctrl[i];
-		if (!ctrl)
-			continue;
-		dsi_ctrl_irq_update(ctrl->ctrl, en);
-	}
-}
-
 int dsi_pre_clkoff_cb(void *priv,
 			   enum dsi_clk_type clk,
 			   enum dsi_clk_state new_state)
@@ -2847,13 +3329,36 @@
 	of_node = of_parse_phandle(display->pdev->dev.of_node,
 				   "qcom,dsi-panel", 0);
 	if (!of_node) {
-		pr_err("No Panel device present\n");
-		rc = -ENODEV;
-		goto error;
+		struct device_node *endpoint;
+
+		endpoint = of_graph_get_next_endpoint(
+				display->pdev->dev.of_node, NULL);
+		if (!endpoint) {
+			pr_err("no endpoint for ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+
+		of_node = of_graph_get_remote_port_parent(endpoint);
+		of_node_put(endpoint);
+		if (!of_node) {
+			pr_err("no valid ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+		of_node_put(of_node);
+
+		display->panel_of = of_node;
+		/* TODO: split support */
+		display->type = DSI_DISPLAY_EXT_BRIDGE;
 	} else {
 		display->panel_of = of_node;
+		display->type = DSI_DISPLAY_SINGLE;
 	}
 
+	/* Parse TE gpio */
+	dsi_display_parse_te_gpio(display);
+
 error:
 	return rc;
 }
@@ -2863,6 +3368,8 @@
 	int rc = 0;
 	int i;
 	struct dsi_display_ctrl *ctrl;
+	enum dsi_panel_type panel_type =
+		dsi_display_has_ext_bridge(display) ? EXT_BRIDGE : DSI_PANEL;
 
 	for (i = 0; i < display->ctrl_count; i++) {
 		ctrl = &display->ctrl[i];
@@ -2885,7 +3392,8 @@
 	}
 
 	display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
-						display->cmdline_topology);
+					display->cmdline_topology, panel_type);
+
 	if (IS_ERR_OR_NULL(display->panel)) {
 		rc = PTR_ERR(display->panel);
 		pr_err("failed to get panel, rc=%d\n", rc);
@@ -3300,9 +3808,9 @@
 	struct dsi_display_mode_priv_info *priv_info;
 
 	priv_info = mode->priv_info;
-	if (!priv_info) {
+	if (!dsi_display_has_ext_bridge(display) && !priv_info) {
 		pr_err("[%s] failed to get private info of the display mode",
-			display->name);
+				display->name);
 		return -EINVAL;
 	}
 
@@ -3339,7 +3847,8 @@
 		}
 	}
 
-	if (priv_info->phy_timing_len) {
+	/* ext bridge calculates these timing params by phy driver */
+	if (priv_info && priv_info->phy_timing_len) {
 		for (i = 0; i < display->ctrl_count; i++) {
 			ctrl = &display->ctrl[i];
 			 rc = dsi_phy_set_timing_params(ctrl->phy,
@@ -3424,6 +3933,12 @@
 {
 	int rc = 0;
 
+	/* Continuous splash not supported by external bridge */
+	if (dsi_display_has_ext_bridge(display)) {
+		display->is_cont_splash_enabled = false;
+		return 0;
+	}
+
 	/* Vote for gdsc required to read register address space */
 
 	display->cont_splash_client = sde_power_client_create(display->phandle,
@@ -3436,7 +3951,9 @@
 		return -EINVAL;
 	}
 
-	/* Verify whether continuous splash is enabled or not */
+	/*
+	 * Verify whether continuous splash is enabled or not.
+	 */
 	display->is_cont_splash_enabled =
 		dsi_display_get_cont_splash_status(display);
 	if (!display->is_cont_splash_enabled) {
@@ -3698,6 +4215,9 @@
 		}
 	}
 
+	/* register te irq handler */
+	dsi_display_register_te_irq(display);
+
 	/* Initialize resources for continuous splash */
 	rc = dsi_display_splash_res_init(display);
 	if (rc)
@@ -4029,7 +4549,7 @@
 	}
 
 	if (display->bridge) {
-		pr_err("display is already initialize\n");
+		pr_err("display is already initialized\n");
 		goto error;
 	}
 
@@ -4048,6 +4568,56 @@
 	return rc;
 }
 
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector)
+{
+	int rc = 0;
+	struct drm_bridge *ext_bridge;
+	struct msm_drm_private *priv = NULL;
+
+	if (!display || !display->drm_dev || !enc) {
+		pr_err("invalid param(s)\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+	priv = display->drm_dev->dev_private;
+
+	if (!priv) {
+		pr_err("Private data is not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!display->bridge) {
+		pr_err("dsi bridge is not initialize\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	ext_bridge = of_drm_find_bridge(display->panel_of);
+	if (!ext_bridge) {
+		pr_err("ext brige not found\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* update connector ops in ext bridge */
+	drm_bridge_connector_init(ext_bridge, connector);
+
+	/* insert ext bridge to the bridge chain */
+	display->bridge->base.next = ext_bridge;
+	ext_bridge->encoder = enc;
+	priv->bridges[priv->num_bridges++] = ext_bridge;
+
+	drm_bridge_attach(display->drm_dev, ext_bridge);
+
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+
+}
+
 int dsi_display_drm_bridge_deinit(struct dsi_display *display)
 {
 	int rc = 0;
@@ -4127,6 +4697,44 @@
 	return rc;
 }
 
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp)
+{
+	struct dsi_display *display;
+	int i;
+
+	if (!info || !disp) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	display = disp;
+	if (!display->panel) {
+		pr_err("invalid display panel\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	memset(info, 0, sizeof(struct msm_display_info));
+
+	info->intf_type = DRM_MODE_CONNECTOR_DSI;
+	info->num_of_h_tiles = display->ctrl_count;
+	for (i = 0; i < info->num_of_h_tiles; i++)
+		info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
+
+	/*
+	 * TODO: these info need come from ext bridge.
+	 * using drm_connector->status, connector->polled.
+	 */
+	info->is_connected = true;
+	info->is_primary = true;
+	info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
+		MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
+
+	mutex_unlock(&display->display_lock);
+	return 0;
+}
+
 static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
 			u32 *count)
 {
@@ -4851,12 +5459,15 @@
 	mode = display->panel->cur_mode;
 
 	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+		if (display->is_cont_splash_enabled) {
+			pr_err("DMS is not supposed to be set on first frame\n");
+			return -EINVAL;
+		}
 		/* update dsi ctrl for new mode */
 		rc = dsi_display_pre_switch(display);
 		if (rc)
 			pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
-				   display->name, rc);
-
+					display->name, rc);
 		goto error;
 	}
 
@@ -4990,6 +5601,9 @@
 	struct dsi_rect req_roi = { 0 };
 	int rc = 0;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5043,6 +5657,9 @@
 	if (!display || !rois || !display->panel)
 		return -EINVAL;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5197,7 +5814,7 @@
 		}
 	}
 
-	if (mode->priv_info->dsc_enabled) {
+	if (mode->priv_info && mode->priv_info->dsc_enabled) {
 		mode->priv_info->dsc.pic_width *= display->ctrl_count;
 		rc = dsi_panel_update_pps(display->panel);
 		if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 4cfd4a9..bb6c8c6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation.All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -132,6 +132,9 @@
  * @is_active:        Is display active.
  * @is_cont_splash_enabled:  Is continuous splash enabled
  * @display_lock:     Mutex for dsi_display interface.
+ * @disp_te_gpio:     GPIO for panel TE interrupt.
+ * @is_te_irq_enabled:bool to specify whether TE interrupt is enabled.
+ * @esd_te_gate:      completion gate to signal TE interrupt.
  * @ctrl_count:       Number of DSI interfaces required by panel.
  * @ctrl:             Controller information for DSI display.
  * @panel:            Handle to DSI panel.
@@ -160,6 +163,7 @@
  * @root:             Debugfs root directory
  * @misr_enable       Frame MISR enable/disable
  * @misr_frame_count  Number of frames to accumulate the MISR value
+ * @esd_trigger       field indicating ESD trigger through debugfs
  */
 struct dsi_display {
 	struct platform_device *pdev;
@@ -172,6 +176,9 @@
 	bool is_active;
 	bool is_cont_splash_enabled;
 	struct mutex display_lock;
+	int disp_te_gpio;
+	bool is_te_irq_enabled;
+	struct completion esd_te_gate;
 
 	u32 ctrl_count;
 	struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
@@ -218,6 +225,7 @@
 
 	bool misr_enable;
 	u32 misr_frame_count;
+	u32 esd_trigger;
 	/* multiple dsi error handlers */
 	struct workqueue_struct *err_workq;
 	struct work_struct fifo_underflow_work;
@@ -225,6 +233,18 @@
 	struct work_struct lp_rx_timeout_work;
 };
 
+/**
+ * dsi_display_has_ext_bridge() - check whether display has ext bridge
+ *                                connected.
+ *
+ * Return: True - ext bridge, False - no ext bridge.
+ */
+static inline bool dsi_display_has_ext_bridge(const struct dsi_display *display)
+{
+	return display->type == DSI_DISPLAY_EXT_BRIDGE ||
+		display->type == DSI_DISPLAY_SPLIT_EXT_BRIDGE;
+}
+
 int dsi_display_dev_probe(struct platform_device *pdev);
 int dsi_display_dev_remove(struct platform_device *pdev);
 
@@ -288,6 +308,19 @@
 int dsi_display_drm_bridge_deinit(struct dsi_display *display);
 
 /**
+ * dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge
+ * @display:            Handle to the display.
+ * @enc:                Pointer to the encoder object which is connected to the
+ *			display.
+ * @connector:          Pointer to the connector object which is connected to
+ *                      the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector);
+
+/**
  * dsi_display_get_info() - returns the display properties
  * @info:             Pointer to the structure where info is stored.
  * @disp:             Handle to the display.
@@ -297,6 +330,15 @@
 int dsi_display_get_info(struct msm_display_info *info, void *disp);
 
 /**
+ * dsi_display_ext_bridge_get_info() - returns the ext bridge's display info
+ * @info:             Pointer to the structure where info is stored.
+ * @disp:             Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp);
+
+/**
  * dsi_display_get_mode_count() - get number of modes supported by the display
  * @display:            Handle to display.
  * @count:              Number of modes supported
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index a1e4685..5b47865 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -63,6 +63,11 @@
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
 	if (msm_is_mode_seamless_vrr(drm_mode))
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+
+	dsi_mode->timing.h_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
+	dsi_mode->timing.v_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
 }
 
 void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -101,6 +106,11 @@
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
 		drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
 
+	if (dsi_mode->timing.h_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	if (dsi_mode->timing.v_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
 	drm_mode_set_name(drm_mode);
 }
 
@@ -288,17 +298,23 @@
 
 	convert_to_dsi_mode(mode, &dsi_mode);
 
-	/*
-	 * retrieve dsi mode from dsi driver's cache since not safe to take
-	 * the drm mode config mutex in all paths
-	 */
-	rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
-	if (rc)
-		return rc;
+	/* external bridge doesn't use priv_info and dsi_mode_flags */
+	if (!dsi_display_has_ext_bridge(display)) {
+		/*
+		 * retrieve dsi mode from dsi driver's cache since not safe to
+		 * take the drm mode config mutex in all paths
+		 */
+		rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+		if (rc)
+			return rc;
 
-	/* propagate the private info to the adjusted_mode derived dsi mode */
-	dsi_mode.priv_info = panel_dsi_mode->priv_info;
-	dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+		/*
+		 * propagate the private info to the adjusted_mode derived dsi
+		 * mode
+		 */
+		dsi_mode.priv_info = panel_dsi_mode->priv_info;
+		dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+	}
 
 	rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
 			DSI_VALIDATE_FLAG_ALLOW_ADJUST);
@@ -377,6 +393,35 @@
 	return 0;
 }
 
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info,
+	u32 max_mixer_width, void *display)
+{
+	struct msm_display_topology *topology;
+	struct dsi_display_mode dsi_mode;
+	struct dsi_mode_info *timing;
+
+	if (!drm_mode || !mode_info)
+		return -EINVAL;
+
+	convert_to_dsi_mode(drm_mode, &dsi_mode);
+
+	memset(mode_info, 0, sizeof(*mode_info));
+
+	timing = &dsi_mode.timing;
+	mode_info->frame_rate = dsi_mode.timing.refresh_rate;
+	mode_info->vtotal = DSI_V_TOTAL(timing);
+
+	topology = &mode_info->topology;
+	topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? 2 : 1;
+	topology->num_enc = 0;
+	topology->num_intf = topology->num_lm;
+
+	mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
+	return 0;
+}
+
 static const struct drm_bridge_funcs dsi_bridge_ops = {
 	.attach       = dsi_bridge_attach,
 	.mode_fixup   = dsi_bridge_mode_fixup,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index ec58479..2bad8c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -86,6 +86,18 @@
 	void *display);
 
 /**
+ * dsi_conn_ext_bridge_get_mode_info - retrieve information on the mode selected
+ * @drm_mode: Display mode set for the display
+ * @mode_info: Out parameter. information of the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info, u32 max_mixer_width,
+	void *display);
+
+/**
  * dsi_conn_mode_valid - callback to determine if specified mode is valid
  * @connector: Pointer to drm connector structure
  * @mode: Pointer to drm mode structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 0ffece3..31d6fd1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <video/mipi_display.h>
+#include <linux/firmware.h>
 
 #include "dsi_panel.h"
 #include "dsi_ctrl_hw.h"
@@ -32,6 +33,7 @@
 #define MAX_TOPOLOGY 5
 
 #define DSI_PANEL_DEFAULT_LABEL  "Default dsi panel"
+#define EXT_BRIDGE_DEFAULT_LABEL  "Default ext bridge"
 
 #define DEFAULT_MDP_TRANSFER_TIME 14000
 
@@ -321,6 +323,30 @@
 	return rc;
 }
 
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel)
+{
+	struct dsi_panel_reset_config *r_config;
+
+	if (!panel) {
+		pr_err("Invalid panel param\n");
+		return -EINVAL;
+	}
+
+	r_config = &panel->reset_config;
+	if (!r_config) {
+		pr_err("Invalid panel reset configuration\n");
+		return -EINVAL;
+	}
+
+	if (gpio_is_valid(r_config->reset_gpio)) {
+		gpio_set_value(r_config->reset_gpio, 0);
+		pr_info("GPIO pulled low to simulate ESD\n");
+		return 0;
+	}
+	pr_err("failed to pull down gpio\n");
+	return -EINVAL;
+}
+
 static int dsi_panel_reset(struct dsi_panel *panel)
 {
 	int rc = 0;
@@ -480,6 +506,9 @@
 	if (!panel || !panel->cur_mode)
 		return -EINVAL;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mode = panel->cur_mode;
 
 	cmds = mode->priv_info->cmd_sets[type].cmds;
@@ -610,13 +639,10 @@
 
 	dsi = &panel->mipi_device;
 
-	mutex_lock(&panel->panel_lock);
-
 	rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl);
 	if (rc < 0)
 		pr_err("failed to update dcs backlight:%d\n", bl_lvl);
 
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -625,13 +651,16 @@
 	int rc = 0;
 	struct dsi_backlight_config *bl = &panel->bl_config;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl);
 	switch (bl->type) {
 	case DSI_BACKLIGHT_WLED:
 		led_trigger_event(bl->wled, bl_lvl);
 		break;
 	case DSI_BACKLIGHT_DCS:
-		dsi_panel_update_backlight(panel, bl_lvl);
+		rc = dsi_panel_update_backlight(panel, bl_lvl);
 		break;
 	default:
 		pr_err("Backlight type(%d) not supported\n", bl->type);
@@ -682,12 +711,58 @@
 error:
 	return rc;
 }
-static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
-				  struct device_node *of_node)
+
+static int dsi_panel_fw_parse(const struct firmware *fw_entry,
+		char *id_match, u32 *param_value)
 {
-	int rc = 0;
+	int value, numlen = 1, index = 0;
+	char id[SZ_256];
+
+	while (sscanf(fw_entry->data + index,
+			"%255s %d", id, &value) > 0) {
+		if (!strcmp(id, id_match)) {
+			*param_value = value;
+			return 0;
+		}
+
+		while ((value / 10) > 0) {
+			value /= 10;
+			numlen++;
+		}
+
+		index += (strlen(id) + numlen + 1);
+		numlen = 1;
+	}
+
+	return -EINVAL;
+}
+
+static int dsi_panel_parse(struct device_node *of_node,
+	const struct firmware *fw_entry, char *id_match, u32 *val)
+{
+	if (fw_entry && fw_entry->data)
+		return dsi_panel_fw_parse(fw_entry, id_match, val);
+	else
+		return of_property_read_u32(of_node, id_match, val);
+
+	return 0;
+}
+
+static int dsi_panel_parse_timing(struct device *parent,
+	struct dsi_mode_info *mode, const char *name,
+	struct device_node *of_node)
+{
+	int fw = 0, rc = 0;
 	u64 tmp64;
 	struct dsi_display_mode *display_mode;
+	const struct firmware *fw_entry = NULL;
+	char *fw_name = "dsi_prop";
+
+	if (strcmp(name, "Simulator video mode dsi panel") == 0)
+		fw = request_firmware(&fw_entry, fw_name, parent);
+
+	if (fw)
+		fw_entry = NULL;
 
 	display_mode = container_of(mode, struct dsi_display_mode, timing);
 
@@ -702,47 +777,47 @@
 	mode->clk_rate_hz = !rc ? tmp64 : 0;
 	display_mode->priv_info->clk_rate_hz = mode->clk_rate_hz;
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-framerate",
-				  &mode->refresh_rate);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-panel-framerate", &mode->refresh_rate);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-panel-framerate, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-width",
-				  &mode->h_active);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-panel-width", &mode->h_active);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-panel-width, rc=%d\n", rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-front-porch",
-				  &mode->h_front_porch);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-h-front-porch", &mode->h_front_porch);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-h-front-porch, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-back-porch",
-				  &mode->h_back_porch);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-h-back-porch", &mode->h_back_porch);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-h-back-porch, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-pulse-width",
-				  &mode->h_sync_width);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-h-pulse-width", &mode->h_sync_width);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-h-pulse-width, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-sync-skew",
-				  &mode->h_skew);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-h-sync-skew", &mode->h_skew);
 	if (rc)
 		pr_err("qcom,mdss-dsi-h-sync-skew is not defined, rc=%d\n", rc);
 
@@ -750,32 +825,32 @@
 		mode->h_active, mode->h_front_porch, mode->h_back_porch,
 		mode->h_sync_width);
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-height",
-				  &mode->v_active);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-panel-height", &mode->v_active);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-panel-height, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-back-porch",
-				  &mode->v_back_porch);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-v-back-porch", &mode->v_back_porch);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-front-porch",
-				  &mode->v_front_porch);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-v-front-porch", &mode->v_front_porch);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n",
 		       rc);
 		goto error;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-pulse-width",
-				  &mode->v_sync_width);
+	rc = dsi_panel_parse(of_node, fw_entry,
+		"qcom,mdss-dsi-v-pulse-width", &mode->v_sync_width);
 	if (rc) {
 		pr_err("failed to read qcom,mdss-dsi-v-pulse-width, rc=%d\n",
 		       rc);
@@ -2552,54 +2627,23 @@
 	kfree(esd_config->status_cmd.cmds);
 }
 
-static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
-				     struct device_node *of_node)
+int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
+				struct device_node *of_node)
 {
+	struct drm_panel_esd_config *esd_config;
 	int rc = 0;
 	u32 tmp;
 	u32 i, status_len, *lenp;
 	struct property *data;
-	const char *string;
-	struct drm_panel_esd_config *esd_config;
-	u8 *esd_mode = NULL;
 
-	esd_config = &panel->esd_config;
-	esd_config->status_mode = ESD_MODE_MAX;
-	esd_config->esd_enabled = of_property_read_bool(of_node,
-		"qcom,esd-check-enabled");
-
-	if (!esd_config->esd_enabled)
-		return 0;
-
-	rc = of_property_read_string(of_node,
-			"qcom,mdss-dsi-panel-status-check-mode", &string);
-	if (!rc) {
-		if (!strcmp(string, "bta_check")) {
-			esd_config->status_mode = ESD_MODE_SW_BTA;
-		} else if (!strcmp(string, "reg_read")) {
-			esd_config->status_mode = ESD_MODE_REG_READ;
-		} else if (!strcmp(string, "te_signal_check")) {
-			if (panel->panel_mode == DSI_OP_CMD_MODE) {
-				esd_config->status_mode = ESD_MODE_PANEL_TE;
-			} else {
-				pr_err("TE-ESD not valid for video mode\n");
-				rc = -EINVAL;
-				goto error;
-			}
-		} else {
-			pr_err("No valid panel-status-check-mode string\n");
-			rc = -EINVAL;
-			goto error;
-		}
-	} else {
-		pr_debug("status check method not defined!\n");
-		rc = -EINVAL;
-		goto error;
+	if (!panel || !of_node) {
+		pr_err("Invalid Params\n");
+		return -EINVAL;
 	}
 
-	if ((esd_config->status_mode == ESD_MODE_SW_BTA) ||
-		(esd_config->status_mode == ESD_MODE_PANEL_TE))
-		return 0;
+	esd_config = &panel->esd_config;
+	if (!esd_config)
+		return -EINVAL;
 
 	dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd,
 				DSI_CMD_SET_PANEL_STATUS, of_node);
@@ -2674,8 +2718,10 @@
 	}
 
 	esd_config->status_buf = kzalloc(SZ_4K, GFP_KERNEL);
-	if (!esd_config->status_buf)
+	if (!esd_config->status_buf) {
+		rc = -ENOMEM;
 		goto error4;
+	}
 
 	rc = of_property_read_u32_array(of_node,
 		"qcom,mdss-dsi-panel-status-value",
@@ -2686,15 +2732,6 @@
 				esd_config->groups * status_len);
 	}
 
-	if (panel->esd_config.status_mode == ESD_MODE_REG_READ)
-		esd_mode = "register_read";
-	else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA)
-		esd_mode = "bta_trigger";
-	else if (panel->esd_config.status_mode ==  ESD_MODE_PANEL_TE)
-		esd_mode = "te_check";
-
-	pr_info("ESD enabled with mode: %s\n", esd_mode);
-
 	return 0;
 
 error4:
@@ -2707,13 +2744,78 @@
 error1:
 	kfree(esd_config->status_cmd.cmds);
 error:
+	return rc;
+}
+
+static int dsi_panel_parse_esd_config(struct dsi_panel *panel,
+				     struct device_node *of_node)
+{
+	int rc = 0;
+	const char *string;
+	struct drm_panel_esd_config *esd_config;
+	u8 *esd_mode = NULL;
+
+	esd_config = &panel->esd_config;
+	esd_config->status_mode = ESD_MODE_MAX;
+	esd_config->esd_enabled = of_property_read_bool(of_node,
+		"qcom,esd-check-enabled");
+
+	if (!esd_config->esd_enabled)
+		return 0;
+
+	rc = of_property_read_string(of_node,
+			"qcom,mdss-dsi-panel-status-check-mode", &string);
+	if (!rc) {
+		if (!strcmp(string, "bta_check")) {
+			esd_config->status_mode = ESD_MODE_SW_BTA;
+		} else if (!strcmp(string, "reg_read")) {
+			esd_config->status_mode = ESD_MODE_REG_READ;
+		} else if (!strcmp(string, "te_signal_check")) {
+			if (panel->panel_mode == DSI_OP_CMD_MODE) {
+				esd_config->status_mode = ESD_MODE_PANEL_TE;
+			} else {
+				pr_err("TE-ESD not valid for video mode\n");
+				rc = -EINVAL;
+				goto error;
+			}
+		} else {
+			pr_err("No valid panel-status-check-mode string\n");
+			rc = -EINVAL;
+			goto error;
+		}
+	} else {
+		pr_debug("status check method not defined!\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (panel->esd_config.status_mode == ESD_MODE_REG_READ) {
+		rc = dsi_panel_parse_esd_reg_read_configs(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse esd reg read mode params, rc=%d\n",
+						rc);
+			goto error;
+		}
+		esd_mode = "register_read";
+	} else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA) {
+		esd_mode = "bta_trigger";
+	} else if (panel->esd_config.status_mode ==  ESD_MODE_PANEL_TE) {
+		esd_mode = "te_check";
+	}
+
+	pr_info("ESD enabled with mode: %s\n", esd_mode);
+
+	return 0;
+
+error:
 	panel->esd_config.esd_enabled = false;
 	return rc;
 }
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override)
+				int topology_override,
+				enum dsi_panel_type type)
 {
 	struct dsi_panel *panel;
 	int rc = 0;
@@ -2722,68 +2824,85 @@
 	if (!panel)
 		return ERR_PTR(-ENOMEM);
 
-	panel->name = of_get_property(of_node, "qcom,mdss-dsi-panel-name",
-				      NULL);
-	if (!panel->name)
-		panel->name = DSI_PANEL_DEFAULT_LABEL;
+	if (type == DSI_PANEL) {
+		panel->name = of_get_property(of_node,
+			"qcom,mdss-dsi-panel-name", NULL);
+		if (!panel->name)
+			panel->name = DSI_PANEL_DEFAULT_LABEL;
 
-	rc = dsi_panel_parse_host_config(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse host configuration, rc=%d\n", rc);
+		rc = dsi_panel_parse_host_config(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse host configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_panel_mode(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse panel mode configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps,
+			of_node, panel->name);
+		if (rc)
+			pr_err("failed to parse dfps configuration, rc=%d\n",
+				rc);
+
+		rc = dsi_panel_parse_phy_props(&panel->phy_props,
+			of_node, panel->name);
+		if (rc) {
+			pr_err("failed to parse panel physical dimension, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
+		if (rc)
+			pr_err("failed to parse power config, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_gpios(panel, of_node);
+		if (rc)
+			pr_err("failed to parse panel gpios, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_bl_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse backlight config, rc=%d\n", rc);
+
+
+		rc = dsi_panel_parse_misc_features(panel, of_node);
+		if (rc)
+			pr_err("failed to parse misc features, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_hdr_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse hdr config, rc=%d\n", rc);
+
+		rc = dsi_panel_get_mode_count(panel, of_node);
+		if (rc) {
+			pr_err("failed to get mode count, rc=%d\n", rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dms_info(panel, of_node);
+		if (rc)
+			pr_debug("failed to get dms info, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_esd_config(panel, of_node);
+		if (rc)
+			pr_debug("failed to parse esd config, rc=%d\n", rc);
+
+		panel->type = DSI_PANEL;
+	} else if (type == EXT_BRIDGE) {
+		panel->name = EXT_BRIDGE_DEFAULT_LABEL;
+		panel->type = EXT_BRIDGE;
+	} else {
+		pr_err("invalid panel type\n");
+		rc = -ENOTSUPP;
 		goto error;
 	}
 
-	rc = dsi_panel_parse_panel_mode(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse panel mode configuration, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps, of_node, panel->name);
-	if (rc)
-		pr_err("failed to parse dfps configuration, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_phy_props(&panel->phy_props, of_node, panel->name);
-	if (rc) {
-		pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
-	if (rc)
-		pr_err("failed to parse power config, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_gpios(panel, of_node);
-	if (rc)
-		pr_err("failed to parse panel gpios, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_bl_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse backlight config, rc=%d\n", rc);
-
-
-	rc = dsi_panel_parse_misc_features(panel, of_node);
-	if (rc)
-		pr_err("failed to parse misc features, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_hdr_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse hdr config, rc=%d\n", rc);
-
-	rc = dsi_panel_get_mode_count(panel, of_node);
-	if (rc) {
-		pr_err("failed to get mode count, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dms_info(panel, of_node);
-	if (rc)
-		pr_debug("failed to get dms info, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_esd_config(panel, of_node);
-	if (rc)
-		pr_debug("failed to parse esd config, rc=%d\n", rc);
-
 	panel->panel_of_node = of_node;
 	drm_panel_init(&panel->drm_panel);
 	mutex_init(&panel->panel_lock);
@@ -2797,7 +2916,8 @@
 void dsi_panel_put(struct dsi_panel *panel)
 {
 	/* free resources allocated for ESD check */
-	dsi_panel_esd_config_deinit(&panel->esd_config);
+	if (panel->type == DSI_PANEL)
+		dsi_panel_esd_config_deinit(&panel->esd_config);
 
 	kfree(panel);
 }
@@ -2813,6 +2933,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	dev = &panel->mipi_device;
@@ -2877,6 +3000,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_bl_unregister(panel);
@@ -2960,11 +3086,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&panel->panel_lock);
-
 	memcpy(phy_props, &panel->phy_props, sizeof(*phy_props));
-
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -2978,11 +3100,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&panel->panel_lock);
-
 	memcpy(dfps_caps, &panel->dfps_caps, sizeof(*dfps_caps));
-
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -3013,6 +3131,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL);
@@ -3042,7 +3163,8 @@
 		if (index != child_idx++)
 			continue;
 
-		rc = dsi_panel_parse_timing(&mode->timing, child_np);
+		rc = dsi_panel_parse_timing(panel->parent, &mode->timing,
+			panel->name, child_np);
 		if (rc) {
 			pr_err("failed to parse panel timing, rc=%d\n", rc);
 			goto parse_fail;
@@ -3120,10 +3242,12 @@
 
 	memcpy(&config->video_timing, &mode->timing,
 	       sizeof(config->video_timing));
-	config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
-	config->video_timing.dsc = &mode->priv_info->dsc;
 
-	config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	if (mode->priv_info) {
+		config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
+		config->video_timing.dsc = &mode->priv_info->dsc;
+		config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	}
 	config->esc_clk_rate_hz = 19200000;
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -3138,6 +3262,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	/* If LP11_INIT is set, panel will be powered up during prepare() */
@@ -3166,6 +3293,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	priv_info = panel->cur_mode->priv_info;
@@ -3201,6 +3331,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
 	if (rc)
@@ -3219,6 +3352,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
 	if (rc)
@@ -3237,6 +3373,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
 	if (rc)
@@ -3255,6 +3394,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (panel->lp11_init) {
@@ -3329,7 +3471,7 @@
 	set->cmds[0].msg.rx_len = 0;
 	set->cmds[0].msg.rx_buf = 0;
 	set->cmds[0].last_command = 0;
-	set->cmds[0].post_wait_ms = 1;
+	set->cmds[0].post_wait_ms = 0;
 
 	set->cmds[1].msg.channel = 0;
 	set->cmds[1].msg.type = MIPI_DSI_DCS_LONG_WRITE;
@@ -3340,7 +3482,7 @@
 	set->cmds[1].msg.rx_len = 0;
 	set->cmds[1].msg.rx_buf = 0;
 	set->cmds[1].last_command = 1;
-	set->cmds[1].post_wait_ms = 1;
+	set->cmds[1].post_wait_ms = 0;
 
 	goto exit;
 
@@ -3365,6 +3507,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	priv_info = panel->cur_mode->priv_info;
 	set = &priv_info->cmd_sets[DSI_CMD_SET_ROI];
 
@@ -3400,6 +3545,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
@@ -3420,6 +3568,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH);
@@ -3440,6 +3591,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON);
@@ -3461,6 +3615,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_ON);
@@ -3483,6 +3640,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF);
@@ -3506,6 +3666,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF);
@@ -3530,6 +3693,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_OFF);
@@ -3561,6 +3727,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (!panel->lp11_init) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 06199f4..f8b65ab 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -140,8 +140,15 @@
 	u32 groups;
 };
 
+enum dsi_panel_type {
+	DSI_PANEL = 0,
+	EXT_BRIDGE,
+	DSI_PANEL_TYPE_MAX,
+};
+
 struct dsi_panel {
 	const char *name;
+	enum dsi_panel_type type;
 	struct device_node *panel_of_node;
 	struct mipi_dsi_device mipi_device;
 
@@ -204,7 +211,10 @@
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override);
+				int topology_override,
+				enum dsi_panel_type type);
+
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel);
 
 void dsi_panel_put(struct dsi_panel *panel);
 
@@ -269,4 +279,13 @@
 
 void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
 
+struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent,
+				struct device_node *of_node,
+				int topology_override);
+
+int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel,
+				struct device_node *of_node);
+
+void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
+
 #endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 07b2305..cc74de2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -694,8 +694,7 @@
 	u32 lanes = 0;
 	u32 ulps_lanes;
 
-	if (config->panel_mode == DSI_OP_CMD_MODE)
-		lanes = config->common_config.data_lanes;
+	lanes = config->common_config.data_lanes;
 	lanes |= DSI_CLOCK_LANE;
 
 	/*
@@ -730,8 +729,7 @@
 {
 	u32 ulps_lanes, lanes = 0;
 
-	if (config->panel_mode == DSI_OP_CMD_MODE)
-		lanes = config->common_config.data_lanes;
+	lanes = config->common_config.data_lanes;
 	lanes |= DSI_CLOCK_LANE;
 
 	ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index c1a670d..d5437d0 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -668,6 +668,27 @@
 		}
 	}
 
+	/**
+	 * Since pp interrupt is heavy weight, try to queue the work
+	 * into a dedicated worker thread, so that they dont interrupt
+	 * other important events.
+	 */
+	kthread_init_worker(&priv->pp_event_worker);
+	priv->pp_event_thread = kthread_run(kthread_worker_fn,
+			&priv->pp_event_worker, "pp_event");
+
+	ret = sched_setscheduler(priv->pp_event_thread,
+						SCHED_FIFO, &param);
+	if (ret)
+		pr_warn("pp_event thread priority update failed: %d\n",
+								ret);
+
+	if (IS_ERR(priv->pp_event_thread)) {
+		dev_err(dev, "failed to create pp_event kthread\n");
+		priv->pp_event_thread = NULL;
+		goto fail;
+	}
+
 	ret = drm_vblank_init(ddev, priv->num_crtcs);
 	if (ret < 0) {
 		dev_err(dev, "failed to initialize vblank\n");
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index cc09256..17a41d5 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -578,6 +578,9 @@
 	struct msm_drm_thread disp_thread[MAX_CRTCS];
 	struct msm_drm_thread event_thread[MAX_CRTCS];
 
+	struct task_struct *pp_event_thread;
+	struct kthread_worker pp_event_worker;
+
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[MAX_ENCODERS];
 
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index 211acce..85867b2 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -321,7 +321,7 @@
 		DRM_DEBUG("%pad/0x%x/0x%x/0x%lx\n", &sgt->sgl->dma_address,
 				sgt->sgl->dma_length, dir, attrs);
 		SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length,
-				dir, attrs);
+				dir, attrs, client->secure);
 	}
 
 	return 0;
@@ -342,7 +342,8 @@
 	if (sgt && sgt->sgl) {
 		DRM_DEBUG("%pad/0x%x/0x%x\n", &sgt->sgl->dma_address,
 				sgt->sgl->dma_length, dir);
-		SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir);
+		SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir,
+			client->secure);
 	}
 
 	msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
diff --git a/drivers/gpu/drm/msm/sde/sde_ad4.h b/drivers/gpu/drm/msm/sde/sde_ad4.h
index 06f004c..bf08360 100644
--- a/drivers/gpu/drm/msm/sde/sde_ad4.h
+++ b/drivers/gpu/drm/msm/sde/sde_ad4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -48,6 +48,7 @@
 	AD_SUSPEND,
 	AD_ASSERTIVE,
 	AD_BACKLIGHT,
+	AD_STRENGTH,
 	AD_IPC_SUSPEND,
 	AD_IPC_RESUME,
 	AD_IPC_RESET,
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 42aea7e..919ed97 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published by
@@ -25,6 +25,7 @@
 #include "sde_hw_interrupts.h"
 #include "sde_core_irq.h"
 #include "dsi_panel.h"
+#include "sde_hw_color_processing.h"
 
 struct sde_cp_node {
 	u32 property_id;
@@ -69,6 +70,8 @@
 
 static void dspp_hist_install_property(struct drm_crtc *crtc);
 
+static void dspp_dither_install_property(struct drm_crtc *crtc);
+
 typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
 
 static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
@@ -98,6 +101,7 @@
 	func[SDE_DSPP_GC] = dspp_gc_install_property; \
 	func[SDE_DSPP_IGC] = dspp_igc_install_property; \
 	func[SDE_DSPP_HIST] = dspp_hist_install_property; \
+	func[SDE_DSPP_DITHER] = dspp_dither_install_property; \
 } while (0)
 
 typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
@@ -133,6 +137,7 @@
 	SDE_CP_CRTC_DSPP_AD_INPUT,
 	SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
 	SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
+	SDE_CP_CRTC_DSPP_AD_STRENGTH,
 	SDE_CP_CRTC_DSPP_MAX,
 	/* DSPP features end */
 
@@ -144,6 +149,24 @@
 	SDE_CP_CRTC_MAX_FEATURES,
 };
 
+#define HIGH_BUS_VOTE_NEEDED(feature) ((feature == SDE_CP_CRTC_DSPP_IGC) |\
+				 (feature == SDE_CP_CRTC_DSPP_GC) |\
+				 (feature == SDE_CP_CRTC_DSPP_SIXZONE) |\
+				 (feature == SDE_CP_CRTC_DSPP_GAMUT))
+
+static u32 crtc_feature_map[SDE_CP_CRTC_MAX_FEATURES] = {
+	[SDE_CP_CRTC_DSPP_IGC] = SDE_DSPP_IGC,
+	[SDE_CP_CRTC_DSPP_PCC] = SDE_DSPP_PCC,
+	[SDE_CP_CRTC_DSPP_GC] = SDE_DSPP_GC,
+	[SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_MEMCOL_SKY] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_SIXZONE] = SDE_DSPP_SIXZONE,
+	[SDE_CP_CRTC_DSPP_GAMUT] = SDE_DSPP_GAMUT,
+	[SDE_CP_CRTC_DSPP_DITHER] = SDE_DSPP_DITHER,
+	[SDE_CP_CRTC_DSPP_VLUT] = SDE_DSPP_VLUT,
+};
+
 #define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
 	do { \
 		(p)->crtc = crtc; \
@@ -613,6 +636,7 @@
 	if (!node)
 		return;
 
+	spin_lock_irqsave(&node->state_lock, flags);
 	if (node->state == IRQ_DISABLED) {
 		ret = sde_core_irq_enable(kms, &irq_idx, 1);
 		if (ret)
@@ -620,6 +644,7 @@
 		else
 			node->state = IRQ_ENABLED;
 	}
+	spin_unlock_irqrestore(&node->state_lock, flags);
 }
 
 static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
@@ -734,6 +759,13 @@
 			}
 			hw_lm->ops.setup_gc(hw_lm, &hw_cfg);
 			break;
+		case SDE_CP_CRTC_DSPP_DITHER:
+			if (!hw_dspp || !hw_dspp->ops.setup_pa_dither) {
+				ret = -EINVAL;
+				continue;
+			}
+			hw_dspp->ops.setup_pa_dither(hw_dspp, &hw_cfg);
+			break;
 		case SDE_CP_CRTC_DSPP_HIST_CTRL:
 			if (!hw_dspp || !hw_dspp->ops.setup_histogram) {
 				ret = -EINVAL;
@@ -803,6 +835,15 @@
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
 			break;
+		case SDE_CP_CRTC_DSPP_AD_STRENGTH:
+			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
+				ret = -EINVAL;
+				continue;
+			}
+			ad_cfg.prop = AD_STRENGTH;
+			ad_cfg.hw_cfg = &hw_cfg;
+			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			break;
 		default:
 			ret = -EINVAL;
 			break;
@@ -837,6 +878,10 @@
 	struct sde_hw_ctl *ctl;
 	uint32_t flush_mask = 0;
 	u32 num_mixers = 0, i = 0;
+	u32 sde_dspp_feature = SDE_DSPP_MAX;
+	struct msm_drm_private *priv = NULL;
+	struct sde_kms *sde_kms = NULL;
+	bool mdss_bus_vote = false;
 
 	if (!crtc || !crtc->dev) {
 		DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
@@ -856,6 +901,17 @@
 		return;
 	}
 
+	priv = crtc->dev->dev_private;
+	if (!priv || !priv->kms) {
+		SDE_ERROR("invalid kms\n");
+		return;
+	}
+	sde_kms = to_sde_kms(priv->kms);
+	if (!sde_kms) {
+		SDE_ERROR("invalid sde kms\n");
+		return;
+	}
+
 	mutex_lock(&sde_crtc->crtc_cp_lock);
 
 	/* Check if dirty lists are empty and ad features are disabled for
@@ -874,6 +930,16 @@
 
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
 				dirty_list) {
+		sde_dspp_feature = crtc_feature_map[prop_node->feature];
+		if (!mdss_bus_vote && HIGH_BUS_VOTE_NEEDED(prop_node->feature)
+			&& !reg_dmav1_dspp_feature_support(sde_dspp_feature)) {
+			sde_power_scale_reg_bus(&priv->phandle,
+				sde_kms->core_client,
+				VOTE_INDEX_HIGH, false);
+			pr_debug("Vote HIGH for data bus: feature %d\n",
+					prop_node->feature);
+			mdss_bus_vote = true;
+		}
 		sde_cp_crtc_setfeature(prop_node, sde_crtc);
 		/* Set the flush flag to true */
 		if (prop_node->is_dspp_feature)
@@ -881,6 +947,12 @@
 		else
 			set_lm_flush = true;
 	}
+	if (mdss_bus_vote) {
+		sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client,
+			VOTE_INDEX_LOW, false);
+		pr_debug("Vote LOW for data bus\n");
+		mdss_bus_vote = false;
+	}
 
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
 				dirty_list) {
@@ -1158,6 +1230,7 @@
 {
 	struct sde_crtc *sde_crtc = NULL;
 	struct sde_cp_node *prop_node = NULL, *n = NULL;
+	bool ad_suspend = false;
 
 	if (!crtc) {
 		DRM_ERROR("crtc %pK\n", crtc);
@@ -1180,8 +1253,12 @@
 				 active_list) {
 		sde_cp_update_list(prop_node, sde_crtc, true);
 		list_del_init(&prop_node->active_list);
+		ad_suspend = true;
 	}
 	mutex_unlock(&sde_crtc->crtc_cp_lock);
+
+	if (ad_suspend)
+		sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND);
 }
 
 void sde_cp_crtc_resume(struct drm_crtc *crtc)
@@ -1363,6 +1440,9 @@
 		sde_cp_crtc_install_range_property(crtc,
 			"SDE_DSPP_AD_V4_ASSERTIVENESS",
 			SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
+		sde_cp_crtc_install_range_property(crtc,
+			"SDE_DSPP_AD_V4_STRENGTH",
+			SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, (BIT(10) - 1), 0);
 		sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
 			SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
 		sde_cp_crtc_install_range_property(crtc,
@@ -1496,6 +1576,31 @@
 	}
 }
 
+static void dspp_dither_install_property(struct drm_crtc *crtc)
+{
+	char feature_name[256];
+	struct sde_kms *kms = NULL;
+	struct sde_mdss_cfg *catalog = NULL;
+	u32 version;
+
+	kms = get_kms(crtc);
+	catalog = kms->catalog;
+
+	version = catalog->dspp[0].sblk->dither.version >> 16;
+	snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
+		"SDE_DSPP_PA_DITHER_V", version);
+	switch (version) {
+	case 1:
+		sde_cp_crtc_install_blob_property(crtc, feature_name,
+			SDE_CP_CRTC_DSPP_DITHER,
+			sizeof(struct drm_msm_pa_dither));
+		break;
+	default:
+		DRM_ERROR("version %d not supported\n", version);
+		break;
+	}
+}
+
 static void sde_cp_update_list(struct sde_cp_node *prop_node,
 		struct sde_crtc *crtc, bool dirty_list)
 {
@@ -1506,6 +1611,7 @@
 	case SDE_CP_CRTC_DSPP_AD_INPUT:
 	case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
 	case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
+	case SDE_CP_CRTC_DSPP_AD_STRENGTH:
 		if (dirty_list)
 			list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
 		else
@@ -1554,6 +1660,9 @@
 		case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
 			ad_prop = AD_BACKLIGHT;
 			break;
+		case SDE_CP_CRTC_DSPP_AD_STRENGTH:
+			ad_prop = AD_STRENGTH;
+			break;
 		default:
 			/* Not an AD property */
 			return 0;
@@ -1571,7 +1680,8 @@
 {
 	struct sde_crtc *crtc = arg;
 
-	sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
+	sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event,
+							NULL, true);
 }
 
 static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
@@ -1584,6 +1694,9 @@
 	struct sde_crtc *crtc;
 	struct drm_event event;
 	int i;
+	struct msm_drm_private *priv;
+	struct sde_kms *kms;
+	int ret;
 
 	crtc = to_sde_crtc(crtc_drm);
 	num_mixers = crtc->num_mixers;
@@ -1600,9 +1713,25 @@
 	if (!hw_dspp)
 		return;
 
+	kms = get_kms(crtc_drm);
+	if (!kms || !kms->dev) {
+		SDE_ERROR("invalid arg(s)\n");
+		return;
+	}
+
+	priv = kms->dev->dev_private;
+	ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
+	if (ret) {
+		SDE_ERROR("failed to enable power resource %d\n", ret);
+		SDE_EVT32(ret, SDE_EVTLOG_ERROR);
+		return;
+	}
+
 	hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_IN_OUT_BACKLIGHT,
 			&input_bl, &output_bl);
 
+	sde_power_resource_enable(&priv->phandle, kms->core_client,
+					false);
 	if (!input_bl || input_bl < output_bl)
 		return;
 
@@ -1623,6 +1752,7 @@
 	struct sde_crtc *crtc;
 	int i;
 	int irq_idx, ret;
+	unsigned long flags;
 	struct sde_cp_node prop_node;
 	struct sde_crtc_irq_info *node = NULL;
 
@@ -1673,6 +1803,7 @@
 
 	if (!en) {
 		if (node) {
+			spin_lock_irqsave(&node->state_lock, flags);
 			if (node->state == IRQ_ENABLED) {
 				ret = sde_core_irq_disable(kms, &irq_idx, 1);
 				if (ret)
@@ -1683,6 +1814,7 @@
 			} else {
 				node->state = IRQ_NOINIT;
 			}
+			spin_unlock_irqrestore(&node->state_lock, flags);
 		} else {
 			DRM_ERROR("failed to get node from crtc event list\n");
 		}
@@ -1701,6 +1833,7 @@
 
 	if (node) {
 		/* device resume or resume from IPC cases */
+		spin_lock_irqsave(&node->state_lock, flags);
 		if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
 			ret = sde_core_irq_enable(kms, &irq_idx, 1);
 			if (ret) {
@@ -1712,6 +1845,7 @@
 				node->state = IRQ_ENABLED;
 			}
 		}
+		spin_unlock_irqrestore(&node->state_lock, flags);
 	} else {
 		/* request from userspace to register the event
 		 * in this case, node has not been added into the event list
@@ -1807,14 +1941,17 @@
 		return;
 	}
 
+	spin_lock_irqsave(&node->state_lock, flags);
 	if (node->state == IRQ_ENABLED) {
 		if (sde_core_irq_disable_nolock(kms, irq_idx)) {
 			DRM_ERROR("failed to disable irq %d, ret %d\n",
 				irq_idx, ret);
+			spin_unlock_irqrestore(&node->state_lock, flags);
 			return;
 		}
 		node->state = IRQ_DISABLED;
 	}
+	spin_unlock_irqrestore(&node->state_lock, flags);
 
 	/* lock histogram buffer */
 	for (i = 0; i < crtc->num_mixers; i++) {
@@ -1824,7 +1961,8 @@
 	}
 
 	/* notify histogram event */
-	sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event, NULL);
+	sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event,
+							NULL, true);
 }
 
 static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
@@ -1834,6 +1972,9 @@
 	struct drm_event event;
 	struct drm_msm_hist *hist_data;
 	struct drm_msm_hist tmp_hist_data;
+	struct msm_drm_private *priv;
+	struct sde_kms *kms;
+	int ret;
 	u32 i, j;
 
 	if (!crtc_drm) {
@@ -1850,6 +1991,20 @@
 	if (!crtc->hist_blob)
 		return;
 
+	kms = get_kms(crtc_drm);
+	if (!kms || !kms->dev) {
+		SDE_ERROR("invalid arg(s)\n");
+		return;
+	}
+
+	priv = kms->dev->dev_private;
+	ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
+	if (ret) {
+		SDE_ERROR("failed to enable power resource %d\n", ret);
+		SDE_EVT32(ret, SDE_EVTLOG_ERROR);
+		return;
+	}
+
 	/* read histogram data into blob */
 	hist_data = (struct drm_msm_hist *)crtc->hist_blob->data;
 	for (i = 0; i < crtc->num_mixers; i++) {
@@ -1857,6 +2012,8 @@
 		if (!hw_dspp || !hw_dspp->ops.read_histogram) {
 			DRM_ERROR("invalid dspp %pK or read_histogram func\n",
 				hw_dspp);
+			sde_power_resource_enable(&priv->phandle,
+						kms->core_client, false);
 			return;
 		}
 		if (!i) {
@@ -1869,6 +2026,8 @@
 		}
 	}
 
+	sde_power_resource_enable(&priv->phandle, kms->core_client,
+					false);
 	/* send histogram event with blob id */
 	event.length = sizeof(u32);
 	event.type = DRM_EVENT_HISTOGRAM;
@@ -1886,6 +2045,7 @@
 	struct sde_crtc *crtc;
 	struct sde_crtc_irq_info *node = NULL;
 	int i, irq_idx, ret = 0;
+	unsigned long flags;
 
 	if (!crtc_drm || !hist_irq) {
 		DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq);
@@ -1928,6 +2088,7 @@
 	if (!en) {
 		if (node) {
 			/* device suspend case or suspend to IPC cases */
+			spin_lock_irqsave(&node->state_lock, flags);
 			if (node->state == IRQ_ENABLED) {
 				ret = sde_core_irq_disable(kms, &irq_idx, 1);
 				if (ret)
@@ -1938,6 +2099,7 @@
 			} else {
 				node->state = IRQ_NOINIT;
 			}
+			spin_unlock_irqrestore(&node->state_lock, flags);
 		} else {
 			DRM_ERROR("failed to get node from crtc event list\n");
 		}
@@ -1957,6 +2119,7 @@
 
 	if (node) {
 		/* device resume or resume from IPC cases */
+		spin_lock_irqsave(&node->state_lock, flags);
 		if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
 			ret = sde_core_irq_enable(kms, &irq_idx, 1);
 			if (ret) {
@@ -1968,6 +2131,7 @@
 				node->state = IRQ_ENABLED;
 			}
 		}
+		spin_unlock_irqrestore(&node->state_lock, flags);
 	} else {
 		/* request from userspace to register the event
 		 * in this case, node has not been added into the event list
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index df0aad5e..2adae3d 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -68,6 +68,7 @@
 	struct sde_connector *c_conn;
 	int bl_lvl;
 	struct drm_event event;
+	int rc = 0;
 
 	brightness = bd->props.brightness;
 
@@ -93,10 +94,10 @@
 		event.length = sizeof(u32);
 		msm_mode_object_event_notify(&c_conn->base.base,
 				c_conn->base.dev, &event, (u8 *)&brightness);
-		c_conn->ops.set_backlight(c_conn->display, bl_lvl);
+		rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl);
 	}
 
-	return 0;
+	return rc;
 }
 
 static int sde_backlight_device_get_brightness(struct backlight_device *bd)
@@ -471,8 +472,11 @@
 	}
 	c_conn->last_panel_power_mode = mode;
 
-	if (mode != SDE_MODE_DPMS_ON)
+	if (mode != SDE_MODE_DPMS_ON) {
+		mutex_unlock(&c_conn->lock);
 		sde_connector_schedule_status_work(connector, false);
+		mutex_lock(&c_conn->lock);
+	}
 
 	return rc;
 }
@@ -1732,6 +1736,7 @@
 	event.length = sizeof(bool);
 	msm_mode_object_event_notify(&conn->base.base,
 		conn->base.dev, &event, (u8 *)&panel_dead);
+	sde_encoder_display_failure_notification(conn->encoder);
 }
 
 static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 8b0c2fd..161b27e 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -4486,46 +4486,6 @@
 	return rc;
 }
 
-static int _sde_crtc_excl_rect_overlap_check(struct plane_state pstates[],
-	int cnt, int curr_cnt, struct sde_rect *excl_rect)
-{
-	struct sde_rect dst_rect, intersect;
-	int i, rc = -EINVAL;
-	const struct drm_plane_state *pstate;
-
-	for (i = 0; i < cnt; i++) {
-		if (i == curr_cnt)
-			continue;
-
-		pstate = pstates[i].drm_pstate;
-		POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y,
-				pstate->crtc_w, pstate->crtc_h, false);
-		sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect);
-
-		/* complete intersection of excl_rect is required */
-		if (intersect.w == excl_rect->w && intersect.h == excl_rect->h
-			    /* intersecting rect should be in another z_order */
-			    && pstates[curr_cnt].stage != pstates[i].stage) {
-			rc = 0;
-			goto end;
-		}
-	}
-
-	SDE_ERROR(
-	    "no overlapping rect for [%d] z_pos:%d, excl_rect:{%d,%d,%d,%d}\n",
-			i, pstates[curr_cnt].stage,
-			excl_rect->x, excl_rect->y, excl_rect->w, excl_rect->h);
-	for (i = 0; i < cnt; i++) {
-		pstate = pstates[i].drm_pstate;
-		SDE_ERROR("[%d] p:%d, z_pos:%d, src:{%d,%d,%d,%d}\n",
-				i, pstate->plane->base.id, pstates[i].stage,
-				pstate->crtc_x, pstate->crtc_y,
-				pstate->crtc_w, pstate->crtc_h);
-	}
-end:
-	return rc;
-}
-
 /* no input validation - caller API has all the checks */
 static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state,
 		struct plane_state pstates[], int cnt)
@@ -4558,17 +4518,16 @@
 		}
 	}
 
-	/* this is traversing on sorted z-order pstates */
+	/* log all src and excl_rect, useful for debugging */
 	for (i = 0; i < cnt; i++) {
 		pstate = pstates[i].drm_pstate;
 		sde_pstate = to_sde_plane_state(pstate);
-		if (sde_pstate->excl_rect.w && sde_pstate->excl_rect.h) {
-			/* check overlap on any other z-order */
-			rc = _sde_crtc_excl_rect_overlap_check(pstates, cnt,
-			     i, &sde_pstate->excl_rect);
-			if (rc)
-				goto end;
-		}
+		SDE_DEBUG("p %d z %d src{%d,%d,%d,%d} excl_rect{%d,%d,%d,%d}\n",
+			pstate->plane->base.id, pstates[i].stage,
+			pstate->crtc_x, pstate->crtc_y,
+			pstate->crtc_w, pstate->crtc_h,
+			sde_pstate->excl_rect.x, sde_pstate->excl_rect.y,
+			sde_pstate->excl_rect.w, sde_pstate->excl_rect.h);
 	}
 
 end:
@@ -4581,10 +4540,13 @@
 {
 	struct drm_encoder *encoder;
 	struct sde_crtc_state *cstate;
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_smmu_state_data *smmu_state;
 	uint32_t secure;
 	uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
 	int encoder_cnt = 0, i;
 	int rc;
+	bool is_video_mode = false;
 
 	if (!crtc || !state) {
 		SDE_ERROR("invalid arguments\n");
@@ -4642,6 +4604,37 @@
 
 		}
 	}
+
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		is_video_mode |= sde_encoder_check_mode(encoder,
+						MSM_DISPLAY_CAP_VID_MODE);
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+	smmu_state = &sde_crtc->smmu_state;
+	/*
+	 * In video mode check for null commit before transition
+	 * from secure to non secure and vice versa
+	 */
+	if (is_video_mode && smmu_state &&
+		state->plane_mask && crtc->state->plane_mask &&
+		((fb_sec_dir && ((smmu_state->state == ATTACHED) &&
+				(secure == SDE_DRM_SEC_ONLY))) ||
+			(fb_ns && ((smmu_state->state == DETACHED) ||
+				(smmu_state->state == DETACH_ALL_REQ))))) {
+
+		SDE_EVT32(DRMID(&sde_crtc->base), fb_ns, fb_sec_dir,
+		  smmu_state->state, crtc->state->plane_mask,
+			crtc->state->plane_mask);
+		SDE_DEBUG("crtc %d, Invalid secure transition %x\n",
+				crtc->base.id, smmu_state->state);
+		return -EINVAL;
+
+	}
+
 	SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);
 
 	return 0;
@@ -5893,7 +5886,8 @@
 }
 
 int sde_crtc_event_queue(struct drm_crtc *crtc,
-		void (*func)(struct drm_crtc *crtc, void *usr), void *usr)
+		void (*func)(struct drm_crtc *crtc, void *usr),
+		void *usr, bool color_processing_event)
 {
 	unsigned long irq_flags;
 	struct sde_crtc *sde_crtc;
@@ -5932,7 +5926,11 @@
 
 	/* queue new event request */
 	kthread_init_work(&event->kt_work, _sde_crtc_event_cb);
-	kthread_queue_work(&priv->event_thread[crtc_id].worker,
+	if (color_processing_event)
+		kthread_queue_work(&priv->pp_event_worker,
+			&event->kt_work);
+	else
+		kthread_queue_work(&priv->event_thread[crtc_id].worker,
 			&event->kt_work);
 
 	return 0;
@@ -6133,6 +6131,7 @@
 			INIT_LIST_HEAD(&node->list);
 			node->func = custom_events[i].func;
 			node->event = event;
+			spin_lock_init(&node->state_lock);
 			break;
 		}
 	}
@@ -6187,6 +6186,7 @@
 	spin_lock_irqsave(&crtc->spin_lock, flags);
 	list_for_each_entry(node, &crtc->user_event_list, list) {
 		if (node->event == event) {
+			list_del(&node->list);
 			found = true;
 			break;
 		}
@@ -6202,7 +6202,6 @@
 	 * no need to disable/de-register.
 	 */
 	if (!crtc_drm->enabled) {
-		list_del(&node->list);
 		kfree(node);
 		return 0;
 	}
@@ -6211,13 +6210,11 @@
 	if (ret) {
 		SDE_ERROR("failed to enable power resource %d\n", ret);
 		SDE_EVT32(ret, SDE_EVTLOG_ERROR);
-		list_del(&node->list);
 		kfree(node);
 		return ret;
 	}
 
 	ret = node->func(crtc_drm, false, &node->irq);
-	list_del(&node->list);
 	kfree(node);
 	sde_power_resource_enable(&priv->phandle, kms->core_client, false);
 	return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 33d2b8fa..21ce3db 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -445,7 +445,8 @@
  * @event: event type of the interrupt
  * @func: function pointer to enable/disable the interrupt
  * @list: list of user customized event in crtc
- * @ref_count: reference count for the interrupt
+ * @state: state of the interrupt
+ * @state_lock: spin lock for interrupt state
  */
 struct sde_crtc_irq_info {
 	struct sde_irq_callback irq;
@@ -454,6 +455,7 @@
 			struct sde_irq_callback *irq);
 	struct list_head list;
 	enum sde_crtc_irq_state state;
+	spinlock_t state_lock;
 };
 
 #define to_sde_crtc_state(x) \
@@ -662,10 +664,12 @@
  * @crtc: Pointer to drm crtc structure
  * @func: Pointer to callback function
  * @usr: Pointer to user data to be passed to callback
+ * @color_processing_event: True if color processing event
  * Returns: Zero on success
  */
 int sde_crtc_event_queue(struct drm_crtc *crtc,
-		void (*func)(struct drm_crtc *crtc, void *usr), void *usr);
+		void (*func)(struct drm_crtc *crtc, void *usr),
+		void *usr, bool color_processing_event);
 
 /**
  * sde_crtc_res_add - add given resource to resource pool in crtc state
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 92ab669..e35a46b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1513,6 +1513,29 @@
 	return ret;
 }
 
+static int _sde_encoder_switch_to_watchdog_vsync(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct msm_display_info disp_info;
+
+	if (!drm_enc) {
+		pr_err("invalid drm encoder\n");
+		return -EINVAL;
+	}
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+
+	sde_encoder_control_te(drm_enc, false);
+
+	memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info));
+	disp_info.is_te_using_watchdog_timer = true;
+	_sde_encoder_update_vsync_source(sde_enc, &disp_info, false);
+
+	sde_encoder_control_te(drm_enc, true);
+
+	return 0;
+}
+
 static int _sde_encoder_update_rsc_client(
 		struct drm_encoder *drm_enc,
 		struct sde_encoder_rsc_config *config, bool enable)
@@ -1652,7 +1675,12 @@
 		if (ret) {
 			SDE_ERROR_ENC(sde_enc,
 					"wait for vblank failed ret:%d\n", ret);
-			break;
+			/**
+			 * rsc hardware may hang without vsync. avoid rsc hang
+			 * by generating the vsync from watchdog timer.
+			 */
+			if (crtc->base.id == wait_vblank_crtc_id)
+				_sde_encoder_switch_to_watchdog_vsync(drm_enc);
 		}
 	}
 
@@ -2257,7 +2285,7 @@
 			if (autorefresh_enabled) {
 				SDE_DEBUG_ENC(sde_enc,
 					"not handling early wakeup since auto refresh is enabled\n");
-				mutex_lock(&sde_enc->rc_lock);
+				mutex_unlock(&sde_enc->rc_lock);
 				return 0;
 			}
 
@@ -2328,6 +2356,16 @@
 
 	SDE_EVT32(DRMID(drm_enc));
 
+	/*
+	 * cache the crtc in sde_enc on enable for duration of use case
+	 * for correctly servicing asynchronous irq events and timers
+	 */
+	if (!drm_enc->crtc) {
+		SDE_ERROR("invalid crtc\n");
+		return;
+	}
+	sde_enc->crtc = drm_enc->crtc;
+
 	list_for_each_entry(conn_iter, connector_list, head)
 		if (conn_iter->encoder == drm_enc)
 			conn = conn_iter;
@@ -2530,22 +2568,15 @@
 		return;
 	}
 
-	/*
-	 * cache the crtc in sde_enc on enable for duration of use case
-	 * for correctly servicing asynchronous irq events and timers
-	 */
-	if (!drm_enc->crtc) {
-		SDE_ERROR("invalid crtc\n");
-		return;
-	}
-	sde_enc->crtc = drm_enc->crtc;
-
 	ret = _sde_encoder_get_mode_info(drm_enc, &mode_info);
 	if (ret) {
 		SDE_ERROR_ENC(sde_enc, "failed to get mode info\n");
 		return;
 	}
 
+	if (drm_enc->crtc && !sde_enc->crtc)
+		sde_enc->crtc = drm_enc->crtc;
+
 	comp_info = &mode_info.comp_info;
 	cur_mode = &sde_enc->base.crtc->state->adjusted_mode;
 
@@ -4755,3 +4786,17 @@
 
 	return ret;
 }
+
+int sde_encoder_display_failure_notification(struct drm_encoder *enc)
+{
+	/**
+	 * panel may stop generating te signal (vsync) during esd failure. rsc
+	 * hardware may hang without vsync. Avoid rsc hang by generating the
+	 * vsync from watchdog timer instead of panel.
+	 */
+	_sde_encoder_switch_to_watchdog_vsync(enc);
+
+	sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 2c84e20..4696736 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -237,4 +237,14 @@
  */
 int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder);
 
+/**
+ * sde_encoder_display_failure_notification - update sde encoder state for
+ * esd timeout or other display failure notification. This event flows from
+ * dsi, sde_connector to sde_encoder.
+ *      TODO: manage the event at sde_kms level for forward processing.
+ * @drm_enc:    Pointer to drm encoder structure
+ * @Return:     true if successful in updating the encoder structure
+ */
+int sde_encoder_display_failure_notification(struct drm_encoder *enc);
+
 #endif /* __SDE_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 53c8dfb..792654d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018 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
@@ -450,6 +450,17 @@
 
 	cmd_enc->pp_timeout_report_cnt++;
 
+	if (sde_encoder_phys_cmd_is_master(phys_enc)) {
+		 /* trigger the retire fence if it was missed */
+		if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
+				-1, 0))
+			phys_enc->parent_ops.handle_frame_done(
+				phys_enc->parent,
+				phys_enc,
+				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
+		atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
+	}
+
 	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
 			cmd_enc->pp_timeout_report_cnt,
 			atomic_read(&phys_enc->pending_kickoff_cnt),
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index 994bf3d..66445da 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,7 +16,12 @@
 #include "sde_hw_lm.h"
 #include "sde_ad4.h"
 
-#define AD_STATE_READY(x) ((x) == (ad4_init | ad4_cfg | ad4_mode | ad4_input))
+#define AD_STATE_READY(x) \
+	(((x) & ad4_init) && \
+	((x) & ad4_cfg) && \
+	((x) & ad4_mode) && \
+	(((x) & ad4_input) | ((x) & ad4_strength)))
+
 #define MERGE_WIDTH_RIGHT 6
 #define MERGE_WIDTH_LEFT 5
 #define AD_IPC_FRAME_COUNT 2
@@ -26,6 +31,7 @@
 	ad4_cfg = BIT(AD_CFG),
 	ad4_mode = BIT(AD_MODE),
 	ad4_input = BIT(AD_INPUT),
+	ad4_strength = BIT(AD_STRENGTH),
 	ad4_ops_max = BIT(31),
 };
 
@@ -37,6 +43,8 @@
 	ad4_state_ipcs,
 	/* idle power collapse resume state */
 	ad4_state_ipcr,
+	/* manual mode state */
+	ad4_state_manual,
 	ad4_state_max,
 };
 
@@ -48,6 +56,8 @@
 
 static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
 static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
+static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg);
 static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode);
 static int ad4_mode_setup_common(struct sde_hw_dspp *dspp,
 		struct sde_ad_hw_cfg *cfg);
@@ -81,6 +91,10 @@
 		struct sde_ad_hw_cfg *cfg);
 static int ad4_backlight_setup_ipcr(struct sde_hw_dspp *dspp,
 		struct sde_ad_hw_cfg *cfg);
+static int ad4_strength_setup(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg);
+static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg);
 
 static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp,
 		struct sde_ad_hw_cfg *cfg);
@@ -103,6 +117,7 @@
 	[ad4_state_idle][AD_SUSPEND] = ad4_suspend_setup,
 	[ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup,
 	[ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup,
+	[ad4_state_idle][AD_STRENGTH] = ad4_strength_setup_idle,
 	[ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup,
@@ -115,6 +130,7 @@
 	[ad4_state_startup][AD_ASSERTIVE] = ad4_assertive_setup,
 	[ad4_state_startup][AD_BACKLIGHT] = ad4_backlight_setup,
 	[ad4_state_startup][AD_IPC_SUSPEND] = ad4_no_op_setup,
+	[ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup,
 	[ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup,
 
@@ -125,6 +141,7 @@
 	[ad4_state_run][AD_SUSPEND] = ad4_suspend_setup,
 	[ad4_state_run][AD_ASSERTIVE] = ad4_assertive_setup,
 	[ad4_state_run][AD_BACKLIGHT] = ad4_backlight_setup,
+	[ad4_state_run][AD_STRENGTH] = ad4_no_op_setup,
 	[ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run,
 	[ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_run][AD_IPC_RESET] = ad4_setup_debug,
@@ -136,6 +153,7 @@
 	[ad4_state_ipcs][AD_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_ASSERTIVE] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_BACKLIGHT] = ad4_no_op_setup,
+	[ad4_state_ipcs][AD_STRENGTH] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs,
 	[ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup,
@@ -147,9 +165,22 @@
 	[ad4_state_ipcr][AD_SUSPEND] = ad4_suspend_setup,
 	[ad4_state_ipcr][AD_ASSERTIVE] = ad4_assertive_setup_ipcr,
 	[ad4_state_ipcr][AD_BACKLIGHT] = ad4_backlight_setup_ipcr,
+	[ad4_state_ipcr][AD_STRENGTH] = ad4_no_op_setup,
 	[ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr,
 	[ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr,
+
+	[ad4_state_manual][AD_MODE] = ad4_mode_setup_common,
+	[ad4_state_manual][AD_INIT] = ad4_init_setup,
+	[ad4_state_manual][AD_CFG] = ad4_cfg_setup,
+	[ad4_state_manual][AD_INPUT] = ad4_no_op_setup,
+	[ad4_state_manual][AD_SUSPEND] = ad4_no_op_setup,
+	[ad4_state_manual][AD_ASSERTIVE] = ad4_no_op_setup,
+	[ad4_state_manual][AD_BACKLIGHT] = ad4_no_op_setup,
+	[ad4_state_manual][AD_STRENGTH] = ad4_strength_setup,
+	[ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup,
+	[ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup,
+	[ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual,
 };
 
 struct ad4_info {
@@ -288,23 +319,33 @@
 
 static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
 {
-	u32 strength = 0, i = 0;
+	u32 strength = 0;
 	struct sde_hw_mixer *hw_lm;
 
 	hw_lm = cfg->hw_cfg->mixer_info;
-	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) {
+	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer)
 		/* this AD core is the salve core */
-		for (i = DSPP_0; i < DSPP_MAX; i++) {
-			if (info[i].is_master) {
-				strength = info[i].last_str;
-				break;
-			}
-		}
-	} else {
-		strength = SDE_REG_READ(&dspp->hw,
-				dspp->cap->sblk->ad.base + 0x4c);
-		pr_debug("%s(): AD strength = %d\n", __func__, strength);
-	}
+		return 0;
+
+	strength = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x4c);
+	pr_debug("%s(): AD strength = %d\n", __func__, strength);
+
+	return 0;
+}
+
+static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg)
+{
+	u32 strength = 0;
+	struct sde_hw_mixer *hw_lm;
+
+	hw_lm = cfg->hw_cfg->mixer_info;
+	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer)
+		/* this AD core is the salve core */
+		return 0;
+
+	strength = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x15c);
+	pr_debug("%s(): AD strength = %d in manual mode\n", __func__, strength);
 
 	return 0;
 }
@@ -313,8 +354,8 @@
 {
 	u32 blk_offset;
 
-	blk_offset = 0x04;
 	if (mode == AD4_OFF) {
+		blk_offset = 0x04;
 		SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
 				0x101);
 		info[dspp->idx].state = ad4_state_idle;
@@ -328,11 +369,30 @@
 		info[dspp->idx].last_als = 0x0;
 		info[dspp->idx].cached_als = U64_MAX;
 	} else {
-		if (info[dspp->idx].state == ad4_state_idle) {
-			info[dspp->idx].frame_count = 0;
-			info[dspp->idx].state = ad4_state_startup;
-			pr_debug("%s(): AD state move to startup\n", __func__);
+		if (mode == AD4_MANUAL) {
+			/*vc_control_0 */
+			blk_offset = 0x138;
+			SDE_REG_WRITE(&dspp->hw,
+				dspp->cap->sblk->ad.base + blk_offset, 0);
+			/* irdx_control_0 */
+			blk_offset = 0x13c;
+			SDE_REG_WRITE(&dspp->hw,
+				dspp->cap->sblk->ad.base + blk_offset,
+				info[dspp->idx].irdx_control_0);
 		}
+		if (info[dspp->idx].state == ad4_state_idle) {
+			if (mode == AD4_MANUAL) {
+				info[dspp->idx].state = ad4_state_manual;
+				pr_debug("%s(): AD state move to manual\n",
+					__func__);
+			} else {
+				info[dspp->idx].frame_count = 0;
+				info[dspp->idx].state = ad4_state_startup;
+				pr_debug("%s(): AD state move to startup\n",
+					__func__);
+			}
+		}
+		blk_offset = 0x04;
 		SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
 				0x100);
 	}
@@ -786,6 +846,7 @@
 	blk_offset += 4;
 	val = (ad_cfg->cfg_param_027 & (BIT(16) - 1));
 	val |= ((ad_cfg->cfg_param_028 & (BIT(16) - 1)) << 16);
+	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
 	blk_offset += 4;
 	val = (ad_cfg->cfg_param_029 & (BIT(16) - 1));
 	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
@@ -830,7 +891,7 @@
 
 	info[dspp->idx].vc_control_0 = (ad_cfg->cfg_param_041 & (BIT(7) - 1));
 
-	blk_offset += 160;
+	blk_offset = 0x160;
 	val = (ad_cfg->cfg_param_043 & (BIT(10) - 1));
 	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
 
@@ -1263,6 +1324,8 @@
 				dspp->cap->sblk->ad.base + 0x2c);
 		*resp_out = SDE_REG_READ(&dspp->hw,
 				dspp->cap->sblk->ad.base + 0x48);
+		pr_debug("%s(): AD4 input BL %u, output BL %u\n", __func__,
+			(*resp_in), (*resp_out));
 		break;
 	default:
 		break;
@@ -1445,3 +1508,41 @@
 
 	return 0;
 }
+
+static int ad4_strength_setup(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg)
+{
+	u64 strength = 0, val;
+	u32 blk_offset = 0x15c;
+
+	if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) {
+		DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
+			sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload);
+		return -EINVAL;
+	}
+
+	if (cfg->hw_cfg->payload)
+		strength = *((u64 *)cfg->hw_cfg->payload);
+	else
+		strength = 0;
+
+	/* set manual strength */
+	info[dspp->idx].completed_ops_mask |= ad4_strength;
+	val = (strength & (BIT(10) - 1));
+	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
+	return 0;
+}
+
+static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg)
+{
+	int ret;
+
+	ret = ad4_strength_setup(dspp, cfg);
+	if (ret)
+		return ret;
+
+	if (AD_STATE_READY(info[dspp->idx].completed_ops_mask))
+		ad4_mode_setup(dspp, info[dspp->idx].mode);
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index cdc6a9c..ea39dcd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -80,6 +80,17 @@
 #define LINE_LM_OFFSET			5
 #define LINE_MODE_WB_OFFSET		2
 
+/**
+ * these configurations are decided based on max mdp clock. It accounts
+ * for max and min display resolution based on virtual hardware resource
+ * support.
+ */
+#define MAX_DISPLAY_HEIGHT_WITH_DECIMATION		2160
+#define MAX_DISPLAY_HEIGHT				5120
+#define MIN_DISPLAY_HEIGHT				0
+#define MIN_DISPLAY_WIDTH				0
+#define MAX_LM_PER_DISPLAY				2
+
 /* maximum XIN halt timeout in usec */
 #define VBIF_XIN_HALT_TIMEOUT		0x4000
 
@@ -3216,7 +3227,7 @@
 	return rc;
 }
 
-static int _sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
+static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
 {
 	int rc = 0;
 
@@ -3249,6 +3260,46 @@
 	return rc;
 }
 
+static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg,
+	uint32_t hw_rev)
+{
+	int rc = 0, i;
+	u32 max_horz_deci = 0, max_vert_deci = 0;
+
+	if (!sde_cfg)
+		return -EINVAL;
+
+	for (i = 0; i < sde_cfg->sspp_count; i++) {
+		if (sde_cfg->sspp[i].sblk) {
+			max_horz_deci = max(max_horz_deci,
+				sde_cfg->sspp[i].sblk->maxhdeciexp);
+			max_vert_deci = max(max_vert_deci,
+				sde_cfg->sspp[i].sblk->maxvdeciexp);
+		}
+	}
+
+	/* this should be updated based on HW rev in future */
+	sde_cfg->max_lm_per_display = MAX_LM_PER_DISPLAY;
+
+	if (max_horz_deci)
+		sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
+			max_horz_deci;
+	else
+		sde_cfg->max_display_width = sde_cfg->max_mixer_width *
+			sde_cfg->max_lm_per_display;
+
+	if (max_vert_deci)
+		sde_cfg->max_display_height =
+			MAX_DISPLAY_HEIGHT_WITH_DECIMATION * max_vert_deci;
+	else
+		sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT;
+
+	sde_cfg->min_display_height = MIN_DISPLAY_HEIGHT;
+	sde_cfg->min_display_width = MIN_DISPLAY_WIDTH;
+
+	return rc;
+}
+
 void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
 {
 	int i;
@@ -3307,7 +3358,7 @@
 
 	sde_cfg->hwversion = hw_rev;
 
-	rc = _sde_hardware_caps(sde_cfg, hw_rev);
+	rc = _sde_hardware_pre_caps(sde_cfg, hw_rev);
 	if (rc)
 		goto end;
 
@@ -3379,6 +3430,10 @@
 	if (rc)
 		goto end;
 
+	rc = _sde_hardware_post_caps(sde_cfg, hw_rev);
+	if (rc)
+		goto end;
+
 	return sde_cfg;
 
 end:
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index aa6c482..0bb61b3 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -909,6 +909,11 @@
  * @max_mixer_blendstages max layer mixer blend stages or
  *                       supported z order
  * @max_wb_linewidth   max writeback line width support.
+ * @max_display_width   maximum display width support.
+ * @max_display_height  maximum display height support.
+ * @max_lm_per_display  maximum layer mixer per display
+ * @min_display_width   minimum display width support.
+ * @min_display_height  minimum display height support.
  * @qseed_type         qseed2 or qseed3 support.
  * @csc_type           csc or csc_10bit support.
  * @smart_dma_rev      Supported version of SmartDMA feature.
@@ -935,6 +940,13 @@
 	u32 max_mixer_width;
 	u32 max_mixer_blendstages;
 	u32 max_wb_linewidth;
+
+	u32 max_display_width;
+	u32 max_display_height;
+	u32 min_display_width;
+	u32 min_display_height;
+	u32 max_lm_per_display;
+
 	u32 qseed_type;
 	u32 csc_type;
 	u32 smart_dma_rev;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
index d32459a..9e64d78 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,8 @@
 #define PA_LUTV_DSPP_CTRL_OFF	0x4c
 #define PA_LUTV_DSPP_SWAP_OFF	0x18
 
+#define PA_DITH_DSPP_MATRIX_OFF	0x4
+
 #define PA_HUE_MASK		0xFFF
 #define PA_SAT_MASK		0xFFFF
 #define PA_VAL_MASK		0xFF
@@ -971,3 +973,45 @@
 	/* lock hist buffer */
 	SDE_REG_WRITE(&ctx->hw, offset_ctl, 1);
 }
+
+void sde_setup_dspp_dither_v1_7(struct sde_hw_dspp *ctx, void *cfg)
+{
+	struct sde_hw_cp_cfg *hw_cfg = cfg;
+	struct drm_msm_pa_dither *dither;
+	u32 ctrl_off, matrix_off;
+	u32 opmode, data, i;
+
+	if (!hw_cfg || (hw_cfg->len != sizeof(struct drm_msm_pa_dither) &&
+			hw_cfg->payload)) {
+		DRM_ERROR("hw %pK payload %pK size %d expected sz %zd\n",
+			hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
+			((hw_cfg) ? hw_cfg->len : 0),
+			sizeof(struct drm_msm_pa_dither));
+		return;
+	}
+
+	ctrl_off = ctx->cap->sblk->dither.base;
+	matrix_off = ctrl_off + PA_DITH_DSPP_MATRIX_OFF;
+
+	/* Turn off feature */
+	if (!hw_cfg->payload) {
+		DRM_DEBUG_DRIVER("Disable DSPP dither feature\n");
+		SDE_REG_WRITE(&ctx->hw, ctrl_off, 0);
+		return;
+	}
+	DRM_DEBUG_DRIVER("Enable DSPP Dither feature\n");
+	dither = hw_cfg->payload;
+
+	for (i = 0; i < DITHER_MATRIX_SZ; i += 4) {
+		data = (dither->matrix[i] & REG_MASK(4)) |
+			((dither->matrix[i + 1] & REG_MASK(4)) << 4) |
+			((dither->matrix[i + 2] & REG_MASK(4)) << 8) |
+			((dither->matrix[i + 3] & REG_MASK(4)) << 12);
+		SDE_REG_WRITE(&ctx->hw, matrix_off + i, data);
+	}
+
+	opmode = BIT(0);
+	opmode |= (dither->offset_en) ? BIT(1) : 0;
+	opmode |= ((dither->strength) & REG_MASK(4)) << 4;
+	SDE_REG_WRITE(&ctx->hw, ctrl_off, opmode);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
index 3c783ee..95ce7fe 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -143,4 +143,11 @@
  * @ctx: Pointer to DSPP context
  */
 void sde_lock_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg);
+
+/**
+ * sde_setup_dspp_dither_v1_7 - setup DSPP dither feature in v1.7 hardware
+ * @ctx: Pointer to DSPP context
+ * @cfg: Pointer to dither data
+ */
+void sde_setup_dspp_dither_v1_7(struct sde_hw_dspp *ctx, void *cfg);
 #endif
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index b268e8f..4451301 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -94,6 +94,12 @@
 				c->ops.setup_sixzone =
 					sde_setup_dspp_sixzone_v17;
 			break;
+		case SDE_DSPP_DITHER:
+			if (c->cap->sblk->dither.version ==
+				SDE_COLOR_PROCESS_VER(0x1, 0x7))
+				c->ops.setup_pa_dither =
+					sde_setup_dspp_dither_v1_7;
+			break;
 		case SDE_DSPP_VLUT:
 			if (c->cap->sblk->vlut.version ==
 				(SDE_COLOR_PROCESS_VER(0x1, 0x7))) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 2d2ac5b..7fe3baa 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -115,11 +115,11 @@
 	void (*setup_danger_safe)(struct sde_hw_dspp *ctx, void *cfg);
 
 	/**
-	 * setup_dither - setup dspp dither
+	 * setup_pa_dither - setup dspp PA dither
 	 * @ctx: Pointer to dspp context
 	 * @cfg: Pointer to configuration
 	 */
-	void (*setup_dither)(struct sde_hw_dspp *ctx, void *cfg);
+	void (*setup_pa_dither)(struct sde_hw_dspp *ctx, void *cfg);
 
 	/**
 	 * setup_vlut - setup dspp PA VLUT
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 6ccf957..02d593b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -474,6 +474,7 @@
 	struct sde_hw_blk_reg_map hw;
 
 	memset(&hw, 0, sizeof(hw));
+	msm_gem_sync(cfg->dma_buf->buf);
 	cmd1 = (cfg->op == REG_DMA_READ) ?
 		(dspp_read_sel[cfg->block_select] << 30) : 0;
 	cmd1 |= (cfg->last_command) ? BIT(24) : 0;
@@ -481,7 +482,6 @@
 	cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0;
 	cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ);
 
-	msm_gem_sync(cfg->dma_buf->buf);
 	SET_UP_REG_DMA_REG(hw, reg_dma);
 	SDE_REG_WRITE(&hw, REG_DMA_OP_MODE_OFF, BIT(0));
 	SDE_REG_WRITE(&hw, reg_dma_clear_status_off,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 0dc3fed..05ac893 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -248,6 +248,32 @@
 	return rc;
 }
 
+bool reg_dmav1_dspp_feature_support(int feature)
+{
+	struct sde_hw_reg_dma_ops *dma_ops;
+	bool is_supported = false;
+
+	if (feature >= SDE_DSPP_MAX) {
+		DRM_ERROR("invalid feature %x max %x\n",
+			feature, SDE_DSPP_MAX);
+		return is_supported;
+	}
+
+	if (feature_map[feature] >= REG_DMA_FEATURES_MAX) {
+		DRM_ERROR("invalid feature map %d for feature %d\n",
+			feature_map[feature], feature);
+		return is_supported;
+	}
+
+	dma_ops = sde_reg_dma_get_ops();
+	if (IS_ERR_OR_NULL(dma_ops))
+		return is_supported;
+
+	dma_ops->check_support(feature_map[feature], DSPP0, &is_supported);
+
+	return is_supported;
+}
+
 int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx)
 {
 	int rc = -ENOTSUPP;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
index a8115d6..5cd212a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -25,6 +25,13 @@
 int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx);
 
 /**
+ * reg_dmav1_dspp_feature_support() - check if dspp feature using REG_DMA
+ *                                    or not.
+ * @feature: dspp feature
+ */
+bool reg_dmav1_dspp_feature_support(int feature);
+
+/**
  * reg_dma_init_sspp_op_v4() - initialize the sspp feature op for sde v4
  * @feature: sspp feature
  * @idx: sspp idx
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 9355080..356f9ef 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -375,19 +375,24 @@
 
 	c = &ctx->hw;
 
-	if (enable) {
-		if ((rect_mode == SDE_SSPP_RECT_SOLO)
-				|| (rect_mode == SDE_SSPP_RECT_0))
-			secure_bit_mask =
-				(rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
-		else
-			secure_bit_mask = 0xA;
+	if ((rect_mode == SDE_SSPP_RECT_SOLO)
+			|| (rect_mode == SDE_SSPP_RECT_0))
+		secure_bit_mask =
+			(rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
+	else
+		secure_bit_mask = 0xA;
 
-		secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
+	secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
+
+	if (enable)
 		secure |= secure_bit_mask;
-	}
+	else
+		secure &= ~secure_bit_mask;
 
 	SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
+
+	/* multiple planes share same sw_status register */
+	wmb();
 }
 
 
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 5d3835c..3bede65 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -952,6 +952,17 @@
 		.config_hdr = dp_connector_config_hdr,
 		.cmd_transfer = NULL,
 	};
+	static const struct sde_connector_ops ext_bridge_ops = {
+		.set_info_blob = dsi_conn_set_info_blob,
+		.mode_valid = dsi_conn_mode_valid,
+		.get_info = dsi_display_ext_bridge_get_info,
+		.soft_reset = dsi_display_soft_reset,
+		.clk_ctrl = dsi_display_clk_ctrl,
+		.get_mode_info = dsi_conn_ext_bridge_get_mode_info,
+		.get_dst_format = dsi_display_get_dst_format,
+		.enable_event = dsi_conn_enable_event,
+		.cmd_transfer = NULL,
+	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;
 	void *display, *connector;
@@ -976,39 +987,95 @@
 		display = sde_kms->dsi_displays[i];
 		encoder = NULL;
 
-		memset(&info, 0x0, sizeof(info));
-		rc = dsi_display_get_info(&info, display);
-		if (rc) {
-			SDE_ERROR("dsi get_info %d failed\n", i);
-			continue;
-		}
+		if (!dsi_display_has_ext_bridge(display)) {
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("dsi get_info %d failed\n", i);
+				continue;
+			}
 
-		encoder = sde_encoder_init(dev, &info);
-		if (IS_ERR_OR_NULL(encoder)) {
-			SDE_ERROR("encoder init failed for dsi %d\n", i);
-			continue;
-		}
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for dsi %d\n",
+					i);
+				continue;
+			}
 
-		rc = dsi_display_drm_bridge_init(display, encoder);
-		if (rc) {
-			SDE_ERROR("dsi bridge %d init failed, %d\n", i, rc);
-			sde_encoder_destroy(encoder);
-			continue;
-		}
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed, %d\n",
+					i, rc);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 
-		connector = sde_connector_init(dev,
-					encoder,
-					0,
-					display,
-					&dsi_ops,
-					DRM_CONNECTOR_POLL_HPD,
-					DRM_MODE_CONNECTOR_DSI);
-		if (connector) {
-			priv->encoders[priv->num_encoders++] = encoder;
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&dsi_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("dsi %d connector init failed\n", i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+			}
 		} else {
-			SDE_ERROR("dsi %d connector init failed\n", i);
-			dsi_display_drm_bridge_deinit(display);
-			sde_encoder_destroy(encoder);
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_ext_bridge_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("ext get_info %d failed\n", i);
+				continue;
+			}
+
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for ext %d\n",
+					i);
+				continue;
+			}
+
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed for ext\n",
+					i);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&ext_bridge_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("connector init %d failed for ext\n",
+					i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			rc = dsi_display_drm_ext_bridge_init(display,
+				encoder, connector);
+			if (rc) {
+				struct drm_connector *conn = connector;
+
+				SDE_ERROR("ext bridge %d init failed, %d\n",
+					i, rc);
+				conn->funcs->destroy(connector);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 		}
 	}
 
@@ -2248,7 +2315,7 @@
 		 * configuration.
 		 */
 		if (conn_iter &&
-			conn_iter->encoder_ids[0] == encoder->base.id) {
+			(conn_iter->encoder_ids[0] == encoder->base.id)) {
 			connector = conn_iter;
 			break;
 		}
@@ -2949,15 +3016,10 @@
 		goto drm_obj_init_err;
 	}
 
-	dev->mode_config.min_width = 0;
-	dev->mode_config.min_height = 0;
-
-	/*
-	 * max crtc width is equal to the max mixer width * 2 and max height is
-	 * is 4K
-	 */
-	dev->mode_config.max_width = sde_kms->catalog->max_mixer_width * 2;
-	dev->mode_config.max_height = 4096;
+	dev->mode_config.min_width = sde_kms->catalog->min_display_width;
+	dev->mode_config.min_height = sde_kms->catalog->min_display_height;
+	dev->mode_config.max_width = sde_kms->catalog->max_display_width;
+	dev->mode_config.max_height = sde_kms->catalog->max_display_height;
 
 	/*
 	 * Support format modifiers for compression etc.
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ed1079d..4c281666 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2379,6 +2379,29 @@
 					(u64) &rstate->rot_hw->base);
 			rstate->out_fbo = NULL;
 		}
+
+		/*
+		 * For video mode, reject any downscale factor greater than or
+		 * equal to 1.1x
+		 *
+		 * Check the downscale factor first to avoid querying the
+		 * interface mode unnecessarily.
+		 */
+		if ((rstate->out_src_h >> 16) * 10 >= state->crtc_h * 11 &&
+				sde_crtc_get_intf_mode(state->crtc) ==
+				INTF_MODE_VIDEO) {
+			SDE_DEBUG_PLANE(psde,
+					"inline %d with invalid scale, %dx%d, %dx%d\n",
+					rstate->sequence_id,
+					rstate->out_src_w, rstate->out_src_h,
+					state->crtc_w, state->crtc_h);
+			SDE_EVT32(DRMID(plane), rstate->sequence_id,
+					rstate->out_src_w >> 16,
+					rstate->out_src_h >> 16,
+					state->crtc_w, state->crtc_h,
+					SDE_EVTLOG_ERROR);
+			return -EINVAL;
+		}
 	} else {
 
 		SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
@@ -3257,7 +3280,8 @@
 
 	if (!fb || !old_fb) {
 		SDE_DEBUG_PLANE(psde, "can't compare fb handles\n");
-	} else if (fb->pixel_format != old_fb->pixel_format) {
+	} else if ((fb->pixel_format != old_fb->pixel_format) ||
+			pstate->const_alpha_en != old_pstate->const_alpha_en) {
 		SDE_DEBUG_PLANE(psde, "format change\n");
 		pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
 	} else {
@@ -3569,7 +3593,8 @@
 
 	pstate->const_alpha_en = fmt->alpha_enable &&
 		(SDE_DRM_BLEND_OP_OPAQUE !=
-		 sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP));
+		 sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP)) &&
+		(pstate->stage != SDE_STAGE_0);
 
 modeset_update:
 	if (!ret)
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 93304e16..52a5bc9 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -398,7 +398,7 @@
 		void __iomem *mmio,
 		struct drm_device *dev)
 {
-	int rc, i;
+	int rc = 0, i;
 	enum sde_hw_blk_type type;
 
 	if (!rm || !cat || !mmio || !dev) {
@@ -1182,7 +1182,7 @@
 	}
 
 	SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR);
-	SDE_ERROR("polling timed out. status = 0x%x\n", status);
+	SDE_DEBUG("polling timed out. status = 0x%x\n", status);
 	return -ETIMEDOUT;
 }
 
diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h
index 6c44260..c8e84d3cc 100644
--- a/drivers/gpu/drm/msm/sde_hdcp.h
+++ b/drivers/gpu/drm/msm/sde_hdcp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,17 +30,21 @@
 	HDCP_CLIENT_DP,
 };
 
-enum sde_hdcp_states {
+enum sde_hdcp_state {
 	HDCP_STATE_INACTIVE,
 	HDCP_STATE_AUTHENTICATING,
 	HDCP_STATE_AUTHENTICATED,
 	HDCP_STATE_AUTH_FAIL,
-	HDCP_STATE_AUTH_ENC_NONE,
-	HDCP_STATE_AUTH_ENC_1X,
-	HDCP_STATE_AUTH_ENC_2P2
+};
+
+enum sde_hdcp_version {
+	HDCP_VERSION_NONE,
+	HDCP_VERSION_1X,
+	HDCP_VERSION_2P2
 };
 
 struct sde_hdcp_init_data {
+	struct device *msm_hdcp_dev;
 	struct dss_io_data *core_io;
 	struct dss_io_data *dp_ahb;
 	struct dss_io_data *dp_aux;
@@ -52,7 +56,7 @@
 	struct mutex *mutex;
 	struct workqueue_struct *workq;
 	void *cb_data;
-	void (*notify_status)(void *cb_data, enum sde_hdcp_states status);
+	void (*notify_status)(void *cb_data, enum sde_hdcp_state state);
 	u8 sink_rx_status;
 	unsigned char *revision;
 	u32 phy_addr;
@@ -69,11 +73,32 @@
 	void (*off)(void *hdcp_ctrl);
 };
 
+static inline const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state)
+{
+	switch (hdcp_state) {
+	case HDCP_STATE_INACTIVE:	return "HDCP_STATE_INACTIVE";
+	case HDCP_STATE_AUTHENTICATING:	return "HDCP_STATE_AUTHENTICATING";
+	case HDCP_STATE_AUTHENTICATED:	return "HDCP_STATE_AUTHENTICATED";
+	case HDCP_STATE_AUTH_FAIL:	return "HDCP_STATE_AUTH_FAIL";
+	default:			return "???";
+	}
+}
+
+static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version)
+{
+	switch (hdcp_version) {
+	case HDCP_VERSION_NONE:		return "HDCP_VERSION_NONE";
+	case HDCP_VERSION_1X:		return "HDCP_VERSION_1X";
+	case HDCP_VERSION_2P2:		return "HDCP_VERSION_2P2";
+	default:			return "???";
+	}
+}
+
 void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data);
 void sde_hdcp_1x_deinit(void *input);
 struct sde_hdcp_ops *sde_hdcp_1x_start(void *input);
 void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data);
 void sde_dp_hdcp2p2_deinit(void *input);
-const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state);
+const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state);
 struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input);
 #endif /* __SDE_HDCP_H__ */
diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c
index 2f900ece..2c7f52c 100644
--- a/drivers/gpu/drm/msm/sde_hdcp_1x.c
+++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/iopoll.h>
+#include <linux/msm_hdcp.h>
 #include <linux/hdcp_qseecom.h>
 #include <drm/drm_dp_helper.h>
 #include "sde_hdcp.h"
@@ -213,8 +214,7 @@
 	bool sink_r0_ready;
 	bool reauth;
 	bool ksv_ready;
-	enum sde_hdcp_states hdcp_state;
-	struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+	enum sde_hdcp_state hdcp_state;
 	struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
 	struct delayed_work hdcp_auth_work;
 	struct completion r0_checked;
@@ -227,17 +227,6 @@
 	struct workqueue_struct *workq;
 };
 
-const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state)
-{
-	switch (hdcp_state) {
-	case HDCP_STATE_INACTIVE:	return "HDCP_STATE_INACTIVE";
-	case HDCP_STATE_AUTHENTICATING:	return "HDCP_STATE_AUTHENTICATING";
-	case HDCP_STATE_AUTHENTICATED:	return "HDCP_STATE_AUTHENTICATED";
-	case HDCP_STATE_AUTH_FAIL:	return "HDCP_STATE_AUTH_FAIL";
-	default:			return "???";
-	}
-}
-
 static int sde_hdcp_1x_count_one(u8 *array, u8 len)
 {
 	int i, j, count = 0;
@@ -1062,30 +1051,12 @@
 	return rc;
 }
 
-static void sde_hdcp_1x_cache_topology(struct sde_hdcp_1x *hdcp)
-{
-	if (!hdcp || !hdcp->init_data.dp_ahb || !hdcp->init_data.dp_aux ||
-		!hdcp->init_data.dp_link || !hdcp->init_data.dp_p0) {
-		pr_err("invalid input\n");
-		return;
-	}
-
-	memcpy((void *)&hdcp->cached_tp,
-		(void *) &hdcp->current_tp,
-		sizeof(hdcp->cached_tp));
-	hdcp1_cache_repeater_topology((void *)&hdcp->cached_tp);
-}
-
-static void sde_hdcp_1x_notify_topology(void)
-{
-	hdcp1_notify_topology();
-}
-
 static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
 {
 	if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
-		sde_hdcp_1x_cache_topology(hdcp);
-		sde_hdcp_1x_notify_topology();
+		msm_hdcp_cache_repeater_topology(hdcp->init_data.msm_hdcp_dev,
+						&hdcp->current_tp);
+		msm_hdcp_notify_topology(hdcp->init_data.msm_hdcp_dev);
 	}
 
 	if (hdcp->init_data.notify_status &&
@@ -1262,11 +1233,9 @@
 	 * Also, need to set the state to inactive here so that any ongoing
 	 * reauth works will know that the HDCP session has been turned off.
 	 */
-	mutex_lock(hdcp->init_data.mutex);
 	DSS_REG_W(io, isr->int_reg,
 		DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
 	hdcp->hdcp_state = HDCP_STATE_INACTIVE;
-	mutex_unlock(hdcp->init_data.mutex);
 
 	/* complete any wait pending */
 	complete_all(&hdcp->sink_r0_available);
@@ -1510,7 +1479,7 @@
 		.off = sde_hdcp_1x_off
 	};
 
-	if (!init_data || !init_data->mutex || !init_data->notify_status ||
+	if (!init_data || !init_data->notify_status ||
 		!init_data->workq || !init_data->cb_data) {
 		pr_err("invalid input\n");
 		goto error;
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 40542ab..037c036 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -844,6 +844,68 @@
 		sde_rsc_client_destroy(phandle->rsc_client);
 }
 
+
+int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
+	struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock)
+{
+	struct sde_power_client *client;
+	int rc = 0;
+	u32 max_usecase_ndx = VOTE_INDEX_DISABLE;
+
+	if (!skip_lock) {
+		mutex_lock(&phandle->phandle_lock);
+
+		if (WARN_ON(pclient->refcount == 0)) {
+			/*
+			 * This is not expected, clients calling without skip
+			 * lock are outside the power resource enable, which
+			 * means that they should have enabled the power
+			 * resource before trying to scale.
+			 */
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+
+	pr_debug("%pS: current idx:%d requested:%d client:%d\n",
+		__builtin_return_address(0), pclient->usecase_ndx,
+		usecase_ndx, pclient->id);
+
+	pclient->usecase_ndx = usecase_ndx;
+
+	list_for_each_entry(client, &phandle->power_client_clist, list) {
+		if (client->usecase_ndx < VOTE_INDEX_MAX &&
+		    client->usecase_ndx > max_usecase_ndx)
+			max_usecase_ndx = client->usecase_ndx;
+	}
+
+	rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
+						max_usecase_ndx);
+	if (rc)
+		pr_err("failed to set reg bus vote rc=%d\n", rc);
+
+exit:
+	if (!skip_lock)
+		mutex_unlock(&phandle->phandle_lock);
+
+	return rc;
+}
+
+static inline bool _resource_changed(u32 current_usecase_ndx,
+		u32 max_usecase_ndx)
+{
+	WARN_ON((current_usecase_ndx >= VOTE_INDEX_MAX)
+		|| (max_usecase_ndx >= VOTE_INDEX_MAX));
+
+	if (((current_usecase_ndx >= VOTE_INDEX_LOW) && /*current enabled */
+		(max_usecase_ndx == VOTE_INDEX_DISABLE)) || /* max disabled */
+		((current_usecase_ndx == VOTE_INDEX_DISABLE) && /* disabled */
+		(max_usecase_ndx >= VOTE_INDEX_LOW))) /* max enabled */
+		return true;
+
+	return false;
+}
+
 int sde_power_resource_enable(struct sde_power_handle *phandle,
 	struct sde_power_client *pclient, bool enable)
 {
@@ -877,7 +939,15 @@
 			max_usecase_ndx = client->usecase_ndx;
 	}
 
-	if (phandle->current_usecase_ndx != max_usecase_ndx) {
+	/*
+	 * Check if we need to enable/disable the power resource, we won't
+	 * only-scale up/down the AHB vote in this API; if a client wants to
+	 * bump up the AHB clock above the LOW (default) level, it needs to
+	 * call 'sde_power_scale_reg_bus' with the desired vote after the power
+	 * resource was enabled.
+	 */
+	if (_resource_changed(phandle->current_usecase_ndx,
+			max_usecase_ndx)) {
 		changed = true;
 		prev_usecase_ndx = phandle->current_usecase_ndx;
 		phandle->current_usecase_ndx = max_usecase_ndx;
@@ -920,8 +990,8 @@
 			}
 		}
 
-		rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
-							max_usecase_ndx);
+		rc = sde_power_scale_reg_bus(phandle, pclient,
+				max_usecase_ndx, true);
 		if (rc) {
 			pr_err("failed to set reg bus vote rc=%d\n", rc);
 			goto reg_bus_hdl_err;
@@ -952,8 +1022,8 @@
 
 		sde_power_rsc_update(phandle, false);
 
-		sde_power_reg_bus_update(phandle->reg_bus_hdl,
-							max_usecase_ndx);
+		sde_power_scale_reg_bus(phandle, pclient,
+				max_usecase_ndx, true);
 
 		if (!phandle->rsc_client)
 			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
@@ -975,7 +1045,7 @@
 clk_err:
 	sde_power_rsc_update(phandle, false);
 rsc_err:
-	sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
+	sde_power_scale_reg_bus(phandle, pclient, max_usecase_ndx, true);
 reg_bus_hdl_err:
 	if (!phandle->rsc_client)
 		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index fb7322e..f02ca0a 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -43,11 +43,15 @@
  * mdss_bus_vote_type: register bus vote type
  * VOTE_INDEX_DISABLE: removes the client vote
  * VOTE_INDEX_LOW: keeps the lowest vote for register bus
+ * VOTE_INDEX_MEDIUM: keeps medium vote for register bus
+ * VOTE_INDEX_HIGH: keeps the highest vote for register bus
  * VOTE_INDEX_MAX: invalid
  */
 enum mdss_bus_vote_type {
 	VOTE_INDEX_DISABLE,
 	VOTE_INDEX_LOW,
+	VOTE_INDEX_MEDIUM,
+	VOTE_INDEX_HIGH,
 	VOTE_INDEX_MAX,
 };
 
@@ -228,6 +232,19 @@
 	struct sde_power_client *pclient, bool enable);
 
 /**
+ * sde_power_scale_reg_bus() - Scale the registers bus for the specified client
+ * @pdata:  power handle containing the resources
+ * @client: client information to scale its vote
+ * @usecase_ndx: new use case to scale the reg bus
+ * @skip_lock: will skip holding the power rsrc mutex during the call, this is
+ *		for internal callers that already hold this required lock.
+ *
+ * Return: error code.
+ */
+int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
+	struct sde_power_client *pclient, u32 usecase_ndx, bool skip_lock);
+
+/**
  * sde_power_resource_is_enabled() - return true if power resource is enabled
  * @pdata:  power handle containing the resources
  *
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 4ceed7a9..4b83e9e 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -638,7 +638,8 @@
 		match = of_match_node(dmm_of_match, dev->dev.of_node);
 		if (!match) {
 			dev_err(&dev->dev, "failed to find matching device node\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto fail;
 		}
 
 		omap_dmm->plat_data = match->data;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index a2ec6d8..3322b15 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -392,6 +392,31 @@
 	rcrtc->started = true;
 }
 
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	struct drm_crtc *crtc = &rcrtc->crtc;
+	u32 status;
+	/* Make sure vblank interrupts are enabled. */
+	drm_crtc_vblank_get(crtc);
+	/*
+	 * Disable planes and calculate how many vertical blanking interrupts we
+	 * have to wait for. If a vertical blanking interrupt has been triggered
+	 * but not processed yet, we don't know whether it occurred before or
+	 * after the planes got disabled. We thus have to wait for two vblank
+	 * interrupts in that case.
+	 */
+	spin_lock_irq(&rcrtc->vblank_lock);
+	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+	status = rcar_du_crtc_read(rcrtc, DSSR);
+	rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
+	spin_unlock_irq(&rcrtc->vblank_lock);
+	if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
+				msecs_to_jiffies(100)))
+		dev_warn(rcdu->dev, "vertical blanking timeout\n");
+	drm_crtc_vblank_put(crtc);
+}
+
 static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
@@ -400,17 +425,16 @@
 		return;
 
 	/* Disable all planes and wait for the change to take effect. This is
-	 * required as the DSnPR registers are updated on vblank, and no vblank
-	 * will occur once the CRTC is stopped. Disabling planes when starting
-	 * the CRTC thus wouldn't be enough as it would start scanning out
-	 * immediately from old frame buffers until the next vblank.
+         * required as the plane enable registers are updated on vblank, and no
+         * vblank will occur once the CRTC is stopped. Disabling planes when
+         * starting the CRTC thus wouldn't be enough as it would start scanning
+         * out immediately from old frame buffers until the next vblank.
 	 *
 	 * This increases the CRTC stop delay, especially when multiple CRTCs
 	 * are stopped in one operation as we now wait for one vblank per CRTC.
 	 * Whether this can be improved needs to be researched.
 	 */
-	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
-	drm_crtc_wait_one_vblank(crtc);
+	rcar_du_crtc_disable_planes(rcrtc);
 
 	/* Disable vertical blanking interrupt reporting. We first need to wait
 	 * for page flip completion before stopping the CRTC as userspace
@@ -548,10 +572,25 @@
 	irqreturn_t ret = IRQ_NONE;
 	u32 status;
 
+	spin_lock(&rcrtc->vblank_lock);
+
 	status = rcar_du_crtc_read(rcrtc, DSSR);
 	rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-	if (status & DSSR_FRM) {
+	if (status & DSSR_VBK) {
+		/*
+		 * Wake up the vblank wait if the counter reaches 0. This must
+		 * be protected by the vblank_lock to avoid races in
+		 * rcar_du_crtc_disable_planes().
+		 */
+		if (rcrtc->vblank_count) {
+			if (--rcrtc->vblank_count == 0)
+				wake_up(&rcrtc->vblank_wait);
+		}
+	}
+	spin_unlock(&rcrtc->vblank_lock);
+
+	if (status & DSSR_VBK) {
 		drm_crtc_handle_vblank(&rcrtc->crtc);
 		rcar_du_crtc_finish_page_flip(rcrtc);
 		ret = IRQ_HANDLED;
@@ -606,6 +645,8 @@
 	}
 
 	init_waitqueue_head(&rcrtc->flip_wait);
+	init_waitqueue_head(&rcrtc->vblank_wait);
+	spin_lock_init(&rcrtc->vblank_lock);
 
 	rcrtc->group = rgrp;
 	rcrtc->mmio_offset = mmio_offsets[index];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 6f08b7e..48bef05 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -15,6 +15,7 @@
 #define __RCAR_DU_CRTC_H__
 
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 #include <drm/drmP.h>
@@ -33,6 +34,9 @@
  * @started: whether the CRTC has been started and is running
  * @event: event to post when the pending page flip completes
  * @flip_wait: wait queue used to signal page flip completion
+ * @vblank_lock: protects vblank_wait and vblank_count
+ * @vblank_wait: wait queue used to signal vertical blanking
+ * @vblank_count: number of vertical blanking interrupts to wait for
  * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
  * @group: CRTC group this CRTC belongs to
  */
@@ -48,6 +52,10 @@
 	struct drm_pending_vblank_event *event;
 	wait_queue_head_t flip_wait;
 
+	spinlock_t vblank_lock;
+	wait_queue_head_t vblank_wait;
+	unsigned int vblank_count;
+
 	unsigned int outputs;
 
 	struct rcar_du_group *group;
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 094bc6a..d96c084 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -225,6 +225,9 @@
 	/* Clear any pending interrupts we might have left. */
 	V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
 
+	/* Finish any interrupt handler still in flight. */
+	disable_irq(dev->irq);
+
 	cancel_work_sync(&vc4->overflow_mem_work);
 }
 
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 7cc346a..ce7c21d 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -173,6 +173,9 @@
 	struct vc4_dev *vc4 = v3d->vc4;
 
 	vc4_v3d_init_hw(vc4->dev);
+
+	/* We disabled the IRQ as part of vc4_irq_uninstall in suspend. */
+	enable_irq(vc4->dev->irq);
 	vc4_irq_postinstall(vc4->dev);
 
 	return 0;
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index da37baf..2aff383 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -367,7 +367,7 @@
 		.major = 1,
 		.minor = 5,
 		.patchid = ANY_ID,
-		.features = ADRENO_64BIT | ADRENO_RPMH |
+		.features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_PREEMPTION |
 			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC,
 		.sqefw_name = "a630_sqe.fw",
 		.zap_name = "a615_zap",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 942621e..7f7c04e 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,7 +19,6 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <soc/qcom/scm.h>
-#include <linux/nvmem-consumer.h>
 
 #include <linux/msm-bus-board.h>
 #include <linux/msm-bus.h>
@@ -614,7 +613,6 @@
 	struct adreno_irq *irq_params = gpudev->irq;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned int status = 0, fence = 0, fence_retries = 0, tmp, int_bit;
-	unsigned int status_retries = 0;
 	int i;
 
 	atomic_inc(&adreno_dev->pending_irq_refcnt);
@@ -654,32 +652,6 @@
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
 
 	/*
-	 * Read status again to make sure the bits aren't transitory.
-	 * Transitory bits mean that they are spurious interrupts and are
-	 * seen while preemption is on going. Empirical experiments have
-	 * shown that the transitory bits are a timing thing and they
-	 * go away in the small time window between two or three consecutive
-	 * reads. If they don't go away, log the message and return.
-	 */
-	while (status_retries < STATUS_RETRY_MAX) {
-		unsigned int new_status;
-
-		adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS,
-			&new_status);
-
-		if (status == new_status)
-			break;
-
-		status = new_status;
-		status_retries++;
-	}
-
-	if (status_retries == STATUS_RETRY_MAX) {
-		KGSL_DRV_CRIT_RATELIMIT(device, "STATUS bits are not stable\n");
-			return ret;
-	}
-
-	/*
 	 * Clear all the interrupt bits but ADRENO_INT_RBBM_AHB_ERROR. Because
 	 * even if we clear it here, it will stay high until it is cleared
 	 * in its respective handler. Otherwise, the interrupt handler will
@@ -772,64 +744,33 @@
 	{ ADRENO_QUIRK_SECVID_SET_ONCE, "qcom,gpu-quirk-secvid-set-once" },
 	{ ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW,
 			"qcom,gpu-quirk-limit-uche-gbif-rw" },
+	{ ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" },
 };
 
-#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
 static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
+adreno_get_soc_hw_revision_node(struct adreno_device *adreno_dev,
+	struct platform_device *pdev)
 {
 	struct device_node *node, *child;
-	struct nvmem_cell *cell;
-	ssize_t len;
-	u32 *buf, hw_rev, rev;
+	unsigned int rev;
 
 	node = of_find_node_by_name(pdev->dev.of_node, "qcom,soc-hw-revisions");
 	if (node == NULL)
-		goto err;
-
-	/* read the soc hw revision and select revision node */
-	cell = nvmem_cell_get(&pdev->dev, "minor_rev");
-	if (IS_ERR_OR_NULL(cell)) {
-		if (PTR_ERR(cell) == -EPROBE_DEFER)
-			return (void *)cell;
-
-		KGSL_CORE_ERR("Unable to get nvmem cell: ret=%ld\n",
-				PTR_ERR(cell));
-		goto err;
-	}
-
-	buf = nvmem_cell_read(cell, &len);
-	nvmem_cell_put(cell);
-
-	if (IS_ERR_OR_NULL(buf)) {
-		KGSL_CORE_ERR("Unable to read nvmem cell: ret=%ld\n",
-				PTR_ERR(buf));
-		goto err;
-	}
-
-	hw_rev = *buf;
-	kfree(buf);
+		return NULL;
 
 	for_each_child_of_node(node, child) {
-		if (of_property_read_u32(child, "reg", &rev))
+		if (of_property_read_u32(child, "qcom,soc-hw-revision", &rev))
 			continue;
 
-		if (rev == hw_rev)
+		if (rev == adreno_dev->soc_hw_rev)
 			return child;
 	}
 
-err:
-	/* fall back to parent node */
-	return pdev->dev.of_node;
+	KGSL_DRV_WARN(KGSL_DEVICE(adreno_dev),
+		"No matching SOC HW revision found for efused HW rev=%u\n",
+		adreno_dev->soc_hw_rev);
+	return NULL;
 }
-#else
-static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
-{
-	return pdev->dev.of_node;
-}
-#endif
-
 
 static int adreno_update_soc_hw_revision_quirks(
 		struct adreno_device *adreno_dev, struct platform_device *pdev)
@@ -837,9 +778,9 @@
 	struct device_node *node;
 	int i;
 
-	node = adreno_get_soc_hw_revision_node(pdev);
-	if (IS_ERR(node))
-		return PTR_ERR(node);
+	node = adreno_get_soc_hw_revision_node(adreno_dev, pdev);
+	if (node == NULL)
+		node = pdev->dev.of_node;
 
 	/* get chip id, fall back to parent if revision node does not have it */
 	if (of_property_read_u32(node, "qcom,chipid", &adreno_dev->chipid))
@@ -907,6 +848,58 @@
 	{}
 };
 
+static void adreno_of_get_ca_target_pwrlevel(struct adreno_device *adreno_dev,
+		struct device_node *node)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	unsigned int ca_target_pwrlevel = 1;
+
+	of_property_read_u32(node, "qcom,ca-target-pwrlevel",
+		&ca_target_pwrlevel);
+
+	if (ca_target_pwrlevel > device->pwrctrl.num_pwrlevels - 2)
+		ca_target_pwrlevel = 1;
+
+	device->pwrscale.ctxt_aware_target_pwrlevel = ca_target_pwrlevel;
+}
+
+static void adreno_of_get_ca_aware_properties(struct adreno_device *adreno_dev,
+		struct device_node *parent)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct kgsl_pwrscale *pwrscale = &device->pwrscale;
+	struct device_node *node, *child;
+	unsigned int bin = 0;
+
+	pwrscale->ctxt_aware_enable =
+		of_property_read_bool(parent, "qcom,enable-ca-jump");
+
+	if (pwrscale->ctxt_aware_enable) {
+		if (of_property_read_u32(parent, "qcom,ca-busy-penalty",
+			&pwrscale->ctxt_aware_busy_penalty))
+			pwrscale->ctxt_aware_busy_penalty = 12000;
+
+		node = of_find_node_by_name(parent, "qcom,gpu-pwrlevel-bins");
+		if (node == NULL) {
+			adreno_of_get_ca_target_pwrlevel(adreno_dev, parent);
+			return;
+		}
+
+		for_each_child_of_node(node, child) {
+			if (of_property_read_u32(child, "qcom,speed-bin", &bin))
+				continue;
+
+			if (bin == adreno_dev->speed_bin) {
+				adreno_of_get_ca_target_pwrlevel(adreno_dev,
+					child);
+				return;
+			}
+		}
+
+		pwrscale->ctxt_aware_target_pwrlevel = 1;
+	}
+}
+
 static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
 		struct device_node *node)
 {
@@ -1064,6 +1057,9 @@
 	if (adreno_of_get_pwrlevels(adreno_dev, node))
 		return -EINVAL;
 
+	/* Get context aware DCVS properties */
+	adreno_of_get_ca_aware_properties(adreno_dev, node);
+
 	/* get pm-qos-active-latency, set it to default if not found */
 	if (of_property_read_u32(node, "qcom,pm-qos-active-latency",
 		&device->pwrctrl.pm_qos_active_latency))
@@ -1158,6 +1154,36 @@
 		KGSL_DRV_WARN(device, "cx_dbgc ioremap failed\n");
 }
 
+static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev)
+{
+	unsigned int val;
+	unsigned int soc_hw_rev[3];
+	int ret;
+
+	if (of_property_read_u32_array(
+		KGSL_DEVICE(adreno_dev)->pdev->dev.of_node,
+		"qcom,soc-hw-rev-efuse", soc_hw_rev, 3))
+		return;
+
+	ret = adreno_efuse_map(adreno_dev);
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to map hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	ret = adreno_efuse_read_u32(adreno_dev, soc_hw_rev[0], &val);
+	adreno_efuse_unmap(adreno_dev);
+
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to read hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	adreno_dev->soc_hw_rev = (val >> soc_hw_rev[1]) & soc_hw_rev[2];
+}
+
 static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev)
 {
 	unsigned int row0;
@@ -1206,11 +1232,10 @@
 		return -ENODEV;
 	}
 
-	status = adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
-	if (status) {
-		device->pdev = NULL;
-		return status;
-	}
+	/* Identify SOC hardware revision to be used */
+	adreno_efuse_read_soc_hw_rev(adreno_dev);
+
+	adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
 
 	/* Get the chip ID from the DT and set up target specific parameters */
 	adreno_identify_gpu(adreno_dev);
@@ -3538,6 +3563,8 @@
 	.clk_set_options = adreno_clk_set_options,
 	.gpu_model = adreno_gpu_model,
 	.stop_fault_timer = adreno_dispatcher_stop_fault_timer,
+	.dispatcher_halt = adreno_dispatcher_halt,
+	.dispatcher_unhalt = adreno_dispatcher_unhalt,
 };
 
 static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4fb0089..8785d62 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -150,6 +150,8 @@
  * between GBIF, SMMU and MEMNOC.
  */
 #define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8)
+/* Select alternate secure context bank for mmu */
+#define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9)
 
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0
@@ -175,9 +177,6 @@
 /* Number of times to poll the AHB fence in ISR */
 #define FENCE_RETRY_MAX 100
 
-/* Number of times to see if INT_0_STATUS changed or not */
-#define STATUS_RETRY_MAX 3
-
 /* One cannot wait forever for the core to idle, so set an upper limit to the
  * amount of time to wait for the core to go idle
  */
@@ -468,6 +467,7 @@
  * @gpuhtw_llc_slice: GPU pagetables system cache slice descriptor
  * @gpuhtw_llc_slice_enable: To enable the GPUHTW system cache slice or not
  * @zap_loaded: Used to track if zap was successfully loaded or not
+ * @soc_hw_rev: Indicate which SOC hardware revision to use
  */
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
@@ -540,6 +540,7 @@
 	void *gpuhtw_llc_slice;
 	bool gpuhtw_llc_slice_enable;
 	unsigned int zap_loaded;
+	unsigned int soc_hw_rev;
 };
 
 /**
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index a615dca..4775c3e 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1353,31 +1353,27 @@
 
 	/* todo double check the reg writes */
 	while ((cur - opcode) < length) {
-		switch (cur[0]) {
-		/* Write a 32 bit value to a 64 bit reg */
-		case 1:
+		if (cur[0] == 1 && ((cur + 4) - opcode) <= length) {
+			/* Write a 32 bit value to a 64 bit reg */
 			reg = cur[2];
 			reg = (reg << 32) | cur[1];
 			kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, cur[3]);
 			cur += 4;
-			break;
-		/* Write a 64 bit value to a 64 bit reg */
-		case 2:
+		} else if (cur[0] == 2 && ((cur + 5) - opcode) <= length) {
+			/* Write a 64 bit value to a 64 bit reg */
 			reg = cur[2];
 			reg = (reg << 32) | cur[1];
 			val = cur[4];
 			val = (val << 32) | cur[3];
 			kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, val);
 			cur += 5;
-			break;
-		/* Delay for X usec */
-		case 3:
+		} else if (cur[0] == 3 && ((cur + 2) - opcode) <= length) {
+			/* Delay for X usec */
 			udelay(cur[1]);
 			cur += 2;
-			break;
-		default:
+		} else
 			return -EINVAL;
-	} }
+	}
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index d8b347d..06bf506 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -791,13 +791,14 @@
 		kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
 			0x1);
 
+	a6xx_protect_init(adreno_dev);
+
 	if (!patch_reglist && (adreno_dev->pwrup_reglist.gpuaddr != 0)) {
 		a6xx_patch_pwrup_reglist(adreno_dev);
 		patch_reglist = true;
 	}
 
 	a6xx_preemption_start(adreno_dev);
-	a6xx_protect_init(adreno_dev);
 
 	/*
 	 * We start LM here because we want all the following to be up
@@ -1257,7 +1258,7 @@
 	_regwrite(gmu->pdc_reg_virt,
 			PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000);
 	_regwrite(gmu->pdc_reg_virt,
-			PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3);
+			PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x6);
 	_regwrite(gmu->pdc_reg_virt,
 			PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108);
 	_regwrite(gmu->pdc_reg_virt,
@@ -1273,7 +1274,7 @@
 	wmb();
 }
 
-#define GMU_START_TIMEOUT	10	/* ms */
+#define GMU_START_TIMEOUT	100	/* ms */
 #define GPU_START_TIMEOUT	100	/* ms */
 #define GPU_RESET_TIMEOUT	1	/* ms */
 #define GPU_RESET_TIMEOUT_US	10	/* us */
@@ -2031,17 +2032,17 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct gmu_device *gmu = &device->gmu;
-	unsigned int status, status2;
+	unsigned int status2;
+	uint64_t ts1;
 
+	ts1 = read_AO_counter(device);
 	if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
 			0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
 		kgsl_gmu_regread(device,
-				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, &status);
-		kgsl_gmu_regread(device,
 				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2);
 		dev_err(&gmu->pdev->dev,
-				"GMU not idling: status=0x%x, status2=0x%x\n",
-				status, status2);
+				"GMU not idling: status2=0x%x %llx %llx\n",
+				status2, ts1, read_AO_counter(device));
 		return -ETIMEDOUT;
 	}
 
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
index b9dd5f4..97b0cb2 100644
--- a/drivers/gpu/msm/adreno_a6xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -370,14 +370,6 @@
 	/* Trigger the preemption */
 	adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_PREEMPT, cntl,
 		FENCE_STATUS_WRITEDROPPED1_MASK);
-
-	/*
-	 * Once preemption has been requested with the final register write,
-	 * the preemption process starts and the GPU is considered busy.
-	 * We can now safely clear the preemption keepalive bit, allowing
-	 * power collapse to resume its regular activity.
-	 */
-	kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0);
 }
 
 void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit)
@@ -405,6 +397,13 @@
 		return;
 	}
 
+	/*
+	 * We can now safely clear the preemption keepalive bit, allowing
+	 * power collapse to resume its regular activity.
+	 */
+	kgsl_gmu_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GMU_AO_SPARE_CNTL, 0x2,
+			0x0);
+
 	del_timer(&adreno_dev->preempt.timer);
 
 	adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_LEVEL_STATUS, &status);
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 472f78e..b8c282d 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -565,6 +565,8 @@
 		return -EBUSY;
 	}
 
+	memset(&time, 0x0, sizeof(time));
+
 	dispatcher->inflight++;
 	dispatch_q->inflight++;
 
@@ -2253,6 +2255,14 @@
 
 	atomic_add(halt, &adreno_dev->halt);
 
+	/*
+	 * At this point it is safe to assume that we recovered. Setting
+	 * this field allows us to take a new snapshot for the next failure
+	 * if we are prioritizing the first unrecoverable snapshot.
+	 */
+	if (device->snapshot)
+		device->snapshot->recovered = true;
+
 	return 1;
 }
 
@@ -2847,6 +2857,16 @@
 	return ret;
 }
 
+void adreno_dispatcher_halt(struct kgsl_device *device)
+{
+	adreno_get_gpu_halt(ADRENO_DEVICE(device));
+}
+
+void adreno_dispatcher_unhalt(struct kgsl_device *device)
+{
+	adreno_put_gpu_halt(ADRENO_DEVICE(device));
+}
+
 /*
  * adreno_dispatcher_idle() - Wait for dispatcher to idle
  * @adreno_dev: Adreno device whose dispatcher needs to idle
@@ -2877,6 +2897,13 @@
 
 	mutex_unlock(&device->mutex);
 
+	/*
+	 * Flush the worker to make sure all executing
+	 * or pending dispatcher works on worker are
+	 * finished
+	 */
+	kthread_flush_worker(&kgsl_driver.worker);
+
 	ret = wait_for_completion_timeout(&dispatcher->idle_gate,
 			msecs_to_jiffies(ADRENO_IDLE_TIMEOUT));
 	if (ret == 0) {
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index 48f0cdc..61bd06f 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -103,6 +103,8 @@
 };
 
 void adreno_dispatcher_start(struct kgsl_device *device);
+void adreno_dispatcher_halt(struct kgsl_device *device);
+void adreno_dispatcher_unhalt(struct kgsl_device *device);
 int adreno_dispatcher_init(struct adreno_device *adreno_dev);
 void adreno_dispatcher_close(struct adreno_device *adreno_dev);
 int adreno_dispatcher_idle(struct adreno_device *adreno_dev);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5168d9e..1faad93 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, 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
@@ -120,13 +120,60 @@
 
 }
 
+static void adreno_profile_submit_time(struct adreno_submit_time *time)
+{
+	struct kgsl_drawobj *drawobj;
+	struct kgsl_drawobj_cmd *cmdobj;
+	struct kgsl_mem_entry *entry;
+
+	if (time == NULL)
+		return;
+
+	drawobj = time->drawobj;
+
+	if (drawobj == NULL)
+		return;
+
+	cmdobj = CMDOBJ(drawobj);
+	entry = cmdobj->profiling_buf_entry;
+
+	if (entry) {
+		struct kgsl_drawobj_profiling_buffer *profile_buffer;
+
+		profile_buffer = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
+					cmdobj->profiling_buffer_gpuaddr);
+
+		if (profile_buffer == NULL)
+			return;
+
+		/* Return kernel clock time to the the client if requested */
+		if (drawobj->flags & KGSL_DRAWOBJ_PROFILING_KTIME) {
+			uint64_t secs = time->ktime;
+
+			profile_buffer->wall_clock_ns =
+				do_div(secs, NSEC_PER_SEC);
+			profile_buffer->wall_clock_s = secs;
+		} else {
+			profile_buffer->wall_clock_s = time->utime.tv_sec;
+			profile_buffer->wall_clock_ns = time->utime.tv_nsec;
+		}
+
+		profile_buffer->gpu_ticks_queued = time->ticks;
+
+		kgsl_memdesc_unmap(&entry->memdesc);
+	}
+}
+
 void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
 		struct adreno_submit_time *time)
 {
 	struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
 
-	if (time != NULL)
+	if (time != NULL) {
 		adreno_get_submit_time(adreno_dev, rb, time);
+		/* Put the timevalues in the profiling buffer */
+		adreno_profile_submit_time(time);
+	}
 
 	adreno_ringbuffer_wptr(adreno_dev, rb);
 }
@@ -261,7 +308,8 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-	int i, status;
+	int i;
+	int status = -ENOMEM;
 
 	if (!adreno_is_a3xx(adreno_dev)) {
 		status = kgsl_allocate_global(device, &device->scratch,
@@ -774,16 +822,12 @@
 	int flags = KGSL_CMD_FLAGS_NONE;
 	int ret;
 	struct adreno_ringbuffer *rb;
-	struct kgsl_drawobj_profiling_buffer *profile_buffer = NULL;
 	unsigned int dwords = 0;
 	struct adreno_submit_time local;
-	struct kgsl_mem_entry *entry = cmdobj->profiling_buf_entry;
 	struct adreno_firmware *fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE);
 	bool set_ib1list_marker = false;
 
-	if (entry)
-		profile_buffer = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
-					cmdobj->profiling_buffer_gpuaddr);
+	memset(&local, 0x0, sizeof(local));
 
 	context = drawobj->context;
 	drawctxt = ADRENO_CONTEXT(context);
@@ -855,7 +899,8 @@
 	dwords += (numibs * 30);
 
 	if (drawobj->flags & KGSL_DRAWOBJ_PROFILING &&
-		!adreno_is_a3xx(adreno_dev) && profile_buffer) {
+		!adreno_is_a3xx(adreno_dev) &&
+		(cmdobj->profiling_buf_entry != NULL)) {
 		user_profiling = true;
 		dwords += 6;
 
@@ -875,6 +920,8 @@
 
 		if (time == NULL)
 			time = &local;
+
+		time->drawobj = drawobj;
 	}
 
 	if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) {
@@ -1027,35 +1074,9 @@
 	if (!ret) {
 		set_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv);
 		cmdobj->global_ts = drawctxt->internal_timestamp;
-
-		/* Put the timevalues in the profiling buffer */
-		if (user_profiling) {
-			/*
-			 * Return kernel clock time to the the client
-			 * if requested
-			 */
-			if (drawobj->flags & KGSL_DRAWOBJ_PROFILING_KTIME) {
-				uint64_t secs = time->ktime;
-
-				profile_buffer->wall_clock_ns =
-					do_div(secs, NSEC_PER_SEC);
-				profile_buffer->wall_clock_s = secs;
-			} else {
-				profile_buffer->wall_clock_s =
-					time->utime.tv_sec;
-				profile_buffer->wall_clock_ns =
-					time->utime.tv_nsec;
-			}
-			profile_buffer->gpu_ticks_queued = time->ticks;
-		}
 	}
 
 done:
-	/* Corresponding unmap to the memdesc map of profile_buffer */
-	if (entry)
-		kgsl_memdesc_unmap(&entry->memdesc);
-
-
 	trace_kgsl_issueibcmds(device, context->id, numibs, drawobj->timestamp,
 			drawobj->flags, ret, drawctxt->type);
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 1dfdb5b..a4dc901 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, 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
@@ -43,11 +43,13 @@
  * @ticks: GPU ticks at submit time (from the 19.2Mhz timer)
  * @ktime: local clock time (in nanoseconds)
  * @utime: Wall clock time
+ * @drawobj: the object that we want to profile
  */
 struct adreno_submit_time {
 	uint64_t ticks;
 	u64 ktime;
 	struct timespec utime;
+	struct kgsl_drawobj *drawobj;
 };
 
 /**
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index f57fbb6..913f9bf 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, 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
@@ -531,14 +531,21 @@
 	int ret = 0, id;
 	struct kgsl_process_private  *proc_priv = dev_priv->process_priv;
 
+	/*
+	 * Read and increment the context count under lock to make sure
+	 * no process goes beyond the specified context limit.
+	 */
+	spin_lock(&proc_priv->ctxt_count_lock);
 	if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
 		KGSL_DRV_ERR(device,
 			"Per process context limit reached for pid %u",
 			dev_priv->process_priv->pid);
+		spin_unlock(&proc_priv->ctxt_count_lock);
 		return -ENOSPC;
 	}
 
 	atomic_inc(&proc_priv->ctxt_count);
+	spin_unlock(&proc_priv->ctxt_count_lock);
 
 	id = _kgsl_get_context_id(device);
 	if (id == -ENOSPC) {
@@ -753,6 +760,8 @@
 
 	mutex_lock(&device->mutex);
 	status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
+	if (status == 0)
+		device->ftbl->dispatcher_halt(device);
 	mutex_unlock(&device->mutex);
 
 	KGSL_PWR_WARN(device, "suspend end\n");
@@ -767,6 +776,7 @@
 	KGSL_PWR_WARN(device, "resume start\n");
 	mutex_lock(&device->mutex);
 	if (device->state == KGSL_STATE_SUSPEND) {
+		device->ftbl->dispatcher_unhalt(device);
 		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
 	} else if (device->state != KGSL_STATE_INIT) {
 		/*
@@ -918,6 +928,7 @@
 
 	spin_lock_init(&private->mem_lock);
 	spin_lock_init(&private->syncsource_lock);
+	spin_lock_init(&private->ctxt_count_lock);
 
 	idr_init(&private->mem_idr);
 	idr_init(&private->syncsource_idr);
@@ -2998,7 +3009,7 @@
 	long ret = 0;
 	bool full_flush = false;
 	uint64_t size = 0;
-	int i, count = 0;
+	int i;
 	void __user *ptr;
 
 	if (param->count == 0 || param->count > 128)
@@ -3010,8 +3021,8 @@
 
 	entries = kcalloc(param->count, sizeof(*entries), GFP_KERNEL);
 	if (entries == NULL) {
-		ret = -ENOMEM;
-		goto out;
+		kfree(objs);
+		return -ENOMEM;
 	}
 
 	ptr = to_user_ptr(param->objs);
@@ -3028,8 +3039,6 @@
 		if (entries[i] == NULL)
 			continue;
 
-		count++;
-
 		if (!(objs[i].op & KGSL_GPUMEM_CACHE_RANGE))
 			size += entries[i]->memdesc.size;
 		else if (objs[i].offset < entries[i]->memdesc.size)
@@ -3038,25 +3047,23 @@
 		full_flush = check_full_flush(size, objs[i].op);
 		if (full_flush) {
 			trace_kgsl_mem_sync_full_cache(i, size);
-			break;
+			goto out;
 		}
 
 		ptr += sizeof(*objs);
 	}
 
-	if (!full_flush) {
-		for (i = 0; !ret && i < param->count; i++)
-			if (entries[i])
-				ret = _kgsl_gpumem_sync_cache(entries[i],
-						objs[i].offset, objs[i].length,
-						objs[i].op);
-	}
+	for (i = 0; !ret && i < param->count; i++)
+		if (entries[i])
+			ret = _kgsl_gpumem_sync_cache(entries[i],
+					objs[i].offset, objs[i].length,
+					objs[i].op);
 
+out:
 	for (i = 0; i < param->count; i++)
 		if (entries[i])
 			kgsl_mem_entry_put(entries[i]);
 
-out:
 	kfree(entries);
 	kfree(objs);
 
@@ -3422,7 +3429,13 @@
 	if (entry == NULL)
 		return -EINVAL;
 
+	if (!kgsl_mem_entry_set_pend(entry)) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+
 	if (entry->memdesc.cur_bindings != 0) {
+		kgsl_mem_entry_unset_pend(entry);
 		kgsl_mem_entry_put(entry);
 		return -EINVAL;
 	}
@@ -3491,7 +3504,13 @@
 	if (entry == NULL)
 		return -EINVAL;
 
+	if (!kgsl_mem_entry_set_pend(entry)) {
+		kgsl_mem_entry_put(entry);
+		return -EBUSY;
+	}
+
 	if (entry->bind_tree.rb_node != NULL) {
+		kgsl_mem_entry_unset_pend(entry);
 		kgsl_mem_entry_put(entry);
 		return -EINVAL;
 	}
@@ -4031,6 +4050,7 @@
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_gpuobj_set_info *param = data;
 	struct kgsl_mem_entry *entry;
+	int ret = 0;
 
 	if (param->id == 0)
 		return -EINVAL;
@@ -4043,13 +4063,16 @@
 		copy_metadata(entry, param->metadata, param->metadata_len);
 
 	if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) {
-		entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
-		entry->memdesc.flags |= (uint64_t)(param->type <<
-						KGSL_MEMTYPE_SHIFT);
+		if (param->type <= (KGSL_MEMTYPE_MASK >> KGSL_MEMTYPE_SHIFT)) {
+			entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
+			entry->memdesc.flags |= (uint64_t)((param->type <<
+				KGSL_MEMTYPE_SHIFT) & KGSL_MEMTYPE_MASK);
+		} else
+			ret = -EINVAL;
 	}
 
 	kgsl_mem_entry_put(entry);
-	return 0;
+	return ret;
 }
 
 /**
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7c3bff7..41d1a38 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, 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
@@ -190,6 +190,8 @@
 	void (*gpu_model)(struct kgsl_device *device, char *str,
 		size_t bufsz);
 	void (*stop_fault_timer)(struct kgsl_device *device);
+	void (*dispatcher_halt)(struct kgsl_device *device);
+	void (*dispatcher_unhalt)(struct kgsl_device *device);
 };
 
 struct kgsl_ioctl {
@@ -303,6 +305,7 @@
 
 	u32 snapshot_faultcount;	/* Total number of faults since boot */
 	bool force_panic;		/* Force panic after snapshot dump */
+	bool prioritize_unrecoverable;	/* Overwrite with new GMU snapshots */
 
 	/* Use CP Crash dumper to get GPU snapshot*/
 	bool snapshot_crashdumper;
@@ -442,6 +445,7 @@
  * @syncsource_lock: Spinlock to protect the syncsource idr
  * @fd_count: Counter for the number of FDs for this process
  * @ctxt_count: Count for the number of contexts for this process
+ * @ctxt_count_lock: Spinlock to protect ctxt_count
  */
 struct kgsl_process_private {
 	unsigned long priv;
@@ -462,6 +466,7 @@
 	spinlock_t syncsource_lock;
 	int fd_count;
 	atomic_t ctxt_count;
+	spinlock_t ctxt_count_lock;
 };
 
 /**
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 52d45bb..dbf517a 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -309,7 +309,7 @@
  * @gmu: Pointer to GMU device
  * @node: Pointer to GMU device node
  */
-int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
+static int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
 {
 	struct device_node *child;
 	struct gmu_iommu_context *ctx = NULL;
@@ -346,7 +346,7 @@
  * from IOMMU context banks.
  * @gmu: Pointer to GMU device
  */
-void gmu_kmem_close(struct gmu_device *gmu)
+static void gmu_kmem_close(struct gmu_device *gmu)
 {
 	int i;
 	struct gmu_memdesc *md = &gmu->fw_image;
@@ -386,7 +386,7 @@
 	iommu_domain_free(ctx->domain);
 }
 
-void gmu_memory_close(struct gmu_device *gmu)
+static void gmu_memory_close(struct gmu_device *gmu)
 {
 	gmu_kmem_close(gmu);
 	/* Free user memory context */
@@ -400,7 +400,7 @@
  * @gmu: Pointer to GMU device
  * @node: Pointer to GMU device node
  */
-int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node)
+static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node)
 {
 	int ret;
 
@@ -753,7 +753,7 @@
 	return 0;
 }
 
-int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr)
+static int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr)
 {
 	struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc;
 	int ret;
@@ -1638,6 +1638,8 @@
 		unsigned int fence_mask)
 {
 	unsigned int status, i;
+	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+	unsigned int reg_offset = gpudev->reg_offsets->offsets[offset];
 
 	adreno_writereg(adreno_dev, offset, val);
 
@@ -1662,6 +1664,6 @@
 	}
 
 	dev_err(adreno_dev->dev.dev,
-		"GMU fenced register write timed out: reg %x\n", offset);
+		"GMU fenced register write timed out: reg 0x%x\n", reg_offset);
 	return -ETIMEDOUT;
 }
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index daac9f1..b1e6c83 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -259,7 +259,7 @@
 	return rc;
 }
 
-int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state)
+static int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state)
 {
 	struct hfi_gmu_init_cmd init_msg = {
 		.hdr = {
@@ -292,7 +292,7 @@
 	return rc;
 }
 
-int hfi_get_fw_version(struct gmu_device *gmu,
+static int hfi_get_fw_version(struct gmu_device *gmu,
 		uint32_t expected_ver, uint32_t *ver)
 {
 	struct hfi_fw_version_cmd fw_ver = {
@@ -356,7 +356,7 @@
 	return rc;
 }
 
-int hfi_send_perftbl(struct gmu_device *gmu)
+static int hfi_send_perftbl(struct gmu_device *gmu)
 {
 	struct hfi_dcvstable_cmd dcvstbl = {
 		.hdr = {
@@ -397,7 +397,7 @@
 	return rc;
 }
 
-int hfi_send_bwtbl(struct gmu_device *gmu)
+static int hfi_send_bwtbl(struct gmu_device *gmu)
 {
 	struct hfi_bwtable_cmd bwtbl = {
 		.hdr = {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 4b11bbe..c4296c8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -165,14 +165,19 @@
 }
 
 void kgsl_iommu_unmap_global_secure_pt_entry(struct kgsl_device *device,
-				struct kgsl_memdesc *entry)
+				struct kgsl_memdesc *memdesc)
 {
-	if (!kgsl_mmu_is_secured(&device->mmu))
+	if (!kgsl_mmu_is_secured(&device->mmu) || memdesc == NULL)
 		return;
 
-	if (entry != NULL && entry->pagetable->name == KGSL_MMU_SECURE_PT)
-		kgsl_mmu_unmap(entry->pagetable, entry);
+	/* Check if an empty memdesc got passed in */
+	if ((memdesc->gpuaddr == 0) || (memdesc->size == 0))
+		return;
 
+	if (memdesc->pagetable) {
+		if (memdesc->pagetable->name == KGSL_MMU_SECURE_PT)
+			kgsl_mmu_unmap(memdesc->pagetable, memdesc);
+	}
 }
 
 int kgsl_iommu_map_global_secure_pt_entry(struct kgsl_device *device,
@@ -2522,6 +2527,7 @@
 } kgsl_iommu_cbs[] = {
 	{ KGSL_IOMMU_CONTEXT_USER, "gfx3d_user", },
 	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure" },
+	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure_alt" },
 };
 
 static int _kgsl_iommu_cb_probe(struct kgsl_device *device,
@@ -2529,12 +2535,20 @@
 {
 	struct platform_device *pdev = of_find_device_by_node(node);
 	struct kgsl_iommu_context *ctx = NULL;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(kgsl_iommu_cbs); i++) {
 		if (!strcmp(node->name, kgsl_iommu_cbs[i].name)) {
 			int id = kgsl_iommu_cbs[i].id;
 
+			if (ADRENO_QUIRK(adreno_dev,
+				ADRENO_QUIRK_MMU_SECURE_CB_ALT)) {
+				if (!strcmp(node->name, "gfx3d_secure"))
+					continue;
+			} else if (!strcmp(node->name, "gfx3d_secure_alt"))
+				continue;
+
 			ctx = &iommu->ctx[id];
 			ctx->id = id;
 			ctx->cb_num = -1;
@@ -2545,8 +2559,8 @@
 	}
 
 	if (ctx == NULL) {
-		KGSL_CORE_ERR("dt: Unknown context label %s\n", node->name);
-		return -EINVAL;
+		KGSL_CORE_ERR("dt: Unused context label %s\n", node->name);
+		return 0;
 	}
 
 	if (ctx->id == KGSL_IOMMU_CONTEXT_SECURE)
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 462ff3b..65460f7 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -25,7 +25,7 @@
  */
 #define KGSL_IOMMU_GLOBAL_MEM_SIZE	(20 * SZ_1M)
 #define KGSL_IOMMU_GLOBAL_MEM_BASE32	0xf8000000
-#define KGSL_IOMMU_GLOBAL_MEM_BASE64	TASK_SIZE_32
+#define KGSL_IOMMU_GLOBAL_MEM_BASE64	0xfc000000
 
 #define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu)	\
 	(MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7509ceb..1baf20e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2222,7 +2222,7 @@
 
 int kgsl_pwrctrl_init(struct kgsl_device *device)
 {
-	int i, k, m, n = 0, result;
+	int i, k, m, n = 0, result, freq;
 	struct platform_device *pdev = device->pdev;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct device_node *ocmem_bus_node;
@@ -2269,7 +2269,7 @@
 	pwr->wakeup_maxpwrlevel = 0;
 
 	for (i = 0; i < pwr->num_pwrlevels; i++) {
-		unsigned int freq = pwr->pwrlevels[i].gpu_freq;
+		freq = pwr->pwrlevels[i].gpu_freq;
 
 		if (freq > 0)
 			freq = clk_round_rate(pwr->grp_clks[0], freq);
@@ -2282,11 +2282,10 @@
 
 	kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
 
-	if (pwr->grp_clks[6] != NULL)
+	freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
+	if (freq > 0)
 		kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[6],
-			clk_round_rate(pwr->grp_clks[6],
-			KGSL_RBBMTIMER_CLK_FREQ),
-			clocks[6]);
+			freq, clocks[6]);
 
 	_isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1);
 
@@ -2749,6 +2748,7 @@
 {
 	int status = 0;
 	struct gmu_device *gmu = &device->gmu;
+	unsigned int state = device->state;
 
 	switch (device->state) {
 	case KGSL_STATE_RESET:
@@ -2795,13 +2795,15 @@
 				WARN_ONCE(1, "Failed to recover GMU\n");
 				if (device->snapshot)
 					device->snapshot->recovered = false;
+				kgsl_pwrctrl_set_state(device, state);
 			} else {
 				if (device->snapshot)
 					device->snapshot->recovered = true;
+				kgsl_pwrctrl_set_state(device,
+					KGSL_STATE_AWARE);
 			}
 
 			clear_bit(GMU_FAULT, &gmu->flags);
-			kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
 			return status;
 		}
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index c4ff22f..2b8b6df 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -892,12 +892,6 @@
 		return PTR_ERR(opp);
 	}
 
-	max_freq = dev_pm_opp_get_freq(opp);
-	if (!max_freq) {
-		rcu_read_unlock();
-		return result;
-	}
-
 	opp = dev_pm_opp_find_freq_ceil(dev, &min_freq);
 	if (IS_ERR(opp))
 		min_freq = pwr->pwrlevels[pwr->min_pwrlevel].gpu_freq;
@@ -910,12 +904,12 @@
 	min_level = pwr->thermal_pwrlevel_floor;
 
 	/* Thermal limit cannot be lower than lowest non-zero operating freq */
-	for (level = 0; level < (pwr->num_pwrlevels - 1); level++)
+	for (level = 0; level < (pwr->num_pwrlevels - 1); level++) {
 		if (pwr->pwrlevels[level].gpu_freq == max_freq)
 			max_level = level;
 		if (pwr->pwrlevels[level].gpu_freq == min_freq)
 			min_level = level;
-
+	}
 
 	pwr->thermal_pwrlevel = max_level;
 	pwr->thermal_pwrlevel_floor = min_level;
@@ -1039,24 +1033,12 @@
 	data->disable_busy_time_burst = of_property_read_bool(
 		device->pdev->dev.of_node, "qcom,disable-busy-time-burst");
 
-	data->ctxt_aware_enable =
-		of_property_read_bool(device->pdev->dev.of_node,
-			"qcom,enable-ca-jump");
-
-	if (data->ctxt_aware_enable) {
-		if (of_property_read_u32(device->pdev->dev.of_node,
-				"qcom,ca-target-pwrlevel",
-				&data->bin.ctxt_aware_target_pwrlevel))
-			data->bin.ctxt_aware_target_pwrlevel = 1;
-
-		if ((data->bin.ctxt_aware_target_pwrlevel >
-						pwr->num_pwrlevels))
-			data->bin.ctxt_aware_target_pwrlevel = 1;
-
-		if (of_property_read_u32(device->pdev->dev.of_node,
-				"qcom,ca-busy-penalty",
-				&data->bin.ctxt_aware_busy_penalty))
-			data->bin.ctxt_aware_busy_penalty = 12000;
+	if (pwrscale->ctxt_aware_enable) {
+		data->ctxt_aware_enable = pwrscale->ctxt_aware_enable;
+		data->bin.ctxt_aware_target_pwrlevel =
+			pwrscale->ctxt_aware_target_pwrlevel;
+		data->bin.ctxt_aware_busy_penalty =
+			pwrscale->ctxt_aware_busy_penalty;
 	}
 
 	if (of_property_read_bool(device->pdev->dev.of_node,
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 7e906a0..9e28b65 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2018, 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
@@ -91,6 +91,11 @@
  * @popp_level - Current level of POPP mitigation
  * @popp_state - Control state for POPP, on/off, recently pushed, etc
  * @cooling_dev - Thermal cooling device handle
+ * @ctxt_aware_enable - Whether or not ctxt aware DCVS feature is enabled
+ * @ctxt_aware_busy_penalty - The time in microseconds required to trigger
+ * ctxt aware power level jump
+ * @ctxt_aware_target_pwrlevel - pwrlevel to jump on in case of ctxt aware
+ * power level jump
  */
 struct kgsl_pwrscale {
 	struct devfreq *devfreqptr;
@@ -113,6 +118,9 @@
 	int popp_level;
 	unsigned long popp_state;
 	struct thermal_cooling_device *cooling_dev;
+	bool ctxt_aware_enable;
+	unsigned int ctxt_aware_target_pwrlevel;
+	unsigned int ctxt_aware_busy_penalty;
 };
 
 int kgsl_pwrscale_init(struct device *dev, const char *governor);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 33ce60d..5e41611 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -663,7 +663,8 @@
 	 * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
 	 */
 	if (device->snapshot != NULL) {
-		if (!gmu_fault || !device->snapshot->recovered)
+		if (!device->prioritize_unrecoverable ||
+				!device->snapshot->recovered)
 			return;
 
 		/*
@@ -954,6 +955,28 @@
 	return (ssize_t) ret < 0 ? ret : count;
 }
 
+/* Show the prioritize_unrecoverable status */
+static ssize_t prioritize_unrecoverable_show(
+		struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			device->prioritize_unrecoverable);
+}
+
+/* Store the priority value to prioritize unrecoverable */
+static ssize_t prioritize_unrecoverable_store(
+		struct kgsl_device *device, const char *buf, size_t count)
+{
+	unsigned int val = 0;
+	int ret = 0;
+
+	ret = kgsl_sysfs_store(buf, &val);
+	if (!ret && device)
+		device->prioritize_unrecoverable = (bool) val;
+
+	return (ssize_t) ret < 0 ? ret : count;
+}
+
 /* Show the snapshot_crashdumper request status */
 static ssize_t snapshot_crashdumper_show(struct kgsl_device *device, char *buf)
 {
@@ -1026,6 +1049,8 @@
 static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
 static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
 static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
+static SNAPSHOT_ATTR(prioritize_unrecoverable, 0644,
+		prioritize_unrecoverable_show, prioritize_unrecoverable_store);
 static SNAPSHOT_ATTR(snapshot_crashdumper, 0644, snapshot_crashdumper_show,
 	snapshot_crashdumper_store);
 static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show,
@@ -1110,6 +1135,7 @@
 	device->snapshot = NULL;
 	device->snapshot_faultcount = 0;
 	device->force_panic = 0;
+	device->prioritize_unrecoverable = true;
 	device->snapshot_crashdumper = 1;
 	device->snapshot_legacy = 0;
 
@@ -1135,6 +1161,11 @@
 	if (ret)
 		goto done;
 
+	ret = sysfs_create_file(&device->snapshot_kobj,
+			&attr_prioritize_unrecoverable.attr);
+	if (ret)
+		goto done;
+
 	ret  = sysfs_create_file(&device->snapshot_kobj,
 			&attr_snapshot_crashdumper.attr);
 	if (ret)
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index d4165b3..a4de6a0 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -734,7 +734,8 @@
 			fput(sync_file->file);
 		else if (sfence)
 			fence_put(&sfence->fence);
-		kgsl_syncsource_put(syncsource);
+		else
+			kgsl_syncsource_put(syncsource);
 	}
 
 	return ret;
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 7c9f334e..955401d 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014,2017-2018 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
@@ -137,8 +137,8 @@
 }
 
 
-struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
-					void (*func)(void *priv), void *priv,
+static inline struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
+					bool (*func)(void *priv), void *priv,
 					char *fence_name, int name_len)
 {
 	return NULL;
@@ -188,7 +188,7 @@
 
 }
 
-void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+static inline void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
 					char *fence_str, int len)
 {
 }
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index f2a7483..b5888db 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2366,7 +2366,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
 	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
-	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
@@ -2636,6 +2635,17 @@
 			strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
 			return true;
 		break;
+	case USB_VENDOR_ID_ELAN:
+		/*
+		 * Many Elan devices have a product id of 0x0401 and are handled
+		 * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
+		 * is not (and cannot be) handled by that driver ->
+		 * Ignore all 0x0401 devs except for the ELAN0800 dev.
+		 */
+		if (hdev->product == 0x0401 &&
+		    strncmp(hdev->name, "ELAN0800", 8) != 0)
+			return true;
+		break;
 	}
 
 	if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index d72dfb2..7a4d39c 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -2192,23 +2192,23 @@
 	int i;
 	unsigned long flags;
 
-	spin_lock_irqsave(&remote->remote_lock, flags);
-	remote->remotes[index].registered = false;
-	spin_unlock_irqrestore(&remote->remote_lock, flags);
-
-	if (remote->remotes[index].battery.battery)
-		devres_release_group(&wacom->hdev->dev,
-				     &remote->remotes[index].battery.bat_desc);
-
-	if (remote->remotes[index].group.name)
-		devres_release_group(&wacom->hdev->dev,
-				     &remote->remotes[index]);
-
 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
 		if (remote->remotes[i].serial == serial) {
+
+			spin_lock_irqsave(&remote->remote_lock, flags);
+			remote->remotes[i].registered = false;
+			spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+			if (remote->remotes[i].battery.battery)
+				devres_release_group(&wacom->hdev->dev,
+						     &remote->remotes[i].battery.bat_desc);
+
+			if (remote->remotes[i].group.name)
+				devres_release_group(&wacom->hdev->dev,
+						     &remote->remotes[i]);
+
 			remote->remotes[i].serial = 0;
 			remote->remotes[i].group.name = NULL;
-			remote->remotes[i].registered = false;
 			remote->remotes[i].battery.battery = NULL;
 			wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
 		}
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index ba59eae..d013acf 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -476,8 +477,8 @@
 static long pmbus_reg2data_direct(struct pmbus_data *data,
 				  struct pmbus_sensor *sensor)
 {
-	long val = (s16) sensor->data;
-	long m, b, R;
+	s64 b, val = (s16)sensor->data;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -505,11 +506,12 @@
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = div_s64(val + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return (val - b) / m;
+	val = div_s64(val - b, m);
+	return clamp_val(val, LONG_MIN, LONG_MAX);
 }
 
 /*
@@ -629,7 +631,8 @@
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 				 struct pmbus_sensor *sensor, long val)
 {
-	long m, b, R;
+	s64 b, val64 = val;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -646,18 +649,18 @@
 		R -= 3;		/* Adjust R and b for data in milli-units */
 		b *= 1000;
 	}
-	val = val * m + b;
+	val64 = val64 * m + b;
 
 	while (R > 0) {
-		val *= 10;
+		val64 *= 10;
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val64 = div_s64(val64 + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return val;
+	return (u16)clamp_val(val64, S16_MIN, S16_MAX);
 }
 
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index f3e16b3..62ad4f4 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -677,6 +677,80 @@
 	{124,	980}
 };
 
+/* Voltage to temperature */
+static const struct qpnp_vadc_map_pt adcmap_batt_therm_qrd[] = {
+	{1840,	-400},
+	{1835,	-380},
+	{1828,	-360},
+	{1821,	-340},
+	{1813,	-320},
+	{1803,	-300},
+	{1793,	-280},
+	{1781,	-260},
+	{1768,	-240},
+	{1753,	-220},
+	{1737,	-200},
+	{1719,	-180},
+	{1700,	-160},
+	{1679,	-140},
+	{1655,	-120},
+	{1630,	-100},
+	{1603,	-80},
+	{1574,	-60},
+	{1543,	-40},
+	{1510,	-20},
+	{1475,	00},
+	{1438,	20},
+	{1400,	40},
+	{1360,	60},
+	{1318,	80},
+	{1276,	100},
+	{1232,	120},
+	{1187,	140},
+	{1142,	160},
+	{1097,	180},
+	{1051,	200},
+	{1005,	220},
+	{960,	240},
+	{915,	260},
+	{871,	280},
+	{828,	300},
+	{786,	320},
+	{745,	340},
+	{705,	360},
+	{666,	380},
+	{629,	400},
+	{594,	420},
+	{560,	440},
+	{527,	460},
+	{497,	480},
+	{467,	500},
+	{439,	520},
+	{413,	540},
+	{388,	560},
+	{365,	580},
+	{343,	600},
+	{322,	620},
+	{302,	640},
+	{284,	660},
+	{267,	680},
+	{251,	700},
+	{235,	720},
+	{221,	740},
+	{208,	760},
+	{195,	780},
+	{184,	800},
+	{173,	820},
+	{163,	840},
+	{153,	860},
+	{144,	880},
+	{136,	900},
+	{128,	920},
+	{120,	940},
+	{114,	960},
+	{107,	980}
+};
+
 /*
  * Voltage to temperature table for 100k pull up for NTCG104EF104 with
  * 1.875V reference.
@@ -1016,6 +1090,36 @@
 }
 EXPORT_SYMBOL(qpnp_adc_batt_therm);
 
+int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *chip,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t batt_thm_voltage = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	if (adc_properties->adc_hc) {
+		/* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */
+		if (adc_code > QPNP_VADC_HC_MAX_CODE)
+			adc_code = 0;
+		batt_thm_voltage = (int64_t) adc_code;
+		batt_thm_voltage *= (adc_properties->adc_vdd_reference
+							* 1000);
+		batt_thm_voltage = div64_s64(batt_thm_voltage,
+				adc_properties->full_scale_code * 1000);
+		qpnp_adc_map_voltage_temp(adcmap_batt_therm_qrd,
+			ARRAY_SIZE(adcmap_batt_therm_qrd),
+			batt_thm_voltage, &adc_chan_result->physical);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_batt_therm_qrd);
+
 int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -1929,6 +2033,34 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_pmi_chg_temp);
 
+int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *chip,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int rc = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	rc = qpnp_adc_scale_default(chip, adc_code, adc_properties,
+			chan_properties, adc_chan_result);
+	if (rc < 0)
+		return rc;
+
+	pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+						adc_chan_result->physical);
+	/* T = (1.49322 – V) / 0.00356 */
+	adc_chan_result->physical = 1493220 - adc_chan_result->physical;
+	adc_chan_result->physical = div64_s64(adc_chan_result->physical, 356);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_die_temp_1390);
+
 int32_t qpnp_adc_enable_voltage(struct qpnp_adc_drv *adc)
 {
 	int rc = 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 8b44c0f..88b879c 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -107,7 +107,7 @@
 #define QPNP_VADC_CONV_TIME_MIN					1000
 #define QPNP_VADC_CONV_TIME_MAX					1100
 #define QPNP_ADC_COMPLETION_TIMEOUT				HZ
-#define QPNP_VADC_ERR_COUNT					20
+#define QPNP_VADC_ERR_COUNT					50
 #define QPNP_OP_MODE_SHIFT					3
 
 #define QPNP_VADC_THR_LSB_MASK(val)				(val & 0xff)
@@ -224,6 +224,8 @@
 	[SCALE_DIE_TEMP] = {qpnp_adc_scale_die_temp},
 	[SCALE_I_DEFAULT] = {qpnp_iadc_scale_default},
 	[SCALE_USBIN_I] = {qpnp_adc_scale_usbin_curr},
+	[SCALE_BATT_THERM_TEMP_QRD] = {qpnp_adc_batt_therm_qrd},
+	[SCALE_SMB1390_DIE_TEMP] = {qpnp_adc_scale_die_temp_1390},
 };
 
 static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = {
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
index 7ef2710..5173770 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.c
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,17 +23,23 @@
 static struct tmc_drvdata *tmcdrvdata;
 
 static void tmc_etr_read_bytes(struct byte_cntr *byte_cntr_data, loff_t *ppos,
-			       size_t bytes, size_t *len)
+			       size_t bytes, size_t *len, char **bufp)
 {
-	if (*len >= bytes) {
-		atomic_dec(&byte_cntr_data->irq_cnt);
+
+	if (*bufp >= (char *)(tmcdrvdata->vaddr + tmcdrvdata->size))
+		*bufp = tmcdrvdata->vaddr;
+
+	if (*len >= bytes)
 		*len = bytes;
-	} else {
-		if (((uint32_t)*ppos % bytes) + *len > bytes)
-			*len = bytes - ((uint32_t)*ppos % bytes);
-		if ((*len + (uint32_t)*ppos) % bytes == 0)
-			atomic_dec(&byte_cntr_data->irq_cnt);
-	}
+	else if (((uint32_t)*ppos % bytes) + *len > bytes)
+		*len = bytes - ((uint32_t)*ppos % bytes);
+
+	if ((*bufp + *len) > (char *)(tmcdrvdata->vaddr +
+		tmcdrvdata->size))
+		*len = (char *)(tmcdrvdata->vaddr + tmcdrvdata->size) -
+			*bufp;
+	if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0)
+		atomic_dec(&byte_cntr_data->irq_cnt);
 }
 
 static void tmc_etr_sg_read_pos(loff_t *ppos,
@@ -96,7 +102,7 @@
 		if (*len >= (bytes - ((uint32_t)*ppos % bytes)))
 			*len = bytes - ((uint32_t)*ppos % bytes);
 
-		if ((*len + (uint32_t)*ppos) % bytes == 0)
+		if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0)
 			atomic_dec(&tmcdrvdata->byte_cntr->irq_cnt);
 	}
 
@@ -143,6 +149,8 @@
 	if (!byte_cntr_data->read_active)
 		goto err0;
 
+	bufp = (char *)(tmcdrvdata->buf + *ppos);
+
 	if (byte_cntr_data->enable) {
 		if (!atomic_read(&byte_cntr_data->irq_cnt)) {
 			mutex_unlock(&byte_cntr_data->byte_cntr_lock);
@@ -153,11 +161,11 @@
 			if (!byte_cntr_data->read_active)
 				goto err0;
 		}
-		bufp = (char *)(tmcdrvdata->vaddr + *ppos);
 
 		if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
 			tmc_etr_read_bytes(byte_cntr_data, ppos,
-					   byte_cntr_data->block_size, &len);
+					   byte_cntr_data->block_size, &len,
+					   &bufp);
 		else
 			tmc_etr_sg_read_pos(ppos, byte_cntr_data->block_size, 0,
 					    &len, &bufp);
@@ -179,7 +187,7 @@
 			if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
 				tmc_etr_read_bytes(byte_cntr_data, ppos,
 						   byte_cntr_data->block_size,
-						   &len);
+						   &len, &bufp);
 			else
 				tmc_etr_sg_read_pos(ppos,
 						    byte_cntr_data->block_size,
@@ -229,7 +237,7 @@
 
 	mutex_lock(&byte_cntr_data->byte_cntr_lock);
 	byte_cntr_data->enable = false;
-	coresight_csr_set_byte_cntr(0);
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr, 0);
 	mutex_unlock(&byte_cntr_data->byte_cntr_lock);
 
 }
@@ -243,7 +251,7 @@
 	mutex_lock(&byte_cntr_data->byte_cntr_lock);
 	byte_cntr_data->read_active = false;
 
-	coresight_csr_set_byte_cntr(0);
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr, 0);
 	mutex_unlock(&byte_cntr_data->byte_cntr_lock);
 
 	return 0;
@@ -261,7 +269,12 @@
 		return -EINVAL;
 	}
 
-	coresight_csr_set_byte_cntr(byte_cntr_data->block_size);
+	/* IRQ is a '8- byte' counter and to observe interrupt at
+	 * 'block_size' bytes of data
+	 */
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr,
+				(byte_cntr_data->block_size) / 8);
+
 	fp->private_data = byte_cntr_data;
 	nonseekable_open(in, fp);
 	byte_cntr_data->enable = true;
@@ -364,6 +377,7 @@
 
 	tmcdrvdata = drvdata;
 	byte_cntr_data->byte_cntr_irq = byte_cntr_irq;
+	byte_cntr_data->csr = drvdata->csr;
 	atomic_set(&byte_cntr_data->irq_cnt, 0);
 	init_waitqueue_head(&byte_cntr_data->wq);
 	mutex_init(&byte_cntr_data->byte_cntr_lock);
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.h b/drivers/hwtracing/coresight/coresight-byte-cntr.h
index 94e9089..b104d92 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.h
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.h
@@ -16,6 +16,7 @@
 	atomic_t		irq_cnt;
 	wait_queue_head_t	wq;
 	struct mutex		byte_cntr_lock;
+	struct coresight_csr		*csr;
 };
 
 extern void tmc_etr_byte_cntr_start(struct byte_cntr *byte_cntr_data);
diff --git a/drivers/hwtracing/coresight/coresight-csr.c b/drivers/hwtracing/coresight/coresight-csr.c
index 1ec73a5..9069530 100644
--- a/drivers/hwtracing/coresight/coresight-csr.c
+++ b/drivers/hwtracing/coresight/coresight-csr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, 2015-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 2015-2016,2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/coresight.h>
+#include <linux/clk.h>
 
 #include "coresight-priv.h"
 
@@ -77,15 +78,32 @@
 	struct device		*dev;
 	struct coresight_device	*csdev;
 	uint32_t		blksize;
+	struct coresight_csr		csr;
+	struct clk		*clk;
+	spinlock_t		spin_lock;
+	bool			usb_bam_support;
+	bool			hwctrl_set_support;
+	bool			set_byte_cntr_support;
+	bool			timestamp_support;
 };
 
-static struct csr_drvdata *csrdrvdata;
+static LIST_HEAD(csr_list);
+#define to_csr_drvdata(c) container_of(c, struct csr_drvdata, csr)
 
-void msm_qdss_csr_enable_bam_to_usb(void)
+void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbbamctrl, usbflshctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
@@ -102,14 +120,24 @@
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_enable_bam_to_usb);
 
-void msm_qdss_csr_disable_bam_to_usb(void)
+void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbbamctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
@@ -117,14 +145,24 @@
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_bam_to_usb);
 
-void msm_qdss_csr_disable_flush(void)
+void msm_qdss_csr_disable_flush(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbflshctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
@@ -132,14 +170,25 @@
 	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
 
-int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val)
+int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
+			 uint32_t val)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	int ret = 0;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return -EINVAL;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->hwctrl_set_support)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
@@ -154,15 +203,24 @@
 		ret = -EINVAL;
 
 	CSR_LOCK(drvdata);
-
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(coresight_csr_hwctrl_set);
 
-void coresight_csr_set_byte_cntr(uint32_t count)
+void coresight_csr_set_byte_cntr(struct coresight_csr *csr, uint32_t count)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->set_byte_cntr_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	csr_writel(drvdata, count, CSR_BYTECNTVAL);
@@ -171,9 +229,85 @@
 	mb();
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
 
+struct coresight_csr *coresight_csr_get(const char *name)
+{
+	struct coresight_csr *csr;
+
+	list_for_each_entry(csr, &csr_list, link) {
+		if (!strcmp(csr->name, name))
+			return csr;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(coresight_csr_get);
+
+static ssize_t csr_show_timestamp(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	ssize_t size = 0;
+	uint64_t time_tick = 0;
+	uint32_t val, time_val0, time_val1;
+	int ret;
+	unsigned long flags;
+
+	struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->timestamp_support) {
+		dev_err(dev, "Invalid param\n");
+		return 0;
+	}
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
+	CSR_UNLOCK(drvdata);
+
+	val = csr_readl(drvdata, CSR_TIMESTAMPCTRL);
+
+	val  = val & ~BIT(0);
+	csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
+
+	val  = val | BIT(0);
+	csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
+
+	time_val0 = csr_readl(drvdata, CSR_QDSSTIMEVAL0);
+	time_val1 = csr_readl(drvdata, CSR_QDSSTIMEVAL1);
+
+	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	time_tick |= (uint64_t)time_val1 << 32;
+	time_tick |= (uint64_t)time_val0;
+	size = scnprintf(buf, PAGE_SIZE, "%llu\n", time_tick);
+	dev_dbg(dev, "timestamp : %s\n", buf);
+	return size;
+}
+
+static DEVICE_ATTR(timestamp, 0444, csr_show_timestamp, NULL);
+
+static struct attribute *csr_attrs[] = {
+	&dev_attr_timestamp.attr,
+	NULL,
+};
+
+static struct attribute_group csr_attr_grp = {
+	.attrs = csr_attrs,
+};
+static const struct attribute_group *csr_attr_grps[] = {
+	&csr_attr_grp,
+	NULL,
+};
+
 static int csr_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -194,6 +328,10 @@
 	drvdata->dev = &pdev->dev;
 	platform_set_drvdata(pdev, drvdata);
 
+	drvdata->clk = devm_clk_get(dev, "apb_pclk");
+	if (IS_ERR(drvdata->clk))
+		dev_dbg(dev, "csr not config clk\n");
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
 	if (!res)
 		return -ENODEV;
@@ -208,27 +346,65 @@
 	if (ret)
 		drvdata->blksize = BLKSIZE_256;
 
+	drvdata->usb_bam_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,usb-bam-support");
+	if (!drvdata->usb_bam_support)
+		dev_dbg(dev, "usb_bam support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "usb_bam operation supported\n");
+
+	drvdata->hwctrl_set_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,hwctrl-set-support");
+	if (!drvdata->hwctrl_set_support)
+		dev_dbg(dev, "hwctrl_set_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "hwctrl_set_support operation supported\n");
+
+	drvdata->set_byte_cntr_support = of_property_read_bool(
+			pdev->dev.of_node, "qcom,set-byte-cntr-support");
+	if (!drvdata->set_byte_cntr_support)
+		dev_dbg(dev, "set byte_cntr_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "set_byte_cntr_support operation supported\n");
+
+	drvdata->timestamp_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,timestamp-support");
+	if (!drvdata->timestamp_support)
+		dev_dbg(dev, "timestamp_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "timestamp_support operation supported\n");
+
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)
 		return -ENOMEM;
 	desc->type = CORESIGHT_DEV_TYPE_NONE;
 	desc->pdata = pdev->dev.platform_data;
 	desc->dev = &pdev->dev;
+	if (drvdata->timestamp_support)
+		desc->groups = csr_attr_grps;
+
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev))
 		return PTR_ERR(drvdata->csdev);
 
 	/* Store the driver data pointer for use in exported functions */
-	csrdrvdata = drvdata;
-	dev_info(dev, "CSR initialized\n");
+	spin_lock_init(&drvdata->spin_lock);
+	drvdata->csr.name = ((struct coresight_platform_data *)
+					 (pdev->dev.platform_data))->name;
+	list_add_tail(&drvdata->csr.link, &csr_list);
+
+	dev_info(dev, "CSR initialized: %s\n", drvdata->csr.name);
 	return 0;
 }
 
 static int csr_remove(struct platform_device *pdev)
 {
+	unsigned long flags;
 	struct csr_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	coresight_unregister(drvdata->csdev);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 	return 0;
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-dbgui.c b/drivers/hwtracing/coresight/coresight-dbgui.c
index e4feea2..eb01fca 100644
--- a/drivers/hwtracing/coresight/coresight-dbgui.c
+++ b/drivers/hwtracing/coresight/coresight-dbgui.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -375,10 +375,10 @@
 				     const char *buf,
 				     size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -403,10 +403,10 @@
 						 const char *buf,
 						 size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -434,10 +434,10 @@
 				     const char *buf,
 				     size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -463,10 +463,10 @@
 				    const char *buf,
 				    size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -492,10 +492,10 @@
 				   const char *buf,
 				   size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	if (!val)
@@ -528,10 +528,10 @@
 				       const char *buf,
 				       size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	if (val > drvdata->size)
@@ -569,10 +569,10 @@
 				       const char *buf,
 				       size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	if (val > drvdata->size)
@@ -615,10 +615,10 @@
 				       const char *buf,
 				       size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -643,10 +643,10 @@
 				    const char *buf,
 				    size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	if (val >= drvdata->size)
@@ -674,10 +674,10 @@
 				    const char *buf,
 				    size_t size)
 {
-	uint32_t val;
+	unsigned long val;
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -755,9 +755,10 @@
 				    size_t size)
 {
 	struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
-	uint32_t val, ret;
+	uint32_t ret;
+	unsigned long val;
 
-	if (kstrtoul(buf, 16, (unsigned long *)&val))
+	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	if (val)
diff --git a/drivers/hwtracing/coresight/coresight-hwevent.c b/drivers/hwtracing/coresight/coresight-hwevent.c
index 22e9d6f..1e8872b 100644
--- a/drivers/hwtracing/coresight/coresight-hwevent.c
+++ b/drivers/hwtracing/coresight/coresight-hwevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -42,6 +42,8 @@
 	struct regulator			**hreg;
 	int					nr_hmux;
 	struct hwevent_mux			*hmux;
+	struct coresight_csr			*csr;
+	const char				*csr_name;
 };
 
 static int hwevent_enable(struct hwevent_drvdata *drvdata)
@@ -132,7 +134,7 @@
 	}
 
 	if (i == drvdata->nr_hmux) {
-		ret = coresight_csr_hwctrl_set(addr, val);
+		ret = coresight_csr_hwctrl_set(drvdata->csr, addr,  val);
 		if (ret) {
 			dev_err(dev, "invalid mux control register address\n");
 			ret = -EINVAL;
@@ -185,6 +187,17 @@
 	drvdata->dev = &pdev->dev;
 	platform_set_drvdata(pdev, drvdata);
 
+	ret = of_get_coresight_csr_name(dev->of_node, &drvdata->csr_name);
+	if (ret) {
+		dev_err(dev, "No csr data\n");
+	} else{
+		drvdata->csr = coresight_csr_get(drvdata->csr_name);
+		if (IS_ERR(drvdata->csr)) {
+			dev_err(dev, "failed to get csr, defer probe\n");
+			return -EPROBE_DEFER;
+		}
+	}
+
 	drvdata->nr_hmux = of_property_count_strings(pdev->dev.of_node,
 						     "reg-names");
 
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index afe9f3d..ba721fd 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2011-2012, 2016-2017, The Linux Foundation.
- * All rights reserved.
+/* Copyright (c) 2011-2012, 2016-2018 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
@@ -73,6 +72,11 @@
 	CS_MODE_PERF,
 };
 
+struct coresight_csr {
+	const char *name;
+	struct list_head link;
+};
+
 /**
  * struct cs_buffer - keep track of a recording session' specifics
  * @cur:	index of the current buffer
@@ -149,18 +153,24 @@
 #endif
 
 #ifdef CONFIG_CORESIGHT_CSR
-extern void msm_qdss_csr_enable_bam_to_usb(void);
-extern void msm_qdss_csr_disable_bam_to_usb(void);
-extern void msm_qdss_csr_disable_flush(void);
-extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
-extern void coresight_csr_set_byte_cntr(uint32_t count);
+extern void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr);
+extern void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr);
+extern void msm_qdss_csr_disable_flush(struct coresight_csr *csr);
+extern int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
+				 uint32_t val);
+extern void coresight_csr_set_byte_cntr(struct coresight_csr *csr,
+				 uint32_t count);
+extern struct coresight_csr *coresight_csr_get(const char *name);
 #else
-static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
-static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
-static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(uint64_t addr,
-					   uint32_t val) { return -EINVAL; }
-static inline void coresight_csr_set_byte_cntr(uint32_t count) {}
+static inline void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr) {}
+static inline void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr) {}
+static inline void msm_qdss_csr_disable_flush(struct coresight_csr *csr) {}
+static inline int coresight_csr_hwctrl_set(struct coresight_csr *csr,
+	uint64_t addr, uint32_t val) { return -EINVAL; }
+static inline void coresight_csr_set_byte_cntr(struct coresight_csr *csr,
+					   uint32_t count) {}
+static inline struct coresight_csr *coresight_csr_get(const char *name)
+					{ return NULL; }
 #endif
 
 #endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index eb70e7a..dcdc3f2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  * Copyright(C) 2016 Linaro Limited. All rights reserved.
  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
  *
@@ -579,7 +579,7 @@
 		return;
 
 	/* Configure and enable required CSR registers */
-	msm_qdss_csr_enable_bam_to_usb();
+	msm_qdss_csr_enable_bam_to_usb(drvdata->csr);
 
 	/* Configure and enable ETR for usb bam output */
 
@@ -675,7 +675,7 @@
 		return;
 
 	/* Ensure periodic flush is disabled in CSR block */
-	msm_qdss_csr_disable_flush();
+	msm_qdss_csr_disable_flush(drvdata->csr);
 
 	CS_UNLOCK(drvdata->base);
 
@@ -685,7 +685,7 @@
 	CS_LOCK(drvdata);
 
 	/* Disable CSR configuration */
-	msm_qdss_csr_disable_bam_to_usb();
+	msm_qdss_csr_disable_bam_to_usb(drvdata->csr);
 	drvdata->enable_to_bam = false;
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 6f13eb3..6597fd6 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
  *
  * Description: CoreSight Trace Memory Controller driver
  *
@@ -487,8 +487,13 @@
 	if (!drvdata->byte_cntr)
 		return -EINVAL;
 
+	if (val && val < 16) {
+		pr_err("Assign minimum block size of 16 bytes\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&drvdata->byte_cntr->byte_cntr_lock);
-	drvdata->byte_cntr->block_size = val * 8;
+	drvdata->byte_cntr->block_size = val;
 	mutex_unlock(&drvdata->byte_cntr->byte_cntr_lock);
 
 	return size;
@@ -611,6 +616,17 @@
 			dev_err(dev, "failed to get reset cti\n");
 	}
 
+	ret = of_get_coresight_csr_name(adev->dev.of_node, &drvdata->csr_name);
+	if (ret) {
+		dev_err(dev, "No csr data\n");
+	} else{
+		drvdata->csr = coresight_csr_get(drvdata->csr_name);
+		if (IS_ERR(drvdata->csr)) {
+			dev_err(dev, "failed to get csr, defer probe\n");
+			return -EPROBE_DEFER;
+		}
+	}
+
 	desc.pdata = pdata;
 	desc.dev = dev;
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index fe6bc76..36117ec 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -189,6 +189,8 @@
 	bool			sticky_enable;
 	struct coresight_cti	*cti_flush;
 	struct coresight_cti	*cti_reset;
+	struct coresight_csr	*csr;
+	const char		*csr_name;
 	struct byte_cntr	*byte_cntr;
 };
 
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index 5473fcf..be810fe 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2018, 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
@@ -238,3 +238,21 @@
 	return ctidata;
 }
 EXPORT_SYMBOL(of_get_coresight_cti_data);
+
+int of_get_coresight_csr_name(struct device_node *node, const char **csr_name)
+{
+	int  ret;
+	struct device_node *csr_node;
+
+	csr_node = of_parse_phandle(node, "coresight-csr", 0);
+	if (!csr_node)
+		return -EINVAL;
+
+	ret = of_property_read_string(csr_node, "coresight-name", csr_name);
+	of_node_put(csr_node);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(of_get_coresight_csr_name);
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index 4daed7f..ad77697 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1274,10 +1274,10 @@
 						tx->dir,
 						(SPS_IOVEC_FLAG_EOT |
 							SPS_IOVEC_FLAG_NWD));
-	if (dma_desc_tx < 0) {
+	if (IS_ERR_OR_NULL(dma_desc_tx)) {
 		dev_err(ctrl->dev, "error dmaengine_prep_slave_sg tx:%ld\n",
 							PTR_ERR(dma_desc_tx));
-		ret = PTR_ERR(dma_desc_tx);
+		ret = dma_desc_tx ? PTR_ERR(dma_desc_tx) : -ENOMEM;
 		goto dma_xfer_end;
 	}
 
@@ -1292,11 +1292,11 @@
 					sg_rx_itr - sg_rx, rx->dir,
 					(SPS_IOVEC_FLAG_EOT |
 							SPS_IOVEC_FLAG_NWD));
-	if (dma_desc_rx < 0) {
+	if (IS_ERR_OR_NULL(dma_desc_rx)) {
 		dev_err(ctrl->dev,
 			"error dmaengine_prep_slave_sg rx:%ld\n",
 						PTR_ERR(dma_desc_rx));
-		ret = PTR_ERR(dma_desc_rx);
+		ret = dma_desc_rx ? PTR_ERR(dma_desc_rx) : -ENOMEM;
 		goto dma_xfer_end;
 	}
 
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index a2120ff..5e29fbd 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -2575,6 +2575,18 @@
 	return ret;
 }
 
+static u8 mlx5_get_umr_fence(u8 umr_fence_cap)
+{
+	switch (umr_fence_cap) {
+	case MLX5_CAP_UMR_FENCE_NONE:
+		return MLX5_FENCE_MODE_NONE;
+	case MLX5_CAP_UMR_FENCE_SMALL:
+		return MLX5_FENCE_MODE_INITIATOR_SMALL;
+	default:
+		return MLX5_FENCE_MODE_STRONG_ORDERING;
+	}
+}
+
 static int create_dev_resources(struct mlx5_ib_resources *devr)
 {
 	struct ib_srq_init_attr attr;
@@ -3101,6 +3113,8 @@
 
 	mlx5_ib_internal_fill_odp_caps(dev);
 
+	dev->umr_fence = mlx5_get_umr_fence(MLX5_CAP_GEN(mdev, umr_fence));
+
 	if (MLX5_CAP_GEN(mdev, imaicl)) {
 		dev->ib_dev.alloc_mw		= mlx5_ib_alloc_mw;
 		dev->ib_dev.dealloc_mw		= mlx5_ib_dealloc_mw;
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 86e1e081..d5cc954 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -345,7 +345,7 @@
 	struct mlx5_ib_wq	rq;
 
 	u8			sq_signal_bits;
-	u8			fm_cache;
+	u8			next_fence;
 	struct mlx5_ib_wq	sq;
 
 	/* serialize qp state modifications
@@ -643,6 +643,7 @@
 	struct list_head	qp_list;
 	/* Array with num_ports elements */
 	struct mlx5_ib_port	*port;
+	u8			umr_fence;
 };
 
 static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 2665414..fdd1561 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -3755,24 +3755,6 @@
 	}
 }
 
-static u8 get_fence(u8 fence, struct ib_send_wr *wr)
-{
-	if (unlikely(wr->opcode == IB_WR_LOCAL_INV &&
-		     wr->send_flags & IB_SEND_FENCE))
-		return MLX5_FENCE_MODE_STRONG_ORDERING;
-
-	if (unlikely(fence)) {
-		if (wr->send_flags & IB_SEND_FENCE)
-			return MLX5_FENCE_MODE_SMALL_AND_FENCE;
-		else
-			return fence;
-	} else if (unlikely(wr->send_flags & IB_SEND_FENCE)) {
-		return MLX5_FENCE_MODE_FENCE;
-	}
-
-	return 0;
-}
-
 static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
 		     struct mlx5_wqe_ctrl_seg **ctrl,
 		     struct ib_send_wr *wr, unsigned *idx,
@@ -3801,8 +3783,7 @@
 static void finish_wqe(struct mlx5_ib_qp *qp,
 		       struct mlx5_wqe_ctrl_seg *ctrl,
 		       u8 size, unsigned idx, u64 wr_id,
-		       int nreq, u8 fence, u8 next_fence,
-		       u32 mlx5_opcode)
+		       int nreq, u8 fence, u32 mlx5_opcode)
 {
 	u8 opmod = 0;
 
@@ -3810,7 +3791,6 @@
 					     mlx5_opcode | ((u32)opmod << 24));
 	ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8));
 	ctrl->fm_ce_se |= fence;
-	qp->fm_cache = next_fence;
 	if (unlikely(qp->wq_sig))
 		ctrl->signature = wq_sig(ctrl);
 
@@ -3870,7 +3850,6 @@
 			goto out;
 		}
 
-		fence = qp->fm_cache;
 		num_sge = wr->num_sge;
 		if (unlikely(num_sge > qp->sq.max_gs)) {
 			mlx5_ib_warn(dev, "\n");
@@ -3887,6 +3866,19 @@
 			goto out;
 		}
 
+		if (wr->opcode == IB_WR_LOCAL_INV ||
+		    wr->opcode == IB_WR_REG_MR) {
+			fence = dev->umr_fence;
+			next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+		} else if (wr->send_flags & IB_SEND_FENCE) {
+			if (qp->next_fence)
+				fence = MLX5_FENCE_MODE_SMALL_AND_FENCE;
+			else
+				fence = MLX5_FENCE_MODE_FENCE;
+		} else {
+			fence = qp->next_fence;
+		}
+
 		switch (ibqp->qp_type) {
 		case IB_QPT_XRC_INI:
 			xrc = seg;
@@ -3913,7 +3905,6 @@
 				goto out;
 
 			case IB_WR_LOCAL_INV:
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
 				ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
 				set_linv_wr(qp, &seg, &size);
@@ -3921,7 +3912,6 @@
 				break;
 
 			case IB_WR_REG_MR:
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				qp->sq.wr_data[idx] = IB_WR_REG_MR;
 				ctrl->imm = cpu_to_be32(reg_wr(wr)->key);
 				err = set_reg_wr(qp, reg_wr(wr), &seg, &size);
@@ -3944,9 +3934,8 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_UMR);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_UMR);
 				/*
 				 * SET_PSV WQEs are not signaled and solicited
 				 * on error
@@ -3971,9 +3960,8 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_SET_PSV);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_SET_PSV);
 				err = begin_wqe(qp, &seg, &ctrl, wr,
 						&idx, &size, nreq);
 				if (err) {
@@ -3983,7 +3971,6 @@
 					goto out;
 				}
 
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->wire,
 						 mr->sig->psv_wire.psv_idx, &seg,
 						 &size);
@@ -3993,9 +3980,9 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_SET_PSV);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_SET_PSV);
+				qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				num_sge = 0;
 				goto skip_psv;
 
@@ -4100,8 +4087,8 @@
 			}
 		}
 
-		finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
-			   get_fence(fence, wr), next_fence,
+		qp->next_fence = next_fence;
+		finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq, fence,
 			   mlx5_ib_opcode[wr->opcode]);
 skip_psv:
 		if (0)
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 39d2837..0983470 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -747,6 +747,7 @@
 {
 	struct isert_conn *isert_conn = cma_id->qp->qp_context;
 
+	ib_drain_qp(isert_conn->qp);
 	list_del_init(&isert_conn->node);
 	isert_conn->cm_id = NULL;
 	isert_put_conn(isert_conn);
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 90493b1..e11dc07 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -1,5 +1,5 @@
 
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,9 @@
 #include <linux/delay.h>
 #include <linux/completion.h>
 
+#ifdef CONFIG_DRM
 #include <linux/msm_drm_notify.h>
+#endif
 
 #define HBTP_INPUT_NAME			"hbtp_input"
 #define DISP_COORDS_SIZE		2
@@ -39,6 +41,7 @@
 #define HBTP_HOLD_DURATION_US			(10)
 #define HBTP_PINCTRL_DDIC_SEQ_NUM		(4)
 #define HBTP_WAIT_TIMEOUT_MS			2000
+#define MSC_HBTP_ACTIVE_BLOB			0x05
 
 struct hbtp_data {
 	struct platform_device *pdev;
@@ -86,16 +89,19 @@
 	u32 power_on_delay;
 	u32 power_off_delay;
 	bool manage_pin_ctrl;
+	bool init_completion_done_once;
 	struct kobject *sysfs_kobject;
 	s16 ROI[MAX_ROI_SIZE];
 	s16 accelBuffer[MAX_ACCEL_SIZE];
 	u32 display_status;
+	u32 touch_flag;
 };
 
 static struct hbtp_data *hbtp;
 
 static struct kobject *sensor_kobject;
 
+#ifdef CONFIG_DRM
 static int hbtp_dsi_panel_suspend(struct hbtp_data *ts);
 static int hbtp_dsi_panel_early_resume(struct hbtp_data *ts);
 
@@ -141,6 +147,7 @@
 	}
 	return 0;
 }
+#endif
 
 static ssize_t hbtp_sensor_roi_show(struct file *dev, struct kobject *kobj,
 		struct bin_attribute *attr, char *buf, loff_t pos,
@@ -233,6 +240,9 @@
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
+	/* for Blob touch interference feature */
+	input_set_capability(input_dev, EV_MSC, MSC_HBTP_ACTIVE_BLOB);
+
 	for (i = KEY_HOME; i <= KEY_MICMUTE; i++)
 		__set_bit(i, input_dev->keybit);
 
@@ -272,10 +282,12 @@
 }
 
 static int hbtp_input_report_events(struct hbtp_data *hbtp_data,
-				struct hbtp_input_mt *mt_data)
+				struct hbtp_input_mt *mt_data, u32 flag)
 {
 	int i;
 	struct hbtp_input_touch *tch;
+	u32 flag_change;
+	bool active_blob;
 
 	for (i = 0; i < HBTP_MAX_FINGER; i++) {
 		tch = &(mt_data->touches[i]);
@@ -330,10 +342,19 @@
 			hbtp_data->touch_status[i] = tch->active;
 		}
 	}
+	flag_change = hbtp_data->touch_flag ^ flag;
+	if (flag_change) {
+		if (flag_change & HBTP_FLAG_ACTIVE_BLOB) {
+			active_blob = (flag & HBTP_FLAG_ACTIVE_BLOB) ?
+				true : false;
 
+			input_event(hbtp_data->input_dev, EV_MSC,
+				MSC_HBTP_ACTIVE_BLOB, active_blob);
+		}
+	}
 	input_report_key(hbtp->input_dev, BTN_TOUCH, mt_data->num_touches > 0);
 	input_sync(hbtp->input_dev);
-
+	hbtp_data->touch_flag = flag;
 	return 0;
 }
 
@@ -594,6 +615,7 @@
 {
 	int error = 0;
 	struct hbtp_input_mt mt_data;
+	struct hbtp_input_mt_ext mt_data_ext;
 	struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1];
 	struct hbtp_input_key key_data;
 	enum hbtp_afe_power_cmd power_cmd;
@@ -635,7 +657,26 @@
 			return -EFAULT;
 		}
 
-		hbtp_input_report_events(hbtp, &mt_data);
+		hbtp_input_report_events(hbtp, &mt_data, 0);
+		error = 0;
+		break;
+
+	case HBTP_SET_TOUCHDATA_EXT:
+		if (!hbtp || !hbtp->input_dev) {
+			pr_err("%s: The input device hasn't been created\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		if (copy_from_user(&mt_data_ext, (void __user *)arg,
+					sizeof(struct hbtp_input_mt_ext))) {
+			pr_err("%s: Error copying data\n", __func__);
+			return -EFAULT;
+		}
+
+		hbtp_input_report_events(hbtp,
+			(struct hbtp_input_mt *)&mt_data_ext,
+			mt_data_ext.flag);
 		error = 0;
 		break;
 
@@ -783,8 +824,14 @@
 				return -EFAULT;
 			}
 			mutex_lock(&hbtp->mutex);
-			init_completion(&hbtp->power_resume_sig);
-			init_completion(&hbtp->power_suspend_sig);
+			if (hbtp->init_completion_done_once) {
+				reinit_completion(&hbtp->power_resume_sig);
+				reinit_completion(&hbtp->power_suspend_sig);
+			} else {
+				init_completion(&hbtp->power_resume_sig);
+				init_completion(&hbtp->power_suspend_sig);
+				hbtp->init_completion_done_once = true;
+			}
 			hbtp->power_sig_enabled = true;
 			mutex_unlock(&hbtp->mutex);
 			pr_err("%s: sync_signal option is enabled\n", __func__);
@@ -1163,6 +1210,7 @@
 	return rc;
 }
 
+#ifdef CONFIG_DRM
 static int hbtp_dsi_panel_suspend(struct hbtp_data *ts)
 {
 	int rc;
@@ -1276,6 +1324,7 @@
 	hbtp_pdev_power_on(ts, false);
 	return rc;
 }
+#endif
 
 static int hbtp_pdev_probe(struct platform_device *pdev)
 {
@@ -1438,6 +1487,25 @@
 		__ATTR(display_pwr, 0660, hbtp_display_pwr_show,
 			hbtp_display_pwr_store);
 
+#ifdef CONFIG_DRM
+static int hbtp_drm_register(struct hbtp_data *ts)
+{
+	int ret = 0;
+
+	ts->dsi_panel_notif.notifier_call = dsi_panel_notifier_callback;
+	ret = msm_drm_register_client(&ts->dsi_panel_notif);
+	if (ret)
+		pr_err("%s: Unable to register dsi_panel_notifier: %d\n",
+			HBTP_INPUT_NAME, ret);
+
+	return ret;
+}
+#else
+static int hbtp_drm_register(struct hbtp_data *ts)
+{
+	return 0;
+}
+#endif
 
 static int __init hbtp_init(void)
 {
@@ -1455,6 +1523,7 @@
 	mutex_init(&hbtp->mutex);
 	mutex_init(&hbtp->sensormutex);
 	hbtp->display_status = 1;
+	hbtp->init_completion_done_once = false;
 
 	error = misc_register(&hbtp_input_misc);
 	if (error) {
@@ -1462,13 +1531,9 @@
 		goto err_misc_reg;
 	}
 
-	hbtp->dsi_panel_notif.notifier_call = dsi_panel_notifier_callback;
-	error = msm_drm_register_client(&hbtp->dsi_panel_notif);
-	if (error) {
-		pr_err("%s: Unable to register dsi_panel_notifier: %d\n",
-			HBTP_INPUT_NAME, error);
-		goto err_dsi_panel_reg;
-	}
+	error = hbtp_drm_register(hbtp);
+	if (error)
+		goto err_drm_reg;
 
 	sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj);
 	if (!sensor_kobject) {
@@ -1517,8 +1582,10 @@
 err_sysfs_create_capdata:
 	kobject_put(sensor_kobject);
 err_kobject_create:
+#ifdef CONFIG_DRM
 	msm_drm_unregister_client(&hbtp->dsi_panel_notif);
-err_dsi_panel_reg:
+#endif
+err_drm_reg:
 	misc_deregister(&hbtp_input_misc);
 err_misc_reg:
 	kfree(hbtp->sensor_data);
@@ -1539,8 +1606,9 @@
 	if (hbtp->input_dev)
 		input_unregister_device(hbtp->input_dev);
 
+#ifdef CONFIG_DRM
 	msm_drm_unregister_client(&hbtp->dsi_panel_notif);
-
+#endif
 	platform_driver_unregister(&hbtp_pdev_driver);
 
 	kfree(hbtp->sensor_data);
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index caa5a62..15929d8 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -178,12 +178,14 @@
 			 twl4030_vibra_suspend, twl4030_vibra_resume);
 
 static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
-			      struct device_node *node)
+			      struct device_node *parent)
 {
+	struct device_node *node;
+
 	if (pdata && pdata->coexist)
 		return true;
 
-	node = of_find_node_by_name(node, "codec");
+	node = of_get_child_by_name(parent, "codec");
 	if (node) {
 		of_node_put(node);
 		return true;
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 5690eb7..15e0d35 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -248,8 +248,7 @@
 	int vddvibr_uV = 0;
 	int error;
 
-	of_node_get(twl6040_core_dev->of_node);
-	twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
+	twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node,
 						 "vibra");
 	if (!twl6040_core_node) {
 		dev_err(&pdev->dev, "parent of node is missing?\n");
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index f26807c..af83d2e 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1247,29 +1247,32 @@
 	case SS4_PACKET_ID_MULTI:
 		if (priv->flags & ALPS_BUTTONPAD) {
 			if (IS_SS4PLUS_DEV(priv->dev_id)) {
-				f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+				no_data_x = SS4_PLUS_MFPACKET_NO_AX_BL;
 			} else {
 				f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
 				f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
+				no_data_x = SS4_MFPACKET_NO_AX_BL;
 			}
+			no_data_y = SS4_MFPACKET_NO_AY_BL;
 
 			f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
 			f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
-			no_data_x = SS4_MFPACKET_NO_AX_BL;
-			no_data_y = SS4_MFPACKET_NO_AY_BL;
 		} else {
 			if (IS_SS4PLUS_DEV(priv->dev_id)) {
-				f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+				no_data_x = SS4_PLUS_MFPACKET_NO_AX;
 			} else {
-				f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
+				no_data_x = SS4_MFPACKET_NO_AX;
 			}
+			no_data_y = SS4_MFPACKET_NO_AY;
+
 			f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
 			f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
-			no_data_x = SS4_MFPACKET_NO_AX;
-			no_data_y = SS4_MFPACKET_NO_AY;
 		}
 
 		f->first_mp = 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 7931237..9bc2bab 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -120,10 +120,12 @@
 #define SS4_IS_5F_DETECTED(_b)	((_b[2] & 0x10) == 0x10)
 
 
-#define SS4_MFPACKET_NO_AX	8160	/* X-Coordinate value */
-#define SS4_MFPACKET_NO_AY	4080	/* Y-Coordinate value */
-#define SS4_MFPACKET_NO_AX_BL	8176	/* Buttonless X-Coordinate value */
-#define SS4_MFPACKET_NO_AY_BL	4088	/* Buttonless Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX		8160	/* X-Coordinate value */
+#define SS4_MFPACKET_NO_AY		4080	/* Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX_BL		8176	/* Buttonless X-Coord value */
+#define SS4_MFPACKET_NO_AY_BL		4088	/* Buttonless Y-Coord value */
+#define SS4_PLUS_MFPACKET_NO_AX		4080	/* SS4 PLUS, X */
+#define SS4_PLUS_MFPACKET_NO_AX_BL	4088	/* Buttonless SS4 PLUS, X */
 
 /*
  * enum V7_PACKET_ID - defines the packet type for V7
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 7e2dc5e..0b49f29 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -383,6 +383,9 @@
 	if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
 		psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n");
 		button_info = 0x33;
+	} else if (!button_info) {
+		psmouse_warn(psmouse, "got 0 in extended button data, assuming 3 buttons\n");
+		button_info = 0x33;
 	}
 
 	psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 251ff2a..7a0dbce 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -126,7 +126,7 @@
 	int data, n, ret;
 	if (!np)
 		return -ENODEV;
-	np = of_find_node_by_name(np, "touch");
+	np = of_get_child_by_name(np, "touch");
 	if (!np) {
 		dev_err(&pdev->dev, "Can't find touch node\n");
 		return -EINVAL;
@@ -144,13 +144,13 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set tsi prebias time */
 	if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set prebias & prechg time of pen detect */
 	data = 0;
@@ -161,10 +161,18 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
+
+	of_node_put(np);
+
 	return 0;
+
+err_put_node:
+	of_node_put(np);
+
+	return -EINVAL;
 }
 #else
 #define pm860x_touch_dt_init(x, y, z)	(-1)
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
index b2fa115..b54e792 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig
@@ -59,6 +59,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_dsx_fw_update.
 
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
+	bool "Synaptics DSX firmware update sysfs attributes"
+	depends on TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
+	help
+	  Say Y here to enable support for sysfs attributes for
+	  performing firmware update in a development environment.
+	  This does not affect the core or other subsystem attributes.
+
+	  If unsure, say N.
+
 config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING
 	tristate "Synaptics DSX test reporting module"
 	depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 7f62e01..395def9 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -137,6 +137,7 @@
 
 static int fwu_recovery_check_status(void);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count);
@@ -201,6 +202,8 @@
 		struct device_attribute *attr, char *buf);
 #endif
 
+#endif
+
 enum f34_version {
 	F34_V0 = 0,
 	F34_V1,
@@ -757,6 +760,7 @@
 	struct work_struct fwu_work;
 };
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static struct bin_attribute dev_attr_data = {
 	.attr = {
 		.name = "data",
@@ -766,8 +770,10 @@
 	.read = fwu_sysfs_show_image,
 	.write = fwu_sysfs_store_image,
 };
+#endif
 
 static struct device_attribute attrs[] = {
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	__ATTR(dorecovery, 0220,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_do_recovery_store),
@@ -821,13 +827,16 @@
 			fwu_sysfs_read_lockdown_code_show,
 			fwu_sysfs_write_lockdown_code_store),
 #endif
+#endif
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
 
 DECLARE_COMPLETION(fwu_remove_complete);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 DEFINE_MUTEX(fwu_sysfs_mutex);
+#endif
 
 static void calculate_checksum(unsigned short *data, unsigned long len,
 		unsigned long *result)
@@ -3061,6 +3070,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_check_pm_configuration_size(void)
 {
 	unsigned short block_count;
@@ -3077,6 +3087,7 @@
 
 	return 0;
 }
+#endif
 
 static int fwu_check_bl_configuration_size(void)
 {
@@ -3444,6 +3455,7 @@
 	return fwu_write_configuration();
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_write_pm_configuration(void)
 {
 	fwu->config_area = PM_CONFIG_AREA;
@@ -3469,6 +3481,7 @@
 	return 0;
 }
 #endif
+#endif
 
 static int fwu_write_flash_configuration(void)
 {
@@ -3757,6 +3770,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -3984,6 +3998,7 @@
 	return retval;
 }
 #endif
+#endif
 
 static int fwu_do_lockdown_v7(void)
 {
@@ -4134,6 +4149,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_start_write_guest_code(void)
 {
 	int retval;
@@ -4339,6 +4355,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_start_reflash(void)
 {
@@ -4970,6 +4987,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count)
@@ -5566,6 +5584,7 @@
 	return count;
 }
 #endif
+#endif
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
 {
@@ -5668,6 +5687,7 @@
 	if (ENABLE_SYS_REFLASH == false)
 		return 0;
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
 			&dev_attr_data);
 	if (retval < 0) {
@@ -5676,6 +5696,7 @@
 				__func__);
 		goto exit_free_mem;
 	}
+#endif
 
 	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
 		retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
@@ -5697,7 +5718,9 @@
 				&attrs[attr_count].attr);
 	}
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
 
 exit_free_mem:
 	kfree(fwu->image_name);
@@ -5739,7 +5762,9 @@
 				&attrs[attr_count].attr);
 	}
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
 
 exit:
 	complete(&fwu_remove_complete);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
index 8776d4a..7725cd3 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
@@ -402,11 +402,11 @@
 	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
 	struct i2c_msg msg[2];
 
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+
 	retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
 	if (retval < 0)
-		return retval;
-
-	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+		goto exit;
 
 	retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
 	if (retval != PAGE_SELECT_LEN) {
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
index 61cf979..331274e 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
@@ -567,16 +567,22 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto clean_up;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto clean_up;
+	}
 	address = (unsigned short)(*f_pos);
 
-	mutex_lock(&(dev_data->file_mutex));
-
 	rmidev_allocate_buffer(count);
 
 	retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
@@ -638,18 +644,26 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto unlock;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
-	mutex_lock(&(dev_data->file_mutex));
-
+	if (count == 0) {
+		retval = 0;
+		goto unlock;
+	}
 	rmidev_allocate_buffer(count);
 
-	if (copy_from_user(rmidev->tmpbuf, buf, count))
+	if (copy_from_user(rmidev->tmpbuf, buf, count)) {
 		return -EFAULT;
+		goto unlock;
+	}
 
 	retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
 			*f_pos,
@@ -658,6 +672,7 @@
 	if (retval >= 0)
 		*f_pos += retval;
 
+unlock:
 	mutex_unlock(&(dev_data->file_mutex));
 
 	return retval;
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
index 78b995e..5389628 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
@@ -114,4 +114,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_dsx_video.
 
+config SECURE_TOUCH_SYNAPTICS_DSX_V26
+	bool "Secure Touch support for Synaptics V2.6 Touchscreen"
+	depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
+	help
+	  Say Y here
+	  -Synaptics DSX V2.6 touch driver is connected
+	  -To enable secure touch for Synaptics DSX V2.6 touch driver
+
+	  If unsure, say N.
+
 endif
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
index b2f3bf5..7633767 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -117,11 +118,11 @@
 static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
 		bool *was_in_bl_mode);
 static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
-static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data);
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
 		bool rebuild);
 
 #ifdef CONFIG_FB
+static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work);
 static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
 		unsigned long event, void *data);
 #endif
@@ -172,6 +173,19 @@
 static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf);
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+#endif
+
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
+
 struct synaptics_rmi4_f01_device_status {
 	union {
 		struct {
@@ -597,26 +611,34 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(reset, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			synaptics_rmi4_f01_reset_store),
 	__ATTR(productinfo, 0444,
 			synaptics_rmi4_f01_productinfo_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(buildid, 0444,
 			synaptics_rmi4_f01_buildid_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(flashprog, 0444,
 			synaptics_rmi4_f01_flashprog_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(0dbutton, 0664,
 			synaptics_rmi4_0dbutton_show,
 			synaptics_rmi4_0dbutton_store),
 	__ATTR(suspend, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			synaptics_rmi4_suspend_store),
 	__ATTR(wake_gesture, 0664,
 			synaptics_rmi4_wake_gesture_show,
 			synaptics_rmi4_wake_gesture_store),
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	__ATTR(secure_touch_enable, 0664,
+			synaptics_rmi4_secure_touch_enable_show,
+			synaptics_rmi4_secure_touch_enable_store),
+	__ATTR(secure_touch, 0444,
+			synaptics_rmi4_secure_touch_show,
+			NULL),
+#endif
 };
 
 static struct kobj_attribute virtual_key_map_attr = {
@@ -627,6 +649,205 @@
 	.show = synaptics_rmi4_virtual_key_map_show,
 };
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
+{
+	data->st_initialized = 0;
+	init_completion(&data->st_powerdown);
+	init_completion(&data->st_irq_processed);
+
+	/* Get clocks */
+	data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk");
+	if (IS_ERR(data->core_clk)) {
+		dev_warn(data->pdev->dev.parent,
+			"%s: error on clk_get(core_clk): %ld\n", __func__,
+			PTR_ERR(data->core_clk));
+		data->core_clk = NULL;
+	}
+
+	data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk");
+	if (IS_ERR(data->iface_clk)) {
+		dev_warn(data->pdev->dev.parent,
+			"%s: error on clk_get(iface_clk): %ld\n", __func__,
+			PTR_ERR(data->iface_clk));
+		data->iface_clk = NULL;
+	}
+
+	data->st_initialized = 1;
+}
+
+static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data)
+{
+	sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch");
+}
+
+static irqreturn_t synaptics_filter_interrupt(
+	struct synaptics_rmi4_data *rmi4_data)
+{
+	if (atomic_read(&rmi4_data->st_enabled)) {
+		if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) {
+			reinit_completion(&rmi4_data->st_irq_processed);
+			synaptics_secure_touch_notify(rmi4_data);
+			wait_for_completion_interruptible(
+				&rmi4_data->st_irq_processed);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/*
+ * 'blocking' variable will have value 'true' when we want to prevent the driver
+ * from accessing the xPU/SMMU protected HW resources while the session is
+ * active.
+ */
+static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
+					bool blocking)
+{
+	if (atomic_read(&rmi4_data->st_enabled)) {
+		atomic_set(&rmi4_data->st_pending_irqs, -1);
+		synaptics_secure_touch_notify(rmi4_data);
+		if (blocking)
+			wait_for_completion_interruptible(
+				&rmi4_data->st_powerdown);
+	}
+}
+
+#else
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data)
+{
+}
+
+static irqreturn_t synaptics_filter_interrupt(
+				struct synaptics_rmi4_data *rmi4_data)
+{
+	return IRQ_NONE;
+}
+
+static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
+					bool blocking)
+{
+}
+#endif
+
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			atomic_read(&rmi4_data->st_enabled));
+}
+/*
+ * Accept only "0" and "1" valid values.
+ * "0" will reset the st_enabled flag, then wake up the reading process and
+ * the interrupt handler.
+ * The bus driver is notified via pm_runtime that it is not required to stay
+ * awake anymore.
+ * It will also make sure the queue of events is emptied in the controller,
+ * in case a touch happened in between the secure touch being disabled and
+ * the local ISR being ungated.
+ * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
+ * The bus driver is requested via pm_runtime to stay awake.
+ */
+static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	unsigned long value;
+	int err = 0;
+
+	if (count > 2)
+		return -EINVAL;
+
+	err = kstrtoul(buf, 10, &value);
+	if (err != 0)
+		return err;
+
+	if (!rmi4_data->st_initialized)
+		return -EIO;
+
+	err = count;
+
+	switch (value) {
+	case 0:
+		if (atomic_read(&rmi4_data->st_enabled) == 0)
+			break;
+
+		synaptics_rmi4_bus_put(rmi4_data);
+		atomic_set(&rmi4_data->st_enabled, 0);
+		synaptics_secure_touch_notify(rmi4_data);
+		complete(&rmi4_data->st_irq_processed);
+		synaptics_rmi4_irq(rmi4_data->irq, rmi4_data);
+		complete(&rmi4_data->st_powerdown);
+
+		break;
+	case 1:
+		if (atomic_read(&rmi4_data->st_enabled)) {
+			err = -EBUSY;
+			break;
+		}
+
+		synchronize_irq(rmi4_data->irq);
+
+		if (synaptics_rmi4_bus_get(rmi4_data) < 0) {
+			dev_err(
+				rmi4_data->pdev->dev.parent,
+				"synaptics_rmi4_bus_get failed\n");
+			err = -EIO;
+			break;
+		}
+		reinit_completion(&rmi4_data->st_powerdown);
+		reinit_completion(&rmi4_data->st_irq_processed);
+		atomic_set(&rmi4_data->st_enabled, 1);
+		atomic_set(&rmi4_data->st_pending_irqs,  0);
+		break;
+	default:
+		dev_err(
+			rmi4_data->pdev->dev.parent,
+			"unsupported value: %lu\n", value);
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+/*
+ * This function returns whether there are pending interrupts, or
+ * other error conditions that need to be signaled to the userspace library,
+ * according tot he following logic:
+ * - st_enabled is 0 if secure touch is not enabled, returning -EBADF
+ * - st_pending_irqs is -1 to signal that secure touch is in being stopped,
+ *   returning -EINVAL
+ * - st_pending_irqs is 1 to signal that there is a pending irq, returning
+ *   the value "1" to the sysfs read operation
+ * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
+ *   has been processed, so the interrupt handler can be allowed to continue.
+ */
+static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int val = 0;
+
+	if (atomic_read(&rmi4_data->st_enabled) == 0)
+		return -EBADF;
+
+	if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1)
+		return -EINVAL;
+
+	if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1)
+		val = 1;
+	else
+		complete(&rmi4_data->st_irq_processed);
+
+	return scnprintf(buf, PAGE_SIZE, "%u", val);
+
+}
+#endif
+
 static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
@@ -1173,7 +1394,6 @@
 #ifndef TYPE_B_PROTOCOL
 			input_mt_sync(rmi4_data->input_dev);
 #endif
-			input_sync(rmi4_data->input_dev);
 
 			dev_dbg(rmi4_data->pdev->dev.parent,
 					"%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n",
@@ -1245,7 +1465,6 @@
 #ifndef TYPE_B_PROTOCOL
 		input_mt_sync(rmi4_data->input_dev);
 #endif
-		input_sync(rmi4_data->input_dev);
 
 		if (rmi4_data->stylus_enable) {
 			stylus_presence = 0;
@@ -1261,6 +1480,8 @@
 		}
 	}
 
+	input_sync(rmi4_data->input_dev);
+
 	mutex_unlock(&(rmi4_data->rmi4_report_mutex));
 
 	return touch_count;
@@ -1465,12 +1686,6 @@
 	}
 	if (status.unconfigured && !status.flash_prog) {
 		pr_notice("%s: spontaneous reset detected\n", __func__);
-		retval = synaptics_rmi4_reinit_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(rmi4_data->pdev->dev.parent,
-					"%s: Failed to reinit device\n",
-					__func__);
-		}
 	}
 
 	if (!report)
@@ -1512,6 +1727,9 @@
 	const struct synaptics_dsx_board_data *bdata =
 			rmi4_data->hw_if->board_data;
 
+	if (synaptics_filter_interrupt(data) == IRQ_HANDLED)
+		return IRQ_HANDLED;
+
 	if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state)
 		goto exit;
 
@@ -2911,7 +3129,9 @@
 	unsigned char buf[16];
 
 	if (config) {
-		snprintf(buf, PAGE_SIZE, "dsx_gpio_%u\n", gpio);
+		retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio);
+		if (retval >= 16)
+			return -EINVAL;
 
 		retval = gpio_request(gpio, buf);
 		if (retval) {
@@ -3434,49 +3654,6 @@
 	return;
 }
 
-static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
-{
-	int retval;
-	struct synaptics_rmi4_fn *fhandler;
-	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
-	struct synaptics_rmi4_device_info *rmi;
-
-	rmi = &(rmi4_data->rmi4_mod_info);
-
-	mutex_lock(&(rmi4_data->rmi4_reset_mutex));
-
-	synaptics_rmi4_free_fingers(rmi4_data);
-
-	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
-			if (fhandler->fn_number == SYNAPTICS_RMI4_F12) {
-				synaptics_rmi4_f12_set_enables(rmi4_data, 0);
-				break;
-			}
-		}
-	}
-
-	retval = synaptics_rmi4_int_enable(rmi4_data, true);
-	if (retval < 0)
-		goto exit;
-
-	mutex_lock(&exp_data.mutex);
-	if (!list_empty(&exp_data.list)) {
-		list_for_each_entry(exp_fhandler, &exp_data.list, link)
-			if (exp_fhandler->exp_fn->reinit != NULL)
-				exp_fhandler->exp_fn->reinit(rmi4_data);
-	}
-	mutex_unlock(&exp_data.mutex);
-
-	synaptics_rmi4_set_configured(rmi4_data);
-
-	retval = 0;
-
-exit:
-	mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
-	return retval;
-}
-
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
 		bool rebuild)
 {
@@ -3688,6 +3865,57 @@
 }
 EXPORT_SYMBOL(synaptics_rmi4_new_function);
 
+static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
+{
+	int retval;
+
+	/* Get pinctrl if target uses pinctrl */
+	rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent));
+	if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
+		retval = PTR_ERR(rmi4_data->ts_pinctrl);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"Target does not use pinctrl %d\n", retval);
+		goto err_pinctrl_get;
+	}
+
+	rmi4_data->pinctrl_state_active
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_active);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_ACTIVE, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	rmi4_data->pinctrl_state_suspend
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
+		dev_dbg(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_SUSPEND, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	rmi4_data->pinctrl_state_release
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_release);
+		dev_dbg(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_RELEASE, retval);
+	}
+
+	return 0;
+
+err_pinctrl_lookup:
+	devm_pinctrl_put(rmi4_data->ts_pinctrl);
+err_pinctrl_get:
+	rmi4_data->ts_pinctrl = NULL;
+	return retval;
+}
+
 static int synaptics_rmi4_probe(struct platform_device *pdev)
 {
 	int retval;
@@ -3757,6 +3985,21 @@
 		goto err_enable_reg;
 	}
 
+	retval = synaptics_dsx_pinctrl_init(rmi4_data);
+	if (!retval && rmi4_data->ts_pinctrl) {
+		/*
+		 * Pinctrl handle is optional. If pinctrl handle is found
+		 * let pins to be configured in active state. If not
+		 * found continue further without error.
+		 */
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_active);
+		if (retval < 0) {
+			dev_err(&pdev->dev,
+				"%s: Failed to select %s pinstate %d\n",
+				__func__, PINCTRL_STATE_ACTIVE, retval);
+		}
+	}
 	retval = synaptics_rmi4_set_gpio(rmi4_data);
 	if (retval < 0) {
 		dev_err(&pdev->dev,
@@ -3784,6 +4027,8 @@
 	}
 
 #ifdef CONFIG_FB
+	INIT_WORK(&rmi4_data->fb_notify_work,
+		  synaptics_rmi4_fb_notify_resume_work);
 	rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb;
 	retval = fb_register_client(&rmi4_data->fb_notifier);
 	if (retval < 0) {
@@ -3849,25 +4094,52 @@
 
 	rmi4_data->rb_workqueue =
 			create_singlethread_workqueue("dsx_rebuild_workqueue");
+	if (!rmi4_data->rb_workqueue) {
+		retval = -ENOMEM;
+		goto err_rb_workqueue;
+	}
 	INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work);
 
 	exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
+	if (!exp_data.workqueue) {
+		retval = -ENOMEM;
+		goto err_exp_data_workqueue;
+	}
 	INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
 	exp_data.rmi4_data = rmi4_data;
 	exp_data.queue_work = true;
-	queue_delayed_work(exp_data.workqueue,
-			&exp_data.work,
-			0);
+	queue_delayed_work(exp_data.workqueue, &exp_data.work, 0);
 
 #ifdef FB_READY_RESET
 	rmi4_data->reset_workqueue =
 			create_singlethread_workqueue("dsx_reset_workqueue");
+	if (!rmi4_data->reset_workqueue) {
+		retval = -ENOMEM;
+		goto err_reset_workqueue;
+	}
 	INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work);
 	queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work);
 #endif
 
+	/* Initialize secure touch */
+	synaptics_secure_touch_init(rmi4_data);
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	return retval;
 
+#ifdef FB_READY_RESET
+err_reset_workqueue:
+#endif
+	cancel_delayed_work_sync(&exp_data.work);
+	flush_workqueue(exp_data.workqueue);
+	destroy_workqueue(exp_data.workqueue);
+
+err_exp_data_workqueue:
+	cancel_delayed_work_sync(&rmi4_data->rb_work);
+	flush_workqueue(rmi4_data->rb_workqueue);
+	destroy_workqueue(rmi4_data->rb_workqueue);
+
+err_rb_workqueue:
 err_sysfs:
 	for (attr_count--; attr_count >= 0; attr_count--) {
 		sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
@@ -3913,6 +4185,21 @@
 err_set_gpio:
 	synaptics_rmi4_enable_reg(rmi4_data, false);
 
+	if (rmi4_data->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+			devm_pinctrl_put(rmi4_data->ts_pinctrl);
+			rmi4_data->ts_pinctrl = NULL;
+		} else {
+			retval = pinctrl_select_state(
+			rmi4_data->ts_pinctrl,
+			rmi4_data->pinctrl_state_release);
+			if (retval)
+				dev_err(&pdev->dev,
+					"%s: Failed to create sysfs attributes\n",
+					__func__);
+		}
+	}
+
 err_enable_reg:
 	synaptics_rmi4_get_reg(rmi4_data, false);
 
@@ -3925,6 +4212,7 @@
 static int synaptics_rmi4_remove(struct platform_device *pdev)
 {
 	unsigned char attr_count;
+	int err;
 	struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev);
 	const struct synaptics_dsx_board_data *bdata =
 			rmi4_data->hw_if->board_data;
@@ -3980,6 +4268,22 @@
 	if (bdata->power_gpio >= 0)
 		synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0);
 
+
+	if (rmi4_data->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+			devm_pinctrl_put(rmi4_data->ts_pinctrl);
+			rmi4_data->ts_pinctrl = NULL;
+		} else {
+			err = pinctrl_select_state(
+			rmi4_data->ts_pinctrl,
+			rmi4_data->pinctrl_state_release);
+			if (err)
+				dev_err(&pdev->dev,
+					"Failed to select release pinctrl state %d\n",
+					err);
+		}
+	}
+
 	synaptics_rmi4_enable_reg(rmi4_data, false);
 	synaptics_rmi4_get_reg(rmi4_data, false);
 
@@ -4096,6 +4400,14 @@
 }
 
 #ifdef CONFIG_FB
+static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work)
+{
+	struct synaptics_rmi4_data *rmi4_data =
+		container_of(work, struct synaptics_rmi4_data, fb_notify_work);
+	synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+	rmi4_data->fb_ready = true;
+}
+
 static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
 		unsigned long event, void *data)
 {
@@ -4106,14 +4418,36 @@
 			fb_notifier);
 
 	if (evdata && evdata->data && rmi4_data) {
-		if (event == FB_EVENT_BLANK) {
-			transition = evdata->data;
-			if (*transition == FB_BLANK_POWERDOWN) {
-				synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
-				rmi4_data->fb_ready = false;
-			} else if (*transition == FB_BLANK_UNBLANK) {
-				synaptics_rmi4_resume(&rmi4_data->pdev->dev);
-				rmi4_data->fb_ready = true;
+		if (rmi4_data->hw_if->board_data->resume_in_workqueue) {
+			if (event == FB_EARLY_EVENT_BLANK) {
+				synaptics_secure_touch_stop(rmi4_data, false);
+			} else if (event == FB_EVENT_BLANK) {
+				transition = evdata->data;
+				if (*transition == FB_BLANK_POWERDOWN) {
+					flush_work(
+						&(rmi4_data->fb_notify_work));
+					synaptics_rmi4_suspend(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = false;
+				} else if (*transition == FB_BLANK_UNBLANK) {
+					schedule_work(
+						&(rmi4_data->fb_notify_work));
+				}
+			}
+		} else {
+			if (event == FB_EARLY_EVENT_BLANK) {
+				synaptics_secure_touch_stop(rmi4_data, false);
+			} else if (event == FB_EVENT_BLANK) {
+				transition = evdata->data;
+				if (*transition == FB_BLANK_POWERDOWN) {
+					synaptics_rmi4_suspend(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = false;
+				} else if (*transition == FB_BLANK_UNBLANK) {
+					synaptics_rmi4_resume(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = true;
+				}
 			}
 		}
 	}
@@ -4133,6 +4467,14 @@
 	if (rmi4_data->stay_awake)
 		return;
 
+	/*
+	 * During early suspend/late resume, the driver doesn't access xPU/SMMU
+	 * protected HW resources. So, there is no compelling need to block,
+	 * but notifying the userspace that a power event has occurred is
+	 * enough. Hence 'blocking' variable can be set to false.
+	 */
+	synaptics_secure_touch_stop(rmi4_data, false);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, true);
 		enable_irq_wake(rmi4_data->irq);
@@ -4170,6 +4512,8 @@
 	if (rmi4_data->stay_awake)
 		return;
 
+	synaptics_secure_touch_stop(rmi4_data, false);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, false);
 		disable_irq_wake(rmi4_data->irq);
@@ -4212,10 +4556,13 @@
 {
 	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int retval;
 
 	if (rmi4_data->stay_awake)
 		return 0;
 
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, true);
 		enable_irq_wake(rmi4_data->irq);
@@ -4228,6 +4575,13 @@
 		synaptics_rmi4_free_fingers(rmi4_data);
 	}
 
+	if (rmi4_data->ts_pinctrl) {
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_suspend);
+		if (retval < 0)
+			dev_err(dev, "Cannot get idle pinctrl state\n");
+			goto err_pinctrl;
+	}
 exit:
 	mutex_lock(&exp_data.mutex);
 	if (!list_empty(&exp_data.list)) {
@@ -4237,9 +4591,19 @@
 	}
 	mutex_unlock(&exp_data.mutex);
 
+	if (!rmi4_data->suspend) {
+		synaptics_rmi4_enable_reg(rmi4_data, false);
+		synaptics_rmi4_get_reg(rmi4_data, false);
+	}
 	rmi4_data->suspend = true;
 
 	return 0;
+
+err_pinctrl:
+	synaptics_rmi4_sleep_enable(rmi4_data, false);
+	synaptics_rmi4_irq_enable(rmi4_data, true, false);
+	return retval;
+
 }
 
 static int synaptics_rmi4_resume(struct device *dev)
@@ -4253,6 +4617,8 @@
 	if (rmi4_data->stay_awake)
 		return 0;
 
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, false);
 		disable_irq_wake(rmi4_data->irq);
@@ -4261,8 +4627,19 @@
 
 	rmi4_data->current_page = MASK_8BIT;
 
+	if (rmi4_data->suspend) {
+		synaptics_rmi4_get_reg(rmi4_data, true);
+		synaptics_rmi4_enable_reg(rmi4_data, true);
+	}
+
 	synaptics_rmi4_sleep_enable(rmi4_data, false);
 	synaptics_rmi4_irq_enable(rmi4_data, true, false);
+	if (rmi4_data->ts_pinctrl) {
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_active);
+		if (retval < 0)
+			dev_err(dev, "Cannot get default pinctrl state\n");
+	}
 
 exit:
 #ifdef FB_READY_RESET
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
index 0de0e99..39fec9a 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -48,6 +49,13 @@
 #include <linux/earlysuspend.h>
 #endif
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+#include <linux/completion.h>
+#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#endif
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
 #define KERNEL_ABOVE_2_6_38
 #endif
@@ -115,6 +123,9 @@
 #define MASK_2BIT 0x03
 #define MASK_1BIT 0x01
 
+#define PINCTRL_STATE_ACTIVE    "pmx_ts_active"
+#define PINCTRL_STATE_SUSPEND   "pmx_ts_suspend"
+#define PINCTRL_STATE_RELEASE   "pmx_ts_release"
 enum exp_fn {
 	RMI_DEV = 0,
 	RMI_FW_UPDATER,
@@ -324,6 +335,7 @@
 	struct delayed_work rb_work;
 	struct workqueue_struct *rb_workqueue;
 #ifdef CONFIG_FB
+	struct work_struct fb_notify_work;
 	struct notifier_block fb_notifier;
 	struct work_struct reset_work;
 	struct workqueue_struct *reset_workqueue;
@@ -374,6 +386,19 @@
 			bool enable);
 	void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
 			struct synaptics_rmi4_fn *fhandler);
+	struct pinctrl *ts_pinctrl;
+	struct pinctrl_state *pinctrl_state_active;
+	struct pinctrl_state *pinctrl_state_suspend;
+	struct pinctrl_state *pinctrl_state_release;
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	atomic_t st_enabled;
+	atomic_t st_pending_irqs;
+	struct completion st_powerdown;
+	struct completion st_irq_processed;
+	bool st_initialized;
+	struct clk *core_clk;
+	struct clk *iface_clk;
+#endif
 };
 
 struct synaptics_dsx_bus_access {
@@ -382,6 +407,10 @@
 		unsigned char *data, unsigned short length);
 	int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
 		unsigned char *data, unsigned short length);
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	int (*get)(struct synaptics_rmi4_data *rmi4_data);
+	void (*put)(struct synaptics_rmi4_data *rmi4_data);
+#endif
 };
 
 struct synaptics_dsx_hw_interface {
@@ -432,21 +461,16 @@
 	return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
 }
 
-static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
-		struct device_attribute *attr, char *buf)
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
 {
-	dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
-			__func__, attr->attr.name);
-	return -EPERM;
+	return rmi4_data->hw_if->bus_access->get(rmi4_data);
 }
-
-static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
+static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
 {
-	dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
-			__func__, attr->attr.name);
-	return -EPERM;
+	rmi4_data->hw_if->bus_access->put(rmi4_data);
 }
+#endif
 
 static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
 		const unsigned char *src, unsigned int src_size,
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
index 9fb9beb..344f4c3 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -127,6 +128,7 @@
 
 static int fwu_recovery_check_status(void);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count);
@@ -179,6 +181,7 @@
 
 static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count);
+#endif
 
 enum f34_version {
 	F34_V0 = 0,
@@ -650,6 +653,7 @@
 	struct work_struct fwu_work;
 };
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static struct bin_attribute dev_attr_data = {
 	.attr = {
 		.name = "data",
@@ -659,53 +663,56 @@
 	.read = fwu_sysfs_show_image,
 	.write = fwu_sysfs_store_image,
 };
+#endif
 
 static struct device_attribute attrs[] = {
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	__ATTR(dorecovery, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_do_recovery_store),
 	__ATTR(doreflash, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_do_reflash_store),
 	__ATTR(writeconfig, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_write_config_store),
 	__ATTR(readconfig, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_read_config_store),
 	__ATTR(configarea, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_config_area_store),
 	__ATTR(imagename, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_image_name_store),
 	__ATTR(imagesize, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_image_size_store),
 	__ATTR(blocksize, 0444,
 			fwu_sysfs_block_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(fwblockcount, 0444,
 			fwu_sysfs_firmware_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(configblockcount, 0444,
 			fwu_sysfs_configuration_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(dispconfigblockcount, 0444,
 			fwu_sysfs_disp_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(permconfigblockcount, 0444,
 			fwu_sysfs_perm_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(blconfigblockcount, 0444,
 			fwu_sysfs_bl_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(guestcodeblockcount, 0444,
 			fwu_sysfs_guest_code_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(writeguestcode, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_write_guest_code_store),
+#endif
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
@@ -2218,10 +2225,12 @@
 					__func__);
 			return -ENOMEM;
 		}
-		while (strptr[index] >= '0' && strptr[index] <= '9') {
+		while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
+						&& strptr[index] <= '9') {
 			firmware_id[index] = strptr[index];
 			index++;
 		}
+		firmware_id[index] = '\0';
 
 		retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id);
 		kfree(firmware_id);
@@ -2608,6 +2617,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_check_pm_configuration_size(void)
 {
 	unsigned short block_count;
@@ -2624,6 +2634,7 @@
 
 	return 0;
 }
+#endif
 
 static int fwu_check_bl_configuration_size(void)
 {
@@ -2823,6 +2834,7 @@
 	return fwu_write_configuration();
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_write_pm_configuration(void)
 {
 	fwu->config_area = PM_CONFIG_AREA;
@@ -2832,6 +2844,7 @@
 
 	return fwu_write_configuration();
 }
+#endif
 
 static int fwu_write_flash_configuration(void)
 {
@@ -3039,6 +3052,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -3116,6 +3130,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_do_lockdown_v7(void)
 {
@@ -3190,6 +3205,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_start_write_guest_code(void)
 {
 	int retval;
@@ -3395,6 +3411,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_start_reflash(void)
 {
@@ -3596,6 +3613,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_recovery_erase_all(void)
 {
 	int retval;
@@ -3789,6 +3807,7 @@
 
 	return retval;
 }
+#endif
 
 int synaptics_fw_updater(const unsigned char *fw_data)
 {
@@ -3847,6 +3866,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count)
@@ -4218,6 +4238,7 @@
 	fwu->image = NULL;
 	return retval;
 }
+#endif
 
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
@@ -4231,6 +4252,28 @@
 	return;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
+static int synaptics_create_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	return sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
+			&dev_attr_data);
+}
+
+static void synaptics_remove_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+}
+#else
+static int synaptics_create_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	return 0;
+}
+
+static void synaptics_remove_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+}
+#endif
+
 static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
 {
 	int retval;
@@ -4302,8 +4345,7 @@
 	fwu->do_lockdown = DO_LOCKDOWN;
 	fwu->initialized = true;
 
-	retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
-			&dev_attr_data);
+	retval = synaptics_create_fwu_bin_file(rmi4_data);
 	if (retval < 0) {
 		dev_err(rmi4_data->pdev->dev.parent,
 				"%s: Failed to create sysfs bin file\n",
@@ -4338,7 +4380,7 @@
 				&attrs[attr_count].attr);
 	}
 
-	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	synaptics_remove_fwu_bin_file(rmi4_data);
 
 exit_free_mem:
 	kfree(fwu->image_name);
@@ -4369,7 +4411,7 @@
 				&attrs[attr_count].attr);
 	}
 
-	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	synaptics_remove_fwu_bin_file(rmi4_data);
 
 	kfree(fwu->read_config_buf);
 	kfree(fwu->image_name);
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
index 0bd342c..ae1a55af 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -389,47 +390,47 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(engine_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_engine_enable_store),
 	__ATTR(detection_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_detection_enable_store),
 	__ATTR(detection_score, 0444,
 			udg_sysfs_detection_score_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(detection_index, 0444,
 			udg_sysfs_detection_index_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(registration_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_registration_enable_store),
 	__ATTR(registration_begin, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_registration_begin_store),
 	__ATTR(registration_status, 0444,
 			udg_sysfs_registration_status_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_size, 0444,
 			udg_sysfs_template_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_max_index, 0444,
 			udg_sysfs_template_max_index_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_detection, 0444,
 			udg_sysfs_template_detection_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_index, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_template_index_store),
 	__ATTR(template_valid, 0664,
 			udg_sysfs_template_valid_show,
 			udg_sysfs_template_valid_store),
 	__ATTR(template_clear, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_template_clear_store),
 	__ATTR(trace_size, 0444,
 			udg_sysfs_trace_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 };
 
 static struct bin_attribute template_data = {
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
index 45951a4..df17a0b 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,6 +78,9 @@
 	else
 		bdata->irq_on_state = value;
 
+	bdata->resume_in_workqueue = of_property_read_bool(np,
+			"synaptics,resume-in-workqueue");
+
 	retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
 	if (retval < 0)
 		bdata->pwr_reg_name = NULL;
@@ -432,11 +436,11 @@
 	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
 	struct i2c_msg msg[1];
 
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+
 	retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
 	if (retval < 0)
-		return retval;
-
-	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+		goto exit;
 
 	retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
 	if (retval != PAGE_SELECT_LEN) {
@@ -487,10 +491,73 @@
 	return retval;
 }
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static int synaptics_rmi4_clk_prepare_enable(
+		struct synaptics_rmi4_data *rmi4_data)
+{
+	int ret;
+
+	ret = clk_prepare_enable(rmi4_data->iface_clk);
+	if (ret) {
+		dev_err(rmi4_data->pdev->dev.parent,
+			"error on clk_prepare_enable(iface_clk):%d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(rmi4_data->core_clk);
+	if (ret) {
+		clk_disable_unprepare(rmi4_data->iface_clk);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"error clk_prepare_enable(core_clk):%d\n", ret);
+	}
+	return ret;
+}
+
+static void synaptics_rmi4_clk_disable_unprepare(
+		struct synaptics_rmi4_data *rmi4_data)
+{
+	clk_disable_unprepare(rmi4_data->core_clk);
+	clk_disable_unprepare(rmi4_data->iface_clk);
+}
+
+static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
+{
+	int retval;
+	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+	retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
+	if (retval >= 0 && rmi4_data->core_clk != NULL &&
+				rmi4_data->iface_clk != NULL) {
+		retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
+		if (retval)
+			pm_runtime_put_sync(i2c->adapter->dev.parent);
+	}
+	mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+
+	return retval;
+}
+
+static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
+{
+	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+	if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL)
+		synaptics_rmi4_clk_disable_unprepare(rmi4_data);
+	pm_runtime_put_sync(i2c->adapter->dev.parent);
+	mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+}
+#endif
+
 static struct synaptics_dsx_bus_access bus_access = {
 	.type = BUS_I2C,
 	.read = synaptics_rmi4_i2c_read,
 	.write = synaptics_rmi4_i2c_write,
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	.get = synaptics_rmi4_i2c_get,
+	.put = synaptics_rmi4_i2c_put,
+#endif
 };
 
 static void synaptics_rmi4_i2c_dev_release(struct device *dev)
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
index 3f57d13..4392374 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -127,19 +128,19 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(open, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_open_store),
 	__ATTR(release, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_release_store),
 	__ATTR(attn_state, 0444,
 			rmidev_sysfs_attn_state_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(pid, 0664,
 			rmidev_sysfs_pid_show,
 			rmidev_sysfs_pid_store),
 	__ATTR(term, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_term_store),
 	__ATTR(intr_mask, 0444,
 			rmidev_sysfs_intr_mask_show,
@@ -562,18 +563,24 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto clean_up;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto clean_up;
+	}
 	address = (unsigned short)(*f_pos);
 
 	rmidev_allocate_buffer(count);
 
-	mutex_lock(&(dev_data->file_mutex));
-
 	retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
 			*f_pos,
 			rmidev->tmpbuf,
@@ -633,18 +640,26 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto unlock;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto unlock;
+	}
 	rmidev_allocate_buffer(count);
 
-	if (copy_from_user(rmidev->tmpbuf, buf, count))
+	if (copy_from_user(rmidev->tmpbuf, buf, count)) {
 		return -EFAULT;
-
-	mutex_lock(&(dev_data->file_mutex));
+		goto unlock;
+	}
 
 	retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
 			*f_pos,
@@ -653,6 +668,7 @@
 	if (retval >= 0)
 		*f_pos += retval;
 
+unlock:
 	mutex_unlock(&(dev_data->file_mutex));
 
 	return retval;
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
index 1fdd89f..49bec56 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -198,23 +199,13 @@
 static ssize_t concat(test_sysfs, _##propname##_show)(\
 		struct device *dev,\
 		struct device_attribute *attr,\
-		char *buf);\
-\
-static struct device_attribute dev_attr_##propname =\
-		__ATTR(propname, 0444,\
-		concat(test_sysfs, _##propname##_show),\
-		synaptics_rmi4_store_error);
+		char *buf);
 
 #define store_prototype(propname)\
 static ssize_t concat(test_sysfs, _##propname##_store)(\
 		struct device *dev,\
 		struct device_attribute *attr,\
-		const char *buf, size_t count);\
-\
-static struct device_attribute dev_attr_##propname =\
-		__ATTR(propname, 0220,\
-		synaptics_rmi4_show_error,\
-		concat(test_sysfs, _##propname##_store));
+		const char *buf, size_t count);
 
 #define show_store_prototype(propname)\
 static ssize_t concat(test_sysfs, _##propname##_show)(\
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
index 312d203..bfd03cf 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -113,10 +114,10 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(dcs_write, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			video_sysfs_dcs_write_store),
 	__ATTR(param, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			video_sysfs_param_store),
 };
 
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 85df514..fc949fe 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -535,6 +535,8 @@
 	struct list_head		unassign_list;
 	struct mutex			assign_lock;
 	struct list_head		secure_pool_list;
+	/* nonsecure pool protected by pgtbl_lock */
+	struct list_head		nonsecure_pool;
 	struct iommu_domain		domain;
 
 	bool				qsmmuv500_errata1_init;
@@ -593,6 +595,16 @@
 static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain);
 static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain);
 
+static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova,
+			       phys_addr_t paddr, size_t size, int prot);
+static size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+				    unsigned long iova,
+				    size_t size);
+static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+				     unsigned long iova,
+				     struct scatterlist *sg,
+				     unsigned int nents, int prot);
+
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
 	return container_of(dom, struct arm_smmu_domain, domain);
@@ -1313,8 +1325,19 @@
 	void *page;
 	struct arm_smmu_domain *smmu_domain = cookie;
 
-	if (!arm_smmu_is_master_side_secure(smmu_domain))
+	if (!arm_smmu_is_master_side_secure(smmu_domain)) {
+		struct page *pg;
+		/* size is expected to be 4K with current configuration */
+		if (size == PAGE_SIZE) {
+			pg = list_first_entry_or_null(
+				&smmu_domain->nonsecure_pool, struct page, lru);
+			if (pg) {
+				list_del_init(&pg->lru);
+				return page_address(pg);
+			}
+		}
 		return alloc_pages_exact(size, gfp_mask);
+	}
 
 	page = arm_smmu_secure_pool_remove(smmu_domain, size);
 	if (page)
@@ -1353,6 +1376,28 @@
 	.free_pages_exact = arm_smmu_free_pages_exact,
 };
 
+static void msm_smmu_tlb_inv_context(void *cookie)
+{
+}
+
+static void msm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
+					  size_t granule, bool leaf,
+					  void *cookie)
+{
+}
+
+static void msm_smmu_tlb_sync(void *cookie)
+{
+}
+
+static struct iommu_gather_ops msm_smmu_gather_ops = {
+	.tlb_flush_all	= msm_smmu_tlb_inv_context,
+	.tlb_add_flush	= msm_smmu_tlb_inv_range_nosync,
+	.tlb_sync	= msm_smmu_tlb_sync,
+	.alloc_pages_exact = arm_smmu_alloc_pages_exact,
+	.free_pages_exact = arm_smmu_free_pages_exact,
+};
+
 static phys_addr_t arm_smmu_verify_fault(struct iommu_domain *domain,
 					 dma_addr_t iova, u32 fsr)
 {
@@ -1874,6 +1919,9 @@
 	if (smmu->options & ARM_SMMU_OPT_MMU500_ERRATA1)
 		tlb = &qsmmuv500_errata1_smmu_gather_ops;
 
+	if (arm_smmu_is_slave_side_secure(smmu_domain))
+		tlb = &msm_smmu_gather_ops;
+
 	ret = arm_smmu_alloc_cb(domain, smmu, dev);
 	if (ret < 0)
 		goto out_unlock;
@@ -1894,6 +1942,7 @@
 				.sec_id = smmu->sec_id,
 				.cbndx = cfg->cbndx,
 			},
+			.tlb		= tlb,
 			.iommu_dev      = smmu->dev,
 		};
 		fmt = ARM_MSM_SECURE;
@@ -2080,6 +2129,7 @@
 	INIT_LIST_HEAD(&smmu_domain->unassign_list);
 	mutex_init(&smmu_domain->assign_lock);
 	INIT_LIST_HEAD(&smmu_domain->secure_pool_list);
+	INIT_LIST_HEAD(&smmu_domain->nonsecure_pool);
 	arm_smmu_domain_reinit(smmu_domain);
 
 	return &smmu_domain->domain;
@@ -2263,8 +2313,6 @@
 	const struct iommu_gather_ops *tlb;
 
 	tlb = smmu_domain->pgtbl_cfg.tlb;
-	if (!tlb)
-		return;
 
 	mutex_lock(&smmu->stream_map_mutex);
 	for_each_cfg_sme(fwspec, i, idx) {
@@ -2432,6 +2480,50 @@
 	return 0;
 }
 
+static void arm_smmu_prealloc_memory(struct arm_smmu_domain *smmu_domain,
+					struct scatterlist *sgl, int nents,
+					struct list_head *pool)
+{
+	u32 nr = 0;
+	int i;
+	size_t size = 0;
+	struct scatterlist *sg;
+	struct page *page;
+
+	if ((smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC)) ||
+			arm_smmu_has_secure_vmid(smmu_domain))
+		return;
+
+	for_each_sg(sgl, sg, nents, i)
+		size += sg->length;
+
+	/* number of 2nd level pagetable entries */
+	nr += round_up(size, SZ_1G) >> 30;
+	/* number of 3rd level pagetabel entries */
+	nr += round_up(size, SZ_2M) >> 21;
+
+	/* Retry later with atomic allocation on error */
+	for (i = 0; i < nr; i++) {
+		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
+		if (!page)
+			break;
+		list_add(&page->lru, pool);
+	}
+}
+
+static void arm_smmu_release_prealloc_memory(
+		struct arm_smmu_domain *smmu_domain, struct list_head *list)
+{
+	struct page *page, *tmp;
+	u32 remaining = 0;
+
+	list_for_each_entry_safe(page, tmp, list, lru) {
+		list_del(&page->lru);
+		__free_pages(page, 0);
+		remaining++;
+	}
+}
+
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
 	int ret;
@@ -2514,6 +2606,9 @@
 	if (!ops)
 		return -ENODEV;
 
+	if (arm_smmu_is_slave_side_secure(smmu_domain))
+		return msm_secure_smmu_map(domain, iova, paddr, size, prot);
+
 	arm_smmu_secure_domain_lock(smmu_domain);
 
 	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
@@ -2554,6 +2649,9 @@
 	if (!ops)
 		return 0;
 
+	if (arm_smmu_is_slave_side_secure(smmu_domain))
+		return msm_secure_smmu_unmap(domain, iova, size);
+
 	ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
 	if (ret)
 		return ret;
@@ -2589,10 +2687,15 @@
 	unsigned int idx_start, idx_end;
 	struct scatterlist *sg_start, *sg_end;
 	unsigned long __saved_iova_start;
+	LIST_HEAD(nonsecure_pool);
 
 	if (!ops)
 		return -ENODEV;
 
+	if (arm_smmu_is_slave_side_secure(smmu_domain))
+		return msm_secure_smmu_map_sg(domain, iova, sg, nents, prot);
+
+	arm_smmu_prealloc_memory(smmu_domain, sg, nents, &nonsecure_pool);
 	arm_smmu_secure_domain_lock(smmu_domain);
 
 	__saved_iova_start = iova;
@@ -2611,8 +2714,10 @@
 		}
 
 		spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+		list_splice_init(&nonsecure_pool, &smmu_domain->nonsecure_pool);
 		ret = ops->map_sg(ops, iova, sg_start, idx_end - idx_start,
 				  prot, &size);
+		list_splice_init(&smmu_domain->nonsecure_pool, &nonsecure_pool);
 		spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
 		/* Returns 0 on error */
 		if (!ret) {
@@ -2633,6 +2738,7 @@
 		iova = __saved_iova_start;
 	}
 	arm_smmu_secure_domain_unlock(smmu_domain);
+	arm_smmu_release_prealloc_memory(smmu_domain, &nonsecure_pool);
 	return iova - __saved_iova_start;
 }
 
@@ -2780,6 +2886,9 @@
 	if (!smmu)
 		return true;
 
+	if (!arm_smmu_is_static_cb(smmu))
+		return false;
+
 	/* Do not write to global space */
 	if (((unsigned long)addr & (smmu->size - 1)) < (smmu->size >> 1))
 		return true;
@@ -2791,6 +2900,56 @@
 
 	return false;
 }
+
+static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova,
+			       phys_addr_t paddr, size_t size, int prot)
+{
+	size_t ret;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	ret = ops->map(ops, iova, paddr, size, prot);
+
+	return ret;
+}
+
+static size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+				    unsigned long iova,
+				    size_t size)
+{
+	size_t ret;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
+	if (ret)
+		return ret;
+
+	ret = ops->unmap(ops, iova, size);
+
+	arm_smmu_domain_power_off(domain, smmu_domain->smmu);
+
+	return ret;
+}
+
+static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+				     unsigned long iova,
+				     struct scatterlist *sg,
+				     unsigned int nents, int prot)
+{
+	int ret;
+	size_t size;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	ret = ops->map_sg(ops, iova, sg, nents, prot, &size);
+
+	if (!ret)
+		msm_secure_smmu_unmap(domain, iova, size);
+
+	return ret;
+}
+
 #endif
 
 static struct arm_smmu_device *arm_smmu_get_by_list(struct device_node *np)
@@ -4396,8 +4555,12 @@
 	smmu->arch_ops = data->arch_ops;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res)
-		smmu->phys_addr = res->start;
+	if (res == NULL) {
+		dev_err(dev, "no MEM resource info\n");
+		return -EINVAL;
+	}
+
+	smmu->phys_addr = res->start;
 	smmu->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(smmu->base))
 		return PTR_ERR(smmu->base);
@@ -4450,6 +4613,11 @@
 		goto out_exit_power_resources;
 
 	smmu->sec_id = msm_dev_to_device_id(dev);
+	INIT_LIST_HEAD(&smmu->list);
+	spin_lock(&arm_smmu_devices_lock);
+	list_add(&smmu->list, &arm_smmu_devices);
+	spin_unlock(&arm_smmu_devices_lock);
+
 	err = arm_smmu_device_cfg_probe(smmu);
 	if (err)
 		goto out_power_off;
@@ -4492,11 +4660,6 @@
 	arm_smmu_device_reset(smmu);
 	arm_smmu_power_off(smmu->pwr);
 
-	INIT_LIST_HEAD(&smmu->list);
-	spin_lock(&arm_smmu_devices_lock);
-	list_add(&smmu->list, &arm_smmu_devices);
-	spin_unlock(&arm_smmu_devices_lock);
-
 	/* bus_set_iommu depends on this. */
 	bus_for_each_dev(&platform_bus_type, NULL, NULL,
 			 arm_smmu_of_iommu_configure_fixup);
@@ -4526,6 +4689,9 @@
 
 out_power_off:
 	arm_smmu_power_off(smmu->pwr);
+	spin_lock(&arm_smmu_devices_lock);
+	list_del(&smmu->list);
+	spin_unlock(&arm_smmu_devices_lock);
 
 out_exit_power_resources:
 	arm_smmu_exit_power_resources(smmu->pwr);
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index ad7ee11..eac7b41 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -927,7 +927,7 @@
 int fast_smmu_init_mapping(struct device *dev,
 			    struct dma_iommu_mapping *mapping)
 {
-	int err;
+	int err = 0;
 	struct iommu_domain *domain = mapping->domain;
 	struct iommu_pgtbl_info info;
 	u64 size = (u64)mapping->bits << PAGE_SHIFT;
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 981172d..6fbade9 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -207,6 +207,7 @@
 	unsigned long		bits_per_level;
 
 	void			*pgd;
+	void			*pgd_ttbr1;
 };
 
 typedef u64 arm_lpae_iopte;
@@ -665,6 +666,8 @@
 	struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop);
 
 	__arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd);
+	__arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data),
+				data->pgd_ttbr1);
 	kfree(data);
 }
 
@@ -1089,14 +1092,22 @@
 	if (!data->pgd)
 		goto out_free_data;
 
+	data->pgd_ttbr1 = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL,
+					   cfg, cookie);
+	if (!data->pgd_ttbr1)
+		goto out_free_pgd;
+
 	/* Ensure the empty pgd is visible before any actual TTBR write */
 	wmb();
 
 	/* TTBRs */
 	cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd);
-	cfg->arm_lpae_s1_cfg.ttbr[1] = 0;
+	cfg->arm_lpae_s1_cfg.ttbr[1] = virt_to_phys(data->pgd_ttbr1);
 	return &data->iop;
 
+out_free_pgd:
+	__arm_lpae_free_pages(data->pgd, data->pgd_size, cfg, cookie);
+
 out_free_data:
 	kfree(data);
 	return NULL;
diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c
index 983b28b..d0a8a79 100644
--- a/drivers/iommu/io-pgtable-msm-secure.c
+++ b/drivers/iommu/io-pgtable-msm-secure.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -41,6 +41,8 @@
 
 struct msm_secure_io_pgtable {
 	struct io_pgtable iop;
+	/* lock required while operating on page tables */
+	struct mutex pgtbl_lock;
 };
 
 int msm_iommu_sec_pgtbl_init(void)
@@ -71,7 +73,7 @@
 	/* Now allocate memory for the secure page tables */
 	attrs = DMA_ATTR_NO_KERNEL_MAPPING;
 	dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
-	arch_setup_dma_ops(&dev, 0, 0, NULL, 1);
+	arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
 	cpu_addr = dma_alloc_attrs(&dev, psize[0], &paddr, GFP_KERNEL, attrs);
 	if (!cpu_addr) {
 		pr_err("%s: Failed to allocate %d bytes for PTBL\n",
@@ -133,6 +135,7 @@
 	flush_va_end = (void *)
 		(((unsigned long) flush_va) + sizeof(phys_addr_t));
 
+	mutex_lock(&data->pgtbl_lock);
 	/*
 	 * Ensure that the buffer is in RAM by the time it gets to TZ
 	 */
@@ -142,10 +145,11 @@
 				SCM_VAL, SCM_VAL, SCM_VAL);
 
 	if (is_scm_armv8()) {
-		ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
+		ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
 				IOMMU_SECURE_MAP2_FLAT), &desc);
 		resp = desc.ret[0];
 	}
+	mutex_unlock(&data->pgtbl_lock);
 
 	if (ret || resp)
 		return -EINVAL;
@@ -258,11 +262,13 @@
 
 	flush_va_end = (void *) (((unsigned long) flush_va) +
 			(cnt * sizeof(*pa_list)));
+
+	mutex_lock(&data->pgtbl_lock);
 	dmac_clean_range(flush_va, flush_va_end);
 
 	if (is_scm_armv8()) {
-		ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
-					 IOMMU_SECURE_MAP2_FLAT), &desc);
+		ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+				IOMMU_SECURE_MAP2_FLAT), &desc);
 		resp = desc.ret[0];
 
 		if (ret || resp)
@@ -270,6 +276,7 @@
 		else
 			ret = len;
 	}
+	mutex_unlock(&data->pgtbl_lock);
 
 	kfree(pa_list);
 	return ret;
@@ -293,13 +300,15 @@
 	desc.args[4] = IOMMU_TLBINVAL_FLAG;
 	desc.arginfo = SCM_ARGS(5);
 
+	mutex_lock(&data->pgtbl_lock);
 	if (is_scm_armv8()) {
-		ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP,
-			IOMMU_SECURE_UNMAP2_FLAT), &desc);
+		ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+				IOMMU_SECURE_UNMAP2_FLAT), &desc);
 
 		if (!ret)
 			ret = len;
 	}
+	mutex_unlock(&data->pgtbl_lock);
 	return ret;
 }
 
@@ -324,6 +333,7 @@
 		.unmap		= msm_secure_unmap,
 		.iova_to_phys	= msm_secure_iova_to_phys,
 	};
+	mutex_init(&data->pgtbl_lock);
 
 	return data;
 }
diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c
index 3f739a2..180edf3 100644
--- a/drivers/iommu/msm_dma_iommu_mapping.c
+++ b/drivers/iommu/msm_dma_iommu_mapping.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -183,7 +183,7 @@
 	mutex_lock(&iommu_meta->lock);
 	iommu_map = msm_iommu_lookup(iommu_meta, dev);
 	if (!iommu_map) {
-		iommu_map = kmalloc(sizeof(*iommu_map), GFP_ATOMIC);
+		iommu_map = kmalloc(sizeof(*iommu_map), GFP_KERNEL);
 
 		if (!iommu_map) {
 			ret = -ENOMEM;
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 450059c..07e01c4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -75,4 +75,4 @@
 obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
 obj-$(CONFIG_ARCH_ASPEED)		+= irq-aspeed-vic.o
 obj-$(CONFIG_STM32_EXTI) 		+= irq-stm32-exti.o
-obj-$(CONFIG_QTI_PDC)			+= qcom/
+obj-$(CONFIG_ARCH_QCOM)			+= qcom/
diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig
index b892109..5d2b451 100644
--- a/drivers/irqchip/qcom/Kconfig
+++ b/drivers/irqchip/qcom/Kconfig
@@ -20,3 +20,19 @@
         default y if ARCH_SDM670
         help
           QTI Power Domain Controller for SDM670
+
+config QTI_PDC_SDXPOORWILLS
+        bool "QTI PDC SDxPOORWILLS"
+        select QTI_PDC
+        default y if ARCH_SDXPOORWILLS
+        help
+          QTI Power Domain Controller for SDxPoorwills
+
+config QTI_MPM
+	bool "QTI MPM"
+	depends on ARCH_QCOM
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+	help
+	  QTI MSM Power Manager driver to manage and configure wakeup
+	  IRQs.
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
index 5e99040..8871f9a 100644
--- a/drivers/irqchip/qcom/Makefile
+++ b/drivers/irqchip/qcom/Makefile
@@ -1,3 +1,5 @@
 obj-$(CONFIG_QTI_PDC)			+= pdc.o
 obj-$(CONFIG_QTI_PDC_SDM845)		+= pdc-sdm845.o
 obj-$(CONFIG_QTI_PDC_SDM670)		+= pdc-sdm670.o
+obj-$(CONFIG_QTI_PDC_SDXPOORWILLS)	+= pdc-sdxpoorwills.o
+obj-$(CONFIG_QTI_MPM)			+= mpm.o mpm-8953.o mpm-8937.o
diff --git a/drivers/irqchip/qcom/mpm-8937.c b/drivers/irqchip/qcom/mpm-8937.c
new file mode 100644
index 0000000..d6875eb
--- /dev/null
+++ b/drivers/irqchip/qcom/mpm-8937.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mpm.h"
+
+const struct mpm_pin mpm_msm8937_gic_chip_data[] = {
+	{2, 216},
+	{49, 172},
+	{53, 104},
+	{58, 166},
+	{62, 222},
+	{-1},
+};
+
+const struct mpm_pin mpm_msm8937_gpio_chip_data[] = {
+	{3, 38},
+	{4, 1},
+	{5, 5},
+	{6, 9},
+	{8, 37},
+	{9, 36},
+	{10, 13},
+	{11, 35},
+	{12, 17},
+	{13, 21},
+	{14, 54},
+	{15, 34},
+	{16, 31},
+	{17, 58},
+	{18, 28},
+	{19, 42},
+	{20, 25},
+	{21, 12},
+	{22, 43},
+	{23, 44},
+	{24, 45},
+	{25, 46},
+	{26, 48},
+	{27, 65},
+	{28, 93},
+	{29, 97},
+	{30, 63},
+	{31, 70},
+	{32, 71},
+	{33, 72},
+	{34, 81},
+	{35, 126},
+	{36, 90},
+	{37, 128},
+	{38, 91},
+	{39, 41},
+	{40, 127},
+	{41, 86},
+	{50, 67},
+	{51, 73},
+	{52, 74},
+	{53, 62},
+	{54, 124},
+	{55, 61},
+	{56, 130},
+	{57, 59},
+	{59, 50},
+	{-1},
+};
diff --git a/drivers/irqchip/qcom/mpm-8953.c b/drivers/irqchip/qcom/mpm-8953.c
new file mode 100644
index 0000000..358f40b
--- /dev/null
+++ b/drivers/irqchip/qcom/mpm-8953.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mpm.h"
+
+const struct mpm_pin mpm_msm8953_gic_chip_data[] = {
+	{2, 216}, /* tsens_upper_lower_int */
+	{37, 252}, /* qmp_usb3_lfps_rxterm_irq -> ss_phy_irq */
+	{49, 168}, /* qusb2phy_dpse_hv -> hs_phy_irq*/
+	{53, 104}, /* mdss_irq */
+	{58, 168}, /* qusb2phy_dmse_hv -> hs_phy_irq*/
+	{88, 222}, /* ee0_krait_hlos_spmi_periph_irq */
+	{-1},
+};
+
+const struct mpm_pin mpm_msm8953_gpio_chip_data[] = {
+	{3, 38},
+	{4, 1},
+	{5, 5},
+	{6, 9},
+	{8, 37},
+	{9, 36},
+	{10, 13},
+	{11, 35},
+	{12, 17},
+	{13, 21},
+	{14, 54},
+	{15, 34},
+	{16, 31},
+	{17, 58},
+	{18, 28},
+	{19, 42},
+	{20, 25},
+	{21, 12},
+	{22, 43},
+	{23, 44},
+	{24, 45},
+	{25, 46},
+	{26, 48},
+	{27, 65},
+	{28, 93},
+	{29, 97},
+	{30, 63},
+	{31, 70},
+	{32, 71},
+	{33, 72},
+	{34, 81},
+	{35, 85},
+	{36, 90},
+	{50, 67},
+	{51, 73},
+	{52, 74},
+	{53, 62},
+	{59, 59},
+	{60, 60},
+	{61, 61},
+	{62, 86},
+	{63, 87},
+	{64, 91},
+	{65, 129},
+	{66, 130},
+	{67, 131},
+	{68, 132},
+	{69, 133},
+	{70, 137},
+	{71, 138},
+	{72, 139},
+	{73, 140},
+	{74, 141},
+	{-1},
+};
diff --git a/drivers/irqchip/qcom/mpm.c b/drivers/irqchip/qcom/mpm.c
new file mode 100644
index 0000000..72bd7fd
--- /dev/null
+++ b/drivers/irqchip/qcom/mpm.c
@@ -0,0 +1,679 @@
+/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/tick.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include<linux/ktime.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/of_irq.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/cpu_pm.h>
+#include <asm/arch_timer.h>
+#include <soc/qcom/rpm-notifier.h>
+#include <soc/qcom/lpm_levels.h>
+#include "mpm.h"
+#define CREATE_TRACE_POINTS
+#include "trace/events/mpm.h"
+
+#define ARCH_TIMER_HZ (19200000)
+#define MAX_MPM_PIN_PER_IRQ 2
+#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
+#define ENABLE_INTR(reg, intr) (reg | (1 << intr))
+#define CLEAR_TYPE(reg, type) (reg & ~(1 << type))
+#define ENABLE_TYPE(reg, type) (reg | (1 << type))
+#define MPM_REG_ENABLE 0
+#define MPM_REG_FALLING_EDGE 1
+#define MPM_REG_RISING_EDGE 2
+#define MPM_REG_POLARITY 3
+#define MPM_REG_STATUS 4
+
+#define QCOM_MPM_REG_WIDTH  DIV_ROUND_UP(num_mpm_irqs, 32)
+#define MPM_REGISTER(reg, index) ((reg * QCOM_MPM_REG_WIDTH + index + 2) * (4))
+
+struct msm_mpm_device_data {
+	struct device *dev;
+	void __iomem *mpm_request_reg_base;
+	void __iomem *mpm_ipc_reg;
+	irq_hw_number_t ipc_irq;
+	struct irq_domain *gic_chip_domain;
+	struct irq_domain *gpio_chip_domain;
+};
+
+static int msm_pm_sleep_time_override;
+static int num_mpm_irqs = 64;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, 0664);
+static struct msm_mpm_device_data msm_mpm_dev_data;
+static unsigned int *mpm_to_irq;
+static DEFINE_SPINLOCK(mpm_lock);
+
+static int msm_get_irq_pin(int mpm_pin, struct mpm_pin *mpm_data)
+{
+	int i = 0;
+
+	if (!mpm_data)
+		return -ENODEV;
+
+	for (i = 0; mpm_data[i].pin >= 0; i++) {
+		if (mpm_data[i].pin == mpm_pin)
+			return mpm_to_irq[mpm_data[i].pin];
+	}
+
+	return -EINVAL;
+}
+
+static void msm_get_mpm_pin(struct irq_data *d, int *mpm_pin)
+{
+	struct mpm_pin *mpm_data = NULL;
+	int i = 0, j = 0;
+
+	if (!d || !d->domain->host_data)
+		return;
+
+	mpm_data = d->domain->host_data;
+
+	for (i = 0; (mpm_data[i].pin >= 0) &&  (j < MAX_MPM_PIN_PER_IRQ); i++) {
+		if (mpm_data[i].hwirq == d->hwirq) {
+			mpm_pin[j] = mpm_data[i].pin;
+			mpm_to_irq[mpm_data[i].pin] = d->irq;
+			j++;
+		}
+	}
+}
+
+static inline uint32_t msm_mpm_read(unsigned int reg, unsigned int subreg_index)
+{
+	unsigned int offset = MPM_REGISTER(reg, subreg_index);
+
+	return readl_relaxed(msm_mpm_dev_data.mpm_request_reg_base + offset);
+}
+
+static inline void msm_mpm_write(unsigned int reg,
+					unsigned int subreg_index,
+					uint32_t value)
+{
+	void __iomem *mpm_reg_base = msm_mpm_dev_data.mpm_request_reg_base;
+	/*
+	 * Add 2 to offset to account for the 64 bit timer in the vMPM
+	 * mapping
+	 */
+	unsigned int offset = MPM_REGISTER(reg, subreg_index);
+	u32 r_value;
+
+	writel_relaxed(value, mpm_reg_base + offset);
+
+	do {
+		r_value = readl_relaxed(mpm_reg_base + offset);
+		udelay(5);
+	} while (r_value != value);
+}
+
+static inline void msm_mpm_enable_irq(struct irq_data *d, bool on)
+{
+	int mpm_pin[MAX_MPM_PIN_PER_IRQ] = {-1, -1};
+	unsigned long flags;
+	int i = 0;
+	u32 enable;
+	unsigned int index, mask;
+	unsigned int reg;
+
+	reg = MPM_REG_ENABLE;
+	msm_get_mpm_pin(d, mpm_pin);
+	for (i = 0; i < MAX_MPM_PIN_PER_IRQ; i++) {
+		if (mpm_pin[i] < 0)
+			return;
+
+		index = mpm_pin[i]/32;
+		mask = mpm_pin[i]%32;
+		spin_lock_irqsave(&mpm_lock, flags);
+		enable = msm_mpm_read(reg, index);
+
+		if (on)
+			enable = ENABLE_INTR(enable, mask);
+		else
+			enable = CLEAR_INTR(enable, mask);
+
+		msm_mpm_write(reg, index, enable);
+		spin_unlock_irqrestore(&mpm_lock, flags);
+	}
+}
+
+static inline void msm_mpm_set_type(struct irq_data *d,
+					unsigned int flowtype)
+{
+	int mpm_pin[MAX_MPM_PIN_PER_IRQ] = {-1, -1};
+	unsigned long flags;
+	int i = 0;
+	u32 type;
+	unsigned int index, mask;
+	unsigned int reg = 0;
+
+	msm_get_mpm_pin(d, mpm_pin);
+	for (i = 0; i < MAX_MPM_PIN_PER_IRQ; i++) {
+		if (mpm_pin[i] < 0)
+			return;
+
+		index = mpm_pin[i]/32;
+		mask = mpm_pin[i]%32;
+
+		if (flowtype & IRQ_TYPE_LEVEL_HIGH)
+			reg = MPM_REG_FALLING_EDGE;
+
+		if (flowtype & IRQ_TYPE_EDGE_RISING)
+			reg = MPM_REG_RISING_EDGE;
+
+		if (flowtype & IRQ_TYPE_EDGE_FALLING)
+			reg = MPM_REG_POLARITY;
+
+		spin_lock_irqsave(&mpm_lock, flags);
+		type = msm_mpm_read(reg, index);
+
+		if (flowtype)
+			type = ENABLE_TYPE(type, mask);
+		else
+			type = CLEAR_TYPE(type, mask);
+
+		msm_mpm_write(reg, index, type);
+		spin_unlock_irqrestore(&mpm_lock, flags);
+	}
+}
+
+static void msm_mpm_gpio_chip_mask(struct irq_data *d)
+{
+	msm_mpm_enable_irq(d, false);
+}
+
+static void msm_mpm_gpio_chip_unmask(struct irq_data *d)
+{
+	msm_mpm_enable_irq(d, true);
+}
+
+static int msm_mpm_gpio_chip_set_type(struct irq_data *d, unsigned int type)
+{
+	msm_mpm_set_type(d, type);
+	return 0;
+}
+
+static void msm_mpm_gic_chip_mask(struct irq_data *d)
+{
+	msm_mpm_enable_irq(d, false);
+	irq_chip_mask_parent(d);
+}
+
+static void msm_mpm_gic_chip_unmask(struct irq_data *d)
+{
+	msm_mpm_enable_irq(d, true);
+	irq_chip_unmask_parent(d);
+}
+
+static int msm_mpm_gic_chip_set_type(struct irq_data *d, unsigned int type)
+{
+	msm_mpm_set_type(d, type);
+	return irq_chip_set_type_parent(d, type);
+}
+
+static struct irq_chip msm_mpm_gic_chip = {
+	.name		= "mpm-gic",
+	.irq_eoi	= irq_chip_eoi_parent,
+	.irq_mask	= msm_mpm_gic_chip_mask,
+	.irq_disable	= msm_mpm_gic_chip_mask,
+	.irq_unmask	= msm_mpm_gic_chip_unmask,
+	.irq_retrigger	= irq_chip_retrigger_hierarchy,
+	.irq_set_type	= msm_mpm_gic_chip_set_type,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+};
+
+static struct irq_chip msm_mpm_gpio_chip = {
+	.name		= "mpm-gpio",
+	.irq_mask	= msm_mpm_gpio_chip_mask,
+	.irq_disable	= msm_mpm_gpio_chip_mask,
+	.irq_unmask	= msm_mpm_gpio_chip_unmask,
+	.irq_set_type	= msm_mpm_gpio_chip_set_type,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+	.irq_retrigger          = irq_chip_retrigger_hierarchy,
+};
+
+static int msm_mpm_gpio_chip_translate(struct irq_domain *d,
+		struct irq_fwspec *fwspec,
+		unsigned long *hwirq,
+		unsigned int *type)
+{
+	if (is_of_node(fwspec->fwnode)) {
+		if (fwspec->param_count != 2)
+			return -EINVAL;
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1];
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int msm_mpm_gpio_chip_alloc(struct irq_domain *domain,
+		unsigned int virq,
+		unsigned int nr_irqs,
+		void *data)
+{
+	int ret = 0;
+	struct irq_fwspec *fwspec = data;
+	irq_hw_number_t hwirq;
+	unsigned int type = IRQ_TYPE_NONE;
+
+	ret = msm_mpm_gpio_chip_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+				&msm_mpm_gpio_chip, NULL);
+
+	return 0;
+}
+
+static const struct irq_domain_ops msm_mpm_gpio_chip_domain_ops = {
+	.translate	= msm_mpm_gpio_chip_translate,
+	.alloc		= msm_mpm_gpio_chip_alloc,
+	.free		= irq_domain_free_irqs_common,
+};
+
+static int msm_mpm_gic_chip_translate(struct irq_domain *d,
+					struct irq_fwspec *fwspec,
+					unsigned long *hwirq,
+					unsigned int *type)
+{
+	if (is_of_node(fwspec->fwnode)) {
+		if (fwspec->param_count < 3)
+			return -EINVAL;
+
+		switch (fwspec->param[0]) {
+		case 0:			/* SPI */
+			*hwirq = fwspec->param[1] + 32;
+			break;
+		case 1:			/* PPI */
+			*hwirq = fwspec->param[1] + 16;
+			break;
+		case GIC_IRQ_TYPE_LPI:	/* LPI */
+			*hwirq = fwspec->param[1];
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+		return 0;
+	}
+
+	if (is_fwnode_irqchip(fwspec->fwnode)) {
+		if (fwspec->param_count != 2)
+			return -EINVAL;
+
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1];
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int msm_mpm_gic_chip_alloc(struct irq_domain *domain,
+					unsigned int virq,
+					unsigned int nr_irqs,
+					void *data)
+{
+	struct irq_fwspec *fwspec = data;
+	struct irq_fwspec parent_fwspec;
+	irq_hw_number_t hwirq;
+	unsigned int type;
+	int  ret;
+
+	ret = msm_mpm_gic_chip_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+						&msm_mpm_gic_chip, NULL);
+
+	parent_fwspec = *fwspec;
+	parent_fwspec.fwnode = domain->parent->fwnode;
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+					    &parent_fwspec);
+}
+
+static const struct irq_domain_ops msm_mpm_gic_chip_domain_ops = {
+	.translate	= msm_mpm_gic_chip_translate,
+	.alloc		= msm_mpm_gic_chip_alloc,
+	.free		= irq_domain_free_irqs_common,
+};
+
+static inline void msm_mpm_send_interrupt(void)
+{
+	writel_relaxed(2, msm_mpm_dev_data.mpm_ipc_reg);
+	/* Ensure the write is complete before returning. */
+	wmb();
+}
+
+static inline void msm_mpm_timer_write(uint32_t *expiry)
+{
+	writel_relaxed(expiry[0], msm_mpm_dev_data.mpm_request_reg_base);
+	writel_relaxed(expiry[1], msm_mpm_dev_data.mpm_request_reg_base + 0x4);
+}
+
+static void msm_mpm_enter_sleep(struct cpumask *cpumask)
+{
+	msm_mpm_send_interrupt();
+	irq_set_affinity(msm_mpm_dev_data.ipc_irq, cpumask);
+}
+
+static int msm_get_apps_irq(unsigned int mpm_irq)
+{
+	struct mpm_pin *mpm_pin = NULL;
+	int apps_irq;
+
+	mpm_pin = (struct mpm_pin *)
+		msm_mpm_dev_data.gic_chip_domain->host_data;
+	apps_irq = msm_get_irq_pin(mpm_irq, mpm_pin);
+	if (apps_irq >= 0)
+		return apps_irq;
+
+	mpm_pin = (struct mpm_pin *)
+		msm_mpm_dev_data.gpio_chip_domain->host_data;
+	return  msm_get_irq_pin(mpm_irq, mpm_pin);
+
+}
+
+static void system_pm_exit_sleep(void)
+{
+	msm_rpm_exit_sleep();
+}
+
+static cycle_t us_to_ticks(uint64_t sleep_val)
+{
+	uint64_t sec, nsec;
+	cycle_t wakeup;
+
+	sec = sleep_val;
+	do_div(sec, USEC_PER_SEC);
+	nsec = sleep_val - sec * USEC_PER_SEC;
+
+	if (nsec > 0) {
+		nsec = nsec * NSEC_PER_USEC;
+		do_div(nsec, NSEC_PER_SEC);
+	}
+
+	sleep_val = sec + nsec;
+
+	wakeup = (u64)sleep_val * ARCH_TIMER_HZ;
+
+	if (sleep_val)
+		wakeup += arch_counter_get_cntvct();
+	else
+		wakeup = (~0ULL);
+
+	return wakeup;
+}
+
+static int system_pm_update_wakeup(bool from_idle)
+{
+	uint64_t wake_time;
+	uint32_t lo = ~0U, hi = ~0U;
+	cycle_t wakeup;
+
+	if (unlikely(!from_idle && msm_pm_sleep_time_override)) {
+		wake_time = msm_pm_sleep_time_override * USEC_PER_SEC;
+		wakeup = us_to_ticks(wake_time);
+	} else {
+		/* Read the hardware to get the most accurate value */
+
+		arch_timer_mem_get_cval(&lo, &hi);
+		wakeup = lo;
+		wakeup |= ((uint64_t)(hi) << 32);
+	}
+
+	msm_mpm_timer_write((uint32_t *)&wakeup);
+	return 0;
+}
+
+static int system_pm_enter_sleep(struct cpumask *mask)
+{
+	int ret = 0;
+
+	ret = msm_rpm_enter_sleep(0, mask);
+	if (ret)
+		return ret;
+	msm_mpm_enter_sleep(mask);
+	return ret;
+}
+
+static bool system_pm_sleep_allowed(void)
+{
+	return !msm_rpm_waiting_for_ack();
+}
+
+static struct system_pm_ops pm_ops = {
+	.enter = system_pm_enter_sleep,
+	.exit = system_pm_exit_sleep,
+	.update_wakeup = system_pm_update_wakeup,
+	.sleep_allowed = system_pm_sleep_allowed,
+};
+
+/*
+ * Triggered by RPM when system resumes from deep sleep
+ */
+static irqreturn_t msm_mpm_irq(int irq, void *dev_id)
+{
+	unsigned long pending;
+	uint32_t value[3];
+	int i, k, apps_irq;
+	unsigned int mpm_irq;
+	struct irq_desc *desc = NULL;
+	unsigned int reg = MPM_REG_ENABLE;
+
+	for (i = 0; i < QCOM_MPM_REG_WIDTH; i++) {
+		value[i] = msm_mpm_read(reg, i);
+		trace_mpm_wakeup_enable_irqs(i, value[i]);
+	}
+
+	for (i = 0; i < QCOM_MPM_REG_WIDTH; i++) {
+		pending = msm_mpm_read(MPM_REG_STATUS, i);
+		pending &= (unsigned long)value[i];
+
+		trace_mpm_wakeup_pending_irqs(i, pending);
+		for_each_set_bit(k, &pending, 32) {
+			mpm_irq = 32 * i + k;
+			apps_irq = msm_get_apps_irq(mpm_irq);
+			desc = apps_irq ?
+				irq_to_desc(apps_irq) : NULL;
+
+			if (desc && !irqd_is_level_type(&desc->irq_data))
+				irq_set_irqchip_state(apps_irq,
+						IRQCHIP_STATE_PENDING, true);
+
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int msm_mpm_init(struct device_node *node)
+{
+	struct msm_mpm_device_data *dev = &msm_mpm_dev_data;
+	int ret = 0;
+	int irq;
+
+	dev->mpm_request_reg_base = of_iomap_by_name(node, "vmpm");
+	if (!dev->mpm_request_reg_base) {
+		pr_err("Unable to iomap\n");
+		ret = -EADDRNOTAVAIL;
+		goto reg_base_err;
+	}
+
+	dev->mpm_ipc_reg = of_iomap_by_name(node, "ipc");
+	if (!dev->mpm_ipc_reg) {
+		pr_err("Unable to iomap IPC register\n");
+		ret = -EADDRNOTAVAIL;
+		goto ipc_reg_err;
+	}
+
+	irq = of_irq_get(node, 0);
+	if (irq <= 0) {
+		pr_err("no IRQ resource info\n");
+		ret = irq;
+		goto ipc_irq_err;
+	}
+	dev->ipc_irq = irq;
+
+	ret = request_irq(dev->ipc_irq, msm_mpm_irq,
+		IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "mpm",
+		msm_mpm_irq);
+	if (ret) {
+		pr_err("request_irq failed errno: %d\n", ret);
+		goto ipc_irq_err;
+	}
+
+	ret = irq_set_irq_wake(dev->ipc_irq, 1);
+	if (ret) {
+		pr_err("failed to set wakeup irq %lu: %d\n",
+			dev->ipc_irq, ret);
+		goto set_wake_irq_err;
+	}
+
+	return register_system_pm_ops(&pm_ops);
+
+set_wake_irq_err:
+	free_irq(dev->ipc_irq, msm_mpm_irq);
+ipc_irq_err:
+	iounmap(dev->mpm_ipc_reg);
+ipc_reg_err:
+	iounmap(dev->mpm_request_reg_base);
+reg_base_err:
+	return ret;
+}
+
+static const struct of_device_id mpm_gic_chip_data_table[] = {
+	{
+		.compatible = "qcom,mpm-gic-msm8953",
+		.data = mpm_msm8953_gic_chip_data,
+	},
+	{
+		.compatible = "qcom,mpm-gic-msm8937",
+		.data = mpm_msm8937_gic_chip_data,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table);
+
+static const struct of_device_id mpm_gpio_chip_data_table[] = {
+	{
+		.compatible = "qcom,mpm-gpio-msm8953",
+		.data = mpm_msm8953_gpio_chip_data,
+	},
+	{
+		.compatible = "qcom,mpm-gpio-msm8937",
+		.data = mpm_msm8937_gpio_chip_data,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mpm_gpio_chip_data_table);
+
+static int __init mpm_gic_chip_init(struct device_node *node,
+					struct device_node *parent)
+{
+	struct irq_domain *parent_domain;
+	const struct of_device_id *id;
+	int ret;
+
+	if (!parent) {
+		pr_err("%s(): no parent for mpm-gic\n", node->full_name);
+		return -ENXIO;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("unable to obtain gic parent domain\n");
+		return -ENXIO;
+	}
+
+	of_property_read_u32(node, "qcom,num-mpm-irqs", &num_mpm_irqs);
+
+	mpm_to_irq = kcalloc(num_mpm_irqs, sizeof(*mpm_to_irq), GFP_KERNEL);
+	if (!mpm_to_irq)
+		return -ENOMEM;
+
+	id = of_match_node(mpm_gic_chip_data_table, node);
+	if (!id) {
+		pr_err("can not find mpm_gic_data_table of_node\n");
+		ret = -ENODEV;
+		goto mpm_map_err;
+	}
+
+	msm_mpm_dev_data.gic_chip_domain = irq_domain_add_hierarchy(
+			parent_domain, 0, num_mpm_irqs, node,
+			&msm_mpm_gic_chip_domain_ops, (void *)id->data);
+	if (!msm_mpm_dev_data.gic_chip_domain) {
+		pr_err("gic domain add failed\n");
+		ret = -ENOMEM;
+		goto mpm_map_err;
+	}
+
+	msm_mpm_dev_data.gic_chip_domain->name = "qcom,mpm-gic";
+
+	ret = msm_mpm_init(node);
+	if (!ret)
+		return ret;
+	irq_domain_remove(msm_mpm_dev_data.gic_chip_domain);
+
+mpm_map_err:
+	kfree(mpm_to_irq);
+	return ret;
+}
+
+IRQCHIP_DECLARE(mpm_gic_chip, "qcom,mpm-gic", mpm_gic_chip_init);
+
+static int __init mpm_gpio_chip_init(struct device_node *node,
+					struct device_node *parent)
+{
+	const struct of_device_id *id;
+
+	id = of_match_node(mpm_gpio_chip_data_table, node);
+	if (!id) {
+		pr_err("match_table not found for mpm-gpio\n");
+		return -ENODEV;
+	}
+
+	msm_mpm_dev_data.gpio_chip_domain = irq_domain_create_linear(
+			of_node_to_fwnode(node), num_mpm_irqs,
+			&msm_mpm_gpio_chip_domain_ops, (void *)id->data);
+
+	if (!msm_mpm_dev_data.gpio_chip_domain)
+		return -ENOMEM;
+
+	msm_mpm_dev_data.gpio_chip_domain->name = "qcom,mpm-gpio";
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(mpm_gpio_chip, "qcom,mpm-gpio", mpm_gpio_chip_init);
diff --git a/drivers/irqchip/qcom/mpm.h b/drivers/irqchip/qcom/mpm.h
new file mode 100644
index 0000000..50a127f
--- /dev/null
+++ b/drivers/irqchip/qcom/mpm.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __QCOM_MPM_H__
+#define __QCOM_MPM_H__
+
+#include <linux/irq.h>
+#include <linux/device.h>
+
+struct mpm_pin {
+	int pin;
+	irq_hw_number_t hwirq;
+};
+
+extern const struct mpm_pin mpm_msm8953_gic_chip_data[];
+extern const struct mpm_pin mpm_msm8953_gpio_chip_data[];
+
+extern const struct mpm_pin mpm_msm8937_gic_chip_data[];
+extern const struct mpm_pin mpm_msm8937_gpio_chip_data[];
+
+#endif /* __QCOM_MPM_H__ */
diff --git a/drivers/irqchip/qcom/pdc-sdxpoorwills.c b/drivers/irqchip/qcom/pdc-sdxpoorwills.c
new file mode 100644
index 0000000..5bbca03
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc-sdxpoorwills.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/irqchip.h>
+#include "pdc.h"
+
+static struct pdc_pin sdxpoorwills_data[] = {
+	{0, 179}, /* rpmh_wake */
+	{1, 180}, /* ee0_apps_hlos_spmi_periph_irq */
+	{2, 181}, /* ee1_apps_trustzone_spmi_periph_irq */
+	{3, 182}, /* secure_wdog_expired */
+	{4, 183}, /* secure_wdog_bark_irq */
+	{5, 184}, /* aop_wdog_expired_irq */
+	{8, 187}, /* aoss_pmic_arb_mpu_xpu_summary_irq */
+	{9, 188}, /* rpmh_wake */
+	{12, 191}, /* pdc_apps_epcb_timeout_summary_irq	*/
+	{13, 192}, /* spmi_protocol_irq	*/
+	{14, 193}, /* tsense0_tsense_max_min_int */
+	{15, 194}, /* apps_pdc_irq_in_15 */
+	{16, 195}, /* tsense0_upper_lower_intr */
+	{17, 196}, /* apps_pdc_irq_in_17 */
+	{18, 197}, /* tsense0_critical_intr	*/
+	{19, 198}, /* apps_pdc_irq_in_19 */
+	{20, 199}, /* apps_pdc.gp_irq_mux[0] */
+	{21, 200}, /* apps_pdc.gp_irq_mux[1] */
+	{22, 201}, /* apps_pdc.gp_irq_mux[2] */
+	{23, 202}, /* apps_pdc.gp_irq_mux[3] */
+	{24, 203}, /* apps_pdc.gp_irq_mux[4] */
+	{25, 204}, /* apps_pdc.gp_irq_mux[5] */
+	{26, 205}, /* apps_pdc.gp_irq_mux[6] */
+	{27, 206}, /* apps_pdc.gp_irq_mux[7] */
+	{28, 207}, /* apps_pdc.gp_irq_mux[8] */
+	{29, 208}, /* apps_pdc.gp_irq_mux[9] */
+	{30, 209}, /* apps_pdc.gp_irq_mux[10] */
+	{31, 210}, /* apps_pdc.gp_irq_mux[11] */
+	{32, 211}, /* apps_pdc.gp_irq_mux[12] */
+	{33, 212}, /* apps_pdc.gp_irq_mux[13] */
+	{34, 213}, /* apps_pdc.gp_irq_mux[14] */
+	{35, 214}, /* apps_pdc.gp_irq_mux[15] */
+	{36, 215}, /* apps_pdc.gp_irq_mux[16] */
+	{37, 216}, /* apps_pdc.gp_irq_mux[17] */
+	{38, 217}, /* apps_pdc.gp_irq_mux[18] */
+	{39, 218}, /* apps_pdc.gp_irq_mux[19] */
+	{40, 219}, /* apps_pdc.gp_irq_mux[20] */
+	{41, 220}, /* apps_pdc.gp_irq_mux[21] */
+	{42, 221}, /* apps_pdc.gp_irq_mux[22] */
+	{43, 222}, /* apps_pdc.gp_irq_mux[23] */
+	{44, 223}, /* apps_pdc.gp_irq_mux[24] */
+	{45, 224}, /* apps_pdc.gp_irq_mux[25] */
+	{46, 225}, /* apps_pdc.gp_irq_mux[26] */
+	{47, 226}, /* apps_pdc.gp_irq_mux[27] */
+	{48, 227}, /* apps_pdc.gp_irq_mux[28] */
+	{49, 228}, /* apps_pdc.gp_irq_mux[29] */
+	{50, 229}, /* apps_pdc.gp_irq_mux[30] */
+	{51, 230}, /* apps_pdc.gp_irq_mux[31] */
+	{-1}
+};
+
+static int __init qcom_pdc_gic_init(struct device_node *node,
+		struct device_node *parent)
+{
+	pr_info("PDC sdxpoowills initialized\n");
+	return qcom_pdc_init(node, parent, sdxpoorwills_data);
+}
+
+IRQCHIP_DECLARE(pdc_sdxpoorwills, "qcom,pdc-sdxpoorwills", qcom_pdc_gic_init);
diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c
index 923552f..f4e9799 100644
--- a/drivers/irqchip/qcom/pdc.c
+++ b/drivers/irqchip/qcom/pdc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -95,6 +96,20 @@
 	return 0;
 }
 
+static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
+		enum irqchip_irq_state which, bool *state)
+{
+	return d->parent_data->chip->irq_get_irqchip_state(d->parent_data,
+		which, state);
+}
+
+static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
+		enum irqchip_irq_state which, bool value)
+{
+	return d->parent_data->chip->irq_set_irqchip_state(d->parent_data,
+		which, value);
+}
+
 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
 	pdc_enable_intr(d, false);
@@ -220,6 +235,8 @@
 #ifdef CONFIG_SMP
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
 #endif
+	.irq_get_irqchip_state	= qcom_pdc_gic_get_irqchip_state,
+	.irq_set_irqchip_state	= qcom_pdc_gic_set_irqchip_state,
 };
 
 static int qcom_pdc_translate(struct irq_domain *d,
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 431123b..dac7a71 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -44,7 +44,8 @@
 		goto unlock;
 	}
 
-	if (sysfs_streq(buf, "none")) {
+	if (sysfs_streq(buf, "none") &&
+			!(led_cdev->flags & LED_KEEP_TRIGGER)) {
 		led_trigger_remove(led_cdev);
 		goto unlock;
 	}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index d400dca..0ac3fa0 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
 struct gpio_led_data {
 	struct led_classdev cdev;
@@ -144,6 +145,7 @@
 
 struct gpio_leds_priv {
 	int num_leds;
+	struct regulator *vdd_ldo_1, *vdd_ldo_2;
 	struct gpio_led_data leds[];
 };
 
@@ -158,8 +160,7 @@
 	struct device *dev = &pdev->dev;
 	struct fwnode_handle *child;
 	struct gpio_leds_priv *priv;
-	int count, ret;
-
+	int count, ret, error;
 	count = device_get_child_node_count(dev);
 	if (!count)
 		return ERR_PTR(-ENODEV);
@@ -214,7 +215,28 @@
 		led_dat->cdev.dev->of_node = np;
 		priv->num_leds++;
 	}
-
+	priv->vdd_ldo_1 = regulator_get(&pdev->dev, "vdd_ldo_1");
+	if (IS_ERR(priv->vdd_ldo_1)) {
+		error = PTR_ERR(priv->vdd_ldo_1);
+		pr_err("%s: regulator get failed vdd_ldo_1 rc=%d\n",
+			__func__, error);
+	}
+	ret = regulator_enable(priv->vdd_ldo_1);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_1 enable failed rc=%d\n",
+			__func__, ret);
+	}
+	priv->vdd_ldo_2 = regulator_get(&pdev->dev, "vdd_ldo_2");
+	if (IS_ERR(priv->vdd_ldo_2)) {
+		error = PTR_ERR(priv->vdd_ldo_2);
+		pr_err("%s: regulator get failed vdd_ldo_2 rc=%d\n",
+			__func__, error);
+	}
+	ret = regulator_enable(priv->vdd_ldo_2);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_2 enable failed rc=%d\n",
+			__func__, ret);
+	}
 	return priv;
 }
 
@@ -230,7 +252,6 @@
 	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct gpio_leds_priv *priv;
 	int i, ret = 0;
-
 	if (pdata && pdata->num_leds) {
 		priv = devm_kzalloc(&pdev->dev,
 				sizeof_gpio_leds_priv(pdata->num_leds),
@@ -269,6 +290,50 @@
 	}
 }
 
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	int ret;
+	struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv->vdd_ldo_1) {
+		ret = regulator_disable(priv->vdd_ldo_1);
+		if (ret) {
+			pr_err("%s: Regulator vdd_ldo_1 disable failed rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	if (priv->vdd_ldo_2) {
+		ret = regulator_disable(priv->vdd_ldo_2);
+		if (ret) {
+			pr_err("%s: Regulator vdd_ldo_2 disable failed rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
+
+	ret = regulator_enable(priv->vdd_ldo_1);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_1 enable failed rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
+	ret = regulator_enable(priv->vdd_ldo_2);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_2 enable failed rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
 static struct platform_driver gpio_led_driver = {
 	.probe		= gpio_led_probe,
 	.shutdown	= gpio_led_shutdown,
@@ -276,6 +341,8 @@
 		.name	= "leds-gpio",
 		.of_match_table = of_gpio_leds_match,
 	},
+	.suspend = gpio_led_suspend,
+	.resume = gpio_led_resume,
 };
 
 module_platform_driver(gpio_led_driver);
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index f3f9a1a..d4b64ba 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -34,132 +34,161 @@
 #include "leds.h"
 
 #define	FLASH_LED_REG_LED_STATUS1(base)		(base + 0x08)
+
 #define	FLASH_LED_REG_LED_STATUS2(base)		(base + 0x09)
+#define	FLASH_LED_VPH_DROOP_FAULT_MASK		BIT(4)
+
 #define	FLASH_LED_REG_INT_RT_STS(base)		(base + 0x10)
+
 #define	FLASH_LED_REG_SAFETY_TMR(base)		(base + 0x40)
+#define	FLASH_LED_SAFETY_TMR_ENABLE		BIT(7)
+
 #define	FLASH_LED_REG_TGR_CURRENT(base)		(base + 0x43)
+
 #define	FLASH_LED_REG_MOD_CTRL(base)		(base + 0x46)
+#define	FLASH_LED_MOD_CTRL_MASK			BIT(7)
+#define	FLASH_LED_MOD_ENABLE			BIT(7)
+
 #define	FLASH_LED_REG_IRES(base)		(base + 0x47)
+
 #define	FLASH_LED_REG_STROBE_CFG(base)		(base + 0x48)
+#define	FLASH_LED_STROBE_MASK			GENMASK(1, 0)
+
 #define	FLASH_LED_REG_STROBE_CTRL(base)		(base + 0x49)
+#define	FLASH_LED_HW_SW_STROBE_SEL_BIT		BIT(2)
+#define	FLASH_HW_STROBE_MASK			GENMASK(2, 0)
+
 #define	FLASH_LED_EN_LED_CTRL(base)		(base + 0x4C)
+#define	FLASH_LED_ENABLE			BIT(0)
+
 #define	FLASH_LED_REG_HDRM_PRGM(base)		(base + 0x4D)
+#define	FLASH_LED_HDRM_VOL_MASK			GENMASK(7, 4)
+#define	FLASH_LED_HDRM_VOL_SHIFT		4
+
 #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_REG_ISC_DELAY(base)		(base + 0x52)
 #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	FLASH_LED_ISC_WARMUP_DELAY_SHIFT		6
+
+#define	FLASH_LED_REG_THERMAL_RMP_DN_RATE(base)	(base + 0x55)
 #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	FLASH_LED_REG_THERMAL_THRSH1(base)	(base + 0x56)
+#define	FLASH_LED_THERMAL_THRSH_MASK		GENMASK(2, 0)
+
+#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_THERMAL_HYSTERESIS_MASK	GENMASK(1, 0)
+
+#define	FLASH_LED_REG_THERMAL_DEBOUNCE(base)	(base + 0x5A)
+#define	FLASH_LED_THERMAL_DEBOUNCE_MASK		GENMASK(1, 0)
+
+#define	FLASH_LED_REG_VPH_DROOP_THRESHOLD(base)	(base + 0x61)
+#define	FLASH_LED_VPH_DROOP_HYSTERESIS_MASK	GENMASK(5, 4)
+#define	FLASH_LED_VPH_DROOP_THRESHOLD_MASK	GENMASK(2, 0)
+#define	FLASH_LED_VPH_DROOP_HYST_SHIFT		4
+
+#define	FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base)	(base + 0x62)
+#define	FLASH_LED_VPH_DROOP_DEBOUNCE_MASK	GENMASK(1, 0)
+
+#define	FLASH_LED_REG_ILED_GRT_THRSH(base)	(base + 0x67)
+#define	FLASH_LED_ILED_GRT_THRSH_MASK		GENMASK(5, 0)
+
+#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_CURRENT_MASK			GENMASK(6, 0)
+
+#define	FLASH_LED_REG_MITIGATION_SEL(base)	(base + 0x6E)
+#define	FLASH_LED_CHGR_MITIGATION_SEL_MASK	GENMASK(5, 4)
+#define	FLASH_LED_LMH_MITIGATION_SEL_MASK	GENMASK(1, 0)
+
+#define	FLASH_LED_REG_MITIGATION_SW(base)	(base + 0x6F)
+#define	FLASH_LED_LMH_MITIGATION_EN_MASK	BIT(0)
+#define	FLASH_LED_CHGR_MITIGATION_EN_MASK	BIT(4)
+#define	FLASH_LED_CHGR_MITIGATION_ENABLE	BIT(4)
+
+#define	FLASH_LED_REG_LMH_LEVEL(base)		(base + 0x70)
+#define	FLASH_LED_LMH_LEVEL_MASK		GENMASK(1, 0)
+
+#define	FLASH_LED_REG_MULTI_STROBE_CTRL(base)	(base + 0x71)
 #define	LED3_FLASH_ONCE_ONLY_BIT		BIT(1)
+
+#define	FLASH_LED_REG_LPG_INPUT_CTRL(base)	(base + 0x72)
 #define	LPG_INPUT_SEL_BIT			BIT(0)
 
+#define	FLASH_LED_REG_CURRENT_DERATE_EN(base)	(base + 0x76)
+#define	FLASH_LED_CURRENT_DERATE_EN_MASK	GENMASK(2, 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
+#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_DEFAULT		2
+#define	FLASH_LED_VPH_DROOP_THRESH_DEFAULT		5
+#define	BHARGER_FLASH_LED_VPH_DROOP_THRESH_DEFAULT	7
+#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_LMH_LEVEL_DEFAULT			0
+#define	FLASH_LED_LMH_MITIGATION_ENABLE			1
+#define	FLASH_LED_LMH_MITIGATION_DISABLE		0
+#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_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_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
+#define	FLASH_BST_PWM_OVRHD_MIN_UV			300000
+#define	FLASH_BST_PWM_OVRHD_MAX_UV			600000
 
 /* notifier call chain for flash-led irqs */
 static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
@@ -171,6 +200,7 @@
 };
 
 enum flash_led_type {
+	FLASH_LED_TYPE_UNKNOWN,
 	FLASH_LED_TYPE_FLASH,
 	FLASH_LED_TYPE_TORCH,
 };
@@ -204,13 +234,13 @@
 	int				prev_current_ma;
 	u8				duration;
 	u8				id;
-	u8				type;
 	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;
 };
 
@@ -225,6 +255,7 @@
 	int				led_mask;
 	bool				regulator_on;
 	bool				enabled;
+	bool				symmetry_en;
 };
 
 /*
@@ -253,6 +284,7 @@
 	u32			led1n2_iclamp_mid_ma;
 	u32			led3_iclamp_low_ma;
 	u32			led3_iclamp_mid_ma;
+	u32			bst_pwm_ovrhd_uv;
 	u8			isc_delay;
 	u8			warmup_delay;
 	u8			current_derate_en_cfg;
@@ -278,6 +310,8 @@
 	struct flash_node_data		*fnode;
 	struct flash_switch_data	*snode;
 	struct power_supply		*bms_psy;
+	struct power_supply		*main_psy;
+	struct power_supply		*usb_psy;
 	struct notifier_block		nb;
 	spinlock_t			lock;
 	int				num_fnodes;
@@ -693,10 +727,13 @@
 	return rc;
 }
 
-#define VOLTAGE_HDRM_DEFAULT_MV	350
+#define VOLTAGE_HDRM_DEFAULT_MV		350
+#define BHARGER_VOLTAGE_HDRM_DEFAULT_MV	400
+#define BHARGER_HEADROOM_OFFSET_MV	50
 static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
 {
 	int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
+	u8 pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 
 	for (i = 0; i < led->num_fnodes; i++) {
 		if (led->fnode[i].led_on) {
@@ -720,13 +757,18 @@
 					voltage_hdrm_mv = 350;
 			}
 
+			if (pmic_subtype == PMI632_SUBTYPE)
+				voltage_hdrm_mv += BHARGER_HEADROOM_OFFSET_MV;
+
 			voltage_hdrm_max = max(voltage_hdrm_max,
 						voltage_hdrm_mv);
 		}
 	}
 
 	if (!voltage_hdrm_max)
-		return VOLTAGE_HDRM_DEFAULT_MV;
+		return (pmic_subtype == PMI632_SUBTYPE) ?
+					BHARGER_VOLTAGE_HDRM_DEFAULT_MV :
+						VOLTAGE_HDRM_DEFAULT_MV;
 
 	return voltage_hdrm_max;
 }
@@ -737,7 +779,7 @@
 #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 *max_current)
 {
 	int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
 	int rbatt_uohm = 0;
@@ -838,8 +880,181 @@
 	return 0;
 }
 
+static int is_main_psy_available(struct qpnp_flash_led *led)
+{
+	if (!led->main_psy) {
+		led->main_psy = power_supply_get_by_name("main");
+		if (!led->main_psy) {
+			pr_err_ratelimited("Couldn't get main_psy\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int is_usb_psy_available(struct qpnp_flash_led *led)
+{
+	if (!led->usb_psy) {
+		led->usb_psy = power_supply_get_by_name("usb");
+		if (!led->usb_psy) {
+			pr_err_ratelimited("Couldn't get usb_psy\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+#define CHGBST_EFFICIENCY		800LL
+#define CHGBST_FLASH_VDIP_MARGIN	10000
+#define VIN_FLASH_UV			5000000
+#define BHARGER_FLASH_LED_MAX_TOTAL_CURRENT_MA		1500
+#define BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA	1100
+static int qpnp_flash_led_calc_bharger_max_current(struct qpnp_flash_led *led,
+						    int *max_current)
+{
+	union power_supply_propval pval = {0, };
+	int ocv_uv, ibat_now, voltage_hdrm_mv, flash_led_max_total_curr_ma, rc;
+	int rbatt_uohm = 0, usb_present, otg_enable;
+	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;
+	int64_t bst_pwm_ovrhd_uv;
+
+	rc = is_usb_psy_available(led);
+	if (rc < 0)
+		return rc;
+
+	rc = power_supply_get_property(led->usb_psy, POWER_SUPPLY_PROP_SCOPE,
+					&pval);
+	if (rc < 0) {
+		pr_err("usb psy does not support usb present, rc=%d\n", rc);
+		return rc;
+	}
+	otg_enable = pval.intval;
+
+	/* 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 = (otg_enable == POWER_SUPPLY_SCOPE_SYSTEM) ?
+			       BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA :
+			       BHARGER_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;
+	}
+
+	bst_pwm_ovrhd_uv = led->pdata->bst_pwm_ovrhd_uv;
+
+	rc = power_supply_get_property(led->usb_psy, POWER_SUPPLY_PROP_PRESENT,
+							&pval);
+	if (rc < 0) {
+		pr_err("usb psy does not support usb present, rc=%d\n", rc);
+		return rc;
+	}
+	usb_present = pval.intval;
+
+	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)
+						+ CHGBST_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_bharger_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);
+	}
+
+	/* when USB is present or OTG is enabled, VIN_FLASH is always at 5V */
+	if (usb_present || (otg_enable == POWER_SUPPLY_SCOPE_SYSTEM))
+		vin_flash_uv = VIN_FLASH_UV;
+	else
+		/* Calculate the input voltage of the flash module. */
+		vin_flash_uv = max((led->pdata->vled_max_uv +
+				   (voltage_hdrm_mv * MCONV)),
+				    vph_flash_uv + bst_pwm_ovrhd_uv);
+
+	/* Calculate the available power for the flash module. */
+	avail_flash_power_fw = CHGBST_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);
+	flash_led_max_total_curr_ma = otg_enable ?
+			       BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA :
+			       BHARGER_FLASH_LED_MAX_TOTAL_CURRENT_MA;
+	*max_current = min(flash_led_max_total_curr_ma,
+			(int)(div64_s64(avail_flash_ua, MCONV)));
+
+	pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d max_current=%lld usb_present=%d otg_enable=%d\n",
+		avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh,
+		(*max_current * MCONV), usb_present, otg_enable);
+	return 0;
+}
+
+
 static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
-						int *thermal_current_lim)
+						   int *thermal_current_lim)
 {
 	int rc;
 	u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
@@ -929,9 +1144,16 @@
 						int *max_avail_current)
 {
 	int thermal_current_lim = 0, rc;
+	u8 pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 
 	led->trigger_lmh = false;
-	rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
+
+	if (pmic_subtype == PMI632_SUBTYPE)
+		rc = qpnp_flash_led_calc_bharger_max_current(led,
+							max_avail_current);
+	else
+		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;
@@ -973,6 +1195,7 @@
 	int prgm_current_ma = value;
 	int min_ma = fnode->ires_ua / 1000;
 	struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+	u8 pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 
 	if (value <= 0)
 		prgm_current_ma = 0;
@@ -999,9 +1222,11 @@
 	fnode->cdev.brightness = prgm_current_ma;
 	fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
 					fnode->ires_ua);
-	fnode->led_on = prgm_current_ma != 0;
+	if (prgm_current_ma)
+		fnode->led_on = true;
 
-	if (led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
+	if (pmic_subtype != PMI632_SUBTYPE &&
+	       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)
@@ -1031,7 +1256,7 @@
 		}
 	}
 
-	if (!led->trigger_chgr) {
+	if (led->pdata->chgr_mitigation_sel && !led->trigger_chgr) {
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_MITIGATION_SW(led->base),
 				FLASH_LED_CHGR_MITIGATION_EN_MASK,
@@ -1091,9 +1316,116 @@
 	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;
+}
+
+#define FLASH_LED_MODULE_EN_TIME_MS	300
+static int qpnp_flash_poll_vreg_ok(struct qpnp_flash_led *led)
+{
+	int rc, i;
+	union power_supply_propval pval = {0, };
+
+	rc = is_main_psy_available(led);
+	if (rc < 0)
+		return rc;
+
+	for (i = 0; i < 60; i++) {
+		/* wait for the flash vreg_ok to be set */
+		mdelay(5);
+
+		rc = power_supply_get_property(led->main_psy,
+					POWER_SUPPLY_PROP_FLASH_TRIGGER, &pval);
+		if (rc < 0) {
+			pr_err("main psy doesn't support reading prop %d rc = %d\n",
+				POWER_SUPPLY_PROP_FLASH_TRIGGER, rc);
+			return rc;
+		}
+
+		if (pval.intval > 0) {
+			pr_debug("Flash trigger set\n");
+			break;
+		}
+
+		if (pval.intval < 0) {
+			pr_err("Error during flash trigger %d\n", pval.intval);
+			return pval.intval;
+		}
+	}
+
+	if (!pval.intval) {
+		pr_err("Failed to enable the module\n");
+		return -ETIMEDOUT;
+	}
+
+	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);
+	u8 pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 	int rc, i, addr_offset;
 	u8 val, mask;
 
@@ -1109,6 +1441,15 @@
 	}
 
 	/* 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 &&
@@ -1179,6 +1520,19 @@
 				FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
 		if (rc < 0)
 			return rc;
+
+		if (pmic_subtype == PMI632_SUBTYPE) {
+			rc = qpnp_flash_poll_vreg_ok(led);
+			if (rc < 0) {
+				/* Disable the module */
+				qpnp_flash_led_masked_write(led,
+					FLASH_LED_REG_MOD_CTRL(led->base),
+					FLASH_LED_MOD_CTRL_MASK,
+					FLASH_LED_DISABLE);
+
+				return rc;
+			}
+		}
 	}
 	led->enable++;
 
@@ -1195,7 +1549,7 @@
 		udelay(500);
 	}
 
-	if (led->trigger_chgr) {
+	if (led->pdata->chgr_mitigation_sel && led->trigger_chgr) {
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_MITIGATION_SW(led->base),
 				FLASH_LED_CHGR_MITIGATION_EN_MASK,
@@ -1216,12 +1570,91 @@
 	return 0;
 }
 
+static int qpnp_flash_led_regulator_control(struct led_classdev *led_cdev,
+					int options, int *max_current)
+{
+	int rc;
+	u8 pmic_subtype;
+	struct flash_switch_data *snode;
+	struct qpnp_flash_led *led;
+	union power_supply_propval ret = {0, };
+
+	snode = container_of(led_cdev, struct flash_switch_data, cdev);
+	led = dev_get_drvdata(&snode->pdev->dev);
+	pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
+
+	if (pmic_subtype == PMI632_SUBTYPE) {
+		rc = is_main_psy_available(led);
+		if (rc < 0)
+			return rc;
+
+		rc = is_usb_psy_available(led);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
+		pr_err("Invalid options %d\n", options);
+		return -EINVAL;
+	}
+
+	if (options & ENABLE_REGULATOR) {
+		if (pmic_subtype == PMI632_SUBTYPE) {
+			ret.intval = 1;
+			rc = power_supply_set_property(led->main_psy,
+					 POWER_SUPPLY_PROP_FLASH_ACTIVE,
+					 &ret);
+			if (rc < 0) {
+				pr_err("Failed to set FLASH_ACTIVE on charger rc=%d\n",
+									rc);
+				return rc;
+			}
+			pr_debug("FLASH_ACTIVE = 1\n");
+		} else {
+			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) {
+		if (pmic_subtype == PMI632_SUBTYPE) {
+			ret.intval = 0;
+			rc = power_supply_set_property(led->main_psy,
+					POWER_SUPPLY_PROP_FLASH_ACTIVE,
+					&ret);
+			if (rc < 0) {
+				pr_err("Failed to set FLASH_ACTIVE on charger rc=%d\n",
+									rc);
+				return rc;
+			}
+			pr_debug("FLASH_ACTIVE = 0\n");
+		} else {
+			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_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 int qpnp_flash_led_prepare_v2(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) {
@@ -1235,39 +1668,9 @@
 		return -EINVAL;
 	}
 
-	snode = container_of(led_cdev, struct flash_switch_data, cdev);
-	led = dev_get_drvdata(&snode->pdev->dev);
+	rc = qpnp_flash_led_regulator_control(led_cdev, options, max_current);
 
-	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_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;
+	return rc;
 }
 
 static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
@@ -1309,6 +1712,29 @@
 	spin_unlock(&led->lock);
 }
 
+static ssize_t qpnp_flash_led_prepare_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc, options, max_current;
+	u32 val;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+	rc = kstrtouint(buf, 0, &val);
+	if (rc < 0)
+		return rc;
+
+	if (val != 0 && val != 1)
+		return count;
+
+	options = val ? ENABLE_REGULATOR : DISABLE_REGULATOR;
+
+	rc = qpnp_flash_led_regulator_control(led_cdev, options, &max_current);
+	if (rc < 0)
+		return rc;
+
+	return count;
+}
+
 /* 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)
@@ -1331,6 +1757,7 @@
 /* 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),
+	__ATTR(enable, 0664, NULL, qpnp_flash_led_prepare_store),
 };
 
 static int flash_led_psy_notifier_call(struct notifier_block *nb,
@@ -1459,6 +1886,7 @@
 	int rc, min_ma;
 	u32 val;
 	bool hw_strobe = 0, edge_trigger = 0, active_high = 0;
+	u8 pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 
 	fnode->pdev = led->pdev;
 	fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
@@ -1488,6 +1916,11 @@
 	rc = of_property_read_u32(node, "qcom,id", &val);
 	if (!rc) {
 		fnode->id = (u8)val;
+
+		if (pmic_subtype == PMI632_SUBTYPE && fnode->id > 1) {
+			pr_err("Flash node id = %d not supported\n", fnode->id);
+			return -EINVAL;
+		}
 	} else {
 		pr_err("Unable to read flash LED ID\n");
 		return rc;
@@ -1707,6 +2140,8 @@
 		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;
@@ -1792,6 +2227,7 @@
 	struct device_node *revid_node;
 	int rc;
 	u32 val;
+	u8 pmic_subtype;
 	bool short_circuit_det, open_circuit_det, vph_droop_det;
 
 	revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
@@ -1812,10 +2248,10 @@
 		return -EPROBE_DEFER;
 	}
 
+	pmic_subtype = led->pdata->pmic_rev_id->pmic_subtype;
 	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");
 
@@ -1923,7 +2359,7 @@
 	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)
+		if (pmic_subtype == PM660L_SUBTYPE)
 			val = THERMAL_HYST_TEMP_TO_VAL(val, 20);
 		else
 			val = THERMAL_HYST_TEMP_TO_VAL(val, 15);
@@ -1987,7 +2423,13 @@
 		return -EINVAL;
 	}
 
-	led->pdata->vph_droop_threshold = FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
+	if (pmic_subtype == PMI632_SUBTYPE)
+		led->pdata->vph_droop_threshold =
+				    BHARGER_FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
+	else
+		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 =
@@ -2132,7 +2574,12 @@
 		return -EINVAL;
 	}
 
-	led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
+	if (pmic_subtype == PMI632_SUBTYPE)
+		led->pdata->chgr_mitigation_sel =
+					FLASH_DISABLE_CHARGER_MITIGATION;
+	else
+		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;
@@ -2160,6 +2607,14 @@
 		return -EINVAL;
 	}
 
+	led->pdata->bst_pwm_ovrhd_uv = FLASH_BST_PWM_OVRHD_MIN_UV;
+	rc = of_property_read_u32(node, "qcom,bst-pwm-ovrhd-uv", &val);
+	if (!rc) {
+		if (val >= FLASH_BST_PWM_OVRHD_MIN_UV &&
+					val <= FLASH_BST_PWM_OVRHD_MAX_UV)
+			led->pdata->bst_pwm_ovrhd_uv = val;
+	}
+
 	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)
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index ce2b055..cbb51c2 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -2226,7 +2226,6 @@
 					"Invalid thermal derate rate\n");
 				return -EINVAL;
 			}
-
 			led->pdata->thermal_derate_rate = (u8)temp_val;
 		} else {
 			dev_err(&led->pdev->dev,
@@ -2474,11 +2473,12 @@
 	if (!led->pdata)
 		return -ENOMEM;
 
-	led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
-	if (led->peripheral_type < 0) {
+	rc = qpnp_flash_led_get_peripheral_type(led);
+	if (rc < 0) {
 		dev_err(&pdev->dev, "Failed to get peripheral type\n");
 		return rc;
 	}
+	led->peripheral_type = (u8) rc;
 
 	rc = qpnp_flash_led_parse_common_dt(led, node);
 	if (rc) {
@@ -2521,6 +2521,7 @@
 	}
 
 	for_each_child_of_node(node, temp) {
+		j = -1;
 		led->flash_node[i].cdev.brightness_set =
 						qpnp_flash_led_brightness_set;
 		led->flash_node[i].cdev.brightness_get =
@@ -2595,7 +2596,6 @@
 			if (rc)
 				goto error_led_register;
 		}
-
 		i++;
 	}
 
@@ -2607,7 +2607,7 @@
 			(long)root);
 		if (PTR_ERR(root) == -ENODEV)
 			pr_err("debugfs is not enabled in kernel");
-		goto error_led_debugfs;
+		goto error_free_led_sysfs;
 	}
 
 	led->dbgfs_root = root;
@@ -2637,6 +2637,8 @@
 	return 0;
 
 error_led_debugfs:
+	debugfs_remove_recursive(root);
+error_free_led_sysfs:
 	i = led->num_leds - 1;
 	j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
 error_led_register:
@@ -2647,7 +2649,6 @@
 		j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
 		led_classdev_unregister(&led->flash_node[i].cdev);
 	}
-	debugfs_remove_recursive(root);
 	mutex_destroy(&led->flash_led_lock);
 	destroy_workqueue(led->ordered_workq);
 
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
index ebdff87..764657a 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation.
- * All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -275,6 +274,7 @@
  *  @ last_rate_cfg - Last rate config updated
  *  @ wave_rep_cnt - waveform repeat count
  *  @ wave_s_rep_cnt - waveform sample repeat count
+ *  @ wf_samp_len - waveform sample length
  *  @ ext_pwm_freq_khz - external pwm frequency in KHz
  *  @ ext_pwm_dtest_line - DTEST line for external pwm
  *  @ status_flags - status
@@ -330,6 +330,7 @@
 	u16				last_rate_cfg;
 	u32				wave_rep_cnt;
 	u32				wave_s_rep_cnt;
+	u32				wf_samp_len;
 	u32				ext_pwm_freq_khz;
 	u8				ext_pwm_dtest_line;
 	u32				status_flags;
@@ -445,6 +446,19 @@
 	return rc;
 }
 
+static inline int get_buffer_mode_duration(struct hap_chip *chip)
+{
+	int sample_count, sample_duration;
+
+	sample_count = chip->wave_rep_cnt * chip->wave_s_rep_cnt *
+			chip->wf_samp_len;
+	sample_duration = sample_count * chip->wave_play_rate_us;
+	pr_debug("sample_count: %d sample_duration: %d\n", sample_count,
+		sample_duration);
+
+	return (sample_duration / 1000);
+}
+
 static bool is_sw_lra_auto_resonance_control(struct hap_chip *chip)
 {
 	if (chip->act_type != HAP_LRA)
@@ -468,7 +482,8 @@
 {
 	int rc = 0;
 	u32 delay_us = HAPTICS_BACK_EMF_DELAY_US;
-	u8 val, auto_res_mode_qwd;
+	u8 val;
+	bool auto_res_mode_qwd;
 
 	if (chip->act_type != HAP_LRA)
 		return 0;
@@ -482,7 +497,7 @@
 
 	/*
 	 * Do not enable auto resonance if auto mode is enabled and auto
-	 * resonance mode is QWD, meaning short pattern.
+	 * resonance mode is QWD, meaning long pattern.
 	 */
 	if (chip->lra_auto_mode && auto_res_mode_qwd && enable) {
 		pr_debug("auto_mode enabled, not enabling auto_res\n");
@@ -735,11 +750,12 @@
 			goto out;
 		}
 
-		if (chip->play_mode != HAP_BUFFER)
-			hrtimer_start(&chip->stop_timer,
-				ktime_set(time_ms / MSEC_PER_SEC,
-				(time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC),
-				HRTIMER_MODE_REL);
+		if (chip->play_mode == HAP_BUFFER)
+			time_ms = get_buffer_mode_duration(chip);
+		hrtimer_start(&chip->stop_timer,
+			ktime_set(time_ms / MSEC_PER_SEC,
+			(time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
 
 		rc = qpnp_haptics_auto_res_enable(chip, true);
 		if (rc < 0) {
@@ -766,6 +782,9 @@
 
 		if (chip->play_mode == HAP_PWM)
 			pwm_disable(chip->pwm_data.pwm_dev);
+
+		if (chip->play_mode == HAP_BUFFER)
+			chip->wave_samp_idx = 0;
 	}
 
 out:
@@ -1182,8 +1201,11 @@
 	if (time_ms <= 20) {
 		wave_samp[0] = HAP_WF_SAMP_MAX;
 		wave_samp[1] = HAP_WF_SAMP_MAX;
-		if (time_ms > 15)
+		chip->wf_samp_len = 2;
+		if (time_ms > 15) {
 			wave_samp[2] = HAP_WF_SAMP_MAX;
+			chip->wf_samp_len = 3;
+		}
 
 		/* short pattern */
 		rc = qpnp_haptics_parse_buffer_dt(chip);
@@ -1211,7 +1233,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 0;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
 		}
@@ -1221,16 +1243,13 @@
 		if (rc < 0)
 			return rc;
 
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for buffer mode */
 		if (chip->play_irq >= 0 && !chip->play_irq_en) {
 			enable_irq(chip->play_irq);
 			chip->play_irq_en = true;
 		}
 
+		brake_pat[0] = BRAKE_VMAX;
 		chip->play_mode = HAP_BUFFER;
 		chip->wave_shape = HAP_WAVE_SQUARE;
 	} else {
@@ -1243,7 +1262,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 1;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
 			ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
@@ -1254,11 +1273,6 @@
 		if (rc < 0)
 			return rc;
 
-		brake_pat[0] = 0x3;
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for direct mode */
 		if (chip->play_irq >= 0 && chip->play_irq_en) {
 			disable_irq(chip->play_irq);
@@ -1282,6 +1296,10 @@
 		return rc;
 	}
 
+	rc = qpnp_haptics_brake_config(chip, brake_pat);
+	if (rc < 0)
+		return rc;
+
 	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
 			HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
 	if (rc < 0)
@@ -1302,33 +1320,20 @@
 		chip->wave_samp_idx += HAP_WAVE_SAMP_LEN;
 		if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) {
 			pr_debug("Samples over\n");
-			/* fall through to stop playing */
 		} else {
 			pr_debug("moving to next sample set %d\n",
 				chip->wave_samp_idx);
 
+			/* Moving to next set of wave sample */
 			rc = qpnp_haptics_buffer_config(chip, NULL, false);
 			if (rc < 0) {
 				pr_err("Error in configuring buffer, rc=%d\n",
 					rc);
 				goto irq_handled;
 			}
-
-			/*
-			 * Moving to next set of wave sample. No need to stop
-			 * or change the play control. Just return.
-			 */
-			goto irq_handled;
 		}
 	}
 
-	rc = qpnp_haptics_play_control(chip, HAP_STOP);
-	if (rc < 0) {
-		pr_err("Error in disabling play, rc=%d\n", rc);
-		goto irq_handled;
-	}
-	chip->wave_samp_idx = 0;
-
 irq_handled:
 	return IRQ_HANDLED;
 }
@@ -1638,6 +1643,7 @@
 		pos += bytes_read;
 	}
 
+	chip->wf_samp_len = i;
 	for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++)
 		chip->wave_samp[i] = samp[i];
 
@@ -1986,7 +1992,10 @@
 		/* Use default values */
 		for (i = 0; i < HAP_WAVE_SAMP_LEN; i++)
 			chip->wave_samp[i] = HAP_WF_SAMP_MAX;
+
+		wf_samp_len = HAP_WAVE_SAMP_LEN;
 	}
+	chip->wf_samp_len = wf_samp_len;
 
 	return 0;
 }
diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c
index ab5e876..f638bc9 100644
--- a/drivers/leds/leds-qti-tri-led.c
+++ b/drivers/leds/leds-qti-tri-led.c
@@ -41,8 +41,6 @@
 #define TRILED_NUM_MAX			3
 
 #define PWM_PERIOD_DEFAULT_NS		1000000
-#define LED_BLINK_ON_MS			125
-#define LED_BLINK_OFF_MS		875
 
 struct pwm_setting {
 	u32	pre_period_ns;
@@ -309,8 +307,7 @@
 		led->cdev.blink_set = qpnp_tri_led_set_blink;
 		led->cdev.default_trigger = led->default_trigger;
 		led->cdev.brightness = LED_OFF;
-		led->cdev.blink_delay_on = LED_BLINK_ON_MS;
-		led->cdev.blink_delay_off = LED_BLINK_OFF_MS;
+		led->cdev.flags |= LED_KEEP_TRIGGER;
 
 		rc = devm_led_classdev_register(chip->dev, &led->cdev);
 		if (rc < 0) {
@@ -361,7 +358,7 @@
 	struct qpnp_led_dev *led;
 	struct pwm_args pargs;
 	const __be32 *addr;
-	int rc, id, i = 0;
+	int rc = 0, id, i = 0;
 
 	addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
 	if (!addr) {
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 2efdce0..cac297f 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -803,7 +803,10 @@
 	c->shrink.scan_objects = bch_mca_scan;
 	c->shrink.seeks = 4;
 	c->shrink.batch = c->btree_pages * 2;
-	register_shrinker(&c->shrink);
+
+	if (register_shrinker(&c->shrink))
+		pr_warn("bcache: %s: could not register shrinker",
+				__func__);
 
 	return 0;
 }
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index edb8d1a..723302c 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -1020,7 +1020,7 @@
 	struct request_queue *q = bdev_get_queue(dc->bdev);
 	int ret = 0;
 
-	if (bdi_congested(&q->backing_dev_info, bits))
+	if (bdi_congested(q->backing_dev_info, bits))
 		return 1;
 
 	if (cached_dev_get(dc)) {
@@ -1029,7 +1029,7 @@
 
 		for_each_cache(ca, d->c, i) {
 			q = bdev_get_queue(ca->bdev);
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 		}
 
 		cached_dev_put(dc);
@@ -1043,7 +1043,7 @@
 	struct gendisk *g = dc->disk.disk;
 
 	g->queue->make_request_fn		= cached_dev_make_request;
-	g->queue->backing_dev_info.congested_fn = cached_dev_congested;
+	g->queue->backing_dev_info->congested_fn = cached_dev_congested;
 	dc->disk.cache_miss			= cached_dev_cache_miss;
 	dc->disk.ioctl				= cached_dev_ioctl;
 }
@@ -1136,7 +1136,7 @@
 
 	for_each_cache(ca, d->c, i) {
 		q = bdev_get_queue(ca->bdev);
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 
 	return ret;
@@ -1147,7 +1147,7 @@
 	struct gendisk *g = d->disk;
 
 	g->queue->make_request_fn		= flash_dev_make_request;
-	g->queue->backing_dev_info.congested_fn = flash_dev_congested;
+	g->queue->backing_dev_info->congested_fn = flash_dev_congested;
 	d->cache_miss				= flash_dev_cache_miss;
 	d->ioctl				= flash_dev_ioctl;
 }
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 28ce342..e44816f 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -804,7 +804,7 @@
 	blk_queue_make_request(q, NULL);
 	d->disk->queue			= q;
 	q->queuedata			= d;
-	q->backing_dev_info.congested_data = d;
+	q->backing_dev_info->congested_data = d;
 	q->limits.max_hw_sectors	= UINT_MAX;
 	q->limits.max_sectors		= UINT_MAX;
 	q->limits.max_segment_size	= UINT_MAX;
@@ -1131,9 +1131,9 @@
 	set_capacity(dc->disk.disk,
 		     dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
 
-	dc->disk.disk->queue->backing_dev_info.ra_pages =
-		max(dc->disk.disk->queue->backing_dev_info.ra_pages,
-		    q->backing_dev_info.ra_pages);
+	dc->disk.disk->queue->backing_dev_info->ra_pages =
+		max(dc->disk.disk->queue->backing_dev_info->ra_pages,
+		    q->backing_dev_info->ra_pages);
 
 	bch_cached_dev_request_init(dc);
 	bch_cached_dev_writeback_init(dc);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index c817627..bed056c 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -2290,7 +2290,7 @@
 static int is_congested(struct dm_dev *dev, int bdi_bits)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index 80e3df1..68d4084 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -1379,7 +1379,7 @@
 static int dev_is_congested(struct dm_dev *dev, int bdi_bits)
 {
 	struct request_queue *q = bdev_get_queue(dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index d837a28..b75ccef 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1756,7 +1756,7 @@
 		char b[BDEVNAME_SIZE];
 
 		if (likely(q))
-			r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+			r |= bdi_congested(q->backing_dev_info, bdi_bits);
 		else
 			DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
 				     dm_device_name(t->md),
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 4477bf9..e976f4f 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -81,10 +81,14 @@
 #define SECTOR_TO_BLOCK_SHIFT 3
 
 /*
+ * For btree insert:
  *  3 for btree insert +
  *  2 for btree lookup used within space map
+ * For btree remove:
+ *  2 for shadow spine +
+ *  4 for rebalance 3 child node
  */
-#define THIN_MAX_CONCURRENT_LOCKS 5
+#define THIN_MAX_CONCURRENT_LOCKS 6
 
 /* This should be plenty */
 #define SPACE_MAP_ROOT_SIZE 128
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 0b678b5..eb419a5 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -2715,7 +2715,7 @@
 		return 1;
 
 	q = bdev_get_queue(pt->data_dev->bdev);
-	return bdi_congested(&q->backing_dev_info, bdi_bits);
+	return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static void requeue_bios(struct pool *pool)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 73e7262..8658ff3 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1380,7 +1380,7 @@
 			 * With request-based DM we only need to check the
 			 * top-level queue for congestion.
 			 */
-			r = md->queue->backing_dev_info.wb.state & bdi_bits;
+			r = md->queue->backing_dev_info->wb.state & bdi_bits;
 		} else {
 			map = dm_get_live_table_fast(md);
 			if (map)
@@ -1463,7 +1463,7 @@
 	 * - must do so here (in alloc_dev callchain) before queue is used
 	 */
 	md->queue->queuedata = md;
-	md->queue->backing_dev_info.congested_data = md;
+	md->queue->backing_dev_info->congested_data = md;
 }
 
 void dm_init_normal_md_queue(struct mapped_device *md)
@@ -1474,7 +1474,7 @@
 	/*
 	 * Initialize aspects of queue that aren't relevant for blk-mq
 	 */
-	md->queue->backing_dev_info.congested_fn = dm_any_congested;
+	md->queue->backing_dev_info->congested_fn = dm_any_congested;
 	blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
 }
 
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 12abf69..be51805 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -68,7 +68,7 @@
 
 	for (i = 0; i < conf->raid_disks && !ret ; i++) {
 		struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 
 	rcu_read_unlock();
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8ebf1b9..df7d606 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5312,8 +5312,8 @@
 			queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
 		else
 			queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
-		mddev->queue->backing_dev_info.congested_data = mddev;
-		mddev->queue->backing_dev_info.congested_fn = md_congested;
+		mddev->queue->backing_dev_info->congested_data = mddev;
+		mddev->queue->backing_dev_info->congested_fn = md_congested;
 	}
 	if (pers->sync_request) {
 		if (mddev->kobj.sd &&
@@ -5668,7 +5668,7 @@
 
 		__md_stop_writes(mddev);
 		__md_stop(mddev);
-		mddev->queue->backing_dev_info.congested_fn = NULL;
+		mddev->queue->backing_dev_info->congested_fn = NULL;
 
 		/* tell userspace to handle 'inactive' */
 		sysfs_notify_dirent_safe(mddev->sysfs_state);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 673efbd..6a7855a 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -169,7 +169,7 @@
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 			/* Just like multipath_map, we just check the
 			 * first available device
 			 */
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index 7a75b50..e4ececd 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -678,23 +678,8 @@
 	pn->keys[1] = rn->keys[0];
 	memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
 
-	/*
-	 * rejig the spine.  This is ugly, since it knows too
-	 * much about the spine
-	 */
-	if (s->nodes[0] != new_parent) {
-		unlock_block(s->info, s->nodes[0]);
-		s->nodes[0] = new_parent;
-	}
-	if (key < le64_to_cpu(rn->keys[0])) {
-		unlock_block(s->info, right);
-		s->nodes[1] = left;
-	} else {
-		unlock_block(s->info, left);
-		s->nodes[1] = right;
-	}
-	s->count = 2;
-
+	unlock_block(s->info, left);
+	unlock_block(s->info, right);
 	return 0;
 }
 
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 258986a..3716dae 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -35,7 +35,7 @@
 	for (i = 0; i < raid_disks && !ret ; i++) {
 		struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
 
-		ret |= bdi_congested(&q->backing_dev_info, bits);
+		ret |= bdi_congested(q->backing_dev_info, bits);
 	}
 	return ret;
 }
@@ -415,8 +415,8 @@
 		 */
 		int stripe = mddev->raid_disks *
 			(mddev->chunk_sectors << 9) / PAGE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2* stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2* stripe;
 	}
 
 	dump_zones(mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 81a7875..208fbf7 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -717,9 +717,9 @@
 			 * non-congested targets, it can be removed
 			 */
 			if ((bits & (1 << WB_async_congested)) || 1)
-				ret |= bdi_congested(&q->backing_dev_info, bits);
+				ret |= bdi_congested(q->backing_dev_info, bits);
 			else
-				ret &= bdi_congested(&q->backing_dev_info, bits);
+				ret &= bdi_congested(q->backing_dev_info, bits);
 		}
 	}
 	rcu_read_unlock();
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index b19b551..8d40238 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -833,7 +833,7 @@
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-			ret |= bdi_congested(&q->backing_dev_info, bits);
+			ret |= bdi_congested(q->backing_dev_info, bits);
 		}
 	}
 	rcu_read_unlock();
@@ -3754,8 +3754,8 @@
 		 * maybe...
 		 */
 		stripe /= conf->geo.near_copies;
-		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 	}
 
 	if (md_integrity_register(mddev))
@@ -4557,8 +4557,8 @@
 		int stripe = conf->geo.raid_disks *
 			((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
 		stripe /= conf->geo.near_copies;
-		if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 	}
 	conf->fullsync = 0;
 }
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 475a7a1..90d863e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6155,10 +6155,10 @@
 		mddev_suspend(mddev);
 		conf->skip_copy = new;
 		if (new)
-			mddev->queue->backing_dev_info.capabilities |=
+			mddev->queue->backing_dev_info->capabilities |=
 				BDI_CAP_STABLE_WRITES;
 		else
-			mddev->queue->backing_dev_info.capabilities &=
+			mddev->queue->backing_dev_info->capabilities &=
 				~BDI_CAP_STABLE_WRITES;
 		mddev_resume(mddev);
 	}
@@ -6984,8 +6984,8 @@
 		int data_disks = conf->previous_raid_disks - conf->max_degraded;
 		int stripe = data_disks *
 			((mddev->chunk_sectors << 9) / PAGE_SIZE);
-		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+			mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 
 		chunk_size = mddev->chunk_sectors << 9;
 		blk_queue_io_min(mddev->queue, chunk_size);
@@ -7591,8 +7591,8 @@
 			int data_disks = conf->raid_disks - conf->max_degraded;
 			int stripe = data_disks * ((conf->chunk_sectors << 9)
 						   / PAGE_SIZE);
-			if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-				conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+			if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+				conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 		}
 	}
 }
diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c
index ad304ee..c61227c 100644
--- a/drivers/media/dvb-frontends/ascot2e.c
+++ b/drivers/media/dvb-frontends/ascot2e.c
@@ -155,7 +155,9 @@
 
 static int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val)
 {
-	return ascot2e_write_regs(priv, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return ascot2e_write_regs(priv, reg, &tmp, 1);
 }
 
 static int ascot2e_read_regs(struct ascot2e_priv *priv,
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
index fd0f25e..b97647c 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -261,7 +261,9 @@
 static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
 			       u8 addr, u8 reg, u8 val)
 {
-	return cxd2841er_write_regs(priv, addr, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return cxd2841er_write_regs(priv, addr, reg, &tmp, 1);
 }
 
 static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c
index dc43c5f..e06bcd4 100644
--- a/drivers/media/dvb-frontends/helene.c
+++ b/drivers/media/dvb-frontends/helene.c
@@ -331,7 +331,9 @@
 
 static int helene_write_reg(struct helene_priv *priv, u8 reg, u8 val)
 {
-	return helene_write_regs(priv, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return helene_write_regs(priv, reg, &tmp, 1);
 }
 
 static int helene_read_regs(struct helene_priv *priv,
diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c
index 0c089b5..4ebddc8 100644
--- a/drivers/media/dvb-frontends/horus3a.c
+++ b/drivers/media/dvb-frontends/horus3a.c
@@ -89,7 +89,9 @@
 
 static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
 {
-	return horus3a_write_regs(priv, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return horus3a_write_regs(priv, reg, &tmp, 1);
 }
 
 static int horus3a_enter_power_save(struct horus3a_priv *priv)
diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c
index cadcae4..ac9d259 100644
--- a/drivers/media/dvb-frontends/itd1000.c
+++ b/drivers/media/dvb-frontends/itd1000.c
@@ -99,8 +99,9 @@
 
 static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
 {
-	int ret = itd1000_write_regs(state, r, &v, 1);
-	state->shadow[r] = v;
+	u8 tmp = v; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+	int ret = itd1000_write_regs(state, r, &tmp, 1);
+	state->shadow[r] = tmp;
 	return ret;
 }
 
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index fc08429..7824926 100644
--- a/drivers/media/dvb-frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -142,7 +142,10 @@
 static inline int mt312_writereg(struct mt312_state *state,
 				 const enum mt312_reg_addr reg, const u8 val)
 {
-	return mt312_write(state, reg, &val, 1);
+	u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+
+	return mt312_write(state, reg, &tmp, 1);
 }
 
 static inline u32 mt312_div(u32 a, u32 b)
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 3d171b0..3deddbc 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -552,7 +552,8 @@
 
 int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
 {
-	return stb0899_write_regs(state, reg, &data, 1);
+	u8 tmp = data;
+	return stb0899_write_regs(state, reg, &tmp, 1);
 }
 
 /*
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index 5add118..4746b1e 100644
--- a/drivers/media/dvb-frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -226,12 +226,14 @@
 
 static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
 {
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
 	if (unlikely(reg >= STB6100_NUMREGS)) {
 		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
 		return -EREMOTEIO;
 	}
-	data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
-	return stb6100_write_reg_range(state, &data, reg, 1);
+	tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set;
+	return stb6100_write_reg_range(state, &tmp, reg, 1);
 }
 
 
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index abc379a..94cec81 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -804,7 +804,9 @@
 
 static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
 {
-	return stv0367_writeregs(state, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv0367_writeregs(state, reg, &tmp, 1);
 }
 
 static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 25bdf6e..f0377e2 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -761,7 +761,9 @@
 
 static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
 {
-	return stv090x_write_regs(state, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv090x_write_regs(state, reg, &tmp, 1);
 }
 
 static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index c611ad2..924f16f 100644
--- a/drivers/media/dvb-frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -97,7 +97,9 @@
 
 static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
 {
-	return stv6110x_write_regs(stv6110x, reg, &data, 1);
+	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return stv6110x_write_regs(stv6110x, reg, &tmp, 1);
 }
 
 static int stv6110x_init(struct dvb_frontend *fe)
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index a9f6bbe..103b9c8 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -369,7 +369,7 @@
 		gain2 = clamp_t(long, gain2, 0, 13);
 		v_agc = clamp_t(long, v_agc, 400, 1100);
 
-		*_gain = -(gain1 * 2330 +
+		*_gain = -((__s64)gain1 * 2330 +
 			   gain2 * 3500 +
 			   v_agc * 24 / 10 * 10 +
 			   10000);
@@ -387,7 +387,7 @@
 		gain3 = clamp_t(long, gain3, 0, 6);
 		v_agc = clamp_t(long, v_agc, 600, 1600);
 
-		*_gain = -(gain1 * 2650 +
+		*_gain = -((__s64)gain1 * 2650 +
 			   gain2 * 3380 +
 			   gain3 * 2850 +
 			   v_agc * 176 / 100 * 10 -
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
index f8c271b..0d2bef6 100644
--- a/drivers/media/dvb-frontends/zl10039.c
+++ b/drivers/media/dvb-frontends/zl10039.c
@@ -138,7 +138,9 @@
 				const enum zl10039_reg_addr reg,
 				const u8 val)
 {
-	return zl10039_write(state, reg, &val, 1);
+	const u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
+
+	return zl10039_write(state, reg, &tmp, 1);
 }
 
 static int zl10039_init(struct dvb_frontend *fe)
diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig
index 484819d..9e4ea8d 100644
--- a/drivers/media/platform/msm/Kconfig
+++ b/drivers/media/platform/msm/Kconfig
@@ -13,8 +13,44 @@
       Enabling this adds support for the camera driver stack including sensor,
       IFE and postprocessing drivers.
 
-source "drivers/media/platform/msm/vidc/Kconfig"
+menuconfig MSM_CAMERA
+    bool "QTI MSM camera and video capture support"
+    depends on ARCH_QCOM && VIDEO_V4L2 && I2C
+    ---help---
+      Say Y here to enable selecting the video adapters for
+      QTI msm camera and video capture drivers. enabling this
+      adds support for the camera driver stack including sensor, isp
+      and postprocessing drivers for legacy chipsets.
 
+config MSM_CAMERA_DEBUG
+    bool "QTI MSM camera debugging with printk"
+    depends on MSM_CAMERA
+    default n
+    ---help---
+      Enable printk() debug for msm camera
+
+menuconfig MSMB_CAMERA
+    bool "QTI MSM camera and video capture 2.0 support"
+    depends on ARCH_QCOM && VIDEO_V4L2 && I2C
+    ---help---
+      Say Y here to enable selecting the video adapters for
+      QTI msm camera and video capture 2.0, enabling this
+      adds support for the camera driver stack including sensor, isp
+      and postprocessing drivers.
+
+config MSMB_CAMERA_DEBUG
+    bool "QTI MSM camera 2.0 debugging with printk"
+    depends on MSMB_CAMERA
+    ---help---
+      Enable printk() debug for msm camera 2.0
+
+if MSMB_CAMERA
+source "drivers/media/platform/msm/camera_v2/Kconfig"
+endif # MSMB_CAMERA
+
+source "drivers/media/platform/msm/vidc_3x/Kconfig"
+source "drivers/media/platform/msm/vidc/Kconfig"
 source "drivers/media/platform/msm/sde/Kconfig"
 source "drivers/media/platform/msm/dvb/Kconfig"
 source "drivers/media/platform/msm/broadcast/Kconfig"
+
diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile
index e64bcd1..24c27cd 100644
--- a/drivers/media/platform/msm/Makefile
+++ b/drivers/media/platform/msm/Makefile
@@ -3,7 +3,9 @@
 # based on V4L2.
 #
 obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) += vidc_3x/
 obj-y += sde/
 obj-$(CONFIG_SPECTRA_CAMERA) += camera/
+obj-$(CONFIG_MSMB_CAMERA) += camera_v2/
 obj-y += broadcast/
 obj-$(CONFIG_DVB_MPQ) += dvb/
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index 7e6d999..98fff48 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -196,10 +196,35 @@
 	return rc;
 }
 
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *process_evt)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context is not ready");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.process_evt) {
+		rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx,
+			process_evt);
+	} else {
+		/* handling of this message is optional */
+		CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d",
+			ctx->dev_hdl, ctx->state);
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
 int cam_context_handle_acquire_dev(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
 	int rc;
+	int i;
 
 	if (!ctx->state_machine) {
 		CAM_ERR(CAM_CORE, "Context is not ready");
@@ -220,6 +245,17 @@
 			cmd->dev_handle, ctx->state);
 		rc = -EPROTO;
 	}
+
+	INIT_LIST_HEAD(&ctx->active_req_list);
+	INIT_LIST_HEAD(&ctx->wait_req_list);
+	INIT_LIST_HEAD(&ctx->pending_req_list);
+	INIT_LIST_HEAD(&ctx->free_req_list);
+
+	for (i = 0; i < ctx->req_size; i++) {
+		INIT_LIST_HEAD(&ctx->req_list[i].list);
+		list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list);
+	}
+
 	mutex_unlock(&ctx->ctx_mutex);
 
 	return rc;
@@ -257,10 +293,10 @@
 int cam_context_handle_flush_dev(struct cam_context *ctx,
 	struct cam_flush_dev_cmd *cmd)
 {
-	int rc;
+	int rc = 0;
 
 	if (!ctx->state_machine) {
-		CAM_ERR(CAM_CORE, "context is not ready");
+		CAM_ERR(CAM_CORE, "Context is not ready");
 		return -EINVAL;
 	}
 
@@ -274,9 +310,8 @@
 		rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev(
 			ctx, cmd);
 	} else {
-		CAM_ERR(CAM_CORE, "No flush device in dev %d, state %d",
+		CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d",
 			ctx->dev_hdl, ctx->state);
-		rc = -EPROTO;
 	}
 	mutex_unlock(&ctx->ctx_mutex);
 
@@ -371,6 +406,8 @@
 
 int cam_context_init(struct cam_context *ctx,
 	const char *dev_name,
+	uint64_t dev_id,
+	uint32_t ctx_id,
 	struct cam_req_mgr_kmd_ops *crm_node_intf,
 	struct cam_hw_mgr_intf *hw_mgr_intf,
 	struct cam_ctx_request *req_list,
@@ -394,6 +431,8 @@
 	spin_lock_init(&ctx->lock);
 
 	ctx->dev_name = dev_name;
+	ctx->dev_id = dev_id;
+	ctx->ctx_id = ctx_id;
 	ctx->ctx_crm_intf = NULL;
 	ctx->crm_ctx_intf = crm_node_intf;
 	ctx->hw_mgr_intf = hw_mgr_intf;
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index c823b7a..8324e78 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -110,6 +110,7 @@
  * @unlink:                Unlink the context
  * @apply_req:             Apply setting for the context
  * @flush_req:             Flush request to remove request ids
+ * @process_evt:           Handle event notification from CRM.(optional)
  *
  */
 struct cam_ctx_crm_ops {
@@ -123,6 +124,8 @@
 			struct cam_req_mgr_apply_request *apply);
 	int (*flush_req)(struct cam_context *ctx,
 			struct cam_req_mgr_flush_request *flush);
+	int (*process_evt)(struct cam_context *ctx,
+			struct cam_req_mgr_link_evt_data *evt_data);
 };
 
 
@@ -144,6 +147,8 @@
  * struct cam_context - camera context object for the subdevice node
  *
  * @dev_name:              String giving name of device associated
+ * @dev_id:                ID of device associated
+ * @ctx_id:                ID for this context
  * @list:                  Link list entry
  * @sessoin_hdl:           Session handle
  * @dev_hdl:               Device handle
@@ -171,6 +176,8 @@
  */
 struct cam_context {
 	const char                  *dev_name;
+	uint64_t                     dev_id;
+	uint32_t                     ctx_id;
 	struct list_head             list;
 	int32_t                      session_hdl;
 	int32_t                      dev_hdl;
@@ -273,6 +280,18 @@
 		struct cam_req_mgr_flush_request *apply);
 
 /**
+ * cam_context_handle_crm_process_evt()
+ *
+ * @brief:        Handle process event command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @process_evt:  process event command payload
+ *
+ */
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *process_evt);
+
+/**
  * cam_context_handle_acquire_dev()
  *
  * @brief:        Handle acquire device command
@@ -361,6 +380,8 @@
  *
  * @ctx:                   Object pointer for cam_context
  * @dev_name:              String giving name of device associated
+ * @dev_id:                ID of the device associated
+ * @ctx_id:                ID for this context
  * @crm_node_intf:         Function table for crm to context interface
  * @hw_mgr_intf:           Function table for context to hw interface
  * @req_list:              Requests storage
@@ -369,6 +390,8 @@
  */
 int cam_context_init(struct cam_context *ctx,
 		const char *dev_name,
+		uint64_t dev_id,
+		uint32_t ctx_id,
 		struct cam_req_mgr_kmd_ops *crm_node_intf,
 		struct cam_hw_mgr_intf *hw_mgr_intf,
 		struct cam_ctx_request *req_list,
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index aab1a1a..b85f00b 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -26,6 +26,9 @@
 #include "cam_trace.h"
 #include "cam_debug_util.h"
 
+static uint cam_debug_ctx_req_list;
+module_param(cam_debug_ctx_req_list, uint, 0644);
+
 static inline int cam_context_validate_thread(void)
 {
 	if (in_interrupt()) {
@@ -56,7 +59,8 @@
 
 	spin_lock(&ctx->lock);
 	if (list_empty(&ctx->active_req_list)) {
-		CAM_ERR(CAM_CTXT, "no active request");
+		CAM_ERR(CAM_CTXT, "[%s][%d] no active request",
+			ctx->dev_name, ctx->ctx_id);
 		spin_unlock(&ctx->lock);
 		return -EIO;
 	}
@@ -66,14 +70,17 @@
 	trace_cam_buf_done("UTILS", ctx, req);
 
 	if (done->request_id != req->request_id) {
-		CAM_ERR(CAM_CTXT, "mismatch: done req[%lld], active req[%lld]",
+		CAM_ERR(CAM_CTXT,
+			"[%s][%d] mismatch: done req[%lld], active req[%lld]",
+			ctx->dev_name, ctx->ctx_id,
 			done->request_id, req->request_id);
 		spin_unlock(&ctx->lock);
 		return -EIO;
 	}
 
 	if (!req->num_out_map_entries) {
-		CAM_ERR(CAM_CTXT, "no output fence to signal");
+		CAM_ERR(CAM_CTXT, "[%s][%d] no output fence to signal",
+			ctx->dev_name, ctx->ctx_id);
 		spin_unlock(&ctx->lock);
 		return -EIO;
 	}
@@ -94,6 +101,11 @@
 		req->out_map_entries[j].sync_id = -1;
 	}
 
+	if (cam_debug_ctx_req_list & ctx->dev_id)
+		CAM_INFO(CAM_CTXT,
+			"[%s][%d] : Moving req[%llu] from active_list to free_list",
+			ctx->dev_name, ctx->ctx_id, req->request_id);
+
 	/*
 	 * another thread may be adding/removing from free list,
 	 * so hold the lock
@@ -114,7 +126,8 @@
 	struct cam_hw_config_args cfg;
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -124,6 +137,11 @@
 	list_add_tail(&req->list, &ctx->active_req_list);
 	spin_unlock(&ctx->lock);
 
+	if (cam_debug_ctx_req_list & ctx->dev_id)
+		CAM_INFO(CAM_CTXT,
+			"[%s][%d] : Moving req[%llu] from pending_list to active_list",
+			ctx->dev_name, ctx->ctx_id, req->request_id);
+
 	cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
 	cfg.hw_update_entries = req->hw_update_entries;
 	cfg.num_hw_update_entries = req->num_hw_update_entries;
@@ -135,7 +153,13 @@
 	if (rc) {
 		spin_lock(&ctx->lock);
 		list_del_init(&req->list);
+		list_add_tail(&req->list, &ctx->free_req_list);
 		spin_unlock(&ctx->lock);
+
+		if (cam_debug_ctx_req_list & ctx->dev_id)
+			CAM_INFO(CAM_CTXT,
+				"[%s][%d] : Moving req[%llu] from active_list to free_list",
+				ctx->dev_name, ctx->ctx_id, req->request_id);
 	}
 
 end:
@@ -159,6 +183,11 @@
 		return;
 
 	ctx = req->ctx;
+	if (!ctx) {
+		CAM_ERR(CAM_CTXT, "Invalid ctx for req %llu", req->request_id);
+		return;
+	}
+
 	req->num_in_acked++;
 	if (req->num_in_acked == req->num_in_map_entries) {
 		apply.request_id = req->request_id;
@@ -174,8 +203,6 @@
 			CAM_DBG(CAM_CTXT, "fence error: %d", sync_obj);
 			flush_cmd.req_id = req->request_id;
 			cam_context_flush_req_to_hw(ctx, &flush_cmd);
-			cam_context_putref(ctx);
-			return;
 		}
 
 		mutex_lock(&ctx->sync_mutex);
@@ -190,6 +217,12 @@
 			list_del_init(&req->list);
 			list_add_tail(&req->list, &ctx->free_req_list);
 			spin_unlock(&ctx->lock);
+
+			if (cam_debug_ctx_req_list & ctx->dev_id)
+				CAM_INFO(CAM_CTXT,
+					"[%s][%d] : Moving req[%llu] from pending_list to free_list",
+					ctx->dev_name, ctx->ctx_id,
+					req->request_id);
 		}
 	}
 	cam_context_putref(ctx);
@@ -206,7 +239,8 @@
 	}
 
 	if ((!ctx->hw_mgr_intf) || (!ctx->hw_mgr_intf->hw_release)) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		return -EINVAL;
 	}
 
@@ -241,7 +275,8 @@
 	}
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -258,7 +293,8 @@
 	spin_unlock(&ctx->lock);
 
 	if (!req) {
-		CAM_ERR(CAM_CTXT, "No more request obj free");
+		CAM_ERR(CAM_CTXT, "[%s][%d] No more request obj free",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -ENOMEM;
 		goto end;
 	}
@@ -273,7 +309,8 @@
 		(uint64_t *) &packet_addr,
 		&len);
 	if (rc != 0) {
-		CAM_ERR(CAM_CTXT, "Can not get packet address");
+		CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EINVAL;
 		goto free_req;
 	}
@@ -295,7 +332,9 @@
 	rc = ctx->hw_mgr_intf->hw_prepare_update(
 		ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
 	if (rc != 0) {
-		CAM_ERR(CAM_CTXT, "Prepare config packet failed in HW layer");
+		CAM_ERR(CAM_CTXT,
+			"[%s][%d] Prepare config packet failed in HW layer",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto free_req;
 	}
@@ -310,6 +349,12 @@
 		spin_lock(&ctx->lock);
 		list_add_tail(&req->list, &ctx->pending_req_list);
 		spin_unlock(&ctx->lock);
+
+		if (cam_debug_ctx_req_list & ctx->dev_id)
+			CAM_INFO(CAM_CTXT,
+				"[%s][%d] : Moving req[%llu] from free_list to pending_list",
+				ctx->dev_name, ctx->ctx_id, req->request_id);
+
 		for (i = 0; i < req->num_in_map_entries; i++) {
 			cam_context_getref(ctx);
 			rc = cam_sync_register_callback(
@@ -318,9 +363,21 @@
 					req->in_map_entries[i].sync_id);
 			if (rc) {
 				CAM_ERR(CAM_CTXT,
-					"Failed register fence cb: %d ret = %d",
+					"[%s][%d] Failed register fence cb: %d ret = %d",
+					ctx->dev_name, ctx->ctx_id,
 					req->in_map_entries[i].sync_id, rc);
+				spin_lock(&ctx->lock);
+				list_del_init(&req->list);
+				spin_unlock(&ctx->lock);
+
+				if (cam_debug_ctx_req_list & ctx->dev_id)
+					CAM_INFO(CAM_CTXT,
+						"[%s][%d] : Moving req[%llu] from pending_list to free_list",
+						ctx->dev_name, ctx->ctx_id,
+						req->request_id);
+
 				cam_context_putref(ctx);
+
 				goto free_req;
 			}
 			CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d",
@@ -355,7 +412,8 @@
 	}
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -365,14 +423,16 @@
 		cmd->resource_hdl);
 
 	if (cmd->num_resources > CAM_CTX_RES_MAX) {
-		CAM_ERR(CAM_CTXT, "resource limit exceeded");
+		CAM_ERR(CAM_CTXT, "[%s][%d] resource limit exceeded",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -ENOMEM;
 		goto end;
 	}
 
 	/* for now we only support user pointer */
 	if (cmd->handle_type != 1)  {
-		CAM_ERR(CAM_CTXT, "Only user pointer is supported");
+		CAM_ERR(CAM_CTXT, "[%s][%d] Only user pointer is supported",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EINVAL;
 		goto end;
 	}
@@ -387,7 +447,8 @@
 	rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv,
 		&param);
 	if (rc != 0) {
-		CAM_ERR(CAM_CTXT, "Acquire device failed");
+		CAM_ERR(CAM_CTXT, "[%s][%d] Acquire device failed",
+			ctx->dev_name, ctx->ctx_id);
 		goto end;
 	}
 
@@ -404,7 +465,8 @@
 	ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
 	if (ctx->dev_hdl <= 0) {
 		rc = -EFAULT;
-		CAM_ERR(CAM_CTXT, "Can not create device handle");
+		CAM_ERR(CAM_CTXT, "[%s][%d] Can not create device handle",
+			ctx->dev_name, ctx->ctx_id);
 		goto free_hw;
 	}
 	cmd->dev_handle = ctx->dev_hdl;
@@ -430,6 +492,8 @@
 	uint32_t i;
 	int rc = 0;
 
+	CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name);
+
 	/*
 	 * flush pending requests, take the sync lock to synchronize with the
 	 * sync callback thread so that the sync cb thread does not try to
@@ -440,27 +504,56 @@
 	spin_lock(&ctx->lock);
 	list_splice_init(&ctx->pending_req_list, &temp_list);
 	spin_unlock(&ctx->lock);
+
+	if (cam_debug_ctx_req_list & ctx->dev_id)
+		CAM_INFO(CAM_CTXT,
+			"[%s][%d] : Moving all pending requests from pending_list to temp_list",
+			ctx->dev_name, ctx->ctx_id);
+
 	flush_args.num_req_pending = 0;
-	while (!list_empty(&temp_list)) {
+	while (true) {
+		spin_lock(&ctx->lock);
+		if (list_empty(&temp_list)) {
+			spin_unlock(&ctx->lock);
+			break;
+		}
+
 		req = list_first_entry(&temp_list,
 				struct cam_ctx_request, list);
+
 		list_del_init(&req->list);
+		spin_unlock(&ctx->lock);
 		req->flushed = 1;
+
 		flush_args.flush_req_pending[flush_args.num_req_pending++] =
 			req->req_priv;
-		for (i = 0; i < req->num_out_map_entries; i++)
-			if (req->out_map_entries[i].sync_id != -1)
-				cam_sync_signal(req->out_map_entries[i].sync_id,
+		for (i = 0; i < req->num_out_map_entries; i++) {
+			if (req->out_map_entries[i].sync_id != -1) {
+				rc = cam_sync_signal(
+					req->out_map_entries[i].sync_id,
 					CAM_SYNC_STATE_SIGNALED_ERROR);
+				if (rc == -EALREADY) {
+					CAM_ERR(CAM_CTXT,
+						"Req: %llu already signalled, sync_id:%d",
+						req->request_id,
+						req->out_map_entries[i].
+						sync_id);
+					break;
+				}
+			}
+		}
+
+		if (cam_debug_ctx_req_list & ctx->dev_id)
+			CAM_INFO(CAM_CTXT,
+				"[%s][%d] : Deleting req[%llu] from temp_list",
+				ctx->dev_name, ctx->ctx_id, req->request_id);
 	}
 	mutex_unlock(&ctx->sync_mutex);
 
 	if (ctx->hw_mgr_intf->hw_flush) {
 		flush_args.num_req_active = 0;
 		spin_lock(&ctx->lock);
-		INIT_LIST_HEAD(&temp_list);
-		list_splice_init(&ctx->active_req_list, &temp_list);
-		list_for_each_entry(req, &temp_list, list) {
+		list_for_each_entry(req, &ctx->active_req_list, list) {
 			flush_args.flush_req_active[flush_args.num_req_active++]
 				= req->req_priv;
 		}
@@ -474,24 +567,59 @@
 		}
 	}
 
-	while (!list_empty(&temp_list)) {
+	INIT_LIST_HEAD(&temp_list);
+	spin_lock(&ctx->lock);
+	list_splice_init(&ctx->active_req_list, &temp_list);
+	INIT_LIST_HEAD(&ctx->active_req_list);
+	spin_unlock(&ctx->lock);
+
+	if (cam_debug_ctx_req_list & ctx->dev_id)
+		CAM_INFO(CAM_CTXT,
+			"[%s][%d] : Moving all requests from active_list to temp_list",
+			ctx->dev_name, ctx->ctx_id);
+
+	while (true) {
+		spin_lock(&ctx->lock);
+		if (list_empty(&temp_list)) {
+			spin_unlock(&ctx->lock);
+			break;
+		}
 		req = list_first_entry(&temp_list,
 			struct cam_ctx_request, list);
 		list_del_init(&req->list);
-		for (i = 0; i < req->num_out_map_entries; i++)
+		spin_unlock(&ctx->lock);
+
+		for (i = 0; i < req->num_out_map_entries; i++) {
 			if (req->out_map_entries[i].sync_id != -1) {
-				cam_sync_signal(req->out_map_entries[i].sync_id,
+				rc = cam_sync_signal(
+					req->out_map_entries[i].sync_id,
 					CAM_SYNC_STATE_SIGNALED_ERROR);
+				if (rc == -EALREADY) {
+					CAM_ERR(CAM_CTXT,
+						"Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d",
+						req->request_id, req->ctx,
+						req->ctx->dev_name,
+						req->ctx->dev_hdl,
+						req->ctx->state);
+					break;
+				}
 			}
+		}
 
 		spin_lock(&ctx->lock);
 		list_add_tail(&req->list, &ctx->free_req_list);
 		spin_unlock(&ctx->lock);
 		req->ctx = NULL;
-	}
-	INIT_LIST_HEAD(&ctx->active_req_list);
 
-	return rc;
+		if (cam_debug_ctx_req_list & ctx->dev_id)
+			CAM_INFO(CAM_CTXT,
+				"[%s][%d] : Moving req[%llu] from temp_list to free_list",
+				ctx->dev_name, ctx->ctx_id, req->request_id);
+	}
+
+	CAM_DBG(CAM_CTXT, "[%s] X: NRT flush ctx", ctx->dev_name);
+
+	return 0;
 }
 
 int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
@@ -502,6 +630,8 @@
 	uint32_t i;
 	int rc = 0;
 
+	CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name);
+
 	flush_args.num_req_pending = 0;
 	flush_args.num_req_active = 0;
 	mutex_lock(&ctx->sync_mutex);
@@ -510,7 +640,14 @@
 		if (req->request_id != cmd->req_id)
 			continue;
 
+		if (cam_debug_ctx_req_list & ctx->dev_id)
+			CAM_INFO(CAM_CTXT,
+				"[%s][%d] : Deleting req[%llu] from pending_list",
+				ctx->dev_name, ctx->ctx_id, req->request_id);
+
+		list_del_init(&req->list);
 		req->flushed = 1;
+
 		flush_args.flush_req_pending[flush_args.num_req_pending++] =
 			req->req_priv;
 		break;
@@ -525,6 +662,8 @@
 				if (req->request_id != cmd->req_id)
 					continue;
 
+				list_del_init(&req->list);
+
 				flush_args.flush_req_active[
 					flush_args.num_req_active++] =
 					req->req_priv;
@@ -543,20 +682,37 @@
 
 	if (req) {
 		if (flush_args.num_req_pending || flush_args.num_req_active) {
-			list_del_init(&req->list);
 			for (i = 0; i < req->num_out_map_entries; i++)
-				if (req->out_map_entries[i].sync_id != -1)
-					cam_sync_signal(
+				if (req->out_map_entries[i].sync_id != -1) {
+					rc = cam_sync_signal(
 						req->out_map_entries[i].sync_id,
 						CAM_SYNC_STATE_SIGNALED_ERROR);
-			spin_lock(&ctx->lock);
-			list_add_tail(&req->list, &ctx->free_req_list);
-			spin_unlock(&ctx->lock);
-			req->ctx = NULL;
+					if (rc == -EALREADY) {
+						CAM_ERR(CAM_CTXT,
+							"Req: %llu already signalled, sync_id:%d",
+							req->request_id,
+							req->out_map_entries[i].
+							sync_id);
+						break;
+					}
+				}
+			if (flush_args.num_req_active) {
+				spin_lock(&ctx->lock);
+				list_add_tail(&req->list, &ctx->free_req_list);
+				spin_unlock(&ctx->lock);
+				req->ctx = NULL;
+
+				if (cam_debug_ctx_req_list & ctx->dev_id)
+					CAM_INFO(CAM_CTXT,
+						"[%s][%d] : Moving req[%llu] from active_list to free_list",
+						ctx->dev_name, ctx->ctx_id,
+						req->request_id);
+			}
 		}
 	}
+	CAM_DBG(CAM_CTXT, "[%s] X: NRT flush req", ctx->dev_name);
 
-	return rc;
+	return 0;
 }
 
 int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx,
@@ -572,7 +728,8 @@
 	}
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -583,7 +740,8 @@
 		rc = cam_context_flush_req_to_hw(ctx, cmd);
 	else {
 		rc = -EINVAL;
-		CAM_ERR(CAM_CORE, "Invalid flush type %d", cmd->flush_type);
+		CAM_ERR(CAM_CORE, "[%s][%d] Invalid flush type %d",
+			ctx->dev_name, ctx->ctx_id, cmd->flush_type);
 	}
 
 end:
@@ -603,14 +761,17 @@
 	}
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
 
 	if ((cmd->session_handle != ctx->session_hdl) ||
 		(cmd->dev_handle != ctx->dev_hdl)) {
-		CAM_ERR(CAM_CTXT, "Invalid session hdl[%d], dev_handle[%d]",
+		CAM_ERR(CAM_CTXT,
+			"[%s][%d] Invalid session hdl[%d], dev_handle[%d]",
+			ctx->dev_name, ctx->ctx_id,
 			cmd->session_handle, cmd->dev_handle);
 		rc = -EPERM;
 		goto end;
@@ -622,7 +783,8 @@
 				&arg);
 		if (rc) {
 			/* HW failure. user need to clean up the resource */
-			CAM_ERR(CAM_CTXT, "Start HW failed");
+			CAM_ERR(CAM_CTXT, "[%s][%d] Start HW failed",
+				ctx->dev_name, ctx->ctx_id);
 			goto end;
 		}
 	}
@@ -643,7 +805,8 @@
 	}
 
 	if (!ctx->hw_mgr_intf) {
-		CAM_ERR(CAM_CTXT, "HW interface is not ready");
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -652,11 +815,9 @@
 	if (rc)
 		goto end;
 
-	if (ctx->ctxt_to_hw_map) {
-		rc = cam_context_flush_ctx_to_hw(ctx);
-		if (rc)
-			goto end;
-	}
+	rc = cam_context_flush_ctx_to_hw(ctx);
+	if (rc)
+		goto end;
 
 	/* stop hw first */
 	if (ctx->hw_mgr_intf->hw_stop) {
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index a90b3d9..cf1859c 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -123,10 +123,12 @@
  * struct cam_hw_stop_args - Payload for stop command
  *
  * @ctxt_to_hw_map:        HW context from the acquire
+ * @args:                  Arguments to pass for stop
  *
  */
 struct cam_hw_stop_args {
 	void              *ctxt_to_hw_map;
+	void              *args;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index a5977b3..4e9034e 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -220,7 +220,7 @@
 
 	rc = cam_context_handle_flush_dev(ctx, flush);
 	if (rc)
-		CAM_ERR(CAM_CORE, "FLush failure for node %s", node->name);
+		CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name);
 
 	return rc;
 }
@@ -342,6 +342,25 @@
 	return cam_context_handle_crm_flush_req(ctx, flush);
 }
 
+static int __cam_node_crm_process_evt(
+	struct cam_req_mgr_link_evt_data *evt_data)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!evt_data) {
+		CAM_ERR(CAM_CORE, "Invalid process event request payload");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl);
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+			evt_data->dev_hdl);
+		return -EINVAL;
+	}
+	return cam_context_handle_crm_process_evt(ctx, evt_data);
+}
+
 int cam_node_deinit(struct cam_node *node)
 {
 	if (node)
@@ -394,6 +413,7 @@
 	node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
 	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
 	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
+	node->crm_node_intf.process_evt = __cam_node_crm_process_evt;
 
 	mutex_init(&node->list_mutex);
 	INIT_LIST_HEAD(&node->free_ctx_list);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index 3ebe7a1..e7de207 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,12 +16,19 @@
 #include <linux/msm-bus.h>
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "cam_cpas_hw.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_soc.h"
 
-#define CAM_CPAS_AXI_MIN_BW (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_MNOC_AB_BW   (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_MNOC_IB_BW   (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L)
+
+static uint cam_min_camnoc_ib_bw;
+module_param(cam_min_camnoc_ib_bw, uint, 0644);
 
 int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
 	enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info)
@@ -84,11 +91,19 @@
 }
 
 static int cam_cpas_util_vote_bus_client_bw(
-	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib)
+	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
+	bool camnoc_bw)
 {
 	struct msm_bus_paths *path;
 	struct msm_bus_scale_pdata *pdata;
 	int idx = 0;
+	uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
+
+	if (cam_min_camnoc_ib_bw > 0)
+		min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;
+
+	CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
+		cam_min_camnoc_ib_bw, min_camnoc_ib_bw);
 
 	if (!bus_client->valid) {
 		CAM_ERR(CAM_CPAS, "bus client not valid");
@@ -118,11 +133,19 @@
 	bus_client->curr_vote_level = idx;
 	mutex_unlock(&bus_client->lock);
 
-	if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_BW))
-		ab = CAM_CPAS_AXI_MIN_BW;
+	if (camnoc_bw == true) {
+		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW))
+			ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW;
 
-	if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_BW))
-		ib = CAM_CPAS_AXI_MIN_BW;
+		if ((ib > 0) && (ib < min_camnoc_ib_bw))
+			ib = min_camnoc_ib_bw;
+	} else {
+		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW))
+			ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW;
+
+		if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW))
+			ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
+	}
 
 	pdata = bus_client->pdata;
 	path = &(pdata->usecase[idx]);
@@ -205,7 +228,7 @@
 		return -EINVAL;
 
 	if (bus_client->dyn_vote)
-		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0);
+		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false);
 	else
 		cam_cpas_util_vote_bus_client_level(bus_client, 0);
 
@@ -370,7 +393,7 @@
 	list_for_each_entry_safe(curr_port, temp_port,
 		&cpas_core->axi_ports_list_head, sibling_port) {
 		rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus,
-			mnoc_bw, mnoc_bw);
+			mnoc_bw, mnoc_bw, false);
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"Failed in mnoc vote, enable=%d, rc=%d",
@@ -380,13 +403,13 @@
 
 		if (soc_private->axi_camnoc_based) {
 			cam_cpas_util_vote_bus_client_bw(
-				&curr_port->camnoc_bus, 0, camnoc_bw);
+				&curr_port->camnoc_bus, 0, camnoc_bw, true);
 			if (rc) {
 				CAM_ERR(CAM_CPAS,
 					"Failed in mnoc vote, enable=%d, %d",
 					enable, rc);
 				cam_cpas_util_vote_bus_client_bw(
-					&curr_port->mnoc_bus, 0, 0);
+					&curr_port->mnoc_bus, 0, 0, false);
 				goto remove_ahb_vote;
 			}
 		}
@@ -520,10 +543,71 @@
 	return rc;
 }
 
-static int cam_cpas_util_apply_client_axi_vote(
-	struct cam_cpas *cpas_core, struct cam_cpas_private_soc *soc_private,
-	struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote)
+static int cam_cpas_util_set_camnoc_axi_clk_rate(
+	struct cam_hw_info *cpas_hw)
 {
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	struct cam_cpas_private_soc *soc_private =
+		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+	int rc = 0;
+
+	CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d",
+		soc_private->control_camnoc_axi_clk);
+
+	if (soc_private->control_camnoc_axi_clk) {
+		struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+		struct cam_cpas_axi_port *curr_axi_port = NULL;
+		struct cam_cpas_axi_port *temp_axi_port = NULL;
+		uint64_t required_camnoc_bw = 0;
+		int32_t clk_rate = 0;
+
+		list_for_each_entry_safe(curr_axi_port, temp_axi_port,
+			&cpas_core->axi_ports_list_head, sibling_port) {
+
+			if (curr_axi_port->consolidated_axi_vote.uncompressed_bw
+				> required_camnoc_bw)
+				required_camnoc_bw = curr_axi_port->
+					consolidated_axi_vote.uncompressed_bw;
+
+			CAM_DBG(CAM_CPAS, "[%s] : curr=%llu, overal=%llu",
+				curr_axi_port->axi_port_name,
+				curr_axi_port->consolidated_axi_vote.
+				uncompressed_bw,
+				required_camnoc_bw);
+		}
+
+		required_camnoc_bw += (required_camnoc_bw *
+			soc_private->camnoc_axi_clk_bw_margin) / 100;
+
+		if ((required_camnoc_bw > 0) &&
+			(required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW))
+			required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
+
+		clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width;
+
+		CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d",
+			required_camnoc_bw, clk_rate);
+
+		rc = cam_soc_util_set_clk_rate(
+			soc_info->clk[soc_info->src_clk_idx],
+			soc_info->clk_name[soc_info->src_clk_idx],
+			clk_rate);
+		if (!rc)
+			CAM_ERR(CAM_CPAS,
+				"Failed in setting camnoc axi clk %llu %d %d",
+				required_camnoc_bw, clk_rate, rc);
+	}
+
+	return rc;
+}
+
+static int cam_cpas_util_apply_client_axi_vote(
+	struct cam_hw_info *cpas_hw,
+	struct cam_cpas_client *cpas_client,
+	struct cam_axi_vote *axi_vote)
+{
+	struct cam_cpas_private_soc *soc_private =
+		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
 	struct cam_cpas_client *curr_client;
 	struct cam_cpas_client *temp_client;
 	struct cam_axi_vote req_axi_vote = *axi_vote;
@@ -564,6 +648,9 @@
 	if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw))
 		mnoc_bw = camnoc_bw;
 
+	axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw;
+	axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw;
+
 	CAM_DBG(CAM_CPAS,
 		"axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]",
 		axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst,
@@ -571,7 +658,7 @@
 		camnoc_bw, mnoc_bw);
 
 	rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
-		mnoc_bw, mnoc_bw);
+		mnoc_bw, mnoc_bw, false);
 	if (rc) {
 		CAM_ERR(CAM_CPAS,
 			"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -581,7 +668,7 @@
 
 	if (soc_private->axi_camnoc_based) {
 		rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus,
-			0, camnoc_bw);
+			0, camnoc_bw, true);
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"Failed camnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -590,6 +677,14 @@
 		}
 	}
 
+	mutex_unlock(&axi_port->lock);
+
+	rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw);
+	if (rc)
+		CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc);
+
+	return rc;
+
 unlock_axi_port:
 	mutex_unlock(&axi_port->lock);
 	return rc;
@@ -622,6 +717,7 @@
 	if (!CAM_CPAS_CLIENT_VALID(client_indx))
 		return -EINVAL;
 
+	mutex_lock(&cpas_hw->hw_mutex);
 	mutex_lock(&cpas_core->client_mutex[client_indx]);
 
 	if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) {
@@ -635,12 +731,12 @@
 		client_indx, axi_vote.compressed_bw,
 		axi_vote.uncompressed_bw);
 
-	rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
-		cpas_hw->soc_info.soc_private,
+	rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
 		cpas_core->cpas_client[client_indx], &axi_vote);
 
 unlock_client:
 	mutex_unlock(&cpas_core->client_mutex[client_indx]);
+	mutex_unlock(&cpas_hw->hw_mutex);
 	return rc;
 }
 
@@ -874,15 +970,17 @@
 		"AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]",
 		client_indx, axi_vote->compressed_bw,
 		axi_vote->uncompressed_bw);
-	rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
-		cpas_hw->soc_info.soc_private, cpas_client, axi_vote);
+	rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
+		cpas_client, axi_vote);
 	if (rc)
 		goto done;
 
 	if (cpas_core->streamon_clients == 0) {
+		atomic_set(&cpas_core->irq_count, 1);
 		rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
 			applied_level);
 		if (rc) {
+			atomic_set(&cpas_core->irq_count, 0);
 			CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc);
 			goto done;
 		}
@@ -890,14 +988,17 @@
 		if (cpas_core->internal_ops.power_on) {
 			rc = cpas_core->internal_ops.power_on(cpas_hw);
 			if (rc) {
+				atomic_set(&cpas_core->irq_count, 0);
 				cam_cpas_soc_disable_resources(
-					&cpas_hw->soc_info);
+					&cpas_hw->soc_info, true, true);
 				CAM_ERR(CAM_CPAS,
 					"failed in power_on settings rc=%d",
 					rc);
 				goto done;
 			}
 		}
+		CAM_DBG(CAM_CPAS, "irq_count=%d\n",
+			atomic_read(&cpas_core->irq_count));
 		cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
 	}
 
@@ -912,6 +1013,10 @@
 	return rc;
 }
 
+static int _check_irq_count(struct cam_cpas *cpas_core)
+{
+	return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1;
+}
 
 static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
 	uint32_t arg_size)
@@ -924,6 +1029,7 @@
 	struct cam_ahb_vote ahb_vote;
 	struct cam_axi_vote axi_vote;
 	int rc = 0;
+	long result;
 
 	if (!hw_priv || !stop_args) {
 		CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -972,11 +1078,29 @@
 			}
 		}
 
-		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+		rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
+		if (rc) {
+			CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
+			goto done;
+		}
+
+		/* Wait for any IRQs still being handled */
+		atomic_dec(&cpas_core->irq_count);
+		result = wait_event_timeout(cpas_core->irq_count_wq,
+			_check_irq_count(cpas_core), HZ);
+		if (result == 0) {
+			CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d",
+				atomic_read(&cpas_core->irq_count));
+		}
+
+		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
+			true, false);
 		if (rc) {
 			CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc);
 			goto done;
 		}
+		CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n",
+			atomic_read(&cpas_core->irq_count));
 		cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
 	}
 
@@ -989,8 +1113,8 @@
 
 	axi_vote.uncompressed_bw = 0;
 	axi_vote.compressed_bw = 0;
-	rc = cam_cpas_util_apply_client_axi_vote(cpas_core,
-		cpas_hw->soc_info.soc_private, cpas_client, &axi_vote);
+	rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
+		cpas_client, &axi_vote);
 
 done:
 	mutex_unlock(&cpas_core->client_mutex[client_indx]);
@@ -1427,6 +1551,8 @@
 	soc_private = (struct cam_cpas_private_soc *)
 		cpas_hw->soc_info.soc_private;
 	cpas_core->num_clients = soc_private->num_clients;
+	atomic_set(&cpas_core->irq_count, 0);
+	init_waitqueue_head(&cpas_core->irq_count_wq);
 
 	if (internal_ops->setup_regbase) {
 		rc = internal_ops->setup_regbase(&cpas_hw->soc_info,
@@ -1482,7 +1608,7 @@
 	if (rc)
 		goto disable_soc_res;
 
-	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
 	if (rc) {
 		CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
 		goto remove_default_vote;
@@ -1500,7 +1626,7 @@
 	return 0;
 
 disable_soc_res:
-	cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+	cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
 remove_default_vote:
 	cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
 axi_cleanup:
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
index aa3663d..2e660b1 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -145,6 +145,7 @@
  * @axi_port_node: Node representing this AXI Port
  * @axi_port_mnoc_node: Node representing mnoc in this AXI Port
  * @axi_port_camnoc_node: Node representing camnoc in this AXI Port
+ * @consolidated_axi_vote: Consolidated axi bw values for this AXI port
  *
  */
 struct cam_cpas_axi_port {
@@ -157,6 +158,7 @@
 	struct device_node *axi_port_node;
 	struct device_node *axi_port_mnoc_node;
 	struct device_node *axi_port_camnoc_node;
+	struct cam_axi_vote consolidated_axi_vote;
 };
 
 /**
@@ -187,6 +189,8 @@
 	struct list_head axi_ports_list_head;
 	struct cam_cpas_internal_ops internal_ops;
 	struct workqueue_struct *work_queue;
+	atomic_t irq_count;
+	wait_queue_head_t irq_count_wq;
 };
 
 int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
index d5108f6..0187a64 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -366,7 +366,6 @@
 	switch (cmd->op_code) {
 	case CAM_QUERY_CAP: {
 		struct cam_cpas_query_cap query;
-		uint32_t cam_cpas;
 
 		rc = copy_from_user(&query, (void __user *) cmd->handle,
 			sizeof(query));
@@ -377,7 +376,8 @@
 		}
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
-			&query.camera_version, &query.cpas_version, &cam_cpas);
+			&query.camera_version, &query.cpas_version,
+			&query.reserved);
 		if (rc)
 			break;
 
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
index f85f461..8f9ec14 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -44,6 +44,18 @@
 		return rc;
 	}
 
+
+	soc_private->hw_version = 0;
+	rc = of_property_read_u32(of_node,
+		"qcom,cpas-hw-ver", &soc_private->hw_version);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "device %s failed to read cpas-hw-ver",
+			pdev->name);
+		return rc;
+	}
+
+	CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version);
+
 	soc_private->client_id_based = of_property_read_bool(of_node,
 		"client-id-based");
 
@@ -93,6 +105,35 @@
 	soc_private->axi_camnoc_based = of_property_read_bool(of_node,
 		"client-bus-camnoc-based");
 
+	soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node,
+		"control-camnoc-axi-clk");
+
+	if (soc_private->control_camnoc_axi_clk == true) {
+		rc = of_property_read_u32(of_node, "camnoc-bus-width",
+			&soc_private->camnoc_bus_width);
+		if (rc || (soc_private->camnoc_bus_width == 0)) {
+			CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d",
+				rc, soc_private->camnoc_bus_width);
+			return rc;
+		}
+
+		rc = of_property_read_u32(of_node,
+			"camnoc-axi-clk-bw-margin-perc",
+			&soc_private->camnoc_axi_clk_bw_margin);
+
+		if (rc) {
+			/* this is not fatal, overwrite rc */
+			rc = 0;
+			soc_private->camnoc_axi_clk_bw_margin = 0;
+		}
+	}
+
+	CAM_DBG(CAM_CPAS,
+		"control_camnoc_axi_clk=%d, width=%d, margin=%d",
+		soc_private->control_camnoc_axi_clk,
+		soc_private->camnoc_bus_width,
+		soc_private->camnoc_axi_clk_bw_margin);
+
 	count = of_property_count_u32_elems(of_node, "vdd-corners");
 	if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) &&
 		(of_property_count_strings(of_node, "vdd-corner-ahb-mapping") ==
@@ -140,6 +181,7 @@
 	irq_handler_t irq_handler, void *irq_data)
 {
 	int rc = 0;
+	struct cam_cpas_private_soc *soc_private;
 
 	rc = cam_soc_util_get_dt_properties(soc_info);
 	if (rc) {
@@ -173,6 +215,12 @@
 		goto free_soc_private;
 	}
 
+	soc_private = soc_info->soc_private;
+	soc_private->soc_id = cam_soc_util_get_soc_id();
+	soc_private->hw_rev = cam_soc_util_get_hw_revision_node(soc_info);
+	CAM_DBG(CAM_CPAS, "soc id %d hw_rev %d",
+		soc_private->soc_id, soc_private->hw_rev);
+
 	return rc;
 
 free_soc_private:
@@ -209,13 +257,26 @@
 	return rc;
 }
 
-int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info)
+int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
+	bool disable_clocks, bool disble_irq)
 {
 	int rc = 0;
 
-	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	rc = cam_soc_util_disable_platform_resource(soc_info,
+		disable_clocks, disble_irq);
 	if (rc)
 		CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc);
 
 	return rc;
 }
+
+int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_irq_disable(soc_info);
+	if (rc)
+		CAM_ERR(CAM_CPAS, "disable irq failed, rc=%d", rc);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
index d4fc039..91e8d0c0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,7 +17,6 @@
 #include "cam_cpas_hw.h"
 
 #define CAM_REGULATOR_LEVEL_MAX 16
-
 /**
  * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
  *
@@ -34,6 +33,7 @@
  * struct cam_cpas_private_soc : CPAS private DT info
  *
  * @arch_compat: ARCH compatible string
+ * @hw_version: Camera HW version
  * @client_id_based: Whether clients are id based
  * @num_clients: Number of clients supported
  * @client_name: Client names
@@ -42,10 +42,17 @@
  * @axi_port_list_node : Node representing AXI Ports list
  * @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported
  * @vdd_ahb : AHB level mapping info for the supported vdd levels
+ * @soc_id : SOC id
+ * @hw_rev : Camera hw revision
+ * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq
+ * @camnoc_bus_width : CAMNOC Bus width
+ * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating
+ *      camnoc axi clock
  *
  */
 struct cam_cpas_private_soc {
 	const char *arch_compat;
+	uint32_t hw_version;
 	bool client_id_based;
 	uint32_t num_clients;
 	const char *client_name[CAM_CPAS_MAX_CLIENTS];
@@ -54,6 +61,11 @@
 	struct device_node *axi_port_list_node;
 	uint32_t num_vdd_ahb_mapping;
 	struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX];
+	uint32_t soc_id;
+	uint32_t hw_rev;
+	bool control_camnoc_axi_clk;
+	uint32_t camnoc_bus_width;
+	uint32_t camnoc_axi_clk_bw_margin;
 };
 
 int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
@@ -61,5 +73,7 @@
 int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
 int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info,
 	enum cam_vote_level default_level);
-int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info);
+int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
+	bool disable_clocks, bool disble_irq);
+int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info);
 #endif /* _CAM_CPAS_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index 0e5ce85..9b703c0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,8 @@
 #include "cam_cpas_soc.h"
 #include "cpastop100.h"
 #include "cpastop_v170_110.h"
+#include "cpastop_v175_100.h"
+#include "cpastop_v175_101.h"
 
 struct cam_camnoc_info *camnoc_info;
 
@@ -114,6 +116,15 @@
 		return -EINVAL;
 	}
 
+	rc = cam_common_util_get_string_index(soc_info->mem_block_name,
+		soc_info->num_mem_block, "core_top_csr_tcsr", &index);
+	if ((rc == 0) && (index < num_reg_map)) {
+		regbase_index[CAM_CPAS_REG_CSR_TCSR] = index;
+	} else {
+		CAM_DBG(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d",
+			rc, index, num_reg_map);
+	}
+
 	return 0;
 }
 
@@ -354,6 +365,11 @@
 	cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 	soc_info = &cpas_hw->soc_info;
 
+	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
+		CAM_ERR(CAM_CPAS, "CPAS off");
+		return;
+	}
+
 	for (i = 0; i < camnoc_info->irq_err_size; i++) {
 		if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
 			(camnoc_info->irq_err[i].enable)) {
@@ -398,6 +414,9 @@
 				~camnoc_info->irq_err[i].sbm_port;
 		}
 	}
+	atomic_dec(&cpas_core->irq_count);
+	wake_up(&cpas_core->irq_count_wq);
+	CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count));
 
 	if (payload->irq_status)
 		CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x",
@@ -414,9 +433,14 @@
 	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
 	struct cam_cpas_work_payload *payload;
 
+	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
+		CAM_ERR(CAM_CPAS, "CPAS off");
+		return IRQ_HANDLED;
+	}
+
 	payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
 	if (!payload)
-		return IRQ_HANDLED;
+		goto done;
 
 	payload->irq_status = cam_io_r_mb(
 		soc_info->reg_map[camnoc_index].mem_base +
@@ -433,6 +457,9 @@
 	cam_cpastop_reset_irq(cpas_hw);
 
 	queue_work(cpas_core->work_queue, &payload->work);
+done:
+	atomic_dec(&cpas_core->irq_count);
+	wake_up(&cpas_core->irq_count_wq);
 
 	return IRQ_HANDLED;
 }
@@ -440,6 +467,9 @@
 static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw)
 {
 	int i;
+	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	struct cam_cpas_private_soc *soc_private = soc_info->soc_private;
 
 	cam_cpastop_reset_irq(cpas_hw);
 
@@ -462,6 +492,29 @@
 		}
 	}
 
+	if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+		(soc_private->hw_rev == SDM670_V1_1)) {
+
+		struct cam_cpas_reg *reg_info;
+		int tcsr_index;
+		void __iomem *mem_base;
+
+		reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+			tcsr_conn_box_spare_0;
+		tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+		if (tcsr_index == -1) {
+			CAM_DBG(CAM_CPAS, "index in not initialized");
+			return 0;
+		}
+		mem_base = soc_info->reg_map[tcsr_index].mem_base;
+
+		reg_info->value = TCSR_CONN_SET;
+		cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+		CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+			(unsigned long int)mem_base + reg_info->offset,
+			cam_io_r_mb(mem_base + reg_info->offset));
+	}
+
 	return 0;
 }
 
@@ -473,6 +526,8 @@
 	int rc = 0;
 	struct cam_cpas_hw_errata_wa_list *errata_wa_list =
 		camnoc_info->errata_wa_list;
+	struct cam_cpas_private_soc *soc_private =
+		cpas_hw->soc_info.soc_private;
 
 	if (!errata_wa_list)
 		return 0;
@@ -496,36 +551,68 @@
 		}
 	}
 
+	if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+		(soc_private->hw_rev == SDM670_V1_1)) {
+
+		struct cam_cpas_reg *reg_info;
+		int tcsr_index;
+		void __iomem *mem_base;
+
+		reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+			tcsr_conn_box_spare_0;
+		reg_info->value = TCSR_CONN_RESET;
+		tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+		if (tcsr_index == -1) {
+			CAM_DBG(CAM_CPAS, "index in not initialized");
+			return 0;
+		}
+		mem_base = soc_info->reg_map[tcsr_index].mem_base;
+		cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+		CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+			(unsigned long int)mem_base + reg_info->offset,
+			cam_io_r_mb(mem_base + reg_info->offset));
+	}
+
 	return rc;
 }
 
 static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 	struct cam_cpas_hw_caps *hw_caps)
 {
-	if ((hw_caps->camera_version.major == 1) &&
-		(hw_caps->camera_version.minor == 7) &&
-		(hw_caps->camera_version.incr == 0)) {
-		if ((hw_caps->cpas_version.major == 1) &&
-			(hw_caps->cpas_version.minor == 0) &&
-			(hw_caps->cpas_version.incr == 0)) {
-			camnoc_info = &cam170_cpas100_camnoc_info;
-		} else if ((hw_caps->cpas_version.major == 1) &&
-			(hw_caps->cpas_version.minor == 1) &&
-			(hw_caps->cpas_version.incr == 0)) {
-			camnoc_info = &cam170_cpas110_camnoc_info;
-		} else {
-			CAM_ERR(CAM_CPAS, "CPAS Version not supported %d.%d.%d",
-				hw_caps->cpas_version.major,
-				hw_caps->cpas_version.minor,
-				hw_caps->cpas_version.incr);
-			return -EINVAL;
-		}
-	} else {
+	int rc = 0;
+	struct cam_cpas_private_soc *soc_private =
+		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+
+	CAM_DBG(CAM_CPAS,
+		"hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
+		soc_private->hw_version,
+		hw_caps->camera_version.major,
+		hw_caps->camera_version.minor,
+		hw_caps->camera_version.incr,
+		hw_caps->cpas_version.major,
+		hw_caps->cpas_version.minor,
+		hw_caps->cpas_version.incr);
+
+	switch (soc_private->hw_version) {
+	case CAM_CPAS_TITAN_170_V100:
+		camnoc_info = &cam170_cpas100_camnoc_info;
+		break;
+	case CAM_CPAS_TITAN_170_V110:
+		camnoc_info = &cam170_cpas110_camnoc_info;
+		break;
+	case CAM_CPAS_TITAN_175_V100:
+		camnoc_info = &cam175_cpas100_camnoc_info;
+		break;
+	case CAM_CPAS_TITAN_175_V101:
+		camnoc_info = &cam175_cpas101_camnoc_info;
+		break;
+	default:
 		CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d",
 			hw_caps->camera_version.major,
 			hw_caps->camera_version.minor,
 			hw_caps->camera_version.incr);
-		return -EINVAL;
+		rc = -EINVAL;
+		break;
 	}
 
 	return 0;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
index 73f7e9b..080f6e6 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -162,14 +162,27 @@
 };
 
 /**
+ * struct cam_camnoc_tcsr_regs : Top control Status register
+ *
+ * @tcsr_conn_box_spare_0: spare register to select PriorityLvl
+ *         for IFE0 and IFE1 (HW workaround for SDM670 1.1)
+ *
+ */
+struct cam_camnoc_tcsr_regs {
+	struct cam_cpas_reg tcsr_conn_box_spare_0;
+};
+
+/**
  * struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info
  *
  * @camnoc_flush_slave_pending_trans: Errata workaround info for flushing
  *         camnoc slave pending transactions before turning off CPAS_TOP gdsc
+ * @tcsr_reg: HW workaround to select PriorityLvl for IFE0 and IFE(SDM670_1.1)
  *
  */
 struct cam_cpas_hw_errata_wa_list {
 	struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans;
+	struct cam_camnoc_tcsr_regs tcsr_reg;
 };
 
 /**
@@ -200,6 +213,7 @@
 	uint32_t errlog3_high;
 };
 
+
 /**
  * struct cam_camnoc_info : Overall CAMNOC settings info
  *
@@ -210,7 +224,6 @@
  * @irq_err_size: Array size of IRQ Error settings
  * @err_logger: Pointer to CAMNOC IRQ Error logger read registers
  * @errata_wa_list: HW Errata workaround info
- *
  */
 struct cam_camnoc_info {
 	struct cam_camnoc_specific *specific;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
index 3c572f0..0c7c799 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,8 @@
 #define _CPASTOP_V170_110_H_
 
 #define TEST_IRQ_ENABLE 0
+#define TCSR_CONN_RESET 0x0
+#define TCSR_CONN_SET  0x3
 
 static struct cam_camnoc_irq_sbm cam_cpas110_irq_sbm = {
 	.sbm_enable = {
@@ -265,7 +267,7 @@
 			.access_type = CAM_REG_TYPE_READ_WRITE,
 			.masked_value = 0,
 			.offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
-			.value = 0x66665555,
+			.value = 0x66666666,
 		},
 		.urgency = {
 			.enable = true,
@@ -313,7 +315,7 @@
 			.access_type = CAM_REG_TYPE_READ_WRITE,
 			.masked_value = 0,
 			.offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
-			.value = 0x66665555,
+			.value = 0x66666666,
 		},
 		.urgency = {
 			.enable = true,
@@ -528,6 +530,14 @@
 			.value = 0, /* expected to be 0 */
 		},
 	},
+	.tcsr_reg = {
+		.tcsr_conn_box_spare_0 = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xB3E4,
+		},
+	},
 };
 
 static struct cam_camnoc_info cam170_cpas110_camnoc_info = {
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h
new file mode 100644
index 0000000..e2aad09
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_100.h
@@ -0,0 +1,545 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CPASTOP_V175_100_H_
+#define _CPASTOP_V175_100_H_
+
+#define TEST_IRQ_ENABLE 0
+
+static struct cam_camnoc_irq_sbm cam_cpas_v175_100_irq_sbm = {
+	.sbm_enable = {
+		.access_type = CAM_REG_TYPE_READ_WRITE,
+		.enable = true,
+		.offset = 0x2040, /* SBM_FAULTINEN0_LOW */
+		.value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/
+			0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */
+			0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */
+			0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */
+			0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */
+			0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */
+			(TEST_IRQ_ENABLE ?
+			0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */
+			0x0),
+	},
+	.sbm_status = {
+		.access_type = CAM_REG_TYPE_READ,
+		.enable = true,
+		.offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */
+	},
+	.sbm_clear = {
+		.access_type = CAM_REG_TYPE_WRITE,
+		.enable = true,
+		.offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */
+		.value = TEST_IRQ_ENABLE ? 0x6 : 0x2,
+	}
+};
+
+static struct cam_camnoc_irq_err
+	cam_cpas_v175_100_irq_err[] = {
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR,
+		.enable = true,
+		.sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x1190,
+			/* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT,
+		.enable = true,
+		.sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+			.value = 0x1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+		},
+		.err_clear = {
+			.enable = false,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1,
+		.enable = false,
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2,
+		.enable = false,
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST,
+		.enable = TEST_IRQ_ENABLE ? true : false,
+		.sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+			.value = 0x5,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+		},
+		.err_clear = {
+			.enable = false,
+		},
+	},
+};
+
+static struct cam_camnoc_specific
+	cam_cpas_v175_100_camnoc_specific[] = {
+	{
+		.port_type = CAM_CAMNOC_CDM,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */
+			.value = 0x22222222,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */
+			.value = 0x22222222,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */
+			.mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */
+			.shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */
+			.value = 0x2,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = false,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IFE02,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */
+			.value = 0x66666543,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
+			.value = 0x66666666,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */
+			/* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
+			.value = 0xFFFFFF00,
+		},
+		.safe_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
+			.value = 0x1,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IFE13,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */
+			.value = 0x66666543,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
+			.value = 0x66666666,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */
+			/* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
+			.value = 0xFFFFFF00,
+		},
+		.safe_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
+			.value = 0x1,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IPE_BPS_LRME_READ,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */
+			.value = 0x33333333,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */
+			.value = 0x33333333,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */
+			/* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */
+			.mask = 0x7,
+			/* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */
+			.shift = 0x0,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */
+			.value = 0x33333333,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */
+			.value = 0x33333333,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */
+			/* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_JPEG,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */
+			.value = 0x22222222,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */
+			.value = 0x22222222,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */
+			.value = 0x22,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = false,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_FD,
+		.enable = false,
+	},
+	{
+		.port_type = CAM_CAMNOC_ICP,
+		.enable = true,
+		.flag_out_set0_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_WRITE,
+			.masked_value = 0,
+			.offset = 0x2088,
+			.value = 0x100000,
+		},
+	},
+};
+
+static struct cam_camnoc_err_logger_info cam175_cpas100_err_logger_offsets = {
+	.mainctrl     =  0x2708, /* ERRLOGGER_MAINCTL_LOW */
+	.errvld       =  0x2710, /* ERRLOGGER_ERRVLD_LOW */
+	.errlog0_low  =  0x2720, /* ERRLOGGER_ERRLOG0_LOW */
+	.errlog0_high =  0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
+	.errlog1_low  =  0x2728, /* ERRLOGGER_ERRLOG1_LOW */
+	.errlog1_high =  0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
+	.errlog2_low  =  0x2730, /* ERRLOGGER_ERRLOG2_LOW */
+	.errlog2_high =  0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
+	.errlog3_low  =  0x2738, /* ERRLOGGER_ERRLOG3_LOW */
+	.errlog3_high =  0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
+};
+
+static struct cam_cpas_hw_errata_wa_list cam175_cpas100_errata_wa_list = {
+	.camnoc_flush_slave_pending_trans = {
+		.enable = false,
+		.data.reg_info = {
+			.access_type = CAM_REG_TYPE_READ,
+			.offset = 0x2100, /* SidebandManager_SenseIn0_Low */
+			.mask = 0xE0000, /* Bits 17, 18, 19 */
+			.value = 0, /* expected to be 0 */
+		},
+	},
+};
+
+static struct cam_camnoc_info cam175_cpas100_camnoc_info = {
+	.specific = &cam_cpas_v175_100_camnoc_specific[0],
+	.specific_size = sizeof(cam_cpas_v175_100_camnoc_specific) /
+		sizeof(cam_cpas_v175_100_camnoc_specific[0]),
+	.irq_sbm = &cam_cpas_v175_100_irq_sbm,
+	.irq_err = &cam_cpas_v175_100_irq_err[0],
+	.irq_err_size = sizeof(cam_cpas_v175_100_irq_err) /
+		sizeof(cam_cpas_v175_100_irq_err[0]),
+	.err_logger = &cam175_cpas100_err_logger_offsets,
+	.errata_wa_list = &cam175_cpas100_errata_wa_list,
+};
+
+#endif /* _CPASTOP_V175_100_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h
new file mode 100644
index 0000000..e5e9673
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v175_101.h
@@ -0,0 +1,545 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CPASTOP_V175_101_H_
+#define _CPASTOP_V175_101_H_
+
+#define TEST_IRQ_ENABLE 0
+
+static struct cam_camnoc_irq_sbm cam_cpas_v175_101_irq_sbm = {
+	.sbm_enable = {
+		.access_type = CAM_REG_TYPE_READ_WRITE,
+		.enable = true,
+		.offset = 0x2040, /* SBM_FAULTINEN0_LOW */
+		.value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/
+			0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */
+			0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */
+			0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */
+			0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */
+			0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */
+			(TEST_IRQ_ENABLE ?
+			0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */
+			0x0),
+	},
+	.sbm_status = {
+		.access_type = CAM_REG_TYPE_READ,
+		.enable = true,
+		.offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */
+	},
+	.sbm_clear = {
+		.access_type = CAM_REG_TYPE_WRITE,
+		.enable = true,
+		.offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */
+		.value = TEST_IRQ_ENABLE ? 0x6 : 0x2,
+	}
+};
+
+static struct cam_camnoc_irq_err
+	cam_cpas_v175_101_irq_err[] = {
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR,
+		.enable = true,
+		.sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR,
+		.enable = true,
+		.sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */
+			.value = 1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x1190,
+			/* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */
+		},
+		.err_clear = {
+			.access_type = CAM_REG_TYPE_WRITE,
+			.enable = true,
+			.offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT,
+		.enable = true,
+		.sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+			.value = 0x1,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+		},
+		.err_clear = {
+			.enable = false,
+		},
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1,
+		.enable = false,
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2,
+		.enable = false,
+	},
+	{
+		.irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST,
+		.enable = TEST_IRQ_ENABLE ? true : false,
+		.sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */
+		.err_enable = {
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.enable = true,
+			.offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */
+			.value = 0x5,
+		},
+		.err_status = {
+			.access_type = CAM_REG_TYPE_READ,
+			.enable = true,
+			.offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */
+		},
+		.err_clear = {
+			.enable = false,
+		},
+	},
+};
+
+static struct cam_camnoc_specific
+	cam_cpas_v175_101_camnoc_specific[] = {
+	{
+		.port_type = CAM_CAMNOC_CDM,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */
+			.value = 0x22222222,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */
+			.value = 0x22222222,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */
+			.mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */
+			.shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */
+			.value = 0x2,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = false,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IFE02,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */
+			.value = 0x66666543,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */
+			.value = 0x66666666,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */
+			/* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
+			.value = 0xFFFFFF00,
+		},
+		.safe_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
+			.value = 0x1,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IFE13,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */
+			.value = 0x66666543,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */
+			.value = 0x66666666,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */
+			/* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
+			.value = 0xFFFFFF00,
+		},
+		.safe_lut = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
+			.value = 0x1,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IPE_BPS_LRME_READ,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */
+			.value = 0x33333333,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */
+			.value = 0x33333333,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */
+			/* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */
+			.mask = 0x7,
+			/* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */
+			.shift = 0x0,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */
+			.value = 0x33333333,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */
+			.value = 0x33333333,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 1,
+			.offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */
+			/* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */
+			.mask = 0x70,
+			/* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */
+			.shift = 0x4,
+			.value = 3,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */
+			.value = 1,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_JPEG,
+		.enable = true,
+		.priority_lut_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */
+			.value = 0x22222222,
+		},
+		.priority_lut_high = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */
+			.value = 0x22222222,
+		},
+		.urgency = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */
+			.value = 0x22,
+		},
+		.danger_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */
+			.value = 0x0,
+		},
+		.safe_lut = {
+			.enable = false,
+			.access_type = CAM_REG_TYPE_READ_WRITE,
+			.masked_value = 0,
+			.offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */
+			.value = 0x0,
+		},
+		.ubwc_ctl = {
+			.enable = false,
+		},
+	},
+	{
+		.port_type = CAM_CAMNOC_FD,
+		.enable = false,
+	},
+	{
+		.port_type = CAM_CAMNOC_ICP,
+		.enable = true,
+		.flag_out_set0_low = {
+			.enable = true,
+			.access_type = CAM_REG_TYPE_WRITE,
+			.masked_value = 0,
+			.offset = 0x2088,
+			.value = 0x100000,
+		},
+	},
+};
+
+static struct cam_camnoc_err_logger_info cam175_cpas101_err_logger_offsets = {
+	.mainctrl     =  0x2708, /* ERRLOGGER_MAINCTL_LOW */
+	.errvld       =  0x2710, /* ERRLOGGER_ERRVLD_LOW */
+	.errlog0_low  =  0x2720, /* ERRLOGGER_ERRLOG0_LOW */
+	.errlog0_high =  0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
+	.errlog1_low  =  0x2728, /* ERRLOGGER_ERRLOG1_LOW */
+	.errlog1_high =  0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
+	.errlog2_low  =  0x2730, /* ERRLOGGER_ERRLOG2_LOW */
+	.errlog2_high =  0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
+	.errlog3_low  =  0x2738, /* ERRLOGGER_ERRLOG3_LOW */
+	.errlog3_high =  0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
+};
+
+static struct cam_cpas_hw_errata_wa_list cam175_cpas101_errata_wa_list = {
+	.camnoc_flush_slave_pending_trans = {
+		.enable = false,
+		.data.reg_info = {
+			.access_type = CAM_REG_TYPE_READ,
+			.offset = 0x2100, /* SidebandManager_SenseIn0_Low */
+			.mask = 0xE0000, /* Bits 17, 18, 19 */
+			.value = 0, /* expected to be 0 */
+		},
+	},
+};
+
+static struct cam_camnoc_info cam175_cpas101_camnoc_info = {
+	.specific = &cam_cpas_v175_101_camnoc_specific[0],
+	.specific_size = sizeof(cam_cpas_v175_101_camnoc_specific) /
+		sizeof(cam_cpas_v175_101_camnoc_specific[0]),
+	.irq_sbm = &cam_cpas_v175_101_irq_sbm,
+	.irq_err = &cam_cpas_v175_101_irq_err[0],
+	.irq_err_size = sizeof(cam_cpas_v175_101_irq_err) /
+		sizeof(cam_cpas_v175_101_irq_err[0]),
+	.err_logger = &cam175_cpas101_err_logger_offsets,
+	.errata_wa_list = &cam175_cpas101_errata_wa_list,
+};
+
+#endif /* _CPASTOP_V175_101_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
index c844ef7..d1492fe 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -32,6 +32,7 @@
 enum cam_cpas_reg_base {
 	CAM_CPAS_REG_CPASTOP,
 	CAM_CPAS_REG_CAMNOC,
+	CAM_CPAS_REG_CSR_TCSR,
 	CAM_CPAS_REG_CAMSS,
 	CAM_CPAS_REG_MAX
 };
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
index 04d65dd..99c509c 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -211,7 +211,8 @@
 
 
 int cam_fd_context_init(struct cam_fd_context *fd_ctx,
-	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf)
+	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id)
 {
 	int rc;
 
@@ -222,8 +223,8 @@
 
 	memset(fd_ctx, 0, sizeof(*fd_ctx));
 
-	rc = cam_context_init(base_ctx, fd_dev_name, NULL, hw_intf,
-		fd_ctx->req_base, CAM_CTX_REQ_MAX);
+	rc = cam_context_init(base_ctx, fd_dev_name, CAM_FD, ctx_id,
+		NULL, hw_intf, fd_ctx->req_base, CAM_CTX_REQ_MAX);
 	if (rc) {
 		CAM_ERR(CAM_FD, "Camera Context Base init failed, rc=%d", rc);
 		return rc;
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
index 6aa5edb..a8b5d15 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,8 @@
 };
 
 int cam_fd_context_init(struct cam_fd_context *fd_ctx,
-	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf);
+	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id);
 int cam_fd_context_deinit(struct cam_fd_context *ctx);
 
 #endif /* _CAM_FD_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
index 260dcd8..3f01244 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -121,7 +121,7 @@
 
 	for (i = 0; i < CAM_CTX_MAX; i++) {
 		rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i],
-			&g_fd_dev.base_ctx[i], &node->hw_mgr_intf);
+			&g_fd_dev.base_ctx[i], &node->hw_mgr_intf, i);
 		if (rc) {
 			CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d",
 				i, rc);
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
index 640c6f6..4d74dec 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -1092,6 +1092,7 @@
 		CAM_ERR(CAM_FD, "Release cdm handle failed, handle=0x%x, rc=%d",
 			ctx_hw_private->cdm_handle, rc);
 
+	kfree(ctx_hw_private->cdm_cmd);
 	kfree(ctx_hw_private);
 	release_args->ctx_hw_private = NULL;
 
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
index 803da76..6d9d330 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -22,6 +22,7 @@
 #include "cam_fd_hw_core.h"
 #include "cam_fd_hw_soc.h"
 #include "cam_fd_hw_v41.h"
+#include "cam_fd_hw_v501.h"
 
 static int cam_fd_hw_dev_probe(struct platform_device *pdev)
 {
@@ -193,6 +194,10 @@
 		.compatible = "qcom,fd41",
 		.data = &cam_fd_wrapper120_core410_info,
 	},
+	{
+		.compatible = "qcom,fd501",
+		.data = &cam_fd_wrapper200_core501_info,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match);
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
index 70448bb..78257a5 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -63,7 +63,7 @@
 		CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE),
 	.qos_priority       = 4,
 	.qos_priority_level = 4,
-	.supported_modes    = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID,
+	.supported_modes    = CAM_FD_MODE_FACEDETECTION,
 	.ro_mode_supported  = true,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h
new file mode 100644
index 0000000..44b9ab5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_V501_H_
+#define _CAM_FD_HW_V501_H_
+
+static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = {
+	.core_version = {
+		.major  = 5,
+		.minor  = 0,
+		.incr   = 1,
+	},
+	.wrapper_version = {
+		.major  = 2,
+		.minor  = 0,
+		.incr   = 0,
+	},
+	.core_regs = {
+		.version               = 0x38,
+		.control               = 0x0,
+		.result_cnt            = 0x4,
+		.result_addr           = 0x20,
+		.image_addr            = 0x24,
+		.work_addr             = 0x28,
+		.ro_mode               = 0x34,
+		.results_reg_base      = 0x400,
+		.raw_results_reg_base  = 0x800,
+	},
+	.wrapper_regs = {
+		.wrapper_version       = 0x0,
+		.cgc_disable           = 0x4,
+		.hw_stop               = 0x8,
+		.sw_reset              = 0x10,
+		.vbif_req_priority     = 0x20,
+		.vbif_priority_level   = 0x24,
+		.vbif_done_status      = 0x34,
+		.irq_mask              = 0x50,
+		.irq_status            = 0x54,
+		.irq_clear             = 0x58,
+	},
+	.results = {
+		.max_faces             = 35,
+		.per_face_entries      = 4,
+		.raw_results_available = true,
+		.raw_results_entries   = 512,
+	},
+	.enable_errata_wa = {
+		.single_irq_only         = true,
+		.ro_mode_enable_always   = true,
+		.ro_mode_results_invalid = true,
+	},
+	.irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) |
+		CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) |
+		CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE),
+	.qos_priority       = 4,
+	.qos_priority_level = 4,
+	.supported_modes    = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID,
+	.ro_mode_supported  = true,
+};
+
+#endif /* _CAM_FD_HW_V501_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
index d47350c..502c95d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -177,7 +177,7 @@
 };
 
 int cam_icp_context_init(struct cam_icp_context *ctx,
-	struct cam_hw_mgr_intf *hw_intf)
+	struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id)
 {
 	int rc;
 
@@ -187,8 +187,8 @@
 		goto err;
 	}
 
-	rc = cam_context_init(ctx->base, icp_dev_name, NULL, hw_intf,
-		ctx->req_base, CAM_CTX_REQ_MAX);
+	rc = cam_context_init(ctx->base, icp_dev_name, CAM_ICP, ctx_id,
+		NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "Camera Context Base init failed");
 		goto err;
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
index 709fc56..0c3a360 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,9 +35,10 @@
  * cam_icp_context_init() - ICP context init
  * @ctx: Pointer to context
  * @hw_intf: Pointer to ICP hardware interface
+ * @ctx_id: ID for this context
  */
 int cam_icp_context_init(struct cam_icp_context *ctx,
-	struct cam_hw_mgr_intf *hw_intf);
+	struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id);
 
 /**
  * cam_icp_context_deinit() - ICP context deinit
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
index 51499de..4f91f73 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -167,7 +167,7 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i];
 		rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i],
-					hw_mgr_intf);
+					hw_mgr_intf, i);
 		if (rc) {
 			CAM_ERR(CAM_ICP, "ICP context init failed");
 			goto ctx_fail;
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index b9b59a1..178e734 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -110,7 +110,7 @@
 /**
  * cam_hfi_deinit() - cleanup HFI
  */
-void cam_hfi_deinit(void);
+void cam_hfi_deinit(void __iomem *icp_base);
 /**
  * hfi_set_debug_level() - set debug level
  * @lvl: FW debug message level
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
index 0412b8a..7b2cb8b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,30 @@
 #define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT               0x3
 
 /**
+ * struct abort_data
+ * @num_req_ids: Number of req ids
+ * @num_req_id: point to specific req id
+ *
+ * create abort data
+ */
+struct abort_data {
+	uint32_t num_req_ids;
+	uint32_t num_req_id[1];
+};
+
+/**
+ * struct hfi_cmd_data
+ * @abort: abort data
+ * @user data: user supplied argument
+ *
+ * create session abort data
+ */
+struct hfi_cmd_abort {
+	struct abort_data abort;
+	uint64_t user_data;
+} __packed;
+
+/**
  * struct hfi_cmd_abort_destroy
  * @user_data: user supplied data
  *
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 77f33d0..f95f8eb 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -124,7 +124,7 @@
 	 * firmware to process
 	 */
 	wmb();
-	cam_io_w((uint32_t)INTR_ENABLE,
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
 		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
 err:
 	mutex_unlock(&hfi_cmd_q_mutex);
@@ -222,6 +222,10 @@
 
 	q->qhdr_read_idx = new_read_idx;
 	*words_read = size_in_words;
+	/* Memory Barrier to make sure message
+	 * queue parameters are updated after read
+	 */
+	wmb();
 err:
 	mutex_unlock(&hfi_msg_q_mutex);
 	return rc;
@@ -445,17 +449,17 @@
 
 	val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN);
-	cam_io_w(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 
 	val = cam_io_r(icp_base + HFI_REG_A5_CSR_NSEC_RESET);
-	cam_io_w(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+	cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
 }
 
 void cam_hfi_enable_cpu(void __iomem *icp_base)
 {
-	cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN,
+	cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN,
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
-	cam_io_w((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+	cam_io_w_mb((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
 }
 
 int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
@@ -464,23 +468,11 @@
 	int rc = 0;
 	uint32_t data;
 	uint32_t fw_version, status = 0;
+	uint32_t retry_cnt = 0;
 
 	cam_hfi_enable_cpu(icp_base);
 	g_hfi->csr_base = icp_base;
 
-	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
-		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
-
-	if (rc) {
-		CAM_ERR(CAM_HFI, "timed out , status = %u", status);
-		return -EINVAL;
-	}
-
-	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
-	CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version);
-
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
-
 	if (debug) {
 		cam_io_w_mb(ICP_FLAG_A5_CTRL_DBG_EN,
 			(icp_base + HFI_REG_A5_CSR_A5_CONTROL));
@@ -499,20 +491,54 @@
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	}
 
+	while (retry_cnt < HFI_MAX_POLL_TRY) {
+		readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+			status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000);
+
+		CAM_DBG(CAM_HFI, "1: status = %u", status);
+		status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+		CAM_DBG(CAM_HFI, "2: status = %u", status);
+		if (status == ICP_INIT_RESP_SUCCESS)
+			break;
+
+		if (status == ICP_INIT_RESP_FAILED) {
+			CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u",
+				status);
+			fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+			CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+			return -EINVAL;
+		}
+		retry_cnt++;
+	}
+
+	if ((retry_cnt == HFI_MAX_POLL_TRY) &&
+		(status == ICP_INIT_RESP_RESET)) {
+		CAM_ERR(CAM_HFI, "Reached Max retries. status = %u",
+				status);
+		fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+		CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+		return -EINVAL;
+	}
+
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
+		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+	CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version);
+
 	data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS);
 	CAM_DBG(CAM_HFI, "wfi status = %x", (int)data);
 
-	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
 		icp_base + HFI_REG_SHARED_MEM_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.len,
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
 		icp_base + HFI_REG_SHARED_MEM_SIZE);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova,
 		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len,
 		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
 
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 	return rc;
 }
 
@@ -524,6 +550,7 @@
 	struct hfi_qtbl_hdr *qtbl_hdr;
 	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
 	uint32_t hw_version, soc_version, fw_version, status = 0;
+	uint32_t retry_cnt = 0;
 
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);
@@ -560,7 +587,7 @@
 		 * disabling the clock gating on both V1 and V2 until the
 		 * hardware team root causes this
 		 */
-		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
+		cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN |
 			ICP_FLAG_CSR_WAKE_UP_EN |
 			ICP_CSR_EN_CLKGATE_WFI,
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
@@ -677,24 +704,48 @@
 		break;
 	}
 
-	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
 		icp_base + HFI_REG_SHARED_MEM_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.len,
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
 		icp_base + HFI_REG_SHARED_MEM_SIZE);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova,
 		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len,
 		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
-	cam_io_w((uint32_t)ICP_INIT_REQUEST_SET,
+	cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_SET,
 		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
 
 	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
 
-	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
-		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
-	if (rc) {
-		CAM_ERR(CAM_HFI, "timed out , status = %u", status);
+	while (retry_cnt < HFI_MAX_POLL_TRY) {
+		readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+			status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000);
+
+		CAM_DBG(CAM_HFI, "1: status = %u rc = %d", status, rc);
+		status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+		CAM_DBG(CAM_HFI, "2: status = %u rc = %d", status, rc);
+		if (status == ICP_INIT_RESP_SUCCESS)
+			break;
+
+		if (status == ICP_INIT_RESP_FAILED) {
+			CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u",
+				status);
+			fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+			CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+			goto regions_fail;
+		}
+		retry_cnt++;
+	}
+
+	if ((retry_cnt == HFI_MAX_POLL_TRY) &&
+		(status == ICP_INIT_RESP_RESET)) {
+		CAM_ERR(CAM_HFI, "Reached Max retries. status = %u",
+				status);
+		fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+		CAM_ERR(CAM_HFI,
+			"hw version : : [%x], fw version : [%x]",
+			hw_version, fw_version);
 		goto regions_fail;
 	}
 
@@ -706,7 +757,8 @@
 	g_hfi->hfi_state = HFI_READY;
 	g_hfi->cmd_q_state = true;
 	g_hfi->msg_q_state = true;
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
+		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 
 	mutex_unlock(&hfi_cmd_q_mutex);
 	mutex_unlock(&hfi_msg_q_mutex);
@@ -714,14 +766,14 @@
 	return rc;
 regions_fail:
 	kfree(g_hfi);
+	g_hfi = NULL;
 alloc_fail:
 	mutex_unlock(&hfi_cmd_q_mutex);
 	mutex_unlock(&hfi_msg_q_mutex);
 	return rc;
 }
 
-
-void cam_hfi_deinit(void)
+void cam_hfi_deinit(void __iomem *icp_base)
 {
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);
@@ -734,7 +786,10 @@
 	g_hfi->cmd_q_state = false;
 	g_hfi->msg_q_state = false;
 
-	cam_io_w((uint32_t)INTR_DISABLE,
+	cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_RESET,
+		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
+
+	cam_io_w_mb((uint32_t)INTR_DISABLE,
 		g_hfi->csr_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 	kzfree(g_hfi);
 	g_hfi = NULL;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
index aeec16c..4b5f22e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -207,37 +207,38 @@
 
 	if (!core_info->fw_elf) {
 		CAM_ERR(CAM_ICP, "Invalid elf size");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto fw_download_failed;
 	}
 
 	fw_start = core_info->fw_elf->data;
 	rc = cam_icp_validate_fw(fw_start);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "fw elf validation failed");
-		return -EINVAL;
+		goto fw_download_failed;
 	}
 
 	rc = cam_icp_get_fw_size(fw_start, &fw_size);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to get fw size");
-		return rc;
+		goto fw_download_failed;
 	}
 
 	if (core_info->fw_buf_len < fw_size) {
 		CAM_ERR(CAM_ICP, "mismatch in fw size: %u %llu",
 			fw_size, core_info->fw_buf_len);
-		goto fw_alloc_failed;
+		rc = -EINVAL;
+		goto fw_download_failed;
 	}
 
 	rc = cam_icp_program_fw(fw_start, core_info);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "fw program is failed");
-		goto fw_program_failed;
+		goto fw_download_failed;
 	}
 
-	return 0;
-fw_program_failed:
-fw_alloc_failed:
+fw_download_failed:
+	release_firmware(core_info->fw_elf);
 	return rc;
 }
 
@@ -387,7 +388,6 @@
 	switch (cmd_type) {
 	case CAM_ICP_A5_CMD_FW_DOWNLOAD:
 		rc = cam_a5_download_fw(device_priv);
-
 		break;
 	case CAM_ICP_A5_CMD_SET_FW_BUF: {
 		struct cam_icp_a5_set_fw_buf_info *fw_buf_info = cmd_args;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
index b7b636c..d2314c4 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -138,9 +138,22 @@
 int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info,
 	uint32_t clk_rate)
 {
+	int32_t src_clk_idx;
+
 	if (!soc_info)
 		return -EINVAL;
 
+	src_clk_idx = soc_info->src_clk_idx;
+
+	if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) &&
+		(soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) &&
+		(clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) {
+		CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d",
+			clk_rate,
+			soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]);
+		clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx];
+	}
+
 	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
 		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
 }
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 0012b34..59d3534 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
@@ -116,7 +117,12 @@
 		if (ctx_data->clk_info.clk_rate[i] >= base_clk)
 			return i;
 
-	return 0;
+	/*
+	 * Caller has to ensure returned index is within array
+	 * size bounds while accessing that index.
+	 */
+
+	return i;
 }
 
 static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr,
@@ -132,7 +138,7 @@
 	curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data,
 		hw_mgr_clk_info->curr_clk);
 
-	CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %lld %lld",
+	CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %d %d",
 		base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk,
 		hw_mgr_clk_info->curr_clk);
 
@@ -192,9 +198,9 @@
 	struct cam_hw_info *dev = NULL;
 
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
-		dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+		dev_intf = hw_mgr->bps_dev_intf;
 	else
-		dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+		dev_intf = hw_mgr->ipe0_dev_intf;
 
 	if (!dev_intf) {
 		CAM_ERR(CAM_ICP, "dev_intf is invalid");
@@ -254,9 +260,9 @@
 	struct cam_hw_intf *dev_intf = NULL;
 	struct cam_a5_clk_update_cmd clk_upd_cmd;
 
-	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
-	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
-	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
+	ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
+	bps_dev_intf = hw_mgr->bps_dev_intf;
 
 	clk_info->base_clk = 0;
 	clk_info->curr_clk = 0;
@@ -265,7 +271,7 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		ctx_data = &hw_mgr->ctx_data[i];
 		mutex_lock(&ctx_data->ctx_mutex);
-		if ((ctx_data->state != CAM_ICP_CTX_STATE_FREE) &&
+		if ((ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED) &&
 			(ICP_DEV_TYPE_TO_CLK_TYPE(ctx_data->
 			icp_dev_acquire_info->dev_type) == clk_info->hw_type))
 			cam_icp_ctx_clk_info_init(ctx_data);
@@ -305,7 +311,96 @@
 	return 0;
 }
 
-static void cam_icp_timer_cb(unsigned long data)
+static int32_t cam_icp_ctx_timer(void *priv, void *data)
+{
+	struct clk_work_data *task_data = (struct clk_work_data *)data;
+	struct cam_icp_hw_ctx_data *ctx_data =
+		(struct cam_icp_hw_ctx_data *)task_data->data;
+	struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr;
+	uint32_t id;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	struct cam_hw_intf *dev_intf = NULL;
+	struct cam_icp_clk_info *clk_info;
+	struct cam_icp_cpas_vote clk_update;
+
+	if (!ctx_data) {
+		CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) ||
+		(ctx_data->watch_dog_reset_counter == 0)) {
+		CAM_DBG(CAM_ICP, "state %d, counter=%d",
+			ctx_data->state, ctx_data->watch_dog_reset_counter);
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return 0;
+	}
+
+	CAM_DBG(CAM_ICP,
+		"E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u",
+		ctx_data->ctx_id,
+		ctx_data->clk_info.uncompressed_bw,
+		ctx_data->clk_info.compressed_bw,
+		ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk);
+
+	ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
+	ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
+	bps_dev_intf = hw_mgr->bps_dev_intf;
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk");
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return -EINVAL;
+	}
+
+	if (!ctx_data->icp_dev_acquire_info) {
+		CAM_WARN(CAM_ICP, "NULL acquire info");
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return -EINVAL;
+	}
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
+		dev_intf = bps_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+		id = CAM_ICP_BPS_CMD_VOTE_CPAS;
+	} else {
+		dev_intf = ipe0_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+		id = CAM_ICP_IPE_CMD_VOTE_CPAS;
+	}
+
+	clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw;
+	clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw;
+	ctx_data->clk_info.uncompressed_bw = 0;
+	ctx_data->clk_info.compressed_bw = 0;
+	ctx_data->clk_info.curr_fc = 0;
+	ctx_data->clk_info.base_clk = 0;
+
+	clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC;
+	clk_update.ahb_vote.vote.freq = clk_info->curr_clk;
+	clk_update.ahb_vote_valid = true;
+	clk_update.axi_vote.compressed_bw = clk_info->compressed_bw;
+	clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw;
+	clk_update.axi_vote_valid = true;
+	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
+		&clk_update, sizeof(clk_update));
+
+	CAM_DBG(CAM_ICP,
+		"X :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u",
+		ctx_data->ctx_id,
+		ctx_data->clk_info.uncompressed_bw,
+		ctx_data->clk_info.compressed_bw,
+		ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk);
+
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	return 0;
+}
+
+static void cam_icp_ctx_timer_cb(unsigned long data)
 {
 	unsigned long flags;
 	struct crm_workq_task *task;
@@ -313,7 +408,31 @@
 	struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
 
 	spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags);
-	task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work);
+	if (!task) {
+		CAM_ERR(CAM_ICP, "no empty task");
+		spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
+		return;
+	}
+
+	task_data = (struct clk_work_data *)task->payload;
+	task_data->data = timer->parent;
+	task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+	task->process_cb = cam_icp_ctx_timer;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
+}
+
+static void cam_icp_device_timer_cb(unsigned long data)
+{
+	unsigned long flags;
+	struct crm_workq_task *task;
+	struct clk_work_data *task_data;
+	struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
+
+	spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work);
 	if (!task) {
 		CAM_ERR(CAM_ICP, "no empty task");
 		spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
@@ -342,13 +461,29 @@
 		hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 		hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 		hw_mgr->clk_info[i].hw_type = i;
+		hw_mgr->clk_info[i].watch_dog_reset_counter = 0;
 	}
 	hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ;
 
 	return 0;
 }
 
-static int cam_icp_timer_start(struct cam_icp_hw_mgr *hw_mgr)
+static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data)
+{
+	int rc = 0;
+
+	rc = crm_timer_init(&ctx_data->watch_dog,
+		200, ctx_data, &cam_icp_ctx_timer_cb);
+	if (rc)
+		CAM_ERR(CAM_ICP, "Failed to start timer");
+
+	ctx_data->watch_dog_reset_counter = 0;
+
+	CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id);
+	return rc;
+}
+
+static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr)
 {
 	int rc = 0;
 	int i;
@@ -356,21 +491,70 @@
 	for (i = 0; i < ICP_CLK_HW_MAX; i++)  {
 		if (!hw_mgr->clk_info[i].watch_dog) {
 			rc = crm_timer_init(&hw_mgr->clk_info[i].watch_dog,
-				3000, &hw_mgr->clk_info[i], &cam_icp_timer_cb);
+				3000, &hw_mgr->clk_info[i],
+				&cam_icp_device_timer_cb);
+
 			if (rc)
 				CAM_ERR(CAM_ICP, "Failed to start timer %d", i);
+
+			hw_mgr->clk_info[i].watch_dog_reset_counter = 0;
 		}
 	}
 
 	return rc;
 }
 
-static void cam_icp_timer_stop(struct cam_icp_hw_mgr *hw_mgr)
+static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data)
 {
-	if (!hw_mgr->bps_ctxt_cnt)
+	if (ctx_data->watch_dog) {
+		CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id);
+		ctx_data->watch_dog_reset_counter = 0;
+		crm_timer_exit(&ctx_data->watch_dog);
+		ctx_data->watch_dog = NULL;
+	}
+
+	return 0;
+}
+
+static void cam_icp_device_timer_stop(struct cam_icp_hw_mgr *hw_mgr)
+{
+	if (!hw_mgr->bps_ctxt_cnt &&
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) {
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0;
 		crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog);
-	else if (!hw_mgr->ipe_ctxt_cnt)
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL;
+	}
+
+	if (!hw_mgr->ipe_ctxt_cnt &&
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) {
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0;
 		crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog);
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL;
+	}
+}
+
+static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data)
+{
+	if (ctx_data && ctx_data->watch_dog) {
+		ctx_data->watch_dog_reset_counter++;
+		CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d",
+			ctx_data->ctx_id, ctx_data->watch_dog_reset_counter);
+		crm_timer_reset(ctx_data->watch_dog);
+	}
+
+	return 0;
+}
+
+static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr,
+	int device_index)
+{
+	if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr))
+		return;
+
+	if (hw_mgr->clk_info[device_index].watch_dog) {
+		crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog);
+		hw_mgr->clk_info[device_index].watch_dog_reset_counter++;
+	}
 }
 
 static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles,
@@ -420,7 +604,9 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		ctx_data = &hw_mgr->ctx_data[i];
 		if (ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED &&
-			ctx_data->icp_dev_acquire_info->dev_type == dev_type)
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx_data->icp_dev_acquire_info->dev_type) ==
+			ICP_DEV_TYPE_TO_CLK_TYPE(dev_type))
 			hw_mgr_clk_info->base_clk +=
 				ctx_data->clk_info.base_clk;
 	}
@@ -575,7 +761,8 @@
 		hw_mgr_clk_info->over_clked = 0;
 		rc = false;
 	}  else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) {
-		hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk;
+		hw_mgr_clk_info->curr_clk = cam_icp_get_actual_clk_rate(hw_mgr,
+			ctx_data, hw_mgr_clk_info->base_clk);
 		rc = true;
 	}
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -633,7 +820,13 @@
 	 * recalculate bandwidth of all contexts of same hardware and update
 	 * voting of bandwidth
 	 */
-	if (clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw)
+	CAM_DBG(CAM_ICP, "ubw ctx = %lld clk_info ubw = %lld busy = %d",
+		ctx_data->clk_info.uncompressed_bw,
+		clk_info->uncompressed_bw, busy);
+
+	if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) &&
+		(ctx_data->clk_info.uncompressed_bw ==
+		hw_mgr_clk_info->uncompressed_bw))
 		return false;
 
 	if (busy &&
@@ -647,13 +840,18 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		ctx = &hw_mgr->ctx_data[i];
 		if (ctx->state == CAM_ICP_CTX_STATE_ACQUIRED &&
-			ctx->icp_dev_acquire_info->dev_type ==
-			ctx_data->icp_dev_acquire_info->dev_type) {
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx->icp_dev_acquire_info->dev_type) ==
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx_data->icp_dev_acquire_info->dev_type)) {
 			mutex_lock(&hw_mgr->hw_mgr_mutex);
 			hw_mgr_clk_info->uncompressed_bw +=
 				ctx->clk_info.uncompressed_bw;
 			hw_mgr_clk_info->compressed_bw +=
 				ctx->clk_info.compressed_bw;
+			CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld",
+				hw_mgr_clk_info->uncompressed_bw,
+				hw_mgr_clk_info->compressed_bw);
 			mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		}
 	}
@@ -671,12 +869,13 @@
 	uint64_t req_id;
 	struct cam_icp_clk_info *hw_mgr_clk_info;
 
+	cam_icp_ctx_timer_reset(ctx_data);
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
-		crm_timer_reset(hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog);
+		cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS);
 		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
 		CAM_DBG(CAM_ICP, "Reset bps timer");
 	} else {
-		crm_timer_reset(hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog);
+		cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE);
 		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
 		CAM_DBG(CAM_ICP, "Reset ipe timer");
 	}
@@ -827,11 +1026,13 @@
 	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
 		&clk_update, sizeof(clk_update));
 
-	if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS)
-		if (ipe1_dev_intf)
-			ipe1_dev_intf->hw_ops.process_cmd(
-				ipe1_dev_intf->hw_priv, id,
-				&clk_update, sizeof(clk_update));
+	/*
+	 * Consolidated bw needs to be voted on only one IPE client. Otherwise
+	 * total bw that we vote at bus client would be doubled. So either
+	 * remove voting on IPE1 or divide the vote for each IPE client
+	 * and vote to cpas - cpas will add up and vote full bw to sf client
+	 * anyway.
+	 */
 
 	return 0;
 }
@@ -870,7 +1071,11 @@
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
 		if (hw_mgr->bps_ctxt_cnt++)
 			goto end;
-		bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
+		if (!hw_mgr->bps_clk_state) {
+			bps_dev_intf->hw_ops.init(
+				bps_dev_intf->hw_priv, NULL, 0);
+			hw_mgr->bps_clk_state = true;
+		}
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			bps_dev_intf->hw_ops.process_cmd(
 				bps_dev_intf->hw_priv,
@@ -880,15 +1085,18 @@
 	} else {
 		if (hw_mgr->ipe_ctxt_cnt++)
 			goto end;
-
-		ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
+		if (!hw_mgr->ipe_clk_state)
+			ipe0_dev_intf->hw_ops.init(
+				ipe0_dev_intf->hw_priv, NULL, 0);
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			ipe0_dev_intf->hw_ops.process_cmd(
 				ipe0_dev_intf->hw_priv,
 				CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
 		}
 
-		if ((icp_hw_mgr.ipe1_enable) && (ipe1_dev_intf)) {
+		if ((icp_hw_mgr.ipe1_enable) &&
+			(ipe1_dev_intf) &&
+			(!hw_mgr->ipe_clk_state)) {
 			ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 
@@ -899,6 +1107,7 @@
 					NULL, 0);
 			}
 		}
+		hw_mgr->ipe_clk_state = true;
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info |
 				(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1);
@@ -908,6 +1117,8 @@
 	CAM_DBG(CAM_ICP, "core_info %X",  hw_mgr->core_info);
 	if (icp_hw_mgr.ipe_bps_pc_flag)
 		rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info);
+	else if (icp_hw_mgr.icp_pc_flag)
+		rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
 	else
 		rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
 end:
@@ -953,7 +1164,11 @@
 				hw_mgr->core_info & (~ICP_PWR_CLP_BPS);
 		}
 
-		bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+		if (hw_mgr->bps_clk_state) {
+			bps_dev_intf->hw_ops.deinit
+				(bps_dev_intf->hw_priv, NULL, 0);
+			hw_mgr->bps_clk_state = false;
+		}
 	} else {
 		CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt);
 		if (ctx_data)
@@ -968,7 +1183,10 @@
 				CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
 
 		}
-		ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+
+		if (hw_mgr->ipe_clk_state)
+			ipe0_dev_intf->hw_ops.deinit(
+				ipe0_dev_intf->hw_priv, NULL, 0);
 
 		if (ipe1_dev_intf) {
 			if (icp_hw_mgr.ipe_bps_pc_flag) {
@@ -978,9 +1196,12 @@
 					NULL, 0);
 			}
 
+		if (hw_mgr->ipe_clk_state)
 			ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 		}
+
+		hw_mgr->ipe_clk_state = false;
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info &
 				(~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1));
@@ -1141,11 +1362,11 @@
 		if (!hfi_frame_process->in_free_resource[i])
 			continue;
 
-		CAM_INFO(CAM_ICP, "Delete merged sync in object: %d",
+		CAM_DBG(CAM_ICP, "Delete merged sync in object: %d",
 			ctx_data->hfi_frame_process.in_free_resource[i]);
 		cam_sync_destroy(
 			ctx_data->hfi_frame_process.in_free_resource[i]);
-		ctx_data->hfi_frame_process.in_resource[i] = 0;
+		ctx_data->hfi_frame_process.in_free_resource[i] = 0;
 	}
 
 	return 0;
@@ -1174,9 +1395,10 @@
 
 	clk_type = ICP_DEV_TYPE_TO_CLK_TYPE(ctx_data->icp_dev_acquire_info->
 		dev_type);
-	crm_timer_reset(icp_hw_mgr.clk_info[clk_type].watch_dog);
+	cam_icp_device_timer_reset(&icp_hw_mgr, clk_type);
 
 	mutex_lock(&ctx_data->ctx_mutex);
+	cam_icp_ctx_timer_reset(ctx_data);
 	if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
 		CAM_DBG(CAM_ICP, "ctx %u is in %d state",
 			ctx_data->ctx_id, ctx_data->state);
@@ -1227,8 +1449,6 @@
 	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
 		CAM_ERR(CAM_ICP, "failed with error : %u",
 		ioconfig_ack->err_type);
-		cam_icp_mgr_handle_frame_process(msg_ptr,
-			ICP_FRAME_PROCESS_FAILURE);
 		return -EIO;
 	}
 
@@ -1301,6 +1521,7 @@
 {
 	struct hfi_msg_create_handle_ack *create_handle_ack = NULL;
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	int rc = 0;
 
 	create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr;
 	if (!create_handle_ack) {
@@ -1317,11 +1538,15 @@
 	if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) {
 		ctx_data->fw_handle = create_handle_ack->fw_handle;
 		CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle);
-		complete(&ctx_data->wait_complete);
-	} else
-		CAM_WARN(CAM_ICP, "Timeout failed to create fw handle");
-
-	return 0;
+	} else {
+		CAM_WARN(CAM_ICP,
+			"This ctx is no longer in use current state: %d",
+			ctx_data->state);
+		ctx_data->fw_handle = 0;
+		rc = -EPERM;
+	}
+	complete(&ctx_data->wait_complete);
+	return rc;
 }
 
 static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr)
@@ -1385,21 +1610,38 @@
 {
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
 	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_info *a5_dev = NULL;
 	int rc = 0;
 
+	a5_dev_intf = icp_hw_mgr.a5_dev_intf;
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		return -EINVAL;
+	}
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	switch (msg_ptr[ICP_PACKET_OPCODE]) {
-	case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY:
-	case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY:
 	case HFI_IPEBPS_CMD_OPCODE_IPE_ABORT:
 	case HFI_IPEBPS_CMD_OPCODE_BPS_ABORT:
-		CAM_DBG(CAM_ICP, "received IPE/BPS_DESTROY/ABORT:");
+		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		if (ctx_data->state != CAM_ICP_CTX_STATE_FREE)
+			complete(&ctx_data->wait_complete);
+		CAM_DBG(CAM_ICP, "received IPE/BPS/ ABORT: ctx_state =%d",
+			ctx_data->state);
+		break;
+	case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY:
 		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
 		ctx_data =
 			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
 		if ((ctx_data->state == CAM_ICP_CTX_STATE_RELEASE) ||
-			(ctx_data->state == CAM_ICP_CTX_STATE_IN_USE))
+			(ctx_data->state == CAM_ICP_CTX_STATE_IN_USE)) {
 			complete(&ctx_data->wait_complete);
-
+		}
+		CAM_DBG(CAM_ICP, "received IPE/BPS/ DESTROY: ctx_state =%d",
+			ctx_data->state);
 		break;
 	default:
 		CAM_ERR(CAM_ICP, "Invalid opcode : %u",
@@ -1407,7 +1649,6 @@
 		rc = -EINVAL;
 		break;
 	}
-
 	return rc;
 }
 
@@ -1531,10 +1772,14 @@
 		read_len = read_len << BYTE_WORD_SHIFT;
 		msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
 		while (true) {
-			rc = cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr,
+			cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr,
 				&msg_processed_len);
-			if (rc)
-				return rc;
+
+			if (!msg_processed_len) {
+				CAM_ERR(CAM_ICP, "Failed to read");
+				rc = -EINVAL;
+				break;
+			}
 
 			read_len -= msg_processed_len;
 			if (read_len > 0) {
@@ -1808,12 +2053,20 @@
 		return 0;
 	}
 
-	if (ipe1_dev_intf) {
+	if (ipe1_dev_intf && hw_mgr->ipe_clk_state) {
 		ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 	}
-	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
-	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+
+	if (hw_mgr->ipe_clk_state)
+		ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (hw_mgr->bps_clk_state)
+		bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+
+
+	hw_mgr->bps_clk_state = false;
+	hw_mgr->ipe_clk_state = false;
+
 	return 0;
 }
 static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
@@ -1831,12 +2084,15 @@
 	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 
-	if (!hw_mgr->icp_pc_flag)
+	if (!hw_mgr->icp_pc_flag) {
+		cam_hfi_disable_cpu(
+			a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 		rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
-	else
+	} else {
 		rc = cam_icp_mgr_send_pc_prep(hw_mgr);
-
-	cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+		cam_hfi_disable_cpu(
+			a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	}
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
 	CAM_DBG(CAM_ICP, "EXIT");
 
@@ -1897,7 +2153,7 @@
 	int rc = 0;
 	unsigned long rem_jiffies;
 	size_t packet_size;
-	int timeout = 5000;
+	int timeout = 100;
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async *abort_cmd;
 	struct crm_workq_task *task;
@@ -1908,9 +2164,10 @@
 
 	packet_size =
 		sizeof(struct hfi_cmd_ipebps_async) +
-		sizeof(struct hfi_cmd_abort_destroy) -
+		sizeof(struct hfi_cmd_abort) -
 		sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct);
 	abort_cmd = kzalloc(packet_size, GFP_KERNEL);
+	CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size);
 	if (!abort_cmd) {
 		rc = -ENOMEM;
 		return rc;
@@ -1928,8 +2185,6 @@
 	abort_cmd->fw_handles[0] = ctx_data->fw_handle;
 	abort_cmd->user_data1 = (uint64_t)ctx_data;
 	abort_cmd->user_data2 = (uint64_t)0x0;
-	memcpy(abort_cmd->payload.direct, &ctx_data->temp_payload,
-		sizeof(uint64_t));
 
 	task_data = (struct hfi_cmd_work_data *)task->payload;
 	task_data->data = (void *)abort_cmd;
@@ -1942,7 +2197,6 @@
 		kfree(abort_cmd);
 		return rc;
 	}
-
 	CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK",
 		ctx_data->fw_handle, ctx_data);
 	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
@@ -1952,7 +2206,6 @@
 		CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command");
 	}
 
-	kfree(abort_cmd);
 	return rc;
 }
 
@@ -1960,7 +2213,7 @@
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
 	int rc = 0;
-	int timeout = 5000;
+	int timeout = 100;
 	unsigned long rem_jiffies;
 	size_t packet_size;
 	struct hfi_cmd_work_data *task_data;
@@ -2007,7 +2260,6 @@
 		kfree(destroy_cmd);
 		return rc;
 	}
-
 	CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK",
 		ctx_data->fw_handle, ctx_data);
 	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
@@ -2019,8 +2271,6 @@
 		if (icp_hw_mgr.a5_debug_q)
 			cam_icp_mgr_process_dbg_buf();
 	}
-
-	kfree(destroy_cmd);
 	return rc;
 }
 
@@ -2047,6 +2297,7 @@
 		&hw_mgr->ctx_data[ctx_id], 0);
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE;
 	CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id);
+	cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]);
 	cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
 	cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]);
 
@@ -2063,6 +2314,7 @@
 	kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
 	hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE;
+	cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]);
 	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 
 	CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id);
@@ -2091,12 +2343,15 @@
 	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
 	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->bps_clk_state = false;
+	hw_mgr->ipe_clk_state = false;
 }
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
 {
 	struct cam_icp_hw_mgr *hw_mgr = hw_priv;
 	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_info *a5_dev = NULL;
 	struct cam_icp_a5_set_irq_cb irq_cb;
 	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
 	int rc = 0;
@@ -2108,14 +2363,13 @@
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return 0;
 	}
-
 	a5_dev_intf = hw_mgr->a5_dev_intf;
 	if (!a5_dev_intf) {
 		CAM_DBG(CAM_ICP, "a5_dev_intf is NULL");
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return -EINVAL;
 	}
-
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	fw_buf_info.kva = 0;
 	fw_buf_info.iova = 0;
 	fw_buf_info.len = 0;
@@ -2126,9 +2380,8 @@
 		sizeof(fw_buf_info));
 	if (rc)
 		CAM_ERR(CAM_ICP, "nullify the fw buf failed");
-
-	cam_hfi_deinit();
-
+	cam_hfi_deinit(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 	irq_cb.icp_hw_mgr_cb = NULL;
 	irq_cb.data = NULL;
 	rc = a5_dev_intf->hw_ops.process_cmd(
@@ -2142,7 +2395,6 @@
 	hw_mgr->fw_download = false;
 	hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
-
 	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
 }
@@ -2184,11 +2436,16 @@
 			goto ipe1_dev_init_failed;
 	}
 
+	hw_mgr->bps_clk_state = true;
+	hw_mgr->ipe_clk_state = true;
+
 	return rc;
 ipe1_dev_init_failed:
 	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->ipe_clk_state = false;
 ipe0_dev_init_failed:
 	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->bps_clk_state = false;
 bps_dev_init_failed:
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
 a5_dev_init_failed:
@@ -2337,10 +2594,10 @@
 	if (hw_mgr->fw_download  == false) {
 		CAM_DBG(CAM_ICP, "Downloading FW");
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
-		cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
+		rc = cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
 		mutex_lock(&hw_mgr->hw_mgr_mutex);
 		CAM_DBG(CAM_ICP, "FW Download Done Exit");
-		return 0;
+		return rc;
 	}
 
 	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
@@ -2386,34 +2643,24 @@
 	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	rc = cam_icp_allocate_hfi_mem();
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto alloc_hfi_mem_failed;
-	}
 
 	rc = cam_icp_mgr_device_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto dev_init_fail;
-	}
 
 	rc = cam_icp_mgr_fw_download(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto fw_download_failed;
-	}
 
 	rc = cam_icp_mgr_hfi_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto hfi_init_failed;
-	}
 
 	rc = cam_icp_mgr_send_fw_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto fw_init_failed;
-	}
 
 	hw_mgr->ctxt_cnt = 0;
 	hw_mgr->fw_download = true;
@@ -2428,22 +2675,32 @@
 	if (download_fw_args)
 		icp_pc = *((bool *)download_fw_args);
 
+	if (download_fw_args && icp_pc == true && hw_mgr->icp_pc_flag) {
+		rc = cam_ipe_bps_deint(hw_mgr);
+		CAM_DBG(CAM_ICP, "deinit all clocks");
+	}
+
 	if (download_fw_args && icp_pc == true)
 		return rc;
 
+	rc = cam_ipe_bps_deint(hw_mgr);
 	rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
+	CAM_DBG(CAM_ICP, "deinit all clocks at boot up");
 
 	return rc;
 
 fw_init_failed:
-	cam_hfi_deinit();
+	cam_hfi_deinit(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 hfi_init_failed:
-	cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	cam_hfi_disable_cpu(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 fw_download_failed:
 	cam_icp_mgr_device_deinit(hw_mgr);
 dev_init_fail:
 	cam_icp_free_hfi_mem();
 alloc_hfi_mem_failed:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 }
 
@@ -2579,8 +2836,23 @@
 			packet->header.op_code & 0xff);
 		return -EINVAL;
 	}
-	CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u",
-			packet->num_cmd_buf, packet->num_patches);
+
+	if (packet->num_io_configs > IPE_IO_IMAGES_MAX) {
+		CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d",
+			IPE_IO_IMAGES_MAX, packet->num_io_configs);
+		return -EINVAL;
+	}
+
+	if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) {
+		CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d",
+			CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u %u %u",
+			packet->num_cmd_buf,
+			packet->num_io_configs, IPE_IO_IMAGES_MAX,
+			packet->num_patches);
 	return 0;
 }
 
@@ -3173,11 +3445,12 @@
 		mutex_lock(&hw_mgr->hw_mgr_mutex);
 		cam_icp_hw_mgr_reset_clk_info(hw_mgr);
 		hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
+		rc = cam_ipe_bps_deint(hw_mgr);
 	}
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
-		cam_icp_timer_stop(hw_mgr);
+		cam_icp_device_timer_stop(hw_mgr);
 
 	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
@@ -3266,6 +3539,11 @@
 		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
 	}
 
+	if (ctx_data->fw_handle == 0) {
+		CAM_ERR(CAM_ICP, "Invalid handle created");
+		rc = -EINVAL;
+	}
+
 	return rc;
 }
 
@@ -3429,12 +3707,13 @@
 	}
 	ctx_data = &hw_mgr->ctx_data[ctx_id];
 	ctx_data->ctx_id = ctx_id;
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	mutex_lock(&ctx_data->ctx_mutex);
 	rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto acquire_info_failed;
+	}
 	icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
 
 	rc = cam_mem_get_io_buf(
@@ -3443,6 +3722,7 @@
 		&io_buf_addr, &io_buf_size);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to get src buf info from io desc");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto get_io_buf_failed;
 	}
 
@@ -3450,7 +3730,6 @@
 		icp_dev_acquire_info->io_config_cmd_handle,
 		(void *)io_buf_addr, io_buf_size);
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	if (!hw_mgr->ctxt_cnt) {
 		rc = cam_icp_clk_info_init(hw_mgr, ctx_data);
 		if (rc) {
@@ -3464,6 +3743,9 @@
 			goto get_io_buf_failed;
 		}
 
+		if (icp_hw_mgr.a5_debug_q)
+			hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
+
 		rc = cam_icp_send_ubwc_cfg(hw_mgr);
 		if (rc) {
 			mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -3471,8 +3753,6 @@
 		}
 	}
 
-	if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
-		cam_icp_timer_start(hw_mgr);
 
 	rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
 	if (rc) {
@@ -3524,6 +3804,11 @@
 			(unsigned int)icp_dev_acquire_info->scratch_mem_size,
 			(unsigned int)ctx_data->fw_handle);
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	/* Start device timer*/
+	if (((hw_mgr->bps_ctxt_cnt == 1) || (hw_mgr->ipe_ctxt_cnt == 1)))
+		cam_icp_device_timer_start(hw_mgr);
+	/* Start context timer*/
+	cam_icp_ctx_timer_start(ctx_data);
 	hw_mgr->ctxt_cnt++;
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	CAM_DBG(CAM_ICP, "Acquire Done");
@@ -3730,17 +4015,24 @@
 	rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
 		&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
 	if (rc) {
-		CAM_ERR(CAM_ICP, "unable to create a worker");
+		CAM_ERR(CAM_ICP, "unable to create a command worker");
 		goto cmd_work_failed;
 	}
 
 	rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
 		&icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ);
 	if (rc) {
-		CAM_ERR(CAM_ICP, "unable to create a worker");
+		CAM_ERR(CAM_ICP, "unable to create a message worker");
 		goto msg_work_failed;
 	}
 
+	rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK,
+		&icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "unable to create a timer worker");
+		goto timer_work_failed;
+	}
+
 	icp_hw_mgr.cmd_work_data = (struct hfi_cmd_work_data *)
 		kzalloc(sizeof(struct hfi_cmd_work_data) * ICP_WORKQ_NUM_TASK,
 		GFP_KERNEL);
@@ -3753,9 +4045,15 @@
 	if (!icp_hw_mgr.msg_work_data)
 		goto msg_work_data_failed;
 
+	icp_hw_mgr.timer_work_data = (struct hfi_msg_work_data *)
+		kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK,
+		GFP_KERNEL);
+	if (!icp_hw_mgr.timer_work_data)
+		goto timer_work_data_failed;
+
 	rc = cam_icp_hw_mgr_create_debugfs_entry();
 	if (rc)
-		goto msg_work_data_failed;
+		goto debugfs_create_failed;
 
 	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
 		icp_hw_mgr.msg_work->task.pool[i].payload =
@@ -3765,10 +4063,20 @@
 		icp_hw_mgr.cmd_work->task.pool[i].payload =
 				&icp_hw_mgr.cmd_work_data[i];
 
+	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+		icp_hw_mgr.timer_work->task.pool[i].payload =
+				&icp_hw_mgr.timer_work_data[i];
 	return 0;
+
+debugfs_create_failed:
+	kfree(icp_hw_mgr.timer_work_data);
+timer_work_data_failed:
+	kfree(icp_hw_mgr.msg_work_data);
 msg_work_data_failed:
 	kfree(icp_hw_mgr.cmd_work_data);
 cmd_work_data_failed:
+	cam_req_mgr_workq_destroy(&icp_hw_mgr.timer_work);
+timer_work_failed:
 	cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work);
 msg_work_failed:
 	cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
@@ -3843,7 +4151,6 @@
 		goto icp_wq_create_failed;
 
 	init_completion(&icp_hw_mgr.a5_complete);
-
 	return rc;
 
 icp_wq_create_failed:
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 85f5b550..cffec2e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -68,6 +68,8 @@
 #define CAM_ICP_CTX_STATE_ACQUIRED  0x2
 #define CAM_ICP_CTX_STATE_RELEASE   0x3
 
+#define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
@@ -183,6 +185,8 @@
  * @temp_payload: Payload for destroy handle data
  * @ctx_id: Context Id
  * @clk_info: Current clock info of a context
+ * @watch_dog: watchdog timer handle
+ * @watch_dog_reset_counter: Counter for watch dog reset
  */
 struct cam_icp_hw_ctx_data {
 	void *context_priv;
@@ -200,6 +204,8 @@
 	struct ipe_bps_destroy temp_payload;
 	uint32_t ctx_id;
 	struct cam_ctx_clk_info clk_info;
+	struct cam_req_mgr_timer *watch_dog;
+	uint32_t watch_dog_reset_counter;
 };
 
 /**
@@ -222,6 +228,7 @@
  * @compressed_bw: Current compressed bandwidth voting
  * @hw_type: IPE/BPS device type
  * @watch_dog: watchdog timer handle
+ * @watch_dog_reset_counter: Counter for watch dog reset
  */
 struct cam_icp_clk_info {
 	uint32_t base_clk;
@@ -232,6 +239,7 @@
 	uint64_t compressed_bw;
 	uint32_t hw_type;
 	struct cam_req_mgr_timer *watch_dog;
+	uint32_t watch_dog_reset_counter;
 };
 
 /**
@@ -247,11 +255,13 @@
  * @hfi_mem: Memory for hfi
  * @cmd_work: Work queue for hfi commands
  * @msg_work: Work queue for hfi messages
+ * @timer_work: Work queue for timer watchdog
  * @msg_buf: Buffer for message data from firmware
  * @dbg_buf: Buffer for debug data from firmware
  * @a5_complete: Completion info
  * @cmd_work_data: Pointer to command work queue task
  * @msg_work_data: Pointer to message work queue task
+ * @timer_work_data: Pointer to timer work queue task
  * @ctxt_cnt: Active context count
  * @ipe_ctxt_cnt: IPE Active context count
  * @bps_ctxt_cnt: BPS Active context count
@@ -271,6 +281,12 @@
  * @ipe1_enable: Flag for IPE1
  * @bps_enable: Flag for BPS
  * @core_info: 32 bit value , tells IPE0/1 and BPS
+ * @a5_dev_intf : Device interface for A5
+ * @ipe0_dev_intf: Device interface for IPE0
+ * @ipe1_dev_intf: Device interface for IPE1
+ * @bps_dev_intf: Device interface for BPS
+ * @ipe_clk_state: IPE clock state flag
+ * @bps_clk_state: BPS clock state flag
  */
 struct cam_icp_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -286,11 +302,13 @@
 	struct icp_hfi_mem_info hfi_mem;
 	struct cam_req_mgr_core_workq *cmd_work;
 	struct cam_req_mgr_core_workq *msg_work;
+	struct cam_req_mgr_core_workq *timer_work;
 	uint32_t msg_buf[ICP_MSG_BUF_SIZE];
 	uint32_t dbg_buf[ICP_DBG_BUF_SIZE];
 	struct completion a5_complete;
 	struct hfi_cmd_work_data *cmd_work_data;
 	struct hfi_msg_work_data *msg_work_data;
+	struct hfi_msg_work_data *timer_work_data;
 	uint32_t ctxt_cnt;
 	uint32_t ipe_ctxt_cnt;
 	uint32_t bps_ctxt_cnt;
@@ -313,6 +331,8 @@
 	struct cam_hw_intf *ipe0_dev_intf;
 	struct cam_hw_intf *ipe1_dev_intf;
 	struct cam_hw_intf *bps_dev_intf;
+	bool ipe_clk_state;
+	bool bps_clk_state;
 };
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
index d2e04ef..771c4ed 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
 #define ICP_CLK_TURBO_HZ         600000000
 #define ICP_CLK_SVS_HZ           400000000
 
-#define CAM_ICP_A5_BW_BYTES_VOTE 100000000
+#define CAM_ICP_A5_BW_BYTES_VOTE 40000000
 
 #define CAM_ICP_CTX_MAX          36
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
index 289d7d4..d24305a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -141,9 +141,22 @@
 int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info,
 	uint32_t clk_rate)
 {
+	int32_t src_clk_idx;
+
 	if (!soc_info)
 		return -EINVAL;
 
+	src_clk_idx = soc_info->src_clk_idx;
+
+	if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) &&
+		(soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) &&
+		(clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) {
+		CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d",
+			clk_rate,
+			soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]);
+		clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx];
+	}
+
 	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
 		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
 }
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index d1153ba..fe42f70 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -86,7 +86,8 @@
 		struct cam_ctx_request, list);
 	req_isp_old = (struct cam_isp_ctx_req *) req_old->req_priv;
 	req_isp_new = (struct cam_isp_ctx_req *) req->req_priv;
-	if (req_isp_old->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV) {
+	if (req_isp_old->hw_update_data.packet_opcode_type ==
+		CAM_ISP_PACKET_INIT_DEV) {
 		if ((req_isp_old->num_cfg + req_isp_new->num_cfg) >=
 			CAM_ISP_CTX_CFG_MAX) {
 			CAM_WARN(CAM_ISP, "Can not merge INIT pkt");
@@ -896,6 +897,29 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_sof_in_flush(
+	struct cam_isp_context *ctx_isp, void *evt_data)
+{
+	int rc = 0;
+	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
+
+	if (!evt_data) {
+		CAM_ERR(CAM_ISP, "in valid sof event data");
+		return -EINVAL;
+	}
+	ctx_isp->frame_id++;
+	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
+	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
+		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+
+	if (--ctx_isp->frame_skip_count == 0)
+		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
+	else
+		CAM_ERR(CAM_ISP, "Skip currect SOF");
+
+	return rc;
+}
+
 static struct cam_isp_ctx_irq_ops
 	cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = {
 	/* SOF */
@@ -967,6 +991,17 @@
 	/* HALT */
 	{
 	},
+	/* FLUSH */
+	{
+		.irq_ops = {
+			NULL,
+			__cam_isp_ctx_sof_in_flush,
+			NULL,
+			NULL,
+			NULL,
+			__cam_isp_ctx_buf_done_in_applied,
+		},
+	},
 };
 
 static int __cam_isp_ctx_apply_req_in_activated_state(
@@ -1037,6 +1072,7 @@
 	cfg.ctxt_to_hw_map = ctx_isp->hw_ctx;
 	cfg.hw_update_entries = req_isp->cfg;
 	cfg.num_hw_update_entries = req_isp->num_cfg;
+	cfg.priv  = &req_isp->hw_update_data;
 
 	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
 	if (rc) {
@@ -1109,7 +1145,9 @@
 	struct cam_ctx_request           *req;
 	struct cam_ctx_request           *req_temp;
 	struct cam_isp_ctx_req           *req_isp;
+	struct list_head                  flush_list;
 
+	INIT_LIST_HEAD(&flush_list);
 	spin_lock_bh(&ctx->lock);
 	if (list_empty(req_list)) {
 		spin_unlock_bh(&ctx->lock);
@@ -1118,11 +1156,22 @@
 	}
 
 	list_for_each_entry_safe(req, req_temp, req_list, list) {
-		if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ)
-				&& (req->request_id != flush_req->req_id))
-			continue;
-
+		if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) {
+			if (req->request_id != flush_req->req_id) {
+				continue;
+			} else {
+				list_del_init(&req->list);
+				list_add_tail(&req->list, &flush_list);
+				cancel_req_id_found = 1;
+				break;
+			}
+		}
 		list_del_init(&req->list);
+		list_add_tail(&req->list, &flush_list);
+	}
+	spin_unlock_bh(&ctx->lock);
+
+	list_for_each_entry_safe(req, req_temp, &flush_list, list) {
 		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
 		for (i = 0; i < req_isp->num_fence_map_out; i++) {
 			if (req_isp->fence_map_out[i].sync_id != -1) {
@@ -1138,15 +1187,10 @@
 				req_isp->fence_map_out[i].sync_id = -1;
 			}
 		}
+		spin_lock_bh(&ctx->lock);
 		list_add_tail(&req->list, &ctx->free_req_list);
-
-		/* If flush request id found, exit the loop */
-		if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) {
-			cancel_req_id_found = 1;
-			break;
-		}
+		spin_unlock_bh(&ctx->lock);
 	}
-	spin_unlock_bh(&ctx->lock);
 
 	if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ &&
 		!cancel_req_id_found)
@@ -1170,6 +1214,24 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_flush_req_in_activated(
+	struct cam_context *ctx,
+	struct cam_req_mgr_flush_request *flush_req)
+{
+	int rc = 0;
+	struct cam_isp_context *ctx_isp;
+
+	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+	spin_lock_bh(&ctx->lock);
+	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH;
+	ctx_isp->frame_skip_count = 2;
+	spin_unlock_bh(&ctx->lock);
+
+	CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state);
+	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
+	return rc;
+}
+
 static int __cam_isp_ctx_flush_req_in_ready(
 	struct cam_context *ctx,
 	struct cam_req_mgr_flush_request *flush_req)
@@ -1230,12 +1292,24 @@
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* HW ERROR */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 	/* HALT */
 	{
 		.ioctl_ops = {},
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* FLUSH */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 };
 
 static int __cam_isp_ctx_rdi_only_sof_in_top_state(
@@ -1601,10 +1675,23 @@
 			__cam_isp_ctx_buf_done_in_bubble_applied,
 		},
 	},
-
+	/* HW ERROR */
+	{
+	},
 	/* HALT */
 	{
 	},
+	/* FLUSH */
+	{
+		.irq_ops = {
+			NULL,
+			__cam_isp_ctx_sof_in_flush,
+			NULL,
+			NULL,
+			NULL,
+			__cam_isp_ctx_buf_done_in_applied,
+		},
+	},
 };
 
 static int __cam_isp_ctx_rdi_only_apply_req_top_state(
@@ -1660,15 +1747,26 @@
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* HW ERROR */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 	/* HALT */
 	{
 		.ioctl_ops = {},
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* FLUSHED */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 };
 
-
 /* top level state machine */
 static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	struct cam_release_dev_cmd *cmd)
@@ -1729,7 +1827,6 @@
 	struct cam_req_mgr_add_request    add_req;
 	struct cam_isp_context           *ctx_isp =
 		(struct cam_isp_context *) ctx->ctx_priv;
-	struct cam_isp_prepare_hw_update_data    hw_update_data;
 
 	CAM_DBG(CAM_ISP, "get free request object......");
 
@@ -1780,7 +1877,7 @@
 	cfg.max_in_map_entries = CAM_ISP_CTX_RES_MAX;
 	cfg.out_map_entries = req_isp->fence_map_out;
 	cfg.in_map_entries = req_isp->fence_map_in;
-	cfg.priv  = &hw_update_data;
+	cfg.priv  = &req_isp->hw_update_data;
 
 	CAM_DBG(CAM_ISP, "try to prepare config packet......");
 
@@ -1795,7 +1892,6 @@
 	req_isp->num_fence_map_out = cfg.num_out_map_entries;
 	req_isp->num_fence_map_in = cfg.num_in_map_entries;
 	req_isp->num_acked = 0;
-	req_isp->packet_opcode_type = hw_update_data.packet_opcode_type;
 
 	CAM_DBG(CAM_ISP, "num_entry: %d, num fence out: %d, num fence in: %d",
 		req_isp->num_cfg, req_isp->num_fence_map_out,
@@ -1805,9 +1901,11 @@
 	req->status = 1;
 
 	CAM_DBG(CAM_ISP, "Packet request id 0x%llx packet opcode:%d",
-		packet->header.request_id, req_isp->packet_opcode_type);
+		packet->header.request_id,
+		req_isp->hw_update_data.packet_opcode_type);
 
-	if (req_isp->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV) {
+	if (req_isp->hw_update_data.packet_opcode_type ==
+		CAM_ISP_PACKET_INIT_DEV) {
 		if (ctx->state < CAM_CTX_ACTIVATED) {
 			rc = __cam_isp_ctx_enqueue_init_request(ctx, req);
 			if (rc)
@@ -2052,7 +2150,7 @@
 	struct cam_start_stop_dev_cmd *cmd)
 {
 	int rc = 0;
-	struct cam_hw_start_args         arg;
+	struct cam_hw_config_args        arg;
 	struct cam_ctx_request          *req;
 	struct cam_isp_ctx_req          *req_isp;
 	struct cam_isp_context          *ctx_isp =
@@ -2080,9 +2178,11 @@
 		rc = -EFAULT;
 		goto end;
 	}
+
 	arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
 	arg.hw_update_entries = req_isp->cfg;
 	arg.num_hw_update_entries = req_isp->num_cfg;
+	arg.priv  = &req_isp->hw_update_data;
 
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
@@ -2123,7 +2223,7 @@
 }
 
 static int __cam_isp_ctx_stop_dev_in_activated_unlock(
-	struct cam_context *ctx)
+	struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd)
 {
 	int rc = 0;
 	uint32_t i;
@@ -2142,6 +2242,7 @@
 	/* stop hw first */
 	if (ctx_isp->hw_ctx) {
 		stop.ctxt_to_hw_map = ctx_isp->hw_ctx;
+		stop.args = stop_cmd;
 		ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
 			&stop);
 	}
@@ -2190,7 +2291,7 @@
 {
 	int rc = 0;
 
-	__cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+	__cam_isp_ctx_stop_dev_in_activated_unlock(ctx, cmd);
 	ctx->state = CAM_CTX_ACQUIRED;
 	trace_cam_context_state("ISP", ctx);
 	return rc;
@@ -2201,7 +2302,7 @@
 {
 	int rc = 0;
 
-	rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+	rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL);
 	if (rc)
 		CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc);
 
@@ -2212,6 +2313,58 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_link_pause(struct cam_context *ctx)
+{
+	int rc = 0;
+	struct cam_isp_hw_cmd_args   hw_cmd_args;
+	struct cam_isp_context      *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+	hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_PAUSE_HW;
+	rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+		&hw_cmd_args);
+
+	return rc;
+}
+
+static int __cam_isp_ctx_link_resume(struct cam_context *ctx)
+{
+	int rc = 0;
+	struct cam_isp_hw_cmd_args   hw_cmd_args;
+	struct cam_isp_context      *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+	hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW;
+	rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+		&hw_cmd_args);
+
+	return rc;
+}
+
+static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *link_evt_data)
+{
+	int rc = 0;
+
+	switch (link_evt_data->evt_type) {
+	case CAM_REQ_MGR_LINK_EVT_ERR:
+		/* No need to handle this message now */
+		break;
+	case CAM_REQ_MGR_LINK_EVT_PAUSE:
+		__cam_isp_ctx_link_pause(ctx);
+		break;
+	case CAM_REQ_MGR_LINK_EVT_RESUME:
+		__cam_isp_ctx_link_resume(ctx);
+		break;
+	default:
+		CAM_WARN(CAM_ISP, "Unknown event from CRM");
+		break;
+	}
+	return rc;
+}
+
 static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx,
 	struct cam_req_mgr_core_dev_link_setup *unlink)
 {
@@ -2219,7 +2372,8 @@
 
 	CAM_WARN(CAM_ISP,
 		"Received unlink in activated state. It's unexpected");
-	rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx);
+
+	rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL);
 	if (rc)
 		CAM_WARN(CAM_ISP, "Stop device failed rc=%d", rc);
 
@@ -2343,7 +2497,8 @@
 		.crm_ops = {
 			.unlink = __cam_isp_ctx_unlink_in_activated,
 			.apply_req = __cam_isp_ctx_apply_req,
-			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
+			.flush_req = __cam_isp_ctx_flush_req_in_activated,
+			.process_evt = __cam_isp_ctx_process_evt,
 		},
 		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
 	},
@@ -2353,7 +2508,8 @@
 int cam_isp_context_init(struct cam_isp_context *ctx,
 	struct cam_context *ctx_base,
 	struct cam_req_mgr_kmd_ops *crm_node_intf,
-	struct cam_hw_mgr_intf *hw_intf)
+	struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id)
 
 {
 	int rc = -1;
@@ -2382,8 +2538,8 @@
 	}
 
 	/* camera context setup */
-	rc = cam_context_init(ctx_base, isp_dev_name, crm_node_intf, hw_intf,
-		ctx->req_base, CAM_CTX_REQ_MAX);
+	rc = cam_context_init(ctx_base, isp_dev_name, CAM_ISP, ctx_id,
+		crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "Camera Context Base init failed");
 		goto err;
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
index 88ebc03..38ea58d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -52,6 +52,7 @@
 	CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED,
 	CAM_ISP_CTX_ACTIVATED_HW_ERROR,
 	CAM_ISP_CTX_ACTIVATED_HALT,
+	CAM_ISP_CTX_ACTIVATED_FLUSH,
 	CAM_ISP_CTX_ACTIVATED_MAX,
 };
 
@@ -81,22 +82,22 @@
  *                         the request has been completed.
  * @bubble_report:         Flag to track if bubble report is active on
  *                         current request
- * @packet_opcode_type:    Request packet opcode type,
- *                         ie INIT packet or update packet
+ * @hw_update_data:        HW update data for this request
  *
  */
 struct cam_isp_ctx_req {
-	struct cam_ctx_request          *base;
+	struct cam_ctx_request               *base;
 
-	struct cam_hw_update_entry       cfg[CAM_ISP_CTX_CFG_MAX];
-	uint32_t                         num_cfg;
-	struct cam_hw_fence_map_entry    fence_map_out[CAM_ISP_CTX_RES_MAX];
-	uint32_t                         num_fence_map_out;
-	struct cam_hw_fence_map_entry    fence_map_in[CAM_ISP_CTX_RES_MAX];
-	uint32_t                         num_fence_map_in;
-	uint32_t                         num_acked;
-	int32_t                          bubble_report;
-	uint32_t                         packet_opcode_type;
+	struct cam_hw_update_entry            cfg[CAM_ISP_CTX_CFG_MAX];
+	uint32_t                              num_cfg;
+	struct cam_hw_fence_map_entry         fence_map_out
+						[CAM_ISP_CTX_RES_MAX];
+	uint32_t                              num_fence_map_out;
+	struct cam_hw_fence_map_entry         fence_map_in[CAM_ISP_CTX_RES_MAX];
+	uint32_t                              num_fence_map_in;
+	uint32_t                              num_acked;
+	int32_t                               bubble_report;
+	struct cam_isp_prepare_hw_update_data hw_update_data;
 };
 
 /**
@@ -116,6 +117,7 @@
  * @subscribe_event:       The irq event mask that CRM subscribes to, IFE will
  *                         invoke CRM cb at those event.
  * @last_applied_req_id:   Last applied request id
+ * @frame_skip_count:      Number of frame to skip before change state
  *
  */
 struct cam_isp_context {
@@ -135,6 +137,7 @@
 	int64_t                          reported_req_id;
 	uint32_t                         subscribe_event;
 	int64_t                          last_applied_req_id;
+	uint32_t                         frame_skip_count;
 };
 
 /**
@@ -145,12 +148,14 @@
  * @ctx:                ISP context obj to be initialized
  * @bridge_ops:         Bridge call back funciton
  * @hw_intf:            ISP hw manager interface
+ * @ctx_id:             ID for this context
  *
  */
 int cam_isp_context_init(struct cam_isp_context *ctx,
 	struct cam_context *ctx_base,
 	struct cam_req_mgr_kmd_ops *bridge_ops,
-	struct cam_hw_mgr_intf *hw_intf);
+	struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id);
 
 /**
  * cam_isp_context_deinit()
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
index bcdba05..e775daa 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -104,7 +104,8 @@
 		rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i],
 			&g_isp_dev.ctx[i],
 			&node->crm_node_intf,
-			&node->hw_mgr_intf);
+			&node->hw_mgr_intf,
+			i);
 		if (rc) {
 			CAM_ERR(CAM_ISP, "ISP context init failed!");
 			goto unregister;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 8d41ae7..33dd8eb 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -860,10 +860,95 @@
 	return rc;
 }
 
-static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp(
+static int cam_ife_mgr_acquire_cid_res(
 	struct cam_ife_hw_mgr_ctx          *ife_ctx,
 	struct cam_isp_in_port_info        *in_port,
-	uint32_t                            cid_res_id)
+	uint32_t                           *cid_res_id,
+	enum cam_ife_pix_path_res_id        csid_path)
+{
+	int rc = -1;
+	int i, j;
+	struct cam_ife_hw_mgr               *ife_hw_mgr;
+	struct cam_ife_hw_mgr_res           *cid_res;
+	struct cam_hw_intf                  *hw_intf;
+	struct cam_csid_hw_reserve_resource_args  csid_acquire;
+
+	ife_hw_mgr = ife_ctx->hw_mgr;
+
+	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
+		goto err;
+	}
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
+
+	csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
+	csid_acquire.in_port = in_port;
+	csid_acquire.res_id =  csid_path;
+
+	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
+		if (!ife_hw_mgr->csid_devices[i])
+			continue;
+
+		hw_intf = ife_hw_mgr->csid_devices[i];
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire,
+			sizeof(csid_acquire));
+		if (rc)
+			continue;
+		else
+			break;
+	}
+
+	if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
+		CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
+		goto err;
+	}
+
+	cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
+	cid_res->res_id = csid_acquire.node_res->res_id;
+	cid_res->is_dual_vfe = in_port->usage_type;
+	cid_res->hw_res[0] = csid_acquire.node_res;
+	cid_res->hw_res[1] = NULL;
+	/* CID(DT_ID) value of acquire device, require for path */
+	*cid_res_id = csid_acquire.node_res->res_id;
+
+	if (cid_res->is_dual_vfe) {
+		csid_acquire.node_res = NULL;
+		csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
+		csid_acquire.in_port = in_port;
+		for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
+			if (!ife_hw_mgr->csid_devices[j])
+				continue;
+
+			hw_intf = ife_hw_mgr->csid_devices[j];
+			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+				&csid_acquire, sizeof(csid_acquire));
+			if (rc)
+				continue;
+			else
+				break;
+		}
+
+		if (j == CAM_IFE_CSID_HW_NUM_MAX) {
+			CAM_ERR(CAM_ISP,
+				"Can not acquire ife csid rdi resource");
+			goto err;
+		}
+		cid_res->hw_res[1] = csid_acquire.node_res;
+	}
+	cid_res->parent = &ife_ctx->res_list_ife_in;
+	ife_ctx->res_list_ife_in.child[
+		ife_ctx->res_list_ife_in.num_children++] = cid_res;
+
+	return 0;
+err:
+	return rc;
+
+}
+
+static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp(
+	struct cam_ife_hw_mgr_ctx          *ife_ctx,
+	struct cam_isp_in_port_info        *in_port)
 {
 	int rc = -1;
 	int i;
@@ -872,8 +957,17 @@
 	struct cam_ife_hw_mgr_res           *csid_res;
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
+	uint32_t                             cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
+	/* get cid resource */
+	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+		CAM_IFE_PIX_PATH_RES_IPP);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+		goto err;
+	}
+
 	ife_hw_mgr = ife_ctx->hw_mgr;
 
 	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
@@ -985,8 +1079,7 @@
 
 static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 	struct cam_ife_hw_mgr_ctx     *ife_ctx,
-	struct cam_isp_in_port_info   *in_port,
-	uint32_t                       cid_res_id)
+	struct cam_isp_in_port_info   *in_port)
 {
 	int rc = -1;
 	int i, j;
@@ -996,6 +1089,7 @@
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
 	struct cam_isp_out_port_info        *out_port;
+	uint32_t                            cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
@@ -1005,6 +1099,15 @@
 		if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
 			continue;
 
+		/* get cid resource */
+		rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+			cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+			out_port->res_type));
+		if (rc) {
+			CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+			goto err;
+		}
+
 		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
 			&csid_res);
 		if (rc) {
@@ -1135,91 +1238,6 @@
 	return 0;
 }
 
-static int cam_ife_mgr_acquire_cid_res(
-	struct cam_ife_hw_mgr_ctx          *ife_ctx,
-	struct cam_isp_in_port_info        *in_port,
-	uint32_t                           *cid_res_id,
-	int                                 pixel_count)
-{
-	int rc = -1;
-	int i, j;
-	struct cam_ife_hw_mgr               *ife_hw_mgr;
-	struct cam_ife_hw_mgr_res           *cid_res;
-	struct cam_hw_intf                  *hw_intf;
-	struct cam_csid_hw_reserve_resource_args  csid_acquire;
-
-	ife_hw_mgr = ife_ctx->hw_mgr;
-
-	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-		goto err;
-	}
-	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
-
-	csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
-	csid_acquire.in_port = in_port;
-	csid_acquire.pixel_count = pixel_count;
-
-	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
-		if (!ife_hw_mgr->csid_devices[i])
-			continue;
-
-		hw_intf = ife_hw_mgr->csid_devices[i];
-		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire,
-			sizeof(csid_acquire));
-		if (rc)
-			continue;
-		else
-			break;
-	}
-
-	if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
-		CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
-		goto err;
-	}
-
-	cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
-	cid_res->res_id = csid_acquire.node_res->res_id;
-	cid_res->is_dual_vfe = in_port->usage_type;
-	cid_res->hw_res[0] = csid_acquire.node_res;
-	cid_res->hw_res[1] = NULL;
-	/* CID(DT_ID) value of acquire device, require for path */
-	*cid_res_id = csid_acquire.node_res->res_id;
-
-	if (cid_res->is_dual_vfe) {
-		csid_acquire.node_res = NULL;
-		csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
-		csid_acquire.in_port = in_port;
-		for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
-			if (!ife_hw_mgr->csid_devices[j])
-				continue;
-
-			hw_intf = ife_hw_mgr->csid_devices[j];
-			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-				&csid_acquire, sizeof(csid_acquire));
-			if (rc)
-				continue;
-			else
-				break;
-		}
-
-		if (j == CAM_IFE_CSID_HW_NUM_MAX) {
-			CAM_ERR(CAM_ISP,
-				"Can not acquire ife csid rdi resource");
-			goto err;
-		}
-		cid_res->hw_res[1] = csid_acquire.node_res;
-	}
-	cid_res->parent = &ife_ctx->res_list_ife_in;
-	ife_ctx->res_list_ife_in.child[
-		ife_ctx->res_list_ife_in.num_children++] = cid_res;
-
-	return 0;
-err:
-	return rc;
-
-}
 static int cam_ife_mgr_acquire_hw_for_ctx(
 	struct cam_ife_hw_mgr_ctx          *ife_ctx,
 	struct cam_isp_in_port_info        *in_port,
@@ -1229,7 +1247,6 @@
 	int is_dual_vfe                           = 0;
 	int pixel_count                           = 0;
 	int rdi_count                             = 0;
-	uint32_t                                cid_res_id = 0;
 
 	is_dual_vfe = in_port->usage_type;
 
@@ -1248,18 +1265,9 @@
 		return -EINVAL;
 	}
 
-	/* get cid resource */
-	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
-		pixel_count);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
-		goto err;
-	}
-
 	if (pixel_count) {
 		/* get ife csid IPP resrouce */
-		rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port,
-				cid_res_id);
+		rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Acquire IFE CSID IPP resource Failed");
@@ -1269,8 +1277,7 @@
 
 	if (rdi_count) {
 		/* get ife csid rdi resource */
-		rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port,
-			cid_res_id);
+		rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Acquire IFE CSID RDI resource Failed");
@@ -1437,15 +1444,97 @@
 	return rc;
 }
 
+static int cam_isp_blob_bw_update(
+	struct cam_isp_bw_config              *bw_config,
+	struct cam_ife_hw_mgr_ctx             *ctx)
+{
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_bw_update_args          bw_upd_args;
+	uint64_t                               cam_bw_bps = 0;
+	uint64_t                               ext_bw_bps = 0;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	CAM_DBG(CAM_ISP,
+		"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
+		"right cam_bw_bps=%llu ext_bw_bps=%llu",
+		bw_config->usage_type,
+		bw_config->left_pix_vote.cam_bw_bps,
+		bw_config->left_pix_vote.ext_bw_bps,
+		bw_config->right_pix_vote.cam_bw_bps,
+		bw_config->right_pix_vote.ext_bw_bps);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+				if (i == CAM_ISP_HW_SPLIT_LEFT) {
+					cam_bw_bps =
+					bw_config->left_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->left_pix_vote.ext_bw_bps;
+				} else {
+					cam_bw_bps =
+					bw_config->right_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->right_pix_vote.ext_bw_bps;
+				}
+			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+						&& (hw_mgr_res->res_id <=
+						CAM_ISP_HW_VFE_IN_RDI3)) {
+				uint32_t idx = hw_mgr_res->res_id -
+						CAM_ISP_HW_VFE_IN_RDI0;
+				if (idx >= bw_config->num_rdi)
+					continue;
+
+				cam_bw_bps =
+					bw_config->rdi_vote[idx].cam_bw_bps;
+				ext_bw_bps =
+					bw_config->rdi_vote[idx].ext_bw_bps;
+			} else
+				if (hw_mgr_res->hw_res[i]) {
+					CAM_ERR(CAM_ISP, "Invalid res_id %u",
+						hw_mgr_res->res_id);
+					rc = -EINVAL;
+					return rc;
+				}
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_upd_args.node_res =
+					hw_mgr_res->hw_res[i];
+
+				bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
+				bw_upd_args.external_bw_bytes = ext_bw_bps;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_UPDATE,
+					&bw_upd_args,
+					sizeof(struct cam_vfe_bw_update_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
 /* entry function: config_hw */
 static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
 					void *config_hw_args)
 {
 	int rc = -1, i;
-	struct cam_hw_start_args *cfg;
+	struct cam_hw_config_args *cfg;
 	struct cam_hw_update_entry *cmd;
 	struct cam_cdm_bl_request *cdm_cmd;
 	struct cam_ife_hw_mgr_ctx *ctx;
+	struct cam_isp_prepare_hw_update_data *hw_update_data;
 
 	CAM_DBG(CAM_ISP, "Enter");
 	if (!hw_mgr_priv || !config_hw_args) {
@@ -1467,6 +1556,18 @@
 	if (atomic_read(&ctx->overflow_pending))
 		return -EINVAL;
 
+	hw_update_data = (struct cam_isp_prepare_hw_update_data  *) cfg->priv;
+
+	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
+		if (hw_update_data->bw_config_valid[i] == true) {
+			rc = cam_isp_blob_bw_update(
+				(struct cam_isp_bw_config *)
+				&hw_update_data->bw_config[i], ctx);
+			if (rc)
+				CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+			}
+	}
+
 	CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d",
 		ctx->ctx_index, cfg->num_hw_update_entries);
 
@@ -1585,6 +1686,7 @@
 	struct cam_hw_stop_args          *stop_args = stop_hw_args;
 	struct cam_ife_hw_mgr_res        *hw_mgr_res;
 	struct cam_ife_hw_mgr_ctx        *ctx;
+	enum cam_ife_csid_halt_cmd        csid_halt_type;
 	uint32_t                          i, master_base_idx = 0;
 
 	if (!hw_mgr_priv || !stop_hw_args) {
@@ -1600,6 +1702,12 @@
 	CAM_DBG(CAM_ISP, " Enter...ctx id:%d",
 		ctx->ctx_index);
 
+	/* Set the csid halt command */
+	if (!stop_args->args)
+		csid_halt_type = CAM_CSID_HALT_IMMEDIATELY;
+	else
+		csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY;
+
 	/* Note:stop resource will remove the irq mask from the hardware */
 
 	if (!ctx->num_base) {
@@ -1624,7 +1732,7 @@
 
 	/* Stop the master CSID path first */
 	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-			master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+			master_base_idx, csid_halt_type);
 
 	/* stop rest of the CSID paths  */
 	for (i = 0; i < ctx->num_base; i++) {
@@ -1632,19 +1740,19 @@
 			continue;
 
 		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
-			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+			ctx->base[i].idx, csid_halt_type);
 	}
 
 	/* Stop the master CIDs first */
 	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
-			master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+			master_base_idx, csid_halt_type);
 
 	/* stop rest of the CIDs  */
 	for (i = 0; i < ctx->num_base; i++) {
 		if (i == master_base_idx)
 			continue;
 		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
-			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+			ctx->base[i].idx, csid_halt_type);
 	}
 
 	if (cam_cdm_stream_off(ctx->cdm_handle))
@@ -1798,7 +1906,7 @@
 static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
 {
 	int                               rc = -1;
-	struct cam_hw_start_args         *start_args = start_hw_args;
+	struct cam_hw_config_args        *start_args = start_hw_args;
 	struct cam_ife_hw_mgr_ctx        *ctx;
 	struct cam_ife_hw_mgr_res        *hw_mgr_res;
 	uint32_t                          i;
@@ -2204,92 +2312,6 @@
 	return rc;
 }
 
-static int cam_isp_blob_bw_update(
-	uint32_t                               blob_type,
-	struct cam_isp_generic_blob_info      *blob_info,
-	struct cam_isp_bw_config              *bw_config,
-	struct cam_hw_prepare_update_args     *prepare)
-{
-	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
-	struct cam_ife_hw_mgr_res             *hw_mgr_res;
-	struct cam_hw_intf                    *hw_intf;
-	struct cam_vfe_bw_update_args          bw_upd_args;
-	uint64_t                               cam_bw_bps = 0;
-	uint64_t                               ext_bw_bps = 0;
-	int                                    rc = -EINVAL;
-	uint32_t                               i;
-
-	ctx = prepare->ctxt_to_hw_map;
-
-	CAM_DBG(CAM_ISP,
-		"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
-		"right cam_bw_bps=%llu ext_bw_bps=%llu",
-		bw_config->usage_type,
-		bw_config->left_pix_vote.cam_bw_bps,
-		bw_config->left_pix_vote.ext_bw_bps,
-		bw_config->right_pix_vote.cam_bw_bps,
-		bw_config->right_pix_vote.ext_bw_bps);
-
-	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
-
-			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
-				if (i == CAM_ISP_HW_SPLIT_LEFT) {
-					cam_bw_bps =
-					bw_config->left_pix_vote.cam_bw_bps;
-					ext_bw_bps =
-					bw_config->left_pix_vote.ext_bw_bps;
-				} else {
-					cam_bw_bps =
-					bw_config->right_pix_vote.cam_bw_bps;
-					ext_bw_bps =
-					bw_config->right_pix_vote.ext_bw_bps;
-				}
-			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
-						&& (hw_mgr_res->res_id <=
-						CAM_ISP_HW_VFE_IN_RDI3)) {
-				uint32_t idx = hw_mgr_res->res_id -
-						CAM_ISP_HW_VFE_IN_RDI0;
-				if (idx >= bw_config->num_rdi)
-					continue;
-
-				cam_bw_bps =
-					bw_config->rdi_vote[idx].cam_bw_bps;
-				ext_bw_bps =
-					bw_config->rdi_vote[idx].ext_bw_bps;
-			} else
-				if (hw_mgr_res->hw_res[i]) {
-					CAM_ERR(CAM_ISP, "Invalid res_id %u",
-						hw_mgr_res->res_id);
-					rc = -EINVAL;
-					return rc;
-				}
-
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			if (hw_intf && hw_intf->hw_ops.process_cmd) {
-				bw_upd_args.node_res =
-					hw_mgr_res->hw_res[i];
-
-				bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
-				bw_upd_args.external_bw_bytes = ext_bw_bps;
-
-				rc = hw_intf->hw_ops.process_cmd(
-					hw_intf->hw_priv,
-					CAM_ISP_HW_CMD_BW_UPDATE,
-					&bw_upd_args,
-					sizeof(struct cam_vfe_bw_update_args));
-				if (rc)
-					CAM_ERR(CAM_ISP, "BW Update failed");
-			} else
-				CAM_WARN(CAM_ISP, "NULL hw_intf!");
-		}
-	}
-
-	return rc;
-}
-
 static int cam_isp_packet_generic_blob_handler(void *user_data,
 	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
 {
@@ -2340,11 +2362,22 @@
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
 		struct cam_isp_bw_config    *bw_config =
 			(struct cam_isp_bw_config *)blob_data;
+		struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
 
-		rc = cam_isp_blob_bw_update(blob_type, blob_info,
-			bw_config, prepare);
-		if (rc)
-			CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+		if (!prepare || !prepare->priv ||
+			(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
+			CAM_ERR(CAM_ISP, "Invalid inputs");
+			rc = -EINVAL;
+			break;
+		}
+
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+			prepare->priv;
+
+		memcpy(&prepare_hw_data->bw_config[bw_config->usage_type],
+			bw_config, sizeof(prepare_hw_data->bw_config[0]));
+		prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
+
 	}
 		break;
 	default:
@@ -2375,6 +2408,9 @@
 
 	CAM_DBG(CAM_ISP, "enter");
 
+	prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+		prepare->priv;
+
 	ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map;
 	hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv;
 
@@ -2399,6 +2435,13 @@
 	prepare->num_in_map_entries = 0;
 	prepare->num_out_map_entries = 0;
 
+	memset(&prepare_hw_data->bw_config[0], 0x0,
+		sizeof(prepare_hw_data->bw_config[0]) *
+		CAM_IFE_HW_NUM_MAX);
+	memset(&prepare_hw_data->bw_config_valid[0], 0x0,
+		sizeof(prepare_hw_data->bw_config_valid[0]) *
+		CAM_IFE_HW_NUM_MAX);
+
 	for (i = 0; i < ctx->num_base; i++) {
 		CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i);
 
@@ -2452,8 +2495,6 @@
 	 * bits to get the type of operation since UMD definition
 	 * of op_code has some difference from KMD.
 	 */
-	prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
-		prepare->priv;
 	if (((prepare->packet->header.op_code + 1) & 0xF) ==
 		CAM_ISP_PACKET_INIT_DEV) {
 		prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV;
@@ -2488,6 +2529,53 @@
 	return rc;
 }
 
+static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
+	enum cam_vfe_bw_control_action action)
+{
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_bw_control_args         bw_ctrl_args;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_ctrl_args.node_res =
+					hw_mgr_res->hw_res[i];
+				bw_ctrl_args.action = action;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_CONTROL,
+					&bw_ctrl_args,
+					sizeof(struct cam_vfe_bw_control_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
+static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
+}
+
+static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
+}
+
 static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 {
 	int rc = 0;
@@ -2513,6 +2601,12 @@
 			hw_cmd_args->u.is_rdi_only_context = 0;
 
 		break;
+	case CAM_ISP_HW_MGR_CMD_PAUSE_HW:
+		cam_ife_mgr_pause_hw(ctx);
+		break;
+	case CAM_ISP_HW_MGR_CMD_RESUME_HW:
+		cam_ife_mgr_resume_hw(ctx);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x",
 			hw_cmd_args->cmd_type);
@@ -3100,7 +3194,7 @@
 		(event_cnt[core_idx1] &&
 		(event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) {
 
-		CAM_WARN(CAM_ISP,
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
 			"One of the VFE cound not generate hw event %d",
 			hw_event_type);
 		rc = -1;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index 4d26138..c418a41 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,9 +18,6 @@
 #include "cam_ife_csid_hw_intf.h"
 #include "cam_tasklet_util.h"
 
-/* MAX IFE instance */
-#define CAM_IFE_HW_NUM_MAX                       4
-
 /* enum cam_ife_hw_mgr_res_type - manager resource node type */
 enum cam_ife_hw_mgr_res_type {
 	CAM_IFE_HW_MGR_RES_UNINIT,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
index cf044eb..78336d2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,10 @@
 #include <uapi/media/cam_isp.h>
 #include "cam_hw_mgr_intf.h"
 
+/* MAX IFE instance */
+#define CAM_IFE_HW_NUM_MAX   4
+#define CAM_IFE_RDI_NUM_MAX  4
+
 /**
  *  enum cam_isp_hw_event_type - Collection of the ISP hardware events
  */
@@ -47,15 +51,38 @@
 };
 
 /**
+ * struct cam_isp_bw_config_internal - Internal Bandwidth configuration
+ *
+ * @usage_type:                 Usage type (Single/Dual)
+ * @num_rdi:                    Number of RDI votes
+ * @left_pix_vote:              Bandwidth vote for left ISP
+ * @right_pix_vote:             Bandwidth vote for right ISP
+ * @rdi_vote:                   RDI bandwidth requirements
+ */
+
+struct cam_isp_bw_config_internal {
+	uint32_t                       usage_type;
+	uint32_t                       num_rdi;
+	struct cam_isp_bw_vote         left_pix_vote;
+	struct cam_isp_bw_vote         right_pix_vote;
+	struct cam_isp_bw_vote         rdi_vote[CAM_IFE_RDI_NUM_MAX];
+};
+
+/**
  * struct cam_isp_prepare_hw_update_data - hw prepare data
  *
  * @packet_opcode_type:     Packet header opcode in the packet header
- *                   this opcode defines, packet is init packet or
- *                   update packet
+ *                          this opcode defines, packet is init packet or
+ *                          update packet
+ * @bw_config:              BW config information
+ * @bw_config_valid:        Flag indicating whether the bw_config at the index
+ *                          is valid or not
  *
  */
 struct cam_isp_prepare_hw_update_data {
-	uint32_t      packet_opcode_type;
+	uint32_t                          packet_opcode_type;
+	struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX];
+	bool                              bw_config_valid[CAM_IFE_HW_NUM_MAX];
 };
 
 
@@ -130,6 +157,8 @@
 /* enum cam_isp_hw_mgr_command - Hardware manager command type */
 enum cam_isp_hw_mgr_command {
 	CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT,
+	CAM_ISP_HW_MGR_CMD_PAUSE_HW,
+	CAM_ISP_HW_MGR_CMD_RESUME_HW,
 	CAM_ISP_HW_MGR_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index bce0374..1359f78 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -287,7 +287,7 @@
 
 static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
 	struct cam_isp_resource_node **res, int32_t vc, uint32_t dt,
-	uint32_t res_type, int pixel_count)
+	uint32_t res_type)
 {
 	int  rc = 0;
 	struct cam_ife_csid_cid_data    *cid_data;
@@ -305,8 +305,7 @@
 					break;
 				}
 			} else {
-				if (cid_data->vc == vc && cid_data->dt == dt &&
-					cid_data->pixel_count == pixel_count) {
+				if (cid_data->vc == vc && cid_data->dt == dt) {
 					cid_data->cnt++;
 					*res = &csid_hw->cid_res[i];
 					break;
@@ -330,7 +329,6 @@
 				cid_data->vc  = vc;
 				cid_data->dt  = dt;
 				cid_data->cnt = 1;
-				cid_data->pixel_count = pixel_count;
 				csid_hw->cid_res[j].res_state =
 					CAM_ISP_RESOURCE_STATE_RESERVED;
 				*res = &csid_hw->cid_res[j];
@@ -570,7 +568,6 @@
 	struct cam_csid_hw_reserve_resource_args  *cid_reserv)
 {
 	int rc = 0;
-	uint32_t i;
 	struct cam_ife_csid_cid_data       *cid_data;
 
 	CAM_DBG(CAM_ISP,
@@ -728,7 +725,6 @@
 		cid_data->vc = cid_reserv->in_port->vc;
 		cid_data->dt = cid_reserv->in_port->dt;
 		cid_data->cnt = 1;
-		cid_data->pixel_count = cid_reserv->pixel_count;
 		cid_reserv->node_res = &csid_hw->cid_res[0];
 		csid_hw->csi2_reserve_cnt++;
 
@@ -737,27 +733,43 @@
 			csid_hw->hw_intf->hw_idx,
 			cid_reserv->node_res->res_id);
 	} else {
-		if (cid_reserv->pixel_count > 0) {
-			for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
-				cid_data = (struct cam_ife_csid_cid_data *)
-					csid_hw->cid_res[i].res_priv;
-				if ((csid_hw->cid_res[i].res_state >=
-					CAM_ISP_RESOURCE_STATE_RESERVED) &&
-					cid_data->pixel_count > 0) {
-					CAM_DBG(CAM_ISP,
-						"CSID:%d IPP resource is full");
-					rc = -EINVAL;
-					goto end;
-				}
+		switch (cid_reserv->res_id) {
+		case CAM_IFE_PIX_PATH_RES_IPP:
+			if (csid_hw->ipp_res.res_state !=
+				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+				CAM_DBG(CAM_ISP,
+					"CSID:%d IPP resource not available",
+					csid_hw->hw_intf->hw_idx);
+				rc = -EINVAL;
+				goto end;
 			}
+			break;
+		case CAM_IFE_PIX_PATH_RES_RDI_0:
+		case CAM_IFE_PIX_PATH_RES_RDI_1:
+		case CAM_IFE_PIX_PATH_RES_RDI_2:
+		case CAM_IFE_PIX_PATH_RES_RDI_3:
+			if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
+				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+				CAM_DBG(CAM_ISP,
+					"CSID:%d RDI:%d resource not available",
+					csid_hw->hw_intf->hw_idx,
+					cid_reserv->res_id);
+				rc = -EINVAL;
+				goto end;
+			}
+			break;
+		default:
+			CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
+				csid_hw->hw_intf->hw_idx);
+			rc = -EINVAL;
+			goto end;
 		}
 
 		rc = cam_ife_csid_cid_get(csid_hw,
 			&cid_reserv->node_res,
 			cid_reserv->in_port->vc,
 			cid_reserv->in_port->dt,
-			cid_reserv->in_port->res_type,
-			cid_reserv->pixel_count);
+			cid_reserv->in_port->res_type);
 		/* if success then increment the reserve count */
 		if (!rc) {
 			if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
@@ -1025,16 +1037,23 @@
 
 static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw)
 {
-	int rc = 0;
+	int rc = -EINVAL;
 	struct cam_hw_soc_info             *soc_info;
 	struct cam_ife_csid_reg_offset     *csid_reg;
 
+	/* Check for refcount */
+	if (!csid_hw->hw_info->open_count) {
+		CAM_WARN(CAM_ISP, "Unbalanced disable_hw");
+		return rc;
+	}
 
 	/*  Decrement ref Count */
-	if (csid_hw->hw_info->open_count)
-		csid_hw->hw_info->open_count--;
-	if (csid_hw->hw_info->open_count)
+	csid_hw->hw_info->open_count--;
+
+	if (csid_hw->hw_info->open_count) {
+		rc = 0;
 		return rc;
+	}
 
 	soc_info = &csid_hw->hw_info->soc_info;
 	csid_reg = csid_hw->csid_info->csid_reg;
@@ -2524,7 +2543,8 @@
 	/*wait for the path to halt */
 	for (i = 0; i < csid_stop->num_res; i++) {
 		res = csid_stop->node_res[i];
-		if (csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
+		if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH &&
+			csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
 			rc = cam_ife_csid_res_wait_for_halt(csid_hw, res);
 		else
 			res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index b400d14..4b546ea 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -368,7 +368,6 @@
 	uint32_t                     dt;
 	uint32_t                     cnt;
 	uint32_t                     tpg_set;
-	int                          pixel_count;
 };
 
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
index df97bd6..ceeacbe 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -75,7 +75,6 @@
  * @cid:          cid (DT_ID) value for path, this is applicable for CSID path
  *                reserve
  * @node_res :    Reserved resource structure pointer
- * @pixel_count:  Number of pixel resources
  *
  */
 struct cam_csid_hw_reserve_resource_args {
@@ -87,7 +86,6 @@
 	uint32_t                                  master_idx;
 	uint32_t                                  cid;
 	struct cam_isp_resource_node             *node_res;
-	int                                       pixel_count;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index 257a5ac..b9f6d77 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -92,6 +92,7 @@
 	CAM_ISP_HW_CMD_STRIPE_UPDATE,
 	CAM_ISP_HW_CMD_CLOCK_UPDATE,
 	CAM_ISP_HW_CMD_BW_UPDATE,
+	CAM_ISP_HW_CMD_BW_CONTROL,
 	CAM_ISP_HW_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index b771ec6..8927d6a 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -185,6 +185,22 @@
 	uint64_t                           external_bw_bytes;
 };
 
+enum cam_vfe_bw_control_action {
+	CAM_VFE_BW_CONTROL_EXCLUDE       = 0,
+	CAM_VFE_BW_CONTROL_INCLUDE       = 1
+};
+
+/*
+ * struct cam_vfe_bw_control_args:
+ *
+ * @node_res:             Resource to get the time stamp
+ * @action:               Bandwidth control action
+ */
+struct cam_vfe_bw_control_args {
+	struct cam_isp_resource_node      *node_res;
+	enum cam_vfe_bw_control_action     action;
+};
+
 /*
  * struct cam_vfe_top_irq_evt_payload:
  *
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 02fec28..2c4fe9d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -697,6 +697,7 @@
 	case CAM_ISP_HW_CMD_GET_REG_UPDATE:
 	case CAM_ISP_HW_CMD_CLOCK_UPDATE:
 	case CAM_ISP_HW_CMD_BW_UPDATE:
+	case CAM_ISP_HW_CMD_BW_CONTROL:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 36ce652..cc897a3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -1000,7 +1000,7 @@
 		rsrc_data->height = 0;
 		rsrc_data->stride = 1;
 		rsrc_data->en_cfg = 0x3;
-	}  else if (rsrc_data->index == 9) {
+	}  else if (rsrc_data->index == 9 || rsrc_data->index == 10) {
 		/* Write master 9 - Raw dump */
 		rsrc_data->width = rsrc_data->width * 2;
 		rsrc_data->stride = rsrc_data->width;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index f427ab9..b748bc8 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -234,13 +234,6 @@
 	CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", camif_res->hw_intf->hw_idx,
 		val);
 
-	cam_io_w_mb(0x00400040, rsrc_data->mem_base +
-		rsrc_data->camif_reg->camif_config);
-	cam_io_w_mb(0x1, rsrc_data->mem_base +
-			rsrc_data->camif_reg->line_skip_pattern);
-	cam_io_w_mb(0x1, rsrc_data->mem_base +
-			rsrc_data->camif_reg->pixel_skip_pattern);
-
 	/* epoch config with 20 line */
 	cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg,
 		rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index f166025..3f843c3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,8 +20,9 @@
 #include "cam_cpas_api.h"
 #include "cam_vfe_soc.h"
 
-#define CAM_VFE_HW_RESET_HW_AND_REG_VAL   0x00003F9F
-#define CAM_VFE_HW_RESET_HW_VAL           0x00003F87
+#define CAM_VFE_HW_RESET_HW_AND_REG_VAL       0x00003F9F
+#define CAM_VFE_HW_RESET_HW_VAL               0x00003F87
+#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3
 
 struct cam_vfe_top_ver2_common_data {
 	struct cam_hw_soc_info                     *soc_info;
@@ -33,7 +34,11 @@
 	struct cam_vfe_top_ver2_common_data common_data;
 	struct cam_isp_resource_node        mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX];
 	unsigned long                       hw_clk_rate;
-	struct cam_axi_vote                 hw_axi_vote;
+	enum cam_vfe_bw_control_action      axi_vote_control[
+						CAM_VFE_TOP_VER2_MUX_MAX];
+	struct cam_axi_vote                 to_be_applied_axi_vote;
+	struct cam_axi_vote                 applied_axi_vote;
+	uint32_t                            counter_to_update_axi_vote;
 	struct cam_axi_vote             req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
 	unsigned long                   req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
 };
@@ -119,7 +124,8 @@
 }
 
 static int cam_vfe_top_set_axi_bw_vote(
-	struct cam_vfe_top_ver2_priv *top_priv)
+	struct cam_vfe_top_ver2_priv *top_priv,
+	bool start_stop)
 {
 	struct cam_axi_vote sum = {0, 0};
 	int i, rc = 0;
@@ -127,6 +133,7 @@
 		top_priv->common_data.soc_info;
 	struct cam_vfe_soc_private *soc_private =
 		soc_info->soc_private;
+	bool apply_bw_update = false;
 
 	if (!soc_private) {
 		CAM_ERR(CAM_ISP, "Error soc_private NULL");
@@ -134,30 +141,98 @@
 	}
 
 	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
-		sum.uncompressed_bw +=
-			top_priv->req_axi_vote[i].uncompressed_bw;
-		sum.compressed_bw +=
-			top_priv->req_axi_vote[i].compressed_bw;
+		if (top_priv->axi_vote_control[i] ==
+			CAM_VFE_BW_CONTROL_INCLUDE) {
+			sum.uncompressed_bw +=
+				top_priv->req_axi_vote[i].uncompressed_bw;
+			sum.compressed_bw +=
+				top_priv->req_axi_vote[i].compressed_bw;
+		}
 	}
 
-	CAM_DBG(CAM_ISP, "BW Vote: u=%lld c=%lld",
+	CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)",
+		top_priv->applied_axi_vote.uncompressed_bw,
+		top_priv->applied_axi_vote.compressed_bw,
 		sum.uncompressed_bw,
 		sum.compressed_bw);
 
-	if ((top_priv->hw_axi_vote.uncompressed_bw ==
+	if ((top_priv->applied_axi_vote.uncompressed_bw ==
 		sum.uncompressed_bw) &&
-		(top_priv->hw_axi_vote.compressed_bw ==
-		sum.compressed_bw))
+		(top_priv->applied_axi_vote.compressed_bw ==
+		sum.compressed_bw)) {
+		CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu",
+			top_priv->applied_axi_vote.uncompressed_bw,
+			top_priv->applied_axi_vote.compressed_bw);
+		top_priv->counter_to_update_axi_vote = 0;
 		return 0;
+	}
 
-	rc = cam_cpas_update_axi_vote(
+	if ((top_priv->to_be_applied_axi_vote.uncompressed_bw !=
+		sum.uncompressed_bw) ||
+		(top_priv->to_be_applied_axi_vote.compressed_bw !=
+		sum.compressed_bw)) {
+		// we got a new bw value to apply
+		top_priv->counter_to_update_axi_vote = 0;
+
+		top_priv->to_be_applied_axi_vote.uncompressed_bw =
+			sum.uncompressed_bw;
+		top_priv->to_be_applied_axi_vote.compressed_bw =
+			sum.compressed_bw;
+	}
+
+	if (start_stop == true) {
+		CAM_DBG(CAM_ISP,
+			"New bw in start/stop, applying bw now, counter=%d",
+			top_priv->counter_to_update_axi_vote);
+		top_priv->counter_to_update_axi_vote = 0;
+		apply_bw_update = true;
+	} else if ((top_priv->to_be_applied_axi_vote.uncompressed_bw <
+		top_priv->applied_axi_vote.uncompressed_bw) ||
+		(top_priv->to_be_applied_axi_vote.compressed_bw <
+		top_priv->applied_axi_vote.compressed_bw)) {
+		if (top_priv->counter_to_update_axi_vote >=
+			(CAM_VFE_TOP_VER2_MUX_MAX *
+			CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)) {
+			CAM_DBG(CAM_ISP,
+				"New bw is less, applying bw now, counter=%d",
+				top_priv->counter_to_update_axi_vote);
+			top_priv->counter_to_update_axi_vote = 0;
+			apply_bw_update = true;
+		} else {
+			CAM_DBG(CAM_ISP,
+				"New bw is less, Defer applying bw, counter=%d",
+				top_priv->counter_to_update_axi_vote);
+
+			top_priv->counter_to_update_axi_vote++;
+			apply_bw_update = false;
+		}
+	} else {
+		CAM_DBG(CAM_ISP,
+			"New bw is more, applying bw now, counter=%d",
+			top_priv->counter_to_update_axi_vote);
+		top_priv->counter_to_update_axi_vote = 0;
+		apply_bw_update = true;
+	}
+
+	CAM_DBG(CAM_ISP,
+		"counter=%d, apply_bw_update=%d",
+		top_priv->counter_to_update_axi_vote,
+		apply_bw_update);
+
+	if (apply_bw_update == true) {
+		rc = cam_cpas_update_axi_vote(
 			soc_private->cpas_handle,
-			&sum);
-	if (!rc) {
-		top_priv->hw_axi_vote.uncompressed_bw = sum.uncompressed_bw;
-		top_priv->hw_axi_vote.compressed_bw = sum.compressed_bw;
-	} else
-		CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+			&top_priv->to_be_applied_axi_vote);
+		if (!rc) {
+			top_priv->applied_axi_vote.uncompressed_bw =
+			top_priv->to_be_applied_axi_vote.uncompressed_bw;
+			top_priv->applied_axi_vote.compressed_bw =
+				top_priv->to_be_applied_axi_vote.compressed_bw;
+		} else {
+			CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+		}
+		top_priv->counter_to_update_axi_vote = 0;
+	}
 
 	return rc;
 }
@@ -198,7 +273,8 @@
 	}
 
 	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set clocks yet :%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set clocks yet :%d",
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else
@@ -239,16 +315,64 @@
 				bw_update->camnoc_bw_bytes;
 			top_priv->req_axi_vote[i].compressed_bw =
 				bw_update->external_bw_bytes;
+			top_priv->axi_vote_control[i] =
+				CAM_VFE_BW_CONTROL_INCLUDE;
 			break;
 		}
 	}
 
 	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set BW yet :%d",
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else
-		rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, false);
+
+	return rc;
+}
+
+static int cam_vfe_top_bw_control(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	 void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_bw_control_args       *bw_ctrl = NULL;
+	struct cam_isp_resource_node         *res = NULL;
+	struct cam_hw_info                   *hw_info = NULL;
+	int                                   rc = 0;
+	int                                   i;
+
+	bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args;
+	res = bw_ctrl->node_res;
+
+	if (!res || !res->hw_intf->hw_priv)
+		return -EINVAL;
+
+	hw_info = res->hw_intf->hw_priv;
+
+	if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+		res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+		CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+			res->hw_intf->hw_idx, res->res_type,
+			res->res_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+			top_priv->axi_vote_control[i] = bw_ctrl->action;
+			break;
+		}
+	}
+
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"VFE:%d Not ready to set BW yet :%d",
+			res->hw_intf->hw_idx,
+			hw_info->hw_state);
+	} else {
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+	}
 
 	return rc;
 }
@@ -396,6 +520,7 @@
 {
 	struct cam_vfe_top_ver2_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
+	struct cam_hw_info                      *hw_info = NULL;
 	int rc = 0;
 
 	if (!device_priv || !start_args) {
@@ -405,24 +530,33 @@
 
 	top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
 	mux_res = (struct cam_isp_resource_node *)start_args;
+	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
-	rc = cam_vfe_top_set_hw_clk_rate(top_priv);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
-		return rc;
-	}
+	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+		rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"set_hw_clk_rate failed, rc=%d", rc);
+			return rc;
+		}
 
-	rc = cam_vfe_top_set_axi_bw_vote(top_priv);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
-		return rc;
-	}
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"set_axi_bw_vote failed, rc=%d", rc);
+			return rc;
+		}
 
-	if (mux_res->start) {
-		rc = mux_res->start(mux_res);
+		if (mux_res->start) {
+			rc = mux_res->start(mux_res);
+		} else {
+			CAM_ERR(CAM_ISP,
+				"Invalid res id:%d", mux_res->res_id);
+			rc = -EINVAL;
+		}
 	} else {
-		CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id);
-		rc = -EINVAL;
+		CAM_ERR(CAM_ISP, "VFE HW not powered up");
+		rc = -EPERM;
 	}
 
 	return rc;
@@ -433,6 +567,7 @@
 {
 	struct cam_vfe_top_ver2_priv            *top_priv;
 	struct cam_isp_resource_node            *mux_res;
+	struct cam_hw_info                      *hw_info = NULL;
 	int i, rc = 0;
 
 	if (!device_priv || !stop_args) {
@@ -442,6 +577,7 @@
 
 	top_priv = (struct cam_vfe_top_ver2_priv   *)device_priv;
 	mux_res = (struct cam_isp_resource_node *)stop_args;
+	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
 	if (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF ||
 		(mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0 &&
@@ -458,20 +594,29 @@
 				top_priv->req_clk_rate[i] = 0;
 				top_priv->req_axi_vote[i].compressed_bw = 0;
 				top_priv->req_axi_vote[i].uncompressed_bw = 0;
+				top_priv->axi_vote_control[i] =
+					CAM_VFE_BW_CONTROL_EXCLUDE;
 				break;
 			}
 		}
 
-		rc = cam_vfe_top_set_hw_clk_rate(top_priv);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
-			return rc;
-		}
+		if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
+			rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"set_hw_clk_rate failed, rc=%d", rc);
+				return rc;
+			}
 
-		rc = cam_vfe_top_set_axi_bw_vote(top_priv);
-		if (rc) {
-			CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
-			return rc;
+			rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"set_axi_bw_vote failed, rc=%d", rc);
+				return rc;
+			}
+		} else {
+			CAM_ERR(CAM_ISP, "VFE HW not powered up");
+			rc = -EPERM;
 		}
 	}
 
@@ -518,6 +663,9 @@
 		rc = cam_vfe_top_bw_update(top_priv, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_CMD_BW_CONTROL:
+		rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -554,8 +702,11 @@
 	}
 	vfe_top->top_priv = top_priv;
 	top_priv->hw_clk_rate = 0;
-	top_priv->hw_axi_vote.compressed_bw = 0;
-	top_priv->hw_axi_vote.uncompressed_bw = 0;
+	top_priv->to_be_applied_axi_vote.compressed_bw = 0;
+	top_priv->to_be_applied_axi_vote.uncompressed_bw = 0;
+	top_priv->applied_axi_vote.compressed_bw = 0;
+	top_priv->applied_axi_vote.uncompressed_bw = 0;
+	top_priv->counter_to_update_axi_vote = 0;
 
 	for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
 		top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN;
@@ -565,6 +716,8 @@
 		top_priv->req_clk_rate[i] = 0;
 		top_priv->req_axi_vote[i].compressed_bw = 0;
 		top_priv->req_axi_vote[i].uncompressed_bw = 0;
+		top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE;
+
 
 		if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
 			top_priv->mux_rsrc[i].res_id =
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
index 1ccef0d..02334a4 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -121,7 +121,8 @@
 
 int cam_jpeg_context_init(struct cam_jpeg_context *ctx,
 	struct cam_context *ctx_base,
-	struct cam_hw_mgr_intf *hw_intf)
+	struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id)
 {
 	int rc;
 	int i;
@@ -139,8 +140,8 @@
 	for (i = 0; i < CAM_CTX_REQ_MAX; i++)
 		ctx->req_base[i].req_priv = ctx;
 
-	rc = cam_context_init(ctx_base, jpeg_dev_name, NULL, hw_intf,
-		ctx->req_base, CAM_CTX_REQ_MAX);
+	rc = cam_context_init(ctx_base, jpeg_dev_name, CAM_JPEG, ctx_id,
+		NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX);
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "Camera Context Base init failed");
 		goto err;
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
index 90ac5cf..1a40679 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -53,11 +53,13 @@
  * @ctx: JPEG context obj to be initialized
  * @ctx_base: Context base from cam_context
  * @hw_intf: JPEG hw manager interface
+ * @ctx_id: ID for this context
  *
  */
 int cam_jpeg_context_init(struct cam_jpeg_context *ctx,
 	struct cam_context *ctx_base,
-	struct cam_hw_mgr_intf *hw_intf);
+	struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id);
 
 /**
  * cam_jpeg_context_deinit()
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
index a400388..60feeac 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -98,7 +98,8 @@
 	for (i = 0; i < CAM_CTX_MAX; i++) {
 		rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i],
 			&g_jpeg_dev.ctx[i],
-			&node->hw_mgr_intf);
+			&node->hw_mgr_intf,
+			i);
 		if (rc) {
 			CAM_ERR(CAM_JPEG, "JPEG context init failed %d %d",
 				i, rc);
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 6e2e7e9..32f11a7 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -333,7 +333,6 @@
 
 	if (list_empty(&hw_mgr->hw_config_req_list)) {
 		CAM_DBG(CAM_JPEG, "no available request");
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -342,7 +341,6 @@
 		struct cam_jpeg_hw_cfg_req, list);
 	if (!p_cfg_req) {
 		CAM_ERR(CAM_JPEG, "no request");
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		rc = -EFAULT;
 		goto end;
 	}
@@ -353,13 +351,10 @@
 		list_del_init(&p_cfg_req->list);
 	} else {
 		CAM_DBG(CAM_JPEG, "Not dequeing, just return");
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		rc = -EFAULT;
 		goto end;
 	}
 
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
-
 	config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args;
 	request_id = task_data->request_id;
 	if (request_id != (uint64_t)config_args->priv) {
@@ -369,11 +364,11 @@
 
 	if (!config_args->num_hw_update_entries) {
 		CAM_ERR(CAM_JPEG, "No hw update enteries are available");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		rc = -EINVAL;
 		goto end_unusedev;
 	}
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map;
 	if (!ctx_data->in_use) {
 		CAM_ERR(CAM_JPEG, "ctx is not in use");
@@ -381,7 +376,6 @@
 		rc = -EINVAL;
 		goto end_unusedev;
 	}
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	dev_type = ctx_data->jpeg_dev_acquire_info.dev_type;
 
@@ -483,9 +477,11 @@
 		goto end_callcb;
 	}
 
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 
 end_callcb:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	if (p_cfg_req) {
 		buf_data.num_handles = p_cfg_req->
 			hw_cfg_args.num_out_map_entries;
@@ -498,14 +494,14 @@
 			(uint64_t)p_cfg_req->hw_cfg_args.priv;
 		ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data);
 	}
+
 end_unusedev:
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	hw_mgr->device_in_use[p_cfg_req->dev_type][0] = false;
 	hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = NULL;
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 end:
-
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 }
 
@@ -743,6 +739,9 @@
 	uint32_t dev_type;
 	struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL;
 	struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL;
+	struct cam_jpeg_set_irq_cb irq_cb;
+
+	CAM_DBG(CAM_JPEG, "E: JPEG flush ctx");
 
 	if (!hw_mgr || !ctx_data) {
 		CAM_ERR(CAM_JPEG, "Invalid args");
@@ -757,6 +756,30 @@
 		if ((struct cam_jpeg_hw_ctx_data *)p_cfg_req->
 		hw_cfg_args.ctxt_to_hw_map == ctx_data) {
 			/* stop reset Unregister CB and deinit */
+			irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb;
+			irq_cb.data = NULL;
+			irq_cb.b_set_cb = false;
+			if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) {
+				rc = hw_mgr->devices[dev_type][0]->
+					hw_ops.process_cmd(
+				hw_mgr->devices[dev_type][0]->hw_priv,
+				CAM_JPEG_CMD_SET_IRQ_CB,
+				&irq_cb, sizeof(irq_cb));
+			if (rc)
+				CAM_ERR(CAM_JPEG,
+					"CMD_SET_IRQ_CB failed %d", rc);
+
+			} else {
+				CAM_ERR(CAM_JPEG, "process_cmd null ");
+			}
+			rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd(
+				hw_mgr->devices[dev_type][0]->hw_priv,
+				CAM_JPEG_CMD_SET_IRQ_CB,
+				&irq_cb, sizeof(irq_cb));
+			if (rc)
+				CAM_ERR(CAM_JPEG,
+					"CMD_SET_IRQ_CB failed %d", rc);
+
 			if (hw_mgr->devices[dev_type][0]->hw_ops.stop) {
 				rc = hw_mgr->devices[dev_type][0]->hw_ops.stop(
 					hw_mgr->devices[dev_type][0]->hw_priv,
@@ -765,7 +788,19 @@
 					CAM_ERR(CAM_JPEG, "stop fail %d", rc);
 			} else {
 				CAM_ERR(CAM_JPEG, "op stop null ");
-				rc = -EINVAL;
+			}
+
+			if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) {
+				rc = hw_mgr->devices[dev_type][0]
+					->hw_ops.deinit(
+					hw_mgr->devices[dev_type][0]->hw_priv,
+					NULL, 0);
+				if (rc)
+					CAM_ERR(CAM_JPEG,
+						"Failed to Deinit %d HW",
+						dev_type);
+			} else {
+				CAM_ERR(CAM_JPEG, "op deinit null");
 			}
 		}
 
@@ -783,6 +818,8 @@
 		list_del_init(&cfg_req->list);
 	}
 
+	CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc);
+
 	return rc;
 }
 
@@ -795,6 +832,8 @@
 	struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp;
 	int64_t request_id;
 
+	CAM_DBG(CAM_JPEG, "E: JPEG flush req");
+
 	if (!hw_mgr || !ctx_data || !flush_args) {
 		CAM_ERR(CAM_JPEG, "Invalid args");
 		return -EINVAL;
@@ -816,6 +855,8 @@
 		list_del_init(&cfg_req->list);
 	}
 
+	CAM_DBG(CAM_JPEG, "X: JPEG flush req");
+
 	return 0;
 }
 
@@ -924,6 +965,7 @@
 	if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) {
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		CAM_ERR(CAM_JPEG, "Error Unbalanced deinit");
+		kfree(ctx_data->cdm_cmd);
 		return -EFAULT;
 	}
 
@@ -943,9 +985,12 @@
 	rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
 	if (rc) {
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		CAM_ERR(CAM_JPEG, "JPEG release ctx failed");
+		kfree(ctx_data->cdm_cmd);
 		return -EINVAL;
 	}
 
+	kfree(ctx_data->cdm_cmd);
 	CAM_DBG(CAM_JPEG, "handle %llu", ctx_data);
 
 	return rc;
@@ -999,7 +1044,7 @@
 			sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
 	if (!ctx_data->cdm_cmd) {
 		rc = -ENOMEM;
-		goto acq_cdm_hdl_failed;
+		goto jpeg_release_ctx;
 	}
 
 	mutex_lock(&ctx_data->ctx_mutex);
@@ -1046,20 +1091,8 @@
 		hw_mgr->cdm_info[dev_type][0].ref_cnt++;
 	}
 
-	ctx_data->cdm_cmd_chbase =
-		kzalloc(((sizeof(struct cam_cdm_bl_request)) +
-			(2 * sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
-	if (!ctx_data->cdm_cmd_chbase) {
-		rc = -ENOMEM;
-		goto start_cdm_hdl_failed;
-	}
 	size = hw_mgr->cdm_info[dev_type][0].
 		cdm_ops->cdm_required_size_changebase();
-	ctx_data->cmd_chbase_buf_addr = kzalloc(size*4, GFP_KERNEL);
-	if (!ctx_data->cdm_cmd_chbase) {
-		rc = -ENOMEM;
-		goto start_cdm_hdl_failed;
-	}
 
 	if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1)
 		if (cam_cdm_stream_on(
@@ -1101,6 +1134,7 @@
 	hw_mgr->cdm_info[dev_type][0].ref_cnt--;
 acq_cdm_hdl_failed:
 	kfree(ctx_data->cdm_cmd);
+jpeg_release_ctx:
 	cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
index dce47d2..5e10167 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -95,8 +95,6 @@
  * @in_use: Flag for context usage
  * @wait_complete: Completion info
  * @cdm_cmd: Cdm cmd submitted for that context.
- * @cdm_cmd_chbase: Change base cdm command from context
- * @cmd_chbase_buf_addr : Change base cmd buf address
  */
 struct cam_jpeg_hw_ctx_data {
 	void *context_priv;
@@ -106,8 +104,6 @@
 	bool in_use;
 	struct completion wait_complete;
 	struct cam_cdm_bl_request *cdm_cmd;
-	struct cam_cdm_bl_request *cdm_cmd_chbase;
-	uint32_t *cmd_chbase_buf_addr;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
index 1ab3143..3d0266d 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,6 +16,8 @@
 #include "cam_debug_util.h"
 #include "cam_lrme_context.h"
 
+static const char lrme_dev_name[] = "lrme";
+
 static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -208,7 +210,7 @@
 int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
 	struct cam_context *base_ctx,
 	struct cam_hw_mgr_intf *hw_intf,
-	uint64_t index)
+	uint32_t index)
 {
 	int rc = 0;
 
@@ -221,8 +223,8 @@
 
 	memset(lrme_ctx, 0, sizeof(*lrme_ctx));
 
-	rc = cam_context_init(base_ctx, "lrme", NULL, hw_intf,
-		lrme_ctx->req_base, CAM_CTX_REQ_MAX);
+	rc = cam_context_init(base_ctx, lrme_dev_name, CAM_LRME, index,
+		NULL, hw_intf, lrme_ctx->req_base, CAM_CTX_REQ_MAX);
 	if (rc) {
 		CAM_ERR(CAM_LRME, "Failed to init context");
 		return rc;
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
index 882f7ac..4c705c1 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,7 +35,7 @@
 
 int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
 	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
-	uint64_t index);
+	uint32_t index);
 int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx);
 
 #endif /* _CAM_LRME_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index bb952e6..21e66a2 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -68,6 +68,10 @@
 		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
 			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
 			0x1);
+	else if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10)
+		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+			0x22);
 	else
 		CAM_ERR(CAM_LRME, "Unsupported format %d",
 			io_buf->io_cfg->format);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index f514139..86c2039 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -2,9 +2,9 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
 
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o \
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\
+				cam_req_mgr_dev.o \
 				cam_req_mgr_util.o \
-				cam_req_mgr_core.o \
 				cam_req_mgr_workq.o \
 				cam_mem_mgr.o \
 				cam_req_mgr_timer.o \
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index 9689698..643b0afc 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -377,7 +377,8 @@
 		heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
 		ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA;
 	} else {
-		heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+		heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+			ION_HEAP(ION_CAMERA_HEAP_ID);
 	}
 
 	if (cmd->flags & CAM_MEM_FLAG_CACHE)
@@ -761,7 +762,7 @@
 				"Buffer inactive at idx=%d, continuing", i);
 			continue;
 		} else {
-			CAM_INFO(CAM_CRM,
+			CAM_DBG(CAM_CRM,
 			"Active buffer at idx=%d, possible leak needs unmapping",
 			i);
 			cam_mem_mgr_unmap_active_buf(i);
@@ -947,7 +948,8 @@
 	else
 		ion_flag &= ~ION_FLAG_CACHED;
 
-	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+		ION_HEAP(ION_CAMERA_HEAP_ID);
 
 	rc = cam_mem_util_get_dma_buf(inp->size,
 		inp->align,
@@ -1111,7 +1113,8 @@
 		return -EINVAL;
 	}
 
-	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) |
+		ION_HEAP(ION_CAMERA_HEAP_ID);
 	rc = cam_mem_util_get_dma_buf(inp->size,
 		inp->align,
 		heap_id,
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index d7662f1..3e6b856 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -25,6 +25,22 @@
 
 static struct cam_req_mgr_core_device *g_crm_core_dev;
 
+void cam_req_mgr_handle_core_shutdown(void)
+{
+	struct cam_req_mgr_core_session *session;
+	struct cam_req_mgr_core_session *tsession;
+	struct cam_req_mgr_session_info ses_info;
+
+	if (!list_empty(&g_crm_core_dev->session_head)) {
+		list_for_each_entry_safe(session, tsession,
+			&g_crm_core_dev->session_head, entry) {
+			ses_info.session_hdl =
+				session->session_hdl;
+			cam_req_mgr_destroy_session(&ses_info);
+		}
+	}
+}
+
 static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq)
 {
 	int32_t                  i = 0;
@@ -183,20 +199,14 @@
 		tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status,
 		traverse_data->in_q->slot[curr_idx].skip_idx);
 
-	if (tbl->inject_delay > 0 && (traverse_data->validate_only == false)) {
+	if ((tbl->inject_delay > 0) &&
+		(traverse_data->self_link == true)) {
 		CAM_DBG(CAM_CRM, "Injecting Delay of one frame");
+		apply_data[tbl->pd].req_id = -1;
 		tbl->inject_delay--;
 		/* This pd table is not ready to proceed with asked idx */
 		SET_FAILURE_BIT(traverse_data->result, tbl->pd);
-		apply_data[tbl->pd].req_id = -1;
-		if (tbl->next) {
-			__cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
-				tbl->num_slots);
-			traverse_data->idx = next_idx;
-			traverse_data->tbl = tbl->next;
-			rc = __cam_req_mgr_traverse(traverse_data);
-		}
-		return rc;
+		return -EAGAIN;
 	}
 
 	/* Check if req is ready or in skip mode or pd tbl is in skip mode */
@@ -212,14 +222,21 @@
 		}
 		if (rc >= 0) {
 			SET_SUCCESS_BIT(traverse_data->result, tbl->pd);
+
 			if (traverse_data->validate_only == false) {
 				apply_data[tbl->pd].pd = tbl->pd;
 				apply_data[tbl->pd].req_id =
-					CRM_GET_REQ_ID(traverse_data->in_q,
-					curr_idx);
+					CRM_GET_REQ_ID(
+					traverse_data->in_q, curr_idx);
 				apply_data[tbl->pd].idx = curr_idx;
 
-				/* If traverse is success dec traverse skip */
+				CAM_DBG(CAM_CRM, "req_id: %d with pd of %d",
+				apply_data[tbl->pd].req_id,
+				apply_data[tbl->pd].pd);
+				/*
+				 * If traverse is successful decrement
+				 * traverse skip
+				 */
 				if (tbl->skip_traverse > 0) {
 					apply_data[tbl->pd].req_id = -1;
 					tbl->skip_traverse--;
@@ -231,20 +248,8 @@
 		}
 	} else {
 		/* This pd table is not ready to proceed with asked idx */
-		if (tbl->slot[curr_idx].state == CRM_REQ_STATE_APPLIED)
-			SET_SUCCESS_BIT(traverse_data->result, tbl->pd);
-		else
-			SET_FAILURE_BIT(traverse_data->result, tbl->pd);
-
-		apply_data[tbl->pd].req_id = -1;
-		if (tbl->next) {
-			__cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
-				tbl->num_slots);
-			traverse_data->idx = next_idx;
-			traverse_data->tbl = tbl->next;
-			rc = __cam_req_mgr_traverse(traverse_data);
-		}
-		return rc;
+		SET_FAILURE_BIT(traverse_data->result, tbl->pd);
+		return -EAGAIN;
 	}
 	return 0;
 }
@@ -439,8 +444,8 @@
 			trace_cam_req_mgr_apply_request(link, &apply_req, dev);
 
 			apply_req.trigger_point = trigger;
-			CAM_DBG(CAM_CRM, "SEND: pd %d req_id %lld",
-				pd, apply_req.request_id);
+			CAM_DBG(CAM_CRM, "SEND: link_hdl: %x pd %d req_id %lld",
+				link->link_hdl, pd, apply_req.request_id);
 			if (dev->ops && dev->ops->apply_req) {
 				rc = dev->ops->apply_req(&apply_req);
 				if (rc < 0)
@@ -468,20 +473,20 @@
 /**
  * __cam_req_mgr_check_link_is_ready()
  *
- * @brief         : traverse through all request tables and see if
- *                  all devices are ready to apply request settings
- * @link          : pointer to link whose input queue and req tbl are
- *                  traversed through
- * @idx           : index within input request queue
+ * @brief    : traverse through all request tables and see if all devices are
+ *             ready to apply request settings.
+ * @link     : pointer to link whose input queue and req tbl are
+ *             traversed through
+ * @idx      : index within input request queue
  * @validate_only : Whether to validate only and/or update settings
- * @result        : Holds the value that indicates which of the pd
- *                  tables have a req that is ready to be applied
+ * @self_link : To indicate whether the validation is for the given link or
+ *              other sync link
  *
  * @return   : 0 for success, negative for failure
  *
  */
 static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link,
-	int32_t idx, bool validate_only, int *result)
+	int32_t idx, bool validate_only, bool self_link)
 {
 	int                            rc;
 	struct cam_req_mgr_traverse    traverse_data;
@@ -491,10 +496,10 @@
 	in_q = link->req.in_q;
 
 	apply_data = link->req.apply_data;
+
 	if (validate_only == false) {
 		memset(apply_data, 0,
-			sizeof(struct cam_req_mgr_apply) *
-			CAM_PIPELINE_DELAY_MAX);
+		    sizeof(struct cam_req_mgr_apply) * CAM_PIPELINE_DELAY_MAX);
 	}
 
 	traverse_data.apply_data = apply_data;
@@ -503,27 +508,28 @@
 	traverse_data.in_q = in_q;
 	traverse_data.result = 0;
 	traverse_data.validate_only = validate_only;
+	traverse_data.self_link = self_link;
 	/*
 	 *  Traverse through all pd tables, if result is success,
 	 *  apply the settings
 	 */
 
 	rc = __cam_req_mgr_traverse(&traverse_data);
-	CAM_DBG(CAM_CRM, "SOF: idx %d result %x pd_mask %x rc %d",
-		idx, traverse_data.result, link->pd_mask, rc);
+	CAM_DBG(CAM_CRM,
+		"SOF: idx %d self_link %d validate %d result %x pd_mask %x rc %d",
+		idx, traverse_data.self_link, traverse_data.validate_only,
+		traverse_data.result, link->pd_mask, rc);
 
-	if (!traverse_data.result)
-		return -EAGAIN;
-
-	if (!rc) {
+	if (!rc && traverse_data.result == link->pd_mask) {
 		CAM_DBG(CAM_CRM,
 			"APPLY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld",
 			link->link_hdl, idx,
-			apply_data[2].req_id, apply_data[1].req_id,
+			apply_data[2].req_id,
+			apply_data[1].req_id,
 			apply_data[0].req_id);
-	}
+	} else
+		rc = -EAGAIN;
 
-	*result = traverse_data.result;
 	return rc;
 }
 
@@ -574,6 +580,11 @@
 	link->sof_counter = -1;
 	link->sync_link->sof_counter = -1;
 	link->frame_skip_flag = false;
+
+	CAM_DBG(CAM_CRM,
+		"link_hdl %x self_counter %lld other_counter %lld frame_skip_lag %d",
+		link->link_hdl, link->sof_counter,
+		link->sync_link->sof_counter, link->frame_skip_flag);
 }
 
 /**
@@ -592,6 +603,11 @@
 	link->sof_counter++;
 	link->sync_self_ref = link->sof_counter -
 		link->sync_link->sof_counter;
+
+	CAM_DBG(CAM_CRM,
+		"link_hdl %x self_counter %lld other_counter %lld",
+		link->link_hdl, link->sof_counter,
+		link->sync_link->sof_counter);
 }
 
 /**
@@ -609,6 +625,11 @@
 	link->sof_counter = (MAX_SYNC_COUNT -
 		(link->sync_link->sof_counter));
 	link->sync_link->sof_counter = 0;
+
+	CAM_DBG(CAM_CRM,
+		"link_hdl %x self_counter %lld sync_link_hdl %x other_counter %lld",
+		link->link_hdl, link->sof_counter,
+		link->sync_link->link_hdl, link->sync_link->sof_counter);
 }
 
 /**
@@ -632,12 +653,18 @@
 		__cam_req_mgr_wrap_sof_cnt(link);
 
 	sync_diff = link->sof_counter - sync_link->sof_counter;
+
+	CAM_DBG(CAM_CRM,
+		"link[%x] self_counter=%lld other_counter=%lld diff=%lld sync_self_ref=%lld",
+		link->link_hdl, link->sof_counter,
+		sync_link->sof_counter, sync_diff, link->sync_self_ref);
+
 	if (sync_diff != link->sync_self_ref) {
 		link->sync_link->frame_skip_flag = true;
 		CAM_WARN(CAM_CRM,
-			"Detected anomaly, skip link:%d, self=%lld, other=%lld",
+			"Detected anomaly, skip link_hdl %x self_counter=%lld other_counter=%lld sync_self_ref=%lld",
 			link->link_hdl, link->sof_counter,
-			sync_link->sof_counter);
+			sync_link->sof_counter, link->sync_self_ref);
 		rc = -EPERM;
 	}
 
@@ -652,16 +679,12 @@
  * @link     : pointer to link whose input queue and req tbl are
  *             traversed through
  * @slot     : pointer to the current slot being processed
- * @result   : Holds the value that indicates which of the pd
- *             tables have a req that is ready to be applied
- *
  * @return   : 0 for success, negative for failure
  *
  */
 static int __cam_req_mgr_process_sync_req(
 	struct cam_req_mgr_core_link *link,
-	struct cam_req_mgr_slot *slot,
-	int *result)
+	struct cam_req_mgr_slot *slot)
 {
 	struct cam_req_mgr_core_link *sync_link = NULL;
 	int64_t req_id = 0;
@@ -674,11 +697,17 @@
 
 	sync_link = link->sync_link;
 	req_id = slot->req_id;
+
+	CAM_DBG(CAM_CRM,
+		"link_hdl %x req %lld sync_self_ref %lld sof_counter %lld frame_skip_flag %d sync_link_self_ref %lld",
+		link->link_hdl, req_id, link->sync_self_ref, link->sof_counter,
+		link->frame_skip_flag, link->sync_link->sync_self_ref);
+
 	if (link->sof_counter == -1) {
 		__cam_req_mgr_sof_cnt_initialize(link);
-	} else if (link->frame_skip_flag &&
+	} else if ((link->frame_skip_flag) &&
 		(sync_link->sync_self_ref != -1)) {
-		CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values",
+		CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values ",
 			link->link_hdl, req_id);
 		__cam_req_mgr_reset_sof_cnt(link);
 		__cam_req_mgr_sof_cnt_initialize(link);
@@ -686,7 +715,7 @@
 		link->sof_counter++;
 	}
 
-	rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, result);
+	rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true);
 	if (rc) {
 		CAM_DBG(CAM_CRM,
 			"Req: %lld [My link]not available link: %x, rc=%d",
@@ -696,9 +725,10 @@
 
 	sync_slot_idx = __cam_req_mgr_find_slot_for_req(
 		sync_link->req.in_q, req_id);
+
 	if (sync_slot_idx != -1) {
 		rc = __cam_req_mgr_check_link_is_ready(
-			sync_link, sync_slot_idx, true, result);
+			sync_link, sync_slot_idx, true, false);
 		CAM_DBG(CAM_CRM, "sync_slot_idx=%d, status=%d, rc=%d",
 			sync_slot_idx,
 			sync_link->req.in_q->slot[sync_slot_idx].status,
@@ -709,8 +739,8 @@
 	}
 
 	if ((sync_slot_idx != -1) &&
-		((sync_link->req.in_q->slot[sync_slot_idx].status ==
-		CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
+	((sync_link->req.in_q->slot[sync_slot_idx].status ==
+	CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
 		rc = __cam_req_mgr_validate_sof_cnt(link, sync_link);
 		if (rc) {
 			CAM_DBG(CAM_CRM,
@@ -718,8 +748,21 @@
 				req_id, sync_link->link_hdl);
 			goto failure;
 		}
-		__cam_req_mgr_check_link_is_ready(link, slot->idx, false,
-			result);
+
+		CAM_DBG(CAM_CRM,
+			"Req: %lld ready to apply on link: %x [validation successful]",
+			req_id, link->link_hdl);
+		/*
+		 *  At this point all validation is successfully done
+		 *  and we can proceed to apply the given request.
+		 *  Ideally the next call should return success.
+		 */
+		rc = __cam_req_mgr_check_link_is_ready(link,
+			slot->idx, false, true);
+
+		if (rc) {
+			CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc);
+		}
 	} else {
 		CAM_DBG(CAM_CRM,
 			"Req: %lld [Other link] not ready to apply on link: %x",
@@ -736,41 +779,6 @@
 }
 
 /**
- * __cam_req_mgr_reset_pd_tables()
- *
- * @brief    : resets pd tables based on req getting applied on
- *             from a particular pd table
- * @link     : pointer to link whose input queue and req tbl are
- *             traversed through
- * @slot     : Pointer to the current slot
- * @result   : indicates request of which pd table was successfully
- *             processed
- *
- */
-static void __cam_req_mgr_reset_pd_tables(
-	struct cam_req_mgr_core_link *link,
-	struct cam_req_mgr_slot *slot,
-	int result)
-{
-	int pd_set_bit = 0;
-	int curr_idx = slot->idx;
-	int no_tables = link->req.num_tbl;
-	int max_pd_delay = link->max_delay;
-	struct cam_req_mgr_req_tbl  *tbl = link->req.l_tbl;
-	struct cam_req_mgr_req_queue *in_q = link->req.in_q;
-
-	while (no_tables) {
-		pd_set_bit = (result & (1 << max_pd_delay));
-		if (pd_set_bit)
-			tbl->slot[curr_idx].state = CRM_REQ_STATE_APPLIED;
-		max_pd_delay--;
-		no_tables--;
-		tbl = tbl->next;
-		__cam_req_mgr_dec_idx(&curr_idx, 1, in_q->num_slots);
-	}
-}
-
-/**
  * __cam_req_mgr_process_req()
  *
  * @brief    : processes read index in request queue and traverse through table
@@ -783,7 +791,7 @@
 static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
 	uint32_t trigger)
 {
-	int                                  rc = 0, idx, result = 0;
+	int                                  rc = 0, idx;
 	struct cam_req_mgr_slot             *slot = NULL;
 	struct cam_req_mgr_req_queue        *in_q;
 	struct cam_req_mgr_core_session     *session;
@@ -798,9 +806,9 @@
 	 * - if in applied_state, somthign wrong.
 	 * - if in no_req state, no new req
 	 */
-	CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d",
+	CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d link_hdl %x",
 		in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx,
-		in_q->slot[in_q->rd_idx].status);
+		in_q->slot[in_q->rd_idx].status, link->link_hdl);
 
 	slot = &in_q->slot[in_q->rd_idx];
 	if (slot->status == CRM_SLOT_STATUS_NO_REQ) {
@@ -809,8 +817,8 @@
 		goto error;
 	}
 
-	if (trigger != CAM_TRIGGER_POINT_SOF &&
-			trigger != CAM_TRIGGER_POINT_EOF)
+	if ((trigger != CAM_TRIGGER_POINT_SOF) &&
+		(trigger != CAM_TRIGGER_POINT_EOF))
 		goto error;
 
 	if ((trigger == CAM_TRIGGER_POINT_EOF) &&
@@ -829,11 +837,10 @@
 		}
 
 		if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)
-			rc = __cam_req_mgr_process_sync_req(link, slot,
-				&result);
+			rc = __cam_req_mgr_process_sync_req(link, slot);
 		else
 			rc = __cam_req_mgr_check_link_is_ready(link,
-				slot->idx, false, &result);
+				slot->idx, false, true);
 
 		if (rc < 0) {
 			/*
@@ -865,10 +872,10 @@
 		/* Apply req failed retry at next sof */
 		slot->status = CRM_SLOT_STATUS_REQ_PENDING;
 	} else {
-		CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success",
-			slot->req_id, link->link_hdl);
 		link->trigger_mask |= trigger;
 
+		CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success",
+			slot->req_id, link->link_hdl);
 		spin_lock_bh(&link->link_state_spin_lock);
 		if (link->state == CAM_CRM_LINK_STATE_ERR) {
 			CAM_WARN(CAM_CRM, "Err recovery done idx %d",
@@ -878,30 +885,21 @@
 		spin_unlock_bh(&link->link_state_spin_lock);
 
 		if (link->trigger_mask == link->subscribe_event) {
-			if (result == link->pd_mask) {
-				slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
-				CAM_DBG(CAM_CRM, "req %d is applied on link %d",
-					slot->req_id, link->link_hdl);
-				idx = in_q->rd_idx;
-				__cam_req_mgr_dec_idx(
-					&idx, link->max_delay + 1,
-					in_q->num_slots);
-				__cam_req_mgr_reset_req_slot(link, idx);
-			} else {
-				CAM_DBG(CAM_CRM,
-					"Req:%lld not applied on all devices",
-				slot->req_id);
-				__cam_req_mgr_reset_pd_tables(link, slot,
-					result);
-				slot->status = CRM_SLOT_STATUS_REQ_PENDING;
-			}
-
+			slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
 			link->trigger_mask = 0;
+			CAM_DBG(CAM_CRM, "req %d is applied on link %x",
+				slot->req_id,
+				link->link_hdl);
+			idx = in_q->rd_idx;
+			__cam_req_mgr_dec_idx(
+				&idx, link->max_delay + 1,
+				in_q->num_slots);
+			__cam_req_mgr_reset_req_slot(link, idx);
 		}
 	}
+
 	mutex_unlock(&session->lock);
 	return rc;
-
 error:
 	mutex_unlock(&session->lock);
 	return rc;
@@ -1138,8 +1136,9 @@
  * @brief    : Cleans up the mem allocated while linking
  * @link     : pointer to link, mem associated with this link is freed
  *
+ * @return   : returns if unlink for any device was success or failure
  */
-static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
 {
 	int32_t                                 i = 0;
 	struct cam_req_mgr_connected_device    *dev;
@@ -1160,8 +1159,8 @@
 				rc = dev->ops->link_setup(&link_data);
 				if (rc)
 					CAM_ERR(CAM_CRM,
-						"Unlink failed dev_hdl 0x%x rc=%d",
-						dev->dev_hdl, rc);
+						"Unlink failed dev_hdl %d",
+						dev->dev_hdl);
 			}
 			dev->dev_hdl = 0;
 			dev->parent = NULL;
@@ -1176,6 +1175,8 @@
 	link->pd_mask = 0;
 	link->num_devs = 0;
 	link->max_delay = 0;
+
+	return rc;
 }
 
 /**
@@ -1238,6 +1239,9 @@
 	/*  Loop through and find a free index */
 	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
 		if (!session->links[i]) {
+			CAM_DBG(CAM_CRM,
+				"Free link index %d found, num_links=%d",
+				i, session->num_links);
 			session->links[i] = link;
 			break;
 		}
@@ -1442,9 +1446,9 @@
 		if (device->ops && device->ops->flush_req)
 			rc = device->ops->flush_req(&flush_req);
 	}
+	complete(&link->workq_comp);
 	mutex_unlock(&link->req.lock);
 
-	complete(&link->workq_comp);
 end:
 	return rc;
 }
@@ -1476,13 +1480,12 @@
 	link = (struct cam_req_mgr_core_link *)priv;
 	task_data = (struct crm_task_payload *)data;
 	sched_req  = (struct cam_req_mgr_sched_request *)&task_data->u;
-	CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld sync_mode %d",
-		sched_req->link_hdl,
-		sched_req->req_id,
-		sched_req->sync_mode);
-
 	in_q = link->req.in_q;
 
+	CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld at slot %d sync_mode %d",
+		sched_req->link_hdl, sched_req->req_id,
+		in_q->wr_idx, sched_req->sync_mode);
+
 	mutex_lock(&link->req.lock);
 	slot = &in_q->slot[in_q->wr_idx];
 
@@ -1490,9 +1493,6 @@
 		slot->status != CRM_SLOT_STATUS_REQ_APPLIED)
 		CAM_WARN(CAM_CRM, "in_q overwrite %d", slot->status);
 
-	CAM_DBG(CAM_CRM, "sched_req %lld at slot %d sync_mode %d",
-		sched_req->req_id, in_q->wr_idx, sched_req->sync_mode);
-
 	slot->status = CRM_SLOT_STATUS_REQ_ADDED;
 	slot->req_id = sched_req->req_id;
 	slot->sync_mode = sched_req->sync_mode;
@@ -1875,9 +1875,9 @@
 		rc = -EPERM;
 		goto end;
 	}
+	crm_timer_reset(link->watchdog);
 	spin_unlock_bh(&link->link_state_spin_lock);
 
-	crm_timer_reset(link->watchdog);
 	task = cam_req_mgr_workq_get_task(link->workq);
 	if (!task) {
 		CAM_ERR(CAM_CRM, "no empty task req_id %lld", err_info->req_id);
@@ -1938,9 +1938,9 @@
 		rc = -EPERM;
 		goto end;
 	}
+	crm_timer_reset(link->watchdog);
 	spin_unlock_bh(&link->link_state_spin_lock);
 
-	crm_timer_reset(link->watchdog);
 	task = cam_req_mgr_workq_get_task(link->workq);
 	if (!task) {
 		CAM_ERR(CAM_CRM, "no empty task frame %lld",
@@ -2109,22 +2109,6 @@
 	return rc;
 }
 
-void cam_req_mgr_handle_core_shutdown(void)
-{
-	struct cam_req_mgr_core_session *session;
-	struct cam_req_mgr_core_session *tsession;
-	struct cam_req_mgr_session_info ses_info;
-
-	if (!list_empty(&g_crm_core_dev->session_head)) {
-		list_for_each_entry_safe(session, tsession,
-			&g_crm_core_dev->session_head, entry) {
-			ses_info.session_hdl =
-				session->session_hdl;
-			cam_req_mgr_destroy_session(&ses_info);
-		}
-	}
-}
-
 /* IOCTLs handling section */
 int cam_req_mgr_create_session(
 	struct cam_req_mgr_session_info *ses_info)
@@ -2185,6 +2169,9 @@
 	mutex_lock(&link->lock);
 	spin_lock_bh(&link->link_state_spin_lock);
 	link->state = CAM_CRM_LINK_STATE_IDLE;
+
+	/* Destroy timer of link */
+	crm_timer_exit(&link->watchdog);
 	spin_unlock_bh(&link->link_state_spin_lock);
 	__cam_req_mgr_print_req_tbl(&link->req);
 
@@ -2192,13 +2179,14 @@
 	kfree(link->workq->task.pool[0].payload);
 	link->workq->task.pool[0].payload = NULL;
 
-	/* Destroy workq and timer of link */
-	crm_timer_exit(&link->watchdog);
-
+	/* Destroy workq of link */
 	cam_req_mgr_workq_destroy(&link->workq);
 
 	/* Cleanup request tables and unlink devices */
-	__cam_req_mgr_destroy_link_info(link);
+	rc = __cam_req_mgr_destroy_link_info(link);
+	if (rc)
+		CAM_ERR(CAM_CORE,
+			"Unlink for all devices was not successful");
 
 	/* Free memory holding data of linked devs */
 	__cam_req_mgr_destroy_subdev(link->l_dev);
@@ -2487,6 +2475,12 @@
 		return -EINVAL;
 	}
 
+	if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) {
+		CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x",
+			sync_info->link_hdls[0], sync_info->link_hdls[1]);
+		return -EINVAL;
+	}
+
 	mutex_lock(&g_crm_core_dev->crm_lock);
 	/* session hdl's priv data is cam session struct */
 	cam_session = (struct cam_req_mgr_core_session *)
@@ -2498,6 +2492,7 @@
 	}
 
 	mutex_lock(&cam_session->lock);
+
 	CAM_DBG(CAM_CRM, "link handles %x %x",
 		sync_info->link_hdls[0], sync_info->link_hdls[1]);
 
@@ -2607,9 +2602,12 @@
 int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control)
 {
 	int                               rc = 0;
-	int                               i;
+	int                               i, j;
 	struct cam_req_mgr_core_link     *link = NULL;
 
+	struct cam_req_mgr_connected_device *dev = NULL;
+	struct cam_req_mgr_link_evt_data     evt_data;
+
 	if (!control) {
 		CAM_ERR(CAM_CRM, "Control command is NULL");
 		rc = -EINVAL;
@@ -2639,9 +2637,31 @@
 					link->link_hdl);
 				rc = -EFAULT;
 			}
+			/* notify nodes */
+			for (j = 0; j < link->num_devs; j++) {
+				dev = &link->l_dev[j];
+				evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_RESUME;
+				evt_data.link_hdl =  link->link_hdl;
+				evt_data.dev_hdl = dev->dev_hdl;
+				evt_data.req_id = 0;
+				if (dev->ops && dev->ops->process_evt)
+					dev->ops->process_evt(&evt_data);
+			}
 		} else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) {
 			/* Destroy SOF watchdog timer */
+			spin_lock_bh(&link->link_state_spin_lock);
 			crm_timer_exit(&link->watchdog);
+			spin_unlock_bh(&link->link_state_spin_lock);
+			/* notify nodes */
+			for (j = 0; j < link->num_devs; j++) {
+				dev = &link->l_dev[j];
+				evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_PAUSE;
+				evt_data.link_hdl =  link->link_hdl;
+				evt_data.dev_hdl = dev->dev_hdl;
+				evt_data.req_id = 0;
+				if (dev->ops && dev->ops->process_evt)
+					dev->ops->process_evt(&evt_data);
+			}
 		} else {
 			CAM_ERR(CAM_CRM, "Invalid link control command");
 			rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
index 4511a5d..e4865b3 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -79,14 +79,12 @@
  * EMPTY   : indicates req slot is empty
  * PENDING : indicates req slot is waiting for reqs from all devs
  * READY   : indicates req slot is ready to be sent to devs
- * APPLIED : indicates req slot is already sent to devs
  * INVALID : indicates req slot is not in valid state
  */
 enum crm_req_state {
 	CRM_REQ_STATE_EMPTY,
 	CRM_REQ_STATE_PENDING,
 	CRM_REQ_STATE_READY,
-	CRM_REQ_STATE_APPLIED,
 	CRM_REQ_STATE_INVALID,
 };
 
@@ -132,6 +130,8 @@
  * @apply_data    : pointer which various tables will update during traverse
  * @in_q          : input request queue pointer
  * @validate_only : Whether to validate only and/or update settings
+ * @self_link     : To indicate whether the check is for the given link or the
+ *                  other sync link
  */
 struct cam_req_mgr_traverse {
 	int32_t                       idx;
@@ -140,6 +140,7 @@
 	struct cam_req_mgr_apply     *apply_data;
 	struct cam_req_mgr_req_queue *in_q;
 	bool                          validate_only;
+	bool                          self_link;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index e4944d0..9a93feb 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -25,10 +25,12 @@
 #include "cam_subdev.h"
 #include "cam_mem_mgr.h"
 #include "cam_debug_util.h"
+#include <linux/slub_def.h>
 
 #define CAM_REQ_MGR_EVENT_MAX 30
 
 static struct cam_req_mgr_device g_dev;
+struct kmem_cache *g_cam_req_mgr_timer_cachep;
 
 static int cam_media_device_setup(struct device *dev)
 {
@@ -635,6 +637,19 @@
 
 	g_dev.state = true;
 
+	if (g_cam_req_mgr_timer_cachep == NULL) {
+		g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer",
+			sizeof(struct cam_req_mgr_timer), 64,
+			SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE |
+			SLAB_POISON | SLAB_STORE_USER, NULL);
+		if (!g_cam_req_mgr_timer_cachep)
+			CAM_ERR(CAM_CRM,
+				"Failed to create kmem_cache for crm_timer");
+		else
+			CAM_DBG(CAM_CRM, "Name : %s",
+				g_cam_req_mgr_timer_cachep->name);
+	}
+
 	return rc;
 
 req_mgr_core_fail:
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
index ce8dfa7..1ca6cc5 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -81,9 +81,9 @@
  * @process_evt  : payload to generic event
  */
 struct cam_req_mgr_kmd_ops {
-	cam_req_mgr_get_dev_info      get_dev_info;
-	cam_req_mgr_link_setup        link_setup;
-	cam_req_mgr_apply_req         apply_req;
+	cam_req_mgr_get_dev_info     get_dev_info;
+	cam_req_mgr_link_setup       link_setup;
+	cam_req_mgr_apply_req        apply_req;
 	cam_req_mgr_flush_req        flush_req;
 	cam_req_mgr_process_evt      process_evt;
 };
@@ -182,6 +182,8 @@
  */
 enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_ERR,
+	CAM_REQ_MGR_LINK_EVT_PAUSE,
+	CAM_REQ_MGR_LINK_EVT_RESUME,
 	CAM_REQ_MGR_LINK_EVT_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
index 2189202..124b336 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -53,9 +53,18 @@
 
 	CAM_DBG(CAM_CRM, "init timer %d %pK", expires, *timer);
 	if (*timer == NULL) {
-		crm_timer = (struct cam_req_mgr_timer *)
-			kzalloc(sizeof(struct cam_req_mgr_timer), GFP_KERNEL);
-		if (!crm_timer) {
+		if (g_cam_req_mgr_timer_cachep) {
+			crm_timer = (struct cam_req_mgr_timer *)
+				kmem_cache_alloc(
+					g_cam_req_mgr_timer_cachep,
+					__GFP_ZERO | GFP_KERNEL);
+			if (!crm_timer) {
+				ret = -ENOMEM;
+				goto end;
+			}
+		}
+
+		else {
 			ret = -ENOMEM;
 			goto end;
 		}
@@ -80,10 +89,11 @@
 }
 void crm_timer_exit(struct cam_req_mgr_timer **crm_timer)
 {
-	CAM_DBG(CAM_CRM, "destroy timer %pK", *crm_timer);
+	CAM_DBG(CAM_CRM, "destroy timer %pK @ %pK", *crm_timer, crm_timer);
 	if (*crm_timer) {
 		del_timer_sync(&(*crm_timer)->sys_timer);
-		kfree(*crm_timer);
+		if (g_cam_req_mgr_timer_cachep)
+			kmem_cache_free(g_cam_req_mgr_timer_cachep, *crm_timer);
 		*crm_timer = NULL;
 	}
 }
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
index 4d600ee..b3e473a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -66,4 +66,6 @@
  * @timer : timer pointer which will be freed
  */
 void crm_timer_exit(struct cam_req_mgr_timer **timer);
+
+extern struct kmem_cache *g_cam_req_mgr_timer_cachep;
 #endif
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index f357941..dda04f8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -296,7 +296,7 @@
 
 	idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
 	if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
-		CAM_ERR(CAM_CRM, "Invalid idx");
+		CAM_ERR(CAM_CRM, "Invalid idx %d", idx);
 		goto destroy_hdl_fail;
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index c48a391..966b573 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -98,8 +98,10 @@
 static void cam_req_mgr_process_workq(struct work_struct *w)
 {
 	struct cam_req_mgr_core_workq *workq = NULL;
-	struct crm_workq_task         *task, *task_save;
+	struct crm_workq_task         *task;
 	int32_t                        i = CRM_TASK_PRIORITY_0;
+	unsigned long                  flags = 0;
+
 	if (!w) {
 		CAM_ERR(CAM_CRM, "NULL task pointer can not schedule");
 		return;
@@ -108,15 +110,19 @@
 		container_of(w, struct cam_req_mgr_core_workq, work);
 
 	while (i < CRM_TASK_PRIORITY_MAX) {
-		if (!list_empty(&workq->task.process_head[i])) {
-			list_for_each_entry_safe(task, task_save,
-				&workq->task.process_head[i], entry) {
-				atomic_sub(1, &workq->task.pending_cnt);
-				cam_req_mgr_process_task(task);
-			}
+		WORKQ_ACQUIRE_LOCK(workq, flags);
+		while (!list_empty(&workq->task.process_head[i])) {
+			task = list_first_entry(&workq->task.process_head[i],
+				struct crm_workq_task, entry);
+			atomic_sub(1, &workq->task.pending_cnt);
+			list_del_init(&task->entry);
+			WORKQ_RELEASE_LOCK(workq, flags);
+			cam_req_mgr_process_task(task);
 			CAM_DBG(CAM_CRM, "processed task %pK free_cnt %d",
 				task, atomic_read(&workq->task.free_cnt));
+			WORKQ_ACQUIRE_LOCK(workq, flags);
 		}
+		WORKQ_RELEASE_LOCK(workq, flags);
 		i++;
 	}
 }
@@ -267,6 +273,7 @@
 			destroy_workqueue((*crm_workq)->job);
 			(*crm_workq)->job = NULL;
 		}
+		kfree((*crm_workq)->task.pool);
 		kfree(*crm_workq);
 		*crm_workq = NULL;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index 9a711ec..bfeee6a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -87,6 +87,7 @@
 	struct cam_hw_soc_info *soc_info =
 		&cci_dev->soc_info;
 	void __iomem *base = soc_info->reg_map[0].mem_base;
+	unsigned long flags;
 
 	read_val = cam_io_r_mb(base +
 		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
@@ -110,12 +111,16 @@
 			CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
 		reg_val = 1 << ((master * 2) + queue);
 		CAM_DBG(CAM_CCI, "CCI_QUEUE_START_ADDR");
+		spin_lock_irqsave(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		atomic_set(&cci_dev->cci_master_info[master].
 						done_pending[queue], 1);
 		cam_io_w_mb(reg_val, base +
 			CCI_QUEUE_START_ADDR);
 		CAM_DBG(CAM_CCI, "wait_for_completion_timeout");
 		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		rc = wait_for_completion_timeout(&cci_dev->
 			cci_master_info[master].report_q[queue], CCI_TIMEOUT);
 		if (rc <= 0) {
@@ -183,45 +188,46 @@
 	uint32_t read_val = 0;
 	uint32_t i = 0;
 	uint32_t reg_offset = 0;
+	void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base;
 
 	/* CCI Top Registers */
-	CAM_DBG(CAM_CCI, "****CCI TOP Registers ****");
+	CAM_INFO(CAM_CCI, "****CCI TOP Registers ****");
 	for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) {
 		reg_offset = DEBUG_TOP_REG_START + i * 4;
-		read_val = cam_io_r_mb(cci_dev->base + reg_offset);
-		CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+		read_val = cam_io_r_mb(base + reg_offset);
+		CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
 			reg_offset, read_val);
 	}
 
 	/* CCI Master registers */
-	CAM_DBG(CAM_CCI, "****CCI MASTER %d Registers ****",
+	CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****",
 		master);
 	for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) {
 		if (i == 6)
 			continue;
 		reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4;
-		read_val = cam_io_r_mb(cci_dev->base + reg_offset);
-		CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+		read_val = cam_io_r_mb(base + reg_offset);
+		CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
 			reg_offset, read_val);
 	}
 
 	/* CCI Master Queue registers */
-	CAM_DBG(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****",
+	CAM_INFO(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****",
 		master, queue);
 	for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) {
 		reg_offset = DEBUG_MASTER_QUEUE_REG_START +  master*0x200 +
 			queue*0x100 + i * 4;
-		read_val = cam_io_r_mb(cci_dev->base + reg_offset);
-		CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+		read_val = cam_io_r_mb(base + reg_offset);
+		CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
 			reg_offset, read_val);
 	}
 
 	/* CCI Interrupt registers */
-	CAM_DBG(CAM_CCI, " ****CCI Interrupt Registers ****");
+	CAM_INFO(CAM_CCI, " ****CCI Interrupt Registers ****");
 	for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) {
 		reg_offset = DEBUG_INTR_REG_START + i * 4;
-		read_val = cam_io_r_mb(cci_dev->base + reg_offset);
-		CAM_DBG(CAM_CCI, "offset = 0x%X value = 0x%X",
+		read_val = cam_io_r_mb(base + reg_offset);
+		CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X",
 			reg_offset, read_val);
 	}
 }
@@ -289,6 +295,7 @@
 	enum cci_i2c_master_t master,
 	enum cci_i2c_queue_t queue)
 {
+	unsigned long flags;
 	struct cam_hw_soc_info *soc_info =
 		&cci_dev->soc_info;
 	void __iomem *base = soc_info->reg_map[0].mem_base;
@@ -296,8 +303,12 @@
 	uint32_t reg_val = 1 << ((master * 2) + queue);
 
 	cam_cci_load_report_cmd(cci_dev, master, queue);
+	spin_lock_irqsave(
+		&cci_dev->cci_master_info[master].lock_q[queue], flags);
 	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
 	atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
+	spin_unlock_irqrestore(
+		&cci_dev->cci_master_info[master].lock_q[queue], flags);
 	cam_io_w_mb(reg_val, base +
 		CCI_QUEUE_START_ADDR);
 
@@ -309,8 +320,13 @@
 	enum cci_i2c_queue_t queue)
 {
 	int32_t rc = 0;
+	unsigned long flags;
 
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+		lock_q[queue], flags);
 	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
 		if (rc < 0) {
 			CAM_ERR(CAM_CCI, "failed rc: %d", rc);
@@ -324,6 +340,8 @@
 	} else {
 		atomic_set(&cci_dev->cci_master_info[master].
 						done_pending[queue], 1);
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		rc = cam_cci_wait(cci_dev, master, queue);
 		if (rc < 0) {
 			CAM_ERR(CAM_CCI, "failed rc %d", rc);
@@ -371,13 +389,18 @@
 		&cci_dev->soc_info;
 	void __iomem *base = soc_info->reg_map[0].mem_base;
 	uint32_t reg_val = 1 << ((master * 2) + queue);
+	unsigned long flags;
 
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
 	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
 		cam_cci_load_report_cmd(cci_dev, master, queue);
 		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
 		cam_io_w_mb(reg_val, base +
 			CCI_QUEUE_START_ADDR);
 	}
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
 }
 
 static int32_t cam_cci_process_full_q(struct cci_device *cci_dev,
@@ -385,16 +408,24 @@
 	enum cci_i2c_queue_t queue)
 {
 	int32_t rc = 0;
+	unsigned long flags;
 
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
 	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 1) {
 		atomic_set(&cci_dev->cci_master_info[master].
 						done_pending[queue], 1);
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		rc = cam_cci_wait(cci_dev, master, queue);
 		if (rc < 0) {
 			CAM_ERR(CAM_CCI, "failed rc %d", rc);
 			return rc;
 		}
 	} else {
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[master].lock_q[queue], flags);
 		rc = cam_cci_wait_report_cmd(cci_dev, master, queue);
 		if (rc < 0) {
 			CAM_ERR(CAM_CCI, "failed rc %d", rc);
@@ -598,6 +629,7 @@
 	struct cam_hw_soc_info *soc_info =
 		&cci_dev->soc_info;
 	void __iomem *base = soc_info->reg_map[0].mem_base;
+	unsigned long flags;
 
 	if (i2c_cmd == NULL) {
 		CAM_ERR(CAM_CCI, "Failed: i2c cmd is NULL");
@@ -640,7 +672,11 @@
 	cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 		reg_offset);
 
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
 	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue],
+		flags);
 
 	max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
 			max_queue_size;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index ed91250..8fb2468 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -64,6 +64,7 @@
 	struct cam_hw_soc_info *soc_info =
 		&cci_dev->soc_info;
 	void __iomem *base = soc_info->reg_map[0].mem_base;
+	unsigned long flags;
 
 	irq = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR);
 	cam_io_w_mb(irq, base + CCI_IRQ_CLEAR_0_ADDR);
@@ -91,23 +92,35 @@
 		struct cam_cci_master_info *cci_master_info;
 
 		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(
+			&cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0],
+			flags);
 		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
 		cci_master_info->status = 0;
 		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
 			complete(&cci_master_info->report_q[QUEUE_0]);
 			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
 		}
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0],
+			flags);
 	}
 	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) {
 		struct cam_cci_master_info *cci_master_info;
 
 		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(
+			&cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1],
+			flags);
 		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
 		cci_master_info->status = 0;
 		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
 			complete(&cci_master_info->report_q[QUEUE_1]);
 			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
 		}
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1],
+			flags);
 	}
 	if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
 		cci_dev->cci_master_info[MASTER_1].status = 0;
@@ -117,23 +130,35 @@
 		struct cam_cci_master_info *cci_master_info;
 
 		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(
+			&cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0],
+			flags);
 		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
 		cci_master_info->status = 0;
 		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
 			complete(&cci_master_info->report_q[QUEUE_0]);
 			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
 		}
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0],
+			flags);
 	}
 	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) {
 		struct cam_cci_master_info *cci_master_info;
 
 		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(
+			&cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1],
+			flags);
 		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
 		cci_master_info->status = 0;
 		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
 			complete(&cci_master_info->report_q[QUEUE_1]);
 			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
 		}
+		spin_unlock_irqrestore(
+			&cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1],
+			flags);
 	}
 	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
 		cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
index d0ee0f6..d25964e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -144,6 +144,7 @@
 	struct mutex mutex_q[NUM_QUEUES];
 	struct completion report_q[NUM_QUEUES];
 	atomic_t done_pending[NUM_QUEUES];
+	spinlock_t lock_q[NUM_QUEUES];
 };
 
 struct cam_cci_clk_params_t {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
index cf7a65f..14737f9 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -198,7 +198,9 @@
 			mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
 			init_completion(&new_cci_dev->
 				cci_master_info[i].report_q[j]);
-			}
+			spin_lock_init(
+				&new_cci_dev->cci_master_info[i].lock_q[j]);
+		}
 	}
 }
 
@@ -390,7 +392,6 @@
 
 	cci_dev->cci_state = CCI_STATE_DISABLED;
 	cci_dev->cycles_per_us = 0;
-	soc_info->src_clk_idx = 0;
 
 	cam_cpas_stop(cci_dev->cpas_handle);
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 262e49c..4f30f56 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -71,9 +71,9 @@
 			csiphy_reset_reg[i].reg_addr);
 
 		usleep_range(csiphy_dev->ctrl_reg->
-			csiphy_reset_reg[i].delay * 100,
+			csiphy_reset_reg[i].delay * 1000,
 			csiphy_dev->ctrl_reg->
-			csiphy_reset_reg[i].delay * 100 + 1000);
+			csiphy_reset_reg[i].delay * 1000 + 10);
 	}
 }
 
@@ -285,6 +285,10 @@
 					csiphybase +
 					csiphy_dev->ctrl_reg->
 					csiphy_common_reg[i].reg_addr);
+				usleep_range(csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000,
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000 + 10);
 			break;
 			case CSIPHY_DEFAULT_PARAMS:
 				cam_io_w_mb(csiphy_dev->ctrl_reg->
@@ -292,6 +296,10 @@
 					csiphybase +
 					csiphy_dev->ctrl_reg->
 					csiphy_common_reg[i].reg_addr);
+				usleep_range(csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000,
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].delay*1000 + 10);
 			break;
 			default:
 			break;
@@ -506,6 +514,13 @@
 		bridge_params.media_entity_flag = 0;
 		bridge_params.priv = csiphy_dev;
 
+		if (csiphy_acq_params.combo_mode >= 2) {
+			CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d",
+				csiphy_acq_params.combo_mode);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+
 		csiphy_acq_dev.device_handle =
 			cam_create_device_hdl(&bridge_params);
 		csiphy_dev->bridge_intf.
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
index 2977834..3f743fc 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,8 +19,8 @@
 	.mipi_csiphy_interrupt_status0_addr = 0x8B0,
 	.mipi_csiphy_interrupt_clear0_addr = 0x858,
 	.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
-	.csiphy_common_array_size = 3,
-	.csiphy_reset_array_size = 3,
+	.csiphy_common_array_size = 5,
+	.csiphy_reset_array_size = 5,
 	.csiphy_2ph_config_array_size = 14,
 	.csiphy_3ph_config_array_size = 19,
 };
@@ -29,12 +29,16 @@
 	{0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE},
 	{0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 	{0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS},
+	{0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
 };
 
 struct csiphy_reg_t csiphy_reset_reg_1_0[] = {
-	{0x0814, 0x00, 0x50, CSIPHY_LANE_ENABLE},
+	{0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE},
 	{0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
 	{0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS},
+	{0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
 };
 
 struct csiphy_reg_t csiphy_irq_reg_1_0[] = {
@@ -148,7 +152,7 @@
 		{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
 		{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
-		{0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0060, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
 	},
 	{
@@ -164,7 +168,7 @@
 		{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
-		{0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0760, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
 	},
 	{
@@ -179,7 +183,7 @@
 		{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
 		{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
-		{0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0260, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
 	},
 	{
@@ -194,7 +198,7 @@
 		{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
 		{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
-		{0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0460, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
 	},
 	{
@@ -210,7 +214,7 @@
 		{0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
-		{0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0660, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
 		{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
 	},
 };
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index 085bcf6..6120e02 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -41,6 +41,8 @@
 			CAM_ERR(CAM_FLASH,
 				"Cannot apply Acquire dev: Prev state: %d",
 				fctrl->flash_state);
+			rc = -EINVAL;
+			goto release_mutex;
 		}
 
 		if (fctrl->bridge_intf.device_hdl != -1) {
@@ -161,6 +163,8 @@
 			CAM_WARN(CAM_FLASH,
 				"Cannot apply Stop dev: Prev state is: %d",
 				fctrl->flash_state);
+			rc = -EINVAL;
+			goto release_mutex;
 		}
 
 		rc = cam_flash_stop_dev(fctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 9894ca3..3066a91 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -161,12 +161,20 @@
 		break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: {
+		if (s_ctrl->streamon_count > 0)
+			return 0;
+
+		s_ctrl->streamon_count = s_ctrl->streamon_count + 1;
 		i2c_reg_settings = &i2c_data->streamon_settings;
 		i2c_reg_settings->request_id = 0;
 		i2c_reg_settings->is_settings_valid = 1;
 		break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: {
+		if (s_ctrl->streamoff_count > 0)
+			return 0;
+
+		s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1;
 		i2c_reg_settings = &i2c_data->streamoff_settings;
 		i2c_reg_settings->request_id = 0;
 		i2c_reg_settings->is_settings_valid = 1;
@@ -191,14 +199,16 @@
 			CAM_ERR(CAM_SENSOR,
 				"Already some pkt in offset req : %lld",
 				csl_packet->header.request_id);
-			rc = delete_request(i2c_reg_settings);
-			if (rc < 0) {
-				CAM_ERR(CAM_SENSOR,
-				"Failed in Deleting the err: %d", rc);
-				return rc;
-			}
+			/*
+			 * Update req mgr even in case of failure.
+			 * This will help not to wait indefinitely
+			 * and freeze. If this log is triggered then
+			 * fix it.
+			 */
+			cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+			return 0;
 		}
-	break;
+		break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
 		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
@@ -512,6 +522,8 @@
 	kfree(power_info->power_setting);
 	kfree(power_info->power_down_setting);
 
+	s_ctrl->streamon_count = 0;
+	s_ctrl->streamoff_count = 0;
 	s_ctrl->sensor_state = CAM_SENSOR_INIT;
 }
 
@@ -712,6 +724,9 @@
 		}
 
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+		CAM_INFO(CAM_SENSOR,
+			"CAM_ACQUIRE_DEV Success, sensor_id:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id);
 	}
 		break;
 	case CAM_RELEASE_DEV: {
@@ -749,6 +764,11 @@
 		s_ctrl->bridge_intf.session_hdl = -1;
 
 		s_ctrl->sensor_state = CAM_SENSOR_INIT;
+		CAM_INFO(CAM_SENSOR,
+			"CAM_RELEASE_DEV Success, sensor_id:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id);
+		s_ctrl->streamon_count = 0;
+		s_ctrl->streamoff_count = 0;
 	}
 		break;
 	case CAM_QUERY_CAP: {
@@ -784,6 +804,9 @@
 			}
 		}
 		s_ctrl->sensor_state = CAM_SENSOR_START;
+		CAM_INFO(CAM_SENSOR,
+			"CAM_START_DEV Success, sensor_id:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id);
 	}
 		break;
 	case CAM_STOP_DEV: {
@@ -807,6 +830,9 @@
 
 		cam_sensor_release_resource(s_ctrl);
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+		CAM_INFO(CAM_SENSOR,
+			"CAM_STOP_DEV Success, sensor_id:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id);
 	}
 		break;
 	case CAM_CONFIG_DEV: {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
index 624ea29..cc6070c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -90,6 +90,8 @@
  * @sensor_info: Sensor query cap structure
  * @bridge_intf: Bridge interface structure
  * @device_name: Sensor device structure
+ * @streamon_count: Count to hold the number of times stream on called
+ * @streamoff_count: Count to hold the number of times stream off called
  */
 struct cam_sensor_ctrl_t {
 	struct platform_device *pdev;
@@ -109,6 +111,8 @@
 	struct  cam_sensor_query_cap sensor_info;
 	struct intf_params bridge_intf;
 	char device_name[20];
+	uint32_t streamon_count;
+	uint32_t streamoff_count;
 };
 
 #endif /* _CAM_SENSOR_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index 7a6d7fd..89aad4e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -98,6 +98,11 @@
 		return -EINVAL;
 	}
 
+	if (!write_setting->reg_setting) {
+		CAM_ERR(CAM_SENSOR, "Invalid Register Settings");
+		return -EINVAL;
+	}
+
 	if (io_master_info->master_type == CCI_MASTER) {
 		return cam_cci_i2c_write_table(io_master_info,
 			write_setting);
@@ -125,6 +130,11 @@
 		return -EINVAL;
 	}
 
+	if (!write_setting->reg_setting) {
+		CAM_ERR(CAM_SENSOR, "Invalid Register Settings");
+		return -EINVAL;
+	}
+
 	if (io_master_info->master_type == CCI_MASTER) {
 		return cam_cci_i2c_write_continuous_table(io_master_info,
 			write_setting, cam_sensor_i2c_write_flag);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
index 131b0ae..07b390b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -468,6 +468,63 @@
 	return rc;
 }
 
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+	uint32_t addr, uint8_t *data,
+	enum camera_sensor_i2c_type addr_type, uint32_t num_byte)
+{
+	struct cam_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	const uint32_t page_size = client->spi_client->page_size;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	uint16_t len;
+	uint32_t cur_len, end;
+	char *tx, *pdata = data;
+	int rc = -EINVAL;
+
+	if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) ||
+		(addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID))
+		return rc;
+    /* single page write */
+	if ((addr % page_size) + num_byte <= page_size) {
+		len = header_len + num_byte;
+		tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!tx)
+			goto NOMEM;
+		rc = cam_spi_page_program(client, addr, data, addr_type,
+			num_byte, tx);
+		if (rc < 0)
+			goto ERROR;
+		goto OUT;
+	}
+	/* multi page write */
+	len = header_len + page_size;
+	tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!tx)
+		goto NOMEM;
+	while (num_byte) {
+		end = min(page_size, (addr % page_size) + num_byte);
+		cur_len = end - (addr % page_size);
+		CAM_ERR(CAM_SENSOR, "Addr: 0x%x curr_len: 0x%x pgSize: %d",
+			addr, cur_len, page_size);
+		rc = cam_spi_page_program(client, addr, pdata, addr_type,
+			cur_len, tx);
+		if (rc < 0)
+			goto ERROR;
+		addr += cur_len;
+		pdata += cur_len;
+		num_byte -= cur_len;
+	}
+	goto OUT;
+NOMEM:
+	pr_err("%s: memory allocation failed\n", __func__);
+	return -ENOMEM;
+ERROR:
+	pr_err("%s: error write\n", __func__);
+OUT:
+	kfree(tx);
+	return rc;
+}
+
 int cam_spi_write_table(struct camera_io_master *client,
 	struct cam_sensor_i2c_reg_setting *write_setting)
 {
@@ -508,3 +565,35 @@
 	addr_type = client_addr_type;
 	return rc;
 }
+
+int cam_spi_erase(struct camera_io_master *client,
+	uint32_t addr, enum camera_sensor_i2c_type addr_type,
+	uint32_t size) {
+	struct cam_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase;
+	int rc = 0;
+	uint32_t cur;
+	uint32_t end = addr + size;
+	uint32_t erase_size = client->spi_client->erase_size;
+
+	end = addr + size;
+	for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) {
+		CAM_ERR(CAM_SENSOR, "%s: erasing 0x%x size: %d\n",
+			__func__, cur, erase_size);
+		rc = cam_spi_write_enable(client, addr_type);
+		if (rc < 0)
+			return rc;
+		rc = cam_spi_tx_helper(client, se, cur, NULL, addr_type, 0,
+			NULL, NULL);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR, "%s: erase failed\n", __func__);
+			return rc;
+		}
+		rc = cam_spi_wait(client, se, addr_type);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR, "%s: erase timedout\n", __func__);
+			return rc;
+		}
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
index ec1bede..a63bff2 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -99,4 +99,12 @@
 int cam_spi_write_table(struct camera_io_master *client,
 	struct cam_sensor_i2c_reg_setting *write_setting);
 
+int cam_spi_erase(struct camera_io_master *client,
+	uint32_t addr, enum camera_sensor_i2c_type addr_type,
+	uint32_t size);
+
+int32_t cam_spi_write_seq(struct camera_io_master *client,
+	uint32_t addr, uint8_t *data,
+	enum camera_sensor_i2c_type addr_type, uint32_t num_byte);
+
 #endif
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 72ca737..622dae6 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -26,7 +26,7 @@
 #define MAX_REGULATOR 5
 #define MAX_POWER_CONFIG 12
 
-#define MAX_PER_FRAME_ARRAY 8
+#define MAX_PER_FRAME_ARRAY 32
 
 #define CAM_SENSOR_NAME    "cam-sensor"
 #define CAM_ACTUATOR_NAME  "cam-actuator"
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 82ba24f..f9b846b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -147,7 +147,7 @@
 		sizeof(uint32_t);
 	(*byte_cnt) += sizeof(struct cam_cmd_conditional_wait);
 
-	(*offset) += 1;
+	*offset = 1;
 	*list_ptr = &(i2c_list->list);
 
 	return rc;
@@ -191,7 +191,7 @@
 		i2c_list->i2c_settings.
 			reg_setting[cnt].data_mask = 0;
 	}
-	(*offset) += cnt;
+	*offset = cnt;
 	*list = &(i2c_list->list);
 
 	return rc;
@@ -246,7 +246,7 @@
 		i2c_list->i2c_settings.
 			reg_setting[cnt].data_mask = 0;
 	}
-	(*offset) += cnt;
+	*offset = cnt;
 	*list = &(i2c_list->list);
 
 	return rc;
@@ -1349,7 +1349,8 @@
 
 			rc = msm_cam_sensor_handle_reg_gpio(
 				power_setting->seq_type,
-				gpio_num_info, 1);
+				gpio_num_info,
+				(int) power_setting->config_val);
 			if (rc < 0) {
 				CAM_ERR(CAM_SENSOR,
 					"Error in handling VREG GPIO");
@@ -1476,6 +1477,9 @@
 				power_setting->data[0] =
 						soc_info->rgltr[vreg_idx];
 
+				regulator_put(
+					soc_info->rgltr[vreg_idx]);
+				soc_info->rgltr[vreg_idx] = NULL;
 			}
 			else
 				CAM_ERR(CAM_SENSOR, "seq_val:%d > num_vreg: %d",
@@ -1575,8 +1579,12 @@
 					soc_info->rgltr_op_mode[j],
 					soc_info->rgltr_delay[j]);
 
-					ps->data[0] =
-						soc_info->rgltr[j];
+				ps->data[0] =
+					soc_info->rgltr[j];
+
+				regulator_put(
+					soc_info->rgltr[j]);
+				soc_info->rgltr[j] = NULL;
 			}
 		}
 	}
@@ -1667,6 +1675,10 @@
 
 					ps->data[0] =
 						soc_info->rgltr[ps->seq_val];
+
+					regulator_put(
+						soc_info->rgltr[ps->seq_val]);
+					soc_info->rgltr[ps->seq_val] = NULL;
 				}
 				else
 					CAM_ERR(CAM_SENSOR,
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index c757315..e04c6b9 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -140,6 +140,7 @@
 	struct work_struct smmu_work;
 	struct mutex payload_list_lock;
 	struct list_head payload_list;
+	u32 non_fatal_fault;
 };
 
 static const struct of_device_id msm_cam_smmu_dt_match[] = {
@@ -2902,6 +2903,15 @@
 			rc = -ENODEV;
 			goto end;
 		}
+
+		iommu_cb_set.non_fatal_fault = 1;
+		if (iommu_domain_set_attr(cb->mapping->domain,
+			DOMAIN_ATTR_NON_FATAL_FAULTS,
+			&iommu_cb_set.non_fatal_fault) < 0) {
+			CAM_ERR(CAM_SMMU,
+				"Error: failed to set non fatal fault attribute");
+		}
+
 	} else {
 		CAM_ERR(CAM_SMMU, "Context bank does not have IO region");
 		rc = -ENODEV;
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 3d230af..d625a20 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -90,8 +90,9 @@
 	}
 
 	/* Trigger callback if sync object is already in SIGNALED state */
-	if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
-		row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+	if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+		row->state == CAM_SYNC_STATE_SIGNALED_ERROR) &&
+		(!row->remaining)) {
 		sync_cb->callback_func = cb_func;
 		sync_cb->cb_data = userdata;
 		sync_cb->sync_obj = sync_obj;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
index 1b5fd9f..8d5f96a 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2014, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2017-2018, 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
@@ -36,6 +37,8 @@
 	/* Ensure previous writes are done */
 	wmb();
 	writel_relaxed_no_log(data, addr);
+	/* Ensure previous writes are done */
+	wmb();
 
 	return 0;
 }
@@ -68,6 +71,8 @@
 	rmb();
 	data = readl_relaxed(addr);
 	CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data);
+	/* Ensure previous read is done */
+	rmb();
 
 	return data;
 }
@@ -113,6 +118,8 @@
 		CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s);
 		writel_relaxed(*s++, d++);
 	}
+	/* Ensure previous writes are done */
+	wmb();
 
 	return 0;
 }
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index bd56310..d0a13ab 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,8 +15,62 @@
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
+#include <soc/qcom/socinfo.h>
 #include "cam_soc_util.h"
 #include "cam_debug_util.h"
+#include <linux/nvmem-consumer.h>
+
+uint32_t cam_soc_util_get_soc_id(void)
+{
+	return socinfo_get_id();
+}
+#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+	struct nvmem_cell *cell;
+	ssize_t len;
+	uint32_t *buf, hw_rev;
+	struct platform_device *pdev;
+
+	pdev = soc_info->pdev;
+	/* read the soc hw revision and select revision node */
+	cell = nvmem_cell_get(&pdev->dev, "minor_rev");
+	if (IS_ERR_OR_NULL(cell)) {
+		if (PTR_ERR(cell) == -EPROBE_DEFER) {
+			CAM_ERR(CAM_UTIL, "Err to get nvmem cell: ret=%ld",
+				PTR_ERR(cell));
+			return -EINVAL;
+		}
+		CAM_ERR(CAM_UTIL, "No DTS entry");
+		return 0;
+	}
+
+	if (PTR_ERR(cell) == -ENOENT) {
+		CAM_DBG(CAM_UTIL, "nvme cell not found");
+		return 0;
+	}
+
+	buf = nvmem_cell_read(cell, &len);
+	nvmem_cell_put(cell);
+
+	if (IS_ERR_OR_NULL(buf)) {
+		CAM_ERR(CAM_UTIL, "Unable to read nvmem cell: ret=%ld",
+			PTR_ERR(buf));
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_UTIL, "hw_rev = %u", *buf);
+	hw_rev = (*buf >> 28) & 0x3;
+	kfree(buf);
+
+	return hw_rev;
+}
+#else
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+	return 0;
+}
+#endif
 
 int cam_soc_util_get_level_from_string(const char *string,
 	enum cam_vote_level *level)
@@ -859,7 +913,7 @@
 
 	count = of_property_count_strings(of_node, "reg-names");
 	if (count <= 0) {
-		CAM_WARN(CAM_UTIL, "no reg-names found for: %s",
+		CAM_DBG(CAM_UTIL, "no reg-names found for: %s",
 			soc_info->dev_name);
 		count = 0;
 	}
@@ -896,7 +950,7 @@
 	rc = of_property_read_string_index(of_node, "interrupt-names", 0,
 		&soc_info->irq_name);
 	if (rc) {
-		CAM_WARN(CAM_UTIL, "No interrupt line preset for: %s",
+		CAM_DBG(CAM_UTIL, "No interrupt line preset for: %s",
 			soc_info->dev_name);
 		rc = 0;
 	} else {
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 4b57d54..1f2d46d 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -40,6 +40,11 @@
 /* maximum number of device clock */
 #define CAM_SOC_MAX_CLK             32
 
+/* soc id */
+#define SDM670_SOC_ID 336
+
+/* Minor Version */
+#define SDM670_V1_1 0x1
 /**
  * enum cam_vote_level - Enum for voting level
  *
@@ -615,5 +620,23 @@
 
 int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info,
 	enum cam_vote_level clk_level);
+/**
+ * cam_soc_util_get_soc_id()
+ *
+ * @brief:           Read soc id
+ *
+ * @return           SOC id
+ */
+uint32_t cam_soc_util_get_soc_id(void);
 
+/**
+ * cam_soc_util_get_hw_revision_node()
+ *
+ * @brief:           Camera HW ID
+ *
+ * @soc_info:        Device soc information
+ *
+ * @return           HW id
+ */
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info);
 #endif /* _CAM_SOC_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
new file mode 100644
index 0000000..cabc612
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -0,0 +1,261 @@
+config MSM_CAMERA_SENSOR
+	    bool "QTI MSM camera sensor support"
+	    depends on MSMB_CAMERA
+	    select NEW_LEDS
+	    select LEDS_CLASS
+        ---help---
+          This flag enables support for Camera Sensor.
+          The sensor driver is capable of providing real time
+          data for camera support. The driver support V4L2
+          subdev APIs.
+
+config MSM_CPP
+        bool "QTI MSM Camera Post Processing Engine support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Camera Post-processing Engine
+          The Post processing engine is capable of scaling
+          and cropping image. The driver support V4L2 subdev
+          APIs.
+
+config MSM_CCI
+        bool "QTI MSM Camera Control Interface support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Camera Control Interface driver only
+          for those platforms that have hardware support. This driver
+          is responsible for handling I2C read and write on the I2C
+          bus. It is also responsible for synchronization with
+          GPIO and data frames.
+
+config MSM_CSI20_HEADER
+        bool "QTI MSM CSI 2.0 Header"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for CSI drivers to include 2.0
+          header. This header has register macros and its
+          values and bit mask for register configuration bits
+          This config macro is required targets based on 8960,
+          8930 and 8064 platforms.
+
+config MSM_CSI22_HEADER
+        bool "QTI MSM CSI 2.2 Header"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for CSI drivers to include 2.2
+          header. This header has register macros and its
+          values and bit mask for register configuration bits
+          This config macro is required targets based on 8610
+          platform.
+
+config MSM_CSI30_HEADER
+        bool "QTI MSM CSI 3.0 Header"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for CSI drivers to include 3.0
+          header. This header has register macros and its
+          values and bit mask for register configuration bits
+          This config macro is required for targets based on
+          8064 platforms.
+
+config MSM_CSI31_HEADER
+        bool "QTI MSM CSI 3.1 Header"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for CSI drivers to include 3.0
+          header. This header has register macros and its
+          values and bit mask for register configuration bits
+          This config macro is required for targets based on
+          APQ8084 platform.
+
+config MSM_CSIPHY
+        bool "QTI MSM Camera Serial Interface Physical receiver support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Camera Serial Interface
+          Physical receiver. It deserializes packets and
+          supports detection of packet start and stop
+          signalling.
+
+config MSM_CSID
+        bool "QTI MSM Camera Serial Interface decoder support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Camera Serial Interface decoder.
+          It supports lane merging and decoding of packets
+          based on cid which is mapped to a virtual channel
+          and datatype.
+
+config MSM_EEPROM
+        bool "QTI MSM Camera ROM Interface for Calibration support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for ROM Interface for Calibration
+          Provides interface for reading the Claibration data.
+          and also provides support for writing data in case of FLASH ROM.
+	  Currently supports I2C, CCI and SPI protocol
+
+config MSM_ISPIF
+        bool "QTI MSM Image Signal Processing interface support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Image Signal Processing interface module.
+          This module acts as a crossbar between CSID and VFE. Output
+          of any CID of CSID can be routed to of of pix or raw
+          data interface in VFE.
+
+config MSM_ISPIF_V1
+        bool "QTI MSM Image Signal Processing interface support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Image Signal Processing interface module.
+          This module acts as a crossbar between CSID and VFE. Output
+          of any CID of MSM_CSI22_HEADER can be routed to of pix
+          or raw data interface in VFE.
+
+config MSM_ISPIF_V2
+        bool "QTI MSM Image Signal Processing interface support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Image Signal Processing interface module.
+          This module acts as a crossbar between CSID and VFE. Output
+          of any CID of CSID can be routed to of pix
+          or raw data interface in VFE.
+
+config IMX134
+	bool "Sensor IMX134 (BAYER 8M)"
+	depends on MSMB_CAMERA
+	---help---
+		Sony 8 MP Bayer Sensor with auto focus, uses
+		4 mipi lanes full resolution @30fps and
+		HFR @60fps and @120fps,
+		Video HDR support.
+
+config IMX132
+	bool "Sensor IMX132 (BAYER 2M)"
+	depends on MSMB_CAMERA
+	---help---
+		Sony 2 MP Bayer Sensor with auto focus, uses
+		2 mipi lanes, preview config = 1920 x 1080 at 30 fps,
+		snapshot config = 1920 x 1080 at 30 fps,
+		Video HDR support.
+
+config OV9724
+	bool "Sensor OV9724 (BAYER 2M)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes,
+		preview and snapshot config at 1280*720 at 30 fps,
+		hfr video at 60, 90 and 120 fps. This sensor driver does
+		not support auto focus.
+
+config OV5648
+	bool "Sensor OV5648 (BAYER 5M)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 5 MP Bayer Sensor, only use 1 mipi lane,
+		preview set to 1296*972 at 30 fps,
+		snapshot set to 2592*1944 at 12 fps,
+		This sensor driver does not support auto focus.
+
+config GC0339
+	bool "Sensor GC0339 (BAYER .3M)"
+	depends on MSMB_CAMERA
+	---help---
+		gc0339 is a Galaxycore .3 MP Bayer Sensor.
+		It supports 1 or 2 mipi lanes.
+		Preview and snapshot resolution shall be 640*480 at 30 fps,
+		It does not support auto focus.
+
+config OV8825
+	bool "OmniVision OV8825 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		2 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 18 fps.
+		2 lanes max fps is 18, 4 lanes max fps is 24.
+
+config OV8865
+	bool "OmniVision OV8865 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 30 fps.
+		Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224
+
+config s5k4e1
+	bool "Sensor s5k4e1 (BAYER 5MP)"
+	depends on MSMB_CAMERA
+	---help---
+		Samsung 5 MP Bayer Sensor. It uses 2 mipi lanes,
+		supports 720P preview at 30 fps
+		and QSXGA snapshot at 15 fps.
+		This sensor driver does not support auto focus.
+
+config OV12830
+	bool "OmniVision OV12830 (BAYER 12MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 12.8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 2112 * 1500 at 30 fps,
+		snapshot config = 4224 * 3000 at 15 fps.
+		2 lanes max fps is 18, 4 lanes max fps is 24.
+
+config MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	tristate "QTI MSM V4l2 video overlay device"
+	---help---
+	  Enables support for the MSM V4L2 video
+	  overlay driver. This allows video rendering
+	  apps to render overlaid video using Video4Linux2
+	  APIs, by using /dev/videoX device
+
+config MSMB_JPEG
+	tristate "QTI MSM Jpeg Encoder Engine support"
+        depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8916 || ARCH_QCOM)
+	---help---
+	  Enable support for Jpeg Encoder/Decoder
+	  Engine for 8974.
+	  This module serves as the common driver
+	  for the JPEG 1.0 encoder and decoder.
+
+config MSM_GEMINI
+	tristate "QTI MSM Gemini JPEG engine support"
+	depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
+	---help---
+	  Enables support for the Gemini JPEG encoder
+	  Engine for 8x60, 7x30 and 8960.
+	  This module serves as the driver
+	  for JPEG encoding functionality.
+
+config MSM_FD
+	 tristate "QTI MSM FD face detection engine support"
+	 depends on MSMB_CAMERA
+	 ---help---
+	    Enables support for the MSM FD face detection engine
+            Engine for 8996, 8998.
+            This module serves as the driver for
+            detection of face ROI in a luma frame.
+
+config MSM_JPEGDMA
+	tristate "QTI MSM Jpeg dma"
+        depends on MSMB_CAMERA
+        select V4L2_MEM2MEM_DEV
+	---help---
+	  Enable support for Jpeg dma engine
+          Engine for 8996, 8998.
+          This module serves as the driver for
+          downscale and data transfer functionality.
+
+config MSM_SEC_CCI_TA_NAME
+	string "Name of TA to handle Secure CCI transactions"
+	depends on MSM_CCI
+	default "seccamdemo64"
+
+config MSM_SEC_CCI_DEBUG
+	bool "QTI MSM Secure CCI Relay Debug"
+	depends on MSM_CCI
+	---help---
+	  Enables simulation of secure camera for Secure CCI Realy
+	  debugging.
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
new file mode 100644
index 0000000..4348d44
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -0,0 +1,24 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/codecs
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_dma
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/fd
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+
+obj-$(CONFIG_MSMB_CAMERA) += common/
+obj-$(CONFIG_MSMB_CAMERA) += msm.o
+obj-$(CONFIG_MSMB_CAMERA) += camera/
+obj-$(CONFIG_MSMB_CAMERA) += msm_vb2/
+obj-$(CONFIG_MSMB_CAMERA) += sensor/
+obj-$(CONFIG_MSMB_CAMERA) += pproc/
+obj-$(CONFIG_MSMB_CAMERA) += isp/
+obj-$(CONFIG_MSMB_CAMERA) += ispif/
+obj-$(CONFIG_MSMB_JPEG) += jpeg_10/
+obj-$(CONFIG_MSM_JPEGDMA) += jpeg_dma/
+obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/
+obj-$(CONFIG_MSM_FD) += fd/
diff --git a/drivers/media/platform/msm/camera_v2/camera/Makefile b/drivers/media/platform/msm/camera_v2/camera/Makefile
new file mode 100644
index 0000000..bd70750
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/camera/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
+obj-$(CONFIG_MSMB_CAMERA) += camera.o
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
new file mode 100644
index 0000000..01ee5d4
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -0,0 +1,970 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "camera.h"
+#include "msm.h"
+#include "msm_vb2.h"
+
+#define fh_to_private(__fh) \
+	container_of(__fh, struct camera_v4l2_private, fh)
+
+struct camera_v4l2_private {
+	struct v4l2_fh fh;
+	unsigned int stream_id;
+	unsigned int is_vb2_valid; /*0 if no vb2 buffers on stream, else 1*/
+	struct vb2_queue vb2_q;
+	bool stream_created;
+	struct mutex lock;
+};
+
+static void camera_pack_event(struct file *filep, int evt_id,
+	int command, int value, struct v4l2_event *event)
+{
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event->u.data[0];
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
+
+	/* always MSM_CAMERA_V4L2_EVENT_TYPE */
+	event->type = MSM_CAMERA_V4L2_EVENT_TYPE;
+	event->id = evt_id;
+	event_data->command = command;
+	event_data->session_id = pvdev->vdev->num;
+	event_data->stream_id = sp->stream_id;
+	event_data->arg_value = value;
+}
+
+static int camera_check_event_status(struct v4l2_event *event)
+{
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event->u.data[0];
+
+	if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) {
+		pr_err("%s : event_data status out of bounds\n",
+				__func__);
+		pr_err("%s : Line %d event_data->status 0X%x\n",
+				__func__, __LINE__, event_data->status);
+
+		switch (event_data->status) {
+		case MSM_CAMERA_ERR_CMD_FAIL:
+		case MSM_CAMERA_ERR_MAPPING:
+			return -EFAULT;
+		case MSM_CAMERA_ERR_DEVICE_BUSY:
+			return -EBUSY;
+		default:
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int camera_v4l2_querycap(struct file *filep, void *fh,
+	struct v4l2_capability *cap)
+{
+	int rc;
+	struct v4l2_event event;
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	/* can use cap->driver to make differentiation */
+	camera_pack_event(filep, MSM_CAMERA_GET_PARM,
+		MSM_CAMERA_PRIV_QUERY_CAP, -1, &event);
+
+	rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+	if (rc < 0)
+		return rc;
+
+	rc = camera_check_event_status(&event);
+
+	return rc;
+}
+
+static int camera_v4l2_s_crop(struct file *filep, void *fh,
+	const struct v4l2_crop *crop)
+{
+	int rc = 0;
+	struct v4l2_event event;
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+
+		camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+			MSM_CAMERA_PRIV_S_CROP, -1, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+
+		rc = camera_check_event_status(&event);
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_g_crop(struct file *filep, void *fh,
+	struct v4l2_crop *crop)
+{
+	int rc = 0;
+	struct v4l2_event event;
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		camera_pack_event(filep, MSM_CAMERA_GET_PARM,
+			MSM_CAMERA_PRIV_G_CROP, -1, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+
+		rc = camera_check_event_status(&event);
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_queryctrl(struct file *filep, void *fh,
+	struct v4l2_queryctrl *ctrl)
+{
+	int rc = 0;
+	struct v4l2_event event;
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+
+		camera_pack_event(filep, MSM_CAMERA_GET_PARM,
+			ctrl->id, -1, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+
+		rc = camera_check_event_status(&event);
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_g_ctrl(struct file *filep, void *fh,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct v4l2_event event;
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+
+	if (ctrl->id >= V4L2_CID_PRIVATE_BASE) {
+		if (ctrl->id == MSM_CAMERA_PRIV_G_SESSION_ID) {
+			ctrl->value = session_id;
+		} else {
+			camera_pack_event(filep, MSM_CAMERA_GET_PARM,
+					ctrl->id, -1, &event);
+
+			rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+			if (rc < 0)
+				return rc;
+
+			rc = camera_check_event_status(&event);
+		}
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_s_ctrl(struct file *filep, void *fh,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct v4l2_event event;
+	struct msm_v4l2_event_data *event_data;
+
+	if (ctrl->id >= V4L2_CID_PRIVATE_BASE) {
+		camera_pack_event(filep, MSM_CAMERA_SET_PARM, ctrl->id,
+		ctrl->value, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+		event_data = (struct msm_v4l2_event_data *)event.u.data;
+		ctrl->value = event_data->ret_value;
+		rc = camera_check_event_status(&event);
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_reqbufs(struct file *filep, void *fh,
+	struct v4l2_requestbuffers *req)
+{
+	int ret;
+	struct msm_session *session;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&sp->lock);
+	ret = vb2_reqbufs(&sp->vb2_q, req);
+	mutex_unlock(&sp->lock);
+	return ret;
+}
+
+static int camera_v4l2_querybuf(struct file *filep, void *fh,
+	struct v4l2_buffer *pb)
+{
+	return 0;
+}
+
+static int camera_v4l2_qbuf(struct file *filep, void *fh,
+	struct v4l2_buffer *pb)
+{
+	int ret;
+	struct msm_session *session;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+		struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&sp->lock);
+	ret = vb2_qbuf(&sp->vb2_q, pb);
+	mutex_unlock(&sp->lock);
+	return ret;
+}
+
+static int camera_v4l2_dqbuf(struct file *filep, void *fh,
+	struct v4l2_buffer *pb)
+{
+	int ret;
+	struct msm_session *session;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+		struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned int session_id = pvdev->vdev->num;
+
+	session = msm_session_find(session_id);
+	if (WARN_ON(!session))
+		return -EIO;
+	mutex_lock(&sp->lock);
+	ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK);
+	mutex_unlock(&sp->lock);
+	return ret;
+}
+
+static int camera_v4l2_streamon(struct file *filep, void *fh,
+	enum v4l2_buf_type buf_type)
+{
+	struct v4l2_event event;
+	int rc;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+
+	mutex_lock(&sp->lock);
+	rc = vb2_streamon(&sp->vb2_q, buf_type);
+	mutex_unlock(&sp->lock);
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+		MSM_CAMERA_PRIV_STREAM_ON, -1, &event);
+
+	rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+	if (rc < 0)
+		return rc;
+
+	rc = camera_check_event_status(&event);
+	return rc;
+}
+
+static int camera_v4l2_streamoff(struct file *filep, void *fh,
+		enum v4l2_buf_type buf_type)
+{
+	struct v4l2_event event;
+	int rc = 0;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+
+	if (msm_is_daemon_present() != false) {
+		camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+			MSM_CAMERA_PRIV_STREAM_OFF, -1, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+		rc = camera_check_event_status(&event);
+	}
+	mutex_lock(&sp->lock);
+	vb2_streamoff(&sp->vb2_q, buf_type);
+	mutex_unlock(&sp->lock);
+	return rc;
+}
+
+static int camera_v4l2_g_fmt_vid_cap_mplane(struct file *filep, void *fh,
+	struct v4l2_format *pfmt)
+{
+	int rc = -EINVAL;
+
+	if (msm_is_daemon_present() == false)
+		return 0;
+
+	if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		struct v4l2_event event;
+
+		camera_pack_event(filep, MSM_CAMERA_GET_PARM,
+			MSM_CAMERA_PRIV_G_FMT, -1, &event);
+
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			return rc;
+
+		rc = camera_check_event_status(&event);
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh,
+	struct v4l2_format *pfmt)
+{
+	int rc = 0;
+	int i = 0;
+	struct v4l2_event event;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+	struct msm_v4l2_format_data *user_fmt;
+
+	if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+
+		if (WARN_ON(!sp->vb2_q.drv_priv))
+			return -ENOMEM;
+
+		memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data,
+			sizeof(struct msm_v4l2_format_data));
+		user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv;
+
+		pr_debug("%s: num planes :%c\n", __func__,
+					user_fmt->num_planes);
+		/* num_planes need to bound checked, otherwise for loop
+		 * can execute forever
+		 */
+		if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES))
+			return -EINVAL;
+		for (i = 0; i < user_fmt->num_planes; i++)
+			pr_debug("%s: plane size[%d]\n", __func__,
+					user_fmt->plane_sizes[i]);
+
+		if (msm_is_daemon_present() != false) {
+			camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+				MSM_CAMERA_PRIV_S_FMT, -1, &event);
+
+			rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+			if (rc < 0)
+				return rc;
+
+			rc = camera_check_event_status(&event);
+			if (rc < 0)
+				return rc;
+		}
+		sp->is_vb2_valid = 1;
+	}
+
+	return rc;
+}
+
+static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh,
+	struct v4l2_format *pfmt)
+{
+	return 0;
+}
+
+
+static int camera_v4l2_g_parm(struct file *filep, void *fh,
+	struct v4l2_streamparm *a)
+{
+	/* TODO */
+	return 0;
+}
+
+static int camera_v4l2_s_parm(struct file *filep, void *fh,
+	struct v4l2_streamparm *parm)
+{
+	int rc = 0;
+	struct v4l2_event event;
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event.u.data[0];
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+
+	camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+		MSM_CAMERA_PRIV_NEW_STREAM, -1, &event);
+
+	rc = msm_create_stream(event_data->session_id,
+		event_data->stream_id, &sp->vb2_q);
+	if (rc < 0)
+		return rc;
+
+	if (msm_is_daemon_present() != false) {
+		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		if (rc < 0)
+			goto error;
+
+		rc = camera_check_event_status(&event);
+		if (rc < 0)
+			goto error;
+	}
+	/* use stream_id as stream index */
+	parm->parm.capture.extendedmode = sp->stream_id;
+	sp->stream_created = true;
+
+	return rc;
+
+error:
+	msm_delete_stream(event_data->session_id,
+		event_data->stream_id);
+	return rc;
+}
+
+static int camera_v4l2_subscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+
+	mutex_lock(&sp->lock);
+	rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL);
+	mutex_unlock(&sp->lock);
+
+	return rc;
+}
+
+static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+
+	mutex_lock(&sp->lock);
+	rc = v4l2_event_unsubscribe(&sp->fh, sub);
+	mutex_unlock(&sp->lock);
+
+	return rc;
+}
+
+static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh,
+	bool valid_prio, unsigned int cmd, void *arg)
+{
+	struct camera_v4l2_private *sp = fh_to_private(fh);
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct msm_camera_private_ioctl_arg *k_ioctl = arg;
+	long rc = -EINVAL;
+
+	if (WARN_ON(!k_ioctl || !pvdev))
+		return -EIO;
+
+	if (cmd != VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD)
+		return -EINVAL;
+
+	switch (k_ioctl->id) {
+	case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
+		struct msm_camera_return_buf ptr;
+		struct msm_camera_return_buf __user *tmp = NULL;
+
+		MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
+			sizeof(tmp));
+		if (copy_from_user(&ptr, tmp,
+			sizeof(struct msm_camera_return_buf))) {
+			return -EFAULT;
+		}
+		rc = msm_vb2_return_buf_by_idx(pvdev->vdev->num, sp->stream_id,
+			ptr.index);
+		}
+		break;
+	default:
+		pr_debug("unimplemented id %d", k_ioctl->id);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = {
+	.vidioc_querycap = camera_v4l2_querycap,
+	.vidioc_s_crop = camera_v4l2_s_crop,
+	.vidioc_g_crop = camera_v4l2_g_crop,
+	.vidioc_queryctrl = camera_v4l2_queryctrl,
+	.vidioc_g_ctrl = camera_v4l2_g_ctrl,
+	.vidioc_s_ctrl = camera_v4l2_s_ctrl,
+	.vidioc_reqbufs = camera_v4l2_reqbufs,
+	.vidioc_querybuf = camera_v4l2_querybuf,
+	.vidioc_qbuf = camera_v4l2_qbuf,
+	.vidioc_dqbuf = camera_v4l2_dqbuf,
+	.vidioc_streamon =  camera_v4l2_streamon,
+	.vidioc_streamoff = camera_v4l2_streamoff,
+	.vidioc_g_fmt_vid_cap_mplane = camera_v4l2_g_fmt_vid_cap_mplane,
+	.vidioc_s_fmt_vid_cap_mplane = camera_v4l2_s_fmt_vid_cap_mplane,
+	.vidioc_try_fmt_vid_cap_mplane = camera_v4l2_try_fmt_vid_cap_mplane,
+
+	/* Stream type-dependent parameter ioctls */
+	.vidioc_g_parm = camera_v4l2_g_parm,
+	.vidioc_s_parm = camera_v4l2_s_parm,
+
+	/* event subscribe/unsubscribe */
+	.vidioc_subscribe_event = camera_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event,
+	.vidioc_default = camera_v4l2_vidioc_private_ioctl,
+};
+
+static int camera_v4l2_fh_open(struct file *filep)
+{
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct camera_v4l2_private *sp;
+	unsigned long stream_id;
+
+	sp = kzalloc(sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	filep->private_data = &sp->fh;
+
+	/* stream_id = open id */
+	stream_id = atomic_read(&pvdev->opened);
+	sp->stream_id = find_first_zero_bit(
+		(const unsigned long *)&stream_id, MSM_CAMERA_STREAM_CNT_BITS);
+	pr_debug("%s: Found stream_id=%d\n", __func__, sp->stream_id);
+
+	mutex_init(&sp->lock);
+
+	v4l2_fh_init(&sp->fh, pvdev->vdev);
+	v4l2_fh_add(&sp->fh);
+
+	return 0;
+}
+
+static int camera_v4l2_fh_release(struct file *filep)
+{
+	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
+
+	if (sp) {
+		v4l2_fh_del(&sp->fh);
+		v4l2_fh_exit(&sp->fh);
+		mutex_destroy(&sp->lock);
+		kzfree(sp);
+	}
+
+	return 0;
+}
+
+static int camera_v4l2_vb2_q_init(struct file *filep)
+{
+	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
+	struct vb2_queue *q = &sp->vb2_q;
+
+	memset(q, 0, sizeof(struct vb2_queue));
+
+	/* free up this buffer when stream is done */
+	q->drv_priv =
+		kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL);
+	if (!q->drv_priv) {
+		pr_err("%s : memory not available\n", __func__);
+		return -ENOMEM;
+	}
+
+	q->mem_ops = msm_vb2_get_q_mem_ops();
+	q->ops = msm_vb2_get_q_ops();
+
+	/* default queue type */
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_USERPTR;
+	q->buf_struct_size = sizeof(struct msm_vb2_buffer);
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	return vb2_queue_init(q);
+}
+
+static void camera_v4l2_vb2_q_release(struct file *filep)
+{
+	struct camera_v4l2_private *sp = filep->private_data;
+
+	kzfree(sp->vb2_q.drv_priv);
+	mutex_lock(&sp->lock);
+	vb2_queue_release(&sp->vb2_q);
+	mutex_unlock(&sp->lock);
+}
+
+static int camera_v4l2_open(struct file *filep)
+{
+	int rc = 0;
+	struct v4l2_event event;
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	unsigned long opn_idx, idx;
+
+	if (WARN_ON(!pvdev))
+		return -EIO;
+
+	mutex_lock(&pvdev->video_drvdata_mutex);
+	rc = camera_v4l2_fh_open(filep);
+	if (rc < 0) {
+		pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
+				__func__, __LINE__, rc);
+		goto fh_open_fail;
+	}
+
+	opn_idx = atomic_read(&pvdev->opened);
+	idx = opn_idx;
+	/* every stream has a vb2 queue */
+	rc = camera_v4l2_vb2_q_init(filep);
+	if (rc < 0) {
+		pr_err("%s : vb2 queue init fails Line %d rc %d\n",
+				__func__, __LINE__, rc);
+		goto vb2_q_fail;
+	}
+
+	if (!atomic_read(&pvdev->opened)) {
+		pm_stay_awake(&pvdev->vdev->dev);
+
+		/* Disable power collapse latency */
+		msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY);
+
+		/* create a new session when first opened */
+		rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
+		if (rc < 0) {
+			pr_err("%s : session creation failed Line %d rc %d\n",
+					__func__, __LINE__, rc);
+			goto session_fail;
+		}
+
+		rc = msm_create_command_ack_q(pvdev->vdev->num,
+			find_first_zero_bit((const unsigned long *)&opn_idx,
+				MSM_CAMERA_STREAM_CNT_BITS));
+		if (rc < 0) {
+			pr_err("%s : creation of command_ack queue failed\n",
+					__func__);
+			pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc);
+			goto command_ack_q_fail;
+		}
+
+		if (msm_is_daemon_present() != false) {
+			camera_pack_event(filep, MSM_CAMERA_NEW_SESSION,
+				0, -1, &event);
+			rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+			if (rc < 0) {
+				pr_err("%s : NEW_SESSION event failed,rc %d\n",
+					__func__, rc);
+				goto post_fail;
+			}
+
+			rc = camera_check_event_status(&event);
+			if (rc < 0)
+				goto post_fail;
+		}
+		/* Enable power collapse latency */
+		msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY);
+	} else {
+		rc = msm_create_command_ack_q(pvdev->vdev->num,
+			find_first_zero_bit((const unsigned long *)&opn_idx,
+				MSM_CAMERA_STREAM_CNT_BITS));
+		if (rc < 0) {
+			pr_err("%s : creation of command_ack queue failed Line %d rc %d\n",
+					__func__, __LINE__, rc);
+			goto stream_fail;
+		}
+	}
+	idx |= (1UL <<
+		find_first_zero_bit((const unsigned long *)&opn_idx,
+		MSM_CAMERA_STREAM_CNT_BITS));
+	atomic_cmpxchg(&pvdev->opened, opn_idx, idx);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
+
+	return rc;
+
+post_fail:
+	msm_delete_command_ack_q(pvdev->vdev->num, 0);
+command_ack_q_fail:
+	msm_destroy_session(pvdev->vdev->num);
+session_fail:
+	pm_relax(&pvdev->vdev->dev);
+stream_fail:
+	camera_v4l2_vb2_q_release(filep);
+vb2_q_fail:
+	camera_v4l2_fh_release(filep);
+fh_open_fail:
+	mutex_unlock(&pvdev->video_drvdata_mutex);
+	return rc;
+}
+
+static unsigned int camera_v4l2_poll(struct file *filep,
+	struct poll_table_struct *wait)
+{
+	int rc = 0;
+	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
+
+	if (sp->is_vb2_valid == 1)
+		rc = vb2_poll(&sp->vb2_q, filep, wait);
+
+	poll_wait(filep, &sp->fh.wait, wait);
+	if (v4l2_event_pending(&sp->fh))
+		rc |= POLLPRI;
+
+	return rc;
+}
+
+static int camera_v4l2_close(struct file *filep)
+{
+	struct v4l2_event event;
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
+	unsigned int opn_idx, mask;
+	struct msm_session *session;
+
+	if (WARN_ON(!pvdev))
+		return -EIO;
+
+	session = msm_session_find(pvdev->vdev->num);
+	if (WARN_ON(!session))
+		return -EIO;
+
+	mutex_lock(&pvdev->video_drvdata_mutex);
+	mutex_lock(&session->close_lock);
+	opn_idx = atomic_read(&pvdev->opened);
+	mask = (1 << sp->stream_id);
+	opn_idx &= ~mask;
+	atomic_set(&pvdev->opened, opn_idx);
+
+	if (msm_is_daemon_present() != false && sp->stream_created == true) {
+		pr_debug("%s: close stream_id=%d\n", __func__, sp->stream_id);
+		camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+			MSM_CAMERA_PRIV_DEL_STREAM, -1, &event);
+		msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+	}
+
+	if (sp->stream_created == true)
+		sp->stream_created = false;
+
+	if (atomic_read(&pvdev->opened) == 0) {
+		if (msm_is_daemon_present() != false) {
+			camera_pack_event(filep, MSM_CAMERA_DEL_SESSION,
+				0, -1, &event);
+			msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+		}
+		msm_delete_command_ack_q(pvdev->vdev->num, 0);
+		msm_delete_stream(pvdev->vdev->num, sp->stream_id);
+		mutex_unlock(&session->close_lock);
+		/* This should take care of both normal close
+		 * and application crashes
+		 */
+		camera_v4l2_vb2_q_release(filep);
+		msm_destroy_session(pvdev->vdev->num);
+
+		pm_relax(&pvdev->vdev->dev);
+	} else {
+		msm_delete_command_ack_q(pvdev->vdev->num,
+			sp->stream_id);
+
+		camera_v4l2_vb2_q_release(filep);
+		msm_delete_stream(pvdev->vdev->num, sp->stream_id);
+		mutex_unlock(&session->close_lock);
+	}
+
+	camera_v4l2_fh_release(filep);
+	mutex_unlock(&pvdev->video_drvdata_mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long camera_handle_internal_compat_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	long rc = 0;
+	struct msm_camera_private_ioctl_arg k_ioctl;
+	void __user *tmp_compat_ioctl_ptr = NULL;
+
+	rc = msm_copy_camera_private_ioctl_args(arg,
+		&k_ioctl, &tmp_compat_ioctl_ptr);
+	if (rc < 0) {
+		pr_err("Subdev cmd %d failed\n", cmd);
+		return rc;
+	}
+	switch (k_ioctl.id) {
+	case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
+		if (k_ioctl.size != sizeof(struct msm_camera_return_buf)) {
+			pr_debug("Invalid size for id %d with size %d",
+				k_ioctl.id, k_ioctl.size);
+			return -EINVAL;
+		}
+		k_ioctl.ioctl_ptr = (__force __u64 __user)tmp_compat_ioctl_ptr;
+		if (!k_ioctl.ioctl_ptr) {
+			pr_debug("Invalid ptr for id %d", k_ioctl.id);
+			return -EINVAL;
+		}
+		rc = camera_v4l2_vidioc_private_ioctl(file, file->private_data,
+			0, cmd, (void *)&k_ioctl);
+		}
+		break;
+	default:
+		pr_debug("unimplemented id %d", k_ioctl.id);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	long ret = 0;
+
+	switch (cmd) {
+	case VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD: {
+		ret = camera_handle_internal_compat_ioctl(file, cmd, arg);
+		if (ret < 0) {
+			pr_debug("Subdev cmd %d fail\n", cmd);
+			return ret;
+		}
+		}
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+
+	}
+	return ret;
+}
+#endif
+static struct v4l2_file_operations camera_v4l2_fops = {
+	.owner   = THIS_MODULE,
+	.open	= camera_v4l2_open,
+	.poll	= camera_v4l2_poll,
+	.release = camera_v4l2_close,
+	.unlocked_ioctl   = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = camera_v4l2_compat_ioctl,
+#endif
+};
+
+int camera_init_v4l2(struct device *dev, unsigned int *session)
+{
+	struct msm_video_device *pvdev;
+	struct v4l2_device *v4l2_dev;
+	int rc = 0;
+
+	pvdev = kzalloc(sizeof(struct msm_video_device),
+		GFP_KERNEL);
+	if (WARN_ON(!pvdev)) {
+		rc = -ENOMEM;
+		goto init_end;
+	}
+
+	pvdev->vdev = video_device_alloc();
+	if (WARN_ON(!pvdev->vdev)) {
+		rc = -ENOMEM;
+		goto video_fail;
+	}
+
+	v4l2_dev = kzalloc(sizeof(struct v4l2_device), GFP_KERNEL);
+	if (WARN_ON(!v4l2_dev)) {
+		rc = -ENOMEM;
+		goto v4l2_fail;
+	}
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	v4l2_dev->mdev = kzalloc(sizeof(struct media_device),
+							 GFP_KERNEL);
+	if (!v4l2_dev->mdev) {
+		rc = -ENOMEM;
+		goto mdev_fail;
+	}
+	media_device_init(v4l2_dev->mdev);
+	strlcpy(v4l2_dev->mdev->model, MSM_CAMERA_NAME,
+			sizeof(v4l2_dev->mdev->model));
+
+	v4l2_dev->mdev->dev = dev;
+
+	rc = media_device_register(v4l2_dev->mdev);
+	if (WARN_ON(rc < 0))
+		goto media_fail;
+
+	rc = media_entity_pads_init(&pvdev->vdev->entity, 0, NULL);
+	if (WARN_ON(rc < 0))
+		goto entity_fail;
+	pvdev->vdev->entity.function = QCAMERA_VNODE_GROUP_ID;
+#endif
+
+	v4l2_dev->notify = NULL;
+	pvdev->vdev->v4l2_dev = v4l2_dev;
+
+	rc = v4l2_device_register(dev, pvdev->vdev->v4l2_dev);
+	if (WARN_ON(rc < 0))
+		goto register_fail;
+
+	strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name));
+	pvdev->vdev->release  = video_device_release;
+	pvdev->vdev->fops     = &camera_v4l2_fops;
+	pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops;
+	pvdev->vdev->minor     = -1;
+	pvdev->vdev->vfl_type  = VFL_TYPE_GRABBER;
+	rc = video_register_device(pvdev->vdev,
+		VFL_TYPE_GRABBER, -1);
+	if (WARN_ON(rc < 0))
+		goto video_register_fail;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	/* FIXME: How to get rid of this messy? */
+	pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev);
+#endif
+
+	*session = pvdev->vdev->num;
+	atomic_set(&pvdev->opened, 0);
+	mutex_init(&pvdev->video_drvdata_mutex);
+	video_set_drvdata(pvdev->vdev, pvdev);
+	device_init_wakeup(&pvdev->vdev->dev, 1);
+	goto init_end;
+
+video_register_fail:
+	v4l2_device_unregister(pvdev->vdev->v4l2_dev);
+register_fail:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&pvdev->vdev->entity);
+entity_fail:
+	media_device_unregister(v4l2_dev->mdev);
+media_fail:
+	kzfree(v4l2_dev->mdev);
+mdev_fail:
+#endif
+	kzfree(v4l2_dev);
+v4l2_fail:
+	video_device_release(pvdev->vdev);
+video_fail:
+	kzfree(pvdev);
+init_end:
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.h b/drivers/media/platform/msm/camera_v2/camera/camera.h
new file mode 100644
index 0000000..06a9c82
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAMERA_H
+#define _CAMERA_H
+
+enum stream_state {
+	START_STREAM = 0,
+	STOP_STREAM,
+};
+
+int camera_init_v4l2(struct device *dev, unsigned int *session);
+
+#endif /*_CAMERA_H */
diff --git a/drivers/media/platform/msm/camera_v2/common/Makefile b/drivers/media/platform/msm/camera_v2/common/Makefile
new file mode 100644
index 0000000..74fe58f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/
+ccflags-y += -Idrivers/misc/
+obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o cam_smmu_api.o cam_hw_ops.o cam_soc_api.o msm_camera_tz_util.o
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.c b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.c
new file mode 100644
index 0000000..a3b41d0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-AHB %s:%d " fmt, __func__, __LINE__
+#define TRUE   1
+#include <linux/module.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include "cam_hw_ops.h"
+
+#ifdef CONFIG_CAM_AHB_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+struct cam_ahb_client {
+	enum cam_ahb_clk_vote vote;
+};
+
+struct cam_bus_vector {
+	const char *name;
+};
+
+struct cam_ahb_client_data {
+	struct msm_bus_scale_pdata *pbus_data;
+	u32 ahb_client;
+	u32 ahb_clk_state;
+	struct msm_bus_vectors *paths;
+	struct msm_bus_paths *usecases;
+	struct cam_bus_vector *vectors;
+	u32 *votes;
+	u32 cnt;
+	u32 probe_done;
+	struct cam_ahb_client clients[CAM_AHB_CLIENT_MAX];
+	struct mutex lock;
+};
+
+static struct cam_ahb_client_data data;
+
+static int get_vector_index(char *name)
+{
+	int i = 0, rc = -1;
+
+	for (i = 0; i < data.cnt; i++) {
+		if (strcmp(name, data.vectors[i].name) == 0)
+			return i;
+	}
+
+	return rc;
+}
+
+int cam_ahb_clk_init(struct platform_device *pdev)
+{
+	int i = 0, cnt = 0, rc = 0, index = 0;
+	struct device_node *of_node;
+
+	if (!pdev) {
+		pr_err("invalid pdev argument\n");
+		return -EINVAL;
+	}
+
+	of_node = pdev->dev.of_node;
+	data.cnt = of_property_count_strings(of_node, "bus-vectors");
+	if (data.cnt == 0) {
+		pr_err("no vectors strings found in device tree, count=%d",
+			data.cnt);
+		return 0;
+	}
+
+	cnt = of_property_count_u32_elems(of_node, "qcom,bus-votes");
+	if (cnt == 0) {
+		pr_err("no vector values found in device tree, count=%d", cnt);
+		return 0;
+	}
+
+	if (data.cnt != cnt) {
+		pr_err("vector mismatch num of strings=%u, num of values %d\n",
+			data.cnt, cnt);
+		return -EINVAL;
+	}
+
+	CDBG("number of bus vectors: %d\n", data.cnt);
+
+	data.vectors = devm_kzalloc(&pdev->dev,
+		sizeof(struct cam_bus_vector) * cnt,
+		GFP_KERNEL);
+	if (!data.vectors)
+		return -ENOMEM;
+
+	for (i = 0; i < data.cnt; i++) {
+		rc = of_property_read_string_index(of_node, "bus-vectors",
+				i, &(data.vectors[i].name));
+		CDBG("dbg: names[%d] = %s\n", i, data.vectors[i].name);
+		if (rc < 0) {
+			pr_err("failed\n");
+			rc = -EINVAL;
+			goto err1;
+		}
+	}
+
+	data.paths = devm_kzalloc(&pdev->dev,
+		sizeof(struct msm_bus_vectors) * cnt,
+		GFP_KERNEL);
+	if (!data.paths) {
+		rc = -ENOMEM;
+		goto err1;
+	}
+
+	data.usecases = devm_kzalloc(&pdev->dev,
+		sizeof(struct msm_bus_paths) * cnt,
+		GFP_KERNEL);
+	if (!data.usecases) {
+		rc = -ENOMEM;
+		goto err2;
+	}
+
+	data.pbus_data = devm_kzalloc(&pdev->dev,
+		sizeof(struct msm_bus_scale_pdata),
+		GFP_KERNEL);
+	if (!data.pbus_data) {
+		rc = -ENOMEM;
+		goto err3;
+	}
+
+	data.votes = devm_kzalloc(&pdev->dev, sizeof(u32) * cnt,
+		GFP_KERNEL);
+	if (!data.votes) {
+		rc = -ENOMEM;
+		goto err4;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,bus-votes",
+		data.votes, cnt);
+
+	for (i = 0; i < data.cnt; i++) {
+		data.paths[i] = (struct msm_bus_vectors) {
+			MSM_BUS_MASTER_AMPSS_M0,
+			MSM_BUS_SLAVE_CAMERA_CFG,
+			0,
+			data.votes[i]
+		};
+		data.usecases[i] = (struct msm_bus_paths) {
+			.num_paths = 1,
+			.vectors   = &data.paths[i],
+		};
+		CDBG("dbg: votes[%d] = %u\n", i, data.votes[i]);
+	}
+
+	*data.pbus_data = (struct msm_bus_scale_pdata) {
+		.name = "msm_camera_ahb",
+		.num_usecases = data.cnt,
+		.usecase = data.usecases,
+	};
+
+	data.ahb_client =
+		msm_bus_scale_register_client(data.pbus_data);
+	if (!data.ahb_client) {
+		pr_err("ahb vote registering failed\n");
+		rc = -EINVAL;
+		goto err5;
+	}
+
+	index = get_vector_index("suspend");
+	if (index < 0) {
+		pr_err("svs vector not supported\n");
+		rc = -EINVAL;
+		goto err6;
+	}
+
+	/* request for svs in init */
+	msm_bus_scale_client_update_request(data.ahb_client,
+		index);
+	data.ahb_clk_state = CAM_AHB_SUSPEND_VOTE;
+	data.probe_done = TRUE;
+	mutex_init(&data.lock);
+
+	CDBG("dbg, done registering ahb votes\n");
+	CDBG("dbg, clk state :%u, probe :%d\n",
+		data.ahb_clk_state, data.probe_done);
+	return rc;
+
+err6:
+	msm_bus_scale_unregister_client(data.ahb_client);
+err5:
+	devm_kfree(&pdev->dev, data.votes);
+	data.votes = NULL;
+err4:
+	devm_kfree(&pdev->dev, data.pbus_data);
+	data.pbus_data = NULL;
+err3:
+	devm_kfree(&pdev->dev, data.usecases);
+	data.usecases = NULL;
+err2:
+	devm_kfree(&pdev->dev, data.paths);
+	data.paths = NULL;
+err1:
+	devm_kfree(&pdev->dev, data.vectors);
+	data.vectors = NULL;
+	return rc;
+}
+EXPORT_SYMBOL(cam_ahb_clk_init);
+
+static int cam_consolidate_ahb_vote(enum cam_ahb_clk_client id,
+	enum cam_ahb_clk_vote vote)
+{
+	int i = 0;
+	u32 max = 0;
+
+	CDBG("dbg: id :%u, vote : 0x%x\n", id, vote);
+	mutex_lock(&data.lock);
+	data.clients[id].vote = vote;
+
+	if (vote == data.ahb_clk_state) {
+		CDBG("dbg: already at desired vote\n");
+		mutex_unlock(&data.lock);
+		return 0;
+	}
+
+	for (i = 0; i < CAM_AHB_CLIENT_MAX; i++) {
+		if (data.clients[i].vote > max)
+			max = data.clients[i].vote;
+	}
+
+	CDBG("dbg: max vote : %u\n", max);
+	if (max != data.ahb_clk_state) {
+		msm_bus_scale_client_update_request(data.ahb_client,
+			max);
+		data.ahb_clk_state = max;
+		CDBG("dbg: state : %u, vector : %d\n",
+			data.ahb_clk_state, max);
+	}
+	mutex_unlock(&data.lock);
+	return 0;
+}
+
+static int cam_ahb_get_voltage_level(unsigned int corner)
+{
+	switch (corner) {
+	case RPM_REGULATOR_CORNER_NONE:
+		return CAM_AHB_SUSPEND_VOTE;
+
+	case RPM_REGULATOR_CORNER_SVS_KRAIT:
+	case RPM_REGULATOR_CORNER_SVS_SOC:
+		return CAM_AHB_SVS_VOTE;
+
+	case RPM_REGULATOR_CORNER_NORMAL:
+		return CAM_AHB_NOMINAL_VOTE;
+
+	case RPM_REGULATOR_CORNER_SUPER_TURBO:
+		return CAM_AHB_TURBO_VOTE;
+
+	case RPM_REGULATOR_CORNER_TURBO:
+	case RPM_REGULATOR_CORNER_RETENTION:
+	default:
+		return -EINVAL;
+	}
+}
+
+int cam_config_ahb_clk(struct device *dev, unsigned long freq,
+	enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote)
+{
+	struct dev_pm_opp *opp;
+	unsigned int corner;
+	enum cam_ahb_clk_vote dyn_vote = vote;
+	int rc = -EINVAL;
+
+	if (id >= CAM_AHB_CLIENT_MAX) {
+		pr_err("err: invalid argument\n");
+		return -EINVAL;
+	}
+
+	if (data.probe_done != TRUE) {
+		pr_err("ahb init is not done yet\n");
+		return -EINVAL;
+	}
+
+	CDBG("dbg: id :%u, vote : 0x%x\n", id, vote);
+	switch (dyn_vote) {
+	case CAM_AHB_SUSPEND_VOTE:
+	case CAM_AHB_SVS_VOTE:
+	case CAM_AHB_NOMINAL_VOTE:
+	case CAM_AHB_TURBO_VOTE:
+		break;
+	case CAM_AHB_DYNAMIC_VOTE:
+		if (!dev) {
+			pr_err("device is NULL\n");
+			return -EINVAL;
+		}
+		opp = dev_pm_opp_find_freq_exact(dev, freq, true);
+		if (IS_ERR(opp)) {
+			pr_err("Error on OPP freq :%ld\n", freq);
+			return -EINVAL;
+		}
+		corner = dev_pm_opp_get_voltage(opp);
+		if (corner == 0) {
+			pr_err("Bad voltage corner for OPP freq :%ld\n", freq);
+			return -EINVAL;
+		}
+		dyn_vote = cam_ahb_get_voltage_level(corner);
+		if (dyn_vote < 0) {
+			pr_err("Bad vote requested\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		pr_err("err: invalid vote argument\n");
+		return -EINVAL;
+	}
+
+	rc = cam_consolidate_ahb_vote(id, dyn_vote);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		goto end;
+	}
+
+end:
+	return rc;
+}
+EXPORT_SYMBOL(cam_config_ahb_clk);
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h
new file mode 100644
index 0000000..bb87ad1
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_hw_ops.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_HW_OPS_H_
+#define _CAM_HW_OPS_H_
+
+enum cam_ahb_clk_vote {
+	/* need to update the voting requests
+	 * according to dtsi entries.
+	 */
+	CAM_AHB_SUSPEND_VOTE = 0x0,
+	CAM_AHB_SVS_VOTE = 0x01,
+	CAM_AHB_NOMINAL_VOTE = 0x02,
+	CAM_AHB_TURBO_VOTE = 0x03,
+	CAM_AHB_DYNAMIC_VOTE = 0xFF,
+};
+
+enum cam_ahb_clk_client {
+	CAM_AHB_CLIENT_CSIPHY,
+	CAM_AHB_CLIENT_CSID,
+	CAM_AHB_CLIENT_CCI,
+	CAM_AHB_CLIENT_ISPIF,
+	CAM_AHB_CLIENT_VFE0,
+	CAM_AHB_CLIENT_VFE1,
+	CAM_AHB_CLIENT_CPP,
+	CAM_AHB_CLIENT_FD,
+	CAM_AHB_CLIENT_JPEG,
+	CAM_AHB_CLIENT_MAX
+};
+
+int cam_config_ahb_clk(struct device *dev, unsigned long freq,
+	enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote);
+int cam_ahb_clk_init(struct platform_device *pdev);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
new file mode 100644
index 0000000..08c8575
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -0,0 +1,2328 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) "CAM-SMMU %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/workqueue.h>
+#include <linux/sizes.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/secure_buffer.h>
+#include <msm_camera_tz_util.h>
+#include "cam_smmu_api.h"
+
+#define SCRATCH_ALLOC_START SZ_128K
+#define SCRATCH_ALLOC_END   SZ_256M
+#define VA_SPACE_END	    SZ_2G
+#define IOMMU_INVALID_DIR -1
+#define BYTE_SIZE 8
+#define COOKIE_NUM_BYTE 2
+#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE)
+#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
+#define HANDLE_INIT (-1)
+#define CAM_SMMU_CB_MAX 2
+#define CAM_SMMU_SID_MAX 4
+
+
+#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
+#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+
+#define CAMERA_DEVICE_ID 0x16
+#define SECURE_SYSCALL_ID 0x18
+
+#ifdef CONFIG_CAM_SMMU_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+struct cam_smmu_work_payload {
+	int idx;
+	struct iommu_domain *domain;
+	struct device *dev;
+	unsigned long iova;
+	int flags;
+	void *token;
+	struct list_head list;
+};
+
+enum cam_protection_type {
+	CAM_PROT_INVALID,
+	CAM_NON_SECURE,
+	CAM_SECURE,
+	CAM_PROT_MAX,
+};
+
+enum cam_iommu_type {
+	CAM_SMMU_INVALID,
+	CAM_QSMMU,
+	CAM_ARM_SMMU,
+	CAM_SMMU_MAX,
+};
+
+enum cam_smmu_buf_state {
+	CAM_SMMU_BUFF_EXIST,
+	CAM_SMMU_BUFF_NOT_EXIST
+};
+
+enum cam_smmu_init_dir {
+	CAM_SMMU_TABLE_INIT,
+	CAM_SMMU_TABLE_DEINIT,
+};
+
+struct scratch_mapping {
+	void *bitmap;
+	size_t bits;
+	unsigned int order;
+	dma_addr_t base;
+};
+
+struct cam_context_bank_info {
+	struct device *dev;
+	struct dma_iommu_mapping *mapping;
+	enum iommu_attr attr;
+	dma_addr_t va_start;
+	size_t va_len;
+	const char *name;
+	bool is_secure;
+	uint8_t scratch_buf_support;
+	struct scratch_mapping scratch_map;
+	struct list_head smmu_buf_list;
+	struct mutex lock;
+	int handle;
+	enum cam_smmu_ops_param state;
+	client_handler handler[CAM_SMMU_CB_MAX];
+	client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX];
+	void *token[CAM_SMMU_CB_MAX];
+	int cb_count;
+	int ref_cnt;
+	int sids[CAM_SMMU_SID_MAX];
+};
+
+struct cam_iommu_cb_set {
+	struct cam_context_bank_info *cb_info;
+	u32 cb_num;
+	u32 cb_init_count;
+	struct work_struct smmu_work;
+	struct mutex payload_list_lock;
+	struct list_head payload_list;
+};
+
+static const struct of_device_id msm_cam_smmu_dt_match[] = {
+	{ .compatible = "qcom,msm-cam-smmu", },
+	{ .compatible = "qcom,msm-cam-smmu-cb", },
+	{}
+};
+
+struct cam_dma_buff_info {
+	struct dma_buf *buf;
+	struct dma_buf_attachment *attach;
+	struct sg_table *table;
+	enum dma_data_direction dir;
+	int iommu_dir;
+	int ref_count;
+	dma_addr_t paddr;
+	struct list_head list;
+	int ion_fd;
+	size_t len;
+	size_t phys_len;
+};
+
+struct cam_sec_buff_info {
+	struct ion_handle *i_hdl;
+	struct ion_client *i_client;
+	enum dma_data_direction dir;
+	int ref_count;
+	dma_addr_t paddr;
+	struct list_head list;
+	int ion_fd;
+	size_t len;
+};
+
+static struct cam_iommu_cb_set iommu_cb_set;
+
+static enum dma_data_direction cam_smmu_translate_dir(
+	enum cam_smmu_map_dir dir);
+
+static int cam_smmu_check_handle_unique(int hdl);
+
+static int cam_smmu_create_iommu_handle(int idx);
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+	int *hdl);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+	int ion_fd);
+
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+	int ion_fd);
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+					dma_addr_t base, size_t size,
+					int order);
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+					size_t size,
+					dma_addr_t *iova);
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+					dma_addr_t addr, size_t size);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+		dma_addr_t virt_addr);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+	enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+	size_t *len_ptr);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+					      size_t virt_len,
+					      size_t phys_len,
+					      unsigned int iommu_dir,
+					      dma_addr_t *virt_addr);
+static int cam_smmu_unmap_buf_and_remove_from_list(
+	struct cam_dma_buff_info *mapping_info, int idx);
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+					struct cam_dma_buff_info *mapping_info,
+					int idx);
+
+static void cam_smmu_clean_buffer_list(int idx);
+
+static void cam_smmu_print_list(int idx);
+
+static void cam_smmu_print_table(void);
+
+static int cam_smmu_probe(struct platform_device *pdev);
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr);
+
+static void cam_smmu_page_fault_work(struct work_struct *work)
+{
+	int j;
+	int idx;
+	struct cam_smmu_work_payload *payload;
+
+	mutex_lock(&iommu_cb_set.payload_list_lock);
+	payload = list_first_entry(&iommu_cb_set.payload_list,
+			struct cam_smmu_work_payload,
+			list);
+	list_del(&payload->list);
+	mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+	/* Dereference the payload to call the handler */
+	idx = payload->idx;
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova);
+	for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+		if ((iommu_cb_set.cb_info[idx].handler[j])) {
+			iommu_cb_set.cb_info[idx].handler[j](
+				payload->domain,
+				payload->dev,
+				payload->iova,
+				payload->flags,
+				iommu_cb_set.cb_info[idx].token[j]);
+		}
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	kfree(payload);
+}
+
+static void cam_smmu_print_list(int idx)
+{
+	struct cam_dma_buff_info *mapping;
+
+	pr_err("index = %d ", idx);
+	list_for_each_entry(mapping,
+		&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		pr_err("ion_fd = %d, paddr= 0x%pK, len = %u\n",
+			 mapping->ion_fd, (void *)mapping->paddr,
+			 (unsigned int)mapping->len);
+	}
+}
+
+static void cam_smmu_print_table(void)
+{
+	int i;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		pr_err("i= %d, handle= %d, name_addr=%pK\n", i,
+			   (int)iommu_cb_set.cb_info[i].handle,
+			   (void *)iommu_cb_set.cb_info[i].name);
+		pr_err("dev = %pK ", iommu_cb_set.cb_info[i].dev);
+	}
+}
+
+
+static int cam_smmu_query_vaddr_in_range(int handle,
+	unsigned long fault_addr, unsigned long *start_addr,
+	unsigned long *end_addr, int *fd)
+{
+	int idx, rc = -EINVAL;
+	struct cam_dma_buff_info *mapping;
+	unsigned long sa, ea;
+
+	if (!start_addr || !end_addr || !fd) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+				iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(mapping,
+		&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		sa = (unsigned long)mapping->paddr;
+		ea = (unsigned long)mapping->paddr + mapping->len;
+
+		if (sa <= fault_addr && fault_addr < ea) {
+			*start_addr = sa;
+			*end_addr = ea;
+			*fd = mapping->ion_fd;
+			rc = 0;
+			break;
+		}
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_query_vaddr_in_range);
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
+{
+	struct cam_dma_buff_info *mapping;
+	unsigned long start_addr, end_addr, current_addr;
+
+	current_addr = (unsigned long)vaddr;
+	list_for_each_entry(mapping,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		start_addr = (unsigned long)mapping->paddr;
+		end_addr = (unsigned long)mapping->paddr + mapping->len;
+
+		if (start_addr <= current_addr && current_addr < end_addr) {
+			pr_err("Error: va %pK is valid: range:%pK-%pK, fd = %d cb: %s\n",
+				vaddr, (void *)start_addr, (void *)end_addr,
+				mapping->ion_fd,
+				iommu_cb_set.cb_info[idx].name);
+			return;
+		}
+			CDBG("va %pK is not in this range: %pK-%pK, fd = %d\n",
+			vaddr, (void *)start_addr, (void *)end_addr,
+				mapping->ion_fd);
+	}
+	if (!strcmp(iommu_cb_set.cb_info[idx].name, "vfe"))
+		pr_err_ratelimited("Cannot find vaddr:%pK in SMMU.\n"
+			" %s uses invalid virtual address\n",
+			vaddr, iommu_cb_set.cb_info[idx].name);
+	else
+		pr_err("Cannot find vaddr:%pK in SMMU.\n"
+			" %s uses invalid virtual address\n",
+			vaddr, iommu_cb_set.cb_info[idx].name);
+}
+
+void cam_smmu_reg_client_page_fault_handler(int handle,
+		client_handler page_fault_handler,
+		client_reset_handler hw_reset_handler,
+		void *token)
+{
+	int idx, i = 0;
+
+	if (!token) {
+		pr_err("Error: token is NULL\n");
+		return;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return;
+	}
+
+	if (page_fault_handler) {
+		if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
+			pr_err("%s Should not regiester more handlers\n",
+				iommu_cb_set.cb_info[idx].name);
+			mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+			return;
+		}
+		iommu_cb_set.cb_info[idx].cb_count++;
+		for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) {
+			if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
+				iommu_cb_set.cb_info[idx].token[i] = token;
+				iommu_cb_set.cb_info[idx].handler[i] =
+					page_fault_handler;
+				iommu_cb_set.cb_info[idx].hw_reset_handler[i] =
+					hw_reset_handler;
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < CAM_SMMU_CB_MAX; i++) {
+			if (iommu_cb_set.cb_info[idx].token[i] == token) {
+				iommu_cb_set.cb_info[idx].token[i] = NULL;
+				iommu_cb_set.cb_info[idx].handler[i] =
+					NULL;
+				iommu_cb_set.cb_info[idx].cb_count--;
+				break;
+			}
+		}
+		if (i == CAM_SMMU_CB_MAX)
+			pr_err("Error: hdl %x no matching tokens: %s\n",
+				handle, iommu_cb_set.cb_info[idx].name);
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+}
+
+static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova,
+		int flags, void *token)
+{
+	char *cb_name;
+	int idx;
+	int j;
+	struct cam_smmu_work_payload *payload;
+
+	if (!token) {
+		pr_err("Error: token is NULL\n");
+		pr_err("Error: domain = %pK, device = %pK\n", domain, dev);
+		pr_err("iova = %lX, flags = %d\n", iova, flags);
+		return 0;
+	}
+
+	cb_name = (char *)token;
+	/* check whether it is in the table */
+	for (idx = 0; idx < iommu_cb_set.cb_num; idx++) {
+		if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name))
+			break;
+	}
+
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: index is not valid, index = %d, token = %s\n",
+			idx, cb_name);
+		return 0;
+	}
+
+	payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
+	if (!payload)
+		return 0;
+
+	payload->domain = domain;
+	payload->dev = dev;
+	payload->iova = iova;
+	payload->flags = flags;
+	payload->token = token;
+	payload->idx = idx;
+
+	/* trigger hw reset handler */
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+		if ((iommu_cb_set.cb_info[idx].hw_reset_handler[j])) {
+			iommu_cb_set.cb_info[idx].hw_reset_handler[j](
+			payload->domain,
+			payload->dev,
+			iommu_cb_set.cb_info[idx].token[j]);
+		}
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
+	mutex_lock(&iommu_cb_set.payload_list_lock);
+	list_add_tail(&payload->list, &iommu_cb_set.payload_list);
+	mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+	schedule_work(&iommu_cb_set.smmu_work);
+
+	return 0;
+}
+
+static int cam_smmu_translate_dir_to_iommu_dir(
+			enum cam_smmu_map_dir dir)
+{
+	switch (dir) {
+	case CAM_SMMU_MAP_READ:
+		return IOMMU_READ;
+	case CAM_SMMU_MAP_WRITE:
+		return IOMMU_WRITE;
+	case CAM_SMMU_MAP_RW:
+		return IOMMU_READ|IOMMU_WRITE;
+	case CAM_SMMU_MAP_INVALID:
+	default:
+		pr_err("Error: Direction is invalid. dir = %d\n", dir);
+		break;
+	};
+	return IOMMU_INVALID_DIR;
+}
+
+static enum dma_data_direction cam_smmu_translate_dir(
+				enum cam_smmu_map_dir dir)
+{
+	switch (dir) {
+	case CAM_SMMU_MAP_READ:
+		return DMA_FROM_DEVICE;
+	case CAM_SMMU_MAP_WRITE:
+		return DMA_TO_DEVICE;
+	case CAM_SMMU_MAP_RW:
+		return DMA_BIDIRECTIONAL;
+	case CAM_SMMU_MAP_INVALID:
+	default:
+		pr_err("Error: Direction is invalid. dir = %d\n", (int)dir);
+		break;
+	}
+	return DMA_NONE;
+}
+
+static void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
+{
+	unsigned int i;
+	int j = 0;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		iommu_cb_set.cb_info[i].handle = HANDLE_INIT;
+		INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list);
+		iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
+		iommu_cb_set.cb_info[i].dev = NULL;
+		iommu_cb_set.cb_info[i].cb_count = 0;
+		iommu_cb_set.cb_info[i].ref_cnt = 0;
+		for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+			iommu_cb_set.cb_info[i].token[j] = NULL;
+			iommu_cb_set.cb_info[i].handler[j] = NULL;
+		}
+		for (j = 0; j < CAM_SMMU_SID_MAX; j++)
+			iommu_cb_set.cb_info[i].sids[j] = -1;
+
+		if (ops == CAM_SMMU_TABLE_INIT)
+			mutex_init(&iommu_cb_set.cb_info[i].lock);
+		else
+			mutex_destroy(&iommu_cb_set.cb_info[i].lock);
+	}
+}
+
+static int cam_smmu_check_handle_unique(int hdl)
+{
+	int i;
+
+	if (hdl == HANDLE_INIT) {
+		CDBG("iommu handle is init number. Need to try again\n");
+		return 1;
+	}
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT)
+			continue;
+
+		if (iommu_cb_set.cb_info[i].handle == hdl) {
+			CDBG("iommu handle %d conflicts\n", (int)hdl);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/**
+ *  use low 2 bytes for handle cookie
+ */
+static int cam_smmu_create_iommu_handle(int idx)
+{
+	int rand, hdl = 0;
+
+	get_random_bytes(&rand, COOKIE_NUM_BYTE);
+	hdl = GET_SMMU_HDL(idx, rand);
+	CDBG("create handle value = %x\n", (int)hdl);
+	return hdl;
+}
+
+static int cam_smmu_attach_device(int idx)
+{
+	int rc;
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+	/* attach the mapping to device */
+	rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+	if (rc < 0) {
+		pr_err("Error: ARM IOMMU attach failed. ret = %d\n", rc);
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+					int *hdl)
+{
+	int i;
+	int handle;
+
+	/* create handle and add in the iommu hardware table */
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		if (!strcmp(iommu_cb_set.cb_info[i].name, name)) {
+			mutex_lock(&iommu_cb_set.cb_info[i].lock);
+			if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) {
+				pr_err("Error: %s already got handle 0x%x\n",
+						name,
+						iommu_cb_set.cb_info[i].handle);
+				*hdl = iommu_cb_set.cb_info[i].handle;
+				iommu_cb_set.cb_info[i].ref_cnt++;
+				mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+				return -EINVAL;
+			}
+
+			/* make sure handle is unique */
+			do {
+				handle = cam_smmu_create_iommu_handle(i);
+			} while (cam_smmu_check_handle_unique(handle));
+
+			/* put handle in the table */
+			iommu_cb_set.cb_info[i].handle = handle;
+			iommu_cb_set.cb_info[i].cb_count = 0;
+			iommu_cb_set.cb_info[i].ref_cnt++;
+			*hdl = handle;
+			CDBG("%s creates handle 0x%x\n", name, handle);
+			mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+			return 0;
+		}
+	}
+
+	/* if i == iommu_cb_set.cb_num */
+	pr_err("Error: Cannot find name %s or all handle exist!\n",
+			name);
+	cam_smmu_print_table();
+	return -EINVAL;
+}
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+					dma_addr_t base, size_t size,
+					int order)
+{
+	unsigned int count = size >> (PAGE_SHIFT + order);
+	unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+	int err = 0;
+
+	if (!count) {
+		err = -EINVAL;
+		pr_err("Error: wrong size passed, page count can't be zero");
+		goto bail;
+	}
+
+	scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!scratch_map->bitmap) {
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	scratch_map->base = base;
+	scratch_map->bits = BITS_PER_BYTE * bitmap_size;
+	scratch_map->order = order;
+
+bail:
+	return err;
+}
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+					size_t size,
+					dma_addr_t *iova)
+{
+	int rc = 0;
+	unsigned int order = get_order(size);
+	unsigned int align = 0;
+	unsigned int count, start;
+
+	count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+		 (1 << mapping->order) - 1) >> mapping->order;
+
+	/* Transparently, add a guard page to the total count of pages
+	 * to be allocated
+	 */
+	count++;
+
+	if (order > mapping->order)
+		align = (1 << (order - mapping->order)) - 1;
+
+	start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+					   count, align);
+
+	if (start > mapping->bits)
+		rc = -ENOMEM;
+
+	bitmap_set(mapping->bitmap, start, count);
+
+	*iova = mapping->base + (start << (mapping->order + PAGE_SHIFT));
+	return rc;
+}
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+					dma_addr_t addr, size_t size)
+{
+	unsigned int start = (addr - mapping->base) >>
+			     (mapping->order + PAGE_SHIFT);
+	unsigned int count = ((size >> PAGE_SHIFT) +
+			      (1 << mapping->order) - 1) >> mapping->order;
+
+	if (!addr) {
+		pr_err("Error: Invalid address\n");
+		return -EINVAL;
+	}
+
+	if (start + count > mapping->bits) {
+		pr_err("Error: Invalid page bits in scratch map\n");
+		return -EINVAL;
+	}
+
+	/* Transparently, add a guard page to the total count of pages
+	 * to be freed
+	 */
+	count++;
+
+	bitmap_clear(mapping->bitmap, start, count);
+
+	return 0;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+		dma_addr_t virt_addr)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->paddr == virt_addr) {
+			CDBG("Found virtual address %lx\n",
+				 (unsigned long)virt_addr);
+			return mapping;
+		}
+	}
+
+	pr_err("Error: Cannot find virtual address %lx by index %d\n",
+		(unsigned long)virt_addr, idx);
+	return NULL;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+		int ion_fd)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->ion_fd == ion_fd) {
+			CDBG(" find ion_fd %d\n", ion_fd);
+			return mapping;
+		}
+	}
+
+	pr_err("Error: Cannot find fd %d by index %d\n",
+		ion_fd, idx);
+	return NULL;
+}
+
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+	int ion_fd)
+{
+	struct cam_sec_buff_info *mapping;
+
+	list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+		list) {
+		if (mapping->ion_fd == ion_fd) {
+			CDBG("[sec_cam] find ion_fd %d\n", ion_fd);
+			return mapping;
+		}
+	}
+	pr_err("Error: Cannot find fd %d by index %d\n",
+		ion_fd, idx);
+	return NULL;
+}
+
+static void cam_smmu_clean_buffer_list(int idx)
+{
+	int ret;
+	struct cam_dma_buff_info *mapping_info, *temp;
+
+	list_for_each_entry_safe(mapping_info, temp,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		CDBG("Free mapping address %pK, i = %d, fd = %d\n",
+			 (void *)mapping_info->paddr, idx,
+			mapping_info->ion_fd);
+
+		if (mapping_info->ion_fd == 0xDEADBEEF)
+			/* Clean up scratch buffers */
+			ret = cam_smmu_free_scratch_buffer_remove_from_list(
+							mapping_info, idx);
+		else
+			/* Clean up regular mapped buffers */
+			ret = cam_smmu_unmap_buf_and_remove_from_list(
+					mapping_info,
+					idx);
+
+		if (ret < 0) {
+			pr_err("Buffer delete failed: idx = %d\n", idx);
+			pr_err("Buffer delete failed: addr = %lx, fd = %d\n",
+					(unsigned long)mapping_info->paddr,
+					mapping_info->ion_fd);
+			/*
+			 * Ignore this error and continue to delete other
+			 * buffers in the list
+			 */
+			continue;
+		}
+	}
+}
+
+static int cam_smmu_attach(int idx)
+{
+	int ret;
+
+	if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+		ret = 0;
+	} else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+		ret = cam_smmu_attach_device(idx);
+		if (ret < 0) {
+			pr_err("Error: ATTACH fail\n");
+			return -ENODEV;
+		}
+		iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH;
+		ret = 0;
+	} else {
+		pr_err("Error: Not detach/attach\n");
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int cam_smmu_send_syscall_cpp_intf(int vmid, int idx)
+{
+	int rc = 0;
+	struct scm_desc desc = {0};
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+	uint32_t sid_info;
+
+
+	sid_info = cb->sids[0]; /* CPP SID */
+
+	desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+	desc.args[0] = CAMERA_DEVICE_ID;
+	desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
+	desc.args[2] = sizeof(uint32_t);
+	desc.args[3] = vmid;
+	/*
+	 * Syscall to hypervisor to switch CPP SID's
+	 * between secure and non-secure contexts
+	 */
+	dmac_flush_range(&sid_info, &sid_info + 1);
+	if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+			&desc)){
+		pr_err("call to hypervisor failed\n");
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int cam_smmu_send_syscall_pix_intf(int vmid, int idx)
+{
+	int rc = 0;
+	struct scm_desc desc = {0};
+	uint32_t *sid_info = NULL;
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+	sid_info = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL);
+	if (!sid_info)
+		return -ENOMEM;
+
+	sid_info[0] = cb->sids[0]; /* VFE 0 Image SID */
+	sid_info[1] = cb->sids[2]; /* VFE 1 Image SID */
+
+	desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+	desc.args[0] = CAMERA_DEVICE_ID;
+	desc.args[1] = SCM_BUFFER_PHYS(sid_info);
+	desc.args[2] = sizeof(uint32_t) * 2;
+	desc.args[3] = vmid;
+	/*
+	 * Syscall to hypervisor to switch VFE SID's
+	 * between secure and non-secure contexts
+	 */
+	dmac_flush_range(sid_info, sid_info + 2);
+	if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+			&desc)){
+		pr_err("call to hypervisor failed\n");
+		kfree(sid_info);
+		return -EINVAL;
+	}
+
+	kfree(sid_info);
+	return rc;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+	if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+		pr_err("Client %s buffer list is not clean!\n",
+			iommu_cb_set.cb_info[idx].name);
+		cam_smmu_print_list(idx);
+		cam_smmu_clean_buffer_list(idx);
+	}
+
+	/* detach the mapping to device */
+	arm_iommu_detach_device(cb->dev);
+	iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+	return 0;
+}
+
+static int cam_smmu_attach_sec_cpp(int idx)
+{
+	int32_t rc = 0;
+
+	/*
+	 * When switching to secure, detach CPP NS, do scm call
+	 * with CPP SID and no need of attach again, because
+	 * all cpp sids are shared in SCM call. so no need of
+	 * attach again.
+	 */
+	if (cam_smmu_send_syscall_cpp_intf(VMID_CP_CAMERA, idx)) {
+		pr_err("error: syscall failed\n");
+		return -EINVAL;
+	}
+
+	rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_SECURE,
+		MSM_CAMERA_TZ_HW_BLOCK_CPP);
+	if (rc != 0) {
+		pr_err("secure mode TA notification for cpp unsuccessful, rc %d\n",
+			rc);
+		/*
+		 * Although the TA notification failed, the flow should proceed
+		 * without returning an error as at this point cpp had already
+		 * entered the secure mode.
+		 */
+	}
+
+	iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH;
+
+	return 0;
+}
+
+static int cam_smmu_detach_sec_cpp(int idx)
+{
+	int32_t rc = 0;
+
+	rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_NON_SECURE,
+		MSM_CAMERA_TZ_HW_BLOCK_CPP);
+	if (rc != 0) {
+		pr_err("secure mode TA notification for cpp unsuccessful, rc %d\n",
+			rc);
+		/*
+		 * Although the TA notification failed, the flow should proceed
+		 * without returning an error, as at this point cpp is in secure
+		 * mode and should be switched to non-secure regardless
+		 */
+	}
+
+	iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+
+	/*
+	 * When exiting secure, do scm call to attach
+	 * with CPP SID in NS mode.
+	 */
+	if (cam_smmu_send_syscall_cpp_intf(VMID_HLOS, idx)) {
+		pr_err("error: syscall failed\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cam_smmu_attach_sec_vfe_ns_stats(int idx)
+{
+	int32_t rc = 0;
+
+	/*
+	 *When switching to secure, for secure pix and non-secure stats
+	 *localizing scm/attach of non-secure SID's in attach secure
+	 */
+	if (cam_smmu_send_syscall_pix_intf(VMID_CP_CAMERA, idx)) {
+		pr_err("error: syscall failed\n");
+		return -EINVAL;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		if (cam_smmu_attach(idx)) {
+			pr_err("error: failed to attach\n");
+			return -EINVAL;
+		}
+	}
+
+	rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_SECURE,
+		MSM_CAMERA_TZ_HW_BLOCK_ISP);
+	if (rc != 0) {
+		pr_err("secure mode TA notification for vfe unsuccessful, rc %d\n",
+			rc);
+		/*
+		 * Although the TA notification failed, the flow should proceed
+		 * without returning an error as at this point vfe had already
+		 * entered the secure mode
+		 */
+	}
+
+	return 0;
+}
+
+static int cam_smmu_detach_sec_vfe_ns_stats(int idx)
+{
+	int32_t rc = 0;
+
+	rc = msm_camera_tz_set_mode(MSM_CAMERA_TZ_MODE_NON_SECURE,
+		MSM_CAMERA_TZ_HW_BLOCK_ISP);
+	if (rc != 0) {
+		pr_err("secure mode TA notification for vfe unsuccessful, rc %d\n",
+			rc);
+		/*
+		 * Although the TA notification failed, the flow should proceed
+		 * without returning an error, as at this point vfe is in secure
+		 * mode and should be switched to non-secure regardless
+		 */
+	}
+
+	/*
+	 *While exiting from secure mode for secure pix and non-secure stats,
+	 *localizing detach/scm of non-secure SID's to detach secure
+	 */
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_DETACH) {
+		if (cam_smmu_detach_device(idx) < 0) {
+			pr_err("Error: ARM IOMMU detach failed\n");
+			return -ENODEV;
+		}
+	}
+
+	if (cam_smmu_send_syscall_pix_intf(VMID_HLOS, idx)) {
+		pr_err("error: syscall failed\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+		 enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+		 size_t *len_ptr)
+{
+	int rc = -1;
+	struct cam_dma_buff_info *mapping_info;
+	struct dma_buf *buf = NULL;
+	struct dma_buf_attachment *attach = NULL;
+	struct sg_table *table = NULL;
+
+	if (!paddr_ptr) {
+		rc = -EINVAL;
+		goto err_out;
+	}
+
+	/* allocate memory for each buffer information */
+	buf = dma_buf_get(ion_fd);
+	if (IS_ERR_OR_NULL(buf)) {
+		rc = PTR_ERR(buf);
+		pr_err("Error: dma get buf failed. fd = %d rc = %d\n",
+		      ion_fd, rc);
+		goto err_out;
+	}
+
+	attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+	if (IS_ERR_OR_NULL(attach)) {
+		rc = PTR_ERR(attach);
+		pr_err("Error: dma buf attach failed\n");
+		goto err_put;
+	}
+
+	table = dma_buf_map_attachment(attach, dma_dir);
+	if (IS_ERR_OR_NULL(table)) {
+		rc = PTR_ERR(table);
+		pr_err("Error: dma buf map attachment failed\n");
+		goto err_detach;
+	}
+
+	rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl,
+			table->nents, dma_dir, buf);
+	if (rc != table->nents) {
+		pr_err("Error: msm_dma_map_sg_lazy failed\n");
+		rc = -ENOMEM;
+		goto err_unmap_sg;
+	}
+
+	if (table->sgl) {
+		CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\n",
+				(void *)buf,
+				(void *)iommu_cb_set.cb_info[idx].dev,
+				(void *)attach, (void *)table);
+		CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n",
+				(void *)table->sgl, rc,
+				(unsigned int)table->sgl->dma_address);
+	} else {
+		rc = -EINVAL;
+		pr_err("Error: table sgl is null\n");
+		goto err_map_addr;
+	}
+
+	/* fill up mapping_info */
+	mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+	if (!mapping_info) {
+		rc = -ENOSPC;
+		goto err_map_addr;
+	}
+	mapping_info->ion_fd = ion_fd;
+	mapping_info->buf = buf;
+	mapping_info->attach = attach;
+	mapping_info->table = table;
+	mapping_info->paddr = sg_dma_address(table->sgl);
+	mapping_info->len = (size_t)sg_dma_len(table->sgl);
+	mapping_info->dir = dma_dir;
+	mapping_info->ref_count = 1;
+
+	/* return paddr and len to client */
+	*paddr_ptr = sg_dma_address(table->sgl);
+	*len_ptr = (size_t)sg_dma_len(table->sgl);
+
+	if (!*paddr_ptr || !*len_ptr) {
+		pr_err("Error: Space Allocation failed!\n");
+		rc = -ENOSPC;
+		goto err_mapping_info;
+	}
+	CDBG("name %s ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n",
+			iommu_cb_set.cb_info[idx].name,
+			ion_fd,
+			(void *)iommu_cb_set.cb_info[idx].dev,
+			(void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+	/* add to the list */
+	list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+	return 0;
+
+err_mapping_info:
+	kzfree(mapping_info);
+err_map_addr:
+	msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+		table->sgl, table->nents,
+		dma_dir, buf);
+err_unmap_sg:
+	dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+	dma_buf_detach(buf, attach);
+err_put:
+	dma_buf_put(buf);
+err_out:
+	return rc;
+}
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+		struct cam_dma_buff_info *mapping_info,
+		int idx)
+{
+	if ((!mapping_info->buf) || (!mapping_info->table) ||
+		(!mapping_info->attach)) {
+		pr_err("Error: Invalid params dev = %pK, table = %pK",
+			(void *)iommu_cb_set.cb_info[idx].dev,
+			(void *)mapping_info->table);
+		pr_err("Error:dma_buf = %pK, attach = %pK\n",
+			(void *)mapping_info->buf,
+			(void *)mapping_info->attach);
+		return -EINVAL;
+	}
+
+	/* iommu buffer clean up */
+	msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+		mapping_info->table->sgl, mapping_info->table->nents,
+		mapping_info->dir, mapping_info->buf);
+	dma_buf_unmap_attachment(mapping_info->attach,
+		mapping_info->table, mapping_info->dir);
+	dma_buf_detach(mapping_info->buf, mapping_info->attach);
+	dma_buf_put(mapping_info->buf);
+	mapping_info->buf = NULL;
+
+	list_del_init(&mapping_info->list);
+
+	/* free one buffer */
+	kfree(mapping_info);
+	return 0;
+}
+
+static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx,
+					int ion_fd, dma_addr_t *paddr_ptr,
+					size_t *len_ptr)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->ion_fd == ion_fd) {
+			mapping->ref_count++;
+			*paddr_ptr = mapping->paddr;
+			*len_ptr = mapping->len;
+			return CAM_SMMU_BUFF_EXIST;
+		}
+	}
+	return CAM_SMMU_BUFF_NOT_EXIST;
+}
+
+static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx,
+					int ion_fd, dma_addr_t *paddr_ptr,
+					size_t *len_ptr)
+{
+	struct cam_sec_buff_info *mapping;
+
+	list_for_each_entry(mapping,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->ion_fd == ion_fd) {
+			mapping->ref_count++;
+			*paddr_ptr = mapping->paddr;
+			*len_ptr = mapping->len;
+			return CAM_SMMU_BUFF_EXIST;
+		}
+	}
+	return CAM_SMMU_BUFF_NOT_EXIST;
+}
+
+int cam_smmu_get_handle(char *identifier, int *handle_ptr)
+{
+	int ret = 0;
+
+	if (!identifier) {
+		pr_err("Error: iommu hardware name is NULL\n");
+		return -EFAULT;
+	}
+
+	if (!handle_ptr) {
+		pr_err("Error: handle pointer is NULL\n");
+		return -EFAULT;
+	}
+
+	/* create and put handle in the table */
+	ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr);
+	if (ret < 0) {
+		pr_err("Error: %s get handle fail\n", identifier);
+		return ret;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(cam_smmu_get_handle);
+
+
+int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data)
+{
+	int ret = 0, idx;
+	struct cam_context_bank_info *cb = NULL;
+	struct iommu_domain *domain = NULL;
+
+	CDBG("E: set_attr\n");
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+		domain = iommu_cb_set.cb_info[idx].mapping->domain;
+		cb = &iommu_cb_set.cb_info[idx];
+		cb->attr |= flags;
+		/* set attributes */
+		ret = iommu_domain_set_attr(domain, cb->attr, (void *)data);
+		if (ret < 0) {
+			mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+			pr_err("Error: set attr\n");
+			return -ENODEV;
+		}
+	} else {
+		ret = -EINVAL;
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return ret;
+}
+EXPORT_SYMBOL(cam_smmu_set_attr);
+
+
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
+{
+	int ret = 0, idx;
+
+	CDBG("E: ops = %d\n", ops);
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	switch (ops) {
+	case CAM_SMMU_ATTACH: {
+		ret = cam_smmu_attach(idx);
+		break;
+	}
+	case CAM_SMMU_DETACH: {
+		ret = cam_smmu_detach_device(idx);
+		break;
+	}
+	case CAM_SMMU_ATTACH_SEC_VFE_NS_STATS: {
+		ret = cam_smmu_attach_sec_vfe_ns_stats(idx);
+		break;
+	}
+	case CAM_SMMU_DETACH_SEC_VFE_NS_STATS: {
+		ret = cam_smmu_detach_sec_vfe_ns_stats(idx);
+		break;
+	}
+	case CAM_SMMU_ATTACH_SEC_CPP: {
+		ret = cam_smmu_attach_sec_cpp(idx);
+		break;
+	}
+	case CAM_SMMU_DETACH_SEC_CPP: {
+		ret = cam_smmu_detach_sec_cpp(idx);
+		break;
+	}
+	case CAM_SMMU_VOTE:
+	case CAM_SMMU_DEVOTE:
+	default:
+		pr_err("Error: idx = %d, ops = %d\n", idx, ops);
+		ret = -EINVAL;
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return ret;
+}
+EXPORT_SYMBOL(cam_smmu_ops);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+					      size_t virt_len,
+					      size_t phys_len,
+					      unsigned int iommu_dir,
+					      dma_addr_t *virt_addr)
+{
+	unsigned long nents = virt_len / phys_len;
+	struct cam_dma_buff_info *mapping_info = NULL;
+	size_t unmapped;
+	dma_addr_t iova = 0;
+	struct scatterlist *sg;
+	int i = 0;
+	int rc;
+	struct iommu_domain *domain = NULL;
+	struct page *page;
+	struct sg_table *table = NULL;
+
+	CDBG("%s: nents = %lu, idx = %d, virt_len  = %zx\n",
+		__func__, nents, idx, virt_len);
+	CDBG("%s: phys_len = %zx, iommu_dir = %d, virt_addr = %pK\n",
+		__func__, phys_len, iommu_dir, virt_addr);
+
+	/* This table will go inside the 'mapping' structure
+	 * where it will be held until put_scratch_buffer is called
+	 */
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table) {
+		rc = -ENOMEM;
+		goto err_table_alloc;
+	}
+
+	rc = sg_alloc_table(table, nents, GFP_KERNEL);
+	if (rc < 0) {
+		rc = -EINVAL;
+		goto err_sg_alloc;
+	}
+
+	page = alloc_pages(GFP_KERNEL, get_order(phys_len));
+	if (!page) {
+		rc = -ENOMEM;
+		goto err_page_alloc;
+	}
+
+	/* Now we create the sg list */
+	for_each_sg(table->sgl, sg, table->nents, i)
+		sg_set_page(sg, page, phys_len, 0);
+
+
+	/* Get the domain from within our cb_set struct and map it*/
+	domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+	rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map,
+					virt_len, &iova);
+
+	if (rc < 0) {
+		pr_err("Could not find valid iova for scratch buffer\n");
+		goto err_iommu_map;
+	}
+
+	if (iommu_map_sg(domain,
+			  iova,
+			  table->sgl,
+			  table->nents,
+			  iommu_dir) != virt_len) {
+		pr_err("iommu_map_sg() failed");
+		goto err_iommu_map;
+	}
+
+	/* Now update our mapping information within the cb_set struct */
+	mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+	if (!mapping_info) {
+		rc = -ENOMEM;
+		goto err_mapping_info;
+	}
+
+	mapping_info->ion_fd = 0xDEADBEEF;
+	mapping_info->buf = NULL;
+	mapping_info->attach = NULL;
+	mapping_info->table = table;
+	mapping_info->paddr = iova;
+	mapping_info->len = virt_len;
+	mapping_info->iommu_dir = iommu_dir;
+	mapping_info->ref_count = 1;
+	mapping_info->phys_len = phys_len;
+
+	CDBG("%s: paddr = %pK, len = %zx, phys_len = %zx",
+		__func__, (void *)mapping_info->paddr,
+		mapping_info->len, mapping_info->phys_len);
+
+	list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+	*virt_addr = (dma_addr_t)iova;
+
+	CDBG("%s: mapped virtual address = %lx\n", __func__,
+		(unsigned long)*virt_addr);
+	return 0;
+
+err_mapping_info:
+	unmapped = iommu_unmap(domain, iova,  virt_len);
+	if (unmapped != virt_len)
+		pr_err("Unmapped only %zx instead of %zx", unmapped, virt_len);
+err_iommu_map:
+	__free_pages(sg_page(table->sgl), get_order(phys_len));
+err_page_alloc:
+	sg_free_table(table);
+err_sg_alloc:
+	kfree(table);
+err_table_alloc:
+	return rc;
+}
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+					struct cam_dma_buff_info *mapping_info,
+					int idx)
+{
+	int rc = 0;
+	size_t unmapped;
+	struct iommu_domain *domain =
+		iommu_cb_set.cb_info[idx].mapping->domain;
+	struct scratch_mapping *scratch_map =
+		&iommu_cb_set.cb_info[idx].scratch_map;
+
+	if (!mapping_info->table) {
+		pr_err("Error: Invalid params: dev = %pK, table = %pK, ",
+				(void *)iommu_cb_set.cb_info[idx].dev,
+				(void *)mapping_info->table);
+		return -EINVAL;
+	}
+
+	/* Clean up the mapping_info struct from the list */
+	unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len);
+	if (unmapped != mapping_info->len)
+		pr_err("Unmapped only %zx instead of %zx",
+				unmapped, mapping_info->len);
+
+	rc = cam_smmu_free_scratch_va(scratch_map,
+				mapping_info->paddr,
+				mapping_info->len);
+	if (rc < 0) {
+		pr_err("Error: Invalid iova while freeing scratch buffer\n");
+		rc = -EINVAL;
+	}
+
+	__free_pages(sg_page(mapping_info->table->sgl),
+			get_order(mapping_info->phys_len));
+	sg_free_table(mapping_info->table);
+	kfree(mapping_info->table);
+	list_del_init(&mapping_info->list);
+
+	kfree(mapping_info);
+	mapping_info = NULL;
+
+	return rc;
+}
+
+int cam_smmu_get_phy_addr_scratch(int handle,
+				  enum cam_smmu_map_dir dir,
+				  dma_addr_t *paddr_ptr,
+				  size_t virt_len,
+				  size_t phys_len)
+{
+	int idx, rc = 0;
+	unsigned int iommu_dir;
+
+	if (!paddr_ptr || !virt_len || !phys_len) {
+		pr_err("Error: Input pointer or lengths invalid\n");
+		return -EINVAL;
+	}
+
+	if (virt_len < phys_len) {
+		pr_err("Error: virt_len > phys_len");
+		return -EINVAL;
+	}
+
+	iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir);
+	if (iommu_dir == IOMMU_INVALID_DIR) {
+		pr_err("Error: translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+		pr_err("Error: Context bank does not support scratch bufs\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+		__func__, handle, idx, dir);
+	CDBG("%s: virt_len = %zx, phys_len  = %zx\n",
+		__func__, phys_len, virt_len);
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!IS_ALIGNED(virt_len, PAGE_SIZE)) {
+		pr_err("Requested scratch buffer length not page aligned");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!IS_ALIGNED(virt_len, phys_len)) {
+		pr_err("Requested virtual length not aligned with physical length");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx,
+							virt_len,
+							phys_len,
+							iommu_dir,
+							paddr_ptr);
+	if (rc < 0) {
+		pr_err("Error: mapping or add list fail\n");
+		goto error;
+	}
+
+error:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+
+int cam_smmu_put_phy_addr_scratch(int handle,
+				  dma_addr_t paddr)
+{
+	int idx;
+	int rc = -1;
+	struct cam_dma_buff_info *mapping_info;
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto handle_err;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+		pr_err("Error: Context bank does not support scratch buffers");
+		rc = -EINVAL;
+		goto handle_err;
+	}
+
+	/* Based on virtual address and index, we can find mapping info
+	 * of the scratch buffer
+	 */
+	mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params\n");
+		rc = -EINVAL;
+		goto handle_err;
+	}
+
+	/* unmapping one buffer from device */
+	rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx);
+	if (rc < 0) {
+		pr_err("Error: unmap or remove list fail\n");
+		goto handle_err;
+	}
+handle_err:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+		enum cam_smmu_map_dir dir, struct ion_client *client,
+		struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+		size_t *len_ptr)
+{
+	int idx, rc = 0;
+	enum dma_data_direction dma_dir;
+
+	dma_dir = cam_smmu_translate_dir(dir);
+	if (dma_dir == DMA_NONE) {
+		pr_err("Error: translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		return -EINVAL;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		return -EINVAL;
+	}
+	*sc_handle = ion_alloc(client, SZ_2M, SZ_2M,
+				ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID),
+				ION_FLAG_SECURE | ION_FLAG_CP_CAMERA);
+	if (IS_ERR_OR_NULL((void *) (*sc_handle))) {
+		rc = -ENOMEM;
+		goto err_ion_handle;
+	}
+
+	/* return addr and len to client */
+	rc = ion_phys(client, *sc_handle, addr, len_ptr);
+	if (rc) {
+		pr_err("%s: ION Get Physical failed, rc = %d\n",
+					__func__, rc);
+		rc = -EINVAL;
+		goto err_ion_phys;
+	}
+
+	CDBG("dev = %pK, paddr= %pK, len = %u\n",
+		(void *)iommu_cb_set.cb_info[idx].dev,
+		(void *)*addr, (unsigned int)*len_ptr);
+	return rc;
+
+err_ion_phys:
+	ion_free(client, *sc_handle);
+
+err_ion_handle:
+	*sc_handle = NULL;
+	return rc;
+}
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+	struct ion_client *client, struct ion_handle *sc_handle)
+{
+	int idx = 0;
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+	ion_free(client, sc_handle);
+	return 0;
+}
+
+static int cam_smmu_secure_unmap_buf_and_remove_from_list(
+		struct cam_sec_buff_info *mapping_info,
+		int idx)
+{
+	if (!mapping_info) {
+		pr_err("Error: List doesn't exist\n");
+		return -EINVAL;
+	}
+	ion_free(mapping_info->i_client, mapping_info->i_hdl);
+	list_del_init(&mapping_info->list);
+
+	/* free one buffer */
+	kfree(mapping_info);
+	return 0;
+}
+
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd)
+{
+	int idx, rc;
+	struct cam_sec_buff_info *mapping_info;
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	/* based on ion fd and index, we can find mapping info of buffer */
+	mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+			idx, ion_fd);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	mapping_info->ref_count--;
+	if (mapping_info->ref_count > 0) {
+		CDBG("There are still %u buffer(s) with same fd %d",
+			mapping_info->ref_count, mapping_info->ion_fd);
+		rc = 0;
+		goto put_addr_end;
+	}
+
+	/* unmapping one buffer from device */
+	rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx);
+	if (rc < 0) {
+		pr_err("Error: unmap or remove list fail\n");
+		goto put_addr_end;
+	}
+
+put_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_stage2_phy_addr);
+
+static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd,
+		 enum dma_data_direction dma_dir, struct ion_client *client,
+		 dma_addr_t *paddr_ptr,
+		 size_t *len_ptr)
+{
+	int rc = 0;
+	struct ion_handle *i_handle = NULL;
+	struct cam_sec_buff_info *mapping_info;
+
+
+	/* clean the content from clients */
+	*paddr_ptr = (dma_addr_t)NULL;
+	*len_ptr = (size_t)0;
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		return -EINVAL;
+	}
+
+	i_handle = ion_import_dma_buf_fd(client, ion_fd);
+	if (IS_ERR_OR_NULL((void *)(i_handle))) {
+		pr_err("%s: ion import dma buffer failed\n", __func__);
+		return -EINVAL;
+	}
+
+	/* return addr and len to client */
+	rc = ion_phys(client, i_handle, paddr_ptr, len_ptr);
+	if (rc) {
+		pr_err("%s: ION Get Physical failed, rc = %d\n",
+					__func__, rc);
+		return -EINVAL;
+	}
+
+	/* fill up mapping_info */
+	mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL);
+	if (!mapping_info)
+		return -ENOSPC;
+
+	mapping_info->ion_fd = ion_fd;
+	mapping_info->paddr = *paddr_ptr;
+	mapping_info->len = *len_ptr;
+	mapping_info->dir = dma_dir;
+	mapping_info->ref_count = 1;
+	mapping_info->i_hdl = i_handle;
+	mapping_info->i_client = client;
+
+	CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+			(void *)iommu_cb_set.cb_info[idx].dev,
+			(void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+	/* add to the list */
+	list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+	return rc;
+}
+
+int cam_smmu_get_stage2_phy_addr(int handle,
+		int ion_fd, enum cam_smmu_map_dir dir,
+		struct ion_client *client, ion_phys_addr_t *paddr_ptr,
+		size_t *len_ptr)
+{
+	int idx, rc;
+	enum dma_data_direction dma_dir;
+	enum cam_smmu_buf_state buf_state;
+
+	if (!paddr_ptr || !len_ptr) {
+		pr_err("Error: Input pointers are invalid\n");
+		return -EINVAL;
+	}
+	/* clean the content from clients */
+	*paddr_ptr = (dma_addr_t)NULL;
+	*len_ptr = (size_t)0;
+
+	dma_dir = cam_smmu_translate_dir(dir);
+	if (dma_dir == DMA_NONE) {
+		pr_err("Error: translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	buf_state = cam_smmu_check_secure_fd_in_list(idx, ion_fd, paddr_ptr,
+			len_ptr);
+	if (buf_state == CAM_SMMU_BUFF_EXIST) {
+		CDBG("ion_fd:%d already in the list, give same addr back",
+				 ion_fd);
+		rc = 0;
+		goto get_addr_end;
+	}
+	rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+			client, paddr_ptr, len_ptr);
+	if (rc < 0) {
+		pr_err("Error: mapping or add list fail\n");
+		goto get_addr_end;
+	}
+
+get_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+
+
+int cam_smmu_get_phy_addr(int handle, int ion_fd,
+		enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+		size_t *len_ptr)
+{
+	int idx, rc;
+	enum dma_data_direction dma_dir;
+	enum cam_smmu_buf_state buf_state;
+
+	if (!paddr_ptr || !len_ptr) {
+		pr_err("Error: Input pointers are invalid\n");
+		return -EINVAL;
+	}
+	/* clean the content from clients */
+	*paddr_ptr = (dma_addr_t)NULL;
+	*len_ptr = (size_t)0;
+
+	dma_dir = cam_smmu_translate_dir(dir);
+	if (dma_dir == DMA_NONE) {
+		pr_err("Error: translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+	if (buf_state == CAM_SMMU_BUFF_EXIST) {
+		CDBG("ion_fd:%d already in the list, give same addr back",
+				 ion_fd);
+		rc = 0;
+		goto get_addr_end;
+	}
+	rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+			paddr_ptr, len_ptr);
+	if (rc < 0) {
+		pr_err("Error: mapping or add list fail\n");
+		goto get_addr_end;
+	}
+
+get_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_get_phy_addr);
+
+int cam_smmu_put_phy_addr(int handle, int ion_fd)
+{
+	int idx, rc;
+	struct cam_dma_buff_info *mapping_info;
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	/* based on ion fd and index, we can find mapping info of buffer */
+	mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+			idx, ion_fd);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	mapping_info->ref_count--;
+	if (mapping_info->ref_count > 0) {
+		CDBG("There are still %u buffer(s) with same fd %d",
+			mapping_info->ref_count, mapping_info->ion_fd);
+		rc = 0;
+		goto put_addr_end;
+	}
+
+	/* unmapping one buffer from device */
+	rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+	if (rc < 0) {
+		pr_err("Error: unmap or remove list fail\n");
+		goto put_addr_end;
+	}
+
+put_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_phy_addr);
+
+int cam_smmu_destroy_handle(int handle)
+{
+	int idx;
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (--iommu_cb_set.cb_info[idx].ref_cnt != 0) {
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return 0;
+	}
+
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+		pr_err("Client %s buffer list is not clean!\n",
+			iommu_cb_set.cb_info[idx].name);
+		cam_smmu_print_list(idx);
+		cam_smmu_clean_buffer_list(idx);
+	}
+
+	iommu_cb_set.cb_info[idx].cb_count = 0;
+	iommu_cb_set.cb_info[idx].handle = HANDLE_INIT;
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return 0;
+}
+EXPORT_SYMBOL(cam_smmu_destroy_handle);
+
+/*This function can only be called after smmu driver probe*/
+int cam_smmu_get_num_of_clients(void)
+{
+	return iommu_cb_set.cb_num;
+}
+
+static void cam_smmu_release_cb(struct platform_device *pdev)
+{
+	int i = 0;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		arm_iommu_detach_device(iommu_cb_set.cb_info[i].dev);
+		arm_iommu_release_mapping(iommu_cb_set.cb_info[i].mapping);
+	}
+
+	devm_kfree(&pdev->dev, iommu_cb_set.cb_info);
+	iommu_cb_set.cb_num = 0;
+}
+
+static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
+	struct device *dev)
+{
+	int rc = 0;
+
+	if (!cb || !dev) {
+		pr_err("Error: invalid input params\n");
+		return -EINVAL;
+	}
+
+	cb->dev = dev;
+	/* Reserve 256M if scratch buffer support is desired
+	 * and initialize the scratch mapping structure
+	 */
+	if (cb->scratch_buf_support) {
+		cb->va_start = SCRATCH_ALLOC_END;
+		cb->va_len = VA_SPACE_END - SCRATCH_ALLOC_END;
+
+		rc = cam_smmu_init_scratch_map(&cb->scratch_map,
+				SCRATCH_ALLOC_START,
+				SCRATCH_ALLOC_END - SCRATCH_ALLOC_START,
+				0);
+		if (rc < 0) {
+			pr_err("Error: failed to create scratch map\n");
+			rc = -ENODEV;
+			goto end;
+		}
+	} else {
+		cb->va_start = SZ_128K;
+		cb->va_len = VA_SPACE_END - SZ_128M;
+	}
+
+	/* create a virtual mapping */
+	cb->mapping = arm_iommu_create_mapping(&platform_bus_type,
+		cb->va_start, cb->va_len);
+	if (IS_ERR(cb->mapping)) {
+		pr_err("Error: create mapping Failed\n");
+		rc = -ENODEV;
+		goto end;
+	}
+
+	return 0;
+end:
+	return rc;
+}
+
+static int cam_smmu_populate_sids(struct device *dev,
+	struct cam_context_bank_info *cb)
+{
+	int i, j, rc = 0;
+	unsigned int cnt = 0;
+	const void *property;
+
+	/* set the name of the context bank */
+	property = of_get_property(dev->of_node, "iommus", &cnt);
+	cnt /= 4;
+	for (i = 0, j = 0; i < cnt; i = i + 3, j++) {
+		rc = of_property_read_u32_index(dev->of_node,
+			"iommus", i + 1, &cb->sids[j]);
+		if (rc < 0)
+			pr_err("misconfiguration, can't fetch SID\n");
+
+		pr_err("__debug cnt = %d, cb->name: :%s sid [%d] = %d\n,",
+			cnt, cb->name, j, cb->sids[j]);
+	}
+	return rc;
+}
+
+static int cam_alloc_smmu_context_banks(struct device *dev)
+{
+	struct device_node *domains_child_node = NULL;
+
+	if (!dev) {
+		pr_err("Error: Invalid device\n");
+		return -ENODEV;
+	}
+
+	iommu_cb_set.cb_num = 0;
+
+	/* traverse thru all the child nodes and increment the cb count */
+	for_each_child_of_node(dev->of_node, domains_child_node) {
+		if (of_device_is_compatible(domains_child_node,
+			"qcom,msm-cam-smmu-cb"))
+			iommu_cb_set.cb_num++;
+
+		if (of_device_is_compatible(domains_child_node,
+			"qcom,qsmmu-cam-cb"))
+			iommu_cb_set.cb_num++;
+	}
+
+	if (iommu_cb_set.cb_num == 0) {
+		pr_err("Error: no context banks present\n");
+		return -ENOENT;
+	}
+
+	/* allocate memory for the context banks */
+	iommu_cb_set.cb_info = devm_kzalloc(dev,
+		iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info),
+		GFP_KERNEL);
+
+	if (!iommu_cb_set.cb_info) {
+		pr_err("Error: cannot allocate context banks\n");
+		return -ENOMEM;
+	}
+
+	cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT);
+	iommu_cb_set.cb_init_count = 0;
+
+	CDBG("no of context banks :%d\n", iommu_cb_set.cb_num);
+	return 0;
+}
+
+static int cam_populate_smmu_context_banks(struct device *dev,
+	enum cam_iommu_type type)
+{
+	int rc = 0;
+	struct cam_context_bank_info *cb;
+	struct device *ctx;
+
+	if (!dev) {
+		pr_err("Error: Invalid device\n");
+		return -ENODEV;
+	}
+
+	/* check the bounds */
+	if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) {
+		pr_err("Error: populate more than allocated cb\n");
+		rc = -EBADHANDLE;
+		goto cb_init_fail;
+	}
+
+	/* read the context bank from cb set */
+	cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count];
+
+	/* set the name of the context bank */
+	rc = of_property_read_string(dev->of_node, "label", &cb->name);
+	if (rc) {
+		pr_err("Error: failed to read label from sub device\n");
+		goto cb_init_fail;
+	}
+
+	/* populate SID's for each cb */
+	rc = cam_smmu_populate_sids(dev, cb);
+	if (rc < 0)
+		pr_err("Error: failed to populate sids : %s\n", cb->name);
+
+	/* Check if context bank supports scratch buffers */
+	if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support"))
+		cb->scratch_buf_support = 1;
+	else
+		cb->scratch_buf_support = 0;
+
+	/* set the secure/non secure domain type */
+	if (of_property_read_bool(dev->of_node, "qcom,secure-context"))
+		cb->is_secure = true;
+	else
+		cb->is_secure = false;
+
+	CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n",
+			cb->name, cb->is_secure, cb->scratch_buf_support);
+
+	/* set up the iommu mapping for the  context bank */
+	if (type == CAM_QSMMU) {
+		pr_err("Error: QSMMU ctx not supported for: %s\n", cb->name);
+		return -EINVAL;
+	}
+		ctx = dev;
+		CDBG("getting Arm SMMU ctx : %s\n", cb->name);
+
+	rc = cam_smmu_setup_cb(cb, ctx);
+	if (rc < 0)
+		pr_err("Error: failed to setup cb : %s\n", cb->name);
+
+	iommu_set_fault_handler(cb->mapping->domain,
+			cam_smmu_iommu_fault_handler,
+			(void *)cb->name);
+
+	/* increment count to next bank */
+	iommu_cb_set.cb_init_count++;
+
+	CDBG("X: cb init count :%d\n", iommu_cb_set.cb_init_count);
+	return rc;
+
+cb_init_fail:
+	iommu_cb_set.cb_info = NULL;
+	return rc;
+}
+
+static int cam_smmu_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct device *dev = &pdev->dev;
+
+	if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) {
+		rc = cam_alloc_smmu_context_banks(dev);
+		if (rc < 0)	{
+			pr_err("Error: allocating context banks\n");
+			return -ENOMEM;
+		}
+	}
+	if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) {
+		rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU);
+		if (rc < 0) {
+			pr_err("Error: populating context banks\n");
+			return -ENOMEM;
+		}
+		return rc;
+	}
+	if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) {
+		rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU);
+		if (rc < 0) {
+			pr_err("Error: populating context banks\n");
+			return -ENOMEM;
+		}
+		return rc;
+	}
+
+	/* probe thru all the subdevices */
+	rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match,
+				NULL, &pdev->dev);
+	if (rc < 0)
+		pr_err("Error: populating devices\n");
+
+	INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work);
+	mutex_init(&iommu_cb_set.payload_list_lock);
+	INIT_LIST_HEAD(&iommu_cb_set.payload_list);
+
+	return rc;
+}
+
+static int cam_smmu_remove(struct platform_device *pdev)
+{
+	/* release all the context banks and memory allocated */
+	cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT);
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu"))
+		cam_smmu_release_cb(pdev);
+	return 0;
+}
+
+static struct platform_driver cam_smmu_driver = {
+	.probe = cam_smmu_probe,
+	.remove = cam_smmu_remove,
+	.driver = {
+		.name = "msm_cam_smmu",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cam_smmu_dt_match,
+	},
+};
+
+static int __init cam_smmu_init_module(void)
+{
+	return platform_driver_register(&cam_smmu_driver);
+}
+
+static void __exit cam_smmu_exit_module(void)
+{
+	platform_driver_unregister(&cam_smmu_driver);
+}
+
+module_init(cam_smmu_init_module);
+module_exit(cam_smmu_exit_module);
+MODULE_DESCRIPTION("MSM Camera SMMU driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
new file mode 100644
index 0000000..ec8476d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
@@ -0,0 +1,242 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_SMMU_API_H_
+#define _CAM_SMMU_API_H_
+
+#include <linux/dma-direction.h>
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/random.h>
+#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
+
+/*
+ * Enum for possible CAM SMMU operations
+ */
+
+enum cam_smmu_ops_param {
+	CAM_SMMU_ATTACH,
+	CAM_SMMU_DETACH,
+	CAM_SMMU_ATTACH_SEC_VFE_NS_STATS,
+	CAM_SMMU_DETACH_SEC_VFE_NS_STATS,
+	CAM_SMMU_ATTACH_SEC_CPP,
+	CAM_SMMU_DETACH_SEC_CPP,
+	CAM_SMMU_VOTE,
+	CAM_SMMU_DEVOTE,
+	CAM_SMMU_OPS_INVALID
+};
+
+enum cam_smmu_map_dir {
+	CAM_SMMU_MAP_READ,
+	CAM_SMMU_MAP_WRITE,
+	CAM_SMMU_MAP_RW,
+	CAM_SMMU_MAP_INVALID
+};
+
+typedef void (*client_handler)(struct iommu_domain *,
+		struct device *, unsigned long,
+		int, void*);
+
+typedef void (*client_reset_handler)(struct iommu_domain *,
+		struct device *, void*);
+
+/**
+ * @param identifier: Unique identifier to be used by clients which they
+ *                    should get from device tree. CAM SMMU driver will
+ *                    not enforce how this string is obtained and will
+ *                    only validate this against the list of permitted
+ *                    identifiers
+ * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will
+ *		      fill the handle pointed by handle_ptr
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_handle(char *identifier, int *handle_ptr);
+
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param flags   : SMMU attribute type
+ * @data             : Value of attribute
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data);
+
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param op    : Operation to be performed. Can be either CAM_SMMU_ATTACH
+ *                or CAM_SMMU_DETACH
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param op);
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @phys_addr   : Pointer to physical address where mapped address will be
+ *                returned.
+ * @dir         : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ *                DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @len         : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_phy_addr(int handle,
+				int ion_fd, enum cam_smmu_map_dir dir,
+				dma_addr_t *dma_addr, size_t *len_ptr);
+
+/**
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_phy_addr(int handle, int ion_fd);
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir         : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ *                DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @client   : Client has to pass the ion_client pointer created by the client.
+ * @phys_addr   : Pointer to physical address where mapped address will be
+ *                returned.
+ * @len         : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_stage2_phy_addr(int handle,
+			int ion_fd, enum cam_smmu_map_dir dir,
+			struct ion_client *client, ion_phys_addr_t *addr,
+			size_t *len_ptr);
+
+/**
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd);
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @dir         : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ *                DMA_TO_DEVICE or DMA_FROM_DEVICE, client has to pass.
+ * @client   : Client has to pass the ion_client pointer created by the client.
+ * @ion_handle  : handle to the buffer returned by CAM SMMU driver.
+ * @phys_addr   : Pointer to physical address where mapped address will be
+ *                returned.
+ * @len         : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+		enum cam_smmu_map_dir dir, struct ion_client *client,
+		struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+		size_t *len_ptr);
+
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @client   : Client has to pass the ion_client pointer provided by SMMU
+ *                driver.
+ * @ion_handle  : Client has to pass the ion_handle provided by SMMU
+ *                driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+	struct ion_client *client, struct ion_handle *sc_handle);
+
+/**
+ * @brief	   : Allocates a scratch buffer
+ *
+ * This function allocates a scratch virtual buffer of length virt_len in the
+ * device virtual address space mapped to phys_len physically contiguous bytes
+ * in that device's SMMU.
+ *
+ * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each
+ * other, otherwise -EINVAL is returned.
+ *
+ * -EINVAL will be returned if virt_len is less than phys_len.
+ *
+ * Passing a too large phys_len might also cause failure if that much size is
+ * not available for allocation in a physically contiguous way.
+ *
+ * @param handle   : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param dir      : Direction of mapping which will translate to IOMMU_READ
+ *			IOMMU_WRITE or a bit mask of both.
+ * @param paddr_ptr: Device virtual address that the client device will be
+ *		able to read from/write to
+ * @param virt_len : Virtual length of the scratch buffer
+ * @param phys_len : Physical length of the scratch buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_get_phy_addr_scratch(int handle,
+				  enum cam_smmu_map_dir dir,
+				  dma_addr_t *paddr_ptr,
+				  size_t virt_len,
+				  size_t phys_len);
+
+/**
+ * @brief	   : Frees a scratch buffer
+ *
+ * This function frees a scratch buffer and releases the corresponding SMMU
+ * mappings.
+ *
+ * @param handle   : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ *			IOMMU_WRITE or a bit mask of both.
+ * @param paddr_ptr: Device virtual address of client's scratch buffer that
+ *			will be freed.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_put_phy_addr_scratch(int handle,
+				  dma_addr_t paddr);
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_destroy_handle(int handle);
+
+/**
+ * @return numger of client. Zero in case of error.
+ */
+int cam_smmu_get_num_of_clients(void);
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @return Index of SMMU client. Nagative in case of error.
+ */
+int cam_smmu_find_index_by_handle(int hdl);
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param client_page_fault_handler: It is triggered in IOMMU page fault
+ * @param client_hw_reset_handler: It is triggered in IOMMU page fault
+ * @param token: It is input param when trigger page fault handler
+ */
+void cam_smmu_reg_client_page_fault_handler(int handle,
+	client_handler page_fault_handler,
+	client_reset_handler hw_reset_handler,
+	void *token);
+
+#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
new file mode 100644
index 0000000..2eb00eb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
@@ -0,0 +1,1100 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-SOC %s:%d " fmt, __func__, __LINE__
+#define NO_SET_RATE -1
+#define INIT_RATE -2
+
+#ifdef CONFIG_CAM_SOC_API_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/msm-bus.h>
+#include <linux/clk/msm-clk.h>
+#include "cam_soc_api.h"
+
+struct msm_cam_bus_pscale_data {
+	struct msm_bus_scale_pdata *pdata;
+	uint32_t bus_client;
+	uint32_t num_usecases;
+	uint32_t num_paths;
+	unsigned int vector_index;
+	bool dyn_vote;
+	struct mutex lock;
+};
+
+static struct msm_cam_bus_pscale_data g_cv[CAM_BUS_CLIENT_MAX];
+
+
+/* Get all clocks from DT */
+static int msm_camera_get_clk_info_internal(struct device *dev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			size_t *num_clk)
+{
+	int rc = 0;
+	size_t cnt, tmp;
+	uint32_t *rates, i = 0;
+	const char *clk_ctl = NULL;
+	bool clock_cntl_support = false;
+	struct device_node *of_node;
+
+	of_node = dev->of_node;
+
+	cnt = of_property_count_strings(of_node, "clock-names");
+	if (cnt <= 0) {
+		pr_err("err: No clocks found in DT=%zu\n", cnt);
+		return -EINVAL;
+	}
+
+	tmp = of_property_count_u32_elems(of_node, "qcom,clock-rates");
+	if (tmp <= 0) {
+		pr_err("err: No clk rates device tree, count=%zu", tmp);
+		return -EINVAL;
+	}
+
+	if (cnt != tmp) {
+		pr_err("err: clk name/rates mismatch, strings=%zu, rates=%zu\n",
+			cnt, tmp);
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(of_node, "qcom,clock-cntl-support")) {
+		tmp = of_property_count_strings(of_node,
+				"qcom,clock-control");
+		if (tmp <= 0) {
+			pr_err("err: control strings not found in DT count=%zu",
+				tmp);
+			return -EINVAL;
+		}
+		if (cnt != tmp) {
+			pr_err("err: controls mismatch, strings=%zu, ctl=%zu\n",
+				cnt, tmp);
+			return -EINVAL;
+		}
+		clock_cntl_support = true;
+	}
+
+	*num_clk = cnt;
+
+	*clk_info = devm_kcalloc(dev, cnt,
+				sizeof(struct msm_cam_clk_info), GFP_KERNEL);
+	if (!*clk_info)
+		return -ENOMEM;
+
+	*clk_ptr = devm_kcalloc(dev, cnt, sizeof(struct clk *),
+				GFP_KERNEL);
+	if (!*clk_ptr) {
+		rc = -ENOMEM;
+		goto err1;
+	}
+
+	rates = devm_kcalloc(dev, cnt, sizeof(long), GFP_KERNEL);
+	if (!rates) {
+		rc = -ENOMEM;
+		goto err2;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
+		rates, cnt);
+	if (rc < 0) {
+		pr_err("err: failed reading clock rates\n");
+		rc = -EINVAL;
+		goto err3;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		rc = of_property_read_string_index(of_node, "clock-names",
+				i, &((*clk_info)[i].clk_name));
+		if (rc < 0) {
+			pr_err("%s reading clock-name failed index %d\n",
+				__func__, i);
+			rc = -EINVAL;
+			goto err3;
+		}
+
+		CDBG("dbg: clk-name[%d] = %s\n", i, (*clk_info)[i].clk_name);
+		if (clock_cntl_support) {
+			rc = of_property_read_string_index(of_node,
+				"qcom,clock-control", i, &clk_ctl);
+			if (rc < 0) {
+				pr_err("%s reading clock-control failed index %d\n",
+					__func__, i);
+				rc = -EINVAL;
+				goto err3;
+			}
+
+			if (!strcmp(clk_ctl, "NO_SET_RATE"))
+				(*clk_info)[i].clk_rate = NO_SET_RATE;
+			else if (!strcmp(clk_ctl, "INIT_RATE"))
+				(*clk_info)[i].clk_rate = INIT_RATE;
+			else if (!strcmp(clk_ctl, "SET_RATE"))
+				(*clk_info)[i].clk_rate = rates[i];
+			else {
+				pr_err("%s: error: clock control has invalid value\n",
+					 __func__);
+				rc = -EBUSY;
+				goto err3;
+			}
+		} else
+			(*clk_info)[i].clk_rate =
+				(rates[i] == 0) ? (long)-1 : rates[i];
+
+		CDBG("dbg: clk-rate[%d] = rate: %ld\n",
+			i, (*clk_info)[i].clk_rate);
+
+		(*clk_ptr)[i] =
+			devm_clk_get(dev, (*clk_info)[i].clk_name);
+		if (IS_ERR((*clk_ptr)[i])) {
+			rc = PTR_ERR((*clk_ptr)[i]);
+			goto err4;
+		}
+		CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]);
+	}
+
+	devm_kfree(dev, rates);
+	return rc;
+
+err4:
+	if (i > 0) {
+		do {
+			devm_clk_put(dev, (*clk_ptr)[--i]);
+		} while (i);
+	}
+err3:
+	devm_kfree(dev, rates);
+err2:
+	devm_kfree(dev, *clk_ptr);
+err1:
+	devm_kfree(dev, *clk_info);
+	return rc;
+}
+
+/* Get all clocks from DT  for I2C devices */
+int msm_camera_i2c_dev_get_clk_info(struct device *dev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			size_t *num_clk)
+{
+	int rc = 0;
+
+	if (!dev || !clk_info || !clk_ptr || !num_clk)
+		return -EINVAL;
+
+	rc = msm_camera_get_clk_info_internal(dev, clk_info, clk_ptr, num_clk);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_i2c_dev_get_clk_info);
+
+/* Get all clocks from DT  for platform devices */
+int msm_camera_get_clk_info(struct platform_device *pdev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			size_t *num_clk)
+{
+	int rc = 0;
+
+	if (!pdev || !&pdev->dev || !clk_info || !clk_ptr || !num_clk)
+		return -EINVAL;
+
+	rc = msm_camera_get_clk_info_internal(&pdev->dev,
+			clk_info, clk_ptr, num_clk);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_get_clk_info);
+
+/* Get all clocks and multiple rates from DT */
+int msm_camera_get_clk_info_and_rates(
+			struct platform_device *pdev,
+			struct msm_cam_clk_info **pclk_info,
+			struct clk ***pclks,
+			uint32_t ***pclk_rates,
+			size_t *num_set,
+			size_t *num_clk)
+{
+	int rc = 0, tmp_var, cnt, tmp;
+	int32_t i = 0, j = 0;
+	struct device_node *of_node;
+	uint32_t **rates;
+	struct clk **clks;
+	struct msm_cam_clk_info *clk_info;
+
+	if (!pdev || !pclk_info || !num_clk
+		|| !pclk_rates || !pclks || !num_set)
+		return -EINVAL;
+
+	of_node = pdev->dev.of_node;
+
+	cnt = of_property_count_strings(of_node, "clock-names");
+	if (cnt <= 0) {
+		pr_err("err: No clocks found in DT=%d\n", cnt);
+		return -EINVAL;
+	}
+
+	tmp = of_property_count_u32_elems(of_node, "qcom,clock-rates");
+	if (tmp <= 0) {
+		pr_err("err: No clk rates device tree, count=%d\n", tmp);
+		return -EINVAL;
+	}
+
+	if ((tmp % cnt) != 0) {
+		pr_err("err: clk name/rates mismatch, strings=%d, rates=%d\n",
+			cnt, tmp);
+		return -EINVAL;
+	}
+
+	*num_clk = cnt;
+	*num_set = (tmp / cnt);
+
+	clk_info = devm_kcalloc(&pdev->dev, cnt,
+				sizeof(struct msm_cam_clk_info), GFP_KERNEL);
+	if (!clk_info)
+		return -ENOMEM;
+
+	clks = devm_kcalloc(&pdev->dev, cnt, sizeof(struct clk *),
+				GFP_KERNEL);
+	if (!clks) {
+		rc = -ENOMEM;
+		goto err1;
+	}
+
+	rates = devm_kcalloc(&pdev->dev, *num_set,
+		sizeof(uint32_t *), GFP_KERNEL);
+	if (!rates) {
+		rc = -ENOMEM;
+		goto err2;
+	}
+
+	for (i = 0; i < *num_set; i++) {
+		rates[i] = devm_kcalloc(&pdev->dev, *num_clk,
+			sizeof(uint32_t), GFP_KERNEL);
+		if (!rates[i] && (i > 0)) {
+			rc = -ENOMEM;
+			for (j = i - 1; j >= 0; j--)
+				devm_kfree(&pdev->dev, rates[j]);
+			goto err3;
+		}
+	}
+
+	tmp_var = 0;
+	for (i = 0; i < *num_set; i++) {
+		for (j = 0; j < *num_clk; j++) {
+			rc = of_property_read_u32_index(of_node,
+				"qcom,clock-rates", tmp_var++, &rates[i][j]);
+			if (rc < 0) {
+				pr_err("err: failed reading clock rates\n");
+				rc = -EINVAL;
+				goto err4;
+			}
+			CDBG("Clock rate idx %d idx %d value %d\n",
+				i, j, rates[i][j]);
+		}
+	}
+	for (i = 0; i < *num_clk; i++) {
+		rc = of_property_read_string_index(of_node, "clock-names",
+				i, &clk_info[i].clk_name);
+		if (rc < 0) {
+			pr_err("%s reading clock-name failed index %d\n",
+				__func__, i);
+			rc = -EINVAL;
+			goto err4;
+		}
+
+		CDBG("dbg: clk-name[%d] = %s\n", i, clk_info[i].clk_name);
+
+		clks[i] =
+			devm_clk_get(&pdev->dev, clk_info[i].clk_name);
+		if (IS_ERR(clks[i])) {
+			rc = PTR_ERR(clks[i]);
+			goto err5;
+		}
+		CDBG("clk ptr[%d] :%pK\n", i, clks[i]);
+	}
+	*pclk_info = clk_info;
+	*pclks = clks;
+	*pclk_rates = rates;
+
+	return rc;
+
+err5:
+	if (i > 0) {
+		do {
+			devm_clk_put(&pdev->dev, clks[--i]);
+		} while (i);
+	}
+err4:
+	for (i = 0; i < *num_set; i++)
+		devm_kfree(&pdev->dev, rates[i]);
+err3:
+	devm_kfree(&pdev->dev, rates);
+err2:
+	devm_kfree(&pdev->dev, clks);
+err1:
+	devm_kfree(&pdev->dev, clk_info);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_get_clk_info_and_rates);
+
+/* Enable/Disable all clocks */
+int msm_camera_clk_enable(struct device *dev,
+		struct msm_cam_clk_info *clk_info,
+		struct clk **clk_ptr, int num_clk, int enable)
+{
+	int i;
+	int rc = 0;
+	long clk_rate;
+
+	if (enable) {
+		for (i = 0; i < num_clk; i++) {
+			CDBG("enable %s\n", clk_info[i].clk_name);
+			if (clk_info[i].clk_rate > 0) {
+				clk_rate = clk_round_rate(clk_ptr[i],
+					clk_info[i].clk_rate);
+				if (clk_rate < 0) {
+					pr_err("%s round failed\n",
+						   clk_info[i].clk_name);
+					goto cam_clk_set_err;
+				}
+				rc = clk_set_rate(clk_ptr[i],
+					clk_rate);
+				if (rc < 0) {
+					pr_err("%s set failed\n",
+						clk_info[i].clk_name);
+					goto cam_clk_set_err;
+				}
+
+			} else if (clk_info[i].clk_rate == INIT_RATE) {
+				clk_rate = clk_get_rate(clk_ptr[i]);
+				if (clk_rate == 0) {
+					clk_rate =
+						  clk_round_rate(clk_ptr[i], 0);
+					if (clk_rate <= 0) {
+						pr_err("%s round rate failed\n",
+							  clk_info[i].clk_name);
+						goto cam_clk_set_err;
+					}
+				}
+				rc = clk_set_rate(clk_ptr[i], clk_rate);
+				if (rc < 0) {
+					pr_err("%s set rate failed\n",
+						clk_info[i].clk_name);
+					goto cam_clk_set_err;
+				}
+			}
+			rc = clk_prepare_enable(clk_ptr[i]);
+			if (rc < 0) {
+				pr_err("%s enable failed\n",
+					   clk_info[i].clk_name);
+				goto cam_clk_enable_err;
+			}
+			if (clk_info[i].delay > 20) {
+				msleep(clk_info[i].delay);
+			} else if (clk_info[i].delay) {
+				usleep_range(clk_info[i].delay * 1000,
+					(clk_info[i].delay * 1000) + 1000);
+			}
+		}
+	} else {
+		for (i = num_clk - 1; i >= 0; i--) {
+			if (clk_ptr[i] != NULL) {
+				CDBG("%s disable %s\n", __func__,
+					clk_info[i].clk_name);
+				clk_disable_unprepare(clk_ptr[i]);
+			}
+		}
+	}
+	return rc;
+
+cam_clk_enable_err:
+cam_clk_set_err:
+	for (i--; i >= 0; i--) {
+		if (clk_ptr[i] != NULL)
+			clk_disable_unprepare(clk_ptr[i]);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_clk_enable);
+
+/* Set rate on a specific clock */
+long msm_camera_clk_set_rate(struct device *dev,
+			struct clk *clk,
+			long clk_rate)
+{
+	int rc = 0;
+	long rate = 0;
+
+	if (!dev || !clk || (clk_rate < 0))
+		return -EINVAL;
+
+	CDBG("clk : %pK, enable : %ld\n", clk, clk_rate);
+
+	if (clk_rate > 0) {
+		rate = clk_round_rate(clk, clk_rate);
+		if (rate < 0) {
+			pr_err("round rate failed\n");
+			return -EINVAL;
+		}
+
+		rc = clk_set_rate(clk, rate);
+		if (rc < 0) {
+			pr_err("set rate failed\n");
+			return -EINVAL;
+		}
+	}
+
+	return rate;
+}
+EXPORT_SYMBOL(msm_camera_clk_set_rate);
+
+int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags)
+{
+	if (!clk)
+		return -EINVAL;
+
+	CDBG("clk : %pK, flags : %ld\n", clk, flags);
+
+	return clk_set_flags(clk, flags);
+}
+EXPORT_SYMBOL(msm_camera_set_clk_flags);
+
+/* release memory allocated for clocks */
+static int msm_camera_put_clk_info_internal(struct device *dev,
+				struct msm_cam_clk_info **clk_info,
+				struct clk ***clk_ptr, int cnt)
+{
+	int i;
+
+	for (i = cnt - 1; i >= 0; i--) {
+		if (clk_ptr[i] != NULL)
+			devm_clk_put(dev, (*clk_ptr)[i]);
+
+		CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]);
+	}
+	devm_kfree(dev, *clk_info);
+	devm_kfree(dev, *clk_ptr);
+	*clk_info = NULL;
+	*clk_ptr = NULL;
+	return 0;
+}
+
+/* release memory allocated for clocks for i2c devices */
+int msm_camera_i2c_dev_put_clk_info(struct device *dev,
+				struct msm_cam_clk_info **clk_info,
+				struct clk ***clk_ptr, int cnt)
+{
+	int rc = 0;
+
+	if (!dev || !clk_info || !clk_ptr)
+		return -EINVAL;
+
+	rc = msm_camera_put_clk_info_internal(dev, clk_info, clk_ptr, cnt);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_i2c_dev_put_clk_info);
+
+/* release memory allocated for clocks for platform devices */
+int msm_camera_put_clk_info(struct platform_device *pdev,
+				struct msm_cam_clk_info **clk_info,
+				struct clk ***clk_ptr, int cnt)
+{
+	int rc = 0;
+
+	if (!pdev || !&pdev->dev || !clk_info || !clk_ptr)
+		return -EINVAL;
+
+	rc = msm_camera_put_clk_info_internal(&pdev->dev,
+			clk_info, clk_ptr, cnt);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_put_clk_info);
+
+int msm_camera_put_clk_info_and_rates(struct platform_device *pdev,
+		struct msm_cam_clk_info **clk_info,
+		struct clk ***clk_ptr, uint32_t ***clk_rates,
+		size_t set, size_t cnt)
+{
+	int i;
+
+	for (i = set - 1; i >= 0; i--)
+		devm_kfree(&pdev->dev, (*clk_rates)[i]);
+
+	devm_kfree(&pdev->dev, *clk_rates);
+	for (i = cnt - 1; i >= 0; i--) {
+		if (clk_ptr[i] != NULL)
+			devm_clk_put(&pdev->dev, (*clk_ptr)[i]);
+		CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]);
+	}
+	devm_kfree(&pdev->dev, *clk_info);
+	devm_kfree(&pdev->dev, *clk_ptr);
+	*clk_info = NULL;
+	*clk_ptr = NULL;
+	*clk_rates = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_put_clk_info_and_rates);
+
+/* Get reset info from DT */
+int msm_camera_get_reset_info(struct platform_device *pdev,
+		struct reset_control **micro_iface_reset)
+{
+	if (!pdev || !micro_iface_reset)
+		return -EINVAL;
+
+	if (of_property_match_string(pdev->dev.of_node, "reset-names",
+				"micro_iface_reset")) {
+		pr_err("err: Reset property not found\n");
+		return -EINVAL;
+	}
+
+	*micro_iface_reset = devm_reset_control_get
+				(&pdev->dev, "micro_iface_reset");
+	if (IS_ERR(*micro_iface_reset))
+		return PTR_ERR(*micro_iface_reset);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_get_reset_info);
+
+/* Get regulators from DT */
+int msm_camera_get_regulator_info(struct platform_device *pdev,
+				struct msm_cam_regulator **vdd_info,
+				int *num_reg)
+{
+	uint32_t cnt;
+	int i, rc;
+	struct device_node *of_node;
+	char prop_name[32];
+	struct msm_cam_regulator *tmp_reg;
+
+	if (!pdev || !vdd_info || !num_reg)
+		return -EINVAL;
+
+	of_node = pdev->dev.of_node;
+
+	if (!of_get_property(of_node, "qcom,vdd-names", NULL)) {
+		pr_err("err: Regulators property not found\n");
+		return -EINVAL;
+	}
+
+	cnt = of_property_count_strings(of_node, "qcom,vdd-names");
+	if (cnt <= 0) {
+		pr_err("err: no regulators found in device tree, count=%d",
+			cnt);
+		return -EINVAL;
+	}
+
+	tmp_reg = devm_kcalloc(&pdev->dev, cnt,
+				sizeof(struct msm_cam_regulator), GFP_KERNEL);
+	if (!tmp_reg)
+		return -ENOMEM;
+
+	for (i = 0; i < cnt; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,vdd-names", i, &tmp_reg[i].name);
+		if (rc < 0) {
+			pr_err("Fail to fetch regulators: %d\n", i);
+			rc = -EINVAL;
+			goto err1;
+		}
+
+		CDBG("regulator-names[%d] = %s\n", i, tmp_reg[i].name);
+
+		snprintf(prop_name, 32, "%s-supply", tmp_reg[i].name);
+
+		if (of_get_property(of_node, prop_name, NULL)) {
+			tmp_reg[i].vdd =
+				devm_regulator_get(&pdev->dev, tmp_reg[i].name);
+			if (IS_ERR(tmp_reg[i].vdd)) {
+				rc = -EINVAL;
+				pr_err("Fail to get regulator :%d\n", i);
+				goto err1;
+			}
+		} else {
+			pr_err("Regulator phandle not found :%s\n",
+				tmp_reg[i].name);
+			rc = -EINVAL;
+			goto err1;
+		}
+		CDBG("vdd ptr[%d] :%pK\n", i, tmp_reg[i].vdd);
+	}
+
+	*num_reg = cnt;
+	*vdd_info = tmp_reg;
+
+	return 0;
+
+err1:
+	for (--i; i >= 0; i--)
+		devm_regulator_put(tmp_reg[i].vdd);
+	devm_kfree(&pdev->dev, tmp_reg);
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_get_regulator_info);
+
+
+/* Enable/Disable regulators */
+int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info,
+				int cnt, int enable)
+{
+	int i;
+	int rc;
+	struct msm_cam_regulator *tmp = vdd_info;
+
+	if (!tmp) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+	CDBG("cnt : %d\n", cnt);
+
+	for (i = 0; i < cnt; i++) {
+		if (tmp && !IS_ERR_OR_NULL(tmp->vdd)) {
+			CDBG("name : %s, enable : %d\n", tmp->name, enable);
+			if (enable) {
+				rc = regulator_enable(tmp->vdd);
+				if (rc < 0) {
+					pr_err("regulator enable failed %d\n",
+						i);
+					goto error;
+				}
+			} else {
+				rc = regulator_disable(tmp->vdd);
+				if (rc < 0)
+					pr_err("regulator disable failed %d\n",
+						i);
+			}
+		}
+		tmp++;
+	}
+
+	return 0;
+error:
+	for (--i; i > 0; i--) {
+		--tmp;
+		if (!IS_ERR_OR_NULL(tmp->vdd))
+			regulator_disable(tmp->vdd);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_regulator_enable);
+
+/* set regulator mode */
+int msm_camera_regulator_set_mode(struct msm_cam_regulator *vdd_info,
+				int cnt, bool mode)
+{
+	int i;
+	int rc;
+	struct msm_cam_regulator *tmp = vdd_info;
+
+	if (!tmp) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+	CDBG("cnt : %d\n", cnt);
+
+	for (i = 0; i < cnt; i++) {
+		if (tmp && !IS_ERR_OR_NULL(tmp->vdd)) {
+			CDBG("name : %s, enable : %d\n", tmp->name, mode);
+			if (mode) {
+				rc = regulator_set_mode(tmp->vdd,
+					REGULATOR_MODE_NORMAL);
+				if (rc < 0) {
+					pr_err("regulator enable failed %d\n",
+						i);
+					goto error;
+				}
+			} else {
+				rc = regulator_set_mode(tmp->vdd,
+					REGULATOR_MODE_NORMAL);
+				if (rc < 0)
+					pr_err("regulator disable failed %d\n",
+						i);
+					goto error;
+			}
+		}
+		tmp++;
+	}
+
+	return 0;
+error:
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_regulator_set_mode);
+
+
+/* Put regulators regulators */
+void msm_camera_put_regulators(struct platform_device *pdev,
+	struct msm_cam_regulator **vdd_info, int cnt)
+{
+	int i;
+
+	if (!vdd_info || !*vdd_info) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	for (i = cnt - 1; i >= 0; i--) {
+		if (vdd_info[i] && !IS_ERR_OR_NULL(vdd_info[i]->vdd))
+			devm_regulator_put(vdd_info[i]->vdd);
+			CDBG("vdd ptr[%d] :%pK\n", i, vdd_info[i]->vdd);
+	}
+
+	devm_kfree(&pdev->dev, *vdd_info);
+	*vdd_info = NULL;
+}
+EXPORT_SYMBOL(msm_camera_put_regulators);
+
+struct resource *msm_camera_get_irq(struct platform_device *pdev,
+							char *irq_name)
+{
+	if (!pdev || !irq_name) {
+		pr_err("Invalid params\n");
+		return NULL;
+	}
+
+	CDBG("Get irq for %s\n", irq_name);
+	return platform_get_resource_byname(pdev, IORESOURCE_IRQ, irq_name);
+}
+EXPORT_SYMBOL(msm_camera_get_irq);
+
+int msm_camera_register_irq(struct platform_device *pdev,
+			struct resource *irq, irq_handler_t handler,
+			unsigned long irqflags, char *irq_name, void *dev_id)
+{
+	int rc = 0;
+
+	if (!pdev || !irq || !handler || !irq_name || !dev_id) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	rc = devm_request_irq(&pdev->dev, irq->start, handler,
+		irqflags, irq_name, dev_id);
+	if (rc < 0) {
+		pr_err("irq request fail\n");
+		rc = -EINVAL;
+	}
+
+	CDBG("Registered irq for %s[resource - %pK]\n", irq_name, irq);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_register_irq);
+
+int msm_camera_register_threaded_irq(struct platform_device *pdev,
+			struct resource *irq, irq_handler_t handler_fn,
+			irq_handler_t thread_fn, unsigned long irqflags,
+			const char *irq_name, void *dev_id)
+{
+	int rc = 0;
+
+	if (!pdev || !irq || !irq_name || !dev_id) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	rc = devm_request_threaded_irq(&pdev->dev, irq->start, handler_fn,
+			thread_fn, irqflags, irq_name, dev_id);
+	if (rc < 0) {
+		pr_err("irq request fail\n");
+		rc = -EINVAL;
+	}
+
+	CDBG("Registered irq for %s[resource - %pK]\n", irq_name, irq);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_camera_register_threaded_irq);
+
+int msm_camera_enable_irq(struct resource *irq, int enable)
+{
+	if (!irq) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	CDBG("irq Enable %d\n", enable);
+	if (enable)
+		enable_irq(irq->start);
+	else
+		disable_irq(irq->start);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_enable_irq);
+
+int msm_camera_unregister_irq(struct platform_device *pdev,
+	struct resource *irq, void *dev_id)
+{
+
+	if (!pdev || !irq || !dev_id) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	CDBG("Un Registering irq for [resource - %pK]\n", irq);
+	devm_free_irq(&pdev->dev, irq->start, dev_id);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_unregister_irq);
+
+void __iomem *msm_camera_get_reg_base(struct platform_device *pdev,
+		char *device_name, int reserve_mem)
+{
+	struct resource *mem;
+	void __iomem *base;
+
+	if (!pdev || !device_name) {
+		pr_err("Invalid params\n");
+		return NULL;
+	}
+
+	CDBG("device name :%s\n", device_name);
+	mem = platform_get_resource_byname(pdev,
+			IORESOURCE_MEM, device_name);
+	if (!mem) {
+		pr_err("err: mem resource %s not found\n", device_name);
+		return NULL;
+	}
+
+	if (reserve_mem) {
+		CDBG("device:%pK, mem : %pK, size : %d\n",
+			&pdev->dev, mem, (int)resource_size(mem));
+		if (!devm_request_mem_region(&pdev->dev, mem->start,
+			resource_size(mem),
+			device_name)) {
+			pr_err("err: no valid mem region for device:%s\n",
+				device_name);
+			return NULL;
+		}
+	}
+
+	base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+	if (!base) {
+		devm_release_mem_region(&pdev->dev, mem->start,
+				resource_size(mem));
+		pr_err("err: ioremap failed: %s\n", device_name);
+		return NULL;
+	}
+
+	CDBG("base : %pK\n", base);
+	return base;
+}
+EXPORT_SYMBOL(msm_camera_get_reg_base);
+
+uint32_t msm_camera_get_res_size(struct platform_device *pdev,
+	char *device_name)
+{
+	struct resource *mem;
+
+	if (!pdev || !device_name) {
+		pr_err("Invalid params\n");
+		return 0;
+	}
+
+	CDBG("device name :%s\n", device_name);
+	mem = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, device_name);
+	if (!mem) {
+		pr_err("err: mem resource %s not found\n", device_name);
+		return 0;
+	}
+	return resource_size(mem);
+}
+EXPORT_SYMBOL(msm_camera_get_res_size);
+
+
+int msm_camera_put_reg_base(struct platform_device *pdev,
+	void __iomem *base,	char *device_name, int reserve_mem)
+{
+	struct resource *mem;
+
+	if (!pdev || !base || !device_name) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	CDBG("device name :%s\n", device_name);
+	mem = platform_get_resource_byname(pdev,
+			IORESOURCE_MEM, device_name);
+	if (!mem) {
+		pr_err("err: mem resource %s not found\n", device_name);
+		return -EINVAL;
+	}
+	CDBG("mem : %pK, size : %d\n", mem, (int)resource_size(mem));
+
+	devm_iounmap(&pdev->dev, base);
+	if (reserve_mem)
+		devm_release_mem_region(&pdev->dev,
+			mem->start, resource_size(mem));
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_put_reg_base);
+
+/* Register the bus client */
+uint32_t msm_camera_register_bus_client(struct platform_device *pdev,
+	enum cam_bus_client id)
+{
+	int rc = 0;
+	uint32_t bus_client, num_usecases, num_paths;
+	struct msm_bus_scale_pdata *pdata;
+	struct device_node *of_node;
+
+	CDBG("Register client ID: %d\n", id);
+
+	if (id >= CAM_BUS_CLIENT_MAX || !pdev) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+
+	of_node = pdev->dev.of_node;
+
+	if (!g_cv[id].pdata) {
+		rc = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
+				&num_usecases);
+		if (rc) {
+			pr_err("num-usecases not found\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
+				&num_paths);
+		if (rc) {
+			pr_err("num-usecases not found\n");
+			return -EINVAL;
+		}
+
+		if (num_paths != 1) {
+			pr_err("Exceeds number of paths\n");
+			return -EINVAL;
+		}
+
+		if (of_property_read_bool(of_node,
+				"qcom,msm-bus-vector-dyn-vote")) {
+			if (num_usecases != 2) {
+				pr_err("Excess or less vectors\n");
+				return -EINVAL;
+			}
+			g_cv[id].dyn_vote = true;
+		}
+
+		pdata = msm_bus_cl_get_pdata(pdev);
+		if (!pdata) {
+			pr_err("failed get_pdata client_id :%d\n", id);
+			return -EINVAL;
+		}
+		bus_client = msm_bus_scale_register_client(pdata);
+		if (!bus_client) {
+			pr_err("Unable to register bus client :%d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		pr_err("vector already setup client_id : %d\n", id);
+		return -EINVAL;
+	}
+
+	g_cv[id].pdata = pdata;
+	g_cv[id].bus_client = bus_client;
+	g_cv[id].vector_index = 0;
+	g_cv[id].num_usecases = num_usecases;
+	g_cv[id].num_paths = num_paths;
+	mutex_init(&g_cv[id].lock);
+	CDBG("Exit Client ID: %d\n", id);
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_register_bus_client);
+
+/* Update the bus bandwidth */
+uint32_t msm_camera_update_bus_bw(int id, uint64_t ab, uint64_t ib)
+{
+	struct msm_bus_paths *path;
+	struct msm_bus_scale_pdata *pdata;
+	int idx = 0;
+
+	if (id >= CAM_BUS_CLIENT_MAX) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+	if (g_cv[id].num_usecases != 2 ||
+		g_cv[id].num_paths != 1 ||
+		g_cv[id].dyn_vote != true) {
+		pr_err("dynamic update not allowed\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&g_cv[id].lock);
+	idx = g_cv[id].vector_index;
+	idx = 1 - idx;
+	g_cv[id].vector_index = idx;
+	mutex_unlock(&g_cv[id].lock);
+
+	pdata = g_cv[id].pdata;
+	path = &(pdata->usecase[idx]);
+	path->vectors[0].ab = ab;
+	path->vectors[0].ib = ib;
+
+	CDBG("Register client ID : %d [ab : %llx, ib : %llx], update :%d\n",
+		id, ab, ib, idx);
+	msm_bus_scale_client_update_request(g_cv[id].bus_client, idx);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_update_bus_bw);
+
+/* Update the bus vector */
+uint32_t msm_camera_update_bus_vector(enum cam_bus_client id,
+	int vector_index)
+{
+	if (id >= CAM_BUS_CLIENT_MAX || g_cv[id].dyn_vote == true) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+
+	if (vector_index < 0 || vector_index > g_cv[id].num_usecases) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+
+	CDBG("Register client ID : %d vector idx: %d,\n", id, vector_index);
+	msm_bus_scale_client_update_request(g_cv[id].bus_client,
+		vector_index);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_update_bus_vector);
+
+/* Unregister the bus client */
+uint32_t msm_camera_unregister_bus_client(enum cam_bus_client id)
+{
+	if (id >= CAM_BUS_CLIENT_MAX) {
+		pr_err("Invalid params");
+		return -EINVAL;
+	}
+
+	CDBG("UnRegister client ID: %d\n", id);
+
+	mutex_destroy(&g_cv[id].lock);
+	msm_bus_scale_unregister_client(g_cv[id].bus_client);
+	g_cv[id].bus_client = 0;
+	g_cv[id].num_usecases = 0;
+	g_cv[id].num_paths = 0;
+	g_cv[id].vector_index = 0;
+	g_cv[id].dyn_vote = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_camera_unregister_bus_client);
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h
new file mode 100644
index 0000000..0e0736a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h
@@ -0,0 +1,471 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_SOC_API_H_
+#define _CAM_SOC_API_H_
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/reset.h>
+#include <soc/qcom/camera2.h>
+
+enum cam_bus_client {
+	CAM_BUS_CLIENT_VFE,
+	CAM_BUS_CLIENT_CPP,
+	CAM_BUS_CLIENT_FD,
+	CAM_BUS_CLIENT_JPEG_ENC0,
+	CAM_BUS_CLIENT_JPEG_ENC1,
+	CAM_BUS_CLIENT_JPEG_DEC,
+	CAM_BUS_CLIENT_JPEG_DMA,
+	CAM_BUS_CLIENT_MAX
+};
+
+struct msm_cam_regulator {
+	const char *name;
+	struct regulator *vdd;
+};
+
+/**
+ * @brief      : Gets clock information from dtsi
+ *
+ * This function extracts the clocks information for a specific
+ * platform device
+ *
+ * @param pdev   : Platform device to get clocks information
+ * @param clk_info   : Pointer to populate clock information array
+ * @param clk_ptr   : Pointer to populate clock resource pointers
+ * @param num_clk: Pointer to populate the number of clocks
+ *                 extracted from dtsi
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_get_clk_info(struct platform_device *pdev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			size_t *num_clk);
+
+/**
+ * @brief      : Gets clock information from dtsi
+ *
+ * This function extracts the clocks information for a specific
+ * i2c device
+ *
+ * @param dev   : i2c device to get clocks information
+ * @param clk_info   : Pointer to populate clock information array
+ * @param clk_ptr   : Pointer to populate clock resource pointers
+ * @param num_clk: Pointer to populate the number of clocks
+ *                 extracted from dtsi
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_i2c_dev_get_clk_info(struct device *dev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			size_t *num_clk);
+
+/**
+ * @brief      : Gets clock information and rates from dtsi
+ *
+ * This function extracts the clocks information for a specific
+ * platform device
+ *
+ * @param pdev   : Platform device to get clocks information
+ * @param clk_info   : Pointer to populate clock information array
+ * @param clk_ptr   : Pointer to populate clock resource pointers
+ * @param clk_rates   : Pointer to populate clock rates
+ * @param num_set: Pointer to populate the number of sets of rates
+ * @param num_clk: Pointer to populate the number of clocks
+ *                 extracted from dtsi
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_get_clk_info_and_rates(
+			struct platform_device *pdev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr,
+			uint32_t ***clk_rates,
+			size_t *num_set,
+			size_t *num_clk);
+
+/**
+ * @brief      : Puts clock information
+ *
+ * This function releases the memory allocated for the clocks
+ *
+ * @param pdev   : Pointer to platform device
+ * @param clk_info   : Pointer to release the allocated memory
+ * @param clk_ptr   : Pointer to release the clock resources
+ * @param cnt   : Number of clk resources
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_put_clk_info(struct platform_device *pdev,
+				struct msm_cam_clk_info **clk_info,
+				struct clk ***clk_ptr, int cnt);
+
+/**
+ * @brief      : Puts clock information
+ *
+ * This function releases the memory allocated for the clocks
+ *
+ * @param dev   : Pointer to i2c device
+ * @param clk_info   : Pointer to release the allocated memory
+ * @param clk_ptr   : Pointer to release the clock resources
+ * @param cnt   : Number of clk resources
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_i2c_dev_put_clk_info(struct device *dev,
+			struct msm_cam_clk_info **clk_info,
+			struct clk ***clk_ptr, int cnt);
+
+/**
+ * @brief      : Puts clock information
+ *
+ * This function releases the memory allocated for the clocks
+ *
+ * @param pdev   : Pointer to platform device
+ * @param clk_info   : Pointer to release the allocated memory
+ * @param clk_ptr   : Pointer to release the clock resources
+ * @param clk_ptr   : Pointer to release the clock rates
+ * @param set   : Number of sets of clock rates
+ * @param cnt   : Number of clk resources
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_put_clk_info_and_rates(struct platform_device *pdev,
+		struct msm_cam_clk_info **clk_info,
+		struct clk ***clk_ptr, uint32_t ***clk_rates,
+		size_t set, size_t cnt);
+/**
+ * @brief      : Enable clocks
+ *
+ * This function enables the clocks for a specified device
+ *
+ * @param dev   : Device to get clocks information
+ * @param clk_info   : Pointer to populate clock information
+ * @param clk_ptr   : Pointer to populate clock information
+ * @param num_clk: Pointer to populate the number of clocks
+ *                 extracted from dtsi
+ * @param enable   : Flag to specify enable/disable
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_clk_enable(struct device *dev,
+					struct msm_cam_clk_info *clk_info,
+					struct clk **clk_ptr,
+					int num_clk,
+					int enable);
+/**
+ * @brief      : Set clock rate
+ *
+ * This function sets the rate for a specified clock and
+ * returns the rounded value
+ *
+ * @param dev   : Device to get clocks information
+ * @param clk   : Pointer to clock to set rate
+ * @param clk_rate   : Rate to be set
+ *
+ * @return Status of operation. Negative in case of error. clk rate otherwise.
+ */
+
+long msm_camera_clk_set_rate(struct device *dev,
+				struct clk *clk,
+				long clk_rate);
+
+/**
+ * @brief      : Gets reset info
+ *
+ * This function extracts the reset information for a specific
+ * platform device
+ *
+ * @param pdev   : platform device to get reset information
+ * @param micro_iface_reset : Pointer to populate the reset names
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_get_reset_info(struct platform_device *pdev,
+			struct reset_control **micro_iface_reset);
+/**
+ * @brief      : Sets flags of a clock
+ *
+ * This function will set the flags for a specified clock
+ *
+ * @param clk   : Pointer to clock to set flags for
+ * @param flags : The flags to set
+ *
+ * @return Status of operation.
+ */
+
+int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags);
+/**
+ * @brief      : Gets regulator info
+ *
+ * This function extracts the regulator information for a specific
+ * platform device
+ *
+ * @param pdev   : platform device to get regulator information
+ * @param vdd_info: Pointer to populate the regulator names
+ * @param num_reg: Pointer to populate the number of regulators
+ *                 extracted from dtsi
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_get_regulator_info(struct platform_device *pdev,
+		struct msm_cam_regulator **vdd_info, int *num_reg);
+/**
+ * @brief      : Enable/Disable the regultors
+ *
+ * This function enables/disables the regulators for a specific
+ * platform device
+ *
+ * @param vdd_info: Pointer to list of regulators
+ * @param cnt: Number of regulators to enable/disable
+ * @param enable: Flags specifies either enable/disable
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info,
+				int cnt, int enable);
+
+/**
+ * @brief      : set the regultors mode
+ *
+ * This function sets the regulators for a specific
+ * mode. say:REGULATOR_MODE_FAST/REGULATOR_MODE_NORMAL
+ *
+ * @param vdd_info: Pointer to list of regulators
+ * @param cnt: Number of regulators to enable/disable
+ * @param mode: Flags specifies either enable/disable
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_regulator_set_mode(struct msm_cam_regulator *vdd_info,
+				int cnt, bool mode);
+
+
+/**
+ * @brief      : Release the regulators
+ *
+ * This function releases the regulator resources.
+ *
+ * @param pdev: Pointer to platform device
+ * @param vdd_info: Pointer to list of regulators
+ * @param cnt: Number of regulators to release
+ */
+
+void msm_camera_put_regulators(struct platform_device *pdev,
+	struct msm_cam_regulator **vdd_info, int cnt);
+/**
+ * @brief      : Get the IRQ resource
+ *
+ * This function gets the irq resource from dtsi for a specific
+ * platform device
+ *
+ * @param pdev   : Platform device to get IRQ
+ * @param irq_name: Name of the IRQ resource to get from DTSI
+ *
+ * @return Pointer to resource if success else null
+ */
+
+struct resource *msm_camera_get_irq(struct platform_device *pdev,
+							char *irq_name);
+/**
+ * @brief      : Register the IRQ
+ *
+ * This function registers the irq resource for specified hardware
+ *
+ * @param pdev    : Platform device to register IRQ resource
+ * @param irq	  : IRQ resource
+ * @param handler : IRQ handler
+ * @param irqflags : IRQ flags
+ * @param irq_name: Name of the IRQ
+ * @param dev	 : Token of the device
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_register_irq(struct platform_device *pdev,
+						struct resource *irq,
+						irq_handler_t handler,
+						unsigned long irqflags,
+						char *irq_name,
+						void *dev);
+
+/**
+ * @brief      : Register the threaded IRQ
+ *
+ * This function registers the irq resource for specified hardware
+ *
+ * @param pdev    : Platform device to register IRQ resource
+ * @param irq	  : IRQ resource
+ * @param handler_fn : IRQ handler function
+ * @param thread_fn : thread handler function
+ * @param irqflags : IRQ flags
+ * @param irq_name: Name of the IRQ
+ * @param dev	 : Token of the device
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_register_threaded_irq(struct platform_device *pdev,
+						struct resource *irq,
+						irq_handler_t handler_fn,
+						irq_handler_t thread_fn,
+						unsigned long irqflags,
+						const char *irq_name,
+						void *dev);
+
+/**
+ * @brief      : Enable/Disable the IRQ
+ *
+ * This function enables or disables a specific IRQ
+ *
+ * @param irq    : IRQ resource
+ * @param flag   : flag to enable/disable
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_enable_irq(struct resource *irq, int flag);
+
+/**
+ * @brief      : UnRegister the IRQ
+ *
+ * This function Unregisters/Frees the irq resource
+ *
+ * @param pdev   : Pointer to platform device
+ * @param irq    : IRQ resource
+ * @param dev    : Token of the device
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_unregister_irq(struct platform_device *pdev,
+	struct resource *irq, void *dev_id);
+
+/**
+ * @brief      : Gets device register base
+ *
+ * This function extracts the device's register base from the dtsi
+ * for the specified platform device
+ *
+ * @param pdev   : Platform device to get regulator infor
+ * @param device_name   : Name of the device to fetch the register base
+ * @param reserve_mem   : Flag to decide whether to reserve memory
+ * region or not.
+ *
+ * @return Pointer to resource if success else null
+ */
+
+void __iomem *msm_camera_get_reg_base(struct platform_device *pdev,
+		char *device_name, int reserve_mem);
+
+/**
+ * @brief      :  Puts device register base
+ *
+ * This function releases the memory region for the specified
+ * resource
+ *
+ * @param pdev   : Pointer to platform device
+ * @param base   : Pointer to base to unmap
+ * @param device_name : Device name
+ * @param reserve_mem   : Flag to decide whether to release memory
+ * region or not.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int msm_camera_put_reg_base(struct platform_device *pdev, void __iomem *base,
+		char *device_name, int reserve_mem);
+
+/**
+ * @brief      : Register the bus client
+ *
+ * This function registers the bus client
+ *
+ * @param pdev : Pointer to platform device
+ * @param id : client identifier
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+uint32_t msm_camera_register_bus_client(struct platform_device *pdev,
+	enum cam_bus_client id);
+
+/**
+ * @brief      : Update bus vector
+ *
+ * This function votes for the specified vector to the bus
+ *
+ * @param id : client identifier
+ * @param vector_index : vector index to register
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+uint32_t msm_camera_update_bus_vector(enum cam_bus_client id,
+	int vector_index);
+
+/**
+ * @brief      : Update the bus bandwidth
+ *
+ * This function updates the bandwidth for the specific client
+ *
+ * @param client_id   : client identifier
+ * @param ab    : Asolute bandwidth
+ * @param ib    : Instantaneous bandwidth
+ *
+ * @return non-zero as client id if success else fail
+ */
+
+uint32_t msm_camera_update_bus_bw(int id, uint64_t ab, uint64_t ib);
+
+/**
+ * @brief      : UnRegister the bus client
+ *
+ * This function unregisters the bus client
+ *
+ * @param id   : client identifier
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+uint32_t msm_camera_unregister_bus_client(enum cam_bus_client id);
+
+/**
+ * @brief      : Gets resource size
+ *
+ * This function returns the size of the resource for the
+ * specified platform device
+ *
+ * @param pdev   : Platform device to get regulator infor
+ * @param device_name   : Name of the device to fetch the register base
+ *
+ * @return size of the resource
+ */
+
+uint32_t msm_camera_get_res_size(struct platform_device *pdev,
+	char *device_name);
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
new file mode 100644
index 0000000..9a212825
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
@@ -0,0 +1,866 @@
+/* Copyright (c) 2011-2014, 2017-2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <soc/qcom/camera2.h>
+#include <linux/msm-bus.h>
+#include "msm_camera_io_util.h"
+
+#define BUFF_SIZE_128 128
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+void msm_camera_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: 0x%pK %08x\n", __func__,  (addr), (data));
+	writel_relaxed((data), (addr));
+}
+
+/* This API is to write a block of data
+ * to same address
+ */
+int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base,
+	u32 len)
+{
+	int i;
+
+	if (!addr || !len || !base)
+		return -EINVAL;
+
+	for (i = 0; i < len; i++) {
+		CDBG("%s: len =%d val=%x base =%pK\n", __func__,
+			len, addr[i], base);
+		writel_relaxed(addr[i], base);
+	}
+	return 0;
+}
+
+/* This API is to write a block of registers
+ *  which is like a 2 dimensional array table with
+ *  register offset and data
+ */
+int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base,
+	u32 len)
+{
+	int i;
+
+	if (!addr || !len || !base)
+		return -EINVAL;
+
+	for (i = 0; i < len; i = i + 2) {
+		CDBG("%s: len =%d val=%x base =%pK reg=%x\n", __func__,
+			len, addr[i + 1], base,  addr[i]);
+		writel_relaxed(addr[i + 1], base + addr[i]);
+	}
+	return 0;
+}
+
+void msm_camera_io_w_mb(u32 data, void __iomem *addr)
+{
+	CDBG("%s: 0x%pK %08x\n", __func__,  (addr), (data));
+	/* ensure write is done */
+	wmb();
+	writel_relaxed((data), (addr));
+	/* ensure write is done */
+	wmb();
+}
+
+int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len)
+{
+	int i;
+
+	if (!addr || !len || !base)
+		return -EINVAL;
+
+	for (i = 0; i < len; i++) {
+		/* ensure write is done */
+		wmb();
+		CDBG("%s: len =%d val=%x base =%pK\n", __func__,
+			len, addr[i], base);
+		writel_relaxed(addr[i], base);
+	}
+	/* ensure last write is done */
+	wmb();
+	return 0;
+}
+
+u32 msm_camera_io_r(void __iomem *addr)
+{
+	uint32_t data = readl_relaxed(addr);
+
+	CDBG("%s: 0x%pK %08x\n", __func__,  (addr), (data));
+	return data;
+}
+
+u32 msm_camera_io_r_mb(void __iomem *addr)
+{
+	uint32_t data;
+	/* ensure read is done */
+	rmb();
+	data = readl_relaxed(addr);
+	/* ensure read is done */
+	rmb();
+	CDBG("%s: 0x%pK %08x\n", __func__,  (addr), (data));
+	return data;
+}
+
+static void msm_camera_io_memcpy_toio(void __iomem *dest_addr,
+	void *src_addr, u32 len)
+{
+	int i;
+	u32 __iomem *d = (u32 __iomem *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+
+	for (i = 0; i < len; i++)
+		writel_relaxed(*s++, d++);
+}
+
+int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry,
+	unsigned long min_usecs, unsigned long max_usecs)
+{
+	uint32_t tmp, cnt = 0;
+	int32_t rc = 0;
+
+	if (!addr)
+		return -EINVAL;
+
+	tmp = msm_camera_io_r(addr);
+	while ((tmp != wait_data) && (cnt++ < retry)) {
+		if (min_usecs > 0 && max_usecs > 0)
+			usleep_range(min_usecs, max_usecs);
+		tmp = msm_camera_io_r(addr);
+	}
+	if (cnt > retry) {
+		pr_debug("Poll failed by value\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data,
+	u32 bmask, u32 retry, unsigned long min_usecs, unsigned long max_usecs)
+{
+	uint32_t tmp, cnt = 0;
+	int32_t rc = 0;
+
+	if (!addr)
+		return -EINVAL;
+
+	tmp = msm_camera_io_r(addr);
+	while (((tmp & bmask) != wait_data) && (cnt++ < retry)) {
+		if (min_usecs > 0 && max_usecs > 0)
+			usleep_range(min_usecs, max_usecs);
+		tmp = msm_camera_io_r(addr);
+	}
+	if (cnt > retry) {
+		pr_debug("Poll failed with mask\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+void msm_camera_io_dump(void __iomem *addr, int size, int enable)
+{
+	char line_str[128];
+	int i;
+	ptrdiff_t p = 0;
+	size_t offset = 0, used = 0;
+	u32 data;
+
+	CDBG("%s: addr=%pK size=%d\n", __func__, addr, size);
+
+	if (!addr || (size <= 0) || !enable)
+		return;
+
+	line_str[0] = '\0';
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			used = snprintf(line_str + offset,
+				sizeof(line_str) - offset, "0x%04tX: ", p);
+			if (offset + used >= sizeof(line_str)) {
+				pr_err("%s\n", line_str);
+				offset = 0;
+				line_str[0] = '\0';
+			} else {
+				offset += used;
+			}
+		}
+		data = readl_relaxed(addr + p);
+		p = p + 4;
+		used = snprintf(line_str + offset,
+			sizeof(line_str) - offset, "%08x ", data);
+		if (offset + used >= sizeof(line_str)) {
+			pr_err("%s\n", line_str);
+			offset = 0;
+			line_str[0] = '\0';
+		} else {
+			offset += used;
+		}
+		if ((i + 1) % 4 == 0) {
+			pr_err("%s\n", line_str);
+			line_str[0] = '\0';
+			offset = 0;
+		}
+	}
+	if (line_str[0] != '\0')
+		pr_err("%s\n", line_str);
+}
+
+void msm_camera_io_dump_wstring_base(void __iomem *addr,
+	struct msm_cam_dump_string_info *dump_data,
+	int size)
+{
+	int i, u = sizeof(struct msm_cam_dump_string_info);
+
+	pr_debug("%s: addr=%pK data=%pK size=%d u=%d, cnt=%d\n", __func__,
+		addr, dump_data, size, u,
+		(size/u));
+
+	if (!addr || (size <= 0) || !dump_data) {
+		pr_err("%s: addr=%pK data=%pK size=%d\n", __func__,
+			addr, dump_data, size);
+		return;
+	}
+	for (i = 0; i < (size / u); i++)
+		pr_debug("%s 0x%x\n", (dump_data + i)->print,
+			readl_relaxed((dump_data + i)->offset + addr));
+}
+
+void msm_camera_io_memcpy(void __iomem *dest_addr,
+	void *src_addr, u32 len)
+{
+	CDBG("%s: %pK %pK %d\n", __func__, dest_addr, src_addr, len);
+	msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4);
+}
+
+void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
+	void *src_addr, u32 len)
+{
+	int i;
+	u32 __iomem *d = (u32 __iomem *) dest_addr;
+	u32 *s = (u32 *) src_addr;
+	/* This is generic function called who needs to register
+	 * writes with memory barrier
+	 */
+	wmb();
+	for (i = 0; i < (len / 4); i++) {
+		msm_camera_io_w(*s++, d++);
+		/* ensure write is done after every iteration */
+		wmb();
+	}
+}
+
+int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct msm_cam_clk_info *clk_src_info, int num_clk)
+{
+	int i;
+	int rc = 0;
+	struct clk *mux_clk = NULL;
+	struct clk *src_clk = NULL;
+
+	for (i = 0; i < num_clk; i++) {
+		if (clk_src_info[i].clk_name) {
+			mux_clk = clk_get(dev, clk_info[i].clk_name);
+			if (IS_ERR(mux_clk)) {
+				pr_err("%s get failed\n",
+					 clk_info[i].clk_name);
+				continue;
+			}
+			src_clk = clk_get(dev, clk_src_info[i].clk_name);
+			if (IS_ERR(src_clk)) {
+				pr_err("%s get failed\n",
+					clk_src_info[i].clk_name);
+				continue;
+			}
+			clk_set_parent(mux_clk, src_clk);
+		}
+	}
+	return rc;
+}
+
+int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct clk **clk_ptr, int num_clk, int enable)
+{
+	int i;
+	int rc = 0;
+	long clk_rate;
+
+	if (enable) {
+		for (i = 0; i < num_clk; i++) {
+			CDBG("%s enable %s\n", __func__, clk_info[i].clk_name);
+			clk_ptr[i] = clk_get(dev, clk_info[i].clk_name);
+			if (IS_ERR(clk_ptr[i])) {
+				pr_err("%s get failed\n", clk_info[i].clk_name);
+				rc = PTR_ERR(clk_ptr[i]);
+				goto cam_clk_get_err;
+			}
+			if (clk_info[i].clk_rate > 0) {
+				clk_rate = clk_round_rate(clk_ptr[i],
+					clk_info[i].clk_rate);
+				if (clk_rate < 0) {
+					pr_err("%s round failed\n",
+						   clk_info[i].clk_name);
+					goto cam_clk_set_err;
+				}
+				rc = clk_set_rate(clk_ptr[i],
+					clk_rate);
+				if (rc < 0) {
+					pr_err("%s set failed\n",
+						clk_info[i].clk_name);
+					goto cam_clk_set_err;
+				}
+
+			} else if (clk_info[i].clk_rate == INIT_RATE) {
+				clk_rate = clk_get_rate(clk_ptr[i]);
+				if (clk_rate == 0) {
+					clk_rate =
+						  clk_round_rate(clk_ptr[i], 0);
+					if (clk_rate < 0) {
+						pr_err("%s round rate failed\n",
+							  clk_info[i].clk_name);
+						goto cam_clk_set_err;
+					}
+					rc = clk_set_rate(clk_ptr[i],
+								clk_rate);
+					if (rc < 0) {
+						pr_err("%s set rate failed\n",
+							  clk_info[i].clk_name);
+						goto cam_clk_set_err;
+					}
+				}
+			}
+			rc = clk_prepare(clk_ptr[i]);
+			if (rc < 0) {
+				pr_err("%s prepare failed\n",
+					   clk_info[i].clk_name);
+				goto cam_clk_prepare_err;
+			}
+
+			rc = clk_enable(clk_ptr[i]);
+			if (rc < 0) {
+				pr_err("%s enable failed\n",
+					   clk_info[i].clk_name);
+				goto cam_clk_enable_err;
+			}
+			if (clk_info[i].delay > 20) {
+				msleep(clk_info[i].delay);
+			} else if (clk_info[i].delay) {
+				usleep_range(clk_info[i].delay * 1000,
+					(clk_info[i].delay * 1000) + 1000);
+			}
+		}
+	} else {
+		for (i = num_clk - 1; i >= 0; i--) {
+			if (clk_ptr[i] != NULL) {
+				CDBG("%s disable %s\n", __func__,
+					clk_info[i].clk_name);
+				clk_disable(clk_ptr[i]);
+				clk_unprepare(clk_ptr[i]);
+				clk_put(clk_ptr[i]);
+			}
+		}
+	}
+	return rc;
+
+
+cam_clk_enable_err:
+	clk_unprepare(clk_ptr[i]);
+cam_clk_prepare_err:
+cam_clk_set_err:
+	clk_put(clk_ptr[i]);
+cam_clk_get_err:
+	for (i--; i >= 0; i--) {
+		if (clk_ptr[i] != NULL) {
+			clk_disable(clk_ptr[i]);
+			clk_unprepare(clk_ptr[i]);
+			clk_put(clk_ptr[i]);
+		}
+	}
+	return rc;
+}
+
+int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int config)
+{
+	int i = 0, j = 0;
+	int rc = 0;
+	struct camera_vreg_t *curr_vreg;
+
+	if (num_vreg_seq > num_vreg) {
+		pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (!num_vreg_seq)
+		num_vreg_seq = num_vreg;
+
+	if ((cam_vreg == NULL) && num_vreg_seq) {
+		pr_err("%s:%d cam_vreg NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (config) {
+		for (i = 0; i < num_vreg_seq; i++) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			curr_vreg = &cam_vreg[j];
+			reg_ptr[j] = regulator_get(dev,
+				curr_vreg->reg_name);
+			if (IS_ERR_OR_NULL(reg_ptr[j])) {
+				pr_err("%s: %s get failed\n",
+					 __func__,
+					 curr_vreg->reg_name);
+				reg_ptr[j] = NULL;
+				goto vreg_get_fail;
+			}
+			if (regulator_count_voltages(reg_ptr[j]) > 0) {
+				rc = regulator_set_voltage(
+					reg_ptr[j],
+					curr_vreg->min_voltage,
+					curr_vreg->max_voltage);
+				if (rc < 0) {
+					pr_err("%s: %s set voltage failed\n",
+						__func__,
+						curr_vreg->reg_name);
+					goto vreg_set_voltage_fail;
+				}
+				if (curr_vreg->op_mode >= 0) {
+					rc = regulator_set_load(
+						reg_ptr[j],
+						curr_vreg->op_mode);
+					rc = 0;
+					if (rc < 0) {
+						pr_err(
+						"%s:%s set optimum mode fail\n",
+						__func__,
+						curr_vreg->reg_name);
+						goto vreg_set_opt_mode_fail;
+					}
+				}
+			}
+		}
+	} else {
+		for (i = num_vreg_seq-1; i >= 0; i--) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			curr_vreg = &cam_vreg[j];
+			if (reg_ptr[j]) {
+				if (regulator_count_voltages(reg_ptr[j]) > 0) {
+					if (curr_vreg->op_mode >= 0) {
+						regulator_set_load(
+							reg_ptr[j], 0);
+					}
+					regulator_set_voltage(
+						reg_ptr[j], 0, curr_vreg->
+						max_voltage);
+				}
+				regulator_put(reg_ptr[j]);
+				reg_ptr[j] = NULL;
+			}
+		}
+	}
+	return 0;
+
+vreg_unconfig:
+if (regulator_count_voltages(reg_ptr[j]) > 0)
+	regulator_set_load(reg_ptr[j], 0);
+
+vreg_set_opt_mode_fail:
+if (regulator_count_voltages(reg_ptr[j]) > 0)
+	regulator_set_voltage(reg_ptr[j], 0,
+		curr_vreg->max_voltage);
+
+vreg_set_voltage_fail:
+	regulator_put(reg_ptr[j]);
+	reg_ptr[j] = NULL;
+
+vreg_get_fail:
+	for (i--; i >= 0; i--) {
+		if (vreg_seq) {
+			j = vreg_seq[i];
+			if (j >= num_vreg)
+				continue;
+		} else
+			j = i;
+		curr_vreg = &cam_vreg[j];
+		goto vreg_unconfig;
+	}
+	return -ENODEV;
+}
+
+int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int enable)
+{
+	int i = 0, j = 0, rc = 0;
+
+	if (num_vreg_seq > num_vreg) {
+		pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (!num_vreg_seq)
+		num_vreg_seq = num_vreg;
+
+	if (enable) {
+		for (i = 0; i < num_vreg_seq; i++) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			if (IS_ERR_OR_NULL(reg_ptr[j])) {
+				pr_err("%s: %s null regulator\n",
+					__func__, cam_vreg[j].reg_name);
+				goto disable_vreg;
+			}
+			rc = regulator_enable(reg_ptr[j]);
+			if (rc < 0) {
+				pr_err("%s: %s enable failed\n",
+					__func__, cam_vreg[j].reg_name);
+				goto disable_vreg;
+			}
+			if (cam_vreg[j].delay > 20)
+				msleep(cam_vreg[j].delay);
+			else if (cam_vreg[j].delay)
+				usleep_range(cam_vreg[j].delay * 1000,
+					(cam_vreg[j].delay * 1000) + 1000);
+		}
+	} else {
+		for (i = num_vreg_seq-1; i >= 0; i--) {
+			if (vreg_seq) {
+				j = vreg_seq[i];
+				if (j >= num_vreg)
+					continue;
+			} else
+				j = i;
+			if (reg_ptr[j]) {
+				regulator_disable(reg_ptr[j]);
+				if (cam_vreg[j].delay > 20)
+					msleep(cam_vreg[j].delay);
+				else if (cam_vreg[j].delay)
+					usleep_range(
+						cam_vreg[j].delay * 1000,
+						(cam_vreg[j].delay * 1000)
+						+ 1000);
+			}
+		}
+	}
+	return rc;
+disable_vreg:
+	for (i--; i >= 0; i--) {
+		if (vreg_seq) {
+			j = vreg_seq[i];
+			if (j >= num_vreg)
+				continue;
+		} else
+			j = i;
+		regulator_disable(reg_ptr[j]);
+		if (cam_vreg[j].delay > 20)
+			msleep(cam_vreg[j].delay);
+		else if (cam_vreg[j].delay)
+			usleep_range(cam_vreg[j].delay * 1000,
+				(cam_vreg[j].delay * 1000) + 1000);
+	}
+	return rc;
+}
+
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting)
+{
+	int rc = 0;
+
+	if (!bus_perf_client) {
+		pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+		return;
+	}
+	switch (perf_setting) {
+	case S_EXIT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		msm_bus_scale_unregister_client(bus_perf_client);
+		break;
+	case S_PREVIEW:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+		break;
+	case S_VIDEO:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
+		break;
+	case S_CAPTURE:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
+		break;
+	case S_ZSL:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
+		break;
+	case S_LIVESHOT:
+		rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
+		break;
+	case S_DEFAULT:
+		break;
+	default:
+		pr_err("%s: INVALID CASE\n", __func__);
+	}
+}
+
+int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
+	uint8_t gpio_tbl_size, int gpio_en)
+{
+	int rc = 0, i;
+
+	if (gpio_en) {
+		for (i = 0; i < gpio_tbl_size; i++) {
+			gpio_set_value_cansleep(gpio_tbl[i].gpio,
+				gpio_tbl[i].flags);
+			usleep_range(gpio_tbl[i].delay,
+				gpio_tbl[i].delay + 1000);
+		}
+	} else {
+		for (i = gpio_tbl_size - 1; i >= 0; i--) {
+			if (gpio_tbl[i].flags)
+				gpio_set_value_cansleep(gpio_tbl[i].gpio,
+					GPIOF_OUT_INIT_LOW);
+		}
+	}
+	return rc;
+}
+
+int msm_camera_config_single_vreg(struct device *dev,
+	struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config)
+{
+	int rc = 0;
+	const char *vreg_name = NULL;
+
+	if (!dev || !cam_vreg || !reg_ptr) {
+		pr_err("%s: get failed NULL parameter\n", __func__);
+		goto vreg_get_fail;
+	}
+	if (cam_vreg->type == VREG_TYPE_CUSTOM) {
+		if (cam_vreg->custom_vreg_name == NULL) {
+			pr_err("%s : can't find sub reg name",
+				__func__);
+			goto vreg_get_fail;
+		}
+		vreg_name = cam_vreg->custom_vreg_name;
+	} else {
+		if (cam_vreg->reg_name == NULL) {
+			pr_err("%s : can't find reg name", __func__);
+			goto vreg_get_fail;
+		}
+		vreg_name = cam_vreg->reg_name;
+	}
+
+	if (config) {
+		CDBG("%s enable %s\n", __func__, vreg_name);
+		*reg_ptr = regulator_get(dev, vreg_name);
+		if (IS_ERR(*reg_ptr)) {
+			pr_err("%s: %s get failed\n", __func__, vreg_name);
+			*reg_ptr = NULL;
+			goto vreg_get_fail;
+		}
+		if (regulator_count_voltages(*reg_ptr) > 0) {
+			CDBG("%s: voltage min=%d, max=%d\n",
+				__func__, cam_vreg->min_voltage,
+				cam_vreg->max_voltage);
+			rc = regulator_set_voltage(
+				*reg_ptr, cam_vreg->min_voltage,
+				cam_vreg->max_voltage);
+			if (rc < 0) {
+				pr_err("%s: %s set voltage failed\n",
+					__func__, vreg_name);
+				goto vreg_set_voltage_fail;
+			}
+			if (cam_vreg->op_mode >= 0) {
+				rc = regulator_set_load(*reg_ptr,
+					cam_vreg->op_mode);
+				if (rc < 0) {
+					pr_err(
+					"%s: %s set optimum mode failed\n",
+					__func__, vreg_name);
+					goto vreg_set_opt_mode_fail;
+				}
+			}
+		}
+		rc = regulator_enable(*reg_ptr);
+		if (rc < 0) {
+			pr_err("%s: %s regulator_enable failed\n", __func__,
+				vreg_name);
+			goto vreg_unconfig;
+		}
+	} else {
+		CDBG("%s disable %s\n", __func__, vreg_name);
+		if (*reg_ptr) {
+			CDBG("%s disable %s\n", __func__, vreg_name);
+			regulator_disable(*reg_ptr);
+			if (regulator_count_voltages(*reg_ptr) > 0) {
+				if (cam_vreg->op_mode >= 0)
+					regulator_set_load(*reg_ptr, 0);
+				regulator_set_voltage(
+					*reg_ptr, 0, cam_vreg->max_voltage);
+			}
+			regulator_put(*reg_ptr);
+			*reg_ptr = NULL;
+		} else {
+			pr_err("%s can't disable %s\n", __func__, vreg_name);
+		}
+	}
+	return 0;
+
+vreg_unconfig:
+if (regulator_count_voltages(*reg_ptr) > 0)
+	regulator_set_load(*reg_ptr, 0);
+
+vreg_set_opt_mode_fail:
+if (regulator_count_voltages(*reg_ptr) > 0)
+	regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage);
+
+vreg_set_voltage_fail:
+	regulator_put(*reg_ptr);
+	*reg_ptr = NULL;
+
+vreg_get_fail:
+	return -ENODEV;
+}
+
+int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
+	int gpio_en)
+{
+	int rc = 0, i = 0, err = 0;
+
+	if (!gpio_tbl || !size) {
+		pr_err("%s:%d invalid gpio_tbl %pK / size %d\n", __func__,
+			__LINE__, gpio_tbl, size);
+		return -EINVAL;
+	}
+	for (i = 0; i < size; i++) {
+		CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i,
+			gpio_tbl[i].gpio, gpio_tbl[i].flags);
+	}
+	if (gpio_en) {
+		for (i = 0; i < size; i++) {
+			err = gpio_request_one(gpio_tbl[i].gpio,
+				gpio_tbl[i].flags, gpio_tbl[i].label);
+			if (err) {
+				/*
+				 * After GPIO request fails, contine to
+				 * apply new gpios, outout a error message
+				 * for driver bringup debug
+				 */
+				pr_err("%s:%d gpio %d:%s request fails\n",
+					__func__, __LINE__,
+					gpio_tbl[i].gpio, gpio_tbl[i].label);
+			}
+		}
+	} else {
+		gpio_free_array(gpio_tbl, size);
+	}
+	return rc;
+}
+
+/*
+ * msm_camera_get_dt_reg_settings - Get dt reg settings from device-tree.
+ * @of_node: Pointer to device of_node from dev.
+ * @dt_prop_name: String of the property to search in of_node from dev.
+ * @reg_s: Double pointer will be allocated by this function and filled.
+ * @size: Pointer to fill the length of the available entries.
+ */
+int msm_camera_get_dt_reg_settings(struct device_node *of_node,
+	const char *dt_prop_name, uint32_t **reg_s,
+	unsigned int *size)
+{
+	int ret;
+	unsigned int cnt;
+
+	if (!of_node || !dt_prop_name || !size || !reg_s) {
+		pr_err("%s: Error invalid args %pK:%pK:%pK:%pK\n",
+			__func__, size, reg_s, of_node, dt_prop_name);
+		return -EINVAL;
+	}
+	if (!of_get_property(of_node, dt_prop_name, &cnt)) {
+		pr_debug("Missing dt reg settings for %s\n", dt_prop_name);
+		return -ENOENT;
+	}
+
+	if (!cnt || (cnt % 8)) {
+		pr_err("%s: Error invalid number of entries cnt=%d\n",
+			__func__, cnt);
+		return -EINVAL;
+	}
+	cnt /= 4;
+	if (cnt != 0) {
+		*reg_s = kcalloc(cnt, sizeof(uint32_t),
+				GFP_KERNEL);
+		if (!*reg_s)
+			return -ENOMEM;
+		ret = of_property_read_u32_array(of_node,
+				dt_prop_name,
+				*reg_s,
+				cnt);
+		if (ret < 0) {
+			pr_err("%s: No dt reg info read for %s ret=%d\n",
+				__func__, dt_prop_name, ret);
+			kfree(*reg_s);
+			return -ENOENT;
+		}
+		*size = cnt;
+	} else {
+		pr_err("%s: Error invalid entries\n", __func__);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * msm_camera_get_dt_reg_settings - Free dt reg settings memory.
+ * @reg_s: Double pointer will be allocated by this function and filled.
+ * @size: Pointer to set the length as invalid.
+ */
+void msm_camera_put_dt_reg_settings(uint32_t **reg_s,
+	unsigned int *size)
+{
+	kfree(*reg_s);
+	*reg_s = NULL;
+	*size = 0;
+}
+
+int msm_camera_hw_write_dt_reg_settings(void __iomem *base,
+	uint32_t *reg_s,
+	unsigned int size)
+{
+	int32_t rc = 0;
+
+	if (!reg_s || !base || !size) {
+		pr_err("%s: Error invalid args\n", __func__);
+		return -EINVAL;
+	}
+	rc = msm_camera_io_w_reg_block((const u32 *) reg_s,
+		base, size);
+	if (rc < 0)
+		pr_err("%s: Failed dt reg setting write\n", __func__);
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h
new file mode 100644
index 0000000..77809d2
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2011-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CAMERA_IO_UTIL_H
+#define __MSM_CAMERA_IO_UTIL_H
+
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <soc/qcom/camera2.h>
+#include <media/msm_cam_sensor.h>
+#include <media/v4l2-ioctl.h>
+
+#define NO_SET_RATE -1
+#define INIT_RATE -2
+
+struct msm_gpio_set_tbl {
+	unsigned int gpio;
+	unsigned long flags;
+	uint32_t delay;
+};
+
+struct msm_cam_dump_string_info {
+	const char *print;
+	uint32_t offset;
+};
+
+void msm_camera_io_w(u32 data, void __iomem *addr);
+void msm_camera_io_w_mb(u32 data, void __iomem *addr);
+u32 msm_camera_io_r(void __iomem *addr);
+u32 msm_camera_io_r_mb(void __iomem *addr);
+void msm_camera_io_dump(void __iomem *addr, int size, int enable);
+void msm_camera_io_memcpy(void __iomem *dest_addr,
+		void *src_addr, u32 len);
+void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
+	void *src_addr, u32 len);
+int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct msm_cam_clk_info *clk_src_info, int num_clk);
+int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct clk **clk_ptr, int num_clk, int enable);
+
+int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int config);
+int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+		int num_vreg_seq, struct regulator **reg_ptr, int enable);
+
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+		enum msm_bus_perf_setting perf_setting);
+
+int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
+	uint8_t gpio_tbl_size, int gpio_en);
+
+void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags,
+	int gpio_en);
+
+int msm_camera_config_single_vreg(struct device *dev,
+	struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config);
+
+int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
+	int gpio_en);
+void msm_camera_io_dump_wstring_base(void __iomem *addr,
+	struct msm_cam_dump_string_info *dump_data,
+	int size);
+int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data,
+	u32 bmask, u32 retry, unsigned long min_usecs,
+	unsigned long max_usecs);
+int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry,
+	unsigned long min_usecs, unsigned long max_usecs);
+int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base, u32 len);
+int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base, u32 len);
+int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len);
+int msm_camera_get_dt_reg_settings(struct device_node *of_node,
+	const char *dt_prop_name, uint32_t **reg_s,
+	unsigned int *size);
+void msm_camera_put_dt_reg_settings(uint32_t **reg_s,
+	unsigned int *size);
+int msm_camera_hw_write_dt_reg_settings(void __iomem *base,
+	uint32_t *reg_s,
+	unsigned int size);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c
new file mode 100644
index 0000000..22f4891
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c
@@ -0,0 +1,354 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <soc/qcom/camera2.h>
+#include "qseecom_kernel.h"
+#include "msm_camera_tz_util.h"
+
+#define EMPTY_QSEECOM_HANDLE    NULL
+#define QSEECOM_SBUFF_SIZE      SZ_128K
+
+#define MSM_CAMERA_TZ_UTIL_VERBOSE
+
+#define MSM_CAMERA_TZ_BOOT_PROTECTED (false)
+
+/* Update version major number in case the HLOS-TA interface is changed*/
+#define TA_IF_VERSION_MAJ	    1
+#define TA_IF_VERSION_MIN	    2
+
+#undef CDBG
+#ifdef MSM_CAMERA_TZ_UTIL_VERBOSE
+	#define CDBG(fmt, args...) \
+		pr_info(CONFIG_MSM_SEC_CCI_TA_NAME "::%s:%d - " fmt,\
+		__func__, __LINE__, ##args)
+#else /* MSM_CAMERA_TZ_UTIL_VERBOSE */
+	#define CDBG(fmt, args...) \
+		pr_debug("%s:%d - " fmt,  __func__, __LINE__, ##args)
+#endif /* MSM_CAMERA_TZ_UTIL_VERBOSE */
+
+#pragma pack(push, msm_camera_tz_util, 1)
+
+/* MSM_CAMERA_TZ_CMD_GET_IF_VERSION */
+#define msm_camera_tz_i2c_get_if_version_req_t msm_camera_tz_generic_req_t
+
+struct msm_camera_tz_i2c_get_if_version_rsp_t {
+	enum msm_camera_tz_status_t rc;
+	uint32_t                    if_version_maj;
+	uint32_t                    if_version_min;
+};
+
+/* MSM_CAMERA_TZ_CMD_SET_MODE */
+struct msm_camera_tz_set_mode_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	uint32_t                    mode;
+	uint32_t                    hw_block;
+};
+
+#define msm_camera_tz_set_mode_rsp_t msm_camera_tz_generic_rsp_t
+
+#pragma pack(pop, msm_camera_tz_util)
+
+/* TA communication control structure */
+struct msm_camera_tz_ctrl_t {
+	uint32_t                ta_enabled;
+	struct qseecom_handle   *ta_qseecom_handle;
+	const char              *ta_name;
+	uint32_t                secure_hw_blocks;
+};
+
+static struct msm_camera_tz_ctrl_t msm_camera_tz_ctrl = {
+	0, NULL, CONFIG_MSM_CAMERA_TZ_TA_NAME, 0
+};
+
+static DEFINE_MUTEX(msm_camera_tz_util_lock);
+
+struct qseecom_handle *msm_camera_tz_get_ta_handle(void)
+{
+	return msm_camera_tz_ctrl.ta_qseecom_handle;
+}
+
+void msm_camera_tz_lock(void)
+{
+	mutex_lock(&msm_camera_tz_util_lock);
+}
+
+void msm_camera_tz_unlock(void)
+{
+	mutex_unlock(&msm_camera_tz_util_lock);
+}
+
+int32_t get_cmd_rsp_buffers(
+	struct qseecom_handle *ta_qseecom_handle,
+	void **cmd,	int *cmd_len,
+	void **rsp,	int *rsp_len)
+{
+	if ((ta_qseecom_handle == NULL) ||
+		(cmd == NULL) || (cmd_len == NULL) ||
+		(rsp == NULL) || (rsp_len == NULL)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (*cmd_len & QSEECOM_ALIGN_MASK)
+		*cmd_len = QSEECOM_ALIGN(*cmd_len);
+
+	if (*rsp_len & QSEECOM_ALIGN_MASK)
+		*rsp_len = QSEECOM_ALIGN(*rsp_len);
+
+	if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) {
+		pr_err("%s:%d - Shared buffer too small to hold cmd=%d and rsp=%d\n",
+			__func__, __LINE__,
+			*cmd_len, *rsp_len);
+		return -ENOMEM;
+	}
+
+	*cmd = ta_qseecom_handle->sbuf;
+	*rsp = ta_qseecom_handle->sbuf + *cmd_len;
+	return 0;
+}
+
+static int32_t msm_camera_tz_i2c_ta_get_if_version(
+	struct qseecom_handle *ta_qseecom_handle,
+	uint32_t *if_version_maj,
+	uint32_t *if_version_min)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_get_if_version_req_t *cmd;
+	struct msm_camera_tz_i2c_get_if_version_rsp_t *rsp;
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	if ((ta_qseecom_handle == NULL) ||
+		(if_version_maj == NULL) || (if_version_min == NULL)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	cmd_len = sizeof(struct msm_camera_tz_i2c_get_if_version_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_get_if_version_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_GET_IF_VERSION;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Unable to get if version info, rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+
+		if (rsp->rc < 0) {
+			CDBG("TZ App error, rc=%d\n", rsp->rc);
+			rc = -EFAULT;
+		} else {
+			*if_version_maj = rsp->if_version_maj;
+			*if_version_min = rsp->if_version_min;
+			CDBG("TZ If version %d.%d\n", *if_version_maj,
+				*if_version_min);
+		}
+	}
+	return rc;
+}
+
+int32_t msm_camera_tz_load_ta(void)
+{
+	int32_t rc = 0;
+
+	if (MSM_CAMERA_TZ_BOOT_PROTECTED &&
+		msm_camera_tz_ctrl.ta_enabled > 0) {
+		CDBG("TA loaded from boot(TA %s - %d)\n",
+			msm_camera_tz_ctrl.ta_name,
+			msm_camera_tz_ctrl.ta_enabled);
+		return 0;
+	}
+
+	CDBG("Enter (TA name = %s, %d)\n",
+		msm_camera_tz_ctrl.ta_name,
+		msm_camera_tz_ctrl.ta_enabled);
+
+	msm_camera_tz_lock();
+	if (msm_camera_tz_ctrl.ta_enabled == 0) {
+		ktime_t startTime = ktime_get();
+
+		/* Start the TA */
+		if ((msm_camera_tz_ctrl.ta_qseecom_handle == NULL) &&
+			(msm_camera_tz_ctrl.ta_name != NULL) &&
+			('\0' != msm_camera_tz_ctrl.ta_name[0])) {
+			uint32_t if_version_maj = 0;
+			uint32_t if_version_min = 0;
+
+			rc = qseecom_start_app(
+				&msm_camera_tz_ctrl.ta_qseecom_handle,
+				(char *)msm_camera_tz_ctrl.ta_name,
+				QSEECOM_SBUFF_SIZE);
+			if (!rc)
+				rc = msm_camera_tz_i2c_ta_get_if_version(
+					msm_camera_tz_ctrl.ta_qseecom_handle,
+					&if_version_maj, &if_version_min);
+
+			if (!rc) {
+				if (if_version_maj != TA_IF_VERSION_MAJ) {
+					CDBG("TA ver mismatch %d.%d != %d.%d\n",
+						if_version_maj, if_version_min,
+						TA_IF_VERSION_MAJ,
+						TA_IF_VERSION_MIN);
+					rc = qseecom_shutdown_app(
+						&msm_camera_tz_ctrl.
+							ta_qseecom_handle);
+					msm_camera_tz_ctrl.ta_qseecom_handle
+						= EMPTY_QSEECOM_HANDLE;
+					rc = -EFAULT;
+				} else {
+					msm_camera_tz_ctrl.ta_enabled = 1;
+				}
+			}
+		}
+		CDBG("Load TA %s - %s(%d) - %lluus\n",
+			msm_camera_tz_ctrl.ta_name,
+			(msm_camera_tz_ctrl.ta_enabled)?"Ok" :
+			"Failed", rc,
+			ktime_us_delta(ktime_get(),	startTime));
+	} else {
+		msm_camera_tz_ctrl.ta_enabled++;
+		CDBG("TA already loaded (TA %s - %d)\n",
+			msm_camera_tz_ctrl.ta_name,
+			msm_camera_tz_ctrl.ta_enabled);
+	}
+	msm_camera_tz_unlock();
+	return rc;
+}
+
+int32_t msm_camera_tz_unload_ta(void)
+{
+	int32_t rc = -EFAULT;
+
+	if (MSM_CAMERA_TZ_BOOT_PROTECTED) {
+		CDBG("TA loaded from boot(TA %s - %d)\n",
+			msm_camera_tz_ctrl.ta_name,
+			msm_camera_tz_ctrl.ta_enabled);
+		return 0;
+	}
+
+	CDBG("Enter (TA name = %s, %d)\n",
+		msm_camera_tz_ctrl.ta_name,
+		msm_camera_tz_ctrl.ta_enabled);
+
+	msm_camera_tz_lock();
+	if (msm_camera_tz_ctrl.ta_enabled == 1) {
+		ktime_t startTime = ktime_get();
+
+		rc = qseecom_shutdown_app(&msm_camera_tz_ctrl.
+			ta_qseecom_handle);
+		msm_camera_tz_ctrl.ta_qseecom_handle
+			= EMPTY_QSEECOM_HANDLE;
+		msm_camera_tz_ctrl.ta_enabled = 0;
+		CDBG("Unload TA %s - %s(%d) - %lluus\n",
+			msm_camera_tz_ctrl.ta_name,
+			(!rc)?"Ok":"Failed", rc,
+			ktime_us_delta(ktime_get(), startTime));
+	} else {
+		msm_camera_tz_ctrl.ta_enabled--;
+		CDBG("TA still loaded (TA %s - %d)\n",
+			msm_camera_tz_ctrl.ta_name,
+			msm_camera_tz_ctrl.ta_enabled);
+	}
+	msm_camera_tz_unlock();
+	return rc;
+}
+
+static int32_t msm_camera_tz_ta_set_mode(uint32_t mode,
+	uint32_t hw_block)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_set_mode_req_t *cmd;
+	struct msm_camera_tz_set_mode_rsp_t *rsp;
+	int32_t rc = 0;
+	struct qseecom_handle *ta_qseecom_handle =
+		msm_camera_tz_get_ta_handle();
+	ktime_t startTime = ktime_get();
+
+	if (ta_qseecom_handle == NULL) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	cmd_len = sizeof(struct msm_camera_tz_set_mode_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_set_mode_rsp_t);
+
+	msm_camera_tz_lock();
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_SET_MODE;
+		cmd->mode = mode;
+		cmd->hw_block = hw_block;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed: rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			msm_camera_tz_unlock();
+			return rc;
+		}
+		rc = rsp->rc;
+	}
+	msm_camera_tz_unlock();
+	CDBG("Done: rc=%d, Mode=0x%08X - %lluus\n",
+		rc, mode,
+		ktime_us_delta(ktime_get(), startTime));
+	return rc;
+}
+
+uint32_t msm_camera_tz_set_mode(uint32_t mode,
+	uint32_t hw_block)
+{
+	uint32_t rc = 0;
+
+	switch (mode) {
+	case MSM_CAMERA_TZ_MODE_SECURE:
+		rc = msm_camera_tz_load_ta();
+		if (!rc) {
+			rc = msm_camera_tz_ta_set_mode(mode, hw_block);
+			if (rc)
+				msm_camera_tz_ctrl.secure_hw_blocks |= hw_block;
+		}
+		break;
+	case MSM_CAMERA_TZ_MODE_NON_SECURE:
+		msm_camera_tz_ta_set_mode(mode, hw_block);
+		if (rc)
+			msm_camera_tz_ctrl.secure_hw_blocks &= ~hw_block;
+		rc = msm_camera_tz_unload_ta();
+		break;
+	default:
+		pr_err("%s:%d - Incorrect mode: %d (hw: 0x%08X)\n",
+			__func__, __LINE__,
+			mode, hw_block);
+		return -EINVAL;
+	}
+	CDBG("Set Mode - rc=%d, Mode: 0x%08X\n",
+		rc, mode);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.h b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.h
new file mode 100644
index 0000000..8a64af9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CAMERA_TZ_UTIL_H
+#define __MSM_CAMERA_TZ_UTIL_H
+
+#include <soc/qcom/camera2.h>
+
+#ifndef CONFIG_MSM_CAMERA_TZ_TA_NAME
+#define CONFIG_MSM_CAMERA_TZ_TA_NAME  "seccamdemo64"
+#endif /* CONFIG_MSM_CAMERA_TZ_TA_NAME */
+
+#define MSM_CAMERA_TZ_MODE_NON_SECURE   0x0000000000
+#define MSM_CAMERA_TZ_MODE_SECURE       0x0000000001
+
+#define MSM_CAMERA_TZ_HW_BLOCK_CSIDCORE 0x0000000001
+#define MSM_CAMERA_TZ_HW_BLOCK_ISPIF    0x0000000002
+#define MSM_CAMERA_TZ_HW_BLOCK_CCI      0x0000000004
+#define MSM_CAMERA_TZ_HW_BLOCK_ISP      0x0000000008
+#define MSM_CAMERA_TZ_HW_BLOCK_CPP      0x0000000010
+
+enum msm_camera_tz_cmd_id_t {
+	MSM_CAMERA_TZ_CMD_NONE,
+	MSM_CAMERA_TZ_CMD_GET_IF_VERSION,
+	MSM_CAMERA_TZ_CMD_POWER_UP,
+	MSM_CAMERA_TZ_CMD_POWER_DOWN,
+	MSM_CAMERA_TZ_CMD_CCI_GENERIC,
+	MSM_CAMERA_TZ_CMD_CCI_READ,
+	MSM_CAMERA_TZ_CMD_CCI_READ_SEQ,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_SEQ,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_ASYNC,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_SYNC,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_SYNC_BLOCK,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_SEQ_TABLE,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_W_MICRODELAY,
+	MSM_CAMERA_TZ_CMD_CCI_POLL,
+	MSM_CAMERA_TZ_CMD_CCI_WRITE_CONF_TBL,
+	MSM_CAMERA_TZ_CMD_CCI_UTIL,
+	MSM_CAMERA_TZ_CMD_SET_MODE,
+	MSM_CAMERA_TZ_CMD_FRAME_NOTIFICATION,
+};
+
+enum msm_camera_tz_status_t {
+	MSM_CAMERA_TZ_STATUS_SUCCESS = 0,
+	MSM_CAMERA_TZ_STATUS_GENERAL_FAILURE = -1,
+	MSM_CAMERA_TZ_STATUS_INVALID_INPUT_PARAMS = -2,
+	MSM_CAMERA_TZ_STATUS_INVALID_SENSOR_ID = -3,
+	MSM_CAMERA_TZ_STATUS_BYPASS = -4,
+	MSM_CAMERA_TZ_STATUS_TIMEOUT = -5,
+
+	MSM_CAMERA_TZ_STATUS_RESET_DONE = 1,
+	MSM_CAMERA_TZ_STATUS_ERR_SIZE = 0x7FFFFFFF
+};
+
+#pragma pack(push, msm_camera_tz, 1)
+
+struct msm_camera_tz_generic_req_t {
+	enum msm_camera_tz_cmd_id_t  cmd_id;
+};
+
+struct msm_camera_tz_generic_rsp_t {
+	enum msm_camera_tz_status_t  rc;
+};
+
+#pragma pack(pop, msm_camera_tz)
+
+uint32_t msm_camera_tz_set_mode(
+	uint32_t mode, uint32_t hw_block);
+
+struct qseecom_handle *msm_camera_tz_get_ta_handle(void);
+int32_t get_cmd_rsp_buffers(
+	struct qseecom_handle *ta_qseecom_handle,
+	void **cmd, int *cmd_len,
+	void **rsp, int *rsp_len);
+int32_t msm_camera_tz_load_ta(void);
+int32_t msm_camera_tz_unload_ta(void);
+void msm_camera_tz_lock(void);
+void msm_camera_tz_unlock(void);
+
+#endif /* __MSM_CAMERA_TZ_UTIL_H */
diff --git a/drivers/media/platform/msm/camera_v2/fd/Makefile b/drivers/media/platform/msm/camera_v2/fd/Makefile
new file mode 100644
index 0000000..8d01d3a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/Makefile
@@ -0,0 +1,8 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc/cpp
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_buf_mgr/
+
+obj-$(CONFIG_MSM_FD) += msm_fd_dev.o msm_fd_hw.o
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
new file mode 100644
index 0000000..eb5bdee
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
@@ -0,0 +1,1492 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ion.h>
+#include <linux/msm_ion.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-v4l2.h>
+#include <linux/clk/msm-clk.h>
+
+#include "msm_fd_dev.h"
+#include "msm_fd_hw.h"
+#include "msm_fd_regs.h"
+
+#define MSM_FD_DRV_NAME "msm_fd"
+
+#define MSM_FD_WORD_SIZE_BYTES 4
+
+/* Face detection thresholds definitions */
+#define MSM_FD_DEF_THRESHOLD 5
+#define MSM_FD_MAX_THRESHOLD_VALUE 9
+
+/* Face angle lookup table */
+#define MSM_FD_DEF_ANGLE_IDX 2
+static int msm_fd_angle[] = {45, 135, 359};
+
+/* Face direction lookup table */
+#define MSM_FD_DEF_DIR_IDX 0
+static int msm_fd_dir[] = {0, 90, 270, 180};
+
+/* Minimum face size lookup table */
+#define MSM_FD_DEF_MIN_SIZE_IDX 0
+static int msm_fd_min_size[] = {20, 25, 32, 40};
+
+/* Face detection size lookup table */
+static struct msm_fd_size fd_size[] = {
+	{
+		.width    = 320,
+		.height   = 240,
+		.reg_val  = MSM_FD_IMAGE_SIZE_QVGA,
+		.work_size = (13120 * MSM_FD_WORD_SIZE_BYTES),
+	},
+	{
+		.width    = 427,
+		.height   = 240,
+		.reg_val  = MSM_FD_IMAGE_SIZE_WQVGA,
+		.work_size = (17744 * MSM_FD_WORD_SIZE_BYTES),
+	},
+	{
+		.width     = 640,
+		.height    = 480,
+		.reg_val   = MSM_FD_IMAGE_SIZE_VGA,
+		.work_size = (52624 * MSM_FD_WORD_SIZE_BYTES),
+	},
+	{
+		.width     = 854,
+		.height    = 480,
+		.reg_val   = MSM_FD_IMAGE_SIZE_WVGA,
+		.work_size = (70560 * MSM_FD_WORD_SIZE_BYTES),
+	},
+};
+
+/*
+ * msm_fd_ctx_from_fh - Get fd context from v4l2 fh.
+ * @fh: Pointer to v4l2 fh.
+ */
+static inline struct fd_ctx *msm_fd_ctx_from_fh(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct fd_ctx, fh);
+}
+
+/*
+ * msm_fd_get_format_index - Get format index from v4l2 format.
+ * @f: Pointer to v4l2 format struct.
+ */
+static int msm_fd_get_format_index(struct v4l2_format *f)
+{
+	int index;
+
+	for (index = 0; index < ARRAY_SIZE(fd_size); index++) {
+		if (f->fmt.pix.width <= fd_size[index].width &&
+		    f->fmt.pix.height <= fd_size[index].height)
+			return index;
+	}
+	return index - 1;
+}
+
+/*
+ * msm_fd_get_idx_from_value - Get array index from value.
+ * @value: Value for which index is needed.
+ * @array: Array in which index is searched for.
+ * @array_size: Array size.
+ */
+static int msm_fd_get_idx_from_value(int value, int *array, int array_size)
+{
+	int index;
+	int i;
+
+	index = 0;
+	for (i = 1; i < array_size; i++) {
+		if (value == array[i]) {
+			index = i;
+			break;
+		}
+		if (abs(value - array[i]) < abs(value - array[index]))
+			index = i;
+	}
+	return index;
+}
+
+/*
+ * msm_fd_fill_format_from_index - Fill v4l2 format struct from size index.
+ * @f: Pointer of v4l2 struct which will be filled.
+ * @index: Size index (Format will be filled based on this index).
+ */
+static int msm_fd_fill_format_from_index(struct v4l2_format *f, int index)
+{
+	f->fmt.pix.width = fd_size[index].width;
+	f->fmt.pix.height = fd_size[index].height;
+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
+	if (f->fmt.pix.bytesperline < f->fmt.pix.width)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+
+	f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, 16);
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+/*
+ * msm_fd_fill_format_from_ctx - Fill v4l2 format struct from fd context.
+ * @f: Pointer of v4l2 struct which will be filled.
+ * @c: Pointer to fd context.
+ */
+static int msm_fd_fill_format_from_ctx(struct v4l2_format *f, struct fd_ctx *c)
+{
+	if (c->format.size == NULL)
+		return -EINVAL;
+
+	f->fmt.pix.width = c->format.size->width;
+	f->fmt.pix.height = c->format.size->height;
+	f->fmt.pix.pixelformat = c->format.pixelformat;
+	f->fmt.pix.bytesperline = c->format.bytesperline;
+	f->fmt.pix.sizeimage = c->format.sizeimage;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+/*
+ * msm_fd_queue_setup - vb2_ops queue_setup callback.
+ * @q: Pointer to vb2 queue struct.
+ * @fmt: Pointer to v4l2 format struct (NULL is valid argument).
+ * @num_buffers: Pointer of number of buffers requested.
+ * @num_planes: Pointer to number of planes requested.
+ * @sizes: Array containing sizes of planes.
+ * @alloc_ctxs: Array of allocated contexts for each plane.
+ */
+static int msm_fd_queue_setup(struct vb2_queue *q,
+//	const void *parg,
+	unsigned int *num_buffers, unsigned int *num_planes,
+	unsigned int sizes[], struct device *alloc_ctxs[])
+{
+	struct fd_ctx *ctx = vb2_get_drv_priv(q);
+	//const struct v4l2_format *fmt = parg;
+	const struct v4l2_format *fmt = NULL;
+
+	*num_planes = 1;
+
+	if (fmt == NULL)
+		sizes[0] = ctx->format.sizeimage;
+	else
+		sizes[0] = fmt->fmt.pix.sizeimage;
+
+	alloc_ctxs[0] = (struct device *)&ctx->mem_pool;
+
+	return 0;
+}
+
+/*
+ * msm_fd_buf_init - vb2_ops buf_init callback.
+ * @vb: Pointer to vb2 buffer struct.
+ */
+static int msm_fd_buf_init(struct vb2_buffer *vb)
+{
+	struct msm_fd_buffer *fd_buffer =
+		(struct msm_fd_buffer *)vb;
+
+	INIT_LIST_HEAD(&fd_buffer->list);
+	atomic_set(&fd_buffer->active, 0);
+
+	return 0;
+}
+
+/*
+ * msm_fd_buf_queue - vb2_ops buf_queue callback.
+ * @vb: Pointer to vb2 buffer struct.
+ */
+static void msm_fd_buf_queue(struct vb2_buffer *vb)
+{
+	struct fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct msm_fd_buffer *fd_buffer =
+		(struct msm_fd_buffer *)vb;
+
+	fd_buffer->format = ctx->format;
+	fd_buffer->settings = ctx->settings;
+	fd_buffer->work_addr = ctx->work_buf.addr;
+	msm_fd_hw_add_buffer(ctx->fd_device, fd_buffer);
+
+	if (vb->vb2_queue->streaming)
+		msm_fd_hw_schedule_and_start(ctx->fd_device);
+
+}
+
+/*
+ * msm_fd_start_streaming - vb2_ops start_streaming callback.
+ * @q: Pointer to vb2 queue struct.
+ * @count: Number of buffer queued before stream on call.
+ */
+static int msm_fd_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct fd_ctx *ctx = vb2_get_drv_priv(q);
+	int ret;
+
+	if (ctx->work_buf.fd == -1) {
+		dev_err(ctx->fd_device->dev, "Missing working buffer\n");
+		return -EINVAL;
+	}
+
+	ret = msm_fd_hw_get(ctx->fd_device, ctx->settings.speed);
+	if (ret < 0) {
+		dev_err(ctx->fd_device->dev, "Can not acquire fd hw\n");
+		goto out;
+	}
+
+	ret = msm_fd_hw_schedule_and_start(ctx->fd_device);
+	if (ret < 0)
+		dev_err(ctx->fd_device->dev, "Can not start fd hw\n");
+
+out:
+	return ret;
+}
+
+/*
+ * msm_fd_stop_streaming - vb2_ops stop_streaming callback.
+ * @q: Pointer to vb2 queue struct.
+ */
+static void msm_fd_stop_streaming(struct vb2_queue *q)
+{
+	struct fd_ctx *ctx = vb2_get_drv_priv(q);
+
+	mutex_lock(&ctx->fd_device->recovery_lock);
+	msm_fd_hw_remove_buffers_from_queue(ctx->fd_device, q);
+	msm_fd_hw_put(ctx->fd_device);
+	mutex_unlock(&ctx->fd_device->recovery_lock);
+}
+
+/* Videobuf2 queue callbacks. */
+static struct vb2_ops msm_fd_vb2_q_ops = {
+	.queue_setup     = msm_fd_queue_setup,
+	.buf_init        = msm_fd_buf_init,
+	.buf_queue       = msm_fd_buf_queue,
+	.start_streaming = msm_fd_start_streaming,
+	.stop_streaming  = msm_fd_stop_streaming,
+};
+
+/*
+ * msm_fd_get_userptr - Map and get buffer handler for user pointer buffer.
+ * @alloc_ctx: Contexts allocated in buf_setup.
+ * @vaddr: Virtual addr passed from userpsace (in our case ion fd)
+ * @size: Size of the buffer
+ * @write: True if buffer will be used for writing the data.
+ */
+static void *msm_fd_get_userptr(struct device *alloc_ctx,
+	unsigned long vaddr, unsigned long size,
+	enum dma_data_direction dma_dir)
+{
+	struct msm_fd_mem_pool *pool = (void *)alloc_ctx;
+	struct msm_fd_buf_handle *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	ret = msm_fd_hw_map_buffer(pool, vaddr, buf);
+	if (ret < 0 || buf->size < size)
+		goto error;
+
+	return buf;
+error:
+	kzfree(buf);
+	return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * msm_fd_put_userptr - Unmap and free buffer handler.
+ * @buf_priv: Buffer handler allocated get_userptr callback.
+ */
+static void msm_fd_put_userptr(void *buf_priv)
+{
+	if (IS_ERR_OR_NULL(buf_priv))
+		return;
+
+	msm_fd_hw_unmap_buffer(buf_priv);
+
+	kzfree(buf_priv);
+}
+
+/* Videobuf2 memory callbacks. */
+static struct vb2_mem_ops msm_fd_vb2_mem_ops = {
+	.get_userptr = msm_fd_get_userptr,
+	.put_userptr = msm_fd_put_userptr,
+};
+
+/*
+ * msm_fd_vbif_error_handler - FD VBIF Error handler
+ * @handle: FD Device handle
+ * @error: CPP-VBIF Error code
+ */
+static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
+{
+	struct fd_ctx *ctx;
+	struct msm_fd_device *fd;
+	struct msm_fd_buffer *active_buf;
+	int ret;
+
+	if (handle == NULL)
+		return 0;
+
+	ctx = (struct fd_ctx *)handle;
+	fd = (struct msm_fd_device *)ctx->fd_device;
+
+	if (error == CPP_VBIF_ERROR_HANG) {
+		mutex_lock(&fd->recovery_lock);
+		dev_err(fd->dev, "Handling FD VBIF Hang\n");
+		if (fd->state != MSM_FD_DEVICE_RUNNING) {
+			dev_err(fd->dev, "FD is not FD_DEVICE_RUNNING, %d\n",
+				fd->state);
+			mutex_unlock(&fd->recovery_lock);
+			return 0;
+		}
+		fd->recovery_mode = 1;
+
+		/* Halt and reset */
+		msm_fd_hw_put(fd);
+		msm_fd_hw_get(fd, ctx->settings.speed);
+
+		/* Get active buffer */
+		MSM_FD_SPIN_LOCK(fd->slock, 1);
+		active_buf = msm_fd_hw_get_active_buffer(fd, 1);
+		MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+
+		if (active_buf == NULL) {
+			dev_dbg(fd->dev, "no active buffer, return\n");
+			fd->recovery_mode = 0;
+			mutex_unlock(&fd->recovery_lock);
+			return 0;
+		}
+
+		dev_dbg(fd->dev, "Active Buffer present.. Start re-schedule\n");
+
+		/* Queue the buffer again */
+		msm_fd_hw_add_buffer(fd, active_buf);
+
+		/* Schedule and restart */
+		ret = msm_fd_hw_schedule_next_buffer(fd, 1);
+		if (ret) {
+			dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n");
+			fd->recovery_mode = 0;
+			mutex_unlock(&fd->recovery_lock);
+			return ret;
+		}
+		dev_dbg(fd->dev, "Restarted FD after VBIF HAng\n");
+		mutex_unlock(&fd->recovery_lock);
+	}
+	return 0;
+}
+
+/*
+ * msm_fd_open - Fd device open method.
+ * @file: Pointer to file struct.
+ */
+static int msm_fd_open(struct file *file)
+{
+	struct msm_fd_device *device = video_drvdata(file);
+	struct video_device *video = video_devdata(file);
+	struct fd_ctx *ctx;
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->fd_device = device;
+
+	/* Initialize work buffer handler */
+	ctx->work_buf.pool = NULL;
+	ctx->work_buf.fd = -1;
+
+	/* Set ctx defaults */
+	ctx->settings.speed = ctx->fd_device->clk_rates_num - 1;
+	ctx->settings.angle_index = MSM_FD_DEF_ANGLE_IDX;
+	ctx->settings.direction_index = MSM_FD_DEF_DIR_IDX;
+	ctx->settings.min_size_index = MSM_FD_DEF_MIN_SIZE_IDX;
+	ctx->settings.threshold = MSM_FD_DEF_THRESHOLD;
+
+	atomic_set(&ctx->subscribed_for_event, 0);
+
+	v4l2_fh_init(&ctx->fh, video);
+
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->vb2_q.drv_priv = ctx;
+	ctx->vb2_q.mem_ops = &msm_fd_vb2_mem_ops;
+	ctx->vb2_q.ops = &msm_fd_vb2_q_ops;
+	ctx->vb2_q.buf_struct_size = sizeof(struct msm_fd_buffer);
+	ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	ctx->vb2_q.io_modes = VB2_USERPTR;
+	ctx->vb2_q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	mutex_init(&ctx->lock);
+	ret = vb2_queue_init(&ctx->vb2_q);
+	if (ret < 0) {
+		dev_err(device->dev, "Error queue init\n");
+		goto error_vb2_queue_init;
+	}
+
+	ctx->mem_pool.fd_device = ctx->fd_device;
+	ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS);
+	if (!ctx->stats) {
+		dev_err(device->dev, "No memory for face statistics\n");
+		ret = -ENOMEM;
+		goto error_stats_vmalloc;
+	}
+
+	ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD,
+			CAM_AHB_SVS_VOTE);
+	if (ret < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		goto error_ahb_config;
+	}
+
+	/* Register with CPP VBIF error handler */
+	msm_cpp_vbif_register_error_handler((void *)ctx,
+		VBIF_CLIENT_FD, msm_fd_vbif_error_handler);
+
+	return 0;
+
+error_ahb_config:
+	vfree(ctx->stats);
+error_stats_vmalloc:
+	vb2_queue_release(&ctx->vb2_q);
+error_vb2_queue_init:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	return ret;
+}
+
+/*
+ * msm_fd_release - Fd device release method.
+ * @file: Pointer to file struct.
+ */
+static int msm_fd_release(struct file *file)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
+
+	/* Un-register with CPP VBIF error handler */
+	msm_cpp_vbif_register_error_handler((void *)ctx,
+		VBIF_CLIENT_FD, NULL);
+
+	mutex_lock(&ctx->lock);
+	vb2_queue_release(&ctx->vb2_q);
+	mutex_unlock(&ctx->lock);
+
+	vfree(ctx->stats);
+
+	if (ctx->work_buf.fd != -1)
+		msm_fd_hw_unmap_buffer(&ctx->work_buf);
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	kfree(ctx);
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+
+	return 0;
+}
+
+/*
+ * msm_fd_poll - Fd device pool method.
+ * @file: Pointer to file struct.
+ * @wait: Pointer to pool table struct.
+ */
+static unsigned int msm_fd_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
+	unsigned int ret;
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_poll(&ctx->vb2_q, file, wait);
+	mutex_unlock(&ctx->lock);
+
+	if (atomic_read(&ctx->subscribed_for_event)) {
+		poll_wait(file, &ctx->fh.wait, wait);
+		if (v4l2_event_pending(&ctx->fh))
+			ret |= POLLPRI;
+	}
+
+	return ret;
+}
+
+/*
+ * msm_fd_private_ioctl - V4l2 private ioctl handler.
+ * @file: Pointer to file struct.
+ * @fd: V4l2 device file handle.
+ * @valid_prio: Priority ioctl valid flag.
+ * @cmd: Ioctl command.
+ * @arg: Ioctl argument.
+ */
+static long msm_fd_private_ioctl(struct file *file, void *fh,
+	bool valid_prio, unsigned int cmd, void *arg)
+{
+	struct msm_fd_result *req_result = arg;
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	struct msm_fd_stats *stats;
+	int stats_idx;
+	int ret = 0;
+	int i;
+
+	switch (cmd) {
+	case VIDIOC_MSM_FD_GET_RESULT:
+		if (req_result->frame_id == 0) {
+			dev_err(ctx->fd_device->dev, "Invalid frame id\n");
+			return -EINVAL;
+		}
+
+		stats_idx = req_result->frame_id % MSM_FD_MAX_RESULT_BUFS;
+		stats = &ctx->stats[stats_idx];
+		if (req_result->frame_id != atomic_read(&stats->frame_id)) {
+			dev_err(ctx->fd_device->dev, "Stats not available\n");
+			return -EINVAL;
+		}
+
+		if (req_result->face_cnt > stats->face_cnt)
+			req_result->face_cnt = stats->face_cnt;
+
+		for (i = 0; i < req_result->face_cnt; i++) {
+			ret = copy_to_user((void __user *)
+					&req_result->face_data[i],
+					&stats->face_data[i],
+					sizeof(struct msm_fd_face_data));
+			if (ret) {
+				dev_err(ctx->fd_device->dev, "Copy to user\n");
+				return -EFAULT;
+			}
+		}
+
+		if (req_result->frame_id != atomic_read(&stats->frame_id)) {
+			dev_err(ctx->fd_device->dev, "Erroneous buffer\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(ctx->fd_device->dev, "Wrong ioctl type %x\n", cmd);
+		ret = -ENOTTY;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+/*
+ * msm_fd_compat_ioctl32 - Compat ioctl handler function.
+ * @file: Pointer to file struct.
+ * @cmd: Ioctl command.
+ * @arg: Ioctl argument.
+ */
+static long msm_fd_compat_ioctl32(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	long ret;
+
+	switch (cmd) {
+	case VIDIOC_MSM_FD_GET_RESULT32:
+	{
+		struct msm_fd_result32 result32;
+		struct msm_fd_result result;
+
+		if (copy_from_user(&result32, (void __user *)arg,
+				sizeof(result32)))
+			return -EFAULT;
+
+		result.frame_id  = result32.frame_id;
+		result.face_cnt  = result32.face_cnt;
+		result.face_data = compat_ptr(result32.face_data);
+
+		ret = msm_fd_private_ioctl(file, file->private_data,
+			0, VIDIOC_MSM_FD_GET_RESULT, (void *)&result);
+
+		result32.frame_id = result.frame_id;
+		result32.face_cnt = result.face_cnt;
+
+		if (copy_to_user((void __user *)arg, &result32,
+				sizeof(result32)))
+			return -EFAULT;
+
+		break;
+	}
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+
+	}
+
+	return ret;
+}
+#endif
+
+/* Fd device file operations callbacks */
+static const struct v4l2_file_operations fd_fops = {
+	.owner          = THIS_MODULE,
+	.open           = msm_fd_open,
+	.release        = msm_fd_release,
+	.poll           = msm_fd_poll,
+	.unlocked_ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = msm_fd_compat_ioctl32,
+#endif
+};
+
+/*
+ * msm_fd_querycap - V4l2 ioctl query capability handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @cap: Pointer to v4l2_capability struct need to be filled.
+ */
+static int msm_fd_querycap(struct file *file,
+	void *fh, struct v4l2_capability *cap)
+{
+	cap->bus_info[0] = 0;
+	strlcpy(cap->driver, MSM_FD_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_FD_DRV_NAME, sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+
+	return 0;
+}
+
+/*
+ * msm_fd_enum_fmt_vid_out - V4l2 ioctl enumerate format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_fmtdesc struct need to be filled.
+ */
+static int msm_fd_enum_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_fmtdesc *f)
+{
+	if (f->index > 0)
+		return -EINVAL;
+
+	f->pixelformat = V4L2_PIX_FMT_GREY;
+	strlcpy(f->description, "8 Greyscale",
+		sizeof(f->description));
+
+	return 0;
+}
+
+/*
+ * msm_fd_g_fmt - V4l2 ioctl get format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct need to be filled.
+ */
+static int msm_fd_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	return msm_fd_fill_format_from_ctx(f, ctx);
+}
+
+/*
+ * msm_fd_try_fmt_vid_out - V4l2 ioctl try format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_fd_try_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	int index;
+
+	index = msm_fd_get_format_index(f);
+
+	return msm_fd_fill_format_from_index(f, index);
+}
+
+/*
+ * msm_fd_s_fmt_vid_out - V4l2 ioctl set format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_fd_s_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int index;
+
+	index = msm_fd_get_format_index(f);
+
+	msm_fd_fill_format_from_index(f, index);
+
+	ctx->format.size = &fd_size[index];
+	ctx->format.pixelformat = f->fmt.pix.pixelformat;
+	ctx->format.bytesperline = f->fmt.pix.bytesperline;
+	ctx->format.sizeimage = f->fmt.pix.sizeimage;
+
+	/* Initialize crop */
+	ctx->format.crop.top = 0;
+	ctx->format.crop.left = 0;
+	ctx->format.crop.width = fd_size[index].width;
+	ctx->format.crop.height = fd_size[index].height;
+
+	return 0;
+}
+
+/*
+ * msm_fd_reqbufs - V4l2 ioctl request buffers handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @req: Pointer to v4l2_requestbuffer struct.
+ */
+static int msm_fd_reqbufs(struct file *file,
+	void *fh, struct v4l2_requestbuffers *req)
+{
+	int ret;
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_reqbufs(&ctx->vb2_q, req);
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+/*
+ * msm_fd_qbuf - V4l2 ioctl queue buffer handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @pb: Pointer to v4l2_buffer struct.
+ */
+static int msm_fd_qbuf(struct file *file, void *fh,
+	struct v4l2_buffer *pb)
+{
+	int ret;
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_qbuf(&ctx->vb2_q, pb);
+	mutex_unlock(&ctx->lock);
+	return ret;
+
+}
+
+/*
+ * msm_fd_dqbuf - V4l2 ioctl dequeue buffer handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @pb: Pointer to v4l2_buffer struct.
+ */
+static int msm_fd_dqbuf(struct file *file,
+	void *fh, struct v4l2_buffer *pb)
+{
+	int ret;
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK);
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+/*
+ * msm_fd_streamon - V4l2 ioctl stream on handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf_type: V4l2 buffer type.
+ */
+static int msm_fd_streamon(struct file *file,
+	void *fh, enum v4l2_buf_type buf_type)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int ret;
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_streamon(&ctx->vb2_q, buf_type);
+	mutex_unlock(&ctx->lock);
+	if (ret < 0)
+		dev_err(ctx->fd_device->dev, "Stream on fails\n");
+
+	return ret;
+}
+
+/*
+ * msm_fd_streamoff - V4l2 ioctl stream off handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf_type: V4l2 buffer type.
+ */
+static int msm_fd_streamoff(struct file *file,
+	void *fh, enum v4l2_buf_type buf_type)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int ret;
+
+	mutex_lock(&ctx->lock);
+	ret = vb2_streamoff(&ctx->vb2_q, buf_type);
+	mutex_unlock(&ctx->lock);
+	if (ret < 0)
+		dev_err(ctx->fd_device->dev, "Stream off fails\n");
+
+	return ret;
+}
+
+/*
+ * msm_fd_subscribe_event - V4l2 ioctl subscribe for event handler.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_event_subscription containing event information.
+ */
+static int msm_fd_subscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int ret;
+
+	if (sub->type != MSM_EVENT_FD)
+		return -EINVAL;
+
+	ret = v4l2_event_subscribe(fh, sub, MSM_FD_MAX_RESULT_BUFS, NULL);
+	if (!ret)
+		atomic_set(&ctx->subscribed_for_event, 1);
+
+	return ret;
+}
+
+/*
+ * msm_fd_unsubscribe_event - V4l2 ioctl unsubscribe from event handler.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_event_subscription containing event information.
+ */
+static int msm_fd_unsubscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int ret;
+
+	ret = v4l2_event_unsubscribe(fh, sub);
+	if (!ret)
+		atomic_set(&ctx->subscribed_for_event, 0);
+
+	return ret;
+}
+
+/*
+ * msm_fd_guery_ctrl - V4l2 ioctl query control.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_queryctrl struct info need to be filled based on id.
+ */
+static int msm_fd_guery_ctrl(struct file *file, void *fh,
+	struct v4l2_queryctrl *a)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	switch (a->id) {
+	case V4L2_CID_FD_SPEED:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = ctx->fd_device->clk_rates_num;
+		a->minimum = 0;
+		a->maximum = ctx->fd_device->clk_rates_num;
+		a->step = 1;
+		strlcpy(a->name, "msm fd face speed idx",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_FACE_ANGLE:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value =  msm_fd_angle[MSM_FD_DEF_ANGLE_IDX];
+		a->minimum = msm_fd_angle[0];
+		a->maximum = msm_fd_angle[ARRAY_SIZE(msm_fd_angle) - 1];
+		a->step = 1;
+		strlcpy(a->name, "msm fd face angle ctrl",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_FACE_DIRECTION:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = msm_fd_dir[MSM_FD_DEF_DIR_IDX];
+		a->minimum = msm_fd_dir[0];
+		a->maximum = msm_fd_dir[ARRAY_SIZE(msm_fd_dir) - 1];
+		a->step = 1;
+		strlcpy(a->name, "msm fd face direction ctrl",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_MIN_FACE_SIZE:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = msm_fd_min_size[MSM_FD_DEF_MIN_SIZE_IDX];
+		a->minimum = msm_fd_min_size[0];
+		a->maximum = msm_fd_min_size[ARRAY_SIZE(msm_fd_min_size) - 1];
+		a->step = 1;
+		strlcpy(a->name, "msm fd minimum face size (pixels)",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_DETECTION_THRESHOLD:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = MSM_FD_DEF_THRESHOLD;
+		a->minimum = 0;
+		a->maximum = MSM_FD_MAX_THRESHOLD_VALUE;
+		a->step = 1;
+		strlcpy(a->name, "msm fd detection threshold",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_SIZE:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = fd_size[0].work_size;
+		a->minimum = fd_size[(ARRAY_SIZE(fd_size) - 1)].work_size;
+		a->maximum = fd_size[0].work_size;
+		a->step = 1;
+		strlcpy(a->name, "msm fd working memory size",
+			sizeof(a->name));
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_FD:
+		a->type = V4L2_CTRL_TYPE_INTEGER;
+		a->default_value = -1;
+		a->minimum = 0;
+		a->maximum = INT_MAX;
+		a->step = 1;
+		strlcpy(a->name, "msm fd ion fd of working memory",
+			sizeof(a->name));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_fd_g_ctrl - V4l2 ioctl get control.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_queryctrl struct need to be filled.
+ */
+static int msm_fd_g_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	switch (a->id) {
+	case V4L2_CID_FD_SPEED:
+		a->value = ctx->settings.speed;
+		break;
+	case V4L2_CID_FD_FACE_ANGLE:
+		a->value = msm_fd_angle[ctx->settings.angle_index];
+		break;
+	case V4L2_CID_FD_FACE_DIRECTION:
+		a->value = msm_fd_dir[ctx->settings.direction_index];
+		break;
+	case V4L2_CID_FD_MIN_FACE_SIZE:
+		a->value = msm_fd_min_size[ctx->settings.min_size_index];
+		break;
+	case V4L2_CID_FD_DETECTION_THRESHOLD:
+		a->value = ctx->settings.threshold;
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_SIZE:
+		if (!ctx->format.size)
+			return -EINVAL;
+
+		a->value = ctx->format.size->work_size;
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_FD:
+		if (ctx->work_buf.fd == -1)
+			return -EINVAL;
+
+		a->value = ctx->work_buf.fd;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_fd_s_ctrl - V4l2 ioctl set control.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_queryctrl struct need to be set.
+ */
+static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int idx;
+	int ret;
+
+	switch (a->id) {
+	case V4L2_CID_FD_SPEED:
+		if (a->value > ctx->fd_device->clk_rates_num - 1)
+			a->value = ctx->fd_device->clk_rates_num - 1;
+		else if (a->value < 0)
+			a->value = 0;
+
+		ctx->settings.speed = a->value;
+		break;
+	case V4L2_CID_FD_FACE_ANGLE:
+		idx = msm_fd_get_idx_from_value(a->value, msm_fd_angle,
+			ARRAY_SIZE(msm_fd_angle));
+
+		ctx->settings.angle_index = idx;
+		a->value = msm_fd_angle[ctx->settings.angle_index];
+		break;
+	case V4L2_CID_FD_FACE_DIRECTION:
+		idx = msm_fd_get_idx_from_value(a->value, msm_fd_dir,
+			ARRAY_SIZE(msm_fd_dir));
+
+		ctx->settings.direction_index = idx;
+		a->value = msm_fd_dir[ctx->settings.direction_index];
+		break;
+	case V4L2_CID_FD_MIN_FACE_SIZE:
+		idx = msm_fd_get_idx_from_value(a->value, msm_fd_min_size,
+			ARRAY_SIZE(msm_fd_min_size));
+
+		ctx->settings.min_size_index = idx;
+		a->value = msm_fd_min_size[ctx->settings.min_size_index];
+		break;
+	case V4L2_CID_FD_DETECTION_THRESHOLD:
+		if (a->value > MSM_FD_MAX_THRESHOLD_VALUE)
+			a->value = MSM_FD_MAX_THRESHOLD_VALUE;
+		else if (a->value < 0)
+			a->value = 0;
+
+		ctx->settings.threshold = a->value;
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_SIZE:
+		if (!ctx->format.size)
+			return -EINVAL;
+
+		if (a->value < ctx->format.size->work_size)
+			a->value = ctx->format.size->work_size;
+		break;
+	case V4L2_CID_FD_WORK_MEMORY_FD:
+		mutex_lock(&ctx->fd_device->recovery_lock);
+		if (ctx->work_buf.fd != -1)
+			msm_fd_hw_unmap_buffer(&ctx->work_buf);
+		if (a->value >= 0) {
+			ret = msm_fd_hw_map_buffer(&ctx->mem_pool,
+				a->value, &ctx->work_buf);
+			if (ret < 0) {
+				mutex_unlock(&ctx->fd_device->recovery_lock);
+				return ret;
+			}
+		}
+		mutex_unlock(&ctx->fd_device->recovery_lock);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_fd_cropcap - V4l2 ioctl crop capabilities.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_cropcap struct need to be set.
+ */
+static int msm_fd_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	if (!ctx->format.size) {
+		dev_err(ctx->fd_device->dev, "Cropcap fails format missing\n");
+		return -EINVAL;
+	}
+
+	a->bounds.top = 0;
+	a->bounds.left = 0;
+	a->bounds.width = ctx->format.size->width;
+	a->bounds.height =  ctx->format.size->height;
+
+	a->defrect = ctx->format.crop;
+
+	a->pixelaspect.numerator = 1;
+	a->pixelaspect.denominator = 1;
+
+	return 0;
+}
+
+/*
+ * msm_fd_g_crop - V4l2 ioctl get crop.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_crop struct need to be set.
+ */
+static int msm_fd_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+
+	if (!ctx->format.size) {
+		dev_err(ctx->fd_device->dev, "Get crop, format missing!\n");
+		return -EINVAL;
+	}
+
+	crop->c = ctx->format.crop;
+
+	return 0;
+}
+
+/*
+ * msm_fd_s_crop - V4l2 ioctl set crop.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_crop struct need to be set.
+ */
+static int msm_fd_s_crop(struct file *file, void *fh,
+	const struct v4l2_crop *crop)
+{
+	struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
+	int min_face_size;
+
+	if (!ctx->format.size) {
+		dev_err(ctx->fd_device->dev, "Get crop, format missing!\n");
+		return -EINVAL;
+	}
+
+	/* First check that crop is valid */
+	min_face_size = msm_fd_min_size[ctx->settings.min_size_index];
+
+	if (crop->c.width < min_face_size || crop->c.height < min_face_size)
+		return -EINVAL;
+
+	if (crop->c.width + crop->c.left > ctx->format.size->width)
+		return -EINVAL;
+
+	if (crop->c.height + crop->c.top > ctx->format.size->height)
+		return -EINVAL;
+
+	ctx->format.crop = crop->c;
+
+	return 0;
+}
+
+/* V4l2 ioctl handlers */
+static const struct v4l2_ioctl_ops fd_ioctl_ops = {
+	.vidioc_querycap          = msm_fd_querycap,
+	.vidioc_enum_fmt_vid_out  = msm_fd_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out     = msm_fd_g_fmt,
+	.vidioc_try_fmt_vid_out   = msm_fd_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out     = msm_fd_s_fmt_vid_out,
+	.vidioc_reqbufs           = msm_fd_reqbufs,
+	.vidioc_qbuf              = msm_fd_qbuf,
+	.vidioc_dqbuf             = msm_fd_dqbuf,
+	.vidioc_streamon          = msm_fd_streamon,
+	.vidioc_streamoff         = msm_fd_streamoff,
+	.vidioc_queryctrl         = msm_fd_guery_ctrl,
+	.vidioc_s_ctrl            = msm_fd_s_ctrl,
+	.vidioc_g_ctrl            = msm_fd_g_ctrl,
+	.vidioc_cropcap           = msm_fd_cropcap,
+	.vidioc_g_crop            = msm_fd_g_crop,
+	.vidioc_s_crop            = msm_fd_s_crop,
+	.vidioc_subscribe_event   = msm_fd_subscribe_event,
+	.vidioc_unsubscribe_event = msm_fd_unsubscribe_event,
+	.vidioc_default           = msm_fd_private_ioctl,
+};
+
+/*
+ * msm_fd_fill_results - Read and fill face detection result.
+ * @fd: Pointer to fd device.
+ * @face: Pointer of face data which information need to be stored.
+ * @idx: Face number index need to be filled.
+ */
+static void msm_fd_fill_results(struct msm_fd_device *fd,
+	struct msm_fd_face_data *face, int idx)
+{
+	int half_face_size;
+
+	msm_fd_hw_get_result_angle_pose(fd, idx, &face->angle, &face->pose);
+
+	msm_fd_hw_get_result_conf_size(fd, idx, &face->confidence,
+		&face->face.width);
+	face->face.height = face->face.width;
+
+	face->face.left = msm_fd_hw_get_result_x(fd, idx);
+	face->face.top = msm_fd_hw_get_result_y(fd, idx);
+
+	half_face_size = (face->face.width >> 1);
+	if (face->face.left > half_face_size)
+		face->face.left -= half_face_size;
+	else
+		face->face.left = 0;
+
+	half_face_size = (face->face.height >> 1);
+	if (face->face.top > half_face_size)
+		face->face.top -= half_face_size;
+	else
+		face->face.top = 0;
+}
+
+/*
+ * msm_fd_wq_handler - Fd device workqueue handler.
+ * @work: Pointer to work struct.
+ *
+ * This function is bottom half of fd irq what it does:
+ *
+ * - Stop the fd engine.
+ * - Getter fd result and store in stats buffer.
+ * - If available schedule next buffer for processing.
+ * - Sent event to v4l2.
+ * - Release buffer from v4l2 queue.
+ */
+static void msm_fd_wq_handler(struct work_struct *work)
+{
+	struct msm_fd_buffer *active_buf;
+	struct msm_fd_stats *stats;
+	struct msm_fd_event *fd_event;
+	struct msm_fd_device *fd;
+	struct fd_ctx *ctx;
+	struct v4l2_event event;
+	int i;
+
+	fd = container_of(work, struct msm_fd_device, work);
+	MSM_FD_SPIN_LOCK(fd->slock, 1);
+	active_buf = msm_fd_hw_get_active_buffer(fd, 0);
+	if (!active_buf) {
+		/* This should never happen, something completely wrong */
+		dev_err(fd->dev, "Oops no active buffer empty queue\n");
+		MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+		return;
+	}
+	ctx = vb2_get_drv_priv(active_buf->vb_v4l2_buf.vb2_buf.vb2_queue);
+
+	/* Increment sequence number, 0 means sequence is not valid */
+	ctx->sequence++;
+	if (unlikely(!ctx->sequence))
+		ctx->sequence = 1;
+
+	/* Fill face detection statistics */
+	stats = &ctx->stats[ctx->sequence % MSM_FD_MAX_RESULT_BUFS];
+
+	/* First mark stats as invalid */
+	atomic_set(&stats->frame_id, 0);
+
+	stats->face_cnt = msm_fd_hw_get_face_count(fd);
+	for (i = 0; i < stats->face_cnt; i++)
+		msm_fd_fill_results(fd, &stats->face_data[i], i);
+
+	/* Stats are ready, set correct frame id */
+	atomic_set(&stats->frame_id, ctx->sequence);
+
+	/* If Recovery mode is on, we got IRQ after recovery, reset it */
+	if (fd->recovery_mode) {
+		fd->recovery_mode = 0;
+		dev_dbg(fd->dev, "Got IRQ after Recovery\n");
+	}
+
+	if (fd->state == MSM_FD_DEVICE_RUNNING) {
+		/* We have the data from fd hw, we can start next processing */
+		msm_fd_hw_schedule_next_buffer(fd, 0);
+	}
+
+	/* Return buffer to vb queue */
+	active_buf->vb_v4l2_buf.sequence = ctx->fh.sequence;
+	vb2_buffer_done(&active_buf->vb_v4l2_buf.vb2_buf, VB2_BUF_STATE_DONE);
+
+	/* Sent event */
+	memset(&event, 0x00, sizeof(event));
+	event.type = MSM_EVENT_FD;
+	fd_event = (struct msm_fd_event *)event.u.data;
+	fd_event->face_cnt = stats->face_cnt;
+	fd_event->buf_index = active_buf->vb_v4l2_buf.vb2_buf.index;
+	fd_event->frame_id = ctx->sequence;
+	v4l2_event_queue_fh(&ctx->fh, &event);
+
+	/* Release buffer from the device */
+	msm_fd_hw_buffer_done(fd, active_buf, 0);
+
+	MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+}
+
+/*
+ * fd_probe - Fd device probe method.
+ * @pdev: Pointer fd platform device.
+ */
+static int fd_probe(struct platform_device *pdev)
+{
+	struct msm_fd_device *fd;
+	int ret;
+	int i;
+
+	/* Face detection device struct */
+	fd = kzalloc(sizeof(struct msm_fd_device), GFP_KERNEL);
+	if (!fd)
+		return -ENOMEM;
+
+	mutex_init(&fd->lock);
+	spin_lock_init(&fd->slock);
+	mutex_init(&fd->recovery_lock);
+	init_completion(&fd->hw_halt_completion);
+	INIT_LIST_HEAD(&fd->buf_queue);
+	fd->pdev = pdev;
+	fd->dev = &pdev->dev;
+
+	/* Get resources */
+	ret = msm_fd_hw_get_mem_resources(pdev, fd);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail get resources\n");
+		ret = -ENODEV;
+		goto error_mem_resources;
+	}
+
+	ret = msm_camera_get_regulator_info(pdev, &fd->vdd_info,
+		&fd->num_reg);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail to get regulators\n");
+		goto error_get_regulator;
+	}
+	ret = msm_camera_get_clk_info_and_rates(pdev, &fd->clk_info,
+		&fd->clk, &fd->clk_rates, &fd->clk_rates_num, &fd->clk_num);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail to get clocks\n");
+		goto error_get_clocks;
+	}
+
+	/*set memcore and mem periphery logic flags to 0*/
+	for (i = 0; i < fd->clk_num; i++) {
+		if ((strcmp(fd->clk_info[i].clk_name,
+			"mmss_fd_core_clk") == 0) ||
+			(strcmp(fd->clk_info[i].clk_name,
+			"mmss_fd_core_uar_clk") == 0)) {
+			msm_camera_set_clk_flags(fd->clk[i],
+				CLKFLAG_NORETAIN_MEM);
+			msm_camera_set_clk_flags(fd->clk[i],
+				CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+
+	ret = msm_camera_register_bus_client(pdev, CAM_BUS_CLIENT_FD);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail to get bus\n");
+		goto error_get_bus;
+	}
+
+	/* Get face detect hw before read engine revision */
+	ret = msm_fd_hw_get(fd, 0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail to get hw\n");
+		goto error_hw_get_request_irq;
+	}
+	fd->hw_revision = msm_fd_hw_get_revision(fd);
+
+	msm_fd_hw_put(fd);
+
+	ret = msm_fd_hw_request_irq(pdev, fd, msm_fd_wq_handler);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Fail request irq\n");
+		goto error_hw_get_request_irq;
+	}
+
+	/* v4l2 device */
+	ret = v4l2_device_register(&pdev->dev, &fd->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+		ret = -ENOENT;
+		goto error_v4l2_register;
+	}
+
+	fd->video.fops  = &fd_fops;
+	fd->video.ioctl_ops = &fd_ioctl_ops;
+	fd->video.minor = -1;
+	fd->video.release  = video_device_release;
+	fd->video.v4l2_dev = &fd->v4l2_dev;
+	fd->video.vfl_dir = VFL_DIR_TX;
+	fd->video.vfl_type = VFL_TYPE_GRABBER;
+	strlcpy(fd->video.name, MSM_FD_DRV_NAME, sizeof(fd->video.name));
+
+	ret = video_register_device(&fd->video, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		v4l2_err(&fd->v4l2_dev, "Failed to register video device\n");
+		goto error_video_register;
+	}
+
+	video_set_drvdata(&fd->video, fd);
+
+	platform_set_drvdata(pdev, fd);
+
+	return 0;
+
+error_video_register:
+	v4l2_device_unregister(&fd->v4l2_dev);
+error_v4l2_register:
+	msm_fd_hw_release_irq(fd);
+error_hw_get_request_irq:
+	msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD);
+error_get_bus:
+	msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info,
+		&fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num);
+error_get_clocks:
+	msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg);
+error_get_regulator:
+	msm_fd_hw_release_mem_resources(fd);
+error_mem_resources:
+	kfree(fd);
+	return ret;
+}
+
+/*
+ * fd_device_remove - Fd device remove method.
+ * @pdev: Pointer fd platform device.
+ */
+static int fd_device_remove(struct platform_device *pdev)
+{
+	struct msm_fd_device *fd;
+
+	fd = platform_get_drvdata(pdev);
+	if (fd == NULL) {
+		dev_err(&pdev->dev, "Can not get fd drvdata\n");
+		return 0;
+	}
+	video_unregister_device(&fd->video);
+	v4l2_device_unregister(&fd->v4l2_dev);
+	msm_fd_hw_release_irq(fd);
+	msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD);
+	msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info,
+		&fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num);
+	msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg);
+	msm_fd_hw_release_mem_resources(fd);
+	kfree(fd);
+
+	return 0;
+}
+
+/* Device tree match struct */
+static const struct of_device_id msm_fd_dt_match[] = {
+	{.compatible = "qcom,face-detection"},
+	{}
+};
+
+/* Fd platform driver definition */
+static struct platform_driver fd_driver = {
+	.probe = fd_probe,
+	.remove = fd_device_remove,
+	.driver = {
+		.name = MSM_FD_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_fd_dt_match,
+	},
+};
+
+static int __init msm_fd_init_module(void)
+{
+	return platform_driver_register(&fd_driver);
+}
+
+static void __exit msm_fd_exit_module(void)
+{
+	platform_driver_unregister(&fd_driver);
+}
+
+module_init(msm_fd_init_module);
+module_exit(msm_fd_exit_module);
+MODULE_DESCRIPTION("MSM FD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
new file mode 100644
index 0000000..c0030f9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
@@ -0,0 +1,272 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_FD_DEV_H__
+#define __MSM_FD_DEV_H__
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-v4l2.h>
+#include <linux/msm-bus.h>
+#include <media/msm_fd.h>
+#include <linux/dma-buf.h>
+#include <linux/msm_ion.h>
+#include "cam_soc_api.h"
+#include "cam_hw_ops.h"
+#include "msm_cpp.h"
+
+/* Maximum number of result buffers */
+#define MSM_FD_MAX_RESULT_BUFS 5
+/* Max number of clocks defined in device tree */
+#define MSM_FD_MAX_CLK_NUM 15
+/* Max number of clock rates defined in device tree */
+#define MSM_FD_MAX_CLK_RATES 5
+/* Max number of faces which can be detected in one hw processing */
+#define MSM_FD_MAX_FACES_DETECTED 32
+/* Max number of regulators defined in device tree */
+#define MSM_FD_MAX_REGULATOR_NUM 3
+
+/* Conditional spin lock macro */
+#define MSM_FD_SPIN_LOCK(l, f) ({\
+	if (f) \
+		spin_lock(&l); \
+})
+
+/* Conditional spin unlock macro */
+#define MSM_FD_SPIN_UNLOCK(l, f) ({ \
+	if (f) \
+		spin_unlock(&l); \
+})
+
+/*
+ * struct msm_fd_size - Structure contain FD size related values.
+ * @width: Image width.
+ * @height: Image height.
+ * @reg_val: Register value for this size.
+ * @work_size: Working buffer size in bytes for this size.
+ */
+struct msm_fd_size {
+	int width;
+	int height;
+	u32 reg_val;
+	int work_size;
+};
+
+/*
+ * struct msm_fd_setings - Structure contain FD settings values.
+ * @min_size_index: Minimum face size array index.
+ * @angle_index: Face detection angle array index.
+ * @direction_index: Face detection direction array index.
+ * @threshold: Face detection threshold value.
+ * @speed: Face detection speed value (it should match with clock rate index).
+ */
+struct msm_fd_setings {
+	unsigned int min_size_index;
+	unsigned int angle_index;
+	unsigned int direction_index;
+	unsigned int threshold;
+	unsigned int speed;
+};
+
+/*
+ * struct msm_fd_format - Structure contain FD format settings.
+ * @size: Pointer to fd size struct used for this format.
+ * @crop: V4l2 crop structure.
+ * @bytesperline: Bytes per line of input image buffer.
+ * @sizeimage: Size of input image buffer.
+ * @pixeformat: Pix format of input image buffer.
+ */
+struct msm_fd_format {
+	struct msm_fd_size *size;
+	struct v4l2_rect crop;
+	int bytesperline;
+	int sizeimage;
+	u32 pixelformat;
+};
+
+/*
+ * struct msm_fd_mem_pool - Structure contain FD memory pool information.
+ * @fd_device: Pointer to fd device.
+ * @client: Pointer to ion client.
+ * @domain_num: Domain number associated with FD hw.
+ */
+struct msm_fd_mem_pool {
+	struct msm_fd_device *fd_device;
+};
+
+/*
+ * struct msm_fd_buf_handle - Structure contain FD buffer handle information.
+ * @fd: ion FD from which this buffer is imported.
+ * @pool: Pointer to FD memory pool struct.
+ * @handle: Pointer to ion handle.
+ * @size: Size of the buffer.
+ * @addr: Adders of FD mmu mapped buffer. This address should be set to FD hw.
+ */
+struct msm_fd_buf_handle {
+	int fd;
+	struct msm_fd_mem_pool *pool;
+	size_t size;
+	ion_phys_addr_t addr;
+};
+
+/*
+ * struct msm_fd_buffer - Vb2 buffer wrapper structure.
+ * @vb: Videobuf 2 buffer structure.
+ * @active: Flag indicating if buffer currently used by FD hw.
+ * @completion: Completion need to wait on, if buffer is used by FD hw.
+ * @format: Format information of this buffer.
+ * @settings: Settings value of this buffer.
+ * @work_addr: Working buffer address need to be used when for this buffer.
+ * @list: Buffer is part of FD device processing queue
+ */
+struct msm_fd_buffer {
+	struct vb2_v4l2_buffer vb_v4l2_buf;
+	atomic_t active;
+	struct completion completion;
+	struct msm_fd_format format;
+	struct msm_fd_setings settings;
+	ion_phys_addr_t work_addr;
+	struct list_head list;
+};
+
+/*
+ * struct msm_fd_stats - Structure contains FD result statistic information.
+ * @frame_id: Frame id for which statistic corresponds to.
+ * @face_cnt: Number of faces detected and included in face data.
+ * @face_data: Structure containing detected face data information.
+ */
+struct msm_fd_stats {
+	atomic_t frame_id;
+	u32 face_cnt;
+	struct msm_fd_face_data face_data[MSM_FD_MAX_FACES_DETECTED];
+};
+
+/*
+ * struct fd_ctx - Structure contains per open file handle context.
+ * @fd_device: Pointer to fd device.
+ * @fh: V4l2 file handle.
+ * @vb2_q: Videobuf 2 queue.
+ * @sequence: Sequence number for this statistic.
+ * @format: Current format.
+ * @settings: Current settings.
+ * @mem_pool: FD hw memory pool.
+ * @stats: Pointer to statistic buffers.
+ * @work_buf: Working memory buffer handle.
+ */
+struct fd_ctx {
+	struct msm_fd_device *fd_device;
+	struct v4l2_fh fh;
+	struct vb2_queue vb2_q;
+	unsigned int sequence;
+	atomic_t subscribed_for_event;
+	struct msm_fd_format format;
+	struct msm_fd_setings settings;
+	struct msm_fd_mem_pool mem_pool;
+	struct msm_fd_stats *stats;
+	struct msm_fd_buf_handle work_buf;
+	struct mutex lock;
+};
+
+/*
+ * enum msm_fd_device_state - FD device state.
+ * @MSM_FD_DEVICE_IDLE: Device is idle, we can start with processing.
+ * @MSM_FD_DEVICE_RUNNING: Device is running, next processing will be
+ * scheduled from fd irq.
+ */
+enum msm_fd_device_state {
+	MSM_FD_DEVICE_IDLE,
+	MSM_FD_DEVICE_RUNNING,
+};
+
+/*
+ * enum msm_fd_mem_resources - FD device iomem resources.
+ * @MSM_FD_IOMEM_CORE: Index of fd core registers.
+ * @MSM_FD_IOMEM_MISC: Index of fd misc registers.
+ * @MSM_FD_IOMEM_VBIF: Index of fd vbif registers.
+ * @MSM_FD_IOMEM_LAST: Not valid.
+ */
+enum msm_fd_mem_resources {
+	MSM_FD_IOMEM_CORE,
+	MSM_FD_IOMEM_MISC,
+	MSM_FD_IOMEM_VBIF,
+	MSM_FD_IOMEM_LAST
+};
+
+/*
+ * struct msm_fd_device - FD device structure.
+ * @hw_revision: Face detection hw revision.
+ * @lock: Lock used for reference count.
+ * @slock: Spinlock used to protect FD device struct.
+ * @irq_num: Face detection irq number.
+ * @ref_count: Device reference count.
+ * @res_mem: Array of memory resources used by FD device.
+ * @iomem_base: Array of register mappings used by FD device.
+ * @vdd: Pointer to vdd regulator.
+ * @clk_num: Number of clocks attached to the device.
+ * @clk: Array of clock resources used by fd device.
+ * @clk_rates: Array of clock rates set.
+ * @bus_vectors: Pointer to bus vectors array.
+ * @bus_paths: Pointer to bus paths array.
+ * @bus_scale_data: Memory access bus scale data.
+ * @bus_client: Memory access bus client.
+ * @iommu_attached_cnt: Iommu attached devices reference count.
+ * @iommu_hdl: reference for iommu context.
+ * @dev: Pointer to device struct.
+ * @v4l2_dev: V4l2 device.
+ * @video: Video device.
+ * @state: FD device state.
+ * @buf_queue: FD device processing queue.
+ * @work_queue: Pointer to FD device IRQ bottom half workqueue.
+ * @work: IRQ bottom half work struct.
+ * @hw_halt_completion: Completes when face detection hw halt completes.
+ * @recovery_mode: Indicates if FD is in recovery mode
+ */
+struct msm_fd_device {
+	u32 hw_revision;
+
+	struct mutex lock;
+	spinlock_t slock;
+	struct mutex recovery_lock;
+	int ref_count;
+
+	int irq_num;
+	void __iomem *iomem_base[MSM_FD_IOMEM_LAST];
+	struct msm_cam_clk_info *clk_info;
+	struct msm_cam_regulator *vdd_info;
+	int num_reg;
+	struct resource *irq;
+
+	size_t clk_num;
+	size_t clk_rates_num;
+	struct clk **clk;
+	uint32_t **clk_rates;
+	uint32_t bus_client;
+
+	unsigned int iommu_attached_cnt;
+
+	int iommu_hdl;
+	struct device *dev;
+	struct platform_device *pdev;
+	struct v4l2_device v4l2_dev;
+	struct video_device video;
+
+	enum msm_fd_device_state state;
+	struct list_head buf_queue;
+	struct workqueue_struct *work_queue;
+	struct work_struct work;
+	struct completion hw_halt_completion;
+	int recovery_mode;
+	uint32_t clk_rate_idx;
+};
+
+#endif /* __MSM_FD_DEV_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
new file mode 100644
index 0000000..2bc453f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
@@ -0,0 +1,1342 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/iommu.h>
+#include <linux/msm_ion.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <media/videobuf2-core.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
+#include "msm_fd_dev.h"
+#include "msm_fd_hw.h"
+#include "msm_fd_regs.h"
+#include "cam_smmu_api.h"
+#include "msm_camera_io_util.h"
+
+/* After which revision misc irq for engine is needed */
+#define MSM_FD_MISC_IRQ_FROM_REV 0x10010000
+/* Face detection workqueue name */
+#define MSM_FD_WORQUEUE_NAME "face-detection"
+/* Face detection bus client name */
+#define MSM_FD_BUS_CLIENT_NAME "msm_face_detect"
+/* Face detection processing timeout in ms */
+#define MSM_FD_PROCESSING_TIMEOUT_MS 150
+/* Face detection halt timeout in ms */
+#define MSM_FD_HALT_TIMEOUT_MS 100
+/* Smmu callback name */
+#define MSM_FD_SMMU_CB_NAME "camera_fd"
+/*
+ * enum msm_fd_reg_setting_entries - FD register setting entries in DT.
+ * @MSM_FD_REG_ADDR_OFFSET_IDX: Register address offset index.
+ * @MSM_FD_REG_VALUE_IDX: Register value index.
+ * @MSM_FD_REG_MASK_IDX: Regester mask index.
+ * @MSM_FD_REG_LAST_IDX: Index count.
+ */
+enum msm_fd_dt_reg_setting_index {
+	MSM_FD_REG_ADDR_OFFSET_IDX,
+	MSM_FD_REG_VALUE_IDX,
+	MSM_FD_REG_MASK_IDX,
+	MSM_FD_REG_LAST_IDX
+};
+
+/*
+ * msm_fd_hw_read_reg - Fd read from register.
+ * @fd: Pointer to fd device.
+ * @base_idx: Fd memory resource index.
+ * @reg: Register addr need to be read from.
+ */
+static inline u32 msm_fd_hw_read_reg(struct msm_fd_device *fd,
+	enum msm_fd_mem_resources base_idx, u32 reg)
+{
+	return msm_camera_io_r(fd->iomem_base[base_idx] + reg);
+}
+
+/*
+ * msm_fd_hw_read_reg - Fd write to register.
+ * @fd: Pointer to fd device.
+ * @base_idx: Fd memory resource index.
+ * @reg: Register addr need to be read from.
+ e @value: Value to be written.
+ */
+static inline void msm_fd_hw_write_reg(struct msm_fd_device *fd,
+	enum msm_fd_mem_resources base_idx, u32 reg, u32 value)
+{
+	msm_camera_io_w(value, fd->iomem_base[base_idx] + reg);
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd clear register bits.
+ * @fd: Pointer to fd device.
+ * @base_idx: Fd memory resource index.
+ * @reg: Register addr need to be read from.
+ * @clr_bits: Bits need to be clear from register.
+ */
+static inline void msm_fd_hw_reg_clr(struct msm_fd_device *fd,
+	enum msm_fd_mem_resources mmio_range, u32 reg, u32 clr_bits)
+{
+	u32 bits = msm_fd_hw_read_reg(fd, mmio_range, reg);
+
+	msm_fd_hw_write_reg(fd, mmio_range, reg, (bits & ~clr_bits));
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd set register bits.
+ * @fd: Pointer to fd device.
+ * @base_idx: Fd memory resource index.
+ * @reg: Register addr need to be read from.
+ * @set_bits: Bits need to be set to register.
+ */
+static inline void msm_fd_hw_reg_set(struct msm_fd_device *fd,
+	enum msm_fd_mem_resources mmio_range, u32 reg, u32 set_bits)
+{
+	u32 bits = msm_fd_hw_read_reg(fd, mmio_range, reg);
+
+	msm_fd_hw_write_reg(fd, mmio_range, reg, (bits | set_bits));
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd set size mode register.
+ * @fd: Pointer to fd device.
+ * @mode: Size mode to be set.
+ */
+static inline void msm_fd_hw_set_size_mode(struct msm_fd_device *fd, u32 mode)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_IMAGE_SIZE, mode);
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd set crop registers.
+ * @fd: Pointer to fd device.
+ * @crop: Pointer to v4l2 crop struct containing the crop information
+ */
+static inline void msm_fd_hw_set_crop(struct msm_fd_device *fd,
+	struct v4l2_rect *crop)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_START_X,
+		(crop->top & MSM_FD_START_X_MASK));
+
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_START_Y,
+		(crop->left & MSM_FD_START_Y_MASK));
+
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_SIZE_X,
+		(crop->width & MSM_FD_SIZE_X_MASK));
+
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_SIZE_Y,
+		(crop->height & MSM_FD_SIZE_Y_MASK));
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd set bytes per line register.
+ * @fd: Pointer to fd device.
+ * @b: Bytes per line need to be set.
+ */
+static inline void msm_fd_hw_set_bytesperline(struct msm_fd_device *fd, u32 b)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_LINE_BYTES,
+		(b & MSM_FD_LINE_BYTES_MASK));
+}
+
+/*
+ * msm_fd_hw_reg_clr - Fd set image address.
+ * @fd: Pointer to fd device.
+ * @addr: Input image address need to be set.
+ */
+static inline void msm_fd_hw_set_image_addr(struct msm_fd_device *fd, u32 addr)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_IMAGE_ADDR, addr);
+}
+
+/*
+ * msm_fd_hw_set_work_addr - Fd set working buffer address.
+ * @fd: Pointer to fd device.
+ * @addr: Working buffer address need to be set.
+ */
+static inline void msm_fd_hw_set_work_addr(struct msm_fd_device *fd, u32 addr)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_WORK_ADDR, addr);
+}
+
+/*
+ * msm_fd_hw_set_direction_angle - Fd set face direction and face angle.
+ * @fd: Pointer to fd device.
+ * @direction: Face direction need to be set.
+ * @angle: Face angle need to be set.
+ */
+static inline void msm_fd_hw_set_direction_angle(struct msm_fd_device *fd,
+	u32 direction, u32 angle)
+{
+	u32 reg;
+	u32 value;
+
+	value = direction | (angle ? 1 << (angle + 1) : 0);
+	if (value > MSM_FD_CONDT_DIR_MAX)
+		value = MSM_FD_CONDT_DIR_MAX;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT);
+
+	reg &= ~MSM_FD_CONDT_DIR_MASK;
+	reg |= (value << MSM_FD_CONDT_DIR_SHIFT);
+
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT, reg);
+}
+
+/*
+ * msm_fd_hw_set_min_face - Fd set minimum face size register.
+ * @fd: Pointer to fd device.
+ * @size: Minimum face size need to be set.
+ */
+static inline void msm_fd_hw_set_min_face(struct msm_fd_device *fd, u32 size)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT);
+
+	reg &= ~MSM_FD_CONDT_MIN_MASK;
+	reg |= (size << MSM_FD_CONDT_MIN_SHIFT);
+
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONDT, reg);
+}
+
+/*
+ * msm_fd_hw_set_threshold - Fd set detection threshold register.
+ * @fd: Pointer to fd device.
+ * @c: Maximum face count need to be set.
+ */
+static inline void msm_fd_hw_set_threshold(struct msm_fd_device *fd, u32 thr)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_DHINT,
+		(thr & MSM_FD_DHINT_MASK));
+}
+
+/*
+ * msm_fd_hw_srst - Sw reset control registers.
+ * @fd: Pointer to fd device.
+ *
+ * Before every processing we need to toggle this bit,
+ * This functions set sw reset control bit to 1/0.
+ */
+static inline void msm_fd_hw_srst(struct msm_fd_device *fd)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL,
+		MSM_FD_CONTROL_SRST);
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, 0);
+}
+
+/*
+ * msm_fd_hw_get_face_count - Fd read face count register.
+ * @fd: Pointer to fd device.
+ */
+int msm_fd_hw_get_face_count(struct msm_fd_device *fd)
+{
+	u32 reg;
+	u32 value;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_RESULT_CNT);
+
+	value = reg & MSM_FD_RESULT_CNT_MASK;
+	if (value > MSM_FD_MAX_FACES_DETECTED) {
+		dev_warn(fd->dev, "Face count %d out of limit\n", value);
+		value = MSM_FD_MAX_FACES_DETECTED;
+	}
+
+	return value;
+}
+
+/*
+ * msm_fd_hw_run - Starts face detection engine.
+ * @fd: Pointer to fd device.
+ *
+ * Before call this function make sure that control sw reset is perfomed
+ * (see function msm_fd_hw_srst).
+ * NOTE: Engine need to be reset before started again.
+ */
+static inline void msm_fd_hw_run(struct msm_fd_device *fd)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL,
+		MSM_FD_CONTROL_RUN);
+}
+
+/*
+ * msm_fd_hw_is_finished - Check if fd hw engine is done with processing.
+ * @fd: Pointer to fd device.
+ *
+ * NOTE: If finish bit is not set, we should not read the result.
+ */
+static int msm_fd_hw_is_finished(struct msm_fd_device *fd)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL);
+
+	return reg & MSM_FD_CONTROL_FINISH;
+}
+
+/*
+ * msm_fd_hw_is_runnig - Check if fd hw engine is busy.
+ * @fd: Pointer to fd device.
+ */
+static int msm_fd_hw_is_runnig(struct msm_fd_device *fd)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL);
+
+	return reg & MSM_FD_CONTROL_RUN;
+}
+
+/*
+ * msm_fd_hw_misc_irq_is_core - Check if fd received misc core irq.
+ * @fd: Pointer to fd device.
+ */
+static int msm_fd_hw_misc_irq_is_core(struct msm_fd_device *fd)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC,
+		MSM_FD_MISC_IRQ_STATUS);
+
+	return reg & MSM_FD_MISC_IRQ_STATUS_CORE_IRQ;
+}
+
+/*
+ * msm_fd_hw_misc_irq_is_halt - Check if fd received misc halt irq.
+ * @fd: Pointer to fd device.
+ */
+static int msm_fd_hw_misc_irq_is_halt(struct msm_fd_device *fd)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC,
+		MSM_FD_MISC_IRQ_STATUS);
+
+	return reg & MSM_FD_MISC_IRQ_STATUS_HALT_REQ;
+}
+
+/*
+ * msm_fd_hw_misc_clear_all_irq - Clear all misc irq statuses.
+ * @fd: Pointer to fd device.
+ */
+static void msm_fd_hw_misc_clear_all_irq(struct msm_fd_device *fd)
+{
+	msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_CLEAR,
+		MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE);
+}
+
+/*
+ * msm_fd_hw_misc_irq_enable - Enable fd misc core and halt irq.
+ * @fd: Pointer to fd device.
+ */
+static void msm_fd_hw_misc_irq_enable(struct msm_fd_device *fd)
+{
+	msm_fd_hw_reg_set(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_MASK,
+		MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE);
+}
+
+/*
+ * msm_fd_hw_misc_irq_disable - Disable fd misc core and halt irq.
+ * @fd: Pointer to fd device.
+ */
+static void msm_fd_hw_misc_irq_disable(struct msm_fd_device *fd)
+{
+	msm_fd_hw_reg_clr(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_MASK,
+		MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE);
+}
+
+/*
+ * msm_fd_hw_get_revision - Get hw revision and store in to device.
+ * @fd: Pointer to fd device.
+ */
+int msm_fd_hw_get_revision(struct msm_fd_device *fd)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC,
+		MSM_FD_MISC_HW_VERSION);
+
+	dev_dbg(fd->dev, "Face detection hw revision 0x%x\n", reg);
+
+	return reg;
+}
+
+/*
+ * msm_fd_hw_get_result_x - Get fd result center x coordinate.
+ * @fd: Pointer to fd device.
+ * @idx: Result face index
+ */
+int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE,
+		MSM_FD_RESULT_CENTER_X(idx));
+
+	return reg;
+}
+
+/*
+ * msm_fd_hw_get_result_y - Get fd result center y coordinate.
+ * @fd: Pointer to fd device.
+ * @idx: Result face index
+ */
+int msm_fd_hw_get_result_y(struct msm_fd_device *fd, int idx)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE,
+		MSM_FD_RESULT_CENTER_Y(idx));
+
+	return reg;
+}
+
+/*
+ * msm_fd_hw_get_result_conf_size - Get fd result confident level and size.
+ * @fd: Pointer to fd device.
+ * @idx: Result face index.
+ * @conf: Pointer to confident value need to be filled.
+ * @size: Pointer to size value need to be filled.
+ */
+void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd,
+	int idx, u32 *conf, u32 *size)
+{
+	u32 reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE,
+		MSM_FD_RESULT_CONF_SIZE(idx));
+
+	*conf = (reg >> MSM_FD_RESULT_CONF_SHIFT) & MSM_FD_RESULT_CONF_MASK;
+	*size = (reg >> MSM_FD_RESULT_SIZE_SHIFT) & MSM_FD_RESULT_SIZE_MASK;
+}
+
+/*
+ * msm_fd_hw_get_result_angle_pose - Get fd result angle and pose.
+ * @fd: Pointer to fd device.
+ * @idx: Result face index.
+ * @angle: Pointer to angle value need to be filled.
+ * @pose: Pointer to pose value need to be filled.
+ */
+void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx,
+	u32 *angle, u32 *pose)
+{
+	u32 reg;
+	u32 pose_reg;
+
+	reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_CORE,
+		MSM_FD_RESULT_ANGLE_POSE(idx));
+	*angle = (reg >> MSM_FD_RESULT_ANGLE_SHIFT) & MSM_FD_RESULT_ANGLE_MASK;
+	pose_reg = (reg >> MSM_FD_RESULT_POSE_SHIFT) & MSM_FD_RESULT_POSE_MASK;
+
+	switch (pose_reg) {
+	case MSM_FD_RESULT_POSE_FRONT:
+		*pose = MSM_FD_POSE_FRONT;
+		break;
+	case MSM_FD_RESULT_POSE_RIGHT_DIAGONAL:
+		*pose = MSM_FD_POSE_RIGHT_DIAGONAL;
+		break;
+	case MSM_FD_RESULT_POSE_RIGHT:
+		*pose = MSM_FD_POSE_RIGHT;
+		break;
+	case MSM_FD_RESULT_POSE_LEFT_DIAGONAL:
+		*pose = MSM_FD_POSE_LEFT_DIAGONAL;
+		break;
+	case MSM_FD_RESULT_POSE_LEFT:
+		*pose = MSM_FD_POSE_LEFT;
+		break;
+	default:
+		dev_err(fd->dev, "Invalid pose from the engine\n");
+		*pose = MSM_FD_POSE_FRONT;
+		break;
+	}
+}
+
+/*
+ * msm_fd_hw_misc_irq_supported - Check if misc irq is supported.
+ * @fd: Pointer to fd device.
+ */
+static int msm_fd_hw_misc_irq_supported(struct msm_fd_device *fd)
+{
+	return fd->hw_revision >= MSM_FD_MISC_IRQ_FROM_REV;
+}
+
+/*
+ * msm_fd_hw_halt - Halt fd core.
+ * @fd: Pointer to fd device.
+ */
+static void msm_fd_hw_halt(struct msm_fd_device *fd)
+{
+	unsigned long time;
+
+	if (msm_fd_hw_misc_irq_supported(fd)) {
+		init_completion(&fd->hw_halt_completion);
+
+		msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_HW_STOP, 1);
+
+		time = wait_for_completion_timeout(&fd->hw_halt_completion,
+			msecs_to_jiffies(MSM_FD_HALT_TIMEOUT_MS));
+		if (!time)
+			dev_err(fd->dev, "Face detection halt timeout\n");
+
+		/* Reset sequence after halt */
+		msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_SW_RESET,
+			MSM_FD_MISC_SW_RESET_SET);
+		msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL,
+			MSM_FD_CONTROL_SRST);
+		msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC,
+			MSM_FD_MISC_SW_RESET, 0);
+		msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_CORE, MSM_FD_CONTROL, 0);
+	}
+}
+
+/*
+ * msm_fd_core_irq - Face detection core irq handler.
+ * @irq: Irq number.
+ * @dev_id: Pointer to fd device.
+ */
+static irqreturn_t msm_fd_hw_core_irq(int irq, void *dev_id)
+{
+	struct msm_fd_device *fd = dev_id;
+
+	if (msm_fd_hw_is_finished(fd))
+		queue_work(fd->work_queue, &fd->work);
+	else
+		dev_err(fd->dev, "Something wrong! FD still running\n");
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * msm_fd_hw_misc_irq - Face detection misc irq handler.
+ * @irq: Irq number.
+ * @dev_id: Pointer to fd device.
+ */
+static irqreturn_t msm_fd_hw_misc_irq(int irq, void *dev_id)
+{
+	struct msm_fd_device *fd = dev_id;
+
+	if (msm_fd_hw_misc_irq_is_core(fd))
+		msm_fd_hw_core_irq(irq, dev_id);
+
+	if (msm_fd_hw_misc_irq_is_halt(fd))
+		complete_all(&fd->hw_halt_completion);
+
+	msm_fd_hw_misc_clear_all_irq(fd);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * msm_fd_hw_request_irq - Configure and enable vbif interface.
+ * @pdev: Pointer to platform device.
+ * @fd: Pointer to fd device.
+ * @work_func: Pointer to work func used for irq bottom half.
+ */
+int msm_fd_hw_request_irq(struct platform_device *pdev,
+	struct msm_fd_device *fd, work_func_t work_func)
+{
+	int ret;
+
+	fd->irq = msm_camera_get_irq(pdev, "fd");
+	if (fd->irq_num < 0) {
+		dev_err(fd->dev, "Can not get fd core irq resource\n");
+		ret = -ENODEV;
+		goto error_irq;
+	}
+
+	/* If vbif is shared we will need wrapper irq for releasing vbif */
+	if (msm_fd_hw_misc_irq_supported(fd)) {
+		ret = msm_camera_register_irq(pdev,
+				fd->irq, msm_fd_hw_misc_irq,
+				IRQF_TRIGGER_RISING, "fd", fd);
+		if (ret) {
+			dev_err(fd->dev, "Can not claim wrapper IRQ\n");
+			goto error_irq;
+		}
+	} else {
+		ret = msm_camera_register_irq(pdev,
+				fd->irq, msm_fd_hw_core_irq,
+				IRQF_TRIGGER_RISING, "fd", fd);
+		if (ret) {
+			dev_err(&pdev->dev, "Can not claim core IRQ\n");
+			goto error_irq;
+		}
+
+	}
+
+	fd->work_queue = alloc_workqueue(MSM_FD_WORQUEUE_NAME,
+		WQ_HIGHPRI | WQ_UNBOUND, 0);
+	if (!fd->work_queue) {
+		dev_err(fd->dev, "Can not register workqueue\n");
+		ret = -ENOMEM;
+		goto error_alloc_workqueue;
+	}
+	INIT_WORK(&fd->work, work_func);
+
+	return 0;
+
+error_alloc_workqueue:
+	msm_camera_unregister_irq(pdev, fd->irq, fd);
+error_irq:
+	return ret;
+}
+
+/*
+ * msm_fd_hw_release_irq - Free core and wrap irq.
+ * @fd: Pointer to fd device.
+ */
+void msm_fd_hw_release_irq(struct msm_fd_device *fd)
+{
+	if (fd->irq)
+		msm_camera_unregister_irq(fd->pdev, fd->irq, fd);
+
+	if (fd->work_queue) {
+		destroy_workqueue(fd->work_queue);
+		fd->work_queue = NULL;
+	}
+}
+
+/*
+ * msm_fd_hw_set_dt_parms_by_name() - read DT params and write to registers.
+ * @fd: Pointer to fd device.
+ * @dt_prop_name: Name of the device tree property to read.
+ * @base_idx: Fd memory resource index.
+ *
+ * This function reads register offset and value pairs from dtsi based on
+ * device tree property name and writes to FD registers.
+ *
+ * Return: 0 on success and negative error on failure.
+ */
+static int32_t msm_fd_hw_set_dt_parms_by_name(struct msm_fd_device *fd,
+			const char *dt_prop_name,
+			enum msm_fd_mem_resources base_idx)
+{
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *dt_reg_settings = NULL;
+	uint32_t dt_count = 0;
+
+	of_node = fd->dev->of_node;
+	pr_debug("%s:%d E\n", __func__, __LINE__);
+
+	if (!of_get_property(of_node, dt_prop_name, &dt_count)) {
+		pr_err("%s: Error property does not exist\n", __func__);
+		return -ENOENT;
+	}
+	if (dt_count % (sizeof(int32_t) * MSM_FD_REG_LAST_IDX)) {
+		pr_err("%s: Error invalid entries\n", __func__);
+		return -EINVAL;
+	}
+	dt_count /= sizeof(int32_t);
+	if (dt_count != 0) {
+		dt_reg_settings = kcalloc(dt_count,
+			sizeof(uint32_t),
+			GFP_KERNEL);
+
+		if (!dt_reg_settings)
+			return -ENOMEM;
+
+		rc = of_property_read_u32_array(of_node,
+				dt_prop_name,
+				dt_reg_settings,
+				dt_count);
+		if (rc < 0) {
+			pr_err("%s: No reg info\n", __func__);
+			kfree(dt_reg_settings);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < dt_count; i = i + MSM_FD_REG_LAST_IDX) {
+			msm_fd_hw_reg_clr(fd, base_idx,
+				dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX],
+				dt_reg_settings[i + MSM_FD_REG_MASK_IDX]);
+			msm_fd_hw_reg_set(fd, base_idx,
+				dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX],
+				dt_reg_settings[i + MSM_FD_REG_VALUE_IDX] &
+				dt_reg_settings[i + MSM_FD_REG_MASK_IDX]);
+			pr_debug("%s:%d] %pK %08x\n", __func__, __LINE__,
+				fd->iomem_base[base_idx] +
+				dt_reg_settings[i + MSM_FD_REG_ADDR_OFFSET_IDX],
+				dt_reg_settings[i + MSM_FD_REG_VALUE_IDX] &
+				dt_reg_settings[i + MSM_FD_REG_MASK_IDX]);
+		}
+		kfree(dt_reg_settings);
+	}
+	return 0;
+}
+
+/*
+ * msm_fd_hw_set_dt_parms() - set FD device tree configuration.
+ * @fd: Pointer to fd device.
+ *
+ * This function holds an array of device tree property names and calls
+ * msm_fd_hw_set_dt_parms_by_name() for each property.
+ *
+ * Return: 0 on success and negative error on failure.
+ */
+static int msm_fd_hw_set_dt_parms(struct msm_fd_device *fd)
+{
+	int rc = 0;
+	uint8_t dt_prop_cnt = MSM_FD_IOMEM_LAST;
+	char *dt_prop_name[MSM_FD_IOMEM_LAST] = {"qcom,fd-core-reg-settings",
+		"qcom,fd-misc-reg-settings", "qcom,fd-vbif-reg-settings"};
+
+	while (dt_prop_cnt) {
+		dt_prop_cnt--;
+		rc = msm_fd_hw_set_dt_parms_by_name(fd,
+			dt_prop_name[dt_prop_cnt],
+			dt_prop_cnt);
+		if (rc == -ENOENT) {
+			pr_debug("%s: No %s property\n", __func__,
+				dt_prop_name[dt_prop_cnt]);
+			rc = 0;
+		} else if (rc < 0) {
+			pr_err("%s: %s params set fail\n", __func__,
+				dt_prop_name[dt_prop_cnt]);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+/*
+ * msm_fd_hw_release_mem_resources - Releases memory resources.
+ * @fd: Pointer to fd device.
+ */
+void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd)
+{
+	msm_camera_put_reg_base(fd->pdev,
+		fd->iomem_base[MSM_FD_IOMEM_MISC], "fd_misc", true);
+	msm_camera_put_reg_base(fd->pdev,
+		fd->iomem_base[MSM_FD_IOMEM_CORE], "fd_core", true);
+	msm_camera_put_reg_base(fd->pdev,
+		fd->iomem_base[MSM_FD_IOMEM_VBIF], "fd_vbif", false);
+}
+
+/*
+ * msm_fd_hw_get_mem_resources - Get memory resources.
+ * @pdev: Pointer to fd platform device.
+ * @fd: Pointer to fd device.
+ *
+ * Get and ioremap platform memory resources.
+ */
+int msm_fd_hw_get_mem_resources(struct platform_device *pdev,
+	struct msm_fd_device *fd)
+{
+	int ret = 0;
+
+	/* Prepare memory resources */
+	fd->iomem_base[MSM_FD_IOMEM_CORE] =
+		msm_camera_get_reg_base(pdev, "fd_core", true);
+	if (!fd->iomem_base[MSM_FD_IOMEM_CORE]) {
+		dev_err(fd->dev, "%s can not map fd_core region\n", __func__);
+		ret = -ENODEV;
+		goto fd_core_base_failed;
+	}
+
+	fd->iomem_base[MSM_FD_IOMEM_MISC] =
+		msm_camera_get_reg_base(pdev, "fd_misc", true);
+	if (!fd->iomem_base[MSM_FD_IOMEM_MISC]) {
+		dev_err(fd->dev, "%s can not map fd_misc region\n", __func__);
+		ret = -ENODEV;
+		goto fd_misc_base_failed;
+	}
+
+	fd->iomem_base[MSM_FD_IOMEM_VBIF] =
+		msm_camera_get_reg_base(pdev, "fd_vbif", false);
+	if (!fd->iomem_base[MSM_FD_IOMEM_VBIF]) {
+		dev_err(fd->dev, "%s can not map fd_vbif region\n", __func__);
+		ret = -ENODEV;
+		goto fd_vbif_base_failed;
+	}
+
+	return ret;
+fd_vbif_base_failed:
+	msm_camera_put_reg_base(pdev,
+		fd->iomem_base[MSM_FD_IOMEM_MISC], "fd_misc", true);
+fd_misc_base_failed:
+	msm_camera_put_reg_base(pdev,
+		fd->iomem_base[MSM_FD_IOMEM_CORE], "fd_core", true);
+fd_core_base_failed:
+	return ret;
+}
+
+/*
+ * msm_fd_hw_bus_request - Request bus for memory access.
+ * @fd: Pointer to fd device.
+ * @idx: Bus bandwidth array index described in device tree.
+ */
+static int msm_fd_hw_bus_request(struct msm_fd_device *fd, unsigned int idx)
+{
+	int ret;
+
+	ret = msm_camera_update_bus_vector(CAM_BUS_CLIENT_FD, idx);
+	if (ret < 0) {
+		dev_err(fd->dev, "Fail bus scale update %d\n", ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_fd_hw_set_clock_rate_idx - Set clock rate based on the index.
+ * @fd: Pointer to fd device.
+ * @idx: Clock Array index described in device tree.
+ */
+static int msm_fd_hw_set_clock_rate_idx(struct msm_fd_device *fd,
+		unsigned int idx)
+{
+	int ret;
+	int i;
+
+	if (idx >= fd->clk_rates_num) {
+		dev_err(fd->dev, "Invalid clock index %u\n", idx);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < fd->clk_num; i++) {
+		ret = msm_camera_clk_set_rate(&fd->pdev->dev,
+			fd->clk[i], fd->clk_rates[idx][i]);
+		if (ret < 0) {
+			dev_err(fd->dev, "fail set rate on idx[%u][%u]\n",
+				idx, i);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * msm_fd_hw_update_settings() - API to set clock rate and bus settings
+ * @fd: Pointer to fd device.
+ * @buf: fd buffer
+ */
+static int msm_fd_hw_update_settings(struct msm_fd_device *fd,
+				struct msm_fd_buffer *buf)
+{
+	int ret = 0;
+	uint32_t clk_rate_idx;
+
+	if (!buf)
+		return 0;
+
+	clk_rate_idx = buf->settings.speed;
+	if (fd->clk_rate_idx == clk_rate_idx)
+		return 0;
+
+	if (fd->bus_client) {
+		ret = msm_fd_hw_bus_request(fd, clk_rate_idx);
+		if (ret < 0) {
+			dev_err(fd->dev, "Fail bus scale update %d\n", ret);
+			return -EINVAL;
+		}
+	}
+
+	ret = msm_fd_hw_set_clock_rate_idx(fd, clk_rate_idx);
+	if (ret < 0) {
+		dev_err(fd->dev, "Fail to set clock rate idx\n");
+		goto end;
+	}
+	dev_dbg(fd->dev, "set clk %d %d", fd->clk_rate_idx, clk_rate_idx);
+	fd->clk_rate_idx = clk_rate_idx;
+
+end:
+	return ret;
+}
+
+/*
+ * msm_fd_hw_get - Get fd hw for performing any hw operation.
+ * @fd: Pointer to fd device.
+ * @clock_rate_idx: Clock rate index.
+ *
+ * Prepare fd hw for operation. Have reference count protected by
+ * fd device mutex.
+ */
+int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx)
+{
+	int ret;
+
+	mutex_lock(&fd->lock);
+
+	if (fd->ref_count == 0) {
+		ret =
+			msm_camera_regulator_enable(fd->vdd_info,
+				fd->num_reg, true);
+		if (ret < 0) {
+			dev_err(fd->dev, "Fail to enable vdd\n");
+			goto error;
+		}
+
+		ret = msm_fd_hw_bus_request(fd, clock_rate_idx);
+		if (ret < 0) {
+			dev_err(fd->dev, "Fail bus request\n");
+			goto error_bus_request;
+		}
+		ret = msm_fd_hw_set_clock_rate_idx(fd, clock_rate_idx);
+		if (ret < 0) {
+			dev_err(fd->dev, "Fail to set clock rate idx\n");
+			goto error_clocks;
+		}
+		ret = msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info,
+				fd->clk, fd->clk_num, true);
+		if (ret < 0) {
+			dev_err(fd->dev, "Fail clk enable request\n");
+			goto error_clocks;
+		}
+
+		if (msm_fd_hw_misc_irq_supported(fd))
+			msm_fd_hw_misc_irq_enable(fd);
+
+		ret = msm_fd_hw_set_dt_parms(fd);
+		if (ret < 0)
+			goto error_set_dt;
+
+		fd->clk_rate_idx = clock_rate_idx;
+	}
+
+	fd->ref_count++;
+	mutex_unlock(&fd->lock);
+
+	return 0;
+
+error_set_dt:
+	if (msm_fd_hw_misc_irq_supported(fd))
+		msm_fd_hw_misc_irq_disable(fd);
+	msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info,
+		fd->clk, fd->clk_num, false);
+error_clocks:
+error_bus_request:
+	msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false);
+error:
+	mutex_unlock(&fd->lock);
+	return ret;
+}
+
+/*
+ * msm_fd_hw_get - Put fd hw.
+ * @fd: Pointer to fd device.
+ *
+ * Release fd hw. Have reference count protected by
+ * fd device mutex.
+ */
+void msm_fd_hw_put(struct msm_fd_device *fd)
+{
+	mutex_lock(&fd->lock);
+	if (WARN_ON(fd->ref_count == 0))
+		goto err;
+
+	if (--fd->ref_count == 0) {
+		msm_fd_hw_halt(fd);
+
+		if (msm_fd_hw_misc_irq_supported(fd))
+			msm_fd_hw_misc_irq_disable(fd);
+
+		/* vector index 0 is 0 ab and 0 ib */
+		msm_fd_hw_bus_request(fd, 0);
+		msm_camera_clk_enable(&fd->pdev->dev, fd->clk_info,
+				fd->clk, fd->clk_num, false);
+		msm_camera_regulator_enable(fd->vdd_info, fd->num_reg, false);
+	}
+err:
+	mutex_unlock(&fd->lock);
+}
+
+/*
+ * msm_fd_hw_attach_iommu - Attach iommu to face detection engine.
+ * @fd: Pointer to fd device.
+ *
+ * Iommu attach have reference count protected by
+ * fd device mutex.
+ */
+static int msm_fd_hw_attach_iommu(struct msm_fd_device *fd)
+{
+	int ret = -EINVAL;
+
+	mutex_lock(&fd->lock);
+
+	if (fd->iommu_attached_cnt == UINT_MAX) {
+		dev_err(fd->dev, "Max count reached! can not attach iommu\n");
+		goto error;
+	}
+
+	if (fd->iommu_attached_cnt == 0) {
+		ret = cam_smmu_get_handle(MSM_FD_SMMU_CB_NAME, &fd->iommu_hdl);
+		if (ret < 0) {
+			dev_err(fd->dev, "get handle failed\n");
+			ret = -ENOMEM;
+			goto error;
+		}
+		ret = cam_smmu_ops(fd->iommu_hdl, CAM_SMMU_ATTACH);
+		if (ret < 0) {
+			dev_err(fd->dev, "Can not attach iommu domain.\n");
+			goto error_attach;
+		}
+	}
+	fd->iommu_attached_cnt++;
+	mutex_unlock(&fd->lock);
+
+	return 0;
+
+error_attach:
+	cam_smmu_destroy_handle(fd->iommu_hdl);
+error:
+	mutex_unlock(&fd->lock);
+	return ret;
+}
+
+/*
+ * msm_fd_hw_detach_iommu - Detach iommu from face detection engine.
+ * @fd: Pointer to fd device.
+ *
+ * Iommu detach have reference count protected by
+ * fd device mutex.
+ */
+static void msm_fd_hw_detach_iommu(struct msm_fd_device *fd)
+{
+	mutex_lock(&fd->lock);
+	if (fd->iommu_attached_cnt == 0) {
+		dev_err(fd->dev, "There is no attached device\n");
+		mutex_unlock(&fd->lock);
+		return;
+	}
+	if (--fd->iommu_attached_cnt == 0) {
+		cam_smmu_ops(fd->iommu_hdl, CAM_SMMU_DETACH);
+		cam_smmu_destroy_handle(fd->iommu_hdl);
+	}
+	mutex_unlock(&fd->lock);
+}
+
+/*
+ * msm_fd_hw_map_buffer - Map buffer to fd hw mmu.
+ * @pool: Pointer to fd memory pool.
+ * @fd: Ion fd.
+ * @buf: Fd buffer handle, for storing mapped buffer information.
+ *
+ * It will map ion fd to fd hw mmu.
+ */
+int msm_fd_hw_map_buffer(struct msm_fd_mem_pool *pool, int fd,
+	struct msm_fd_buf_handle *buf)
+{
+	int ret;
+
+	if (!pool || fd < 0)
+		return -EINVAL;
+
+	ret = msm_fd_hw_attach_iommu(pool->fd_device);
+	if (ret < 0)
+		return -ENOMEM;
+
+	buf->pool = pool;
+	buf->fd = fd;
+	ret = cam_smmu_get_phy_addr(pool->fd_device->iommu_hdl,
+			buf->fd, CAM_SMMU_MAP_RW,
+			&buf->addr, &buf->size);
+	if (ret < 0) {
+		pr_err("Error: cannot get phy addr\n");
+		return -ENOMEM;
+	}
+	return buf->size;
+}
+
+/*
+ * msm_fd_hw_unmap_buffer - Unmap buffer from fd hw mmu.
+ * @buf: Fd buffer handle, for storing mapped buffer information.
+ */
+void msm_fd_hw_unmap_buffer(struct msm_fd_buf_handle *buf)
+{
+	if (buf->size) {
+		cam_smmu_put_phy_addr(buf->pool->fd_device->iommu_hdl,
+			buf->fd);
+		msm_fd_hw_detach_iommu(buf->pool->fd_device);
+	}
+
+	buf->fd = -1;
+	buf->pool = NULL;
+}
+
+/*
+ * msm_fd_hw_enable - Configure and enable fd hw.
+ * @fd: Fd device.
+ * @buffer: Buffer need to be processed.
+ *
+ * Configure and starts fd processing with given buffer.
+ * NOTE: Fd will not be enabled if engine is in running state.
+ */
+static int msm_fd_hw_enable(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer)
+{
+	struct msm_fd_buf_handle *buf_handle =
+		buffer->vb_v4l2_buf.vb2_buf.planes[0].mem_priv;
+
+	if (msm_fd_hw_is_runnig(fd)) {
+		dev_err(fd->dev, "Device is busy we can not enable\n");
+		return 0;
+	}
+
+	msm_fd_hw_srst(fd);
+	msm_fd_hw_set_size_mode(fd, buffer->format.size->reg_val);
+	msm_fd_hw_set_crop(fd, &buffer->format.crop);
+	msm_fd_hw_set_bytesperline(fd, buffer->format.bytesperline);
+	msm_fd_hw_set_image_addr(fd, buf_handle->addr);
+	msm_fd_hw_set_work_addr(fd, buffer->work_addr);
+	msm_fd_hw_set_min_face(fd, buffer->settings.min_size_index);
+	msm_fd_hw_set_threshold(fd, buffer->settings.threshold);
+	msm_fd_hw_set_direction_angle(fd, buffer->settings.direction_index,
+		buffer->settings.angle_index);
+	msm_fd_hw_run(fd);
+	if (fd->recovery_mode)
+		dev_err(fd->dev, "Scheduled buffer in recovery mode\n");
+	return 1;
+}
+
+/*
+ * msm_fd_hw_try_enable - Try to enable fd hw.
+ * @fd: Fd device.
+ * @buffer: Buffer need to be processed.
+ * @state: Enable on device state
+ *
+ * It will enable fd hw if actual device state is equal with state argument.
+ */
+static int msm_fd_hw_try_enable(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer, enum msm_fd_device_state state)
+{
+	int enabled = 0;
+
+	if (state == fd->state) {
+		fd->state = MSM_FD_DEVICE_RUNNING;
+		atomic_set(&buffer->active, 1);
+
+		msm_fd_hw_enable(fd, buffer);
+		enabled = 1;
+	}
+	return enabled;
+}
+
+/*
+ * msm_fd_hw_next_buffer - Get next buffer from fd device processing queue.
+ * @fd: Fd device.
+ */
+struct msm_fd_buffer *msm_fd_hw_get_next_buffer(struct msm_fd_device *fd)
+{
+	struct msm_fd_buffer *buffer = NULL;
+
+	if (!list_empty(&fd->buf_queue))
+		buffer = list_first_entry(&fd->buf_queue,
+			struct msm_fd_buffer, list);
+
+	return buffer;
+}
+
+/*
+ * msm_fd_hw_add_buffer - Add buffer to fd device processing queue.
+ * @fd: Fd device.
+ */
+void msm_fd_hw_add_buffer(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer)
+{
+	MSM_FD_SPIN_LOCK(fd->slock, 1);
+
+	atomic_set(&buffer->active, 0);
+	init_completion(&buffer->completion);
+
+	INIT_LIST_HEAD(&buffer->list);
+	list_add_tail(&buffer->list, &fd->buf_queue);
+
+	MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+}
+
+/*
+ * msm_fd_hw_remove_buffers_from_queue - Removes buffer from
+ *  fd device processing queue.
+ * @fd: Fd device.
+ */
+void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
+	struct vb2_queue *vb2_q)
+{
+	struct msm_fd_buffer *curr_buff;
+	struct msm_fd_buffer *temp;
+	struct msm_fd_buffer *active_buffer;
+	unsigned long time;
+
+	MSM_FD_SPIN_LOCK(fd->slock, 1);
+	active_buffer = NULL;
+	list_for_each_entry_safe(curr_buff, temp, &fd->buf_queue, list) {
+		if (curr_buff->vb_v4l2_buf.vb2_buf.vb2_queue == vb2_q) {
+
+			if (atomic_read(&curr_buff->active))
+				active_buffer = curr_buff;
+			else {
+				/* Do a Buffer done on all the other buffers */
+				vb2_buffer_done(&curr_buff->vb_v4l2_buf.vb2_buf,
+					VB2_BUF_STATE_DONE);
+				list_del(&curr_buff->list);
+			}
+		}
+	}
+	MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+
+	/* We need to wait active buffer to finish */
+	if (active_buffer) {
+		time = wait_for_completion_timeout(&active_buffer->completion,
+			msecs_to_jiffies(MSM_FD_PROCESSING_TIMEOUT_MS));
+
+		MSM_FD_SPIN_LOCK(fd->slock, 1);
+		if (!time) {
+			if (atomic_read(&active_buffer->active)) {
+				atomic_set(&active_buffer->active, 0);
+				/* Do a vb2 buffer done since it timed out */
+				vb2_buffer_done(
+					&active_buffer->vb_v4l2_buf.vb2_buf,
+					VB2_BUF_STATE_DONE);
+				/* Remove active buffer */
+				msm_fd_hw_get_active_buffer(fd, 0);
+				/* Schedule if other buffers are present */
+				msm_fd_hw_schedule_next_buffer(fd, 0);
+			} else {
+				dev_err(fd->dev, "activ buf no longer active\n");
+			}
+		}
+		fd->state = MSM_FD_DEVICE_IDLE;
+		MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+	}
+}
+
+/*
+ * msm_fd_hw_buffer_done - Mark as done and removes from processing queue.
+ * @fd: Fd device.
+ * @buffer: Fd buffer.
+ */
+int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer, u8 lock_flag)
+{
+	int ret = 0;
+
+	if (atomic_read(&buffer->active)) {
+		atomic_set(&buffer->active, 0);
+		complete_all(&buffer->completion);
+	} else {
+		ret = -1;
+	}
+	return ret;
+}
+
+/*
+ * msm_fd_hw_get_active_buffer - Get active buffer from fd processing queue.
+ * @fd: Fd device.
+ */
+struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd,
+	u8 lock_flag)
+{
+	struct msm_fd_buffer *buffer = NULL;
+
+	if (!list_empty(&fd->buf_queue)) {
+		buffer = list_first_entry(&fd->buf_queue,
+			struct msm_fd_buffer, list);
+		list_del(&buffer->list);
+	}
+
+	return buffer;
+}
+
+/*
+ * msm_fd_hw_schedule_and_start - Schedule active buffer and start processing.
+ * @fd: Fd device.
+ *
+ * This can be executed only when device is in idle state.
+ */
+int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd)
+{
+	struct msm_fd_buffer *buf;
+
+	MSM_FD_SPIN_LOCK(fd->slock, 1);
+
+	buf = msm_fd_hw_get_next_buffer(fd);
+	if (buf)
+		msm_fd_hw_try_enable(fd, buf, MSM_FD_DEVICE_IDLE);
+
+	MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+
+	msm_fd_hw_update_settings(fd, buf);
+
+	return 0;
+}
+
+/*
+ * msm_fd_hw_schedule_next_buffer - Schedule next buffer and start processing.
+ * @fd: Fd device.
+ *
+ * NOTE: This can be executed only when device is in running state.
+ */
+int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd, u8 lock_flag)
+{
+	struct msm_fd_buffer *buf;
+	int ret;
+
+	if (lock_flag) {
+		MSM_FD_SPIN_LOCK(fd->slock, 1);
+
+		/* We can schedule next buffer only in running state */
+		if (fd->state != MSM_FD_DEVICE_RUNNING) {
+			dev_err(fd->dev, "Can not schedule next buffer\n");
+			MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+			return -EBUSY;
+		}
+
+		buf = msm_fd_hw_get_next_buffer(fd);
+		if (buf) {
+			ret = msm_fd_hw_try_enable(fd, buf,
+				MSM_FD_DEVICE_RUNNING);
+			if (ret == 0) {
+				dev_err(fd->dev, "Can not process next buffer\n");
+				MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+				return -EBUSY;
+			}
+		} else {
+			fd->state = MSM_FD_DEVICE_IDLE;
+			if (fd->recovery_mode)
+				dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n");
+		}
+		MSM_FD_SPIN_UNLOCK(fd->slock, 1);
+	} else {
+		/* We can schedule next buffer only in running state */
+		if (fd->state != MSM_FD_DEVICE_RUNNING) {
+			dev_err(fd->dev, "Can not schedule next buffer\n");
+			return -EBUSY;
+		}
+
+		buf = msm_fd_hw_get_next_buffer(fd);
+		if (buf) {
+			ret = msm_fd_hw_try_enable(fd, buf,
+				MSM_FD_DEVICE_RUNNING);
+			if (ret == 0) {
+				dev_err(fd->dev, "Can not process next buffer\n");
+				return -EBUSY;
+			}
+		} else {
+			fd->state = MSM_FD_DEVICE_IDLE;
+			if (fd->recovery_mode)
+				dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n");
+		}
+	}
+
+	msm_fd_hw_update_settings(fd, buf);
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h
new file mode 100644
index 0000000..84b10f3
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_FD_HW_H__
+#define __MSM_FD_HW_H__
+
+#include "msm_fd_dev.h"
+
+int msm_fd_hw_get_face_count(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx);
+
+int msm_fd_hw_get_result_y(struct msm_fd_device *fd, int idx);
+
+void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd,
+	int idx, u32 *conf, u32 *size);
+
+void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx,
+	u32 *angle, u32 *pose);
+
+int msm_fd_hw_request_irq(struct platform_device *pdev,
+	struct msm_fd_device *fd, work_func_t work_func);
+
+void msm_fd_hw_release_irq(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_revision(struct msm_fd_device *fd);
+
+void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_mem_resources(struct platform_device *pdev,
+	struct msm_fd_device *fd);
+
+int msm_fd_hw_get_iommu(struct msm_fd_device *fd);
+
+void msm_fd_hw_put_iommu(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_regulators(struct msm_fd_device *fd);
+
+int msm_fd_hw_put_regulators(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_clocks(struct msm_fd_device *fd);
+
+int msm_fd_hw_put_clocks(struct msm_fd_device *fd);
+
+int msm_fd_hw_get_bus(struct msm_fd_device *fd);
+
+void msm_fd_hw_put_bus(struct msm_fd_device *fd);
+
+int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx);
+
+void msm_fd_hw_put(struct msm_fd_device *fd);
+
+int msm_fd_hw_map_buffer(struct msm_fd_mem_pool *pool, int fd,
+	struct msm_fd_buf_handle *buf);
+
+void msm_fd_hw_unmap_buffer(struct msm_fd_buf_handle *buf);
+
+void msm_fd_hw_add_buffer(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer);
+
+void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
+	struct vb2_queue *vb2_q);
+
+int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
+	struct msm_fd_buffer *buffer, u8 lock_flag);
+
+struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd,
+	u8 lock_flag);
+
+struct msm_fd_buffer *msm_fd_hw_get_next_buffer(struct msm_fd_device *fd);
+
+int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd);
+
+int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd, u8 lock_flag);
+
+#endif /* __MSM_FD_HW_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_regs.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_regs.h
new file mode 100644
index 0000000..beb192b
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_regs.h
@@ -0,0 +1,169 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_FD_REGS_H__
+#define __MSM_FD_REGS_H__
+
+/* FD core registers */
+#define MSM_FD_CONTROL (0x00)
+#define MSM_FD_CONTROL_SRST   (1 << 0)
+#define MSM_FD_CONTROL_RUN    (1 << 1)
+#define MSM_FD_CONTROL_FINISH (1 << 2)
+
+#define MSM_FD_RESULT_CNT (0x04)
+#define MSM_FD_RESULT_CNT_MASK (0x3F)
+
+#define MSM_FD_CONDT (0x08)
+#define MSM_FD_CONDT_MIN_MASK  (0x03)
+#define MSM_FD_CONDT_MIN_SHIFT (0x00)
+#define MSM_FD_CONDT_DIR_MAX   (0x08)
+#define MSM_FD_CONDT_DIR_MASK  (0x3C)
+#define MSM_FD_CONDT_DIR_SHIFT (0x02)
+
+#define MSM_FD_START_X (0x0C)
+#define MSM_FD_START_X_MASK (0x3FF)
+
+#define MSM_FD_START_Y (0x10)
+#define MSM_FD_START_Y_MASK (0x1FF)
+
+#define MSM_FD_SIZE_X (0x14)
+#define MSM_FD_SIZE_X_MASK (0x3FF)
+
+#define MSM_FD_SIZE_Y (0x18)
+#define MSM_FD_SIZE_Y_MASK (0x1FF)
+
+#define MSM_FD_DHINT (0x1C)
+#define MSM_FD_DHINT_MASK (0xF)
+
+#define MSM_FD_IMAGE_ADDR (0x24)
+#define MSM_FD_IMAGE_ADDR_ALIGN (0x8)
+
+#define MSM_FD_WORK_ADDR (0x28)
+#define MSM_FD_WORK_ADDR_ALIGN (0x8)
+
+#define MSM_FD_IMAGE_SIZE (0x2C)
+#define MSM_FD_IMAGE_SIZE_QVGA  (0x0)
+#define MSM_FD_IMAGE_SIZE_VGA   (0x1)
+#define MSM_FD_IMAGE_SIZE_WQVGA (0x2)
+#define MSM_FD_IMAGE_SIZE_WVGA  (0x3)
+
+#define MSM_FD_LINE_BYTES (0x30)
+#define MSM_FD_LINE_BYTES_MASK  (0x1FFF)
+#define MSM_FD_LINE_BYTES_ALIGN (0x8)
+
+#define MSM_FD_RESULT_CENTER_X(x) (0x400 + (0x10 * (x)))
+
+#define MSM_FD_RESULT_CENTER_Y(x) (0x404 + (0x10 * (x)))
+
+#define MSM_FD_RESULT_CONF_SIZE(x) (0x408 + (0x10 * (x)))
+#define MSM_FD_RESULT_SIZE_MASK  (0x1FF)
+#define MSM_FD_RESULT_SIZE_SHIFT (0x000)
+#define MSM_FD_RESULT_CONF_MASK  (0xF)
+#define MSM_FD_RESULT_CONF_SHIFT (0x9)
+
+#define MSM_FD_RESULT_ANGLE_POSE(x) (0x40C + (0x10 * (x)))
+#define MSM_FD_RESULT_ANGLE_MASK  (0x1FF)
+#define MSM_FD_RESULT_ANGLE_SHIFT (0x000)
+#define MSM_FD_RESULT_POSE_MASK   (0x7)
+#define MSM_FD_RESULT_POSE_SHIFT  (0x9)
+#define MSM_FD_RESULT_POSE_FRONT           (0x1)
+#define MSM_FD_RESULT_POSE_RIGHT_DIAGONAL  (0x2)
+#define MSM_FD_RESULT_POSE_RIGHT           (0x3)
+#define MSM_FD_RESULT_POSE_LEFT_DIAGONAL   (0x4)
+#define MSM_FD_RESULT_POSE_LEFT            (0x5)
+
+/* FD misc registers */
+#define MSM_FD_MISC_HW_VERSION (0x00)
+#define MSM_FD_MISC_CGC_DISABLE (0x04)
+#define MSM_FD_HW_STOP          (0x08)
+
+#define MSM_FD_MISC_SW_RESET (0x10)
+#define MSM_FD_MISC_SW_RESET_SET (1 << 0)
+
+#define MSM_FD_MISC_FIFO_STATUS (0x14)
+#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_MAST (0x1F)
+#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_SHIFT (0)
+#define MSM_FD_MISC_FIFO_STATUS_RFIFO_FULL  (1 << 13)
+#define MSM_FD_MISC_FIFO_STATUS_RFIFO_EMPTY (1 << 14)
+#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_MAST (0x1F)
+#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_SHIFT (16)
+#define MSM_FD_MISC_FIFO_STATUS_WFIFO_EMPTY (1 << 29)
+#define MSM_FD_MISC_FIFO_STATUS_WFIFO_FULL  (1 << 30)
+
+#define MSM_FD_MISC_DATA_ENDIAN (0x18)
+#define MSM_FD_MISC_DATA_ENDIAN_BYTE_SWAP_SET (1 << 0)
+
+#define MSM_FD_MISC_VBIF_REQ_PRIO (0x20)
+#define MSM_FD_MISC_VBIF_REQ_PRIO_MASK (0x3)
+
+#define MSM_FD_MISC_VBIF_PRIO_LEVEL (0x24)
+#define MSM_FD_MISC_VBIF_PRIO_LEVEL_MASK (0x3)
+
+#define MSM_FD_MISC_VBIF_MMU_PDIRECT (0x28)
+#define MSM_FD_MISC_VBIF_MMU_PDIRECT_INCREMENT (1 << 0)
+
+#define MSM_FD_MISC_VBIF_IRQ_CLR (0x30)
+#define MSM_FD_MISC_VBIF_IRQ_CLR_ALL (1 << 0)
+
+#define MSM_FD_MISC_VBIF_DONE_STATUS (0x34)
+#define MSM_FD_MISC_VBIF_DONE_STATUS_WRITE (1 << 0)
+#define MSM_FD_MISC_VBIF_DONE_STATUS_READ  (1 << 1)
+
+#define MSM_FD_MISC_IRQ_MASK (0x50)
+#define MSM_FD_MISC_IRQ_MASK_HALT_REQ (1 << 1)
+#define MSM_FD_MISC_IRQ_MASK_CORE_IRQ (1 << 0)
+
+#define MSM_FD_MISC_IRQ_STATUS (0x54)
+#define MSM_FD_MISC_IRQ_STATUS_HALT_REQ (1 << 1)
+#define MSM_FD_MISC_IRQ_STATUS_CORE_IRQ (1 << 0)
+
+#define MSM_FD_MISC_IRQ_CLEAR (0x58)
+#define MSM_FD_MISC_IRQ_CLEAR_HALT (1 << 1)
+#define MSM_FD_MISC_IRQ_CLEAR_CORE (1 << 0)
+
+#define MSM_FD_MISC_TEST_BUS_SEL (0x40)
+#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_MASK  (0xF)
+#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_SHIFT (0)
+#define MSM_FD_MISC_TEST_BUS_SEL_7_0_MASK    (0x3)
+#define MSM_FD_MISC_TEST_BUS_SEL_7_0_SHIFT   (16)
+#define MSM_FD_MISC_TEST_BUS_SEL_15_8_MASK   (0x3)
+#define MSM_FD_MISC_TEST_BUS_SEL_15_8_SHIFT  (18)
+#define MSM_FD_MISC_TEST_BUS_SEL_23_16_MASK  (0x3)
+#define MSM_FD_MISC_TEST_BUS_SEL_23_16_SHIFT (20)
+#define MSM_FD_MISC_TEST_BUS_SEL_31_24_MASK  (0x3)
+#define MSM_FD_MISC_TEST_BUS_SEL_31_24_SHIFT (22)
+
+#define MSM_FD_MISC_AHB_TEST_EN (0x44)
+#define MSM_FD_MISC_AHB_TEST_EN_MASK (0x3)
+
+#define MSM_FD_MISC_FD2VBIF_INT_TEST_SEL  (0x48)
+#define MSM_FD_MISC_FD2VBIF_INT_TEST_MASK (0xF)
+
+#define MSM_FD_MISC_TEST_BUS (0x4C)
+
+/* FD vbif registers */
+#define MSM_FD_VBIF_CLKON                   (0x04)
+#define MSM_FD_VBIF_QOS_OVERRIDE_EN         (0x10)
+#define MSM_FD_VBIF_QOS_OVERRIDE_REQPRI     (0x18)
+#define MSM_FD_VBIF_QOS_OVERRIDE_PRILVL     (0x1C)
+#define MSM_FD_VBIF_IN_RD_LIM_CONF0         (0xB0)
+#define MSM_FD_VBIF_IN_WR_LIM_CONF0         (0xC0)
+#define MSM_FD_VBIF_OUT_RD_LIM_CONF0        (0xD0)
+#define MSM_FD_VBIF_OUT_WR_LIM_CONF0        (0xD4)
+#define MSM_FD_VBIF_DDR_OUT_MAX_BURST       (0xD8)
+#define MSM_FD_VBIF_ARB_CTL                 (0xF0)
+#define MSM_FD_VBIF_OUT_AXI_AMEMTYPE_CONF0  (0x160)
+#define MSM_FD_VBIF_OUT_AXI_AOOO_EN         (0x178)
+#define MSM_FD_VBIF_OUT_AXI_AOOO            (0x17c)
+#define MSM_FD_VBIF_ROUND_ROBIN_QOS_ARB     (0x124)
+
+#endif /* __MSM_FD_REGS_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/Makefile b/drivers/media/platform/msm/camera_v2/isp/Makefile
new file mode 100644
index 0000000..621d81d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common/
+obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_isp48.o msm_isp47.o msm_isp46.o msm_isp44.o msm_isp40.o msm_isp.o
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
new file mode 100644
index 0000000..fda45cb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -0,0 +1,1514 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+
+#include "msm.h"
+#include "msm_buf_mgr.h"
+#include "cam_smmu_api.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define BUF_DEBUG_FULL 0
+#define MAX_LIST_COUNT 100
+
+static int msm_buf_check_head_sanity(struct msm_isp_bufq *bufq)
+{
+	int rc = 0;
+	struct list_head *prev = NULL;
+	struct list_head *next = NULL;
+
+	if (!bufq) {
+		pr_err("%s: Error! Invalid bufq\n", __func__);
+		return -EINVAL;
+	}
+
+	prev = bufq->head.prev;
+	next = bufq->head.next;
+
+	if (!prev) {
+		pr_err("%s: Error! bufq->head.prev is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!next) {
+		pr_err("%s: Error! bufq->head.next is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (prev->next != &bufq->head) {
+		pr_err("%s: Error! head prev->next is %pK should be %pK\n",
+			__func__, prev->next, &bufq->head);
+		return -EINVAL;
+	}
+
+	if (next->prev != &bufq->head) {
+		pr_err("%s: Error! head next->prev is %pK should be %pK\n",
+			__func__, next->prev, &bufq->head);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static struct msm_isp_bufq *msm_isp_get_bufq(
+	struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle)
+{
+	struct msm_isp_bufq *bufq = NULL;
+	uint32_t bufq_index = bufq_handle & 0xFF;
+
+	/* bufq_handle cannot be 0 */
+	if ((bufq_handle == 0) ||
+		bufq_index >= BUF_MGR_NUM_BUF_Q ||
+		(bufq_index >= buf_mgr->num_buf_q))
+		return NULL;
+
+	bufq = &buf_mgr->bufq[bufq_index];
+	if (bufq->bufq_handle == bufq_handle)
+		return bufq;
+
+	return NULL;
+}
+
+static struct msm_isp_buffer *msm_isp_get_buf_ptr(
+	struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index)
+{
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return buf_info;
+	}
+
+	if (bufq->num_bufs <= buf_index) {
+		pr_err("%s: Invalid buf index\n", __func__);
+		return buf_info;
+	}
+	buf_info = &bufq->bufs[buf_index];
+	return buf_info;
+}
+
+static uint32_t msm_isp_get_buf_handle(
+	struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t session_id, uint32_t stream_id)
+{
+	int i;
+	uint32_t embedded_stream_id = 0;
+
+	for (i = 0; i < buf_mgr->num_buf_q; i++) {
+		if (buf_mgr->bufq[i].session_id == session_id &&
+			buf_mgr->bufq[i].stream_id == stream_id)
+			return 0;
+	}
+
+	/* put stream id in handle, if its stats, use FFFF */
+	if (stream_id & (1 << 31))
+		embedded_stream_id = 0xFFFF;
+	else
+		embedded_stream_id = stream_id;
+
+	for (i = 0; i < buf_mgr->num_buf_q; i++) {
+		if (buf_mgr->bufq[i].bufq_handle == 0) {
+			buf_mgr->bufq[i].bufq_handle =
+				embedded_stream_id << 8 | i;
+			return buf_mgr->bufq[i].bufq_handle;
+		}
+	}
+	return 0;
+}
+
+static int msm_isp_free_bufq_handle(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle)
+{
+	struct msm_isp_bufq *bufq =
+		msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq)
+		return -EINVAL;
+
+	/* Set everything except lock to 0 */
+	bufq->bufq_handle = 0;
+	bufq->bufs = NULL;
+	bufq->session_id = 0;
+	bufq->stream_id = 0;
+	bufq->num_bufs = 0;
+	bufq->buf_type = 0;
+	INIT_LIST_HEAD(&bufq->head);
+
+	return 0;
+}
+
+static void msm_isp_copy_planes_from_v4l2_buffer(
+	struct msm_isp_qbuf_buffer *qbuf_buf,
+	const struct vb2_buffer *vb2_buf)
+{
+	int i;
+
+	qbuf_buf->num_planes = vb2_buf->num_planes;
+	for (i = 0; i < qbuf_buf->num_planes; i++) {
+		qbuf_buf->planes[i].addr = vb2_buf->planes[i].m.userptr;
+		qbuf_buf->planes[i].offset = vb2_buf->planes[i].data_offset;
+		qbuf_buf->planes[i].length = vb2_buf->planes[i].length;
+	}
+}
+
+static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_buffer *buf_info,
+	struct msm_isp_qbuf_buffer *qbuf_buf,
+	uint32_t stream_id)
+{
+	int i, rc = -1;
+	int ret;
+	struct msm_isp_buffer_mapped_info *mapped_info;
+	uint32_t accu_length = 0;
+	struct msm_isp_bufq *bufq = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq, stream id %x\n",
+			__func__, stream_id);
+		return -EINVAL;
+	}
+
+	if (qbuf_buf->num_planes > MAX_PLANES_PER_STREAM) {
+		pr_err("%s: Invalid num_planes %d , stream id %x\n",
+			__func__, qbuf_buf->num_planes, stream_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < qbuf_buf->num_planes; i++) {
+		mapped_info = &buf_info->mapped_info[i];
+		mapped_info->buf_fd = qbuf_buf->planes[i].addr;
+
+		if (bufq->security_mode == SECURE_MODE)
+			ret = cam_smmu_get_stage2_phy_addr(buf_mgr->iommu_hdl,
+					mapped_info->buf_fd,
+					CAM_SMMU_MAP_RW,
+					buf_mgr->client,
+					&(mapped_info->paddr),
+					&(mapped_info->len));
+		else
+			ret = cam_smmu_get_phy_addr(buf_mgr->iommu_hdl,
+					mapped_info->buf_fd,
+					CAM_SMMU_MAP_RW,
+					&(mapped_info->paddr),
+					&(mapped_info->len));
+		if (ret) {
+			rc = -EINVAL;
+			pr_err_ratelimited("%s: cannot map address", __func__);
+			goto get_phy_err;
+		}
+
+		mapped_info->paddr += accu_length;
+		accu_length += qbuf_buf->planes[i].length;
+
+		CDBG("%s: plane: %d addr:%pK\n",
+			__func__, i, (void *)mapped_info->paddr);
+
+	}
+	buf_info->num_planes = qbuf_buf->num_planes;
+	return 0;
+get_phy_err:
+	i--;
+
+	return rc;
+}
+
+static void msm_isp_unprepare_v4l2_buf(
+	struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_buffer *buf_info,
+	uint32_t stream_id)
+{
+	int i;
+	struct msm_isp_buffer_mapped_info *mapped_info;
+	struct msm_isp_bufq *bufq = NULL;
+
+	if (!buf_mgr || !buf_info) {
+		pr_err("%s: NULL ptr %pK %pK\n", __func__,
+			buf_mgr, buf_info);
+		return;
+	}
+
+	if (buf_info->num_planes > VIDEO_MAX_PLANES) {
+		pr_err("%s: Invalid num_planes %d , stream id %x\n",
+			__func__, buf_info->num_planes, stream_id);
+		return;
+	}
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq, stream id %x\n",
+			__func__, stream_id);
+		return;
+	}
+
+	for (i = 0; i < buf_info->num_planes; i++) {
+		mapped_info = &buf_info->mapped_info[i];
+		/* SEC_CAM: check any change is needed for secure_mode */
+		if (bufq->security_mode == SECURE_MODE)
+			cam_smmu_put_stage2_phy_addr(buf_mgr->iommu_hdl,
+					mapped_info->buf_fd);
+		else
+			cam_smmu_put_phy_addr(buf_mgr->iommu_hdl,
+					mapped_info->buf_fd);
+	}
+}
+
+static int msm_isp_map_buf(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_buffer_mapped_info *mapped_info, uint32_t fd)
+{
+	int rc = 0;
+	int ret;
+
+	if (!buf_mgr || !mapped_info) {
+		pr_err_ratelimited("%s: %d] NULL ptr buf_mgr %pK mapped_info %pK\n",
+			__func__, __LINE__, buf_mgr, mapped_info);
+		return -EINVAL;
+	}
+	if (buf_mgr->secure_enable == SECURE_MODE)
+		ret = cam_smmu_get_stage2_phy_addr(buf_mgr->iommu_hdl,
+				fd,
+				CAM_SMMU_MAP_RW,
+				buf_mgr->client,
+				&(mapped_info->paddr),
+				&(mapped_info->len));
+	else
+		ret = cam_smmu_get_phy_addr(buf_mgr->iommu_hdl,
+				fd,
+				CAM_SMMU_MAP_RW,
+				&(mapped_info->paddr),
+				&(mapped_info->len));
+
+	if (ret) {
+		rc = -EINVAL;
+		pr_err_ratelimited("%s: cannot map address", __func__);
+		goto smmu_map_error;
+	}
+	CDBG("%s: addr:%pK\n",
+		__func__, (void *)mapped_info->paddr);
+
+	return rc;
+smmu_map_error:
+	if (buf_mgr->secure_enable == SECURE_MODE)
+		cam_smmu_put_stage2_phy_addr(buf_mgr->iommu_hdl,
+					fd);
+	else
+		cam_smmu_put_phy_addr(buf_mgr->iommu_hdl,
+			fd);
+	return rc;
+}
+
+static int msm_isp_unmap_buf(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t fd)
+{
+	if (!buf_mgr) {
+		pr_err_ratelimited("%s: %d] NULL ptr buf_mgr\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	/* SEC_CAMERA: recheck Put part for stats */
+	if (buf_mgr->secure_enable == SECURE_MODE)
+		cam_smmu_put_stage2_phy_addr(buf_mgr->iommu_hdl,
+					fd);
+	else
+		cam_smmu_put_phy_addr(buf_mgr->iommu_hdl,
+			fd);
+
+	return 0;
+}
+
+static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_qbuf_info *info, struct vb2_v4l2_buffer *vb2_v4l2_buf)
+{
+	int rc = -1;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+	struct msm_isp_qbuf_buffer buf;
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr,
+		info->handle, info->buf_idx);
+	if (!buf_info) {
+		pr_err("Invalid buffer prepare\n");
+		return rc;
+	}
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n",
+			__func__);
+		return rc;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) {
+		rc = buf_info->state;
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		return rc;
+	}
+
+	if (buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) {
+		pr_err("%s: Invalid buffer state: %d bufq %x buf-id %d\n",
+			__func__, buf_info->state, bufq->bufq_handle,
+			buf_info->buf_idx);
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		return rc;
+	}
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+
+	if (vb2_v4l2_buf) {
+		msm_isp_copy_planes_from_v4l2_buffer(&buf,
+			&vb2_v4l2_buf->vb2_buf);
+		buf_info->vb2_v4l2_buf = vb2_v4l2_buf;
+	} else {
+		buf = info->buffer;
+	}
+
+	rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, &buf, bufq->stream_id);
+	if (rc < 0) {
+		pr_err_ratelimited("%s: Prepare buffer error\n", __func__);
+		return rc;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED;
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	return rc;
+}
+
+static int msm_isp_buf_unprepare_all(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t buf_handle)
+{
+	int rc = -1, i;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return rc;
+	}
+
+	for (i = 0; i < bufq->num_bufs; i++) {
+		buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i);
+		if (!buf_info) {
+			pr_err("%s: buf not found\n", __func__);
+			return rc;
+		}
+		if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED ||
+				buf_info->state ==
+					MSM_ISP_BUFFER_STATE_INITIALIZED)
+			continue;
+
+		if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_HAL) {
+			if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+			buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)
+				buf_mgr->vb2_ops->put_buf(
+					buf_info->vb2_v4l2_buf,
+					bufq->session_id, bufq->stream_id);
+		}
+		msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info, bufq->stream_id);
+	}
+	return 0;
+}
+
+static int msm_isp_get_buf_by_index(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index,
+	struct msm_isp_buffer **buf_info)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *temp_buf_info;
+	uint32_t i = 0;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return rc;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	if (buf_index >= bufq->num_bufs) {
+		pr_err("%s: Invalid buf index: %d max: %d\n", __func__,
+			buf_index, bufq->num_bufs);
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		return rc;
+	}
+
+	*buf_info = NULL;
+	for (i = 0; bufq->num_bufs; i++) {
+		temp_buf_info = &bufq->bufs[i];
+		if (temp_buf_info && temp_buf_info->buf_idx == buf_index) {
+			*buf_info = temp_buf_info;
+			break;
+		}
+	}
+
+	if (*buf_info) {
+		pr_debug("Found buf in isp buf mgr");
+		rc = 0;
+	}
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	return rc;
+}
+
+static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t buf_handle, int32_t buf_idx)
+{
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return -EINVAL;
+	}
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, buf_idx);
+	if (!buf_info) {
+		pr_err("%s: buf not found\n", __func__);
+		return -EINVAL;
+	}
+	if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED ||
+			buf_info->state == MSM_ISP_BUFFER_STATE_INITIALIZED)
+		return 0;
+
+	if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_HAL) {
+		if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+		buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)
+			buf_mgr->vb2_ops->put_buf(buf_info->vb2_v4l2_buf,
+				bufq->session_id, bufq->stream_id);
+	}
+	msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info, bufq->stream_id);
+
+	return 0;
+}
+
+
+static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id,
+	uint32_t bufq_handle, uint32_t buf_index,
+	struct msm_isp_buffer **buf_info)
+{
+	int rc = -1;
+	unsigned long flags;
+	struct msm_isp_buffer *temp_buf_info = NULL;
+	struct msm_isp_bufq *bufq = NULL;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+
+	if (buf_mgr->open_count == 0) {
+		pr_err_ratelimited("%s: bug mgr open cnt = 0\n",
+			__func__);
+		return 0;
+	}
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err_ratelimited("%s: Invalid bufq\n", __func__);
+		return rc;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	if (!bufq->bufq_handle) {
+		pr_err_ratelimited("%s: Invalid bufq handle\n", __func__);
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		return rc;
+	}
+
+	*buf_info = NULL;
+
+	switch (BUF_SRC(bufq->stream_id)) {
+	case MSM_ISP_BUFFER_SRC_NATIVE:
+		list_for_each_entry(temp_buf_info, &bufq->head, list) {
+			if (temp_buf_info->state ==
+					MSM_ISP_BUFFER_STATE_QUEUED) {
+				list_del_init(&temp_buf_info->list);
+				if (msm_buf_check_head_sanity(bufq) < 0) {
+					spin_unlock_irqrestore(
+						&bufq->bufq_lock, flags);
+					WARN(1, "%s buf_handle 0x%x buf_idx %d\n",
+						__func__,
+						bufq->bufq_handle,
+						temp_buf_info->buf_idx);
+					return -EFAULT;
+				}
+				*buf_info = temp_buf_info;
+				break;
+			}
+		}
+		break;
+	case MSM_ISP_BUFFER_SRC_HAL:
+		if (buf_index == MSM_ISP_INVALID_BUF_INDEX)
+			vb2_v4l2_buf = buf_mgr->vb2_ops->get_buf(
+				bufq->session_id, bufq->stream_id);
+		else
+			vb2_v4l2_buf = buf_mgr->vb2_ops->get_buf_by_idx(
+				bufq->session_id, bufq->stream_id,  buf_index);
+		if (vb2_v4l2_buf) {
+			if (vb2_v4l2_buf->vb2_buf.index < bufq->num_bufs) {
+				*buf_info = &bufq->bufs[vb2_v4l2_buf
+						->vb2_buf.index];
+				(*buf_info)->vb2_v4l2_buf = vb2_v4l2_buf;
+			} else {
+				pr_err("%s: Incorrect buf index %d\n",
+					__func__, vb2_v4l2_buf->vb2_buf.index);
+				rc = -EINVAL;
+			}
+			if ((*buf_info) == NULL) {
+				buf_mgr->vb2_ops->put_buf(vb2_v4l2_buf,
+					bufq->session_id, bufq->stream_id);
+				pr_err("%s: buf index %d not found!\n",
+					__func__, vb2_v4l2_buf->vb2_buf.index);
+				rc = -EINVAL;
+
+			}
+		} else {
+			CDBG("%s: No HAL Buffer session_id: %d stream_id: %d\n",
+				__func__, bufq->session_id, bufq->stream_id);
+			rc = -EINVAL;
+		}
+		break;
+	case MSM_ISP_BUFFER_SRC_SCRATCH:
+		/* In scratch buf case we have only on buffer in queue.
+		 * We return every time same buffer.
+		 */
+		*buf_info = list_entry(bufq->head.next, typeof(**buf_info),
+				list);
+		break;
+	default:
+		pr_err("%s: Incorrect buf source.\n", __func__);
+		rc = -EINVAL;
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		return rc;
+	}
+
+	if (!(*buf_info)) {
+		rc = -ENOMEM;
+	} else {
+		(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
+		rc = 0;
+	}
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	return rc;
+}
+
+static int msm_isp_put_buf_unsafe(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index)
+{
+	int rc = -1;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return rc;
+	}
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
+	if (!buf_info) {
+		pr_err("%s: buf not found\n", __func__);
+		return rc;
+	}
+
+	switch (buf_info->state) {
+	case MSM_ISP_BUFFER_STATE_PREPARED:
+	case MSM_ISP_BUFFER_STATE_DEQUEUED:
+		if (BUF_SRC(bufq->stream_id)) {
+			if (!list_empty(&buf_info->list)) {
+				WARN(1, "%s: buf %x/%x double add\n",
+					__func__, bufq_handle, buf_index);
+				return -EFAULT;
+			}
+			list_add_tail(&buf_info->list, &bufq->head);
+			if (msm_buf_check_head_sanity(bufq) < 0) {
+				WARN(1, "%s buf_handle 0x%x buf_idx %d\n",
+					__func__,
+					bufq->bufq_handle,
+					buf_info->buf_idx);
+				return -EFAULT;
+			}
+		} else {
+			buf_mgr->vb2_ops->put_buf(buf_info->vb2_v4l2_buf,
+				bufq->session_id, bufq->stream_id);
+		}
+		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
+		rc = 0;
+		break;
+	case MSM_ISP_BUFFER_STATE_DISPATCHED:
+		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
+		rc = 0;
+		break;
+	case MSM_ISP_BUFFER_STATE_QUEUED:
+	case MSM_ISP_BUFFER_STATE_DIVERTED:
+	default:
+		WARN(1, "%s: bufq 0x%x, buf idx 0x%x, incorrect state = %d",
+			__func__, bufq_handle, buf_index, buf_info->state);
+		return -EFAULT;
+	}
+
+	return rc;
+}
+
+static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index)
+{
+	int rc = -1;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n", __func__);
+		return rc;
+	}
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
+	if (!buf_info) {
+		pr_err("%s: buf not found\n", __func__);
+		return rc;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+
+	rc = msm_isp_put_buf_unsafe(buf_mgr, bufq_handle, buf_index);
+
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+
+	return rc;
+}
+
+static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index,
+	struct timeval *tv, uint32_t frame_id)
+{
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("Invalid bufq\n");
+		return -EINVAL;
+	}
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
+	if (!buf_info) {
+		pr_err("%s: buf not found\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+
+	buf_info->frame_id = frame_id;
+	if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_NATIVE) {
+		buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED;
+		buf_info->tv = tv;
+	}
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	return 0;
+}
+
+static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t buf_index,
+	struct timeval *tv, uint32_t frame_id, uint32_t output_format)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+	enum msm_isp_buffer_state state;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("Invalid bufq\n");
+		return -EINVAL;
+	}
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
+	if (!buf_info) {
+		pr_err("%s: buf not found\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	state = buf_info->state;
+
+	if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_HAL) {
+		if (state == MSM_ISP_BUFFER_STATE_DEQUEUED) {
+			buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+			spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+			buf_mgr->vb2_ops->buf_done(buf_info->vb2_v4l2_buf,
+				bufq->session_id, bufq->stream_id,
+				frame_id, tv, output_format);
+		} else {
+			spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+		}
+		goto done;
+	}
+
+	/*
+	 * For native buffer put the diverted buffer back to queue since caller
+	 * is not going to send it to CPP, this is error case like
+	 * drop_frame/empty_buffer
+	 */
+	if (state == MSM_ISP_BUFFER_STATE_DIVERTED) {
+		buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED;
+		rc = msm_isp_put_buf_unsafe(buf_mgr, buf_info->bufq_handle,
+			buf_info->buf_idx);
+		if (rc < 0)
+			pr_err("%s: Buf put failed\n", __func__);
+	}
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+done:
+	return rc;
+}
+
+static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type,
+	struct timeval *tv, uint32_t frame_id)
+{
+	int i;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+	unsigned long flags;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("Invalid bufq\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	for (i = 0; i < bufq->num_bufs; i++) {
+		buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, i);
+		if (!buf_info) {
+			pr_err("%s: buf not found\n", __func__);
+			continue;
+		}
+		switch (flush_type) {
+		case MSM_ISP_BUFFER_FLUSH_DIVERTED:
+			if (buf_info->state !=
+				MSM_ISP_BUFFER_STATE_DIVERTED)
+				continue;
+			buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED;
+			msm_isp_put_buf_unsafe(buf_mgr,
+				bufq_handle, buf_info->buf_idx);
+			break;
+		case MSM_ISP_BUFFER_FLUSH_ALL:
+			if (buf_info->state ==
+				MSM_ISP_BUFFER_STATE_DIVERTED)
+				continue;
+			if (buf_info->state !=
+				MSM_ISP_BUFFER_STATE_DEQUEUED)
+				continue;
+			msm_isp_put_buf_unsafe(buf_mgr,
+				bufq_handle, buf_info->buf_idx);
+			break;
+		default:
+			WARN(1, "Invalid flush type %d\n", flush_type);
+		}
+	}
+
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	return 0;
+}
+
+static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_qbuf_info *info)
+{
+	int rc = 0, buf_state;
+	struct msm_isp_bufq *bufq = NULL;
+	struct msm_isp_buffer *buf_info = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, info->handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq, handle 0x%x, stream id %x num_plane %d\n"
+			, __func__, info->handle, (info->handle >> 8),
+			info->buffer.num_planes);
+		return -EINVAL;
+	}
+
+	buf_state = msm_isp_buf_prepare(buf_mgr, info, NULL);
+	if (buf_state < 0) {
+		pr_err_ratelimited("%s: Buf prepare failed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) {
+		buf_info = msm_isp_get_buf_ptr(buf_mgr,
+						info->handle, info->buf_idx);
+		if (!buf_info) {
+			pr_err("%s: buf not found\n", __func__);
+			return -EINVAL;
+		}
+		if (info->dirty_buf) {
+			buf_info->buf_debug.put_state[
+				buf_info->buf_debug.put_state_last]
+				= MSM_ISP_BUFFER_STATE_PUT_BUF;
+			buf_info->buf_debug.put_state_last ^= 1;
+			buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED;
+			rc = msm_isp_put_buf(buf_mgr,
+				info->handle, info->buf_idx);
+		} else {
+			if (BUF_SRC(bufq->stream_id))
+				pr_err("%s: Invalid native buffer state\n",
+					__func__);
+			else {
+				buf_info->buf_debug.put_state[
+					buf_info->buf_debug.put_state_last] =
+					MSM_ISP_BUFFER_STATE_PUT_BUF;
+				buf_info->buf_debug.put_state_last ^= 1;
+				rc = msm_isp_buf_done(buf_mgr,
+					info->handle, info->buf_idx,
+					buf_info->tv, buf_info->frame_id, 0);
+			}
+		}
+	} else {
+		if (BUF_SRC(bufq->stream_id) != MSM_ISP_BUFFER_SRC_HAL) {
+			buf_info = msm_isp_get_buf_ptr(buf_mgr,
+				info->handle, info->buf_idx);
+			if (!buf_info) {
+				pr_err("%s: buf not found\n", __func__);
+				return -EINVAL;
+			}
+
+			buf_info->buf_debug.put_state[
+				buf_info->buf_debug.put_state_last] =
+				MSM_ISP_BUFFER_STATE_PUT_PREPARED;
+			buf_info->buf_debug.put_state_last ^= 1;
+			rc = msm_isp_put_buf(buf_mgr,
+					info->handle, info->buf_idx);
+			if (rc < 0) {
+				pr_err("%s: Buf put failed stream %x\n",
+					__func__, bufq->stream_id);
+				return rc;
+			}
+		}
+	}
+	return 0;
+}
+
+static int msm_isp_buf_dequeue(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_qbuf_info *info)
+{
+	struct msm_isp_buffer *buf_info = NULL;
+	int rc = 0;
+
+	buf_info = msm_isp_get_buf_ptr(buf_mgr, info->handle, info->buf_idx);
+	if (!buf_info) {
+		pr_err("Invalid buffer dequeue\n");
+		return -EINVAL;
+	}
+
+	if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+		buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) {
+		pr_err("%s: Invalid state %d\n", __func__, buf_info->state);
+		return -EINVAL;
+	}
+	msm_isp_buf_unprepare(buf_mgr, info->handle, info->buf_idx);
+
+	buf_info->state = MSM_ISP_BUFFER_STATE_INITIALIZED;
+
+	return rc;
+}
+
+static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t session_id, uint32_t stream_id)
+{
+	int i;
+
+	for (i = 0; i < buf_mgr->num_buf_q; i++) {
+		if (buf_mgr->bufq[i].session_id == session_id &&
+			buf_mgr->bufq[i].stream_id == stream_id) {
+			return buf_mgr->bufq[i].bufq_handle;
+		}
+	}
+	pr_err("%s: No match found 0x%x 0x%x\n", __func__,
+			session_id, stream_id);
+	return 0;
+}
+
+static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, uint32_t *buf_src)
+{
+	struct msm_isp_bufq *bufq = NULL;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq\n",
+			__func__);
+		return -EINVAL;
+	}
+	*buf_src = BUF_SRC(bufq->stream_id);
+
+	return 0;
+}
+
+static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_isp_buf_request_ver2 *buf_request)
+{
+	int i;
+	struct msm_isp_bufq *bufq = NULL;
+
+	CDBG("%s: E\n", __func__);
+
+	if (!buf_request->num_buf || buf_request->num_buf > VB2_MAX_FRAME) {
+		pr_err("Invalid buffer request\n");
+		return -EINVAL;
+	}
+
+	buf_request->handle = msm_isp_get_buf_handle(buf_mgr,
+		buf_request->session_id, buf_request->stream_id);
+	if (!buf_request->handle) {
+		pr_err("Invalid buffer handle\n");
+		return -EINVAL;
+	}
+
+	bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle);
+	if (!bufq) {
+		pr_err("%s: Invalid bufq stream_id %x\n",
+			__func__, buf_request->stream_id);
+
+		return -EINVAL;
+	}
+
+	bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) *
+		buf_request->num_buf, GFP_KERNEL);
+	if (!bufq->bufs) {
+		msm_isp_free_bufq_handle(buf_mgr, buf_request->handle);
+		return -ENOMEM;
+	}
+	spin_lock_init(&bufq->bufq_lock);
+	bufq->bufq_handle = buf_request->handle;
+	bufq->session_id = buf_request->session_id;
+	bufq->stream_id = buf_request->stream_id;
+	bufq->num_bufs = buf_request->num_buf;
+	bufq->buf_type = buf_request->buf_type;
+	INIT_LIST_HEAD(&bufq->head);
+	bufq->security_mode = buf_request->security_mode;
+
+	for (i = 0; i < buf_request->num_buf; i++) {
+		bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED;
+		bufq->bufs[i].buf_debug.put_state[0] =
+			MSM_ISP_BUFFER_STATE_PUT_PREPARED;
+		bufq->bufs[i].buf_debug.put_state[1] =
+			MSM_ISP_BUFFER_STATE_PUT_PREPARED;
+		bufq->bufs[i].buf_debug.put_state_last = 0;
+		bufq->bufs[i].bufq_handle = bufq->bufq_handle;
+		bufq->bufs[i].buf_idx = i;
+		INIT_LIST_HEAD(&bufq->bufs[i].list);
+	}
+
+	return 0;
+}
+
+static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle)
+{
+	struct msm_isp_bufq *bufq = NULL;
+	unsigned long flags;
+
+	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
+	if (!bufq) {
+		pr_err("Invalid bufq release\n");
+		return -EINVAL;
+	}
+
+	msm_isp_buf_unprepare_all(buf_mgr, bufq_handle);
+
+	spin_lock_irqsave(&bufq->bufq_lock, flags);
+	kfree(bufq->bufs);
+	msm_isp_free_bufq_handle(buf_mgr, bufq_handle);
+	spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+
+	return 0;
+}
+
+static void msm_isp_release_all_bufq(
+	struct msm_isp_buf_mgr *buf_mgr)
+{
+	struct msm_isp_bufq *bufq = NULL;
+	unsigned long flags;
+	int i;
+
+	for (i = 0; i < buf_mgr->num_buf_q; i++) {
+		bufq = &buf_mgr->bufq[i];
+		if (!bufq->bufq_handle)
+			continue;
+
+		msm_isp_buf_unprepare_all(buf_mgr, bufq->bufq_handle);
+
+		spin_lock_irqsave(&bufq->bufq_lock, flags);
+		kfree(bufq->bufs);
+		msm_isp_free_bufq_handle(buf_mgr, bufq->bufq_handle);
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	}
+}
+
+
+/**
+ * msm_isp_buf_put_scratch() - Release scratch buffers
+ * @buf_mgr: The buffer structure for h/w
+ *
+ * Returns 0 on success else error code
+ */
+static int msm_isp_buf_put_scratch(struct msm_isp_buf_mgr *buf_mgr)
+{
+	int rc;
+
+	if (!buf_mgr->scratch_buf_addr)
+		return 0;
+
+	if (buf_mgr->secure_enable == SECURE_MODE) {
+		rc = cam_smmu_free_stage2_scratch_mem(buf_mgr->iommu_hdl,
+				buf_mgr->client, buf_mgr->sc_handle);
+		if (buf_mgr->scratch_buf_stats_addr)
+			rc = cam_smmu_put_phy_addr_scratch(buf_mgr->iommu_hdl,
+				buf_mgr->scratch_buf_stats_addr);
+	} else {
+		rc = cam_smmu_put_phy_addr_scratch(buf_mgr->iommu_hdl,
+				buf_mgr->scratch_buf_addr);
+	}
+	if (rc)
+		pr_err("%s: failed to put scratch buffer to img iommu: %d\n",
+			__func__, rc);
+
+
+	if (!rc) {
+		buf_mgr->scratch_buf_addr = 0;
+		buf_mgr->scratch_buf_stats_addr = 0;
+	}
+
+	return rc;
+}
+
+/**
+ * msm_isp_buf_get_scratch() - Create scratch buffers
+ * @buf_mgr: The buffer structure for h/w
+ *
+ * Create and map scratch buffers for all IOMMU's under the buffer
+ * manager.
+ *
+ * Returns 0 on success else error code
+ */
+static int msm_isp_buf_get_scratch(struct msm_isp_buf_mgr *buf_mgr)
+{
+	int rc;
+	size_t range = buf_mgr->scratch_buf_range;
+
+	if (buf_mgr->scratch_buf_addr || !buf_mgr->scratch_buf_range)
+		/* already mapped or not supported */
+		return 0;
+
+	if (buf_mgr->secure_enable == SECURE_MODE) {
+		rc = cam_smmu_alloc_get_stage2_scratch_mem(buf_mgr->iommu_hdl,
+				CAM_SMMU_MAP_RW,
+				buf_mgr->client,
+				&buf_mgr->sc_handle,
+				&buf_mgr->scratch_buf_addr,
+				&range);
+		if (rc)
+			goto done;
+
+		rc = cam_smmu_get_phy_addr_scratch(
+				buf_mgr->iommu_hdl,
+				CAM_SMMU_MAP_RW,
+				&buf_mgr->scratch_buf_stats_addr,
+				buf_mgr->scratch_buf_range,
+				SZ_4K);
+		if (rc)
+			msm_isp_buf_put_scratch(buf_mgr);
+	} else {
+		rc = cam_smmu_get_phy_addr_scratch(
+				buf_mgr->iommu_hdl,
+				CAM_SMMU_MAP_RW,
+				&buf_mgr->scratch_buf_addr,
+				buf_mgr->scratch_buf_range,
+				SZ_4K);
+		buf_mgr->scratch_buf_stats_addr = buf_mgr->scratch_buf_addr;
+	}
+done:
+	if (rc) {
+		pr_err("%s: failed to map scratch buffer to img iommu: %d\n",
+			__func__, rc);
+		return rc;
+	}
+	return rc;
+}
+
+int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr,
+	void *arg)
+{
+	struct msm_vfe_smmu_attach_cmd *cmd = arg;
+	int rc = 0;
+	int32_t stall_disable = 1;
+
+	pr_debug("%s: cmd->security_mode : %d\n", __func__, cmd->security_mode);
+
+	mutex_lock(&buf_mgr->lock);
+	if (cmd->iommu_attach_mode == IOMMU_ATTACH) {
+		/* disable smmu stall on fault */
+		cam_smmu_set_attr(buf_mgr->iommu_hdl,
+			DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
+		/*
+		 * Call hypervisor thru scm call to notify secure or
+		 * non-secure mode
+		 */
+		if (buf_mgr->attach_ref_cnt == 0) {
+			if (cmd->security_mode == SECURE_MODE)
+				rc = cam_smmu_ops(buf_mgr->iommu_hdl,
+					CAM_SMMU_ATTACH_SEC_VFE_NS_STATS);
+			else
+				rc = cam_smmu_ops(buf_mgr->iommu_hdl,
+					CAM_SMMU_ATTACH);
+			if (rc < 0) {
+				pr_err("%s: img smmu attach error, rc :%d\n",
+					__func__, rc);
+				goto err1;
+			}
+			buf_mgr->secure_enable = cmd->security_mode;
+		}
+		buf_mgr->attach_ref_cnt++;
+		rc = msm_isp_buf_get_scratch(buf_mgr);
+		if (rc)
+			goto err2;
+	}
+
+	mutex_unlock(&buf_mgr->lock);
+	return rc;
+
+err2:
+	if (buf_mgr->secure_enable == SECURE_MODE)
+		cam_smmu_ops(buf_mgr->iommu_hdl,
+				CAM_SMMU_DETACH_SEC_VFE_NS_STATS);
+	else
+		cam_smmu_ops(buf_mgr->iommu_hdl, CAM_SMMU_DETACH);
+err1:
+	mutex_unlock(&buf_mgr->lock);
+	return rc;
+}
+
+
+static int msm_isp_init_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
+	const char *ctx_name)
+{
+	int rc = -1;
+	int i = 0;
+
+	mutex_lock(&buf_mgr->lock);
+	if (buf_mgr->open_count++) {
+		mutex_unlock(&buf_mgr->lock);
+		return 0;
+	}
+
+	CDBG("%s: E\n", __func__);
+	buf_mgr->attach_ref_cnt = 0;
+
+	buf_mgr->num_buf_q = BUF_MGR_NUM_BUF_Q;
+	memset(buf_mgr->bufq, 0, sizeof(buf_mgr->bufq));
+
+	rc = cam_smmu_get_handle("vfe", &buf_mgr->iommu_hdl);
+	if (rc < 0) {
+		pr_err("vfe get handle failed\n");
+		goto get_handle_error;
+	}
+
+	for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++)
+		spin_lock_init(&buf_mgr->bufq[i].bufq_lock);
+
+	buf_mgr->pagefault_debug_disable = 0;
+	buf_mgr->frameId_mismatch_recovery = 0;
+	/* create ION client */
+	buf_mgr->client = msm_ion_client_create("vfe");
+get_handle_error:
+	mutex_unlock(&buf_mgr->lock);
+	return 0;
+}
+
+static int msm_isp_deinit_isp_buf_mgr(
+	struct msm_isp_buf_mgr *buf_mgr)
+{
+	mutex_lock(&buf_mgr->lock);
+	if (buf_mgr->open_count > 0)
+		buf_mgr->open_count--;
+
+	if (buf_mgr->open_count) {
+		mutex_unlock(&buf_mgr->lock);
+		return 0;
+	}
+	msm_isp_release_all_bufq(buf_mgr);
+	buf_mgr->num_buf_q = 0;
+	buf_mgr->pagefault_debug_disable = 0;
+
+	msm_isp_buf_put_scratch(buf_mgr);
+	if (buf_mgr->attach_ref_cnt != 0) {
+		if (buf_mgr->secure_enable == SECURE_MODE)
+			cam_smmu_ops(buf_mgr->iommu_hdl,
+				CAM_SMMU_DETACH_SEC_VFE_NS_STATS);
+		else
+			cam_smmu_ops(buf_mgr->iommu_hdl, CAM_SMMU_DETACH);
+	}
+	cam_smmu_destroy_handle(buf_mgr->iommu_hdl);
+	buf_mgr->attach_ref_cnt = 0;
+	buf_mgr->secure_enable = 0;
+	buf_mgr->attach_ref_cnt = 0;
+	if (buf_mgr->client) {
+		ion_client_destroy(buf_mgr->client);
+		buf_mgr->client = NULL;
+	}
+	mutex_unlock(&buf_mgr->lock);
+	return 0;
+}
+
+int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr,
+	unsigned int cmd, void *arg)
+{
+	int rc = -EINVAL;
+
+	switch (cmd) {
+	case VIDIOC_MSM_ISP_REQUEST_BUF: {
+		struct msm_isp_buf_request *buf_req = arg;
+		struct msm_isp_buf_request_ver2 buf_req_ver2;
+
+		memcpy(&buf_req_ver2, buf_req,
+			sizeof(struct msm_isp_buf_request));
+		buf_req_ver2.security_mode = NON_SECURE_MODE;
+		rc = buf_mgr->ops->request_buf(buf_mgr, &buf_req_ver2);
+		memcpy(buf_req, &buf_req_ver2,
+			sizeof(struct msm_isp_buf_request));
+		break;
+	}
+	case VIDIOC_MSM_ISP_REQUEST_BUF_VER2: {
+		struct msm_isp_buf_request_ver2 *buf_req_ver2 = arg;
+
+		rc = buf_mgr->ops->request_buf(buf_mgr, buf_req_ver2);
+		break;
+	}
+	case VIDIOC_MSM_ISP_ENQUEUE_BUF: {
+		struct msm_isp_qbuf_info *qbuf_info = arg;
+
+		rc = buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info);
+		break;
+	}
+	case VIDIOC_MSM_ISP_DEQUEUE_BUF: {
+		struct msm_isp_qbuf_info *qbuf_info = arg;
+
+		rc = buf_mgr->ops->dequeue_buf(buf_mgr, qbuf_info);
+		break;
+	}
+	case VIDIOC_MSM_ISP_RELEASE_BUF: {
+		struct msm_isp_buf_request *buf_req = arg;
+
+		rc = buf_mgr->ops->release_buf(buf_mgr, buf_req->handle);
+		break;
+	}
+	case VIDIOC_MSM_ISP_UNMAP_BUF: {
+		struct msm_isp_unmap_buf_req *unmap_req = arg;
+
+		rc = buf_mgr->ops->unmap_buf(buf_mgr, unmap_req->fd);
+		break;
+	}
+	}
+	return rc;
+}
+
+static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
+	unsigned long fault_addr)
+{
+	struct msm_isp_buffer *bufs = NULL;
+	uint32_t i = 0, j = 0, k = 0, rc = 0;
+	char *print_buf = NULL, temp_buf[100];
+	uint32_t print_buf_size = 2000;
+	unsigned long start_addr = 0, end_addr = 0;
+	int buf_addr_delta = -1;
+	int temp_delta = 0;
+	uint32_t debug_stream_id = 0;
+	uint32_t debug_buf_idx = 0;
+	uint32_t debug_buf_plane = 0;
+	unsigned long debug_start_addr = 0;
+	unsigned long debug_end_addr = 0;
+	uint32_t debug_frame_id = 0;
+	enum msm_isp_buffer_state debug_state = MSM_ISP_BUFFER_STATE_UNUSED;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+
+	if (!buf_mgr) {
+		pr_err_ratelimited("%s: %d] NULL buf_mgr\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) {
+		bufq = &buf_mgr->bufq[i];
+
+		spin_lock_irqsave(&bufq->bufq_lock, flags);
+		if (!bufq->bufq_handle) {
+			spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+			continue;
+		}
+
+		for (j = 0; j < bufq->num_bufs; j++) {
+			bufs = &bufq->bufs[j];
+			if (!bufs)
+				continue;
+
+			for (k = 0; k < bufs->num_planes; k++) {
+				start_addr = bufs->
+						mapped_info[k].paddr;
+				end_addr = bufs->mapped_info[k].paddr +
+					bufs->mapped_info[k].len - 1;
+				temp_delta = fault_addr - start_addr;
+				if (temp_delta < 0)
+					continue;
+
+				if (buf_addr_delta == -1 ||
+					temp_delta < buf_addr_delta) {
+					buf_addr_delta = temp_delta;
+					debug_stream_id = bufq->stream_id;
+					debug_buf_idx = j;
+					debug_buf_plane = k;
+					debug_start_addr = start_addr;
+					debug_end_addr = end_addr;
+					debug_frame_id = bufs->frame_id;
+					debug_state = bufs->state;
+				}
+			}
+		}
+		start_addr = 0;
+		end_addr = 0;
+		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
+	}
+
+	pr_err("%s: ==== SMMU page fault addr %lx ====\n", __func__,
+		fault_addr);
+	pr_err("%s: nearby stream id %x, frame_id %d\n", __func__,
+		debug_stream_id, debug_frame_id);
+	pr_err("%s: nearby buf index %d, plane %d, state %d\n", __func__,
+		debug_buf_idx, debug_buf_plane, debug_state);
+	pr_err("%s: buf address %pK -- %pK\n", __func__,
+		(void *)debug_start_addr, (void *)debug_end_addr);
+
+	if (BUF_DEBUG_FULL) {
+		print_buf = kzalloc(print_buf_size, GFP_ATOMIC);
+		if (!print_buf) {
+			pr_err("%s failed: No memory", __func__);
+			return -ENOMEM;
+		}
+		snprintf(print_buf, print_buf_size, "%s\n", __func__);
+		for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) {
+			if (i % 2 == 0 && i > 0) {
+				pr_err("%s\n", print_buf);
+				print_buf[0] = 0;
+			}
+			if (buf_mgr->bufq[i].bufq_handle != 0) {
+				snprintf(temp_buf, sizeof(temp_buf),
+					"handle %x stream %x num_bufs %d\n",
+					buf_mgr->bufq[i].bufq_handle,
+					buf_mgr->bufq[i].stream_id,
+					buf_mgr->bufq[i].num_bufs);
+				strlcat(print_buf, temp_buf, print_buf_size);
+				for (j = 0; j < buf_mgr->bufq[i].num_bufs;
+					j++) {
+					bufs = &buf_mgr->bufq[i].bufs[j];
+					if (!bufs)
+						break;
+
+					for (k = 0; k < bufs->num_planes; k++) {
+						start_addr = bufs->
+							mapped_info[k].paddr;
+						end_addr = bufs->mapped_info[k].
+							paddr + bufs->
+							mapped_info[k].len;
+						snprintf(temp_buf,
+							sizeof(temp_buf),
+							" buf %d plane %d start_addr %pK end_addr %pK\n",
+							j, k,
+							(void *)start_addr,
+							(void *)end_addr);
+						strlcat(print_buf, temp_buf,
+							print_buf_size);
+					}
+				}
+				start_addr = 0;
+				end_addr = 0;
+			}
+		}
+		pr_err("%s\n", print_buf);
+		kfree(print_buf);
+	}
+	return rc;
+}
+
+static struct msm_isp_buf_ops isp_buf_ops = {
+	.request_buf = msm_isp_request_bufq,
+	.enqueue_buf = msm_isp_buf_enqueue,
+	.dequeue_buf = msm_isp_buf_dequeue,
+	.release_buf = msm_isp_release_bufq,
+	.get_bufq_handle = msm_isp_get_bufq_handle,
+	.get_buf_src = msm_isp_get_buf_src,
+	.get_buf = msm_isp_get_buf,
+	.get_buf_by_index = msm_isp_get_buf_by_index,
+	.map_buf = msm_isp_map_buf,
+	.unmap_buf = msm_isp_unmap_buf,
+	.put_buf = msm_isp_put_buf,
+	.flush_buf = msm_isp_flush_buf,
+	.buf_done = msm_isp_buf_done,
+	.buf_mgr_init = msm_isp_init_isp_buf_mgr,
+	.buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr,
+	.buf_mgr_debug = msm_isp_buf_mgr_debug,
+	.get_bufq = msm_isp_get_bufq,
+	.buf_divert = msm_isp_buf_divert,
+};
+
+int msm_isp_create_isp_buf_mgr(
+	struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_sd_req_vb2_q *vb2_ops,
+	struct device *dev,
+	uint32_t scratch_buf_range)
+{
+	int rc = 0;
+
+	if (buf_mgr->init_done)
+		return rc;
+
+	buf_mgr->ops = &isp_buf_ops;
+	buf_mgr->vb2_ops = vb2_ops;
+	buf_mgr->open_count = 0;
+	buf_mgr->pagefault_debug_disable = 0;
+	buf_mgr->secure_enable = NON_SECURE_MODE;
+	buf_mgr->scratch_buf_range = scratch_buf_range;
+	mutex_init(&buf_mgr->lock);
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
new file mode 100644
index 0000000..4ea6dd6
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -0,0 +1,224 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_ISP_BUF_H_
+#define _MSM_ISP_BUF_H_
+
+#include <media/msmb_isp.h>
+#include "msm_sd.h"
+
+/* Buffer type could be userspace / HAL.
+ * Userspase could provide native or scratch buffer.
+ */
+#define BUF_SRC(id) ( \
+		(id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \
+		(id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \
+				MSM_ISP_BUFFER_SRC_HAL)
+
+/*
+ * This mask can be set dynamically if there are more than 2 VFE
+ * and 2 of those are used
+ */
+#define ISP_SHARE_BUF_MASK 0x3
+#define ISP_NUM_BUF_MASK 2
+#define BUF_MGR_NUM_BUF_Q 28
+#define MAX_IOMMU_CTX 2
+
+#define MSM_ISP_INVALID_BUF_INDEX 0xFFFFFFFF
+
+struct msm_isp_buf_mgr;
+
+enum msm_isp_buffer_src_t {
+	MSM_ISP_BUFFER_SRC_HAL,
+	MSM_ISP_BUFFER_SRC_NATIVE,
+	MSM_ISP_BUFFER_SRC_SCRATCH,
+	MSM_ISP_BUFFER_SRC_MAX,
+};
+
+enum msm_isp_buffer_state {
+	MSM_ISP_BUFFER_STATE_UNUSED,         /* not used */
+	MSM_ISP_BUFFER_STATE_INITIALIZED,    /* REQBUF done */
+	MSM_ISP_BUFFER_STATE_PREPARED,       /* BUF mapped */
+	MSM_ISP_BUFFER_STATE_QUEUED,         /* buf queued */
+	MSM_ISP_BUFFER_STATE_DEQUEUED,       /* in use in VFE */
+	MSM_ISP_BUFFER_STATE_DIVERTED,       /* Sent to other hardware*/
+	MSM_ISP_BUFFER_STATE_DISPATCHED,     /* Sent to HAL*/
+};
+
+enum msm_isp_buffer_put_state {
+	MSM_ISP_BUFFER_STATE_PUT_PREPARED,  /* on init */
+	MSM_ISP_BUFFER_STATE_PUT_BUF,       /* on rotation */
+	MSM_ISP_BUFFER_STATE_FLUSH,         /* on recovery */
+	MSM_ISP_BUFFER_STATE_DROP_REG,      /* on drop frame for reg_update */
+	MSM_ISP_BUFFER_STATE_DROP_SKIP,      /* on drop frame for sw skip */
+	MSM_ISP_BUFFER_STATE_RETURN_EMPTY,  /* for return empty */
+};
+
+enum msm_isp_buffer_flush_t {
+	MSM_ISP_BUFFER_FLUSH_DIVERTED,
+	MSM_ISP_BUFFER_FLUSH_ALL,
+};
+
+enum msm_isp_buf_mgr_state {
+	MSM_ISP_BUF_MGR_ATTACH,
+	MSM_ISP_BUF_MGR_DETACH,
+};
+
+struct msm_isp_buffer_mapped_info {
+	size_t len;
+	dma_addr_t paddr;
+	int buf_fd;
+};
+
+struct buffer_cmd {
+	struct list_head list;
+	struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
+struct msm_isp_buffer_debug_t {
+	enum msm_isp_buffer_put_state put_state[2];
+	uint8_t put_state_last;
+};
+
+struct msm_isp_buffer {
+	/*Common Data structure*/
+	int num_planes;
+	struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES];
+	int buf_idx;
+	uint32_t bufq_handle;
+	uint32_t frame_id;
+	struct timeval *tv;
+	/* Indicates whether buffer is used as ping ot pong buffer */
+	uint32_t pingpong_bit;
+	/* Indicates buffer is reconfig due to drop frame */
+	uint32_t is_drop_reconfig;
+
+	/*Native buffer*/
+	struct list_head list;
+	enum msm_isp_buffer_state state;
+
+	struct msm_isp_buffer_debug_t buf_debug;
+
+	/*Vb2 buffer data*/
+	struct vb2_v4l2_buffer *vb2_v4l2_buf;
+};
+
+struct msm_isp_bufq {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t num_bufs;
+	uint32_t bufq_handle;
+	enum msm_isp_buf_type buf_type;
+	struct msm_isp_buffer *bufs;
+	spinlock_t bufq_lock;
+	/*Native buffer queue*/
+	struct list_head head;
+	enum smmu_attach_mode security_mode;
+};
+
+struct msm_isp_buf_ops {
+	int (*request_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		struct msm_isp_buf_request_ver2 *buf_request);
+
+	int (*enqueue_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		struct msm_isp_qbuf_info *info);
+
+	int (*dequeue_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		struct msm_isp_qbuf_info *info);
+
+	int (*release_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle);
+
+	int (*get_bufq_handle)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t session_id, uint32_t stream_id);
+
+	int (*get_buf_src)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle, uint32_t *buf_src);
+
+	int (*get_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id,
+		uint32_t bufq_handle, uint32_t buf_index,
+		struct msm_isp_buffer **buf_info);
+
+	int (*get_buf_by_index)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle, uint32_t buf_index,
+		struct msm_isp_buffer **buf_info);
+
+	int (*map_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		struct msm_isp_buffer_mapped_info *mapped_info, uint32_t fd);
+
+	int (*unmap_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t fd);
+
+	int (*put_buf)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle, uint32_t buf_index);
+
+	int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type,
+	struct timeval *tv, uint32_t frame_id);
+
+	int (*buf_done)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle, uint32_t buf_index,
+		struct timeval *tv, uint32_t frame_id, uint32_t output_format);
+	void (*register_ctx)(struct msm_isp_buf_mgr *buf_mgr,
+		struct device **iommu_ctx1, struct device **iommu_ctx2,
+		int num_iommu_ctx1, int num_iommu_ctx2);
+	int (*buf_mgr_init)(struct msm_isp_buf_mgr *buf_mgr,
+		const char *ctx_name);
+	int (*buf_mgr_deinit)(struct msm_isp_buf_mgr *buf_mgr);
+	int (*buf_mgr_debug)(struct msm_isp_buf_mgr *buf_mgr,
+		unsigned long fault_addr);
+	struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr,
+		uint32_t bufq_handle);
+	int (*buf_divert)(struct msm_isp_buf_mgr *buf_mgr,
+			uint32_t bufq_handle, uint32_t buf_index,
+			struct timeval *tv, uint32_t frame_id);
+};
+
+struct msm_isp_buf_mgr {
+	int init_done;
+	uint32_t open_count;
+	uint32_t pagefault_debug_disable;
+	uint32_t frameId_mismatch_recovery;
+	uint16_t num_buf_q;
+	struct msm_isp_bufq bufq[BUF_MGR_NUM_BUF_Q];
+
+	struct ion_client *client;
+	struct msm_isp_buf_ops *ops;
+
+	struct msm_sd_req_vb2_q *vb2_ops;
+
+
+	/*Add secure mode*/
+	int secure_enable;
+
+	int attach_ref_cnt;
+	enum msm_isp_buf_mgr_state attach_state;
+	struct device *isp_dev;
+	struct mutex lock;
+	/* Scratch buffer */
+	dma_addr_t scratch_buf_addr;
+	dma_addr_t scratch_buf_stats_addr;
+	uint32_t scratch_buf_range;
+	int iommu_hdl;
+	struct ion_handle *sc_handle;
+};
+
+int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
+	struct msm_sd_req_vb2_q *vb2_ops, struct device *dev,
+	uint32_t scratch_addr_range);
+
+int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr,
+	unsigned int cmd, void *arg);
+
+int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr,
+	void *arg);
+
+#endif /* _MSM_ISP_BUF_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
new file mode 100644
index 0000000..cfe8054
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -0,0 +1,771 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/of_device.h>
+#include <linux/sched_clock.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+
+#include "msm_isp.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_sd.h"
+#include "msm_isp48.h"
+#include "msm_isp47.h"
+#include "msm_isp46.h"
+#include "msm_isp44.h"
+#include "msm_isp40.h"
+#include "msm_isp32.h"
+
+static struct msm_sd_req_vb2_q vfe_vb2_ops;
+static struct msm_isp_buf_mgr vfe_buf_mgr;
+static struct msm_vfe_common_dev_data vfe_common_data;
+static struct dual_vfe_resource dualvfe;
+
+static const struct of_device_id msm_vfe_dt_match[] = {
+	{
+		.compatible = "qcom,vfe",
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
+
+#define MAX_OVERFLOW_COUNTERS  29
+#define OVERFLOW_LENGTH 1024
+#define OVERFLOW_BUFFER_LENGTH 64
+static char stat_line[OVERFLOW_LENGTH];
+
+static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
+	  struct msm_isp_bw_req_info *isp_req_hist);
+
+static char *stats_str[MAX_OVERFLOW_COUNTERS] = {
+	"imgmaster0_overflow_cnt",
+	"imgmaster1_overflow_cnt",
+	"imgmaster2_overflow_cnt",
+	"imgmaster3_overflow_cnt",
+	"imgmaster4_overflow_cnt",
+	"imgmaster5_overflow_cnt",
+	"imgmaster6_overflow_cnt",
+	"be_overflow_cnt",
+	"bg_overflow_cnt",
+	"bf_overflow_cnt",
+	"awb_overflow_cnt",
+	"rs_overflow_cnt",
+	"cs_overflow_cnt",
+	"ihist_overflow_cnt",
+	"skinbhist_overflow_cnt",
+	"bfscale_overflow_cnt",
+	"ISP_VFE0_client_info.active",
+	"ISP_VFE0_client_info.ab",
+	"ISP_VFE0_client_info.ib",
+	"ISP_VFE1_client_info.active",
+	"ISP_VFE1_client_info.ab",
+	"ISP_VFE1_client_info.ib",
+	"ISP_CPP_client_info.active",
+	"ISP_CPP_client_info.ab",
+	"ISP_CPP_client_info.ib",
+	"ISP_last_overflow.ab",
+	"ISP_last_overflow.ib",
+	"ISP_VFE_CLK_RATE",
+	"ISP_CPP_CLK_RATE",
+};
+
+#define MAX_DEPTH_BW_REQ_HISTORY 25
+#define MAX_BW_HISTORY_BUFF_LEN  6144
+#define MAX_BW_HISTORY_LINE_BUFF_LEN 512
+
+#define MAX_UB_INFO_BUFF_LEN  1024
+#define MAX_UB_INFO_LINE_BUFF_LEN 256
+
+static struct msm_isp_bw_req_info
+	msm_isp_bw_request_history[MAX_DEPTH_BW_REQ_HISTORY];
+static int msm_isp_bw_request_history_idx;
+static char bw_request_history_buff[MAX_BW_HISTORY_BUFF_LEN];
+static char ub_info_buffer[MAX_UB_INFO_BUFF_LEN];
+static spinlock_t req_history_lock;
+
+static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t vfe_debugfs_statistics_read(struct file *t_file,
+	char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
+{
+	int i;
+	uint64_t *ptr;
+	char buffer[OVERFLOW_BUFFER_LENGTH] = {0};
+	struct vfe_device *vfe_dev = (struct vfe_device *)
+		t_file->private_data;
+	struct msm_isp_statistics *stats = vfe_dev->stats;
+
+	memset(stat_line, 0, sizeof(stat_line));
+	msm_isp_util_get_bandwidth_stats(vfe_dev, stats);
+	ptr = (uint64_t *)(stats);
+	for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) {
+		strlcat(stat_line, stats_str[i], sizeof(stat_line));
+		strlcat(stat_line, "     ", sizeof(stat_line));
+		snprintf(buffer, sizeof(buffer), "%llu", ptr[i]);
+		strlcat(stat_line, buffer, sizeof(stat_line));
+		strlcat(stat_line, "\r\n", sizeof(stat_line));
+	}
+	return simple_read_from_buffer(t_char, t_size_t,
+		t_loff_t, stat_line, strlen(stat_line));
+}
+
+static ssize_t vfe_debugfs_statistics_write(struct file *t_file,
+	const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
+{
+	struct vfe_device *vfe_dev = (struct vfe_device *)
+		t_file->private_data;
+	struct msm_isp_statistics *stats = vfe_dev->stats;
+
+	memset(stats, 0, sizeof(struct msm_isp_statistics));
+
+	return sizeof(struct msm_isp_statistics);
+}
+
+static int bw_history_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t bw_history_read(struct file *t_file, char __user *t_char,
+	size_t t_size_t, loff_t *t_loff_t)
+{
+	int i;
+	char *out_buffer = bw_request_history_buff;
+	char line_buffer[MAX_BW_HISTORY_LINE_BUFF_LEN] = {0};
+	struct msm_isp_bw_req_info *isp_req_hist =
+		(struct msm_isp_bw_req_info *) t_file->private_data;
+
+	memset(out_buffer, 0, MAX_BW_HISTORY_BUFF_LEN);
+
+	snprintf(line_buffer, sizeof(line_buffer),
+		"Bus bandwidth request history in chronological order:\n");
+	strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
+
+	snprintf(line_buffer, sizeof(line_buffer),
+		"MSM_ISP_MIN_AB = %u, MSM_ISP_MIN_IB = %u\n\n",
+		MSM_ISP_MIN_AB, MSM_ISP_MIN_IB);
+	strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
+
+	for (i = 0; i < MAX_DEPTH_BW_REQ_HISTORY; i++) {
+		snprintf(line_buffer, sizeof(line_buffer),
+		 "idx = %d, client = %u, timestamp = %llu, ab = %llu, ib = %llu\n"
+		 "ISP0.active = %x, ISP0.ab = %llu, ISP0.ib = %llu\n"
+		 "ISP1.active = %x, ISP1.ab = %llu, ISP1.ib = %llu\n"
+		 "CPP.active = %x, CPP.ab = %llu, CPP.ib = %llu\n\n",
+		 i, isp_req_hist[i].client, isp_req_hist[i].timestamp,
+		 isp_req_hist[i].total_ab, isp_req_hist[i].total_ib,
+		 isp_req_hist[i].client_info[0].active,
+		 isp_req_hist[i].client_info[0].ab,
+		 isp_req_hist[i].client_info[0].ib,
+		 isp_req_hist[i].client_info[1].active,
+		 isp_req_hist[i].client_info[1].ab,
+		 isp_req_hist[i].client_info[1].ib,
+		 isp_req_hist[i].client_info[2].active,
+		 isp_req_hist[i].client_info[2].ab,
+		 isp_req_hist[i].client_info[2].ib);
+		strlcat(out_buffer, line_buffer,
+		sizeof(bw_request_history_buff));
+	}
+	return simple_read_from_buffer(t_char, t_size_t,
+		t_loff_t, out_buffer, strlen(out_buffer));
+}
+
+static ssize_t bw_history_write(struct file *t_file,
+	const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
+{
+	struct msm_isp_bw_req_info *isp_req_hist =
+		(struct msm_isp_bw_req_info *) t_file->private_data;
+
+	memset(isp_req_hist, 0, sizeof(msm_isp_bw_request_history));
+	msm_isp_bw_request_history_idx = 0;
+	return sizeof(msm_isp_bw_request_history);
+}
+
+static int ub_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t ub_info_read(struct file *t_file, char __user *t_char,
+	size_t t_size_t, loff_t *t_loff_t)
+{
+	int i;
+	char *out_buffer = ub_info_buffer;
+	char line_buffer[MAX_UB_INFO_LINE_BUFF_LEN] = {0};
+	struct vfe_device *vfe_dev =
+		(struct vfe_device *) t_file->private_data;
+	struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
+
+	memset(out_buffer, 0, MAX_UB_INFO_LINE_BUFF_LEN);
+	snprintf(line_buffer, sizeof(line_buffer),
+		"wm_ub_policy_type = %d\n"
+		"num_wm = %d\n"
+		"wm_ub = %d\n",
+		ub_info->policy, ub_info->num_wm, ub_info->wm_ub);
+	strlcat(out_buffer, line_buffer,
+	    sizeof(ub_info_buffer));
+	for (i = 0; i < ub_info->num_wm; i++) {
+		snprintf(line_buffer, sizeof(line_buffer),
+			"data[%d] = 0x%x, addr[%d] = 0x%llx\n",
+			i, ub_info->data[i], i, ub_info->addr[i]);
+		strlcat(out_buffer, line_buffer,
+			sizeof(ub_info_buffer));
+	}
+
+	return simple_read_from_buffer(t_char, t_size_t,
+		t_loff_t, out_buffer, strlen(out_buffer));
+}
+
+static ssize_t ub_info_write(struct file *t_file,
+	const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
+{
+	struct vfe_device *vfe_dev =
+		(struct vfe_device *) t_file->private_data;
+	struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
+
+	memset(ub_info, 0, sizeof(struct msm_isp_ub_info));
+
+	return sizeof(struct msm_isp_ub_info);
+}
+
+static const struct file_operations vfe_debugfs_error = {
+	.open = vfe_debugfs_statistics_open,
+	.read = vfe_debugfs_statistics_read,
+	.write = vfe_debugfs_statistics_write,
+};
+
+static const struct file_operations bw_history_ops = {
+	.open = bw_history_open,
+	.read = bw_history_read,
+	.write = bw_history_write,
+};
+
+static const struct file_operations ub_info_ops = {
+	.open = ub_info_open,
+	.read = ub_info_read,
+	.write = ub_info_write,
+};
+
+static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
+	struct msm_isp_bw_req_info *isp_req_hist)
+{
+	struct dentry *debugfs_base;
+	char dirname[32] = {0};
+
+	snprintf(dirname, sizeof(dirname), "msm_isp%d", vfe_dev->pdev->id);
+	debugfs_base = debugfs_create_dir(dirname, NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+	if (!debugfs_create_file("stats", 0644, debugfs_base,
+		vfe_dev, &vfe_debugfs_error))
+		return -ENOMEM;
+
+	if (!debugfs_create_file("bw_req_history", 0644,
+		debugfs_base, isp_req_hist, &bw_history_ops))
+		return -ENOMEM;
+
+	if (!debugfs_create_file("ub_info", 0644,
+		debugfs_base, vfe_dev, &ub_info_ops))
+		return -ENOMEM;
+
+	return 0;
+}
+
+void msm_isp_update_req_history(uint32_t client, uint64_t ab,
+				 uint64_t ib,
+				 struct msm_isp_bandwidth_info *client_info,
+				 unsigned long long ts)
+{
+	int i;
+
+	spin_lock(&req_history_lock);
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].client =
+		client;
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].timestamp =
+		ts;
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab =
+		ab;
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib =
+		ib;
+
+	for (i = 0; i < MAX_ISP_CLIENT; i++) {
+		msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
+			client_info[i].active = client_info[i].active;
+		msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
+			client_info[i].ab = client_info[i].ab;
+		msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
+			client_info[i].ib = client_info[i].ib;
+	}
+
+	msm_isp_bw_request_history_idx = (msm_isp_bw_request_history_idx + 1)
+			 % MAX_DEPTH_BW_REQ_HISTORY;
+	spin_unlock(&req_history_lock);
+}
+
+void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev)
+{
+	spin_lock(&req_history_lock);
+	vfe_dev->msm_isp_last_overflow_ab =
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab;
+	vfe_dev->msm_isp_last_overflow_ib =
+	msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib;
+	spin_unlock(&req_history_lock);
+}
+
+
+#ifdef CONFIG_COMPAT
+static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
+{
+	long rc;
+
+	if (is_compat_task()) {
+		struct msm_isp_event_data32 *event_data32;
+		struct msm_isp_event_data  *event_data;
+		struct v4l2_event isp_event;
+		struct v4l2_event *isp_event_user;
+
+		memset(&isp_event, 0, sizeof(isp_event));
+		rc = v4l2_event_dequeue(vfh, &isp_event,
+				file->f_flags & O_NONBLOCK);
+		if (rc)
+			return rc;
+		event_data = (struct msm_isp_event_data *)
+				isp_event.u.data;
+		isp_event_user = (struct v4l2_event *)arg;
+		memcpy(isp_event_user, &isp_event,
+				sizeof(*isp_event_user));
+		event_data32 = (struct msm_isp_event_data32 *)
+			isp_event_user->u.data;
+		memset(event_data32, 0,
+				sizeof(struct msm_isp_event_data32));
+		event_data32->timestamp.tv_sec =
+				event_data->timestamp.tv_sec;
+		event_data32->timestamp.tv_usec =
+				event_data->timestamp.tv_usec;
+		event_data32->mono_timestamp.tv_sec =
+				event_data->mono_timestamp.tv_sec;
+		event_data32->mono_timestamp.tv_usec =
+				event_data->mono_timestamp.tv_usec;
+		event_data32->frame_id = event_data->frame_id;
+		memcpy(&(event_data32->u), &(event_data->u),
+					sizeof(event_data32->u));
+	} else {
+		rc = v4l2_event_dequeue(vfh, arg,
+				file->f_flags & O_NONBLOCK);
+	}
+	return rc;
+}
+#else
+static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
+{
+	return v4l2_event_dequeue(vfh, arg,
+			file->f_flags & O_NONBLOCK);
+}
+#endif
+
+static long msm_isp_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct v4l2_fh *vfh = file->private_data;
+
+	switch (cmd) {
+	case VIDIOC_DQEVENT: {
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+			return -ENOIOCTLCMD;
+		return msm_isp_dqevent(file, vfh, arg);
+	}
+	break;
+	case VIDIOC_SUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+	default:
+		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+	}
+}
+
+static struct v4l2_subdev_core_ops msm_vfe_v4l2_subdev_core_ops = {
+	.ioctl = msm_isp_ioctl,
+	.subscribe_event = msm_isp_subscribe_event,
+	.unsubscribe_event = msm_isp_unsubscribe_event,
+};
+
+static struct v4l2_subdev_ops msm_vfe_v4l2_subdev_ops = {
+	.core = &msm_vfe_v4l2_subdev_core_ops,
+};
+
+static struct v4l2_subdev_internal_ops msm_vfe_subdev_internal_ops = {
+	.open = msm_isp_open_node,
+	.close = msm_isp_close_node,
+};
+
+static long msm_isp_v4l2_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl);
+}
+
+static void isp_vma_open(struct vm_area_struct *vma)
+{
+	pr_debug("%s: open called\n", __func__);
+}
+
+static void isp_vma_close(struct vm_area_struct *vma)
+{
+	pr_debug("%s: close called\n", __func__);
+}
+
+static int isp_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct page *page;
+	struct vfe_device *vfe_dev = vma->vm_private_data;
+	struct isp_proc *isp_page = NULL;
+
+	isp_page = vfe_dev->isp_page;
+
+	pr_debug("%s: vfeid:%d u_virt_addr:0x%lx k_virt_addr:%pK\n",
+		__func__, vfe_dev->pdev->id, vma->vm_start,
+		(void *)isp_page);
+	if (isp_page != NULL) {
+		page = virt_to_page(isp_page);
+		get_page(page);
+		vmf->page = page;
+		isp_page->kernel_sofid =
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+		isp_page->vfeid = vfe_dev->pdev->id;
+	}
+	return 0;
+}
+
+static const struct vm_operations_struct isp_vm_ops = {
+	.open = isp_vma_open,
+	.close = isp_vma_close,
+	.fault = isp_vma_fault,
+};
+
+static int msm_isp_v4l2_fops_mmap(struct file *filep,
+	struct vm_area_struct *vma)
+{
+	int ret =  -EINVAL;
+	struct video_device *vdev = video_devdata(filep);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
+
+	vma->vm_ops = &isp_vm_ops;
+	vma->vm_flags |=
+		(unsigned long)(VM_DONTEXPAND | VM_DONTDUMP);
+	vma->vm_private_data = vfe_dev;
+	isp_vma_open(vma);
+	ret = 0;
+	pr_debug("%s: isp mmap is called vm_start: 0x%lx\n",
+		__func__, vma->vm_start);
+	return ret;
+}
+
+static struct v4l2_file_operations msm_isp_v4l2_fops = {
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = msm_isp_v4l2_fops_ioctl,
+#endif
+	.unlocked_ioctl = msm_isp_v4l2_fops_ioctl,
+	.mmap = msm_isp_v4l2_fops_mmap
+};
+
+static int vfe_set_common_data(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = NULL;
+	struct vfe_device *vfe_dev = NULL;
+
+	sd = (struct v4l2_subdev *)platform_get_drvdata(pdev);
+	if (!sd) {
+		pr_err("%s: Error! Cannot find subdev\n", __func__);
+		return -EPERM;
+	}
+	vfe_dev = (struct vfe_device *)v4l2_get_subdevdata(sd);
+	if (!vfe_dev) {
+		pr_err("%s: Error! Cannot find vfe_dev\n", __func__);
+		return -EPERM;
+	}
+
+	vfe_dev->common_data = (struct msm_vfe_common_dev_data *)
+		pdev->dev.platform_data;
+
+	vfe_dev->common_data->dual_vfe_res = &dualvfe;
+	vfe_dev->common_data->dual_vfe_res->axi_data[vfe_dev->pdev->id] =
+		&vfe_dev->axi_data;
+	vfe_dev->common_data->dual_vfe_res->stats_data[vfe_dev->pdev->id] =
+		&vfe_dev->stats_data;
+	vfe_dev->common_data->dual_vfe_res->vfe_dev[vfe_dev->pdev->id] =
+		vfe_dev;
+	return 0;
+}
+
+static int vfe_probe(struct platform_device *pdev)
+{
+	struct vfe_parent_device *vfe_parent_dev;
+	int rc = 0;
+	struct device_node *node;
+	struct platform_device *new_dev = NULL;
+	uint32_t i = 0;
+	char name[10] = "\0";
+
+	vfe_parent_dev = kzalloc(sizeof(struct vfe_parent_device),
+		GFP_KERNEL);
+	if (!vfe_parent_dev) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	vfe_parent_dev->common_sd = kzalloc(
+		sizeof(struct msm_vfe_common_subdev), GFP_KERNEL);
+	if (!vfe_parent_dev->common_sd) {
+		rc = -ENOMEM;
+		goto probe_fail1;
+	}
+
+	vfe_parent_dev->common_sd->common_data = &vfe_common_data;
+	mutex_init(&vfe_common_data.vfe_common_mutex);
+	spin_lock_init(&vfe_common_data.common_dev_data_lock);
+	spin_lock_init(&vfe_common_data.vfe_irq_dump.
+			common_dev_irq_dump_lock);
+	spin_lock_init(&vfe_common_data.vfe_irq_dump.
+			common_dev_tasklet_dump_lock);
+	for (i = 0; i < (VFE_AXI_SRC_MAX * MAX_VFE); i++)
+		spin_lock_init(&(vfe_common_data.streams[i].lock));
+	for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++)
+		spin_lock_init(&(vfe_common_data.stats_streams[i].lock));
+
+	for (i = 0; i <= MAX_VFE; i++) {
+		INIT_LIST_HEAD(&vfe_common_data.tasklets[i].tasklet_q);
+		tasklet_init(&vfe_common_data.tasklets[i].tasklet,
+			msm_isp_do_tasklet,
+			(unsigned long)(&vfe_common_data.tasklets[i]));
+		spin_lock_init(&vfe_common_data.tasklets[i].tasklet_lock);
+	}
+
+	of_property_read_u32(pdev->dev.of_node,
+		"num_child", &vfe_parent_dev->num_hw_sd);
+
+	for (i = 0; i < vfe_parent_dev->num_hw_sd; i++) {
+		node = NULL;
+		snprintf(name, sizeof(name), "qcom,vfe%d", i);
+		node = of_find_node_by_name(NULL, name);
+		if (!node) {
+			pr_err("%s: Error! Cannot find node in dtsi %s\n",
+				__func__, name);
+			goto probe_fail2;
+		}
+		new_dev = of_find_device_by_node(node);
+		if (!new_dev) {
+			pr_err("%s: Failed to find device on bus %s\n",
+				__func__, node->name);
+			goto probe_fail2;
+		}
+		vfe_parent_dev->child_list[i] = new_dev;
+		new_dev->dev.platform_data =
+			(void *)vfe_parent_dev->common_sd->common_data;
+		rc = vfe_set_common_data(new_dev);
+		if (rc < 0)
+			goto probe_fail2;
+	}
+
+	vfe_parent_dev->num_sd = vfe_parent_dev->num_hw_sd;
+	vfe_parent_dev->pdev = pdev;
+
+	return rc;
+
+probe_fail2:
+	kfree(vfe_parent_dev->common_sd);
+probe_fail1:
+	kfree(vfe_parent_dev);
+end:
+	return rc;
+}
+
+int vfe_hw_probe(struct platform_device *pdev)
+{
+	struct vfe_device *vfe_dev;
+	/*struct msm_cam_subdev_info sd_info;*/
+	const struct of_device_id *match_dev;
+	int rc = 0;
+
+	vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL);
+	if (!vfe_dev) {
+		rc = -ENOMEM;
+		goto end;
+	}
+	vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL);
+	if (!vfe_dev->stats) {
+		rc = -ENOMEM;
+		goto probe_fail1;
+	}
+
+	vfe_dev->ub_info = kzalloc(sizeof(struct msm_isp_ub_info), GFP_KERNEL);
+	if (!vfe_dev->ub_info) {
+		rc = -ENOMEM;
+		goto probe_fail2;
+	}
+
+	if (pdev->dev.of_node) {
+		of_property_read_u32(pdev->dev.of_node,
+			"cell-index", &pdev->id);
+
+		match_dev = of_match_device(pdev->dev.driver->of_match_table,
+			&pdev->dev);
+		if (!match_dev) {
+			pr_err("%s: No vfe hardware info\n", __func__);
+			rc = -EINVAL;
+			goto probe_fail3;
+		}
+		vfe_dev->hw_info =
+			(struct msm_vfe_hardware_info *) match_dev->data;
+		/* Cx ipeak support */
+		if (of_find_property(pdev->dev.of_node,
+			"qcom,vfe-cx-ipeak", NULL)) {
+			vfe_dev->vfe_cx_ipeak = cx_ipeak_register(
+				pdev->dev.of_node, "qcom,vfe-cx-ipeak");
+		}
+	} else {
+		vfe_dev->hw_info = (struct msm_vfe_hardware_info *)
+			platform_get_device_id(pdev)->driver_data;
+	}
+
+	if (!vfe_dev->hw_info) {
+		pr_err("%s: No vfe hardware info\n", __func__);
+		rc = -EINVAL;
+		goto probe_fail3;
+	}
+	ISP_DBG("%s: device id = %d\n", __func__, pdev->id);
+
+	vfe_dev->pdev = pdev;
+
+	rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_platform_data(vfe_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to get platform resources\n", __func__);
+		rc = -ENOMEM;
+		goto probe_fail3;
+	}
+
+	v4l2_subdev_init(&vfe_dev->subdev.sd, &msm_vfe_v4l2_subdev_ops);
+	vfe_dev->subdev.sd.internal_ops =
+		&msm_vfe_subdev_internal_ops;
+	snprintf(vfe_dev->subdev.sd.name,
+		ARRAY_SIZE(vfe_dev->subdev.sd.name),
+		"vfe");
+	vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev);
+	platform_set_drvdata(pdev, &vfe_dev->subdev.sd);
+	mutex_init(&vfe_dev->realtime_mutex);
+	mutex_init(&vfe_dev->core_mutex);
+	spin_lock_init(&vfe_dev->shared_data_lock);
+	spin_lock_init(&vfe_dev->reg_update_lock);
+	spin_lock_init(&req_history_lock);
+	spin_lock_init(&vfe_dev->completion_lock);
+	media_entity_pads_init(&vfe_dev->subdev.sd.entity, 0, NULL);
+	vfe_dev->subdev.sd.entity.function = MSM_CAMERA_SUBDEV_VFE;
+	//vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
+	vfe_dev->subdev.sd.entity.name = pdev->name;
+	vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
+	rc = msm_sd_register(&vfe_dev->subdev);
+	if (rc != 0) {
+		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
+		goto probe_fail3;
+	}
+	msm_cam_copy_v4l2_subdev_fops(&msm_isp_v4l2_fops);
+	msm_isp_v4l2_fops.unlocked_ioctl = msm_isp_v4l2_fops_ioctl;
+#ifdef CONFIG_COMPAT
+	msm_isp_v4l2_fops.compat_ioctl32 =
+		msm_isp_v4l2_fops_ioctl;
+#endif
+	msm_isp_v4l2_fops.mmap = msm_isp_v4l2_fops_mmap;
+
+	vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_fops;
+
+	vfe_dev->buf_mgr = &vfe_buf_mgr;
+	v4l2_subdev_notify(&vfe_dev->subdev.sd,
+		MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops);
+	rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr,
+		&vfe_vb2_ops, &pdev->dev,
+		vfe_dev->hw_info->axi_hw_info->scratch_buf_range);
+	if (rc < 0) {
+		pr_err("%s: Unable to create buffer manager\n", __func__);
+		rc = -EINVAL;
+		goto probe_fail3;
+	}
+	msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history);
+	vfe_dev->buf_mgr->init_done = 1;
+	vfe_dev->vfe_open_cnt = 0;
+	/*Allocate a page in kernel and map it to camera user process*/
+	vfe_dev->isp_page = (struct isp_proc *)get_zeroed_page(GFP_KERNEL);
+	if (vfe_dev->isp_page == NULL) {
+		pr_err("%s: no enough memory\n", __func__);
+		rc = -ENOMEM;
+		goto probe_fail3;
+	}
+	vfe_dev->isp_page->vfeid = vfe_dev->pdev->id;
+	return rc;
+
+probe_fail3:
+	kfree(vfe_dev->ub_info);
+probe_fail2:
+	kfree(vfe_dev->stats);
+probe_fail1:
+	kfree(vfe_dev);
+end:
+	return rc;
+}
+
+static struct platform_driver vfe_driver = {
+	.probe = vfe_probe,
+	.driver = {
+		.name = "msm_vfe",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe_dt_match,
+	},
+};
+
+static int __init msm_vfe_init_module(void)
+{
+	return platform_driver_register(&vfe_driver);
+}
+
+static void __exit msm_vfe_exit_module(void)
+{
+	platform_driver_unregister(&vfe_driver);
+}
+
+late_initcall(msm_vfe_init_module);
+module_exit(msm_vfe_exit_module);
+MODULE_DESCRIPTION("MSM VFE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
new file mode 100644
index 0000000..56cce54
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -0,0 +1,860 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_VFE_H__
+#define __MSM_VFE_H__
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_isp.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+
+#include "msm_buf_mgr.h"
+#include "cam_hw_ops.h"
+#include <soc/qcom/cx_ipeak.h>
+
+#define VFE40_8974V1_VERSION 0x10000018
+#define VFE40_8974V2_VERSION 0x1001001A
+#define VFE40_8974V3_VERSION 0x1001001B
+#define VFE40_8x26_VERSION 0x20000013
+#define VFE40_8x26V2_VERSION 0x20010014
+#define VFE40_8916_VERSION 0x10030000
+#define VFE40_8939_VERSION 0x10040000
+#define VFE40_8952_VERSION 0x10060000
+#define VFE40_8976_VERSION 0x10050000
+#define VFE40_8937_VERSION 0x10080000
+#define VFE40_8917_VERSION 0x10080001
+#define VFE40_8953_VERSION 0x10090000
+#define VFE32_8909_VERSION 0x30600
+
+#define MAX_IOMMU_CTX 2
+#define MAX_NUM_WM 7
+#define MAX_NUM_RDI 3
+#define MAX_NUM_RDI_MASTER 3
+#define MAX_NUM_COMPOSITE_MASK 4
+#define MAX_NUM_STATS_COMP_MASK 2
+#define MAX_INIT_FRAME_DROP 31
+#define MAX_REG_UPDATE_THRESHOLD 10
+#define ISP_Q2 (1 << 2)
+
+#define VFE_PING_FLAG 0xFFFFFFFF
+#define VFE_PONG_FLAG 0x0
+
+#define VFE_MAX_CFG_TIMEOUT 3000
+#define VFE_CLK_INFO_MAX 16
+#define STATS_COMP_BIT_MASK 0x1FF
+
+#define MSM_ISP_MIN_AB 100000000
+#define MSM_ISP_MIN_IB 100000000
+#define MAX_BUFFERS_IN_HW 2
+
+#define MAX_VFE 2
+#define MAX_VFE_IRQ_DEBUG_DUMP_SIZE 10
+#define MAX_RECOVERY_THRESHOLD  5
+
+struct vfe_device;
+struct msm_vfe_axi_stream;
+struct msm_vfe_stats_stream;
+
+#define VFE_SD_HW_MAX VFE_SD_COMMON
+
+/* Irq operations to perform on the irq mask register */
+enum msm_isp_irq_operation {
+	/* enable the irq bits in given parameters */
+	MSM_ISP_IRQ_ENABLE = 1,
+	/* disable the irq bits in the given parameters */
+	MSM_ISP_IRQ_DISABLE = 2,
+	/* set the irq bits to the given parameters */
+	MSM_ISP_IRQ_SET = 3,
+};
+
+/* This struct is used to save/track SOF info for some INTF.
+ * e.g. used in Master-Slave mode
+ */
+struct msm_vfe_sof_info {
+	uint32_t timestamp_ms;
+	uint32_t mono_timestamp_ms;
+	uint32_t frame_id;
+};
+
+/* Each INTF in Master-Slave mode uses this struct. */
+struct msm_vfe_dual_hw_ms_info {
+	/* type is Master/Slave */
+	enum msm_vfe_dual_hw_ms_type dual_hw_ms_type;
+	enum msm_vfe_dual_cam_sync_mode sync_state;
+	struct msm_vfe_sof_info sof_info;
+	int index;
+};
+
+struct vfe_subscribe_info {
+	struct v4l2_fh *vfh;
+	uint32_t active;
+};
+
+enum msm_isp_pack_fmt {
+	QCOM,
+	MIPI,
+	DPCM6,
+	DPCM8,
+	PLAIN8,
+	PLAIN16,
+	DPCM10,
+	MAX_ISP_PACK_FMT,
+};
+
+enum msm_isp_camif_update_state {
+	NO_UPDATE,
+	ENABLE_CAMIF,
+	DISABLE_CAMIF,
+	DISABLE_CAMIF_IMMEDIATELY
+};
+
+struct msm_isp_timestamp {
+	/*Monotonic clock for v4l2 buffer*/
+	struct timeval buf_time;
+	/*Monotonic clock for VT */
+	struct timeval vt_time;
+	/*Wall clock for userspace event*/
+	struct timeval event_time;
+};
+
+struct msm_vfe_irq_ops {
+	void (*read_and_clear_irq_status)(struct vfe_device *vfe_dev,
+		uint32_t *irq_status0, uint32_t *irq_status1);
+	void (*read_irq_status)(struct vfe_device *vfe_dev,
+		uint32_t *irq_status0, uint32_t *irq_status1);
+	void (*process_reg_update)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		struct msm_isp_timestamp *ts);
+	void (*process_epoch_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		struct msm_isp_timestamp *ts);
+	void (*process_reset_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1);
+	void (*process_halt_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1);
+	void (*process_camif_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		struct msm_isp_timestamp *ts);
+	void (*process_axi_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		struct msm_isp_timestamp *ts);
+	void (*process_stats_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		struct msm_isp_timestamp *ts);
+	void (*config_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0, uint32_t irq_status1,
+		enum msm_isp_irq_operation);
+	void (*preprocess_camif_irq)(struct vfe_device *vfe_dev,
+		uint32_t irq_status0);
+};
+
+struct msm_vfe_axi_ops {
+	void (*reload_wm)(struct vfe_device *vfe_dev, void __iomem *vfe_base,
+		uint32_t reload_mask);
+	void (*enable_wm)(void __iomem *vfe_base,
+		uint8_t wm_idx, uint8_t enable);
+	int32_t (*cfg_io_format)(struct vfe_device *vfe_dev,
+		enum msm_vfe_axi_stream_src stream_src,
+		uint32_t io_format);
+	void (*cfg_framedrop)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info,
+		uint32_t framedrop_pattern, uint32_t framedrop_period);
+	void (*clear_framedrop)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info);
+	void (*cfg_comp_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info);
+	void (*clear_comp_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info);
+	void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info);
+	void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info);
+
+	void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info,
+		uint8_t plane_idx);
+	void (*clear_wm_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
+
+	void (*cfg_wm_xbar_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info,
+		uint8_t plane_idx);
+	void (*clear_wm_xbar_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
+	void (*cfg_ub)(struct vfe_device *vfe_dev,
+		enum msm_vfe_input_src frame_src);
+	void (*read_wm_ping_pong_addr)(struct vfe_device *vfe_dev);
+	void (*update_ping_pong_addr)(void __iomem *vfe_base,
+		uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+		int32_t buf_size);
+	uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1);
+	uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1);
+	uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev);
+	int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking);
+	void (*restart)(struct vfe_device *vfe_dev, uint32_t blocking,
+		uint32_t enable_camif);
+	void (*update_cgc_override)(struct vfe_device *vfe_dev,
+		uint8_t wm_idx, uint8_t cgc_override);
+	uint32_t (*ub_reg_offset)(struct vfe_device *vfe_dev, int idx);
+	uint32_t (*get_ub_size)(struct vfe_device *vfe_dev);
+};
+
+struct msm_vfe_core_ops {
+	void (*reg_update)(struct vfe_device *vfe_dev,
+		enum msm_vfe_input_src frame_src);
+	long (*reset_hw)(struct vfe_device *vfe_dev, uint32_t first_start,
+		uint32_t blocking_call);
+	int (*init_hw)(struct vfe_device *vfe_dev);
+	void (*init_hw_reg)(struct vfe_device *vfe_dev);
+	void (*clear_status_reg)(struct vfe_device *vfe_dev);
+	void (*release_hw)(struct vfe_device *vfe_dev);
+	void (*cfg_input_mux)(struct vfe_device *vfe_dev,
+		struct msm_vfe_pix_cfg *pix_cfg);
+	int (*start_fetch_eng)(struct vfe_device *vfe_dev,
+		void *arg);
+	void (*update_camif_state)(struct vfe_device *vfe_dev,
+		enum msm_isp_camif_update_state update_state);
+	void (*cfg_rdi_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_rdi_cfg *rdi_cfg,
+		enum msm_vfe_input_src input_src);
+	void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1);
+	void (*process_error_status)(struct vfe_device *vfe_dev);
+	void (*get_overflow_mask)(uint32_t *overflow_mask);
+	void (*get_irq_mask)(struct vfe_device *vfe_dev,
+		uint32_t *irq0_mask, uint32_t *irq1_mask);
+	void (*get_halt_restart_mask)(uint32_t *irq0_mask,
+		uint32_t *irq1_mask);
+	void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev,
+		uint32_t *rdi_wm_mask);
+	bool (*is_module_cfg_lock_needed)(uint32_t reg_offset);
+	int (*ahb_clk_cfg)(struct vfe_device *vfe_dev,
+			struct msm_isp_ahb_clk_cfg *ahb_cfg);
+	int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev,
+		void *arg);
+	void (*set_halt_restart_mask)(struct vfe_device *vfe_dev);
+	void (*set_bus_err_ign_mask)(struct vfe_device *vfe_dev,
+		int wm, int enable);
+	void (*get_bus_err_mask)(struct vfe_device *vfe_dev,
+		uint32_t *bus_err, uint32_t *irq_status1);
+};
+
+struct msm_vfe_stats_ops {
+	int (*get_stats_idx)(enum msm_isp_stats_type stats_type);
+	int (*check_streams)(struct msm_vfe_stats_stream *stream_info);
+	void (*cfg_framedrop)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info,
+		uint32_t framedrop_pattern, uint32_t framedrop_period);
+	void (*clear_framedrop)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+	void (*cfg_comp_mask)(struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t comp_index,
+		uint8_t enable);
+	void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+	void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+
+	void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+	void (*clear_wm_reg)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info);
+
+	void (*cfg_ub)(struct vfe_device *vfe_dev);
+
+	void (*enable_module)(struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t enable);
+
+	void (*update_ping_pong_addr)(struct vfe_device *vfe_dev,
+		struct msm_vfe_stats_stream *stream_info,
+		uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size);
+
+	uint32_t (*get_frame_id)(struct vfe_device *vfe_dev);
+	uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1);
+	uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1);
+	uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev);
+
+	void (*update_cgc_override)(struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t enable);
+	void (*enable_stats_wm)(struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t enable);
+};
+
+enum msm_isp_hw_client {
+	ISP_VFE0,
+	ISP_VFE1,
+	ISP_CPP,
+	MAX_ISP_CLIENT,
+};
+
+struct msm_isp_bandwidth_info {
+	uint32_t active;
+	uint64_t ab;
+	uint64_t ib;
+};
+
+struct msm_isp_bandwidth_mgr {
+	uint32_t bus_client;
+	uint32_t bus_vector_active_idx;
+	uint32_t use_count;
+	struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
+	int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+	void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+};
+
+struct msm_vfe_platform_ops {
+	int (*get_platform_data)(struct vfe_device *vfe_dev);
+	int (*enable_clks)(struct vfe_device *vfe_dev, int enable);
+	int (*get_clks)(struct vfe_device *vfe_dev);
+	void (*put_clks)(struct vfe_device *vfe_dev);
+	int (*get_clk_rates)(struct vfe_device *vfe_dev,
+				struct msm_isp_clk_rates *rates);
+	int (*get_max_clk_rate)(struct vfe_device *vfe_dev, long *rate);
+	int (*set_clk_rate)(struct vfe_device *vfe_dev, long *rate);
+	int (*enable_regulators)(struct vfe_device *vfe_dev, int enable);
+	int (*get_regulators)(struct vfe_device *vfe_dev);
+	void (*put_regulators)(struct vfe_device *vfe_dev);
+	int (*init_bw_mgr)(struct vfe_device *vfe_dev,
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+	int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+	void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+};
+
+struct msm_vfe_ops {
+	struct msm_vfe_irq_ops irq_ops;
+	struct msm_vfe_axi_ops axi_ops;
+	struct msm_vfe_core_ops core_ops;
+	struct msm_vfe_stats_ops stats_ops;
+	struct msm_vfe_platform_ops platform_ops;
+};
+
+struct msm_vfe_hardware_info {
+	int num_iommu_ctx;
+	/* secure iommu ctx nums */
+	int num_iommu_secure_ctx;
+	int vfe_clk_idx;
+	int runtime_axi_update;
+	struct msm_vfe_ops vfe_ops;
+	struct msm_vfe_axi_hardware_info *axi_hw_info;
+	struct msm_vfe_stats_hardware_info *stats_hw_info;
+	uint32_t dmi_reg_offset;
+	uint32_t min_ab;
+	uint32_t min_ib;
+	const char *regulator_names[];
+};
+
+struct msm_vfe_axi_hardware_info {
+	uint8_t num_wm;
+	uint8_t num_rdi;
+	uint8_t num_rdi_master;
+	uint8_t num_comp_mask;
+	uint32_t min_wm_ub;
+	uint32_t scratch_buf_range;
+};
+
+enum msm_vfe_axi_state {
+	AVAILABLE,
+	INACTIVE,
+	ACTIVE,
+	PAUSED,
+	START_PENDING,
+	STOP_PENDING,
+	PAUSE_PENDING,
+	RESUME_PENDING,
+	STARTING,
+	STOPPING,
+	PAUSING,
+	RESUMING,
+	UPDATING,
+};
+
+#define VFE_NO_DROP	       0xFFFFFFFF
+#define VFE_DROP_EVERY_2FRAME  0x55555555
+#define VFE_DROP_EVERY_4FRAME  0x11111111
+#define VFE_DROP_EVERY_8FRAME  0x01010101
+#define VFE_DROP_EVERY_16FRAME 0x00010001
+#define VFE_DROP_EVERY_32FRAME 0x00000001
+
+enum msm_vfe_axi_stream_type {
+	CONTINUOUS_STREAM,
+	BURST_STREAM,
+};
+
+struct msm_vfe_frame_request_queue {
+	struct list_head list;
+	enum msm_vfe_buff_queue_id buff_queue_id;
+	uint32_t buf_index;
+	uint8_t cmd_used;
+};
+
+enum msm_isp_comp_irq_types {
+	MSM_ISP_COMP_IRQ_REG_UPD = 0,
+	MSM_ISP_COMP_IRQ_EPOCH = 1,
+	MSM_ISP_COMP_IRQ_PING_BUFDONE = 2,
+	MSM_ISP_COMP_IRQ_PONG_BUFDONE = 3,
+	MSM_ISP_COMP_IRQ_MAX = 4
+};
+
+#define MSM_VFE_REQUESTQ_SIZE 8
+
+struct msm_vfe_axi_stream {
+	uint32_t frame_id;
+	enum msm_vfe_axi_state state;
+	enum msm_vfe_axi_stream_src stream_src;
+	uint8_t num_planes;
+	uint8_t wm[MAX_VFE][MAX_PLANES_PER_STREAM];
+	uint32_t output_format;/*Planar/RAW/Misc*/
+	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_VFE][MAX_PLANES_PER_STREAM];
+	uint8_t comp_mask_index[MAX_VFE];
+	struct msm_isp_buffer *buf[2];
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t bufq_handle[VFE_BUF_QUEUE_MAX];
+	uint8_t controllable_output;
+	uint8_t undelivered_request_cnt;
+	uint8_t request_q_idx;
+	uint32_t request_q_cnt;
+	struct list_head request_q;
+	struct msm_vfe_frame_request_queue
+			request_queue_cmd[MSM_VFE_REQUESTQ_SIZE];
+	uint32_t stream_handle[MAX_VFE];
+	uint8_t buf_divert;
+	enum msm_vfe_axi_stream_type stream_type;
+	uint32_t frame_based;
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern;
+	uint32_t current_framedrop_period; /* user requested period*/
+	uint32_t requested_framedrop_period; /* requested period*/
+	uint32_t activated_framedrop_period; /* active hw period */
+	uint32_t num_burst_capture;/*number of frame to capture*/
+	uint32_t init_frame_drop;
+	spinlock_t lock;
+
+	/*Bandwidth calculation info*/
+	uint32_t max_width[MAX_VFE];
+	/*Based on format plane size in Q2. e.g NV12 = 1.5*/
+	uint32_t format_factor;
+	uint32_t bandwidth[MAX_VFE];
+
+	uint32_t runtime_num_burst_capture;
+	uint32_t runtime_output_format;
+	enum msm_stream_rdi_input_type  rdi_input_type;
+	struct msm_isp_sw_framskip sw_skip;
+	int8_t sw_ping_pong_bit;
+
+	struct vfe_device *vfe_dev[MAX_VFE];
+	int num_isp;
+	struct completion active_comp;
+	struct completion inactive_comp;
+	uint32_t update_vfe_mask;
+	/*
+	 * bits in this mask are set that correspond to vfe_id of
+	 * the vfe on which this stream operates
+	 */
+	uint32_t vfe_mask;
+	uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX];
+	int lpm_mode;
+};
+
+struct msm_vfe_axi_composite_info {
+	uint32_t stream_handle;
+	uint32_t stream_composite_mask;
+};
+
+enum msm_vfe_camif_state {
+	CAMIF_ENABLE,
+	CAMIF_DISABLE,
+};
+
+struct msm_vfe_src_info {
+	uint32_t frame_id;
+	uint32_t reg_update_frame_id;
+	uint8_t active;
+	uint8_t stream_count;
+	uint8_t raw_stream_count;
+	enum msm_vfe_inputmux input_mux;
+	uint32_t width;
+	long pixel_clock;
+	uint32_t input_format;/*V4L2 pix format with bayer pattern*/
+	uint32_t last_updt_frm_id;
+	uint32_t sof_counter_step;
+	struct timeval time_stamp;
+	enum msm_vfe_dual_hw_type dual_hw_type;
+	struct msm_vfe_dual_hw_ms_info dual_hw_ms_info;
+	bool accept_frame;
+	uint32_t lpm;
+};
+
+struct msm_vfe_fetch_engine_info {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t bufq_handle;
+	uint32_t buf_idx;
+	uint8_t is_busy;
+	uint8_t offline_mode;
+	uint32_t fd;
+};
+
+enum msm_wm_ub_cfg_type {
+	MSM_WM_UB_CFG_DEFAULT,
+	MSM_WM_UB_EQUAL_SLICING,
+	MSM_WM_UB_CFG_MAX_NUM
+};
+
+struct msm_vfe_axi_shared_data {
+	struct msm_vfe_axi_hardware_info *hw_info;
+	uint32_t free_wm[MAX_NUM_WM];
+	uint32_t wm_image_size[MAX_NUM_WM];
+	enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
+	uint8_t num_used_wm;
+	uint8_t num_active_stream;
+	uint8_t num_rdi_stream;
+	uint8_t num_pix_stream;
+	uint32_t rdi_wm_mask;
+	struct msm_vfe_axi_composite_info
+		composite_info[MAX_NUM_COMPOSITE_MASK];
+	uint8_t num_used_composite_mask;
+	atomic_t axi_cfg_update[VFE_SRC_MAX];
+	struct msm_vfe_src_info src_info[VFE_SRC_MAX];
+	uint16_t stream_handle_cnt;
+	uint32_t event_mask;
+	uint8_t enable_frameid_recovery;
+	uint8_t recovery_count;
+};
+
+struct msm_vfe_stats_hardware_info {
+	uint32_t stats_capability_mask;
+	uint8_t *stats_ping_pong_offset;
+	uint8_t *stats_wm_index;
+	uint8_t num_stats_type;
+	uint8_t num_stats_comp_mask;
+};
+
+enum msm_vfe_stats_state {
+	STATS_AVAILABLE,
+	STATS_INACTIVE,
+	STATS_ACTIVE,
+	STATS_START_PENDING,
+	STATS_STOP_PENDING,
+	STATS_STARTING,
+	STATS_STOPPING,
+};
+
+struct msm_vfe_stats_stream {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t stream_handle[MAX_VFE];
+	uint32_t composite_flag;
+	enum msm_isp_stats_type stats_type;
+	enum msm_vfe_stats_state state;
+	uint32_t framedrop_pattern;
+	uint32_t framedrop_period;
+	uint32_t irq_subsample_pattern;
+	uint32_t init_stats_frame_drop;
+	struct msm_isp_sw_framskip sw_skip;
+
+	uint32_t buffer_offset[MAX_VFE];
+	struct msm_isp_buffer *buf[2];
+	uint32_t bufq_handle;
+
+	spinlock_t lock;
+	struct vfe_device *vfe_dev[MAX_VFE];
+	int num_isp;
+	struct completion active_comp;
+	struct completion inactive_comp;
+	/*
+	 * bits in this mask are set that correspond to vfe_id of
+	 * the vfe on which this stream operates
+	 */
+	uint32_t vfe_mask;
+	uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX];
+};
+
+struct msm_vfe_stats_shared_data {
+	uint8_t num_active_stream;
+	atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK];
+	uint16_t stream_handle_cnt;
+};
+
+struct msm_vfe_tasklet_queue_cmd {
+	struct list_head list;
+	uint32_t vfeInterruptStatus0;
+	uint32_t vfeInterruptStatus1;
+	struct msm_isp_timestamp ts;
+	uint8_t cmd_used;
+	struct vfe_device *vfe_dev;
+};
+
+#define MSM_VFE_TASKLETQ_SIZE 400
+
+enum msm_vfe_overflow_state {
+	NO_OVERFLOW,
+	OVERFLOW_DETECTED,
+	HALT_ENFORCED,
+};
+
+struct msm_vfe_error_info {
+	atomic_t overflow_state;
+	uint32_t error_mask0;
+	uint32_t error_mask1;
+	uint32_t violation_status;
+	uint32_t camif_status;
+	uint8_t stream_framedrop_count[BUF_MGR_NUM_BUF_Q];
+	uint8_t stats_framedrop_count[MSM_ISP_STATS_MAX];
+	uint32_t info_dump_frame_count;
+	uint32_t error_count;
+	uint32_t framedrop_flag;
+};
+
+struct msm_isp_statistics {
+	int64_t imagemaster0_overflow;
+	int64_t imagemaster1_overflow;
+	int64_t imagemaster2_overflow;
+	int64_t imagemaster3_overflow;
+	int64_t imagemaster4_overflow;
+	int64_t imagemaster5_overflow;
+	int64_t imagemaster6_overflow;
+	int64_t be_overflow;
+	int64_t bg_overflow;
+	int64_t bf_overflow;
+	int64_t awb_overflow;
+	int64_t rs_overflow;
+	int64_t cs_overflow;
+	int64_t ihist_overflow;
+	int64_t skinbhist_overflow;
+	int64_t bfscale_overflow;
+
+	int64_t isp_vfe0_active;
+	int64_t isp_vfe0_ab;
+	int64_t isp_vfe0_ib;
+
+	int64_t isp_vfe1_active;
+	int64_t isp_vfe1_ab;
+	int64_t isp_vfe1_ib;
+
+	int64_t isp_cpp_active;
+	int64_t isp_cpp_ab;
+	int64_t isp_cpp_ib;
+
+	int64_t last_overflow_ab;
+	int64_t last_overflow_ib;
+
+	int64_t vfe_clk_rate;
+	int64_t cpp_clk_rate;
+};
+
+struct msm_isp_bw_req_info {
+	uint32_t client;
+	unsigned long long timestamp;
+	uint64_t total_ab;
+	uint64_t total_ib;
+	struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
+};
+
+#define MSM_ISP_MAX_WM 7
+struct msm_isp_ub_info {
+	enum msm_wm_ub_cfg_type policy;
+	uint8_t num_wm;
+	uint32_t wm_ub;
+	uint32_t data[MSM_ISP_MAX_WM];
+	uint64_t addr[MSM_ISP_MAX_WM];
+};
+
+struct msm_vfe_hw_init_parms {
+	const char *entries;
+	const char *regs;
+	const char *settings;
+};
+
+struct dual_vfe_resource {
+	struct vfe_device *vfe_dev[MAX_VFE];
+	void __iomem *vfe_base[MAX_VFE];
+	uint32_t reg_update_mask[MAX_VFE];
+	struct msm_vfe_stats_shared_data *stats_data[MAX_VFE];
+	struct msm_vfe_axi_shared_data *axi_data[MAX_VFE];
+	uint32_t wm_reload_mask[MAX_VFE];
+};
+
+struct master_slave_resource_info {
+	enum msm_vfe_dual_hw_type dual_hw_type;
+	uint32_t sof_delta_threshold; /* Updated by Master */
+	uint32_t active_src_mask;
+	uint32_t src_sof_mask;
+	int master_index;
+	int primary_slv_idx;
+	struct msm_vfe_src_info *src_info[MAX_VFE * VFE_SRC_MAX];
+	uint32_t num_src;
+	enum msm_vfe_dual_cam_sync_mode dual_sync_mode;
+};
+
+struct msm_vfe_irq_debug_info {
+	uint32_t vfe_id;
+	struct msm_isp_timestamp ts;
+	uint32_t core_id;
+	uint32_t irq_status0[MAX_VFE];
+	uint32_t irq_status1[MAX_VFE];
+	uint32_t ping_pong_status[MAX_VFE];
+};
+
+struct msm_vfe_irq_dump {
+	spinlock_t common_dev_irq_dump_lock;
+	spinlock_t common_dev_tasklet_dump_lock;
+	uint8_t current_irq_index;
+	uint8_t current_tasklet_index;
+	struct msm_vfe_irq_debug_info
+		irq_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE];
+	struct msm_vfe_irq_debug_info
+		tasklet_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE];
+};
+
+struct msm_vfe_tasklet {
+	spinlock_t tasklet_lock;
+	uint8_t taskletq_idx;
+	struct list_head tasklet_q;
+	struct tasklet_struct tasklet;
+	struct msm_vfe_tasklet_queue_cmd
+		tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
+};
+
+struct msm_vfe_common_dev_data {
+	spinlock_t common_dev_data_lock;
+	struct dual_vfe_resource *dual_vfe_res;
+	struct master_slave_resource_info ms_resource;
+	struct msm_vfe_axi_stream streams[VFE_AXI_SRC_MAX * MAX_VFE];
+	struct msm_vfe_stats_stream stats_streams[MSM_ISP_STATS_MAX * MAX_VFE];
+	struct mutex vfe_common_mutex;
+	uint8_t pd_buf_idx;
+	/* Irq debug Info */
+	struct msm_vfe_irq_dump vfe_irq_dump;
+	struct msm_vfe_tasklet tasklets[MAX_VFE + 1];
+};
+
+struct msm_vfe_common_subdev {
+	/* parent reference */
+	struct vfe_parent_device *parent;
+
+	/* Media Subdevice */
+	struct msm_sd_subdev *subdev;
+
+	/* Buf Mgr */
+	struct msm_isp_buf_mgr *buf_mgr;
+
+	/* Common Data */
+	struct msm_vfe_common_dev_data *common_data;
+};
+
+struct isp_proc {
+	uint32_t  kernel_sofid;
+	uint32_t  vfeid;
+};
+
+struct vfe_device {
+	/* Driver private data */
+	struct platform_device *pdev;
+	struct msm_vfe_common_dev_data *common_data;
+	struct msm_sd_subdev subdev;
+	struct msm_isp_buf_mgr *buf_mgr;
+
+	/* Resource info */
+	struct resource *vfe_irq;
+	void __iomem *vfe_base;
+	uint32_t vfe_base_size;
+	void __iomem *vfe_vbif_base;
+	uint32_t vfe_vbif_base_size;
+	struct device *iommu_ctx[MAX_IOMMU_CTX];
+	struct msm_cam_regulator *regulator_info;
+	uint32_t vfe_num_regulators;
+	struct clk **vfe_clk;
+	struct msm_cam_clk_info *vfe_clk_info;
+	uint32_t **vfe_clk_rates;
+	size_t num_clk;
+	size_t num_rates;
+	struct clk **hvx_clk;
+	struct msm_cam_clk_info *hvx_clk_info;
+	size_t num_hvx_clk;
+	size_t num_norm_clk;
+	bool hvx_clk_state;
+	enum cam_ahb_clk_vote ahb_vote;
+	enum cam_ahb_clk_vote user_requested_ahb_vote;
+	struct cx_ipeak_client *vfe_cx_ipeak;
+
+	/* Sync variables*/
+	struct completion reset_complete;
+	struct completion halt_complete;
+	struct mutex realtime_mutex;
+	struct mutex core_mutex;
+	spinlock_t shared_data_lock;
+	spinlock_t reg_update_lock;
+	spinlock_t completion_lock;
+
+	/* Tasklet info */
+	atomic_t irq_cnt;
+
+	/* Data structures */
+	struct msm_vfe_hardware_info *hw_info;
+	struct msm_vfe_axi_shared_data axi_data;
+	struct msm_vfe_stats_shared_data stats_data;
+	struct msm_vfe_error_info error_info;
+	struct msm_vfe_fetch_engine_info fetch_engine_info;
+	enum msm_vfe_hvx_streaming_cmd hvx_cmd;
+	uint8_t cur_hvx_state;
+
+	/* State variables */
+	uint32_t vfe_hw_version;
+	uint32_t vfe_open_cnt;
+	uint8_t vt_enable;
+	uint32_t vfe_ub_policy;
+	uint8_t reset_pending;
+	uint8_t reg_update_requested;
+	uint8_t reg_updated;
+	uint32_t is_split;
+	uint32_t dual_vfe_enable;
+	unsigned long page_fault_addr;
+	uint32_t vfe_hw_limit;
+
+	/* Debug variables */
+	int dump_reg;
+	struct msm_isp_statistics *stats;
+	uint64_t msm_isp_last_overflow_ab;
+	uint64_t msm_isp_last_overflow_ib;
+	struct msm_isp_ub_info *ub_info;
+	int32_t isp_sof_debug;
+	int32_t isp_raw0_debug;
+	int32_t isp_raw1_debug;
+	int32_t isp_raw2_debug;
+
+	/* irq info */
+	uint32_t irq0_mask;
+	uint32_t irq1_mask;
+	uint32_t bus_err_ign_mask;
+	uint32_t recovery_irq0_mask;
+	uint32_t recovery_irq1_mask;
+	/* total bandwidth per vfe */
+	uint64_t total_bandwidth;
+	struct isp_proc *isp_page;
+};
+
+struct vfe_parent_device {
+	struct platform_device *pdev;
+	uint32_t num_sd;
+	uint32_t num_hw_sd;
+	struct platform_device *child_list[VFE_SD_HW_MAX];
+	struct msm_vfe_common_subdev *common_sd;
+};
+int vfe_hw_probe(struct platform_device *pdev);
+void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
new file mode 100644
index 0000000..6da1360
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -0,0 +1,1539 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "msm_isp32.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm.h"
+#include "msm_camera_io_util.h"
+
+static const struct platform_device_id msm_vfe32_dev_id[] = {
+	{"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info},
+	{}
+};
+
+#define VFE32_BURST_LEN 2
+#define VFE32_UB_SIZE 1024
+#define VFE32_UB_SIZE_32KB 2048
+#define VFE32_EQUAL_SLICE_UB 194
+#define VFE32_AXI_SLICE_UB 792
+#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
+#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
+#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
+#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8)
+#define VFE32_PING_PONG_BASE(wm, ping_pong) \
+	(VFE32_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1)))
+
+static uint8_t stats_pingpong_offset_map[] = {
+	7, 8, 9, 10, 11, 12, 13};
+
+#define VFE32_NUM_STATS_TYPE 7
+#define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx)
+#define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \
+	(VFE32_STATS_BASE(idx) + 0x4 * \
+	(~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1))
+
+#define VFE32_CLK_IDX 1
+#define MSM_ISP32_TOTAL_WM_UB 792
+/*792 double word*/
+
+static struct msm_cam_clk_info msm_vfe32_1_clk_info[VFE_CLK_INFO_MAX];
+
+static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = {
+	/*vfe32 clock info for A-family: 8960 */
+	{"vfe_clk", 266667000},
+	{"vfe_pclk", -1},
+	{"csi_vfe_clk", -1},
+};
+
+static uint32_t msm_vfe32_ub_reg_offset(struct vfe_device *vfe_dev, int idx)
+{
+	return (VFE32_WM_BASE(idx) + 0x10);
+}
+
+static uint32_t msm_vfe32_get_ub_size(struct vfe_device *vfe_dev)
+{
+	return MSM_ISP32_TOTAL_WM_UB;
+}
+
+static int32_t msm_vfe32_init_qos_parms(struct vfe_device *vfe_dev,
+				struct msm_vfe_hw_init_parms *qos_parms,
+				struct msm_vfe_hw_init_parms *ds_parms)
+{
+	void __iomem *vfebase = vfe_dev->vfe_base;
+	struct device_node *of_node;
+	uint32_t *ds_settings = NULL, *ds_regs = NULL, ds_entries = 0;
+	int32_t i = 0, rc = 0;
+	uint32_t *qos_settings = NULL, *qos_regs = NULL, qos_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, qos_parms->entries,
+		&qos_entries);
+	if (rc < 0 || !qos_entries) {
+		pr_err("%s: NO QOS entries found\n", __func__);
+	} else {
+		qos_settings = kcalloc(qos_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!qos_settings)
+			return -ENOMEM;
+		qos_regs = kcalloc(qos_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!qos_regs) {
+			kfree(qos_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, qos_parms->regs,
+			qos_regs, qos_entries);
+		if (rc < 0) {
+			pr_err("%s: NO QOS BUS BDG info\n", __func__);
+			kfree(qos_settings);
+			kfree(qos_regs);
+		} else {
+			if (qos_parms->settings) {
+				rc = of_property_read_u32_array(of_node,
+					qos_parms->settings,
+					qos_settings, qos_entries);
+				if (rc < 0) {
+					pr_err("%s: NO QOS settings\n",
+						__func__);
+					kfree(qos_settings);
+					kfree(qos_regs);
+				} else {
+					for (i = 0; i < qos_entries; i++)
+						msm_camera_io_w(qos_settings[i],
+							vfebase + qos_regs[i]);
+					kfree(qos_settings);
+					kfree(qos_regs);
+				}
+			} else {
+				kfree(qos_settings);
+				kfree(qos_regs);
+			}
+		}
+	}
+	rc = of_property_read_u32(of_node, ds_parms->entries,
+		&ds_entries);
+	if (rc < 0 || !ds_entries) {
+		pr_err("%s: NO D/S entries found\n", __func__);
+	} else {
+		ds_settings = kcalloc(ds_entries, sizeof(uint32_t),
+				GFP_KERNEL);
+		if (!ds_settings)
+			return -ENOMEM;
+		ds_regs = kcalloc(ds_entries, sizeof(uint32_t),
+				GFP_KERNEL);
+		if (!ds_regs) {
+			kfree(ds_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, ds_parms->regs,
+			ds_regs, ds_entries);
+		if (rc < 0) {
+			pr_err("%s: NO D/S register info\n", __func__);
+			kfree(ds_settings);
+			kfree(ds_regs);
+		} else {
+			if (ds_parms->settings) {
+				rc = of_property_read_u32_array(of_node,
+					ds_parms->settings, ds_settings,
+					ds_entries);
+				if (rc < 0) {
+					pr_err("%s: NO D/S settings\n",
+						__func__);
+					kfree(ds_settings);
+					kfree(ds_regs);
+	} else {
+					for (i = 0; i < ds_entries; i++)
+						msm_camera_io_w(ds_settings[i],
+							vfebase + ds_regs[i]);
+						kfree(ds_regs);
+						kfree(ds_settings);
+				}
+			} else {
+				kfree(ds_regs);
+				kfree(ds_settings);
+			}
+		}
+	}
+	return 0;
+}
+
+static int32_t msm_vfe32_init_vbif_parms(struct vfe_device *vfe_dev,
+				struct msm_vfe_hw_init_parms *vbif_parms)
+{
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *vbif_settings = NULL, *vbif_regs = NULL, vbif_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, vbif_parms->entries,
+		&vbif_entries);
+	if (rc < 0 || !vbif_entries) {
+		pr_err("%s: NO VBIF entries found\n", __func__);
+	} else {
+		vbif_settings = kcalloc(vbif_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!vbif_settings)
+			return -ENOMEM;
+		vbif_regs = kcalloc(vbif_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!vbif_regs) {
+			kfree(vbif_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, vbif_parms->regs,
+			vbif_regs, vbif_entries);
+		if (rc < 0) {
+			pr_err("%s: NO VBIF info\n", __func__);
+			kfree(vbif_settings);
+			kfree(vbif_regs);
+		} else {
+			rc = of_property_read_u32_array(of_node,
+				vbif_parms->settings,
+				vbif_settings, vbif_entries);
+			if (rc < 0) {
+				pr_err("%s: NO VBIF settings\n",
+					__func__);
+				kfree(vbif_settings);
+				kfree(vbif_regs);
+			} else {
+				for (i = 0; i < vbif_entries; i++)
+					msm_camera_io_w(
+						vbif_settings[i],
+						vfe_vbif_base + vbif_regs[i]);
+				kfree(vbif_settings);
+				kfree(vbif_regs);
+			}
+		}
+	}
+	return 0;
+}
+
+static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
+{
+	int rc = -1;
+
+	vfe_dev->vfe_clk_idx = 0;
+	rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
+	if (rc < 0) {
+		pr_err("%s: Bandwidth registration Failed!\n", __func__);
+		goto bus_scale_register_failed;
+	}
+
+	if (vfe_dev->fs_vfe) {
+		rc = regulator_enable(vfe_dev->fs_vfe);
+		if (rc) {
+			pr_err("%s: Regulator enable failed\n", __func__);
+			goto fs_failed;
+		}
+	}
+
+	rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev,
+		 &msm_vfe32_1_clk_info[0]);
+	if (rc < 0) {
+		pr_err("msm_isp_get_clk_info() failed\n");
+		goto fs_failed;
+	}
+
+	if (vfe_dev->num_clk <= 0) {
+		pr_err("%s: Invalid num of clock\n", __func__);
+		goto fs_failed;
+	} else {
+		vfe_dev->vfe_clk =
+			kzalloc(sizeof(struct clk *) * vfe_dev->num_clk,
+			GFP_KERNEL);
+		if (!vfe_dev->vfe_clk) {
+			pr_err("%s:%d No memory\n", __func__, __LINE__);
+			return -ENOMEM;
+		}
+	}
+	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
+		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
+	if (rc < 0) {
+		rc = msm_cam_clk_enable(&vfe_dev->pdev->dev,
+			 msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+			ARRAY_SIZE(msm_vfe32_2_clk_info), 1);
+		if (rc < 0)
+			goto clk_enable_failed;
+		else
+			vfe_dev->vfe_clk_idx = 2;
+	} else
+		vfe_dev->vfe_clk_idx = 1;
+
+	vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start,
+		resource_size(vfe_dev->vfe_mem));
+	if (!vfe_dev->vfe_base) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto vfe_remap_failed;
+	}
+	vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] =
+		vfe_dev->vfe_base;
+
+	vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start,
+		resource_size(vfe_dev->vfe_vbif_mem));
+	if (!vfe_dev->vfe_vbif_base) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto vbif_remap_failed;
+	}
+
+	rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq,
+					 IRQF_TRIGGER_RISING, "vfe", vfe_dev);
+	if (rc < 0) {
+		pr_err("%s: irq request failed\n", __func__);
+		goto irq_req_failed;
+	}
+
+	return rc;
+irq_req_failed:
+	iounmap(vfe_dev->vfe_vbif_base);
+	vfe_dev->vfe_vbif_base = NULL;
+vbif_remap_failed:
+	iounmap(vfe_dev->vfe_base);
+	vfe_dev->vfe_base = NULL;
+vfe_remap_failed:
+	if (vfe_dev->vfe_clk_idx == 1)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 2)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
+clk_enable_failed:
+	if (vfe_dev->fs_vfe)
+		regulator_disable(vfe_dev->fs_vfe);
+	kfree(vfe_dev->vfe_clk);
+fs_failed:
+	msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
+bus_scale_register_failed:
+	return rc;
+}
+
+static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev)
+{
+	msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1C);
+	msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x20);
+	disable_irq(vfe_dev->vfe_irq->start);
+	free_irq(vfe_dev->vfe_irq->start, vfe_dev);
+	tasklet_kill(&vfe_dev->vfe_tasklet);
+	msm_isp_flush_tasklet(vfe_dev);
+	iounmap(vfe_dev->vfe_vbif_base);
+	vfe_dev->vfe_vbif_base = NULL;
+	if (vfe_dev->vfe_clk_idx == 1)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+	if (vfe_dev->vfe_clk_idx == 2)
+		msm_cam_clk_enable(&vfe_dev->pdev->dev,
+				msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+				ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
+	vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
+	iounmap(vfe_dev->vfe_base);
+	vfe_dev->vfe_base = NULL;
+	kfree(vfe_dev->vfe_clk);
+	regulator_disable(vfe_dev->fs_vfe);
+	msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
+}
+
+static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_hw_init_parms qos_parms;
+	struct msm_vfe_hw_init_parms vbif_parms;
+	struct msm_vfe_hw_init_parms ds_parms;
+
+	qos_parms.entries = "qos-entries";
+	qos_parms.regs = "qos-regs";
+	qos_parms.settings = "qos-settings";
+	vbif_parms.entries = "vbif-entries";
+	vbif_parms.regs = "vbif-regs";
+	vbif_parms.settings = "vbif-settings";
+	ds_parms.entries = "ds-entries";
+	ds_parms.regs = "ds-regs";
+	ds_parms.settings = "ds-settings";
+
+	msm_vfe32_init_qos_parms(vfe_dev, &qos_parms, &ds_parms);
+	msm_vfe32_init_vbif_parms(vfe_dev, &vbif_parms);
+
+	/* CGC_OVERRIDE */
+	msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC);
+	/* BUS_CFG */
+	msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C);
+	msm_camera_io_w(0x01000021, vfe_dev->vfe_base + 0x1C);
+	msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
+	msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
+
+}
+
+static void msm_vfe32_clear_status_reg(struct vfe_device *vfe_dev)
+{
+	msm_camera_io_w((1 << 23), vfe_dev->vfe_base + 0x1C);
+	msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x20);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
+	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
+}
+
+static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status1 & BIT(23))
+		complete(&vfe_dev->reset_complete);
+}
+
+static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+}
+
+static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0x1F))
+		return;
+
+	if (irq_status0 & BIT(0)) {
+		ISP_DBG("%s: SOF IRQ\n", __func__);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+			stream_count == 0) {
+			msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+			msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0, ts);
+			msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0);
+		}
+	}
+}
+
+static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev)
+{
+	uint32_t violation_status = vfe_dev->error_info.violation_status;
+
+	if (!violation_status)
+		return;
+
+	if (violation_status & BIT(0))
+		pr_err("%s: black violation\n", __func__);
+	if (violation_status & BIT(1))
+		pr_err("%s: rolloff violation\n", __func__);
+	if (violation_status & BIT(2))
+		pr_err("%s: demux violation\n", __func__);
+	if (violation_status & BIT(3))
+		pr_err("%s: demosaic violation\n", __func__);
+	if (violation_status & BIT(4))
+		pr_err("%s: crop violation\n", __func__);
+	if (violation_status & BIT(5))
+		pr_err("%s: scale violation\n", __func__);
+	if (violation_status & BIT(6))
+		pr_err("%s: wb violation\n", __func__);
+	if (violation_status & BIT(7))
+		pr_err("%s: clf violation\n", __func__);
+	if (violation_status & BIT(8))
+		pr_err("%s: matrix violation\n", __func__);
+	if (violation_status & BIT(9))
+		pr_err("%s: rgb lut violation\n", __func__);
+	if (violation_status & BIT(10))
+		pr_err("%s: la violation\n", __func__);
+	if (violation_status & BIT(11))
+		pr_err("%s: chroma enhance violation\n", __func__);
+	if (violation_status & BIT(12))
+		pr_err("%s: chroma suppress mce violation\n", __func__);
+	if (violation_status & BIT(13))
+		pr_err("%s: skin enhance violation\n", __func__);
+	if (violation_status & BIT(14))
+		pr_err("%s: asf violation\n", __func__);
+	if (violation_status & BIT(15))
+		pr_err("%s: scale y violation\n", __func__);
+	if (violation_status & BIT(16))
+		pr_err("%s: scale cbcr violation\n", __func__);
+	if (violation_status & BIT(17))
+		pr_err("%s: chroma subsample violation\n", __func__);
+	if (violation_status & BIT(18))
+		pr_err("%s: framedrop enc y violation\n", __func__);
+	if (violation_status & BIT(19))
+		pr_err("%s: framedrop enc cbcr violation\n", __func__);
+	if (violation_status & BIT(20))
+		pr_err("%s: framedrop view y violation\n", __func__);
+	if (violation_status & BIT(21))
+		pr_err("%s: framedrop view cbcr violation\n", __func__);
+	if (violation_status & BIT(22))
+		pr_err("%s: realign buf y violation\n", __func__);
+	if (violation_status & BIT(23))
+		pr_err("%s: realign buf cb violation\n", __func__);
+	if (violation_status & BIT(24))
+		pr_err("%s: realign buf cr violation\n", __func__);
+}
+
+static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask)
+{
+	*overflow_mask = 0x0;
+}
+
+static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev)
+{
+	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
+
+	if (error_status1 & BIT(0))
+		pr_err("%s: camif error status: 0x%x\n",
+			__func__, vfe_dev->error_info.camif_status);
+	if (error_status1 & BIT(1))
+		pr_err("%s: stats bhist overwrite\n", __func__);
+	if (error_status1 & BIT(2))
+		pr_err("%s: stats cs overwrite\n", __func__);
+	if (error_status1 & BIT(3))
+		pr_err("%s: stats ihist overwrite\n", __func__);
+	if (error_status1 & BIT(4))
+		pr_err("%s: realign buf y overflow\n", __func__);
+	if (error_status1 & BIT(5))
+		pr_err("%s: realign buf cb overflow\n", __func__);
+	if (error_status1 & BIT(6))
+		pr_err("%s: realign buf cr overflow\n", __func__);
+	if (error_status1 & BIT(7)) {
+		pr_err("%s: violation\n", __func__);
+		msm_vfe32_process_violation_status(vfe_dev);
+	}
+	if (error_status1 & BIT(8)) {
+		vfe_dev->stats->imagemaster0_overflow++;
+		pr_err("%s: image master 0 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(9)) {
+		vfe_dev->stats->imagemaster1_overflow++;
+		pr_err("%s: image master 1 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(10)) {
+		vfe_dev->stats->imagemaster2_overflow++;
+		pr_err("%s: image master 2 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(11)) {
+		vfe_dev->stats->imagemaster3_overflow++;
+		pr_err("%s: image master 3 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(12)) {
+		vfe_dev->stats->imagemaster4_overflow++;
+		pr_err("%s: image master 4 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(13)) {
+		vfe_dev->stats->imagemaster5_overflow++;
+		pr_err("%s: image master 5 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(14)) {
+		vfe_dev->stats->imagemaster6_overflow++;
+		pr_err("%s: image master 6 bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(15)) {
+		vfe_dev->stats->bg_overflow++;
+		pr_err("%s: status ae/bg bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(16)) {
+		vfe_dev->stats->bf_overflow++;
+		pr_err("%s: status af/bf bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(17)) {
+		vfe_dev->stats->awb_overflow++;
+		pr_err("%s: status awb bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(18)) {
+		vfe_dev->stats->rs_overflow++;
+		pr_err("%s: status rs bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(19)) {
+		vfe_dev->stats->cs_overflow++;
+		pr_err("%s: status cs bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(20)) {
+		vfe_dev->stats->ihist_overflow++;
+		pr_err("%s: status ihist bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(21)) {
+		vfe_dev->stats->skinbhist_overflow++;
+		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	}
+	if (error_status1 & BIT(22))
+		pr_err("%s: axi error\n", __func__);
+}
+
+static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
+	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24);
+	msm_camera_io_w_mb(*irq_status1, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18);
+
+	if (*irq_status1 & BIT(0))
+		vfe_dev->error_info.camif_status =
+			msm_camera_io_r(vfe_dev->vfe_base + 0x204);
+
+	if (*irq_status1 & BIT(7))
+		vfe_dev->error_info.violation_status |=
+			msm_camera_io_r(vfe_dev->vfe_base + 0x7B4);
+}
+
+static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
+}
+
+static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	uint32_t rdi_status;
+	enum msm_vfe_input_src i;
+
+	if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
+		return;
+
+	if (irq_status0 & BIT(5)) {
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+		vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
+			VFE_PIX_0);
+		if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) {
+			rdi_status = msm_camera_io_r(vfe_dev->vfe_base +
+				VFE32_XBAR_BASE(0));
+			rdi_status |= msm_camera_io_r(vfe_dev->vfe_base +
+				VFE32_XBAR_BASE(4));
+
+			if ((rdi_status & BIT(7)) && (!(irq_status0 & 0x20)))
+				return;
+		}
+		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+				MSM_ISP_COMP_IRQ_REG_UPD);
+	}
+
+	for (i = VFE_RAW_0; i <= VFE_RAW_2; i++) {
+		if (irq_status1 & BIT(26 + (i - VFE_RAW_0))) {
+			msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
+			msm_isp_axi_stream_update(vfe_dev, i, ts);
+			msm_isp_update_framedrop_reg(vfe_dev, i);
+
+			vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
+				i);
+		}
+	}
+
+	msm_isp_update_error_frame_count(vfe_dev);
+
+}
+
+static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	/* Not supported */
+}
+
+static void msm_vfe32_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) {
+		msm_camera_io_w_mb(0xF,
+			vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+			+ 0x260);
+		msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
+	} else if (!vfe_dev->is_split) {
+		msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
+	}
+}
+
+static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking)
+{
+	init_completion(&vfe_dev->reset_complete);
+	msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
+	return wait_for_completion_timeout(
+	   &vfe_dev->reset_complete, msecs_to_jiffies(50));
+}
+
+static void msm_vfe32_axi_reload_wm(
+	struct vfe_device *vfe_dev, void __iomem *vfe_base,
+	uint32_t reload_mask)
+{
+	if (!vfe_dev->pdev->dev.of_node) {
+		/*vfe32 A-family: 8960*/
+		msm_camera_io_w_mb(reload_mask, vfe_base + 0x38);
+	} else {
+		/*vfe32 B-family: 8610*/
+		msm_camera_io_w(0x0, vfe_base + 0x24);
+		msm_camera_io_w(0x0, vfe_base + 0x28);
+		msm_camera_io_w(0x0, vfe_base + 0x20);
+		msm_camera_io_w_mb(0x1, vfe_base + 0x18);
+		msm_camera_io_w(0x9AAAAAAA, vfe_base + 0x600);
+		msm_camera_io_w(reload_mask, vfe_base + 0x38);
+	}
+}
+
+static void msm_vfe32_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val = msm_camera_io_r(
+	   vfe_base + VFE32_WM_BASE(wm_idx));
+	if (enable)
+		val |= 0x1;
+	else
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_base + VFE32_WM_BASE(wm_idx));
+}
+
+static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index =
+		stream_info->comp_mask_index[vfe_idx];
+	uint32_t irq_mask;
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34);
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask |= BIT(comp_mask_index + 21);
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index =
+			stream_info->comp_mask_index[vfe_idx];
+	uint32_t irq_mask;
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34);
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask &= ~BIT(comp_mask_index + 21);
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t irq_mask;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask |= BIT(stream_info->wm[vfe_idx][0] + 6);
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t irq_mask;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask &= ~BIT(stream_info->wm[vfe_idx][0] + 6);
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+
+	if (stream_info->stream_src == PIX_ENCODER) {
+		msm_camera_io_w(framedrop_period - 1, vfe_base + 0x504);
+		msm_camera_io_w(framedrop_period - 1, vfe_base + 0x508);
+		msm_camera_io_w(framedrop_pattern, vfe_base + 0x50C);
+		msm_camera_io_w(framedrop_pattern, vfe_base + 0x510);
+	} else if (stream_info->stream_src == PIX_VIEWFINDER) {
+		msm_camera_io_w(framedrop_period - 1, vfe_base + 0x514);
+		msm_camera_io_w(framedrop_period - 1, vfe_base + 0x518);
+		msm_camera_io_w(framedrop_pattern, vfe_base + 0x51C);
+		msm_camera_io_w(framedrop_pattern, vfe_base + 0x520);
+	}
+	msm_camera_io_w_mb(0x1, vfe_base + 0x260);
+}
+
+static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	if (stream_info->stream_src == PIX_ENCODER) {
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x50C);
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x510);
+	} else if (stream_info->stream_src == PIX_VIEWFINDER) {
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x51C);
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x520);
+	}
+}
+
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
+{
+	int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
+	uint32_t io_format_reg;
+
+	bpp = msm_isp_get_bit_per_pixel(io_format);
+	if (bpp < 0) {
+		pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+			io_format, bpp);
+		return -EINVAL;
+	}
+
+	switch (bpp) {
+	case 8:
+		bpp_reg = 0;
+		break;
+	case 10:
+		bpp_reg = 1 << 0;
+		break;
+	case 12:
+		bpp_reg = 1 << 1;
+		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
+	}
+
+	if (stream_src == IDEAL_RAW) {
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		switch (pack_fmt) {
+		case QCOM:
+			pack_reg = 0x0;
+			break;
+		case MIPI:
+			pack_reg = 0x1;
+			break;
+		case DPCM6:
+			pack_reg = 0x2;
+			break;
+		case DPCM8:
+			pack_reg = 0x3;
+			break;
+		case PLAIN8:
+			pack_reg = 0x4;
+			break;
+		case PLAIN16:
+			pack_reg = 0x5;
+			break;
+		default:
+			pr_err("%s: invalid pack fmt!\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
+	switch (stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case CAMIF_RAW:
+		io_format_reg &= 0xFFFFCFFF;
+		io_format_reg |= bpp_reg << 12;
+		break;
+	case IDEAL_RAW:
+		io_format_reg &= 0xFFFFFFC8;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
+		break;
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+	default:
+		pr_err("%s: Invalid stream source\n", __func__);
+		return -EINVAL;
+	}
+	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+	return 0;
+}
+
+static int msm_vfe32_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	return 0;
+}
+
+static void msm_vfe32_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	pr_err("%s: Fetch engine not supported\n", __func__);
+}
+
+static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint16_t first_pixel, last_pixel, first_line, last_line;
+	struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
+	uint32_t val;
+
+	first_pixel = camif_cfg->first_pixel;
+	last_pixel = camif_cfg->last_pixel;
+	first_line = camif_cfg->first_line;
+	last_line = camif_cfg->last_line;
+
+	msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern,
+					vfe_dev->vfe_base + 0x14);
+
+	msm_camera_io_w(camif_cfg->lines_per_frame << 16 |
+					camif_cfg->pixels_per_line,
+					vfe_dev->vfe_base + 0x1EC);
+
+	msm_camera_io_w(first_pixel << 16 | last_pixel,
+					vfe_dev->vfe_base + 0x1F0);
+
+	msm_camera_io_w(first_line << 16 | last_line,
+					vfe_dev->vfe_base + 0x1F4);
+
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC);
+	val &= 0xFFFFFFFC;
+	val |= camif_cfg->camif_input;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x6FC);
+}
+
+static void msm_vfe32_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	switch (pix_cfg->input_mux) {
+	case CAMIF:
+		msm_vfe32_cfg_camif(vfe_dev, pix_cfg);
+		break;
+	case EXTERNAL_READ:
+		msm_vfe32_cfg_fetch_engine(vfe_dev, pix_cfg);
+		break;
+	default:
+		pr_err("%s: Unsupported input mux %d\n",
+			__func__, pix_cfg->input_mux);
+	}
+}
+
+static void msm_vfe32_update_camif_state(
+	struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state)
+{
+	uint32_t val;
+	bool bus_en, vfe_en;
+
+	if (update_state == NO_UPDATE)
+		return;
+
+	if (update_state == ENABLE_CAMIF) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+		val |= 0x1;
+		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x1C);
+
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4);
+		bus_en =
+		((vfe_dev->axi_data.src_info[
+			VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
+		vfe_en =
+		((vfe_dev->axi_data.src_info[
+			VFE_PIX_0].stream_count > 0) ? 1 : 0);
+		val &= 0xFFFFFF3F;
+		val = val | bus_en << 7 | vfe_en << 6;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
+	} else if (update_state == DISABLE_CAMIF) {
+		msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
+		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+	}
+}
+
+static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev,
+	struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+	rdi_reg_cfg &= ~(BIT(16 + rdi));
+	rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+	msm_camera_io_w(rdi_reg_cfg,
+		vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x70003;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+
+}
+
+static void msm_vfe32_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	uint32_t val;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+
+	if (!stream_info->frame_based) {
+		/*WR_IMAGE_SIZE*/
+		val =
+			((msm_isp_cal_word_per_line(
+			stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_width)+1)/2 - 1) << 16 |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
+
+		/*WR_BUFFER_CFG*/
+		val =
+			msm_isp_cal_word_per_line(
+			stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_stride) << 16 |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_height - 1) << 4 | VFE32_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	} else {
+		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+		val =
+			msm_isp_cal_word_per_line(
+			stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_width) << 16 |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_height - 1) << 4 | VFE32_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	}
+}
+
+static void msm_vfe32_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	uint32_t val = 0;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+	/*WR_IMAGE_SIZE*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
+	/*WR_BUFFER_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+}
+
+static void msm_vfe32_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	struct msm_vfe_axi_plane_cfg *plane_cfg =
+		&stream_info->plane_cfg[vfe_idx][plane_idx];
+	uint8_t wm = stream_info->wm[vfe_idx][plane_idx];
+	uint32_t xbar_cfg = 0;
+	uint32_t xbar_reg_cfg = 0;
+
+	switch (stream_info->stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER: {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
+			/*SINGLE_STREAM_SEL*/
+			xbar_cfg |= plane_cfg->output_plane_format << 5;
+		} else {
+			switch (stream_info->output_format) {
+			case V4L2_PIX_FMT_NV12:
+			case V4L2_PIX_FMT_NV14:
+			case V4L2_PIX_FMT_NV16:
+				xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
+				break;
+			}
+			xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/
+		}
+		if (stream_info->stream_src == PIX_VIEWFINDER)
+			xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
+		break;
+	}
+	case CAMIF_RAW:
+		xbar_cfg = 0x60;
+		break;
+	case IDEAL_RAW:
+		xbar_cfg = 0x80;
+		break;
+	case RDI_INTF_0:
+		xbar_cfg = 0xA0;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0xC0;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0xE0;
+		break;
+	default:
+		pr_err("%s: Invalid stream src\n", __func__);
+	}
+	xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm));
+	xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
+}
+
+static void msm_vfe32_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint8_t wm = stream_info->wm[vfe_idx][plane_idx];
+	uint32_t xbar_reg_cfg = 0;
+
+	xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
+}
+
+static void msm_vfe32_update_ping_pong_addr(void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size)
+{
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE32_PING_PONG_BASE(wm_idx, pingpong_bit));
+}
+
+static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking)
+{
+	uint32_t halt_mask;
+	uint32_t axi_busy_flag = true;
+
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);
+	while (axi_busy_flag) {
+		if (msm_camera_io_r(
+			vfe_dev->vfe_base + 0x1DC) & 0x1)
+			axi_busy_flag = false;
+	}
+	msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8);
+	halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
+	halt_mask &= 0xFEFFFFFF;
+	/* Disable AXI IRQ */
+	msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20);
+	return 0;
+}
+
+static uint32_t msm_vfe32_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 6) & 0x7F;
+}
+
+static uint32_t msm_vfe32_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 21) & 0x7;
+}
+
+static uint32_t msm_vfe32_get_pingpong_status(struct vfe_device *vfe_dev)
+{
+	return msm_camera_io_r(vfe_dev->vfe_base + 0x180);
+}
+
+static int msm_vfe32_get_stats_idx(enum msm_isp_stats_type stats_type)
+{
+	switch (stats_type) {
+	case MSM_ISP_STATS_AEC:
+	case MSM_ISP_STATS_BG:
+		return 0;
+	case MSM_ISP_STATS_AF:
+	case MSM_ISP_STATS_BF:
+		return 1;
+	case MSM_ISP_STATS_AWB:
+		return 2;
+	case MSM_ISP_STATS_RS:
+		return 3;
+	case MSM_ISP_STATS_CS:
+		return 4;
+	case MSM_ISP_STATS_IHIST:
+		return 5;
+	case MSM_ISP_STATS_SKIN:
+	case MSM_ISP_STATS_BHIST:
+		return 6;
+	default:
+		pr_err("%s: Invalid stats type\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int msm_vfe32_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	return 0;
+}
+
+static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t comp_idx, uint8_t enable)
+{
+}
+
+static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t irq_mask;
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask |= BIT(STATS_IDX(stream_info->stream_handle[vfe_idx]) + 13);
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	uint32_t irq_mask;
+
+	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13));
+	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
+}
+
+static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	/*Nothing to configure for VFE3.x*/
+}
+
+static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	/*Nothing to configure for VFE3.x*/
+}
+
+static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = VFE32_UB_SIZE;
+	uint32_t ub_size[VFE32_NUM_STATS_TYPE] = {
+		107, /*MSM_ISP_STATS_BG*/
+		92, /*MSM_ISP_STATS_BF*/
+		2, /*MSM_ISP_STATS_AWB*/
+		7,  /*MSM_ISP_STATS_RS*/
+		16, /*MSM_ISP_STATS_CS*/
+		2, /*MSM_ISP_STATS_IHIST*/
+		7, /*MSM_ISP_STATS_BHIST*/
+	};
+
+	if (vfe_dev->vfe_hw_version == VFE32_8909_VERSION)
+		ub_offset = VFE32_UB_SIZE_32KB;
+
+	for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8);
+	}
+}
+
+static bool msm_vfe32_is_module_cfg_lock_needed(
+	uint32_t reg_offset)
+{
+	return false;
+}
+
+static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, module_cfg_mask = 0;
+
+	for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				module_cfg_mask |= 1 << (5 + i);
+				break;
+			case 5:
+				module_cfg_mask |= 1 << 16;
+				break;
+			case 6:
+				module_cfg_mask |= 1 << 19;
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x10);
+	if (enable)
+		module_cfg |= module_cfg_mask;
+	else
+		module_cfg &= ~module_cfg_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10);
+}
+
+static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
+	dma_addr_t paddr, uint32_t buf_sz)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	int stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+}
+
+static uint32_t msm_vfe32_stats_get_wm_mask(uint32_t irq_status0,
+	uint32_t irq_status1)
+{
+	return (irq_status0 >> 13) & 0x7F;
+}
+
+static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0,
+	uint32_t irq_status1)
+{
+	return (irq_status0 >> 24) & 0x1;
+}
+
+static uint32_t msm_vfe32_stats_get_frame_id(struct vfe_device *vfe_dev)
+{
+	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+}
+
+static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev)
+{
+	int rc = 0;
+
+	vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev,
+					IORESOURCE_MEM, "vfe");
+	if (!vfe_dev->vfe_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+	vfe_dev->vfe_vbif_mem = platform_get_resource_byname(
+		vfe_dev->pdev,
+		IORESOURCE_MEM, "vfe_vbif");
+	if (!vfe_dev->vfe_vbif_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+	vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev,
+					IORESOURCE_IRQ, "vfe");
+	if (!vfe_dev->vfe_irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+	vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd");
+	if (IS_ERR(vfe_dev->fs_vfe)) {
+		pr_err("%s: Regulator get failed %ld\n", __func__,
+			PTR_ERR(vfe_dev->fs_vfe));
+		vfe_dev->fs_vfe = NULL;
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+	if (!vfe_dev->pdev->dev.of_node)
+		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+	else
+		vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe");
+
+	if (!vfe_dev->iommu_ctx[0]) {
+		pr_err("%s: no iommux ctx resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+	if (!vfe_dev->pdev->dev.of_node)
+		vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+	else
+		vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe");
+
+	if (!vfe_dev->iommu_ctx[1]) {
+		pr_err("%s: no iommux ctx resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
+vfe_no_resource:
+	return rc;
+}
+
+static void msm_vfe32_get_error_mask(uint32_t *error_mask0,
+	uint32_t *error_mask1)
+{
+	*error_mask0 = 0x00000000;
+	*error_mask1 = 0x007FFFFF;
+}
+
+struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
+	.num_wm = 5,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 64,
+	.scratch_buf_range = SZ_32M,
+};
+
+static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_AEC | 1 << MSM_ISP_STATS_BG |
+		1 << MSM_ISP_STATS_AF | 1 << MSM_ISP_STATS_BF |
+		1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS |
+		1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.num_stats_type = VFE32_NUM_STATS_TYPE,
+	.num_stats_comp_mask = 0,
+};
+
+struct msm_vfe_hardware_info vfe32_hw_info = {
+	.num_iommu_ctx = 2,
+	.num_iommu_secure_ctx = 0,
+	.vfe_clk_idx = VFE32_CLK_IDX,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe32_read_and_clear_irq_status,
+			.read_irq_status = msm_vfe32_read_irq_status,
+			.process_camif_irq = msm_vfe32_process_camif_irq,
+			.process_reset_irq = msm_vfe32_process_reset_irq,
+			.process_halt_irq = msm_vfe32_process_halt_irq,
+			.process_reg_update = msm_vfe32_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe32_process_epoch_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe32_axi_reload_wm,
+			.enable_wm = msm_vfe32_axi_enable_wm,
+			.cfg_io_format = msm_vfe32_cfg_io_format,
+			.cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe32_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe32_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe32_cfg_framedrop,
+			.clear_framedrop = msm_vfe32_clear_framedrop,
+			.cfg_wm_reg = msm_vfe32_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe32_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.update_ping_pong_addr =
+				msm_vfe32_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe32_get_comp_mask,
+			.get_wm_mask = msm_vfe32_get_wm_mask,
+			.get_pingpong_status = msm_vfe32_get_pingpong_status,
+			.halt = msm_vfe32_axi_halt,
+			.ub_reg_offset = msm_vfe40_ub_reg_offset,
+			.get_ub_size = msm_vfe40_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe32_reg_update,
+			.cfg_input_mux = msm_vfe32_cfg_input_mux,
+			.update_camif_state = msm_vfe32_update_camif_state,
+			.start_fetch_eng = msm_vfe32_start_fetch_engine,
+			.cfg_rdi_reg = msm_vfe32_cfg_rdi_reg,
+			.reset_hw = msm_vfe32_reset_hardware,
+			.init_hw = msm_vfe32_init_hardware,
+			.init_hw_reg = msm_vfe32_init_hardware_reg,
+			.clear_status_reg = msm_vfe32_clear_status_reg,
+			.release_hw = msm_vfe32_release_hardware,
+			.get_platform_data = msm_vfe32_get_platform_data,
+			.get_error_mask = msm_vfe32_get_error_mask,
+			.process_error_status = msm_vfe32_process_error_status,
+			.get_overflow_mask = msm_vfe32_get_overflow_mask,
+			.is_module_cfg_lock_needed =
+				msm_vfe32_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = NULL,
+			.set_bus_err_ign_mask = NULL,
+			.get_bus_err_mask = NULL,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe32_get_stats_idx,
+			.check_streams = msm_vfe32_stats_check_streams,
+			.cfg_comp_mask = msm_vfe32_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe32_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe32_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe32_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe32_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe32_stats_cfg_ub,
+			.enable_module = msm_vfe32_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe32_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe32_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe32_stats_get_wm_mask,
+			.get_frame_id = msm_vfe32_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe32_get_pingpong_status,
+			.enable_stats_wm = NULL,
+		},
+	},
+	.dmi_reg_offset = 0x5A0,
+	.axi_hw_info = &msm_vfe32_axi_hw_info,
+	.stats_hw_info = &msm_vfe32_stats_hw_info,
+};
+EXPORT_SYMBOL(vfe32_hw_info);
+
+static const struct of_device_id msm_vfe32_dt_match[] = {
+	{
+		.compatible = "qcom,vfe32",
+		.data = &vfe32_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe32_dt_match);
+
+static struct platform_driver vfe32_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe32",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe32_dt_match,
+	},
+	.id_table = msm_vfe32_dev_id,
+};
+
+static int __init msm_vfe32_init_module(void)
+{
+	return platform_driver_register(&vfe32_driver);
+}
+
+static void __exit msm_vfe32_exit_module(void)
+{
+	platform_driver_unregister(&vfe32_driver);
+}
+
+module_init(msm_vfe32_init_module);
+module_exit(msm_vfe32_exit_module);
+MODULE_DESCRIPTION("MSM VFE32 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.h
new file mode 100644
index 0000000..3669b97
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP32_H__
+#define __MSM_ISP32_H__
+
+extern struct msm_vfe_hardware_info vfe32_hw_info;
+#endif /* __MSM_ISP32_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
new file mode 100644
index 0000000..269d563
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -0,0 +1,2373 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <asm/div64.h>
+#include "msm_isp40.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm.h"
+#include "msm_camera_io_util.h"
+#include "msm_isp47.h"
+#include "linux/iopoll.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define VFE40_BURST_LEN 1
+#define VFE40_BURST_LEN_8916_VERSION 2
+#define VFE40_BURST_LEN_8952_VERSION 3
+#define VFE40_WM_BIT_SHIFT 4
+#define VFE40_WM_BIT_SHIFT_8976_VERSION 3
+#define VFE40_STATS_BURST_LEN 1
+#define VFE40_STATS_BURST_LEN_8916_VERSION 2
+#define VFE40_FETCH_BURST_LEN 3
+#define VFE40_UB_SIZE 1536 /* 1536 * 128 bits = 24KB */
+#define VFE40_UB_SIZE_8952 2048 /* 2048 * 128 bits = 32KB */
+#define VFE40_UB_SIZE_8916 3072 /* 3072 * 128 bits = 48KB */
+#define VFE40_EQUAL_SLICE_UB 190 /* (UB_SIZE - STATS SIZE)/6 */
+#define VFE40_EQUAL_SLICE_UB_8916 236
+#define VFE40_TOTAL_WM_UB 1144 /* UB_SIZE - STATS SIZE */
+#define VFE40_TOTAL_WM_UB_8916 1656
+#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
+#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
+#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
+#define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
+#define VFE40_PING_PONG_BASE(wm, ping_pong) \
+	(VFE40_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1)))
+
+#define VFE40_BUS_RD_CGC_OVERRIDE_BIT 16
+
+#define STATS_IDX_BE        0
+#define STATS_IDX_BG        1
+#define STATS_IDX_BF        2
+#define STATS_IDX_AWB       3
+#define STATS_IDX_RS        4
+#define STATS_IDX_CS        5
+#define STATS_IDX_IHIST     6
+#define STATS_IDX_BHIST     7
+
+static uint8_t stats_pingpong_offset_map[] = {
+	8, 9, 10, 11, 12, 13, 14, 15};
+
+#define VFE40_NUM_STATS_TYPE 8
+#define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx)
+#define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \
+	(VFE40_STATS_BASE(idx) + 0x4 * \
+	(~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1))
+
+#define VFE40_VBIF_CLKON                    0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0          0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1          0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2          0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0          0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1          0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2          0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0         0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0         0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST        0xD8
+#define VFE40_VBIF_OCMEM_OUT_MAX_BURST      0xDC
+#define VFE40_VBIF_ARB_CTL                  0xF0
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB      0x124
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0   0x160
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1   0x164
+#define VFE40_VBIF_OUT_AXI_AOOO_EN          0x178
+#define VFE40_VBIF_OUT_AXI_AOOO             0x17C
+
+#define VFE40_BUS_BDG_QOS_CFG_0     0x000002C4
+#define VFE40_BUS_BDG_QOS_CFG_1     0x000002C8
+#define VFE40_BUS_BDG_QOS_CFG_2     0x000002CC
+#define VFE40_BUS_BDG_QOS_CFG_3     0x000002D0
+#define VFE40_BUS_BDG_QOS_CFG_4     0x000002D4
+#define VFE40_BUS_BDG_QOS_CFG_5     0x000002D8
+#define VFE40_BUS_BDG_QOS_CFG_6     0x000002DC
+#define VFE40_BUS_BDG_QOS_CFG_7     0x000002E0
+
+#define VFE40_CLK_IDX 2
+
+static uint32_t msm_vfe40_ub_reg_offset(struct vfe_device *vfe_dev, int idx)
+{
+	return (VFE40_WM_BASE(idx) + 0x10);
+}
+
+static uint32_t msm_vfe40_get_ub_size(struct vfe_device *vfe_dev)
+{
+	if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) {
+		vfe_dev->ub_info->wm_ub = VFE40_TOTAL_WM_UB_8916;
+		return VFE40_TOTAL_WM_UB_8916;
+	}
+	return VFE40_TOTAL_WM_UB;
+}
+
+static void msm_vfe40_config_irq(struct vfe_device *vfe_dev,
+		uint32_t irq0_mask, uint32_t irq1_mask,
+		enum msm_isp_irq_operation oper)
+{
+	switch (oper) {
+	case MSM_ISP_IRQ_ENABLE:
+		vfe_dev->irq0_mask |= irq0_mask;
+		vfe_dev->irq1_mask |= irq1_mask;
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+		break;
+	case MSM_ISP_IRQ_DISABLE:
+		vfe_dev->irq0_mask &= ~irq0_mask;
+		vfe_dev->irq1_mask &= ~irq1_mask;
+		break;
+	case MSM_ISP_IRQ_SET:
+		vfe_dev->irq0_mask = irq0_mask;
+		vfe_dev->irq1_mask = irq1_mask;
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+	}
+	msm_camera_io_w_mb(vfe_dev->irq0_mask, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w_mb(vfe_dev->irq1_mask, vfe_dev->vfe_base + 0x2C);
+}
+
+static int32_t msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev,
+				struct msm_vfe_hw_init_parms *qos_parms,
+				struct msm_vfe_hw_init_parms *ds_parms)
+{
+	void __iomem *vfebase = vfe_dev->vfe_base;
+	struct device_node *of_node;
+	uint32_t *ds_settings = NULL, *ds_regs = NULL, ds_entries = 0;
+	int32_t i = 0, rc = 0;
+	uint32_t *qos_settings = NULL, *qos_regs = NULL, qos_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, qos_parms->entries,
+		&qos_entries);
+	if (rc < 0 || !qos_entries) {
+		pr_err("%s: NO QOS entries found\n", __func__);
+	} else {
+		qos_settings = kcalloc(qos_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!qos_settings)
+			return -ENOMEM;
+		qos_regs = kcalloc(qos_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!qos_regs) {
+			kfree(qos_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, qos_parms->regs,
+			qos_regs, qos_entries);
+		if (rc < 0) {
+			pr_err("%s: NO QOS BUS BDG info\n", __func__);
+			kfree(qos_settings);
+			kfree(qos_regs);
+		} else {
+			if (qos_parms->settings) {
+				rc = of_property_read_u32_array(of_node,
+					qos_parms->settings,
+					qos_settings, qos_entries);
+				if (rc < 0) {
+					pr_err("%s: NO QOS settings\n",
+						__func__);
+					kfree(qos_settings);
+					kfree(qos_regs);
+				} else {
+					for (i = 0; i < qos_entries; i++)
+						msm_camera_io_w(qos_settings[i],
+							vfebase + qos_regs[i]);
+					kfree(qos_settings);
+					kfree(qos_regs);
+				}
+			} else {
+				kfree(qos_settings);
+				kfree(qos_regs);
+			}
+		}
+	}
+	rc = of_property_read_u32(of_node, ds_parms->entries,
+		&ds_entries);
+	if (rc < 0 || !ds_entries) {
+		pr_err("%s: NO D/S entries found\n", __func__);
+	} else {
+		ds_settings = kcalloc(ds_entries, sizeof(uint32_t),
+				GFP_KERNEL);
+		if (!ds_settings)
+			return -ENOMEM;
+		ds_regs = kcalloc(ds_entries, sizeof(uint32_t),
+				GFP_KERNEL);
+		if (!ds_regs) {
+			kfree(ds_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, ds_parms->regs,
+			ds_regs, ds_entries);
+		if (rc < 0) {
+			pr_err("%s: NO D/S register info\n", __func__);
+			kfree(ds_settings);
+			kfree(ds_regs);
+		} else {
+			if (ds_parms->settings) {
+				rc = of_property_read_u32_array(of_node,
+					ds_parms->settings, ds_settings,
+					ds_entries);
+				if (rc < 0) {
+					pr_err("%s: NO D/S settings\n",
+						__func__);
+					kfree(ds_settings);
+					kfree(ds_regs);
+	} else {
+					for (i = 0; i < ds_entries; i++)
+						msm_camera_io_w(ds_settings[i],
+							vfebase + ds_regs[i]);
+						kfree(ds_regs);
+						kfree(ds_settings);
+				}
+			} else {
+				kfree(ds_regs);
+				kfree(ds_settings);
+			}
+		}
+	}
+	return 0;
+}
+
+static int32_t msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev,
+				struct msm_vfe_hw_init_parms *vbif_parms)
+{
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *vbif_settings = NULL, *vbif_regs = NULL, vbif_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, vbif_parms->entries,
+		&vbif_entries);
+	if (rc < 0 || !vbif_entries) {
+		pr_err("%s: NO VBIF entries found\n", __func__);
+	} else {
+		vbif_settings = kcalloc(vbif_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!vbif_settings)
+			return -ENOMEM;
+		vbif_regs = kcalloc(vbif_entries, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!vbif_regs) {
+			kfree(vbif_settings);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node, vbif_parms->regs,
+			vbif_regs, vbif_entries);
+		if (rc < 0) {
+			pr_err("%s: NO VBIF info\n", __func__);
+			kfree(vbif_settings);
+			kfree(vbif_regs);
+		} else {
+			rc = of_property_read_u32_array(of_node,
+				vbif_parms->settings,
+				vbif_settings, vbif_entries);
+			if (rc < 0) {
+				pr_err("%s: NO VBIF settings\n",
+					__func__);
+				kfree(vbif_settings);
+				kfree(vbif_regs);
+			} else {
+				for (i = 0; i < vbif_entries; i++)
+					msm_camera_io_w(
+						vbif_settings[i],
+						vfe_vbif_base + vbif_regs[i]);
+				kfree(vbif_settings);
+				kfree(vbif_regs);
+			}
+		}
+	}
+	return 0;
+}
+
+static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_hw_init_parms qos_parms;
+	struct msm_vfe_hw_init_parms vbif_parms;
+	struct msm_vfe_hw_init_parms ds_parms;
+
+	qos_parms.entries = "qos-entries";
+	qos_parms.regs = "qos-regs";
+	qos_parms.settings = "qos-settings";
+	vbif_parms.entries = "vbif-entries";
+	vbif_parms.regs = "vbif-regs";
+	vbif_parms.settings = "vbif-settings";
+	ds_parms.entries = "ds-entries";
+	ds_parms.regs = "ds-regs";
+	ds_parms.settings = "ds-settings";
+
+	switch (vfe_dev->vfe_hw_version) {
+	case VFE40_8974V1_VERSION:
+	case VFE40_8x26_VERSION:
+	case VFE40_8916_VERSION:
+	case VFE40_8939_VERSION:
+		break;
+	case VFE40_8x26V2_VERSION:
+		qos_parms.settings = "qos-v2-settings";
+		break;
+	case VFE40_8974V2_VERSION:
+	case VFE40_8974V3_VERSION:
+		if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION)
+			qos_parms.settings = "qos-v2-settings";
+		else
+			qos_parms.settings = "qos-v3-settings";
+		vbif_parms.entries = "vbif-v2-entries";
+		vbif_parms.regs = "vbif-v2-regs";
+		vbif_parms.settings = "vbif-v2-settings";
+		break;
+	case VFE40_8937_VERSION:
+	case VFE40_8953_VERSION:
+	case VFE40_8917_VERSION:
+	default:
+		ISP_DBG("%s: No special QOS\n", __func__);
+	}
+
+	msm_vfe40_init_qos_parms(vfe_dev, &qos_parms, &ds_parms);
+	msm_vfe40_init_vbif_parms(vfe_dev, &vbif_parms);
+	/* BUS_CFG */
+	msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50);
+	msm_vfe40_config_irq(vfe_dev, 0x800000E0, 0xFEFFFF7E,
+			MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe40_clear_status_reg(struct vfe_device *vfe_dev)
+{
+	vfe_dev->irq0_mask = (1 << 31);
+	vfe_dev->irq1_mask = 0;
+	msm_vfe40_config_irq(vfe_dev, (1 << 31), 0,
+			MSM_ISP_IRQ_SET);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
+	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
+}
+
+static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status0 & (1 << 31))
+		complete(&vfe_dev->reset_complete);
+}
+
+static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status1 & (1 << 8)) {
+		complete(&vfe_dev->halt_complete);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
+	}
+}
+
+static void msm_vfe40_process_input_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0x1000003))
+		return;
+
+	if (irq_status0 & (1 << 0)) {
+		ISP_DBG("%s: SOF IRQ\n", __func__);
+		msm_isp_increment_frame_id(vfe_dev, VFE_PIX_0, ts);
+	}
+
+	if (irq_status0 & (1 << 24)) {
+		ISP_DBG("%s: Fetch Engine Read IRQ\n", __func__);
+		msm_isp_fetch_engine_done_notify(vfe_dev,
+				&vfe_dev->fetch_engine_info);
+	}
+
+	if (irq_status0 & (1 << 1))
+		ISP_DBG("%s: EOF IRQ\n", __func__);
+}
+
+static void msm_vfe40_process_violation_status(
+	struct vfe_device *vfe_dev)
+{
+	uint32_t violation_status = vfe_dev->error_info.violation_status;
+
+	if (!violation_status)
+		return;
+
+	if (violation_status & (1 << 0))
+		pr_err("%s: vfe %d camif violation\n", __func__,
+			vfe_dev->pdev->id);
+	if (violation_status & (1 << 1))
+		pr_err("%s: vfe %d black violation\n", __func__,
+		vfe_dev->pdev->id);
+	if (violation_status & (1 << 2))
+		pr_err("%s: vfe %d rolloff violation\n", __func__,
+		vfe_dev->pdev->id);
+	if (violation_status & (1 << 3))
+		pr_err("%s: demux violation\n", __func__);
+	if (violation_status & (1 << 4))
+		pr_err("%s: demosaic violation\n", __func__);
+	if (violation_status & (1 << 5))
+		pr_err("%s: wb violation\n", __func__);
+	if (violation_status & (1 << 6))
+		pr_err("%s: clf violation\n", __func__);
+	if (violation_status & (1 << 7))
+		pr_err("%s: color correct violation\n", __func__);
+	if (violation_status & (1 << 8))
+		pr_err("%s: rgb lut violation\n", __func__);
+	if (violation_status & (1 << 9))
+		pr_err("%s: la violation\n", __func__);
+	if (violation_status & (1 << 10))
+		pr_err("%s: chroma enhance violation\n", __func__);
+	if (violation_status & (1 << 11))
+		pr_err("%s: chroma suppress mce violation\n", __func__);
+	if (violation_status & (1 << 12))
+		pr_err("%s: skin enhance violation\n", __func__);
+	if (violation_status & (1 << 13))
+		pr_err("%s: color tranform enc violation\n", __func__);
+	if (violation_status & (1 << 14))
+		pr_err("%s: color tranform view violation\n", __func__);
+	if (violation_status & (1 << 15))
+		pr_err("%s: scale enc y violation\n", __func__);
+	if (violation_status & (1 << 16))
+		pr_err("%s: scale enc cbcr violation\n", __func__);
+	if (violation_status & (1 << 17))
+		pr_err("%s: scale view y violation\n", __func__);
+	if (violation_status & (1 << 18))
+		pr_err("%s: scale view cbcr violation\n", __func__);
+	if (violation_status & (1 << 19))
+		pr_err("%s: asf enc violation\n", __func__);
+	if (violation_status & (1 << 20))
+		pr_err("%s: asf view violation\n", __func__);
+	if (violation_status & (1 << 21))
+		pr_err("%s: crop enc y violation\n", __func__);
+	if (violation_status & (1 << 22))
+		pr_err("%s: crop enc cbcr violation\n", __func__);
+	if (violation_status & (1 << 23))
+		pr_err("%s: crop view y violation\n", __func__);
+	if (violation_status & (1 << 24))
+		pr_err("%s: crop view cbcr violation\n", __func__);
+	if (violation_status & (1 << 25))
+		pr_err("%s: realign buf y violation\n", __func__);
+	if (violation_status & (1 << 26))
+		pr_err("%s: realign buf cb violation\n", __func__);
+	if (violation_status & (1 << 27))
+		pr_err("%s: realign buf cr violation\n", __func__);
+}
+
+static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev)
+{
+	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
+
+	if (error_status1 & (1 << 0)) {
+		pr_err_ratelimited("%s: vfe %d camif error status: 0x%x\n",
+			__func__, vfe_dev->pdev->id,
+			vfe_dev->error_info.camif_status);
+		msm_camera_io_dump(vfe_dev->vfe_base + 0x2F4, 0x30, 1);
+	}
+	if (error_status1 & (1 << 1))
+		pr_err_ratelimited("%s: stats bhist overwrite\n", __func__);
+	if (error_status1 & (1 << 2))
+		pr_err_ratelimited("%s: stats cs overwrite\n", __func__);
+	if (error_status1 & (1 << 3))
+		pr_err_ratelimited("%s: stats ihist overwrite\n", __func__);
+	if (error_status1 & (1 << 4))
+		pr_err_ratelimited("%s: realign buf y overflow\n", __func__);
+	if (error_status1 & (1 << 5))
+		pr_err_ratelimited("%s: realign buf cb overflow\n", __func__);
+	if (error_status1 & (1 << 6))
+		pr_err_ratelimited("%s: realign buf cr overflow\n", __func__);
+	if (error_status1 & (1 << 7))
+		msm_vfe40_process_violation_status(vfe_dev);
+	if (error_status1 & (1 << 9)) {
+		vfe_dev->stats->imagemaster0_overflow++;
+		pr_err_ratelimited("%s: image master 0 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 10)) {
+		vfe_dev->stats->imagemaster1_overflow++;
+		pr_err_ratelimited("%s: image master 1 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 11)) {
+		vfe_dev->stats->imagemaster2_overflow++;
+		pr_err_ratelimited("%s: image master 2 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 12)) {
+		vfe_dev->stats->imagemaster3_overflow++;
+		pr_err_ratelimited("%s: image master 3 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 13)) {
+		vfe_dev->stats->imagemaster4_overflow++;
+		pr_err_ratelimited("%s: image master 4 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 14)) {
+		vfe_dev->stats->imagemaster5_overflow++;
+		pr_err_ratelimited("%s: image master 5 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 15)) {
+		vfe_dev->stats->imagemaster6_overflow++;
+		pr_err_ratelimited("%s: image master 6 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 16)) {
+		vfe_dev->stats->be_overflow++;
+		pr_err_ratelimited("%s: status be bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 17)) {
+		vfe_dev->stats->bg_overflow++;
+		pr_err_ratelimited("%s: status bg bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 18)) {
+		vfe_dev->stats->bf_overflow++;
+		pr_err_ratelimited("%s: status bf bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 19)) {
+		vfe_dev->stats->awb_overflow++;
+		pr_err_ratelimited("%s: status awb bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 20)) {
+		vfe_dev->stats->rs_overflow++;
+		pr_err_ratelimited("%s: status rs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 21)) {
+		vfe_dev->stats->cs_overflow++;
+		pr_err_ratelimited("%s: status cs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 22)) {
+		vfe_dev->stats->ihist_overflow++;
+		pr_err_ratelimited("%s: status ihist bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 23)) {
+		vfe_dev->stats->skinbhist_overflow++;
+		pr_err_ratelimited("%s: status skin bhist bus overflow\n",
+			__func__);
+	}
+
+	/* Update ab/ib values for any overflow that may have occurred*/
+	if ((error_status1 >> 9) & 0x7FFF)
+		msm_isp_update_last_overflow_ab_ib(vfe_dev);
+}
+
+static void msm_vfe40_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+	/*
+	 * Ignore composite 2/3 irq which is used for dual VFE only
+	 */
+	if (*irq_status0 & 0x6000000)
+		*irq_status0 &= ~(0x18000000);
+	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
+	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
+	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+	if (*irq_status0 & 0x18000000) {
+		pr_err_ratelimited("%s: Protection triggered\n", __func__);
+		*irq_status0 &= ~(0x18000000);
+	}
+
+	*irq_status0 &= vfe_dev->irq0_mask;
+	*irq_status1 &= vfe_dev->irq1_mask;
+
+	if (*irq_status1 & (1 << 0)) {
+		vfe_dev->error_info.camif_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x31C);
+		msm_vfe40_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
+	}
+
+	if (*irq_status1 & (1 << 7))
+		vfe_dev->error_info.violation_status |=
+		msm_camera_io_r(vfe_dev->vfe_base + 0x48);
+
+}
+
+static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+}
+
+static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	enum msm_vfe_input_src i;
+	uint32_t shift_irq;
+	uint8_t reg_updated = 0;
+	unsigned long flags;
+
+	if (!(irq_status0 & 0xF0))
+		return;
+	/* Shift status bits so that PIX REG UPDATE is 1st bit */
+	shift_irq = ((irq_status0 & 0xF0) >> 4);
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		if (shift_irq & BIT(i)) {
+			reg_updated |= BIT(i);
+			ISP_DBG("%s REG_UPDATE IRQ %x\n", __func__,
+				(uint32_t)BIT(i));
+			switch (i) {
+			case VFE_PIX_0:
+				msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE,
+					VFE_PIX_0, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_REG_UPD);
+				if (vfe_dev->axi_data.src_info[i].stream_count
+									== 0 &&
+					vfe_dev->axi_data.src_info[i].
+						raw_stream_count == 0 &&
+					vfe_dev->axi_data.src_info[i].active)
+					vfe_dev->hw_info->vfe_ops.core_ops.
+						reg_update(vfe_dev, i);
+				break;
+			case VFE_RAW_0:
+			case VFE_RAW_1:
+			case VFE_RAW_2:
+				msm_isp_increment_frame_id(vfe_dev, i, ts);
+				msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				/*
+				 * Reg Update is pseudo SOF for RDI,
+				 * so request every frame
+				 */
+				vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+					vfe_dev, i);
+				/* reg upd is also epoch for RDI */
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_EPOCH, ts);
+				break;
+			default:
+				pr_err("%s: Error case\n", __func__);
+				return;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	if (reg_updated & BIT(VFE_PIX_0))
+		vfe_dev->reg_updated = 1;
+
+	vfe_dev->reg_update_requested &= ~reg_updated;
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static void msm_vfe40_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	uint32_t update_mask = 0;
+	unsigned long flags;
+
+	/* This HW supports upto VFE_RAW_2 */
+	if (frame_src > VFE_RAW_2 && frame_src != VFE_SRC_MAX) {
+		pr_err("%s Error case\n", __func__);
+		return;
+	}
+
+	/*
+	 * If frame_src == VFE_SRC_MAX request reg_update on all
+	 *  supported INTF
+	 */
+	if (frame_src == VFE_SRC_MAX)
+		update_mask = 0xF;
+	else
+		update_mask = BIT((uint32_t)frame_src);
+	ISP_DBG("%s update_mask %x\n", __func__, update_mask);
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	vfe_dev->axi_data.src_info[VFE_PIX_0].reg_update_frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	vfe_dev->reg_update_requested |= update_mask;
+	vfe_dev->common_data->dual_vfe_res->reg_update_mask[vfe_dev->pdev->id] =
+		vfe_dev->reg_update_requested;
+	if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) &&
+		((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) {
+		if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) {
+			pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__);
+			spin_unlock_irqrestore(&vfe_dev->reg_update_lock,
+				flags);
+			return;
+		}
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+			+ 0x378);
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x378);
+	} else if (!vfe_dev->is_split ||
+		((frame_src == VFE_PIX_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].
+					raw_stream_count == 0)) ||
+		(frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) {
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x378);
+	}
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0xc))
+		return;
+
+	if (irq_status0 & BIT(2)) {
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+		ISP_DBG("%s: EPOCH0 IRQ\n", __func__);
+		msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+					MSM_ISP_COMP_IRQ_EPOCH, ts);
+		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_EPOCH);
+		msm_isp_update_error_frame_count(vfe_dev);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+			stream_count == 0) {
+			ISP_DBG("%s: SOF IRQ\n", __func__);
+			msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+			msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+			vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+				vfe_dev, VFE_PIX_0);
+		}
+	}
+}
+
+static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking_call)
+{
+	long rc = 0;
+
+	init_completion(&vfe_dev->reset_complete);
+
+	if (first_start) {
+		msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0xC);
+	} else {
+		msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC);
+		msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0003FFFF);
+	}
+
+
+	if (blocking_call) {
+		rc = wait_for_completion_timeout(
+			&vfe_dev->reset_complete, msecs_to_jiffies(50));
+	}
+	return rc;
+}
+
+static void msm_vfe40_axi_reload_wm(struct vfe_device *vfe_dev,
+	void __iomem *vfe_base, uint32_t reload_mask)
+{
+	msm_camera_io_w_mb(reload_mask, vfe_base + 0x4C);
+}
+
+static void msm_vfe40_axi_update_cgc_override(struct vfe_device *vfe_dev,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	/* Change CGC override */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x974);
+	if (enable)
+		val |= (1 << wm_idx);
+	else
+		val &= ~(1 << wm_idx);
+	msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x974);
+}
+
+static void msm_vfe40_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	val = msm_camera_io_r(vfe_base + VFE40_WM_BASE(wm_idx));
+	if (enable)
+		val |= 0x1;
+	else
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_base + VFE40_WM_BASE(wm_idx));
+}
+
+static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << (comp_mask_index * 8));
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
+	msm_vfe40_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+			MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+	vfe_dev->irq0_mask &= ~BIT(27);
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
+	msm_vfe40_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0,
+				MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0,
+				MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[vfe_idx][0] + 8));
+	msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)),
+				0, MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	uint32_t i, temp;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		msm_camera_io_w(framedrop_pattern, vfe_base +
+			VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+		temp = msm_camera_io_r(vfe_base +
+			VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+		temp &= 0xFFFFFF83;
+		msm_camera_io_w(temp | (framedrop_period - 1) << 2,
+		vfe_base + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+	}
+
+	msm_camera_io_w_mb(0x1, vfe_base + 0x378);
+}
+
+static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		msm_camera_io_w(0, vfe_dev->vfe_base +
+			VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+}
+
+static int32_t msm_vfe40_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg)
+{
+	int rc = 0;
+
+	switch (bpp) {
+	case 8:
+		*bpp_reg = 0;
+		break;
+	case 10:
+		*bpp_reg = 1 << 0;
+		break;
+	case 12:
+		*bpp_reg = 1 << 1;
+		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int32_t msm_vfe40_convert_io_fmt_to_reg(
+		enum msm_isp_pack_fmt pack_format, uint32_t *pack_reg)
+{
+	int rc = 0;
+
+	switch (pack_format) {
+	case QCOM:
+		*pack_reg = 0x0;
+		break;
+	case MIPI:
+		*pack_reg = 0x1;
+		break;
+	case DPCM6:
+		*pack_reg = 0x2;
+		break;
+	case DPCM8:
+		*pack_reg = 0x3;
+		break;
+	case PLAIN8:
+		*pack_reg = 0x4;
+		break;
+	case PLAIN16:
+		*pack_reg = 0x5;
+		break;
+	default:
+		pr_err("%s: invalid pack fmt %d!\n", __func__, pack_format);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
+{
+	int rc = 0;
+	int bpp = 0, read_bpp = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0, read_pack_fmt = 0;
+	uint32_t bpp_reg = 0, pack_reg = 0;
+	uint32_t read_bpp_reg = 0, read_pack_reg = 0;
+	uint32_t io_format_reg = 0; /*io format register bit*/
+
+	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
+	if ((stream_src < RDI_INTF_0) &&
+	(vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux ==
+		EXTERNAL_READ)) {
+		read_bpp = msm_isp_get_bit_per_pixel(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe40_convert_bpp_to_reg(read_bpp, &read_bpp_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_bpp_to_reg err! in_bpp %d rc %d\n",
+				__func__, read_bpp, rc);
+			return rc;
+		}
+		read_pack_fmt = msm_isp_get_pack_format(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe40_convert_io_fmt_to_reg(
+			read_pack_fmt, &read_pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		/*use input format(v4l2_pix_fmt) to get pack format*/
+		io_format_reg &= 0xFFC8FFFF;
+		io_format_reg |= (read_bpp_reg << 20 | read_pack_reg << 16);
+	}
+
+	bpp = msm_isp_get_bit_per_pixel(io_format);
+	rc = msm_vfe40_convert_bpp_to_reg(bpp, &bpp_reg);
+	if (rc < 0) {
+		pr_err("%s: convert_bpp_to_reg err! bpp %d rc = %d\n",
+				__func__, bpp, rc);
+		return rc;
+	}
+
+	switch (stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case CAMIF_RAW:
+		io_format_reg &= 0xFFFFCFFF;
+		io_format_reg |= bpp_reg << 12;
+		break;
+	case IDEAL_RAW:
+		/*use output format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		rc = msm_vfe40_convert_io_fmt_to_reg(pack_fmt, &pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+					__func__, rc);
+			return rc;
+		}
+		io_format_reg &= 0xFFFFFFC8;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
+		break;
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+	default:
+		pr_err("%s: Invalid stream source\n", __func__);
+		return -EINVAL;
+	}
+	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+	return 0;
+}
+
+static int msm_vfe40_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+	/* There is other option of passing buffer address from user,
+	 *in such case, driver needs to map the buffer and use it
+	 */
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+				vfe_dev->buf_mgr, fe_cfg->session_id,
+				fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+	if (rc < 0) {
+		pr_err("%s: can not map buffer\n", __func__);
+		return -EINVAL;
+	}
+	}
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr, vfe_dev->vfe_base + 0x228);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378);
+
+	msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
+	msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);
+
+	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+	return 0;
+}
+
+static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+	/* There is other option of passing buffer address from user,
+	 * in such case, driver needs to map the buffer and use it
+	 */
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+				vfe_dev->buf_mgr, fe_cfg->session_id,
+				fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+		if (rc < 0) {
+			pr_err("%s: can not map buffer\n", __func__);
+			return -EINVAL;
+		}
+	}
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
+		vfe_dev->vfe_base + 0x228);
+
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378);
+
+	msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
+	msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);
+
+	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+	return 0;
+}
+
+static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t x_size_word;
+	uint32_t temp = 0;
+	uint32_t main_unpack_pattern = 0;
+	struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
+
+	if (pix_cfg->input_mux != EXTERNAL_READ) {
+		pr_err("%s: Invalid mux configuration - mux: %d",
+			__func__, pix_cfg->input_mux);
+		return;
+	}
+
+	fe_cfg = &pix_cfg->fetch_engine_cfg;
+	pr_debug("%s: fetch_dbg wd x ht buf = %d x %d, fe = %d x %d\n",
+			__func__, fe_cfg->buf_width, fe_cfg->buf_height,
+			fe_cfg->fetch_width, fe_cfg->fetch_height);
+
+	vfe_dev->hw_info->vfe_ops.axi_ops.update_cgc_override(vfe_dev,
+		VFE40_BUS_RD_CGC_OVERRIDE_BIT, 1);
+
+	temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+	temp &= 0xFFFFFFFD;
+	temp |= (1 << 1);
+	msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+	msm_vfe40_config_irq(vfe_dev, (1 << 24), 0,
+			MSM_ISP_IRQ_ENABLE);
+
+	msm_camera_io_w((fe_cfg->fetch_height - 1),
+			vfe_dev->vfe_base + 0x238);
+
+	/* need to update to use formulae to calculate X_SIZE_WORD*/
+	x_size_word = msm_isp_cal_word_per_line(
+		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+		fe_cfg->buf_width);
+
+	msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x23C);
+
+	x_size_word = msm_isp_cal_word_per_line(
+		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+		fe_cfg->fetch_width);
+
+	temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	temp |= 2 << 16 | pix_cfg->pixel_pattern;
+	msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C);
+
+	if (vfe_dev->vfe_hw_version == VFE40_8953_VERSION) {
+		msm_camera_io_w(x_size_word  << 17 |
+			(fe_cfg->buf_height-1) << 4 |
+			VFE40_FETCH_BURST_LEN,
+			vfe_dev->vfe_base + 0x240);
+		msm_camera_io_w(0 << 29 | 2 << 26 |
+			(fe_cfg->buf_width - 1)  << 13 |
+			(fe_cfg->buf_height - 1),
+			vfe_dev->vfe_base + 0x244);
+	} else {
+		msm_camera_io_w(x_size_word  << 16 |
+			(fe_cfg->buf_height-1) << 4 |
+			VFE40_FETCH_BURST_LEN,
+			vfe_dev->vfe_base + 0x240);
+		msm_camera_io_w(0 << 28 | 2 << 25 |
+			(fe_cfg->buf_width - 1)  << 12 |
+			(fe_cfg->buf_height - 1),
+			vfe_dev->vfe_base + 0x244);
+	}
+
+	/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
+	switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+		main_unpack_pattern = 0xB210;
+		break;
+	default:
+		main_unpack_pattern = 0xF6543210;
+		break;
+	}
+	msm_camera_io_w(main_unpack_pattern,
+		vfe_dev->vfe_base + 0x248);
+	msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264);
+
+}
+
+static void msm_vfe40_cfg_testgen(struct vfe_device *vfe_dev,
+		struct msm_vfe_testgen_cfg *testgen_cfg)
+{
+	uint32_t bit_per_pixel = 0;
+	uint32_t bpp_reg = 0;
+	uint32_t bayer_pix_pattern_reg = 0;
+	uint32_t unicolorbar_reg = 0;
+	uint32_t unicolor_enb = 0;
+
+	bit_per_pixel = msm_isp_get_bit_per_pixel(
+		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+
+	switch (bit_per_pixel) {
+	case 8:
+		bpp_reg = 0x0;
+		break;
+	case 10:
+		bpp_reg = 0x1;
+		break;
+	case 12:
+		bpp_reg = 0x10;
+		break;
+	case 14:
+		bpp_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid bpp %d\n", __func__, bit_per_pixel);
+		break;
+	}
+
+	msm_camera_io_w(bpp_reg << 16 | testgen_cfg->burst_num_frame,
+		vfe_dev->vfe_base + 0x940);
+
+	msm_camera_io_w(((testgen_cfg->lines_per_frame - 1) << 16) |
+		(testgen_cfg->pixels_per_line - 1), vfe_dev->vfe_base + 0x944);
+
+	msm_camera_io_w(testgen_cfg->h_blank, vfe_dev->vfe_base + 0x958);
+
+	msm_camera_io_w((1 << 16) | testgen_cfg->v_blank,
+		vfe_dev->vfe_base + 0x95C);
+
+	switch (testgen_cfg->pixel_bayer_pattern) {
+	case ISP_BAYER_RGRGRG:
+		bayer_pix_pattern_reg = 0x0;
+		break;
+	case ISP_BAYER_GRGRGR:
+		bayer_pix_pattern_reg = 0x1;
+		break;
+	case ISP_BAYER_BGBGBG:
+		bayer_pix_pattern_reg = 0x10;
+		break;
+	case ISP_BAYER_GBGBGB:
+		bayer_pix_pattern_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid pix pattern %d\n",
+			__func__, bit_per_pixel);
+		break;
+	}
+
+	if (testgen_cfg->color_bar_pattern == COLOR_BAR_8_COLOR) {
+		unicolor_enb = 0x0;
+	} else {
+		unicolor_enb = 0x1;
+		switch (testgen_cfg->color_bar_pattern) {
+		case UNICOLOR_WHITE:
+			unicolorbar_reg = 0x0;
+			break;
+		case UNICOLOR_YELLOW:
+			unicolorbar_reg = 0x1;
+			break;
+		case UNICOLOR_CYAN:
+			unicolorbar_reg = 0x10;
+			break;
+		case UNICOLOR_GREEN:
+			unicolorbar_reg = 0x11;
+			break;
+		case UNICOLOR_MAGENTA:
+			unicolorbar_reg = 0x100;
+			break;
+		case UNICOLOR_RED:
+			unicolorbar_reg = 0x101;
+			break;
+		case UNICOLOR_BLUE:
+			unicolorbar_reg = 0x110;
+			break;
+		case UNICOLOR_BLACK:
+			unicolorbar_reg = 0x111;
+			break;
+		default:
+			pr_err("%s: invalid colorbar %d\n",
+				__func__, testgen_cfg->color_bar_pattern);
+			break;
+		}
+	}
+	msm_camera_io_w((testgen_cfg->rotate_period << 8) |
+	(bayer_pix_pattern_reg << 6) | (unicolor_enb << 4) |
+	(unicolorbar_reg), vfe_dev->vfe_base + 0x968);
+}
+
+static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint16_t first_pixel, last_pixel, first_line, last_line;
+	uint16_t epoch_line1;
+	struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
+	uint32_t val, subsample_period, subsample_pattern;
+	struct msm_vfe_camif_subsample_cfg *subsample_cfg =
+		&pix_cfg->camif_cfg.subsample_cfg;
+	uint16_t bus_sub_en = 0;
+
+	vfe_dev->dual_vfe_enable = camif_cfg->is_split;
+
+	msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern,
+			vfe_dev->vfe_base + 0x1C);
+
+	first_pixel = camif_cfg->first_pixel;
+	last_pixel = camif_cfg->last_pixel;
+	first_line = camif_cfg->first_line;
+	last_line = camif_cfg->last_line;
+	epoch_line1 = camif_cfg->epoch_line1;
+
+	if ((epoch_line1 <= 0) || (epoch_line1 > last_line))
+		epoch_line1 = last_line - 50;
+
+	if ((last_line - epoch_line1) > 100)
+		epoch_line1 = last_line - 100;
+
+	subsample_period = camif_cfg->subsample_cfg.irq_subsample_period;
+	subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern;
+
+	msm_camera_io_w(camif_cfg->lines_per_frame << 16 |
+		camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300);
+
+	msm_camera_io_w(first_pixel << 16 | last_pixel,
+	vfe_dev->vfe_base + 0x304);
+
+	msm_camera_io_w(first_line << 16 | last_line,
+	vfe_dev->vfe_base + 0x308);
+
+	/* configure EPOCH0: 20 lines, and
+	 * configure EPOCH1: epoch_line1 before EOF
+	 */
+	msm_camera_io_w_mb(0x140000 | epoch_line1,
+		vfe_dev->vfe_base + 0x318);
+	pr_debug("%s:%d: epoch_line1: %d\n",
+		__func__, __LINE__, epoch_line1);
+	if (subsample_period && subsample_pattern) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFE0FFFF;
+		val = (subsample_period - 1) << 16;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		ISP_DBG("%s:camif PERIOD %x PATTERN %x\n",
+			__func__,  subsample_period, subsample_pattern);
+
+		val = subsample_pattern;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x314);
+	} else {
+		msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314);
+	}
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8);
+	val |= camif_cfg->camif_input;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8);
+
+	if (subsample_cfg->pixel_skip || subsample_cfg->line_skip) {
+		bus_sub_en = 1;
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFFFFFDF;
+		val = val | bus_sub_en << 5;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		subsample_cfg->pixel_skip &= 0x0000FFFF;
+		subsample_cfg->line_skip  &= 0x0000FFFF;
+		msm_camera_io_w((subsample_cfg->line_skip << 16) |
+			subsample_cfg->pixel_skip,
+			vfe_dev->vfe_base + 0x30C);
+		if (subsample_cfg->first_pixel ||
+			subsample_cfg->last_pixel ||
+			subsample_cfg->first_line ||
+			subsample_cfg->last_line) {
+			msm_camera_io_w(
+			subsample_cfg->first_pixel << 16 |
+				subsample_cfg->last_pixel,
+				vfe_dev->vfe_base + 0x8A4);
+			msm_camera_io_w(
+			subsample_cfg->first_line << 16 |
+				subsample_cfg->last_line,
+				vfe_dev->vfe_base + 0x8A8);
+			val = msm_camera_io_r(
+				vfe_dev->vfe_base + 0x2F8);
+			val |= 1 << 22;
+			msm_camera_io_w(val,
+				vfe_dev->vfe_base + 0x2F8);
+		}
+
+		ISP_DBG("%s:camif raw op fmt %d\n",
+			__func__, subsample_cfg->output_format);
+		/* Pdaf output will be sent in PLAIN16 format*/
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
+		switch (subsample_cfg->output_format) {
+		case CAMIF_PLAIN_8:
+			val |= 4 << 9;
+			break;
+		case CAMIF_PLAIN_16:
+			val |= 5 << 9;
+			break;
+		case CAMIF_MIPI_RAW:
+			val |= 1 << 9;
+			break;
+		case CAMIF_QCOM_RAW:
+		default:
+			break;
+		}
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x54);
+	}
+}
+
+static void msm_vfe40_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t core_cfg = 0;
+	uint32_t val = 0;
+
+	core_cfg =  msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+	core_cfg &= 0xFFFCFFFF;
+
+	switch (pix_cfg->input_mux) {
+	case CAMIF:
+		core_cfg |= 0x0 << 16;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x1C);
+		msm_vfe40_cfg_camif(vfe_dev, pix_cfg);
+		break;
+	case TESTGEN:
+		/* Change CGC override */
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x974);
+		val |= (1 << 31);
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x974);
+
+		/* CAMIF and TESTGEN will both go thorugh CAMIF*/
+		core_cfg |= 0x1 << 16;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x1C);
+		msm_vfe40_cfg_camif(vfe_dev, pix_cfg);
+		msm_vfe40_cfg_testgen(vfe_dev, &pix_cfg->testgen_cfg);
+		break;
+	case EXTERNAL_READ:
+		core_cfg |= 0x2 << 16;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x1C);
+		msm_vfe40_cfg_fetch_engine(vfe_dev, pix_cfg);
+		break;
+	default:
+		pr_err("%s: Unsupported input mux %d\n",
+			__func__, pix_cfg->input_mux);
+		break;
+	}
+}
+
+static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state)
+{
+	uint32_t val;
+	bool bus_en, vfe_en;
+
+	if (update_state == NO_UPDATE)
+		return;
+
+	if (update_state == ENABLE_CAMIF) {
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
+		msm_vfe40_config_irq(vfe_dev, 0xFF, 0x81,
+				MSM_ISP_IRQ_ENABLE);
+
+		bus_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
+		vfe_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFFFFF3F;
+		val = val | bus_en << 7 | vfe_en << 6;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		/* testgen GO*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1, vfe_dev->vfe_base + 0x93C);
+		msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
+	} else if (update_state == DISABLE_CAMIF ||
+		update_state == DISABLE_CAMIF_IMMEDIATELY) {
+		uint32_t poll_val;
+
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			update_state = DISABLE_CAMIF;
+		msm_vfe40_config_irq(vfe_dev, 0, 0x81,
+				MSM_ISP_IRQ_DISABLE);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x464);
+		/* disable danger signal */
+		msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464);
+		msm_camera_io_w_mb((update_state == DISABLE_CAMIF ? 0x0 : 0x6),
+				vfe_dev->vfe_base + 0x2F4);
+		if (readl_poll_timeout_atomic(vfe_dev->vfe_base + 0x31C,
+				poll_val, poll_val & 0x80000000, 1000, 2000000))
+			pr_err("%s: camif disable failed %x\n",
+				__func__, poll_val);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+		/* testgen OFF*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0x93C);
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w((1 << 0), vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+		msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask,
+				vfe_dev->irq1_mask,
+				MSM_ISP_IRQ_SET);
+	}
+}
+
+static void msm_vfe40_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+	rdi_reg_cfg &= ~(BIT(16 + rdi));
+	rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+	msm_camera_io_w(rdi_reg_cfg,
+		vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x70003;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+}
+
+static void msm_vfe40_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	uint32_t val;
+	uint32_t burst_len, wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+
+	if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION ||
+	    vfe_dev->vfe_hw_version == VFE40_8939_VERSION) {
+		burst_len = VFE40_BURST_LEN_8916_VERSION;
+		wm_bit_shift = VFE40_WM_BIT_SHIFT;
+	} else if (vfe_dev->vfe_hw_version == VFE40_8952_VERSION) {
+		burst_len = VFE40_BURST_LEN_8952_VERSION;
+		wm_bit_shift = VFE40_WM_BIT_SHIFT;
+	} else if (vfe_dev->vfe_hw_version == VFE40_8976_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8937_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8917_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8953_VERSION) {
+		burst_len = VFE40_BURST_LEN_8952_VERSION;
+		wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION;
+	} else {
+		burst_len = VFE40_BURST_LEN;
+	}
+
+	if (!stream_info->frame_based) {
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base);
+		/*WR_IMAGE_SIZE*/
+		val =
+			((msm_isp_cal_word_per_line(
+				stream_info->output_format,
+				stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_width)+1)/2 - 1) << 16 |
+				(stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+
+		/*WR_BUFFER_CFG*/
+		val =
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_stride) << 16 |
+			(stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_height - 1) << wm_bit_shift |
+			burst_len;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	} else {
+		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+		val =
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_width) << 16 |
+			(stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_height - 1) << 4 |
+			burst_len;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	}
+
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + wm_base + 0x20);
+	/* TD: Add IRQ subsample pattern */
+}
+
+static void msm_vfe40_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	uint32_t val = 0;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC);
+	/*WR_IMAGE_SIZE*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	/*WR_BUFFER_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20);
+}
+
+static void msm_vfe40_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	struct msm_vfe_axi_plane_cfg *plane_cfg;
+	uint8_t wm;
+	uint32_t xbar_cfg = 0;
+	uint32_t xbar_reg_cfg = 0;
+
+	plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx];
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	switch (stream_info->stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER: {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
+			/*SINGLE_STREAM_SEL*/
+			xbar_cfg |= plane_cfg->output_plane_format << 8;
+		} else {
+			switch (stream_info->output_format) {
+			case V4L2_PIX_FMT_NV12:
+			case V4L2_PIX_FMT_NV14:
+			case V4L2_PIX_FMT_NV16:
+			case V4L2_PIX_FMT_NV24:
+				xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
+				break;
+			}
+			xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
+		}
+		if (stream_info->stream_src == PIX_VIEWFINDER)
+			xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
+		break;
+	}
+	case CAMIF_RAW:
+		xbar_cfg = 0x300;
+		break;
+	case IDEAL_RAW:
+		xbar_cfg = 0x400;
+		break;
+	case RDI_INTF_0:
+		xbar_cfg = 0x500;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0x600;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0x700;
+		break;
+	default:
+		pr_err("%s: Invalid stream src\n", __func__);
+		break;
+	}
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm));
+	xbar_reg_cfg |= (xbar_cfg << VFE40_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE40_XBAR_BASE(wm));
+}
+
+static void msm_vfe40_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint8_t wm;
+	uint32_t xbar_reg_cfg = 0;
+
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE40_XBAR_BASE(wm));
+}
+
+static void msm_vfe40_read_wm_ping_pong_addr(
+	struct vfe_device *vfe_dev)
+{
+	msm_camera_io_dump(vfe_dev->vfe_base +
+		(VFE40_WM_BASE(0) & 0xFFFFFFF0), 0x200, 1);
+}
+
+static void msm_vfe40_update_ping_pong_addr(
+	void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size)
+{
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE40_PING_PONG_BASE(wm_idx, pingpong_bit));
+}
+
+static void msm_vfe40_set_halt_restart_mask(struct vfe_device *vfe_dev)
+{
+	msm_vfe40_config_irq(vfe_dev, BIT(31), BIT(8), MSM_ISP_IRQ_SET);
+}
+
+static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev,
+	uint32_t blocking)
+{
+	int rc = 0;
+	enum msm_vfe_input_src i;
+	struct msm_isp_timestamp ts;
+
+	/* Keep only halt and restart mask */
+	msm_vfe40_config_irq(vfe_dev, (1 << 31), (1 << 8),
+			MSM_ISP_IRQ_SET);
+
+	msm_isp_get_timestamp(&ts, vfe_dev);
+	/* if any stream is waiting for update, signal complete */
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+	}
+
+	msm_isp_stats_stream_update(vfe_dev);
+	msm_isp_stats_stream_update(vfe_dev);
+
+	if (blocking) {
+		init_completion(&vfe_dev->halt_complete);
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
+		rc = wait_for_completion_interruptible_timeout(
+			&vfe_dev->halt_complete, msecs_to_jiffies(500));
+		if (rc <= 0)
+			pr_err("%s:VFE%d halt timeout rc=%d\n", __func__,
+				vfe_dev->pdev->id, rc);
+	} else {
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
+	}
+
+	return rc;
+}
+
+static void msm_vfe40_axi_restart(struct vfe_device *vfe_dev,
+	uint32_t blocking, uint32_t enable_camif)
+{
+	msm_vfe40_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
+			vfe_dev->recovery_irq1_mask,
+			MSM_ISP_IRQ_ENABLE);
+	msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
+
+	/* Start AXI */
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, VFE_SRC_MAX);
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+	if (enable_camif)
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, ENABLE_CAMIF);
+}
+
+static uint32_t msm_vfe40_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 8) & 0x7F;
+}
+
+static uint32_t msm_vfe40_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 25) & 0xF;
+}
+
+static uint32_t msm_vfe40_get_pingpong_status(
+	struct vfe_device *vfe_dev)
+{
+	return msm_camera_io_r(vfe_dev->vfe_base + 0x268);
+}
+
+static int msm_vfe40_get_stats_idx(enum msm_isp_stats_type stats_type)
+{
+	switch (stats_type) {
+	case MSM_ISP_STATS_BE:
+		return 0;
+	case MSM_ISP_STATS_BG:
+		return 1;
+	case MSM_ISP_STATS_BF:
+		return 2;
+	case MSM_ISP_STATS_AWB:
+		return 3;
+	case MSM_ISP_STATS_RS:
+		return 4;
+	case MSM_ISP_STATS_CS:
+		return 5;
+	case MSM_ISP_STATS_IHIST:
+		return 6;
+	case MSM_ISP_STATS_BHIST:
+		return 7;
+	default:
+		pr_err("%s: Invalid stats type\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int msm_vfe40_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	return 0;
+}
+
+static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t request_comp_index, uint8_t enable)
+{
+	uint32_t comp_mask_reg, mask_bf_scale;
+	atomic_t *stats_comp_mask;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask < 1)
+		return;
+
+	if (request_comp_index >= MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__, request_comp_index,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask >
+			MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__,
+			vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	stats_mask = stats_mask & 0xFF;
+	mask_bf_scale = stats_mask;
+
+	stats_comp_mask = &stats_data->stats_comp_mask[request_comp_index];
+	comp_mask_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x44);
+
+	if (enable) {
+		comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
+		atomic_set(stats_comp_mask, stats_mask |
+				atomic_read(stats_comp_mask));
+		msm_vfe40_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_ENABLE);
+	} else {
+		if (!(atomic_read(stats_comp_mask) & stats_mask))
+			return;
+		atomic_set(stats_comp_mask,
+				~stats_mask & atomic_read(stats_comp_mask));
+		comp_mask_reg &= ~(mask_bf_scale <<
+			(16 + request_comp_index * 8));
+		msm_vfe40_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_DISABLE);
+	}
+	msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44);
+
+	ISP_DBG("%s: comp_mask_reg: %x comp mask0 %x mask1: %x\n",
+		__func__, comp_mask_reg,
+		atomic_read(&stats_data->stats_comp_mask[0]),
+		atomic_read(&stats_data->stats_comp_mask[1]));
+
+}
+
+static void msm_vfe40_stats_cfg_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe40_config_irq(vfe_dev,
+		1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16), 0,
+		MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe40_stats_clear_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe40_config_irq(vfe_dev,
+		(1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16)), 0,
+		MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe40_stats_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE40_STATS_BASE(stats_idx);
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
+		vfe_dev->vfe_base + stats_base + 0x8);
+	/*WR_IRQ_FRAMEDROP_PATTERN*/
+	msm_camera_io_w(stream_info->framedrop_pattern,
+		vfe_dev->vfe_base + stats_base + 0x10);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe40_stats_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t val = 0;
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE40_STATS_BASE(stats_idx);
+
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8);
+	/*WR_IRQ_FRAMEDROP_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset;
+	uint32_t stats_burst_len;
+	uint32_t ub_size[VFE40_NUM_STATS_TYPE] = {
+		64, /*MSM_ISP_STATS_BE*/
+		128, /*MSM_ISP_STATS_BG*/
+		128, /*MSM_ISP_STATS_BF*/
+		16, /*MSM_ISP_STATS_AWB*/
+		8,  /*MSM_ISP_STATS_RS*/
+		16, /*MSM_ISP_STATS_CS*/
+		16, /*MSM_ISP_STATS_IHIST*/
+		16, /*MSM_ISP_STATS_BHIST*/
+	};
+
+	if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8939_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8937_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8917_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8953_VERSION) {
+		stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION;
+		ub_offset = VFE40_UB_SIZE_8916;
+	} else if (vfe_dev->vfe_hw_version == VFE40_8952_VERSION ||
+	    vfe_dev->vfe_hw_version == VFE40_8976_VERSION) {
+		stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION;
+		ub_offset = VFE40_UB_SIZE_8952;
+	} else {
+		stats_burst_len = VFE40_STATS_BURST_LEN;
+		ub_offset = VFE40_UB_SIZE;
+	}
+
+	for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(stats_burst_len << 30 |
+			ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC);
+	}
+}
+
+static void msm_vfe40_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, cgc_mask = 0;
+
+	for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_IDX_BE:
+				cgc_mask |= (1 << 8);
+				break;
+			case STATS_IDX_BF:
+				cgc_mask |= (1 << 10);
+				break;
+			case STATS_IDX_BG:
+				cgc_mask |= (1 << 9);
+				break;
+			case STATS_IDX_BHIST:
+				cgc_mask |= (1 << 15);
+				break;
+			case STATS_IDX_AWB:
+				cgc_mask |= (1 << 11);
+				break;
+			case STATS_IDX_RS:
+				cgc_mask |= (1 << 12);
+				break;
+			case STATS_IDX_CS:
+				cgc_mask |= (1 << 13);
+				break;
+			case STATS_IDX_IHIST:
+				cgc_mask |= (1 << 14);
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/* CGC override */
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x974);
+	if (enable)
+		module_cfg |= cgc_mask;
+	else
+		module_cfg &= ~cgc_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x974);
+}
+
+static bool msm_vfe40_is_module_cfg_lock_needed(
+	uint32_t reg_offset)
+{
+	if (reg_offset == 0x18)
+		return true;
+	else
+		return false;
+}
+
+static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, module_cfg_mask = 0;
+	unsigned long flags;
+
+	for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+				module_cfg_mask |= 1 << (5 + i);
+				break;
+			case 6:
+				module_cfg_mask |= 1 << 15;
+				break;
+			case 7:
+				module_cfg_mask |= 1 << 18;
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/*
+	 * For vfe40 stats and other modules share module_cfg register.
+	 * Hence need to Grab lock.
+	 */
+	spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18);
+	if (enable)
+		module_cfg |= module_cfg_mask;
+	else
+		module_cfg &= ~module_cfg_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18);
+	spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
+}
+
+static void msm_vfe40_stats_update_ping_pong_addr(
+	struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
+	uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	int stats_idx;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+}
+
+static uint32_t msm_vfe40_stats_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 16) & 0xFF;
+}
+
+static uint32_t msm_vfe40_stats_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 29) & 0x3;
+}
+
+static uint32_t msm_vfe40_stats_get_frame_id(
+	struct vfe_device *vfe_dev)
+{
+	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+}
+
+static void msm_vfe40_get_error_mask(
+	uint32_t *error_mask0, uint32_t *error_mask1)
+{
+	*error_mask0 = 0x00000000;
+	*error_mask1 = 0x00FFFEFF;
+}
+
+static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask)
+{
+	*overflow_mask = 0x00FFFE7E;
+}
+
+static void msm_vfe40_get_rdi_wm_mask(struct vfe_device *vfe_dev,
+	uint32_t *rdi_wm_mask)
+{
+	*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
+}
+
+static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev,
+	uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+	*irq0_mask = vfe_dev->irq0_mask;
+	*irq1_mask = vfe_dev->irq1_mask;
+}
+
+static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask,
+	uint32_t *irq1_mask)
+{
+	*irq0_mask = BIT(31);
+	*irq1_mask = BIT(8);
+}
+
+static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
+	.num_wm = 7,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 64,
+	.scratch_buf_range = SZ_32M + SZ_4M,
+};
+
+static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF |
+		1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST |
+		1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.num_stats_type = VFE40_NUM_STATS_TYPE,
+	.num_stats_comp_mask = 2,
+};
+
+struct msm_vfe_hardware_info vfe40_hw_info = {
+	.num_iommu_ctx = 1,
+	.num_iommu_secure_ctx = 1,
+	.vfe_clk_idx = VFE40_CLK_IDX,
+	.runtime_axi_update = 0,
+	.min_ab = 12000000,
+	.min_ib = 12000000,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe40_read_and_clear_irq_status,
+			.read_irq_status = msm_vfe40_read_irq_status,
+			.process_camif_irq = msm_vfe40_process_input_irq,
+			.process_reset_irq = msm_vfe40_process_reset_irq,
+			.process_halt_irq = msm_vfe40_process_halt_irq,
+			.process_reg_update = msm_vfe40_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe40_process_epoch_irq,
+			.config_irq = msm_vfe40_config_irq,
+			.preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe40_axi_reload_wm,
+			.enable_wm = msm_vfe40_axi_enable_wm,
+			.cfg_io_format = msm_vfe40_cfg_io_format,
+			.cfg_comp_mask = msm_vfe40_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe40_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe40_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe40_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe40_cfg_framedrop,
+			.clear_framedrop = msm_vfe40_clear_framedrop,
+			.cfg_wm_reg = msm_vfe40_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe40_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.read_wm_ping_pong_addr =
+				msm_vfe40_read_wm_ping_pong_addr,
+			.update_ping_pong_addr =
+				msm_vfe40_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe40_get_comp_mask,
+			.get_wm_mask = msm_vfe40_get_wm_mask,
+			.get_pingpong_status = msm_vfe40_get_pingpong_status,
+			.halt = msm_vfe40_axi_halt,
+			.restart = msm_vfe40_axi_restart,
+			.update_cgc_override =
+				msm_vfe40_axi_update_cgc_override,
+			.ub_reg_offset = msm_vfe40_ub_reg_offset,
+			.get_ub_size = msm_vfe40_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe40_reg_update,
+			.cfg_input_mux = msm_vfe40_cfg_input_mux,
+			.update_camif_state = msm_vfe40_update_camif_state,
+			.start_fetch_eng = msm_vfe40_start_fetch_engine,
+			.cfg_rdi_reg = msm_vfe40_cfg_rdi_reg,
+			.reset_hw = msm_vfe40_reset_hardware,
+			.init_hw = msm_vfe47_init_hardware,
+			.init_hw_reg = msm_vfe40_init_hardware_reg,
+			.clear_status_reg = msm_vfe40_clear_status_reg,
+			.release_hw = msm_vfe47_release_hardware,
+			.get_error_mask = msm_vfe40_get_error_mask,
+			.get_overflow_mask = msm_vfe40_get_overflow_mask,
+			.get_rdi_wm_mask = msm_vfe40_get_rdi_wm_mask,
+			.get_irq_mask = msm_vfe40_get_irq_mask,
+			.get_halt_restart_mask =
+				msm_vfe40_get_halt_restart_mask,
+			.process_error_status = msm_vfe40_process_error_status,
+			.is_module_cfg_lock_needed =
+				msm_vfe40_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = NULL,
+			.start_fetch_eng_multi_pass =
+				msm_vfe40_start_fetch_engine_multi_pass,
+			.set_halt_restart_mask =
+				msm_vfe40_set_halt_restart_mask,
+			.set_bus_err_ign_mask = NULL,
+			.get_bus_err_mask = NULL,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe40_get_stats_idx,
+			.check_streams = msm_vfe40_stats_check_streams,
+			.cfg_comp_mask = msm_vfe40_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe40_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe40_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe40_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe40_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe40_stats_cfg_ub,
+			.enable_module = msm_vfe40_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe40_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe40_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe40_stats_get_wm_mask,
+			.get_frame_id = msm_vfe40_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe40_get_pingpong_status,
+			.update_cgc_override =
+				msm_vfe40_stats_update_cgc_override,
+			.enable_stats_wm = NULL,
+		},
+		.platform_ops = {
+			.get_platform_data = msm_vfe47_get_platform_data,
+			.enable_regulators = msm_vfe47_enable_regulators,
+			.get_regulators = msm_vfe47_get_regulators,
+			.put_regulators = msm_vfe47_put_regulators,
+			.enable_clks = msm_vfe47_enable_clks,
+			.get_clks = msm_vfe47_get_clks,
+			.put_clks = msm_vfe47_put_clks,
+			.get_clk_rates = msm_vfe47_get_clk_rates,
+			.get_max_clk_rate = msm_vfe47_get_max_clk_rate,
+			.set_clk_rate = msm_vfe47_set_clk_rate,
+			.init_bw_mgr = msm_vfe47_init_bandwidth_mgr,
+			.deinit_bw_mgr = msm_vfe47_deinit_bandwidth_mgr,
+			.update_bw = msm_vfe47_update_bandwidth,
+		}
+	},
+	.dmi_reg_offset = 0x918,
+	.axi_hw_info = &msm_vfe40_axi_hw_info,
+	.stats_hw_info = &msm_vfe40_stats_hw_info,
+	.regulator_names = {"vdd"},
+};
+EXPORT_SYMBOL(vfe40_hw_info);
+
+static const struct of_device_id msm_vfe40_dt_match[] = {
+	{
+		.compatible = "qcom,vfe40",
+		.data = &vfe40_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe40_dt_match);
+
+static struct platform_driver vfe40_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe40",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe40_dt_match,
+	},
+};
+
+static int __init msm_vfe40_init_module(void)
+{
+	return platform_driver_register(&vfe40_driver);
+}
+
+static void __exit msm_vfe40_exit_module(void)
+{
+	platform_driver_unregister(&vfe40_driver);
+}
+
+module_init(msm_vfe40_init_module);
+module_exit(msm_vfe40_exit_module);
+MODULE_DESCRIPTION("MSM VFE40 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.h
new file mode 100644
index 0000000..98c7174
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP40_H__
+#define __MSM_ISP40_H__
+
+extern struct msm_vfe_hardware_info vfe40_hw_info;
+#endif /* __MSM_ISP40_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
new file mode 100644
index 0000000..a9ff454
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -0,0 +1,1970 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+
+#include "msm_isp44.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm.h"
+#include "msm_camera_io_util.h"
+#include "msm_isp47.h"
+#include "linux/iopoll.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define STATS_IDX_BF_SCALE  0
+#define STATS_IDX_BE        1
+#define STATS_IDX_BG        2
+#define STATS_IDX_BF        3
+#define STATS_IDX_AWB       4
+#define STATS_IDX_RS        5
+#define STATS_IDX_CS        6
+#define STATS_IDX_IHIST     7
+#define STATS_IDX_BHIST     8
+
+#define VFE44_8084V1_VERSION   0x4000000A
+
+#define VFE44_BURST_LEN 3
+#define VFE44_FETCH_BURST_LEN 3
+#define VFE44_STATS_BURST_LEN 2
+#define VFE44_UB_SIZE 2048
+#define MSM_ISP44_TOTAL_IMAGE_UB 1528
+#define VFE44_WM_BASE(idx) (0x6C + 0x24 * idx)
+#define VFE44_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
+#define VFE44_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
+#define VFE44_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
+#define VFE44_PING_PONG_BASE(wm, ping_pong) \
+	(VFE44_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1)))
+
+#define VFE44_BUS_RD_CGC_OVERRIDE_BIT 16
+
+static uint8_t stats_pingpong_offset_map[] = {
+	7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+#define SHIFT_BF_SCALE_BIT 1
+#define VFE44_NUM_STATS_COMP 2
+#define VFE44_NUM_STATS_TYPE 9
+#define VFE44_STATS_BASE(idx) \
+	((idx) == STATS_IDX_BF_SCALE ? 0xA0C : (0x168 + 0x18 * (idx-1)))
+#define VFE44_STATS_PING_PONG_BASE(idx, ping_pong) \
+	(VFE44_STATS_BASE(idx) + 0x4 * \
+	(~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1))
+
+#define VFE44_CLK_IDX 2
+
+static uint32_t msm_vfe44_ub_reg_offset(struct vfe_device *vfe_dev, int wm_idx)
+{
+	return (VFE44_WM_BASE(wm_idx) + 0x10);
+}
+
+static uint32_t msm_vfe44_get_ub_size(struct vfe_device *vfe_dev)
+{
+	return MSM_ISP44_TOTAL_IMAGE_UB;
+}
+
+static void msm_vfe44_config_irq(struct vfe_device *vfe_dev,
+		uint32_t irq0_mask, uint32_t irq1_mask,
+		enum msm_isp_irq_operation oper)
+{
+	switch (oper) {
+	case MSM_ISP_IRQ_ENABLE:
+		vfe_dev->irq0_mask |= irq0_mask;
+		vfe_dev->irq1_mask |= irq1_mask;
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(irq1_mask, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+		break;
+	case MSM_ISP_IRQ_DISABLE:
+		vfe_dev->irq0_mask &= ~irq0_mask;
+		vfe_dev->irq1_mask &= ~irq1_mask;
+		break;
+	case MSM_ISP_IRQ_SET:
+		vfe_dev->irq0_mask = irq0_mask;
+		vfe_dev->irq1_mask = irq1_mask;
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(irq1_mask, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+		break;
+	}
+	msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C);
+}
+
+static int32_t msm_vfe44_init_dt_parms(struct vfe_device *vfe_dev,
+				struct msm_vfe_hw_init_parms *dt_parms)
+{
+	void __iomem *vfebase = vfe_dev->vfe_base;
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *dt_settings = NULL, *dt_regs = NULL, dt_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, dt_parms->entries,
+		&dt_entries);
+	if (rc < 0 || !dt_entries) {
+		pr_err("%s: NO QOS entries found\n", __func__);
+		return -EINVAL;
+	}
+	dt_settings = kcalloc(dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_settings)
+		return -ENOMEM;
+	dt_regs = kcalloc(dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_regs) {
+		kfree(dt_settings);
+		return -ENOMEM;
+	}
+	rc = of_property_read_u32_array(of_node, dt_parms->regs,
+		dt_regs, dt_entries);
+	if (rc < 0) {
+		pr_err("%s: NO QOS BUS BDG info\n", __func__);
+		kfree(dt_settings);
+		kfree(dt_regs);
+		return -EINVAL;
+	}
+	if (dt_parms->settings) {
+		rc = of_property_read_u32_array(of_node,
+			dt_parms->settings,
+			dt_settings, dt_entries);
+		if (rc < 0) {
+			pr_err("%s: NO QOS settings\n",
+				__func__);
+			kfree(dt_settings);
+			kfree(dt_regs);
+		} else {
+			for (i = 0; i < dt_entries; i++) {
+				msm_camera_io_w(dt_settings[i],
+					vfebase + dt_regs[i]);
+			}
+			kfree(dt_settings);
+			kfree(dt_regs);
+		}
+	} else {
+		kfree(dt_settings);
+		kfree(dt_regs);
+	}
+	return 0;
+}
+
+static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_hw_init_parms qos_parms;
+	struct msm_vfe_hw_init_parms vbif_parms;
+	struct msm_vfe_hw_init_parms ds_parms;
+
+	qos_parms.entries = "qos-entries";
+	qos_parms.regs = "qos-regs";
+	qos_parms.settings = "qos-settings";
+	vbif_parms.entries = "vbif-entries";
+	vbif_parms.regs = "vbif-regs";
+	vbif_parms.settings = "vbif-settings";
+	ds_parms.entries = "ds-entries";
+	ds_parms.regs = "ds-regs";
+	ds_parms.settings = "ds-settings";
+
+	msm_vfe44_init_dt_parms(vfe_dev, &qos_parms);
+	msm_vfe44_init_dt_parms(vfe_dev, &ds_parms);
+	msm_vfe44_init_dt_parms(vfe_dev, &vbif_parms);
+
+	/* BUS_CFG */
+	msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50);
+	msm_vfe44_config_irq(vfe_dev, 0x800000E0, 0xFFFFFF7E,
+			MSM_ISP_IRQ_ENABLE);
+
+}
+
+static void msm_vfe44_clear_status_reg(struct vfe_device *vfe_dev)
+{
+	msm_vfe44_config_irq(vfe_dev, 0x80000000, 0,
+			MSM_ISP_IRQ_SET);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
+	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
+}
+
+static void msm_vfe44_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status0 & (1 << 31)) {
+		complete(&vfe_dev->reset_complete);
+		vfe_dev->reset_pending = 0;
+	}
+}
+
+static void msm_vfe44_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status1 & (1 << 8)) {
+		complete(&vfe_dev->halt_complete);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
+	}
+}
+
+static void msm_vfe44_process_input_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0x1000003))
+		return;
+
+	if (irq_status0 & (1 << 0)) {
+		ISP_DBG("%s: SOF IRQ\n", __func__);
+		msm_isp_increment_frame_id(vfe_dev, VFE_PIX_0, ts);
+	}
+
+	if (irq_status0 & (1 << 24)) {
+		ISP_DBG("%s: Fetch Engine Read IRQ\n", __func__);
+		msm_isp_fetch_engine_done_notify(vfe_dev,
+			&vfe_dev->fetch_engine_info);
+	}
+
+	if (irq_status0 & (1 << 1))
+		ISP_DBG("%s: EOF IRQ\n", __func__);
+}
+
+static void msm_vfe44_process_violation_status(
+	struct vfe_device *vfe_dev)
+{
+	uint32_t violation_status = vfe_dev->error_info.violation_status;
+
+	if (!violation_status)
+		return;
+
+	if (violation_status & (1 << 0))
+		pr_err("%s: camif violation\n", __func__);
+	if (violation_status & (1 << 1))
+		pr_err("%s: black violation\n", __func__);
+	if (violation_status & (1 << 2))
+		pr_err("%s: rolloff violation\n", __func__);
+	if (violation_status & (1 << 3))
+		pr_err("%s: demux violation\n", __func__);
+	if (violation_status & (1 << 4))
+		pr_err("%s: demosaic violation\n", __func__);
+	if (violation_status & (1 << 5))
+		pr_err("%s: wb violation\n", __func__);
+	if (violation_status & (1 << 6))
+		pr_err("%s: clf violation\n", __func__);
+	if (violation_status & (1 << 7))
+		pr_err("%s: color correct violation\n", __func__);
+	if (violation_status & (1 << 8))
+		pr_err("%s: rgb lut violation\n", __func__);
+	if (violation_status & (1 << 9))
+		pr_err("%s: la violation\n", __func__);
+	if (violation_status & (1 << 10))
+		pr_err("%s: chroma enhance violation\n", __func__);
+	if (violation_status & (1 << 11))
+		pr_err("%s: chroma suppress mce violation\n", __func__);
+	if (violation_status & (1 << 12))
+		pr_err("%s: skin enhance violation\n", __func__);
+	if (violation_status & (1 << 13))
+		pr_err("%s: color tranform enc violation\n", __func__);
+	if (violation_status & (1 << 14))
+		pr_err("%s: color tranform view violation\n", __func__);
+	if (violation_status & (1 << 15))
+		pr_err("%s: scale enc y violation\n", __func__);
+	if (violation_status & (1 << 16))
+		pr_err("%s: scale enc cbcr violation\n", __func__);
+	if (violation_status & (1 << 17))
+		pr_err("%s: scale view y violation\n", __func__);
+	if (violation_status & (1 << 18))
+		pr_err("%s: scale view cbcr violation\n", __func__);
+	if (violation_status & (1 << 21))
+		pr_err("%s: crop enc y violation\n", __func__);
+	if (violation_status & (1 << 22))
+		pr_err("%s: crop enc cbcr violation\n", __func__);
+	if (violation_status & (1 << 23))
+		pr_err("%s: crop view y violation\n", __func__);
+	if (violation_status & (1 << 24))
+		pr_err("%s: crop view cbcr violation\n", __func__);
+	if (violation_status & (1 << 25))
+		pr_err("%s: realign buf y violation\n", __func__);
+	if (violation_status & (1 << 26))
+		pr_err("%s: realign buf cb violation\n", __func__);
+	if (violation_status & (1 << 27))
+		pr_err("%s: realign buf cr violation\n", __func__);
+	if (violation_status & (1 << 28))
+		pr_err("%s: ltm violation\n", __func__);
+	if (violation_status & (1 << 29))
+		pr_err("%s: ltm cov violation\n", __func__);
+	if (violation_status & (1 << 30))
+		pr_err("%s: abf violation\n", __func__);
+	if (violation_status & (1 << 31))
+		pr_err("%s: bpc violation\n", __func__);
+}
+
+static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev)
+{
+	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
+
+	if (error_status1 & (1 << 0)) {
+		pr_err("%s: camif error status: 0x%x\n",
+			__func__, vfe_dev->error_info.camif_status);
+		msm_camera_io_dump(vfe_dev->vfe_base + 0x2f4, 0x30, 1);
+	}
+	if (error_status1 & (1 << 1))
+		pr_err("%s: stats bhist overwrite\n", __func__);
+	if (error_status1 & (1 << 2))
+		pr_err("%s: stats cs overwrite\n", __func__);
+	if (error_status1 & (1 << 3))
+		pr_err("%s: stats ihist overwrite\n", __func__);
+	if (error_status1 & (1 << 4))
+		pr_err("%s: realign buf y overflow\n", __func__);
+	if (error_status1 & (1 << 5))
+		pr_err("%s: realign buf cb overflow\n", __func__);
+	if (error_status1 & (1 << 6))
+		pr_err("%s: realign buf cr overflow\n", __func__);
+	if (error_status1 & (1 << 7))
+		msm_vfe44_process_violation_status(vfe_dev);
+	if (error_status1 & (1 << 9)) {
+		vfe_dev->stats->imagemaster0_overflow++;
+		pr_err("%s: image master 0 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 10)) {
+		vfe_dev->stats->imagemaster1_overflow++;
+		pr_err("%s: image master 1 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 11)) {
+		vfe_dev->stats->imagemaster2_overflow++;
+		pr_err("%s: image master 2 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 12)) {
+		vfe_dev->stats->imagemaster3_overflow++;
+		pr_err("%s: image master 3 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 13)) {
+		vfe_dev->stats->imagemaster4_overflow++;
+		pr_err("%s: image master 4 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 14)) {
+		vfe_dev->stats->imagemaster5_overflow++;
+		pr_err("%s: image master 5 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 15)) {
+		vfe_dev->stats->imagemaster6_overflow++;
+		pr_err("%s: image master 6 bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 16)) {
+		vfe_dev->stats->be_overflow++;
+		pr_err("%s: status be bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 17)) {
+		vfe_dev->stats->bg_overflow++;
+		pr_err("%s: status bg bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 18)) {
+		vfe_dev->stats->bf_overflow++;
+		pr_err("%s: status bf bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 19)) {
+		vfe_dev->stats->awb_overflow++;
+		pr_err("%s: status awb bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 20)) {
+		vfe_dev->stats->rs_overflow++;
+		pr_err("%s: status rs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 21)) {
+		vfe_dev->stats->cs_overflow++;
+		pr_err("%s: status cs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 22)) {
+		vfe_dev->stats->ihist_overflow++;
+		pr_err("%s: status ihist bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 23)) {
+		vfe_dev->stats->skinbhist_overflow++;
+		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 24)) {
+		vfe_dev->stats->bfscale_overflow++;
+		pr_err("%s: status bf scale bus overflow\n", __func__);
+	}
+}
+
+static void msm_vfe44_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+
+	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
+	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
+	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+	*irq_status0 &= vfe_dev->irq0_mask;
+	*irq_status1 &= vfe_dev->irq1_mask;
+	if (*irq_status0 & 0x10000000) {
+		pr_err_ratelimited("%s: Protection triggered\n", __func__);
+		*irq_status0 &= ~(0x10000000);
+	}
+
+	if (*irq_status1 & (1 << 0)) {
+		vfe_dev->error_info.camif_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x31C);
+		msm_vfe44_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
+	}
+
+	if (*irq_status1 & (1 << 7))
+		vfe_dev->error_info.violation_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x48);
+
+}
+
+static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
+	 uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+}
+
+static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	enum msm_vfe_input_src i;
+	uint32_t shift_irq;
+	uint8_t reg_updated = 0;
+	unsigned long flags;
+
+	if (!(irq_status0 & 0xF0))
+		return;
+	/* Shift status bits so that PIX SOF is 1st bit */
+	shift_irq = ((irq_status0 & 0xF0) >> 4);
+
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		if (shift_irq & BIT(i)) {
+			reg_updated |= BIT(i);
+			ISP_DBG("%s REG_UPDATE IRQ %x\n", __func__,
+				(uint32_t)BIT(i));
+			switch (i) {
+			case VFE_PIX_0:
+				msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE,
+					VFE_PIX_0, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_REG_UPD);
+				if (vfe_dev->axi_data.src_info[i].stream_count
+									== 0 &&
+					vfe_dev->axi_data.src_info[i].
+						raw_stream_count == 0 &&
+					vfe_dev->axi_data.src_info[i].active)
+					vfe_dev->hw_info->vfe_ops.core_ops.
+						reg_update(vfe_dev, i);
+				break;
+			case VFE_RAW_0:
+			case VFE_RAW_1:
+			case VFE_RAW_2:
+				msm_isp_increment_frame_id(vfe_dev, i, ts);
+				msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				/*
+				 * Reg Update is pseudo SOF for RDI,
+				 * so request every frame
+				 */
+				vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+					vfe_dev, i);
+				/* reg upd is epoch for rdi */
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_EPOCH, ts);
+				break;
+			default:
+				pr_err("%s: Error case\n", __func__);
+				return;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	if (reg_updated & BIT(VFE_PIX_0))
+		vfe_dev->reg_updated = 1;
+
+	vfe_dev->reg_update_requested &= ~reg_updated;
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static void msm_vfe44_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0xc))
+		return;
+
+	if (irq_status0 & BIT(2)) {
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+		ISP_DBG("%s: EPOCH0 IRQ\n", __func__);
+		msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+					MSM_ISP_COMP_IRQ_EPOCH, ts);
+		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_EPOCH);
+		msm_isp_update_error_frame_count(vfe_dev);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+			stream_count == 0) {
+			ISP_DBG("%s: SOF IRQ\n", __func__);
+			msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+			msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+			vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+				   vfe_dev, VFE_PIX_0);
+		}
+	}
+}
+
+static void msm_vfe44_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	uint32_t update_mask = 0;
+	unsigned long flags;
+
+	/* This HW supports upto VFE_RAW_2 */
+	if (frame_src > VFE_RAW_2 && frame_src != VFE_SRC_MAX) {
+		pr_err("%s Error case\n", __func__);
+		return;
+	}
+
+	/*
+	 * If frame_src == VFE_SRC_MAX request reg_update on
+	 * all supported INTF
+	 */
+	if (frame_src == VFE_SRC_MAX)
+		update_mask = 0xF;
+	else
+		update_mask = BIT((uint32_t)frame_src);
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	vfe_dev->axi_data.src_info[VFE_PIX_0].reg_update_frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	vfe_dev->reg_update_requested |= update_mask;
+	vfe_dev->common_data->dual_vfe_res->reg_update_mask[vfe_dev->pdev->id] =
+		vfe_dev->reg_update_requested;
+	if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) &&
+		((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) {
+		if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) {
+			pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__);
+			spin_unlock_irqrestore(&vfe_dev->reg_update_lock,
+				flags);
+			return;
+		}
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+			+ 0x378);
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x378);
+	} else if (!vfe_dev->is_split ||
+		((frame_src == VFE_PIX_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].
+					raw_stream_count == 0)) ||
+		(frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) {
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x378);
+	}
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static long msm_vfe44_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking_call)
+{
+	long rc = 0;
+
+	init_completion(&vfe_dev->reset_complete);
+
+	if (blocking_call)
+		vfe_dev->reset_pending = 1;
+
+	if (first_start) {
+		msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0xC);
+	} else {
+		msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC);
+		msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0031FFFF);
+	}
+
+	if (blocking_call) {
+		rc = wait_for_completion_timeout(
+			&vfe_dev->reset_complete, msecs_to_jiffies(50));
+		if (rc <= 0) {
+			pr_err("%s:%d failed: reset timeout\n", __func__,
+				__LINE__);
+			vfe_dev->reset_pending = 0;
+		}
+	}
+
+	return rc;
+}
+
+static void msm_vfe44_axi_reload_wm(struct vfe_device *vfe_dev,
+	void __iomem *vfe_base, uint32_t reload_mask)
+{
+	msm_camera_io_w_mb(reload_mask, vfe_base + 0x4C);
+}
+
+static void msm_vfe44_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	val = msm_camera_io_r(vfe_base + VFE44_WM_BASE(wm_idx));
+	if (enable)
+		val |= 0x1;
+	else
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_base + VFE44_WM_BASE(wm_idx));
+}
+
+static void msm_vfe44_axi_update_cgc_override(struct vfe_device *vfe_dev,
+	uint8_t wm_idx, uint8_t cgc_override)
+{
+	uint32_t val = 0;
+
+	/* Change CGC override */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x974);
+	if (cgc_override)
+		val |= (1 << wm_idx);
+	else
+		val &= ~(1 << wm_idx);
+	msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x974);
+}
+
+static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
+
+	msm_vfe44_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+			MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
+
+	msm_vfe44_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0,
+			MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0,
+			MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)),
+			0, MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	uint32_t i, temp;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		msm_camera_io_w(framedrop_pattern, vfe_base +
+			VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+		temp = msm_camera_io_r(vfe_base +
+			VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+		temp &= 0xFFFFFF83;
+		msm_camera_io_w(temp | (framedrop_period - 1) << 2,
+			vfe_base +
+			VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+	}
+}
+
+static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		msm_camera_io_w(0, vfe_dev->vfe_base +
+			VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+}
+
+static int32_t msm_vfe44_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg)
+{
+	int rc = 0;
+
+	switch (bpp) {
+	case 8:
+		*bpp_reg = 0;
+		break;
+	case 10:
+		*bpp_reg = 1 << 0;
+		break;
+	case 12:
+		*bpp_reg = 1 << 1;
+		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_vfe44_convert_io_fmt_to_reg(
+	enum msm_isp_pack_fmt pack_format, uint32_t *pack_reg)
+{
+	int rc = 0;
+
+	switch (pack_format) {
+	case QCOM:
+		*pack_reg = 0x0;
+		break;
+	case MIPI:
+		*pack_reg = 0x1;
+		break;
+	case DPCM6:
+		*pack_reg = 0x2;
+		break;
+	case DPCM8:
+		*pack_reg = 0x3;
+		break;
+	case PLAIN8:
+		*pack_reg = 0x4;
+		break;
+	case PLAIN16:
+		*pack_reg = 0x5;
+		break;
+	default:
+		pr_err("%s: invalid pack fmt %d!\n", __func__, pack_format);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_vfe44_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
+{
+	int rc = 0;
+	int bpp = 0, read_bpp = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0, read_pack_fmt = 0;
+	uint32_t bpp_reg = 0, pack_reg = 0;
+	uint32_t read_bpp_reg = 0, read_pack_reg = 0;
+	uint32_t io_format_reg = 0; /*io format register bit*/
+
+	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
+
+	/*input config*/
+	if ((stream_src < RDI_INTF_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux ==
+		EXTERNAL_READ)) {
+		read_bpp = msm_isp_get_bit_per_pixel(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe44_convert_bpp_to_reg(read_bpp, &read_bpp_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_bpp_to_reg err! in_bpp %d rc %d\n",
+				__func__, read_bpp, rc);
+			return rc;
+		}
+
+		read_pack_fmt = msm_isp_get_pack_format(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe44_convert_io_fmt_to_reg(
+			read_pack_fmt, &read_pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		/*use input format(v4l2_pix_fmt) to get pack format*/
+		io_format_reg &= 0xFFC8FFFF;
+		io_format_reg |= (read_bpp_reg << 20 | read_pack_reg << 16);
+	}
+
+	bpp = msm_isp_get_bit_per_pixel(io_format);
+	rc = msm_vfe44_convert_bpp_to_reg(bpp, &bpp_reg);
+	if (rc < 0) {
+		pr_err("%s: convert_bpp_to_reg err! bpp %d rc = %d\n",
+			__func__, bpp, rc);
+		return rc;
+	}
+
+	switch (stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case CAMIF_RAW:
+		io_format_reg &= 0xFFFFCFFF;
+		io_format_reg |= bpp_reg << 12;
+		break;
+	case IDEAL_RAW:
+		/*use output format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		rc = msm_vfe44_convert_io_fmt_to_reg(pack_fmt, &pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		io_format_reg &= 0xFFFFFFC8;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
+		break;
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+	default:
+		pr_err("%s: Invalid stream source\n", __func__);
+		return -EINVAL;
+	}
+
+	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+	return 0;
+}
+
+static int msm_vfe44_fetch_engine_start(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+	/* There is other option of passing buffer address from user,
+	 * in such case, driver needs to map the buffer and use it
+	 */
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+			vfe_dev->buf_mgr, fe_cfg->session_id,
+			fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		if (rc < 0) {
+			pr_err("%s: No fetch buffer\n", __func__);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+		if (rc < 0) {
+			pr_err("%s: can not map buffer\n", __func__);
+			return -EINVAL;
+		}
+	}
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr, vfe_dev->vfe_base + 0x228);
+
+	msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
+	msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);
+
+	ISP_DBG("%s: Fetch Engine ready\n", __func__);
+	return 0;
+}
+
+static void msm_vfe44_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t x_size_word;
+	struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
+	uint32_t temp = 0;
+
+	if (pix_cfg->input_mux == EXTERNAL_READ) {
+		fe_cfg = &pix_cfg->fetch_engine_cfg;
+		pr_debug("%s: fetch_dbg wd x ht buf = %d x %d, fe = %d x %d\n",
+			__func__, fe_cfg->buf_width, fe_cfg->buf_height,
+			fe_cfg->fetch_width, fe_cfg->fetch_height);
+
+		vfe_dev->hw_info->vfe_ops.axi_ops.update_cgc_override(vfe_dev,
+			VFE44_BUS_RD_CGC_OVERRIDE_BIT, 1);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+		temp &= 0xFFFFFFFD;
+		temp |= (1 << 1);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+		msm_vfe44_config_irq(vfe_dev, (1 << 24), 0,
+					MSM_ISP_IRQ_SET);
+		msm_camera_io_w((fe_cfg->fetch_height - 1) & 0xFFF,
+			vfe_dev->vfe_base + 0x238);
+
+		x_size_word = msm_isp_cal_word_per_line(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+			fe_cfg->fetch_width);
+		msm_camera_io_w((x_size_word - 1) << 16,
+			vfe_dev->vfe_base + 0x23C);
+
+		msm_camera_io_w(x_size_word << 16 |
+			(fe_cfg->buf_height - 1) << 4 | VFE44_FETCH_BURST_LEN,
+			vfe_dev->vfe_base + 0x240);
+
+		msm_camera_io_w(0 << 28 | 2 << 25 |
+		((fe_cfg->buf_width - 1) & 0x1FFF) << 12 |
+		((fe_cfg->buf_height - 1) & 0xFFF), vfe_dev->vfe_base + 0x244);
+
+		/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
+		msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x248);
+		msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+		temp |= 2 << 16 | pix_cfg->pixel_pattern;
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C);
+
+	} else {
+		pr_err("%s: Invalid mux configuration - mux: %d", __func__,
+			pix_cfg->input_mux);
+		return;
+	}
+
+}
+
+static void msm_vfe44_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint16_t first_pixel, last_pixel, first_line, last_line;
+	struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
+	uint32_t val, subsample_period, subsample_pattern;
+	struct msm_vfe_camif_subsample_cfg *subsample_cfg =
+		&pix_cfg->camif_cfg.subsample_cfg;
+	uint16_t bus_sub_en = 0;
+
+	vfe_dev->dual_vfe_enable = camif_cfg->is_split;
+
+	msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern,
+		vfe_dev->vfe_base + 0x1C);
+
+	if (subsample_cfg->pixel_skip || subsample_cfg->line_skip) {
+		bus_sub_en = 1;
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFFFFFDF;
+		val = val | bus_sub_en << 5;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		subsample_cfg->pixel_skip &= 0x0000FFFF;
+		subsample_cfg->line_skip  &= 0x0000FFFF;
+		msm_camera_io_w((subsample_cfg->line_skip << 16) |
+			subsample_cfg->pixel_skip,
+			vfe_dev->vfe_base + 0x30C);
+	}
+
+	first_pixel = camif_cfg->first_pixel;
+	last_pixel = camif_cfg->last_pixel;
+	first_line = camif_cfg->first_line;
+	last_line = camif_cfg->last_line;
+	subsample_period = camif_cfg->subsample_cfg.irq_subsample_period;
+	subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern;
+
+	msm_camera_io_w(camif_cfg->lines_per_frame << 16 |
+		camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300);
+
+	msm_camera_io_w(first_pixel << 16 | last_pixel,
+	vfe_dev->vfe_base + 0x304);
+
+	msm_camera_io_w(first_line << 16 | last_line,
+	vfe_dev->vfe_base + 0x308);
+	if (subsample_period && subsample_pattern) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFE0FFFF;
+		val = (subsample_period - 1) << 16;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		ISP_DBG("%s:camif PERIOD %x PATTERN %x\n",
+			__func__,  subsample_period, subsample_pattern);
+
+		val = subsample_pattern;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x314);
+	} else {
+		msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314);
+	}
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8);
+	val |= camif_cfg->camif_input;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8);
+
+}
+
+static void msm_vfe44_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	switch (pix_cfg->input_mux) {
+	case CAMIF:
+		msm_vfe44_cfg_camif(vfe_dev, pix_cfg);
+		break;
+	case EXTERNAL_READ:
+		msm_vfe44_cfg_fetch_engine(vfe_dev, pix_cfg);
+		break;
+	default:
+		pr_err("%s: Unsupported input mux %d\n",
+			__func__, pix_cfg->input_mux);
+	}
+}
+
+static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state)
+{
+	uint32_t val;
+	bool bus_en, vfe_en;
+
+	if (update_state == NO_UPDATE)
+		return;
+
+	if (update_state == ENABLE_CAMIF) {
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
+
+		msm_vfe44_config_irq(vfe_dev, 0xF7, 0x81,
+				MSM_ISP_IRQ_ENABLE);
+		msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
+
+		bus_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
+		vfe_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8);
+		val &= 0xFFFFFF3F;
+		val = val | bus_en << 7 | vfe_en << 6;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+		msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4);
+
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
+	} else if (update_state == DISABLE_CAMIF ||
+		update_state == DISABLE_CAMIF_IMMEDIATELY) {
+		uint32_t poll_val;
+
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			update_state = DISABLE_CAMIF;
+		msm_vfe44_config_irq(vfe_dev, 0,
+			0x81, MSM_ISP_IRQ_DISABLE);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18);
+		/* disable danger signal */
+		msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0xC18);
+		msm_camera_io_w_mb((update_state == DISABLE_CAMIF ? 0x0 : 0x6),
+				vfe_dev->vfe_base + 0x2F4);
+		if (readl_poll_timeout_atomic(vfe_dev->vfe_base + 0x31C,
+				poll_val, poll_val & 0x80000000, 1000, 2000000))
+			pr_err("%s: camif disable failed %x\n",
+				__func__, poll_val);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+		msm_camera_io_w(0, vfe_dev->vfe_base + 0x30);
+		msm_camera_io_w((1 << 0), vfe_dev->vfe_base + 0x34);
+		msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+		msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask,
+			vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+	}
+}
+
+static void msm_vfe44_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE44_RDI_BASE(0));
+	rdi_reg_cfg &= ~(BIT(16 + rdi));
+	rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+	msm_camera_io_w(rdi_reg_cfg,
+		vfe_dev->vfe_base + VFE44_RDI_BASE(0));
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE44_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x70003;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE44_RDI_BASE(rdi));
+}
+
+static void msm_vfe44_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	uint32_t val;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+
+	if (!stream_info->frame_based) {
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base);
+		/*WR_IMAGE_SIZE*/
+		val =
+			((msm_isp_cal_word_per_line(
+				stream_info->output_format,
+				stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_width)+1)/2 - 1) << 16 |
+				(stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+
+		/*WR_BUFFER_CFG*/
+		val = (stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_height - 1);
+		val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3));
+		val = val << 2 |
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_stride) << 16 |
+			VFE44_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	} else {
+		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+		val = (stream_info->plane_cfg[vfe_idx][plane_idx].
+							output_height - 1);
+		val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3));
+		val = val << 2 |
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][
+				plane_idx].output_width) << 16 |
+			VFE44_BURST_LEN;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	}
+
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + wm_base + 0x20);
+	/* TD: Add IRQ subsample pattern */
+}
+
+static void msm_vfe44_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	uint32_t val = 0;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC);
+	/*WR_IMAGE_SIZE*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	/*WR_BUFFER_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20);
+}
+
+static void msm_vfe44_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	struct msm_vfe_axi_plane_cfg *plane_cfg;
+	uint8_t wm;
+	uint32_t xbar_cfg = 0;
+	uint32_t xbar_reg_cfg = 0;
+
+	plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx];
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	switch (stream_info->stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER: {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
+			/*SINGLE_STREAM_SEL*/
+			xbar_cfg |= plane_cfg->output_plane_format << 8;
+		} else {
+			switch (stream_info->output_format) {
+			case V4L2_PIX_FMT_NV12:
+			case V4L2_PIX_FMT_NV14:
+			case V4L2_PIX_FMT_NV16:
+			case V4L2_PIX_FMT_NV24:
+				xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
+				break;
+			}
+			xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
+		}
+		if (stream_info->stream_src == PIX_VIEWFINDER)
+			xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
+		break;
+	}
+	case CAMIF_RAW:
+		xbar_cfg = 0x300;
+		break;
+	case IDEAL_RAW:
+		xbar_cfg = 0x400;
+		break;
+	case RDI_INTF_0:
+		xbar_cfg = 0x500;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0x600;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0x700;
+		break;
+	default:
+		pr_err("%s: Invalid stream src\n", __func__);
+		break;
+	}
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm));
+	xbar_reg_cfg |= (xbar_cfg << VFE44_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE44_XBAR_BASE(wm));
+}
+
+static void msm_vfe44_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint8_t wm;
+	uint32_t xbar_reg_cfg = 0;
+
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE44_XBAR_BASE(wm));
+}
+
+static void msm_vfe44_read_wm_ping_pong_addr(
+	struct vfe_device *vfe_dev)
+{
+	msm_camera_io_dump(vfe_dev->vfe_base +
+		(VFE44_WM_BASE(0) & 0xFFFFFFF0), 0x200, 1);
+}
+
+static void msm_vfe44_update_ping_pong_addr(
+	void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size)
+{
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE44_PING_PONG_BASE(wm_idx, pingpong_bit));
+}
+
+static void msm_vfe44_set_halt_restart_mask(struct vfe_device *vfe_dev)
+{
+	msm_vfe44_config_irq(vfe_dev, BIT(31), BIT(8), MSM_ISP_IRQ_SET);
+}
+
+
+static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev,
+	uint32_t blocking)
+{
+	int rc = 0;
+	enum msm_vfe_input_src i;
+	struct msm_isp_timestamp ts;
+
+	/* Keep only halt and restart mask */
+	msm_vfe44_config_irq(vfe_dev, (1 << 31), (1 << 8),
+			MSM_ISP_IRQ_SET);
+
+	if (atomic_read(&vfe_dev->error_info.overflow_state)
+		== OVERFLOW_DETECTED)
+		pr_err_ratelimited("%s: VFE%d halt for recovery, blocking %d\n",
+			__func__, vfe_dev->pdev->id, blocking);
+
+	if (blocking) {
+		init_completion(&vfe_dev->halt_complete);
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
+		rc = wait_for_completion_timeout(
+			&vfe_dev->halt_complete, msecs_to_jiffies(500));
+		if (rc <= 0)
+			pr_err("%s:VFE%d halt timeout rc=%d\n", __func__,
+				vfe_dev->pdev->id, rc);
+	} else {
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
+	}
+
+	msm_isp_get_timestamp(&ts, vfe_dev);
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		/* if any stream is waiting for update, signal complete */
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+	}
+
+	msm_isp_stats_stream_update(vfe_dev);
+	msm_isp_stats_stream_update(vfe_dev);
+
+	return rc;
+}
+
+static void msm_vfe44_axi_restart(struct vfe_device *vfe_dev,
+	uint32_t blocking, uint32_t enable_camif)
+{
+	msm_vfe44_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
+			vfe_dev->recovery_irq1_mask, MSM_ISP_IRQ_ENABLE);
+	msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
+
+	/* Start AXI */
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, VFE_SRC_MAX);
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+	if (enable_camif)
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, ENABLE_CAMIF);
+}
+
+static uint32_t msm_vfe44_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 8) & 0x7F;
+}
+
+static uint32_t msm_vfe44_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 25) & 0xF;
+}
+
+static uint32_t msm_vfe44_get_pingpong_status(
+	struct vfe_device *vfe_dev)
+{
+	return msm_camera_io_r(vfe_dev->vfe_base + 0x268);
+}
+
+static int msm_vfe44_get_stats_idx(enum msm_isp_stats_type stats_type)
+{
+	switch (stats_type) {
+	case MSM_ISP_STATS_BE:
+		return STATS_IDX_BE;
+	case MSM_ISP_STATS_BG:
+		return STATS_IDX_BG;
+	case MSM_ISP_STATS_BF:
+		return STATS_IDX_BF;
+	case MSM_ISP_STATS_AWB:
+		return STATS_IDX_AWB;
+	case MSM_ISP_STATS_RS:
+		return STATS_IDX_RS;
+	case MSM_ISP_STATS_CS:
+		return STATS_IDX_CS;
+	case MSM_ISP_STATS_IHIST:
+		return STATS_IDX_IHIST;
+	case MSM_ISP_STATS_BHIST:
+		return STATS_IDX_BHIST;
+	case MSM_ISP_STATS_BF_SCALE:
+		return STATS_IDX_BF_SCALE;
+	default:
+		pr_err("%s: Invalid stats type\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int msm_vfe44_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	if (stream_info[STATS_IDX_BF].state ==
+		STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF_SCALE].state !=
+		STATS_AVAILABLE) {
+		pr_err("%s: does not support BF_SCALE while BF is disabled\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF].composite_flag !=
+		stream_info[STATS_IDX_BF_SCALE].composite_flag) {
+		pr_err("%s: Different composite flag for BF and BF_SCALE\n",
+			__func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_vfe44_stats_cfg_comp_mask(
+	struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t request_comp_index, uint8_t enable)
+{
+	uint32_t comp_mask_reg, mask_bf_scale;
+	atomic_t *stats_comp_mask;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask < 1)
+		return;
+
+	if (request_comp_index >= MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__, request_comp_index,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask >
+			MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__,
+			vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	/* BF scale is controlled by BF also so ignore bit 0 of BF scale */
+	stats_mask = stats_mask & 0x1FF;
+	mask_bf_scale = stats_mask >> SHIFT_BF_SCALE_BIT;
+
+	stats_comp_mask = &stats_data->stats_comp_mask[request_comp_index];
+	comp_mask_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x44);
+
+	if (enable) {
+		comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
+		atomic_set(stats_comp_mask, stats_mask |
+				atomic_read(stats_comp_mask));
+		msm_vfe44_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_ENABLE);
+	} else {
+		if (!(atomic_read(stats_comp_mask) & stats_mask))
+			return;
+		if (stats_mask & (1 << STATS_IDX_BF_SCALE) &&
+			atomic_read(stats_comp_mask) &
+				(1 << STATS_IDX_BF_SCALE))
+			atomic_set(stats_comp_mask,
+					~(1 << STATS_IDX_BF_SCALE) &
+					atomic_read(stats_comp_mask));
+
+		atomic_set(stats_comp_mask,
+				~stats_mask & atomic_read(stats_comp_mask));
+		comp_mask_reg &= ~(mask_bf_scale <<
+			(16 + request_comp_index * 8));
+		msm_vfe44_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_DISABLE);
+	}
+	msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44);
+
+	ISP_DBG("%s: comp_mask_reg: %x comp mask0 %x mask1: %x\n",
+		__func__, comp_mask_reg,
+		atomic_read(&stats_data->stats_comp_mask[0]),
+		atomic_read(&stats_data->stats_comp_mask[1]));
+
+}
+
+static void msm_vfe44_stats_cfg_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe44_config_irq(vfe_dev,
+		1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0,
+		MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe44_stats_clear_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe44_config_irq(vfe_dev,
+		(1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15)), 0,
+		MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe44_stats_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE44_STATS_BASE(stats_idx);
+	/* BF_SCALE does not have its own WR_ADDR_CFG,
+	 * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN;
+	 * it's using the same from BF
+	 */
+	if (stats_idx == STATS_IDX_BF_SCALE)
+		return;
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
+		vfe_dev->vfe_base + stats_base + 0x8);
+	/*WR_IRQ_FRAMEDROP_PATTERN*/
+	msm_camera_io_w(stream_info->framedrop_pattern,
+		vfe_dev->vfe_base + stats_base + 0x10);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe44_stats_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t val = 0;
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE44_STATS_BASE(stats_idx);
+	/* BF_SCALE does not have its own WR_ADDR_CFG,
+	 * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN;
+	 * it's using the same from BF
+	 */
+	if (stats_idx == STATS_IDX_BF_SCALE)
+		return;
+
+	/*WR_ADDR_CFG*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8);
+	/*WR_IRQ_FRAMEDROP_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10);
+	/*WR_IRQ_SUBSAMPLE_PATTERN*/
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe44_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = VFE44_UB_SIZE;
+	uint32_t ub_size[VFE44_NUM_STATS_TYPE] = {
+		128, /*MSM_ISP_STATS_BF_SCALE*/
+		64, /*MSM_ISP_STATS_BE*/
+		128, /*MSM_ISP_STATS_BG*/
+		128, /*MSM_ISP_STATS_BF*/
+		16, /*MSM_ISP_STATS_AWB*/
+		8,  /*MSM_ISP_STATS_RS*/
+		16, /*MSM_ISP_STATS_CS*/
+		16, /*MSM_ISP_STATS_IHIST*/
+		16, /*MSM_ISP_STATS_BHIST*/
+	};
+
+	for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(VFE44_STATS_BURST_LEN << 30 |
+			ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE44_STATS_BASE(i) +
+			((i == STATS_IDX_BF_SCALE) ? 0x8 : 0xC));
+	}
+}
+
+static bool msm_vfe44_is_module_cfg_lock_needed(
+	uint32_t reg_offset)
+{
+	if (reg_offset == 0x18)
+		return true;
+	else
+		return false;
+}
+
+static void msm_vfe44_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, module_cfg_mask = 0;
+	uint32_t stats_cfg, stats_cfg_mask = 0;
+	unsigned long flags;
+
+	for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_IDX_BE:
+			case STATS_IDX_BG:
+			case STATS_IDX_BF:
+			case STATS_IDX_AWB:
+			case STATS_IDX_RS:
+			case STATS_IDX_CS:
+				module_cfg_mask |= 1 << (4 + i);
+				break;
+			case STATS_IDX_IHIST:
+				module_cfg_mask |= 1 << 15;
+				break;
+			case STATS_IDX_BHIST:
+				module_cfg_mask |= 1 << 18;
+				break;
+			case STATS_IDX_BF_SCALE:
+				stats_cfg_mask |= 1 << 2;
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/*
+	 * For vfe44 stats and other modules share module_cfg register.
+	 * Hence need to Grab lock.
+	 */
+	spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18);
+	if (enable)
+		module_cfg |= module_cfg_mask;
+	else
+		module_cfg &= ~module_cfg_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18);
+	spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
+
+	stats_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x888);
+	if (enable)
+		stats_cfg |= stats_cfg_mask;
+	else
+		stats_cfg &= ~stats_cfg_mask;
+	msm_camera_io_w(stats_cfg, vfe_dev->vfe_base + 0x888);
+}
+
+static void msm_vfe44_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t cgc_override)
+{
+	int i;
+	uint32_t val = 0, cgc_mask = 0;
+
+	for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_IDX_BE:
+				cgc_mask |= (1 << 8);
+				break;
+			case STATS_IDX_BG:
+				cgc_mask |= (1 << 9);
+				break;
+			case STATS_IDX_BF:
+				cgc_mask |= (1 << 10);
+				break;
+			case STATS_IDX_AWB:
+				cgc_mask |= (1 << 11);
+				break;
+			case STATS_IDX_RS:
+				cgc_mask |= (1 << 12);
+				break;
+			case STATS_IDX_CS:
+				cgc_mask |= (1 << 13);
+				break;
+			case STATS_IDX_IHIST:
+				cgc_mask |= (1 << 14);
+				break;
+			case STATS_IDX_BHIST:
+				cgc_mask |= (1 << 15);
+				break;
+			case STATS_IDX_BF_SCALE:
+				cgc_mask |= (1 << 10);
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/* CGC override */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x974);
+	if (cgc_override)
+		val |= cgc_mask;
+	else
+		val &= ~cgc_mask;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x974);
+}
+
+static void msm_vfe44_stats_update_ping_pong_addr(
+	struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
+	uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	int stats_idx;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+}
+
+static uint32_t msm_vfe44_stats_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 15) & 0x1FF;
+}
+
+static uint32_t msm_vfe44_stats_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 29) & 0x3;
+}
+
+static uint32_t msm_vfe44_stats_get_frame_id(
+	struct vfe_device *vfe_dev)
+{
+	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+}
+
+static void msm_vfe44_get_error_mask(
+	uint32_t *error_mask0, uint32_t *error_mask1)
+{
+	*error_mask0 = 0x00000000;
+	*error_mask1 = 0x01FFFEFF;
+}
+
+static void msm_vfe44_get_overflow_mask(uint32_t *overflow_mask)
+{
+	*overflow_mask = 0x00FFFE7E;
+}
+
+static void msm_vfe44_get_rdi_wm_mask(struct vfe_device *vfe_dev,
+	uint32_t *rdi_wm_mask)
+{
+	*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
+}
+
+static void msm_vfe44_get_irq_mask(struct vfe_device *vfe_dev,
+	uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+	*irq0_mask = vfe_dev->irq0_mask;
+	*irq1_mask = vfe_dev->irq1_mask;
+}
+
+static void msm_vfe44_get_halt_restart_mask(uint32_t *irq0_mask,
+	uint32_t *irq1_mask)
+{
+	*irq0_mask = BIT(31);
+	*irq1_mask = BIT(8);
+}
+
+static struct msm_vfe_axi_hardware_info msm_vfe44_axi_hw_info = {
+	.num_wm = 6,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 96,
+	.scratch_buf_range = SZ_32M + SZ_4M,
+};
+
+static struct msm_vfe_stats_hardware_info msm_vfe44_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF |
+		1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST |
+		1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS |
+		1 << MSM_ISP_STATS_BF_SCALE,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.num_stats_type = VFE44_NUM_STATS_TYPE,
+	.num_stats_comp_mask = VFE44_NUM_STATS_COMP,
+};
+
+struct msm_vfe_hardware_info vfe44_hw_info = {
+	.num_iommu_ctx = 1,
+	.num_iommu_secure_ctx = 1,
+	.vfe_clk_idx = VFE44_CLK_IDX,
+	.runtime_axi_update = 0,
+	.min_ab = 100000000,
+	.min_ib = 100000000,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe44_read_and_clear_irq_status,
+			.read_irq_status = msm_vfe44_read_irq_status,
+			.process_camif_irq = msm_vfe44_process_input_irq,
+			.process_reset_irq = msm_vfe44_process_reset_irq,
+			.process_halt_irq = msm_vfe44_process_halt_irq,
+			.process_reg_update = msm_vfe44_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe44_process_epoch_irq,
+			.config_irq = msm_vfe44_config_irq,
+			.preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe44_axi_reload_wm,
+			.enable_wm = msm_vfe44_axi_enable_wm,
+			.cfg_io_format = msm_vfe44_cfg_io_format,
+			.cfg_comp_mask = msm_vfe44_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe44_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe44_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe44_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe44_cfg_framedrop,
+			.clear_framedrop = msm_vfe44_clear_framedrop,
+			.cfg_wm_reg = msm_vfe44_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe44_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe44_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe44_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.read_wm_ping_pong_addr =
+				msm_vfe44_read_wm_ping_pong_addr,
+			.update_ping_pong_addr =
+				msm_vfe44_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe44_get_comp_mask,
+			.get_wm_mask = msm_vfe44_get_wm_mask,
+			.get_pingpong_status = msm_vfe44_get_pingpong_status,
+			.halt = msm_vfe44_axi_halt,
+			.restart = msm_vfe44_axi_restart,
+			.update_cgc_override =
+				msm_vfe44_axi_update_cgc_override,
+			.ub_reg_offset = msm_vfe44_ub_reg_offset,
+			.get_ub_size = msm_vfe44_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe44_reg_update,
+			.cfg_input_mux = msm_vfe44_cfg_input_mux,
+			.update_camif_state = msm_vfe44_update_camif_state,
+			.start_fetch_eng = msm_vfe44_fetch_engine_start,
+			.cfg_rdi_reg = msm_vfe44_cfg_rdi_reg,
+			.reset_hw = msm_vfe44_reset_hardware,
+			.init_hw = msm_vfe47_init_hardware,
+			.init_hw_reg = msm_vfe44_init_hardware_reg,
+			.clear_status_reg = msm_vfe44_clear_status_reg,
+			.release_hw = msm_vfe47_release_hardware,
+			.get_error_mask = msm_vfe44_get_error_mask,
+			.get_overflow_mask = msm_vfe44_get_overflow_mask,
+			.get_rdi_wm_mask = msm_vfe44_get_rdi_wm_mask,
+			.get_irq_mask = msm_vfe44_get_irq_mask,
+			.get_halt_restart_mask =
+				msm_vfe44_get_halt_restart_mask,
+			.process_error_status = msm_vfe44_process_error_status,
+			.is_module_cfg_lock_needed =
+				msm_vfe44_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = NULL,
+			.set_halt_restart_mask =
+				msm_vfe44_set_halt_restart_mask,
+			.set_bus_err_ign_mask = NULL,
+			.get_bus_err_mask = NULL,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe44_get_stats_idx,
+			.check_streams = msm_vfe44_stats_check_streams,
+			.cfg_comp_mask = msm_vfe44_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe44_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe44_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe44_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe44_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe44_stats_cfg_ub,
+			.enable_module = msm_vfe44_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe44_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe44_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe44_stats_get_wm_mask,
+			.get_frame_id = msm_vfe44_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe44_get_pingpong_status,
+			.update_cgc_override =
+				msm_vfe44_stats_update_cgc_override,
+			.enable_stats_wm = NULL,
+		},
+		.platform_ops = {
+			.get_platform_data = msm_vfe47_get_platform_data,
+			.enable_regulators = msm_vfe47_enable_regulators,
+			.get_regulators = msm_vfe47_get_regulators,
+			.put_regulators = msm_vfe47_put_regulators,
+			.enable_clks = msm_vfe47_enable_clks,
+			.get_clks = msm_vfe47_get_clks,
+			.put_clks = msm_vfe47_put_clks,
+			.get_clk_rates = msm_vfe47_get_clk_rates,
+			.get_max_clk_rate = msm_vfe47_get_max_clk_rate,
+			.set_clk_rate = msm_vfe47_set_clk_rate,
+			.init_bw_mgr = msm_vfe47_init_bandwidth_mgr,
+			.deinit_bw_mgr = msm_vfe47_deinit_bandwidth_mgr,
+			.update_bw = msm_vfe47_update_bandwidth,
+		}
+	},
+	.dmi_reg_offset = 0x918,
+	.axi_hw_info = &msm_vfe44_axi_hw_info,
+	.stats_hw_info = &msm_vfe44_stats_hw_info,
+	.regulator_names = {"vdd"},
+};
+EXPORT_SYMBOL(vfe44_hw_info);
+
+static const struct of_device_id msm_vfe44_dt_match[] = {
+	{
+		.compatible = "qcom,vfe44",
+		.data = &vfe44_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe44_dt_match);
+
+static struct platform_driver vfe44_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe44",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe44_dt_match,
+	},
+};
+
+static int __init msm_vfe44_init_module(void)
+{
+	return platform_driver_register(&vfe44_driver);
+}
+
+static void __exit msm_vfe44_exit_module(void)
+{
+	platform_driver_unregister(&vfe44_driver);
+}
+
+module_init(msm_vfe44_init_module);
+module_exit(msm_vfe44_exit_module);
+MODULE_DESCRIPTION("MSM VFE44 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.h
new file mode 100644
index 0000000..274674b
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP44_H__
+#define __MSM_ISP44_H__
+
+extern struct msm_vfe_hardware_info vfe44_hw_info;
+#endif /* __MSM_ISP44_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
new file mode 100644
index 0000000..0239fe7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -0,0 +1,2039 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+
+#include "msm_isp46.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm.h"
+#include "msm_camera_io_util.h"
+#include "msm_isp47.h"
+#include "linux/iopoll.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define STATS_IDX_BF_SCALE  0
+#define STATS_IDX_HDR_BE    1
+#define STATS_IDX_BG        2
+#define STATS_IDX_BF        3
+#define STATS_IDX_HDR_BHIST 4
+#define STATS_IDX_RS        5
+#define STATS_IDX_CS        6
+#define STATS_IDX_IHIST     7
+#define STATS_IDX_BHIST     8
+
+#define VFE46_8994V1_VERSION   0x60000000
+
+#define VFE46_BURST_LEN 3
+#define VFE46_FETCH_BURST_LEN 3
+#define VFE46_STATS_BURST_LEN 3
+#define VFE46_UB_SIZE_VFE0 2048
+#define VFE46_UB_SIZE_VFE1 1536
+#define VFE46_UB_STATS_SIZE 144
+#define MSM_ISP46_TOTAL_IMAGE_UB_VFE0 (VFE46_UB_SIZE_VFE0 - VFE46_UB_STATS_SIZE)
+#define MSM_ISP46_TOTAL_IMAGE_UB_VFE1 (VFE46_UB_SIZE_VFE1 - VFE46_UB_STATS_SIZE)
+#define VFE46_WM_BASE(idx) (0xA0 + 0x24 * idx)
+#define VFE46_RDI_BASE(idx) (0x39C + 0x4 * idx)
+#define VFE46_XBAR_BASE(idx) (0x90 + 0x4 * (idx / 2))
+#define VFE46_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
+#define VFE46_PING_PONG_BASE(wm, ping_pong) \
+	(VFE46_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1)))
+#define SHIFT_BF_SCALE_BIT 1
+#define VFE46_NUM_STATS_COMP 2
+#define VFE46_BUS_RD_CGC_OVERRIDE_BIT 16
+
+static uint32_t stats_base_addr[] = {
+	0x1E4, /* BF_SCALE */
+	0x19C, /* HDR_BE */
+	0x1F0, /* BG */
+	0x1CC, /* BF */
+	0x1B4, /* HDR_BHIST */
+	0x220, /* RS */
+	0x238, /* CS */
+	0x250, /* IHIST */
+	0x208, /* BHIST (SKIN_BHIST) */
+};
+
+static uint8_t stats_pingpong_offset_map[] = {
+	11, /* BF_SCALE */
+	 8, /* HDR_BE */
+	12, /* BG */
+	10, /* BF */
+	 9, /* HDR_BHIST */
+	14, /* RS */
+	15, /* CS */
+	16, /* IHIST */
+	13, /* BHIST (SKIN_BHIST) */
+};
+
+#define VFE46_NUM_STATS_TYPE 9
+#define VFE46_STATS_BASE(idx) (stats_base_addr[idx])
+#define VFE46_STATS_PING_PONG_BASE(idx, ping_pong) \
+	(VFE46_STATS_BASE(idx) + 0x4 * \
+	(~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1))
+
+#define VFE46_CLK_IDX 2
+
+static uint32_t msm_vfe46_ub_reg_offset(struct vfe_device *vfe_dev, int wm_idx)
+{
+	return (VFE46_WM_BASE(wm_idx) + 0x10);
+}
+
+static uint32_t msm_vfe46_get_ub_size(struct vfe_device *vfe_dev)
+{
+	if (vfe_dev->pdev->id == ISP_VFE0)
+		return MSM_ISP46_TOTAL_IMAGE_UB_VFE0;
+	return MSM_ISP46_TOTAL_IMAGE_UB_VFE1;
+}
+
+static void msm_vfe46_config_irq(struct vfe_device *vfe_dev,
+		uint32_t irq0_mask, uint32_t irq1_mask,
+		enum msm_isp_irq_operation oper)
+{
+	switch (oper) {
+	case MSM_ISP_IRQ_ENABLE:
+		vfe_dev->irq0_mask |= irq0_mask;
+		vfe_dev->irq1_mask |= irq1_mask;
+		msm_camera_io_w(irq0_mask, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+		break;
+	case MSM_ISP_IRQ_DISABLE:
+		vfe_dev->irq0_mask &= ~irq0_mask;
+		vfe_dev->irq1_mask &= ~irq1_mask;
+		break;
+	case MSM_ISP_IRQ_SET:
+		vfe_dev->irq0_mask = irq0_mask;
+		vfe_dev->irq1_mask = irq1_mask;
+		msm_camera_io_w(irq1_mask, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+		break;
+	}
+	msm_camera_io_w_mb(vfe_dev->irq0_mask,
+				vfe_dev->vfe_base + 0x5C);
+	msm_camera_io_w_mb(vfe_dev->irq1_mask,
+				vfe_dev->vfe_base + 0x60);
+}
+
+static int32_t msm_vfe46_init_dt_parms(struct vfe_device *vfe_dev,
+	struct msm_vfe_hw_init_parms *dt_parms, void __iomem *dev_mem_base)
+{
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *dt_settings = NULL, *dt_regs = NULL, num_dt_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, dt_parms->entries,
+		&num_dt_entries);
+	if (rc < 0 || !num_dt_entries) {
+		pr_err("%s: NO QOS entries found\n", __func__);
+		return -EINVAL;
+	}
+	dt_settings = kcalloc(num_dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_settings)
+		return -ENOMEM;
+	dt_regs = kcalloc(num_dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_regs) {
+		kfree(dt_settings);
+		return -ENOMEM;
+	}
+	rc = of_property_read_u32_array(of_node, dt_parms->regs,
+		dt_regs, num_dt_entries);
+	if (rc < 0) {
+		pr_err("%s: NO QOS BUS BDG info\n", __func__);
+		kfree(dt_settings);
+		kfree(dt_regs);
+		return -EINVAL;
+	}
+	if (dt_parms->settings) {
+		rc = of_property_read_u32_array(of_node,
+			dt_parms->settings,
+			dt_settings, num_dt_entries);
+		if (rc < 0) {
+			pr_err("%s: NO QOS settings\n",
+				__func__);
+			kfree(dt_settings);
+			kfree(dt_regs);
+		} else {
+			for (i = 0; i < num_dt_entries; i++) {
+				msm_camera_io_w(dt_settings[i],
+					dev_mem_base +
+					dt_regs[i]);
+			}
+			kfree(dt_settings);
+			kfree(dt_regs);
+		}
+	} else {
+		kfree(dt_settings);
+		kfree(dt_regs);
+	}
+	return 0;
+}
+
+static void msm_vfe46_init_hardware_reg(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_hw_init_parms qos_parms;
+	struct msm_vfe_hw_init_parms vbif_parms;
+	struct msm_vfe_hw_init_parms ds_parms;
+
+	memset(&qos_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+	memset(&vbif_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+	memset(&ds_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+
+	qos_parms.entries = "qos-entries";
+	qos_parms.regs = "qos-regs";
+	qos_parms.settings = "qos-settings";
+	vbif_parms.entries = "vbif-entries";
+	vbif_parms.regs = "vbif-regs";
+	vbif_parms.settings = "vbif-settings";
+	ds_parms.entries = "ds-entries";
+	ds_parms.regs = "ds-regs";
+	ds_parms.settings = "ds-settings";
+
+	msm_vfe46_init_dt_parms(vfe_dev, &qos_parms, vfe_dev->vfe_base);
+	msm_vfe46_init_dt_parms(vfe_dev, &ds_parms, vfe_dev->vfe_base);
+	msm_vfe46_init_dt_parms(vfe_dev, &vbif_parms, vfe_dev->vfe_vbif_base);
+
+	/* BUS_CFG */
+	msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x84);
+	/* IRQ_MASK/CLEAR */
+	msm_vfe46_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E,
+			MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe46_clear_status_reg(struct vfe_device *vfe_dev)
+{
+	msm_vfe46_config_irq(vfe_dev, 0x80000000, 0, MSM_ISP_IRQ_SET);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
+	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+}
+
+static void msm_vfe46_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status0 & (1 << 31)) {
+		complete(&vfe_dev->reset_complete);
+		vfe_dev->reset_pending = 0;
+	}
+}
+
+static void msm_vfe46_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	if (irq_status1 & (1 << 8)) {
+		complete(&vfe_dev->halt_complete);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x374);
+	}
+}
+
+static void msm_vfe46_process_input_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0x1000003))
+		return;
+
+	if (irq_status0 & (1 << 24)) {
+		ISP_DBG("%s: Fetch Engine Read IRQ\n", __func__);
+		msm_isp_fetch_engine_done_notify(vfe_dev,
+			&vfe_dev->fetch_engine_info);
+	}
+
+	if (irq_status0 & (1 << 0)) {
+		ISP_DBG("%s: SOF IRQ\n", __func__);
+		msm_isp_increment_frame_id(vfe_dev, VFE_PIX_0, ts);
+	}
+
+	if (irq_status0 & (1 << 1))
+		ISP_DBG("%s: EOF IRQ\n", __func__);
+}
+
+static void msm_vfe46_process_violation_status(
+	struct vfe_device *vfe_dev)
+{
+	uint32_t violation_status = vfe_dev->error_info.violation_status;
+
+	if (violation_status > 39) {
+		pr_err("%s: invalid violation status %d\n",
+			__func__, violation_status);
+		return;
+	}
+
+	pr_err("%s: VFE pipeline violation status %d\n", __func__,
+		violation_status);
+}
+
+static void msm_vfe46_process_error_status(struct vfe_device *vfe_dev)
+{
+	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
+
+	if (error_status1 & (1 << 0)) {
+		pr_err("%s: camif error status: 0x%x\n",
+			__func__, vfe_dev->error_info.camif_status);
+		msm_camera_io_dump(vfe_dev->vfe_base + 0x3A8, 0x30, 1);
+	}
+	if (error_status1 & (1 << 1))
+		pr_err("%s: stats bhist overwrite\n", __func__);
+	if (error_status1 & (1 << 2))
+		pr_err("%s: stats cs overwrite\n", __func__);
+	if (error_status1 & (1 << 3))
+		pr_err("%s: stats ihist overwrite\n", __func__);
+	if (error_status1 & (1 << 4))
+		pr_err("%s: realign buf y overflow\n", __func__);
+	if (error_status1 & (1 << 5))
+		pr_err("%s: realign buf cb overflow\n", __func__);
+	if (error_status1 & (1 << 6))
+		pr_err("%s: realign buf cr overflow\n", __func__);
+	if (error_status1 & (1 << 7))
+		msm_vfe46_process_violation_status(vfe_dev);
+	if (error_status1 & (1 << 9))
+		pr_err("%s: image master 0 bus overflow\n", __func__);
+	if (error_status1 & (1 << 10))
+		pr_err("%s: image master 1 bus overflow\n", __func__);
+	if (error_status1 & (1 << 11))
+		pr_err("%s: image master 2 bus overflow\n", __func__);
+	if (error_status1 & (1 << 12))
+		pr_err("%s: image master 3 bus overflow\n", __func__);
+	if (error_status1 & (1 << 13))
+		pr_err("%s: image master 4 bus overflow\n", __func__);
+	if (error_status1 & (1 << 14))
+		pr_err("%s: image master 5 bus overflow\n", __func__);
+	if (error_status1 & (1 << 15))
+		pr_err("%s: image master 6 bus overflow\n", __func__);
+	if (error_status1 & (1 << 16))
+		pr_err("%s: status hdr be bus overflow\n", __func__);
+	if (error_status1 & (1 << 17))
+		pr_err("%s: status bg bus overflow\n", __func__);
+	if (error_status1 & (1 << 18))
+		pr_err("%s: status bf bus overflow\n", __func__);
+	if (error_status1 & (1 << 19))
+		pr_err("%s: status hdr bhist bus overflow\n", __func__);
+	if (error_status1 & (1 << 20))
+		pr_err("%s: status rs bus overflow\n", __func__);
+	if (error_status1 & (1 << 21))
+		pr_err("%s: status cs bus overflow\n", __func__);
+	if (error_status1 & (1 << 22))
+		pr_err("%s: status ihist bus overflow\n", __func__);
+	if (error_status1 & (1 << 23))
+		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	if (error_status1 & (1 << 24))
+		pr_err("%s: status bf scale bus overflow\n", __func__);
+}
+
+static void msm_vfe46_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
+	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x64);
+	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x68);
+	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x58);
+
+	*irq_status0 &= vfe_dev->irq0_mask;
+	*irq_status1 &= vfe_dev->irq1_mask;
+
+	if (*irq_status1 & (1 << 0)) {
+		vfe_dev->error_info.camif_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x3D0);
+		msm_vfe46_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
+	}
+
+	if (*irq_status1 & (1 << 7))
+		vfe_dev->error_info.violation_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x7C);
+
+}
+
+static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
+}
+
+static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	enum msm_vfe_input_src i;
+	uint32_t shift_irq;
+	uint8_t reg_updated = 0;
+	unsigned long flags;
+
+	if (!(irq_status0 & 0xF0))
+		return;
+	/* Shift status bits so that PIX REG UPDATE is 1st bit */
+	shift_irq = ((irq_status0 & 0xF0) >> 4);
+
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		if (shift_irq & BIT(i)) {
+			reg_updated |= BIT(i);
+			ISP_DBG("%s Reg Update IRQ %x\n", __func__,
+				(uint32_t)BIT(i));
+
+			switch (i) {
+			case VFE_PIX_0:
+				msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE,
+					VFE_PIX_0, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_REG_UPD);
+				msm_isp_stats_stream_update(vfe_dev);
+				if (vfe_dev->axi_data.src_info[i].stream_count
+									== 0 &&
+					vfe_dev->axi_data.src_info[i].active)
+					vfe_dev->hw_info->vfe_ops.core_ops.
+							reg_update(vfe_dev, i);
+				break;
+			case VFE_RAW_0:
+			case VFE_RAW_1:
+			case VFE_RAW_2:
+				msm_isp_increment_frame_id(vfe_dev, i, ts);
+				msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				/*
+				 * Reg Update is pseudo SOF for RDI,
+				 * so request every frame
+				 */
+				vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+					vfe_dev, i);
+				/* reg upd is also epoch for rdi */
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_EPOCH, ts);
+				break;
+			default:
+				pr_err("%s: Error case\n", __func__);
+				return;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	if (reg_updated & BIT(VFE_PIX_0))
+		vfe_dev->reg_updated = 1;
+
+	vfe_dev->reg_update_requested &= ~reg_updated;
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static void msm_vfe46_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0xc))
+		return;
+
+	if (irq_status0 & BIT(2)) {
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+		ISP_DBG("%s: EPOCH0 IRQ\n", __func__);
+		msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+			MSM_ISP_COMP_IRQ_EPOCH, ts);
+		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_EPOCH);
+		msm_isp_update_error_frame_count(vfe_dev);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+			stream_count == 0) {
+			msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+				MSM_ISP_COMP_IRQ_REG_UPD, ts);
+			vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+				vfe_dev, VFE_PIX_0);
+		}
+	}
+}
+
+static void msm_vfe46_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	uint32_t update_mask = 0;
+	unsigned long flags;
+
+	/* This HW supports upto VFE_RAW_2 */
+	if (frame_src > VFE_RAW_2 && frame_src != VFE_SRC_MAX) {
+		pr_err("%s Error case\n", __func__);
+		return;
+	}
+
+	/*
+	 * If frame_src == VFE_SRC_MAX request reg_update on all
+	 *  supported INTF
+	 */
+	if (frame_src == VFE_SRC_MAX)
+		update_mask = 0xF;
+	else
+		update_mask = BIT((uint32_t)frame_src);
+	ISP_DBG("%s update_mask %x\n", __func__, update_mask);
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	vfe_dev->axi_data.src_info[VFE_PIX_0].reg_update_frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	vfe_dev->reg_update_requested |= update_mask;
+	vfe_dev->common_data->dual_vfe_res->reg_update_mask[vfe_dev->pdev->id] =
+		vfe_dev->reg_update_requested;
+	if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) &&
+		((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) {
+		if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) {
+			pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__);
+			spin_unlock_irqrestore(&vfe_dev->reg_update_lock,
+				flags);
+			return;
+		}
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+			+ 0x3D8);
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x3D8);
+	} else if (!vfe_dev->is_split ||
+		((frame_src == VFE_PIX_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].
+				raw_stream_count == 0)) ||
+		(frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) {
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x3D8);
+	}
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+static long msm_vfe46_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking_call)
+{
+	long rc = 0;
+
+	init_completion(&vfe_dev->reset_complete);
+
+	if (blocking_call)
+		vfe_dev->reset_pending = 1;
+
+	if (first_start) {
+		msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0x18);
+	} else {
+		msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0x18);
+		msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w(0xFFFFFEFF, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58);
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0031FFFF);
+	}
+
+	if (blocking_call) {
+		rc = wait_for_completion_timeout(
+			&vfe_dev->reset_complete, msecs_to_jiffies(50));
+		if (rc <= 0) {
+			pr_err("%s:%d failed: reset timeout\n", __func__,
+				__LINE__);
+			vfe_dev->reset_pending = 0;
+		}
+	}
+
+	return rc;
+}
+
+static void msm_vfe46_axi_reload_wm(struct vfe_device *vfe_dev,
+	void __iomem *vfe_base, uint32_t reload_mask)
+{
+	msm_camera_io_w_mb(reload_mask, vfe_base + 0x80);
+}
+
+static void msm_vfe46_axi_update_cgc_override(struct vfe_device *vfe_dev,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	/* Change CGC override */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+	if (enable)
+		val |= (1 << wm_idx);
+	else
+		val &= ~(1 << wm_idx);
+	msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x3C);
+}
+
+static void msm_vfe46_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	val = msm_camera_io_r(vfe_base + VFE46_WM_BASE(wm_idx));
+	if (enable)
+		val |= 0x1;
+	else
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_base + VFE46_WM_BASE(wm_idx));
+}
+
+static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
+
+	msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+				MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
+
+	msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+				MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe46_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0,
+				MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe46_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)),
+				0, MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe46_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period)
+{
+	uint32_t i, temp;
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		msm_camera_io_w(framedrop_pattern, vfe_base +
+			VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+		temp = msm_camera_io_r(vfe_base +
+			VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+		temp &= 0xFFFFFF83;
+		msm_camera_io_w(temp | (framedrop_period - 1) << 2,
+		vfe_base + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC);
+	}
+}
+
+static void msm_vfe46_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		msm_camera_io_w(0, vfe_dev->vfe_base +
+			VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C);
+}
+
+static int32_t msm_vfe46_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg)
+{
+	int rc = 0;
+
+	switch (bpp) {
+	case 8:
+		*bpp_reg = 0;
+		break;
+	case 10:
+		*bpp_reg = 0x1;
+		break;
+	case 12:
+		*bpp_reg = 0x2;
+		break;
+	case 14:
+		*bpp_reg = 0x3;
+		break;
+	default:
+		pr_err("%s:%d invalid bpp %d\n", __func__, __LINE__, bpp);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_vfe46_convert_io_fmt_to_reg(
+	enum msm_isp_pack_fmt pack_format, uint32_t *pack_reg)
+{
+	int rc = 0;
+
+	switch (pack_format) {
+	case QCOM:
+		*pack_reg = 0x0;
+		break;
+	case MIPI:
+		*pack_reg = 0x1;
+		break;
+	case DPCM6:
+		*pack_reg = 0x2;
+		break;
+	case DPCM8:
+		*pack_reg = 0x3;
+		break;
+	case PLAIN8:
+		*pack_reg = 0x4;
+		break;
+	case PLAIN16:
+		*pack_reg = 0x5;
+		break;
+	default:
+		pr_err("%s: invalid pack fmt %d!\n", __func__, pack_format);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+static int32_t msm_vfe46_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
+{
+	int rc = 0;
+	int bpp = 0, read_bpp = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0, read_pack_fmt = 0;
+	uint32_t bpp_reg = 0, pack_reg = 0;
+	uint32_t read_bpp_reg = 0, read_pack_reg = 0;
+	uint32_t io_format_reg = 0; /*io format register bit*/
+
+	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x88);
+
+	/*input config*/
+	if ((stream_src < RDI_INTF_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux ==
+		EXTERNAL_READ)) {
+		read_bpp = msm_isp_get_bit_per_pixel(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe46_convert_bpp_to_reg(read_bpp, &read_bpp_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_bpp_to_reg err! in_bpp %d rc %d\n",
+				__func__, read_bpp, rc);
+			return rc;
+	}
+
+		read_pack_fmt = msm_isp_get_pack_format(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe46_convert_io_fmt_to_reg(
+			read_pack_fmt, &read_pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		/*use input format(v4l2_pix_fmt) to get pack format*/
+		io_format_reg &= 0xFFC8FFFF;
+		io_format_reg |= (read_bpp_reg << 20 | read_pack_reg << 16);
+	}
+
+	bpp = msm_isp_get_bit_per_pixel(io_format);
+	rc = msm_vfe46_convert_bpp_to_reg(bpp, &bpp_reg);
+	if (rc < 0) {
+		pr_err("%s: convert_bpp_to_reg err! bpp %d rc = %d\n",
+			__func__, bpp, rc);
+		return rc;
+	}
+
+	switch (stream_src) {
+	case PIX_VIDEO:
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case CAMIF_RAW:
+		io_format_reg &= 0xFFFFCFFF;
+		io_format_reg |= bpp_reg << 12;
+		break;
+	case IDEAL_RAW:
+		/*use output format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		rc = msm_vfe46_convert_io_fmt_to_reg(pack_fmt, &pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		io_format_reg &= 0xFFFFFFC8;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
+		break;
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+	default:
+		pr_err("%s: Invalid stream source\n", __func__);
+		return -EINVAL;
+	}
+	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x88);
+	return 0;
+}
+
+static int msm_vfe46_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+	/* There is other option of passing buffer address from user,
+	 * in such case, driver needs to map the buffer and use it
+	 */
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+			vfe_dev->buf_mgr, fe_cfg->session_id,
+			fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+		if (rc < 0) {
+			pr_err("%s: can not map buffer\n", __func__);
+			return -EINVAL;
+		}
+	}
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr, vfe_dev->vfe_base + 0x268);
+
+	msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
+	msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);
+
+	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+	return 0;
+}
+
+static void msm_vfe46_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t x_size_word, temp;
+	struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
+
+	if (pix_cfg->input_mux == EXTERNAL_READ) {
+		fe_cfg = &pix_cfg->fetch_engine_cfg;
+		pr_debug("%s:VFE%d wd x ht buf = %d x %d, fe = %d x %d\n",
+			__func__, vfe_dev->pdev->id, fe_cfg->buf_width,
+			fe_cfg->buf_height,
+			fe_cfg->fetch_width, fe_cfg->fetch_height);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x84);
+		temp &= 0xFFFFFFFD;
+		temp |= (1 << 1);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84);
+
+		msm_vfe46_config_irq(vfe_dev, 1 << 24, 0,
+					MSM_ISP_IRQ_ENABLE);
+
+		temp = fe_cfg->fetch_height - 1;
+		msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x278);
+
+		x_size_word = msm_isp_cal_word_per_line(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+			fe_cfg->fetch_width);
+		msm_camera_io_w((x_size_word - 1) << 16,
+			vfe_dev->vfe_base + 0x27C);
+
+		msm_camera_io_w(x_size_word << 16 |
+			(temp & 0x3FFF) << 2 | VFE46_FETCH_BURST_LEN,
+			vfe_dev->vfe_base + 0x280);
+
+		temp = ((fe_cfg->buf_width - 1) & 0x3FFF) << 16 |
+			((fe_cfg->buf_height - 1) & 0x3FFF);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x284);
+
+		/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
+		msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x288);
+		msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x2A4);
+
+		vfe_dev->hw_info->vfe_ops.axi_ops.update_cgc_override(vfe_dev,
+			VFE46_BUS_RD_CGC_OVERRIDE_BIT, 1);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+		temp |= 2 << 5;
+		temp |= 128 << 8;
+		temp |= pix_cfg->pixel_pattern;
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+	} else {
+		pr_err("%s: Invalid mux configuration - mux: %d", __func__,
+			pix_cfg->input_mux);
+	}
+}
+
+static void msm_vfe46_cfg_testgen(struct vfe_device *vfe_dev,
+	struct msm_vfe_testgen_cfg *testgen_cfg)
+{
+	uint32_t temp;
+	uint32_t bit_per_pixel = 0;
+	uint32_t bpp_reg = 0;
+	uint32_t bayer_pix_pattern_reg = 0;
+	uint32_t unicolorbar_reg = 0;
+	uint32_t unicolor_enb = 0;
+
+	bit_per_pixel = msm_isp_get_bit_per_pixel(
+		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+
+	switch (bit_per_pixel) {
+	case 8:
+		bpp_reg = 0x0;
+		break;
+	case 10:
+		bpp_reg = 0x1;
+		break;
+	case 12:
+		bpp_reg = 0x10;
+		break;
+	case 14:
+		bpp_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid bpp %d\n", __func__, bit_per_pixel);
+		break;
+	}
+
+	msm_camera_io_w(bpp_reg << 16 | testgen_cfg->burst_num_frame,
+		vfe_dev->vfe_base + 0xAF8);
+
+	msm_camera_io_w(((testgen_cfg->lines_per_frame - 1) << 16) |
+		(testgen_cfg->pixels_per_line - 1), vfe_dev->vfe_base + 0xAFC);
+
+	temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+	temp |= (((testgen_cfg->h_blank) & 0x3FFF) << 8);
+	temp |= (1 << 24);
+	msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+	msm_camera_io_w((1 << 16) | testgen_cfg->v_blank,
+		vfe_dev->vfe_base + 0xB0C);
+
+	switch (testgen_cfg->pixel_bayer_pattern) {
+	case ISP_BAYER_RGRGRG:
+		bayer_pix_pattern_reg = 0x0;
+		break;
+	case ISP_BAYER_GRGRGR:
+		bayer_pix_pattern_reg = 0x1;
+		break;
+	case ISP_BAYER_BGBGBG:
+		bayer_pix_pattern_reg = 0x10;
+		break;
+	case ISP_BAYER_GBGBGB:
+		bayer_pix_pattern_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid pix pattern %d\n",
+			__func__, bit_per_pixel);
+		break;
+	}
+
+	if (testgen_cfg->color_bar_pattern == COLOR_BAR_8_COLOR) {
+		unicolor_enb = 0x0;
+	} else {
+		unicolor_enb = 0x1;
+		switch (testgen_cfg->color_bar_pattern) {
+		case UNICOLOR_WHITE:
+			unicolorbar_reg = 0x0;
+			break;
+		case UNICOLOR_YELLOW:
+			unicolorbar_reg = 0x1;
+			break;
+		case UNICOLOR_CYAN:
+			unicolorbar_reg = 0x10;
+			break;
+		case UNICOLOR_GREEN:
+			unicolorbar_reg = 0x11;
+			break;
+		case UNICOLOR_MAGENTA:
+			unicolorbar_reg = 0x100;
+			break;
+		case UNICOLOR_RED:
+			unicolorbar_reg = 0x101;
+			break;
+		case UNICOLOR_BLUE:
+			unicolorbar_reg = 0x110;
+			break;
+		case UNICOLOR_BLACK:
+			unicolorbar_reg = 0x111;
+			break;
+		default:
+			pr_err("%s: invalid colorbar %d\n",
+				__func__, testgen_cfg->color_bar_pattern);
+			break;
+		}
+	}
+
+	msm_camera_io_w((testgen_cfg->rotate_period << 8) |
+		(bayer_pix_pattern_reg << 6) | (unicolor_enb << 4) |
+		(unicolorbar_reg), vfe_dev->vfe_base + 0xB14);
+}
+
+static void msm_vfe46_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint16_t first_pixel, last_pixel, first_line, last_line;
+	struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
+	uint32_t val, subsample_period, subsample_pattern;
+	struct msm_vfe_camif_subsample_cfg *subsample_cfg =
+		&pix_cfg->camif_cfg.subsample_cfg;
+	uint16_t bus_sub_en = 0;
+
+	if (subsample_cfg->pixel_skip || subsample_cfg->line_skip)
+		bus_sub_en = 1;
+	else
+		bus_sub_en = 0;
+
+	vfe_dev->dual_vfe_enable = camif_cfg->is_split;
+
+	msm_camera_io_w(pix_cfg->input_mux << 5 | pix_cfg->pixel_pattern,
+		vfe_dev->vfe_base + 0x50);
+
+	first_pixel = camif_cfg->first_pixel;
+	last_pixel = camif_cfg->last_pixel;
+	first_line = camif_cfg->first_line;
+	last_line = camif_cfg->last_line;
+	subsample_period = camif_cfg->subsample_cfg.irq_subsample_period;
+	subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern;
+
+	if (bus_sub_en) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x3AC);
+		val &= 0xFFFFFFDF;
+		val = val | bus_sub_en << 5;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3AC);
+		subsample_cfg->pixel_skip &= 0x0000FFFF;
+		subsample_cfg->line_skip  &= 0x0000FFFF;
+		msm_camera_io_w((subsample_cfg->line_skip << 16) |
+			subsample_cfg->pixel_skip, vfe_dev->vfe_base + 0x3C0);
+	}
+
+	msm_camera_io_w(camif_cfg->lines_per_frame << 16 |
+		camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x3B4);
+
+	msm_camera_io_w(first_pixel << 16 | last_pixel,
+	vfe_dev->vfe_base + 0x3B8);
+
+	msm_camera_io_w(first_line << 16 | last_line,
+	vfe_dev->vfe_base + 0x3BC);
+
+	if (subsample_period && subsample_pattern) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x3AC);
+		val &= 0xFFE0FFFF;
+		val = (subsample_period - 1) << 16;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3AC);
+		ISP_DBG("%s:camif PERIOD %x PATTERN %x\n",
+			__func__,  subsample_period, subsample_pattern);
+
+		val = subsample_pattern;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3C8);
+	} else {
+		msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x3C8);
+	}
+
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x39C);
+	val |= camif_cfg->camif_input;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x39C);
+}
+
+static void msm_vfe46_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t core_cfg = 0;
+	uint32_t val = 0;
+
+	core_cfg =  msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+	core_cfg &= 0xFFFFFF9F;
+
+	switch (pix_cfg->input_mux) {
+	case CAMIF:
+		core_cfg |= 0x0 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe46_cfg_camif(vfe_dev, pix_cfg);
+		break;
+	case TESTGEN:
+		/* Change CGC override */
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+		val |= (1 << 31);
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3C);
+
+		/* CAMIF and TESTGEN will both go thorugh CAMIF*/
+		core_cfg |= 0x1 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe46_cfg_camif(vfe_dev, pix_cfg);
+		msm_vfe46_cfg_testgen(vfe_dev, &pix_cfg->testgen_cfg);
+		break;
+	case EXTERNAL_READ:
+		core_cfg |= 0x2 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe46_cfg_fetch_engine(vfe_dev, pix_cfg);
+		break;
+	default:
+		pr_err("%s: Unsupported input mux %d\n",
+			__func__, pix_cfg->input_mux);
+		break;
+	}
+}
+
+static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state)
+{
+	uint32_t val;
+	bool bus_en, vfe_en;
+
+	if (update_state == NO_UPDATE)
+		return;
+
+	if (update_state == ENABLE_CAMIF) {
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w(0x81, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58);
+		msm_vfe46_config_irq(vfe_dev, 0x15, 0x81,
+					MSM_ISP_IRQ_ENABLE);
+
+		bus_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
+		vfe_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x3AC);
+		val &= 0xFFFFFF3F;
+		val = val | bus_en << 7 | vfe_en << 6;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3AC);
+		msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x3A8);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x3A8);
+		/* configure EPOCH0 for 20 lines */
+		msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x3CC);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
+		/* testgen GO*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1, vfe_dev->vfe_base + 0xAF4);
+	} else if (update_state == DISABLE_CAMIF ||
+		update_state == DISABLE_CAMIF_IMMEDIATELY) {
+		uint32_t poll_val;
+
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			update_state = DISABLE_CAMIF;
+		msm_vfe46_config_irq(vfe_dev, 0, 0x81,
+				MSM_ISP_IRQ_DISABLE);
+		/* disable danger signal */
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18);
+		val &= ~(1 << 8);
+		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0xC18);
+		msm_camera_io_w_mb((update_state == DISABLE_CAMIF ? 0x0 : 0x6),
+				vfe_dev->vfe_base + 0x3A8);
+		if (readl_poll_timeout_atomic(vfe_dev->vfe_base + 0x3D0,
+			poll_val, poll_val & 0x80000000, 1000, 2000000))
+			pr_err("%s: camif disable failed %x\n",
+				__func__, poll_val);
+		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+		/* testgen OFF*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0xAF4);
+	}
+}
+
+static void msm_vfe46_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE46_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x03;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE46_RDI_BASE(rdi));
+}
+
+static void msm_vfe46_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	uint32_t val;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+
+	val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0xC);
+	val &= ~0x2;
+	if (stream_info->frame_based)
+		val |= 0x2;
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC);
+	if (!stream_info->frame_based) {
+		/* WR_IMAGE_SIZE */
+		val =
+			((msm_isp_cal_word_per_line(
+				stream_info->output_format,
+				stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_width)+3)/4 - 1) << 16 |
+				(stream_info->plane_cfg[vfe_idx][plane_idx].
+				output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+		/* WR_BUFFER_CFG */
+		val = VFE46_BURST_LEN |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+						output_height - 1) <<
+			2 |
+			((msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_stride)+1)/2) << 16;
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	}
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + wm_base + 0x20);
+	/* TD: Add IRQ subsample pattern */
+}
+
+static void msm_vfe46_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	uint32_t val = 0;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+
+	/* WR_ADDR_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC);
+	/* WR_IMAGE_SIZE */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	/* WR_BUFFER_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20);
+}
+
+static void msm_vfe46_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	struct msm_vfe_axi_plane_cfg *plane_cfg;
+	uint8_t wm;
+	uint32_t xbar_cfg = 0;
+	uint32_t xbar_reg_cfg = 0;
+
+	plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx];
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	switch (stream_info->stream_src) {
+	case PIX_VIDEO:
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER: {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
+			/* SINGLE_STREAM_SEL */
+			xbar_cfg |= plane_cfg->output_plane_format << 8;
+		} else {
+			switch (stream_info->output_format) {
+			case V4L2_PIX_FMT_NV12:
+			case V4L2_PIX_FMT_NV14:
+			case V4L2_PIX_FMT_NV16:
+			case V4L2_PIX_FMT_NV24:
+				/* PAIR_STREAM_SWAP_CTRL */
+				xbar_cfg |= 0x3 << 4;
+				break;
+			}
+			xbar_cfg |= 0x1 << 2; /* PAIR_STREAM_EN */
+		}
+		if (stream_info->stream_src == PIX_VIEWFINDER)
+			xbar_cfg |= 0x1; /* VIEW_STREAM_EN */
+		else if (stream_info->stream_src == PIX_VIDEO)
+			xbar_cfg |= 0x2;
+		break;
+	}
+	case CAMIF_RAW:
+		xbar_cfg = 0x300;
+		break;
+	case IDEAL_RAW:
+		xbar_cfg = 0x400;
+		break;
+	case RDI_INTF_0:
+		xbar_cfg = 0xC00;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0xD00;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0xE00;
+		break;
+	default:
+		pr_err("%s: Invalid stream src\n", __func__);
+		break;
+	}
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE46_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE46_XBAR_SHIFT(wm));
+	xbar_reg_cfg |= (xbar_cfg << VFE46_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE46_XBAR_BASE(wm));
+}
+
+static void msm_vfe46_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint8_t wm;
+	uint32_t xbar_reg_cfg = 0;
+
+	wm = stream_info->wm[vfe_idx][plane_idx];
+
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE46_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE46_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE46_XBAR_BASE(wm));
+}
+
+static void msm_vfe46_read_wm_ping_pong_addr(
+	struct vfe_device *vfe_dev)
+{
+	msm_camera_io_dump(vfe_dev->vfe_base +
+		(VFE46_WM_BASE(0) & 0xFFFFFFF0), 0x200, 1);
+}
+
+static void msm_vfe46_update_ping_pong_addr(
+	void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size)
+{
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE46_PING_PONG_BASE(wm_idx, pingpong_bit));
+}
+
+static void msm_vfe46_set_halt_restart_mask(struct vfe_device *vfe_dev)
+{
+	msm_vfe46_config_irq(vfe_dev, BIT(31), BIT(8), MSM_ISP_IRQ_SET);
+}
+
+static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev,
+	uint32_t blocking)
+{
+	int rc = 0;
+	enum msm_vfe_input_src i;
+	struct msm_isp_timestamp ts;
+
+	/* Keep only halt and restart mask */
+	msm_vfe46_config_irq(vfe_dev, (1 << 31), (1 << 8),
+			MSM_ISP_IRQ_SET);
+
+	if (atomic_read(&vfe_dev->error_info.overflow_state)
+		== OVERFLOW_DETECTED)
+		pr_err_ratelimited("%s: VFE%d halt for recovery, blocking %d\n",
+			__func__, vfe_dev->pdev->id, blocking);
+
+	if (blocking) {
+		init_completion(&vfe_dev->halt_complete);
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x374);
+		rc = wait_for_completion_timeout(
+			&vfe_dev->halt_complete, msecs_to_jiffies(500));
+		if (rc <= 0)
+			pr_err("%s:VFE%d halt timeout rc=%d\n", __func__,
+				vfe_dev->pdev->id, rc);
+	} else {
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x374);
+	}
+
+	msm_isp_get_timestamp(&ts, vfe_dev);
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+	}
+
+	msm_isp_stats_stream_update(vfe_dev);
+	msm_isp_stats_stream_update(vfe_dev);
+
+	return rc;
+}
+
+static void msm_vfe46_axi_restart(struct vfe_device *vfe_dev,
+	uint32_t blocking, uint32_t enable_camif)
+{
+	msm_vfe46_config_irq(vfe_dev, vfe_dev->recovery_irq0_mask,
+			vfe_dev->recovery_irq1_mask,
+			MSM_ISP_IRQ_ENABLE);
+	msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x3CC);
+
+	/* Start AXI */
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x374);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, VFE_SRC_MAX);
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+	if (enable_camif)
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, ENABLE_CAMIF);
+}
+
+static uint32_t msm_vfe46_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 8) & 0x7F;
+}
+
+static uint32_t msm_vfe46_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 25) & 0xF;
+}
+
+static uint32_t msm_vfe46_get_pingpong_status(
+	struct vfe_device *vfe_dev)
+{
+	return msm_camera_io_r(vfe_dev->vfe_base + 0x2A8);
+}
+
+static int msm_vfe46_get_stats_idx(enum msm_isp_stats_type stats_type)
+{
+	switch (stats_type) {
+	case MSM_ISP_STATS_HDR_BE:
+		return STATS_IDX_HDR_BE;
+	case MSM_ISP_STATS_BG:
+		return STATS_IDX_BG;
+	case MSM_ISP_STATS_BF:
+		return STATS_IDX_BF;
+	case MSM_ISP_STATS_HDR_BHIST:
+		return STATS_IDX_HDR_BHIST;
+	case MSM_ISP_STATS_RS:
+		return STATS_IDX_RS;
+	case MSM_ISP_STATS_CS:
+		return STATS_IDX_CS;
+	case MSM_ISP_STATS_IHIST:
+		return STATS_IDX_IHIST;
+	case MSM_ISP_STATS_BHIST:
+		return STATS_IDX_BHIST;
+	case MSM_ISP_STATS_BF_SCALE:
+		return STATS_IDX_BF_SCALE;
+	default:
+		pr_err("%s: Invalid stats type\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int msm_vfe46_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	if (stream_info[STATS_IDX_BF].state ==
+		STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF_SCALE].state !=
+		STATS_AVAILABLE) {
+		pr_err("%s: does not support BF_SCALE while BF is disabled\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE &&
+		stream_info[STATS_IDX_BF].composite_flag !=
+		stream_info[STATS_IDX_BF_SCALE].composite_flag) {
+		pr_err("%s: Different composite flag for BF and BF_SCALE\n",
+			__func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_vfe46_stats_cfg_comp_mask(
+	struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t request_comp_index, uint8_t enable)
+{
+	uint32_t comp_mask_reg, mask_bf_scale;
+	atomic_t *stats_comp_mask;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask < 1)
+		return;
+
+	if (request_comp_index >= MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__, request_comp_index,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask >
+			MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__,
+			vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	/* BF scale is controlled by BF also so ignore bit 0 of BF scale */
+	stats_mask = stats_mask & 0x1FF;
+	mask_bf_scale = stats_mask >> SHIFT_BF_SCALE_BIT;
+
+	stats_comp_mask = &stats_data->stats_comp_mask[request_comp_index];
+	comp_mask_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x78);
+
+	if (enable) {
+		comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
+		atomic_set(stats_comp_mask, stats_mask |
+				atomic_read(stats_comp_mask));
+		msm_vfe46_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_ENABLE);
+	} else {
+		if (!(atomic_read(stats_comp_mask) & stats_mask))
+			return;
+		if (stats_mask & (1 << STATS_IDX_BF_SCALE) &&
+			atomic_read(stats_comp_mask) &
+				(1 << STATS_IDX_BF_SCALE))
+			atomic_set(stats_comp_mask,
+					~(1 << STATS_IDX_BF_SCALE) &
+					atomic_read(stats_comp_mask));
+
+		atomic_set(stats_comp_mask,
+				~stats_mask & atomic_read(stats_comp_mask));
+		comp_mask_reg &= ~(mask_bf_scale <<
+			(16 + request_comp_index * 8));
+		msm_vfe46_config_irq(vfe_dev,
+			1 << (request_comp_index + 29), 0,
+			MSM_ISP_IRQ_DISABLE);
+	}
+	msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78);
+
+	ISP_DBG("%s: comp_mask_reg: %x comp mask0 %x mask1: %x\n",
+		__func__, comp_mask_reg,
+		atomic_read(&stats_data->stats_comp_mask[0]),
+		atomic_read(&stats_data->stats_comp_mask[1]));
+
+}
+
+static void msm_vfe46_stats_cfg_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe46_config_irq(vfe_dev,
+		1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0,
+		MSM_ISP_IRQ_ENABLE);
+}
+
+static void msm_vfe46_stats_clear_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	msm_vfe46_config_irq(vfe_dev,
+		1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0,
+		MSM_ISP_IRQ_DISABLE);
+}
+
+static void msm_vfe46_stats_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE46_STATS_BASE(stats_idx);
+
+	/*
+	 * BF_SCALE does not have its own WR_ADDR_CFG,
+	 * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN;
+	 * it's using the same from BF.
+	 */
+	if (stats_idx == STATS_IDX_BF_SCALE)
+		return;
+
+	/* WR_ADDR_CFG */
+	msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
+		vfe_dev->vfe_base + stats_base + 0x8);
+	/* WR_IRQ_FRAMEDROP_PATTERN */
+	msm_camera_io_w(stream_info->framedrop_pattern,
+		vfe_dev->vfe_base + stats_base + 0x10);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe46_stats_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t val = 0;
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE46_STATS_BASE(stats_idx);
+	/*
+	 * BF_SCALE does not have its own WR_ADDR_CFG,
+	 * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN;
+	 * it's using the same from BF.
+	 */
+	if (stats_idx == STATS_IDX_BF_SCALE)
+		return;
+
+	/* WR_ADDR_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8);
+	/* WR_IRQ_FRAMEDROP_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14);
+}
+
+static void msm_vfe46_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = 0;
+	uint32_t ub_size[VFE46_NUM_STATS_TYPE] = {
+		16, /* MSM_ISP_STATS_BF_SCALE */
+		16, /* MSM_ISP_STATS_HDR_BE */
+		16, /* MSM_ISP_STATS_BG */
+		16, /* MSM_ISP_STATS_BF */
+		16, /* MSM_ISP_STATS_HDR_BHIST */
+		16, /* MSM_ISP_STATS_RS */
+		16, /* MSM_ISP_STATS_CS */
+		16, /* MSM_ISP_STATS_IHIST */
+		16, /* MSM_ISP_STATS_BHIST */
+	};
+	if (vfe_dev->pdev->id == ISP_VFE1)
+		ub_offset = VFE46_UB_SIZE_VFE1;
+	else if (vfe_dev->pdev->id == ISP_VFE0)
+		ub_offset = VFE46_UB_SIZE_VFE0;
+	else
+		pr_err("%s: incorrect VFE device\n", __func__);
+
+	for (i = 0; i < VFE46_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(VFE46_STATS_BURST_LEN << 30 |
+			ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE46_STATS_BASE(i) +
+			((i == STATS_IDX_BF_SCALE) ? 0x8 : 0xC));
+	}
+}
+
+static void msm_vfe46_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, cgc_mask = 0;
+
+	for (i = 0; i < VFE46_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_IDX_HDR_BE:
+				cgc_mask |= 1;
+				break;
+			case STATS_IDX_HDR_BHIST:
+				cgc_mask |= (1 << 1);
+				break;
+			case STATS_IDX_BF:
+				cgc_mask |= (1 << 2);
+				break;
+			case STATS_IDX_BG:
+				cgc_mask |= (1 << 3);
+				break;
+			case STATS_IDX_BHIST:
+				cgc_mask |= (1 << 4);
+				break;
+			case STATS_IDX_RS:
+				cgc_mask |= (1 << 5);
+				break;
+			case STATS_IDX_CS:
+				cgc_mask |= (1 << 6);
+				break;
+			case STATS_IDX_IHIST:
+				cgc_mask |= (1 << 7);
+				break;
+			case STATS_IDX_BF_SCALE:
+				cgc_mask |= (1 << 2);
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/* CGC override */
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
+	if (enable)
+		module_cfg |= cgc_mask;
+	else
+		module_cfg &= ~cgc_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x30);
+}
+
+static bool msm_vfe46_is_module_cfg_lock_needed(
+	uint32_t reg_offset)
+{
+	return false;
+}
+
+static void msm_vfe46_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, module_cfg_mask = 0;
+	uint32_t stats_cfg, stats_cfg_mask = 0;
+
+	for (i = 0; i < VFE46_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_IDX_HDR_BE:
+				module_cfg_mask |= 1;
+				break;
+			case STATS_IDX_HDR_BHIST:
+				module_cfg_mask |= 1 << 1;
+				break;
+			case STATS_IDX_BF:
+				module_cfg_mask |= 1 << 2;
+				break;
+			case STATS_IDX_BG:
+				module_cfg_mask |= 1 << 3;
+				break;
+			case STATS_IDX_BHIST:
+				module_cfg_mask |= 1 << 4;
+				break;
+			case STATS_IDX_RS:
+				module_cfg_mask |= 1 << 5;
+				break;
+			case STATS_IDX_CS:
+				module_cfg_mask |= 1 << 6;
+				break;
+			case STATS_IDX_IHIST:
+				module_cfg_mask |= 1 << 7;
+				break;
+			case STATS_IDX_BF_SCALE:
+				stats_cfg_mask |= 1 << 5;
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x44);
+	if (enable)
+		module_cfg |= module_cfg_mask;
+	else
+		module_cfg &= ~module_cfg_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x44);
+
+	stats_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x9B8);
+	if (enable)
+		stats_cfg |= stats_cfg_mask;
+	else
+		stats_cfg &= ~stats_cfg_mask;
+	msm_camera_io_w(stats_cfg, vfe_dev->vfe_base + 0x9B8);
+}
+
+static void msm_vfe46_stats_update_ping_pong_addr(
+	struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
+	uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	int stats_idx;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE46_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+}
+
+static uint32_t msm_vfe46_stats_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 15) & 0x1FF;
+}
+
+static uint32_t msm_vfe46_stats_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 29) & 0x3;
+}
+
+static uint32_t msm_vfe46_stats_get_frame_id(
+	struct vfe_device *vfe_dev)
+{
+	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+}
+
+static void msm_vfe46_get_error_mask(
+	uint32_t *error_mask0, uint32_t *error_mask1)
+{
+	*error_mask0 = 0x00000000;
+	*error_mask1 = 0x01FFFEFF;
+}
+
+static void msm_vfe46_get_overflow_mask(uint32_t *overflow_mask)
+{
+	*overflow_mask = 0x01FFFE7E;
+}
+
+static void msm_vfe46_get_rdi_wm_mask(struct vfe_device *vfe_dev,
+	uint32_t *rdi_wm_mask)
+{
+	*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
+}
+
+static void msm_vfe46_get_irq_mask(struct vfe_device *vfe_dev,
+	uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+	*irq0_mask = vfe_dev->irq0_mask;
+	*irq1_mask = vfe_dev->irq1_mask;
+}
+
+static void msm_vfe46_get_halt_restart_mask(uint32_t *irq0_mask,
+	uint32_t *irq1_mask)
+{
+	*irq0_mask = BIT(31);
+	*irq1_mask = BIT(8);
+}
+static struct msm_vfe_axi_hardware_info msm_vfe46_axi_hw_info = {
+	.num_wm = 7,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 96,
+	.scratch_buf_range = SZ_32M + SZ_4M,
+};
+
+static struct msm_vfe_stats_hardware_info msm_vfe46_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_HDR_BE    | 1 << MSM_ISP_STATS_BF    |
+		1 << MSM_ISP_STATS_BG        | 1 << MSM_ISP_STATS_BHIST |
+		1 << MSM_ISP_STATS_HDR_BHIST | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS        | 1 << MSM_ISP_STATS_CS    |
+		1 << MSM_ISP_STATS_BF_SCALE,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.num_stats_type = VFE46_NUM_STATS_TYPE,
+	.num_stats_comp_mask = VFE46_NUM_STATS_COMP,
+};
+
+struct msm_vfe_hardware_info vfe46_hw_info = {
+	.num_iommu_ctx = 1,
+	.num_iommu_secure_ctx = 1,
+	.vfe_clk_idx = VFE46_CLK_IDX,
+	.runtime_axi_update = 0,
+	.min_ab = 100000000,
+	.min_ib = 100000000,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe46_read_and_clear_irq_status,
+			.read_irq_status = msm_vfe46_read_irq_status,
+			.process_camif_irq = msm_vfe46_process_input_irq,
+			.process_reset_irq = msm_vfe46_process_reset_irq,
+			.process_halt_irq = msm_vfe46_process_halt_irq,
+			.process_reg_update = msm_vfe46_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe46_process_epoch_irq,
+			.config_irq = msm_vfe46_config_irq,
+			.preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe46_axi_reload_wm,
+			.enable_wm = msm_vfe46_axi_enable_wm,
+			.cfg_io_format = msm_vfe46_cfg_io_format,
+			.cfg_comp_mask = msm_vfe46_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe46_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe46_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe46_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe46_cfg_framedrop,
+			.clear_framedrop = msm_vfe46_clear_framedrop,
+			.cfg_wm_reg = msm_vfe46_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe46_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe46_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe46_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.read_wm_ping_pong_addr =
+				msm_vfe46_read_wm_ping_pong_addr,
+			.update_ping_pong_addr =
+				msm_vfe46_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe46_get_comp_mask,
+			.get_wm_mask = msm_vfe46_get_wm_mask,
+			.get_pingpong_status = msm_vfe46_get_pingpong_status,
+			.halt = msm_vfe46_axi_halt,
+			.restart = msm_vfe46_axi_restart,
+			.update_cgc_override =
+				msm_vfe46_axi_update_cgc_override,
+			.ub_reg_offset = msm_vfe46_ub_reg_offset,
+			.get_ub_size = msm_vfe46_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe46_reg_update,
+			.cfg_input_mux = msm_vfe46_cfg_input_mux,
+			.update_camif_state = msm_vfe46_update_camif_state,
+			.start_fetch_eng = msm_vfe46_start_fetch_engine,
+			.cfg_rdi_reg = msm_vfe46_cfg_rdi_reg,
+			.reset_hw = msm_vfe46_reset_hardware,
+			.init_hw = msm_vfe47_init_hardware,
+			.init_hw_reg = msm_vfe46_init_hardware_reg,
+			.clear_status_reg = msm_vfe46_clear_status_reg,
+			.release_hw = msm_vfe47_release_hardware,
+			.get_error_mask = msm_vfe46_get_error_mask,
+			.get_overflow_mask = msm_vfe46_get_overflow_mask,
+			.get_rdi_wm_mask = msm_vfe46_get_rdi_wm_mask,
+			.get_irq_mask = msm_vfe46_get_irq_mask,
+			.get_halt_restart_mask =
+				msm_vfe46_get_halt_restart_mask,
+			.process_error_status = msm_vfe46_process_error_status,
+			.is_module_cfg_lock_needed =
+				msm_vfe46_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = NULL,
+			.set_halt_restart_mask =
+				msm_vfe46_set_halt_restart_mask,
+			.set_bus_err_ign_mask = NULL,
+			.get_bus_err_mask = NULL,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe46_get_stats_idx,
+			.check_streams = msm_vfe46_stats_check_streams,
+			.cfg_comp_mask = msm_vfe46_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe46_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe46_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe46_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe46_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe46_stats_cfg_ub,
+			.enable_module = msm_vfe46_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe46_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe46_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe46_stats_get_wm_mask,
+			.get_frame_id = msm_vfe46_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe46_get_pingpong_status,
+			.update_cgc_override =
+				msm_vfe46_stats_update_cgc_override,
+			.enable_stats_wm = NULL,
+		},
+		.platform_ops = {
+			.get_platform_data = msm_vfe47_get_platform_data,
+			.enable_regulators = msm_vfe47_enable_regulators,
+			.get_regulators = msm_vfe47_get_regulators,
+			.put_regulators = msm_vfe47_put_regulators,
+			.enable_clks = msm_vfe47_enable_clks,
+			.get_clks = msm_vfe47_get_clks,
+			.put_clks = msm_vfe47_put_clks,
+			.get_clk_rates = msm_vfe47_get_clk_rates,
+			.get_max_clk_rate = msm_vfe47_get_max_clk_rate,
+			.set_clk_rate = msm_vfe47_set_clk_rate,
+			.init_bw_mgr = msm_vfe47_init_bandwidth_mgr,
+			.deinit_bw_mgr = msm_vfe47_deinit_bandwidth_mgr,
+			.update_bw = msm_vfe47_update_bandwidth,
+		}
+	},
+	.dmi_reg_offset = 0xACC,
+	.axi_hw_info = &msm_vfe46_axi_hw_info,
+	.stats_hw_info = &msm_vfe46_stats_hw_info,
+	.regulator_names = {"vdd"},
+};
+EXPORT_SYMBOL(vfe46_hw_info);
+
+static const struct of_device_id msm_vfe46_dt_match[] = {
+	{
+		.compatible = "qcom,vfe46",
+		.data = &vfe46_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe46_dt_match);
+
+static struct platform_driver vfe46_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe46",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe46_dt_match,
+	},
+};
+
+static int __init msm_vfe46_init_module(void)
+{
+	return platform_driver_register(&vfe46_driver);
+}
+
+static void __exit msm_vfe46_exit_module(void)
+{
+	platform_driver_unregister(&vfe46_driver);
+}
+
+module_init(msm_vfe46_init_module);
+module_exit(msm_vfe46_exit_module);
+MODULE_DESCRIPTION("MSM VFE46 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.h
new file mode 100644
index 0000000..68444a0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP46_H__
+#define __MSM_ISP46_H__
+
+extern struct msm_vfe_hardware_info vfe46_hw_info;
+#endif /* __MSM_ISP46_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
new file mode 100644
index 0000000..410689f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -0,0 +1,3141 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+
+#include "msm.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm_camera_io_util.h"
+#include "cam_hw_ops.h"
+#include "msm_isp47.h"
+#include "cam_soc_api.h"
+#include "msm_isp48.h"
+#include "linux/iopoll.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define VFE47_8996V1_VERSION   0x70000000
+
+#define VFE47_BURST_LEN 3
+#define VFE47_FETCH_BURST_LEN 3
+#define VFE47_STATS_BURST_LEN 3
+#define VFE47_UB_SIZE_VFE0 2048
+#define VFE47_UB_SIZE_VFE1 1536
+#define VFE47_UB_STATS_SIZE 144
+#define MSM_ISP47_TOTAL_IMAGE_UB_VFE0 (VFE47_UB_SIZE_VFE0 - VFE47_UB_STATS_SIZE)
+#define MSM_ISP47_TOTAL_IMAGE_UB_VFE1 (VFE47_UB_SIZE_VFE1 - VFE47_UB_STATS_SIZE)
+#define VFE47_WM_BASE(idx) (0xA0 + 0x2C * idx)
+#define VFE47_RDI_BASE(idx) (0x46C + 0x4 * idx)
+#define VFE47_XBAR_BASE(idx) (0x90 + 0x4 * (idx / 2))
+#define VFE47_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
+/*add ping MAX and Pong MAX*/
+#define VFE47_PING_PONG_BASE(wm, ping_pong) \
+	(VFE47_WM_BASE(wm) + 0x4 * (1 + (((~ping_pong) & 0x1) * 2)))
+#define SHIFT_BF_SCALE_BIT 1
+
+#define VFE47_BUS_RD_CGC_OVERRIDE_BIT 16
+
+#define VFE47_VBIF_CLK_OFFSET    0x4
+
+static uint32_t stats_base_addr[] = {
+	0x1D4, /* HDR_BE */
+	0x254, /* BG(AWB_BG) */
+	0x214, /* BF */
+	0x1F4, /* HDR_BHIST */
+	0x294, /* RS */
+	0x2B4, /* CS */
+	0x2D4, /* IHIST */
+	0x274, /* BHIST (SKIN_BHIST) */
+	0x234, /* AEC_BG */
+};
+
+static uint8_t stats_pingpong_offset_map[] = {
+	 8, /* HDR_BE */
+	12, /* BG(AWB_BG) */
+	10, /* BF */
+	 9, /* HDR_BHIST */
+	14, /* RS */
+	15, /* CS */
+	16, /* IHIST */
+	13, /* BHIST (SKIN_BHIST) */
+	11, /* AEC_BG */
+};
+
+static uint8_t stats_irq_map_comp_mask[] = {
+	16, /* HDR_BE */
+	17, /* BG(AWB_BG) */
+	18, /* BF EARLY DONE/ BF */
+	19, /* HDR_BHIST */
+	20, /* RS */
+	21, /* CS */
+	22, /* IHIST */
+	23, /* BHIST (SKIN_BHIST) */
+	15, /* AEC_BG */
+};
+
+#define VFE47_STATS_BASE(idx) (stats_base_addr[idx])
+#define VFE47_STATS_PING_PONG_BASE(idx, ping_pong) \
+	(VFE47_STATS_BASE(idx) + 0x4 * \
+	(~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1) * 2)
+
+#define VFE47_SRC_CLK_DTSI_IDX 5
+
+static struct msm_bus_vectors msm_isp_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+/* During open node request min ab/ib bus bandwidth which
+ * is needed to successfully enable bus clocks
+ */
+static struct msm_bus_vectors msm_isp_ping_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = MSM_ISP_MIN_AB,
+		.ib  = MSM_ISP_MIN_IB,
+	},
+};
+
+static struct msm_bus_vectors msm_isp_pong_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_paths msm_isp_bus_client_config[] = {
+	{
+		ARRAY_SIZE(msm_isp_init_vectors),
+		msm_isp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(msm_isp_ping_vectors),
+		msm_isp_ping_vectors,
+	},
+	{
+		ARRAY_SIZE(msm_isp_pong_vectors),
+		msm_isp_pong_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata msm_isp_bus_client_pdata = {
+	msm_isp_bus_client_config,
+	NULL,
+	ARRAY_SIZE(msm_isp_bus_client_config),
+	.name = "msm_camera_isp",
+	0
+};
+
+uint32_t msm_vfe47_ub_reg_offset(struct vfe_device *vfe_dev, int wm_idx)
+{
+	return (VFE47_WM_BASE(wm_idx) + 0x18);
+}
+
+uint32_t msm_vfe47_get_ub_size(struct vfe_device *vfe_dev)
+{
+	if (vfe_dev->pdev->id == ISP_VFE0)
+		return MSM_ISP47_TOTAL_IMAGE_UB_VFE0;
+	return MSM_ISP47_TOTAL_IMAGE_UB_VFE1;
+}
+
+void msm_vfe47_config_irq(struct vfe_device *vfe_dev,
+		uint32_t irq0_mask, uint32_t irq1_mask,
+		enum msm_isp_irq_operation oper)
+{
+	switch (oper) {
+	case MSM_ISP_IRQ_ENABLE:
+		vfe_dev->irq0_mask |= irq0_mask;
+		vfe_dev->irq1_mask |= irq1_mask;
+		msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+		break;
+	case MSM_ISP_IRQ_DISABLE:
+		vfe_dev->irq0_mask &= ~irq0_mask;
+		vfe_dev->irq1_mask &= ~irq1_mask;
+		break;
+	case MSM_ISP_IRQ_SET:
+		vfe_dev->irq0_mask = irq0_mask;
+		vfe_dev->irq1_mask = irq1_mask;
+		msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+		break;
+	}
+	msm_camera_io_w_mb(vfe_dev->irq0_mask,
+				vfe_dev->vfe_base + 0x5C);
+	msm_camera_io_w_mb(vfe_dev->irq1_mask,
+				vfe_dev->vfe_base + 0x60);
+}
+
+static int32_t msm_vfe47_init_dt_parms(struct vfe_device *vfe_dev,
+	struct msm_vfe_hw_init_parms *dt_parms, void __iomem *dev_mem_base)
+{
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *dt_settings = NULL, *dt_regs = NULL, num_dt_entries = 0;
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	rc = of_property_read_u32(of_node, dt_parms->entries,
+		&num_dt_entries);
+	if (rc < 0 || !num_dt_entries) {
+		pr_err("%s: NO QOS entries found\n", __func__);
+		return -EINVAL;
+	}
+	dt_settings = kcalloc(num_dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_settings)
+		return -ENOMEM;
+	dt_regs = kcalloc(num_dt_entries, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!dt_regs) {
+		kfree(dt_settings);
+		return -ENOMEM;
+	}
+	rc = of_property_read_u32_array(of_node, dt_parms->regs,
+		dt_regs, num_dt_entries);
+	if (rc < 0) {
+		pr_err("%s: NO QOS BUS BDG info\n", __func__);
+		kfree(dt_settings);
+		kfree(dt_regs);
+		return -EINVAL;
+	}
+	if (dt_parms->settings) {
+		rc = of_property_read_u32_array(of_node,
+			dt_parms->settings,
+			dt_settings, num_dt_entries);
+		if (rc < 0) {
+			pr_err("%s: NO QOS settings\n",
+				__func__);
+			kfree(dt_settings);
+			kfree(dt_regs);
+		} else {
+			for (i = 0; i < num_dt_entries; i++) {
+				msm_camera_io_w(dt_settings[i],
+					dev_mem_base +
+					dt_regs[i]);
+			}
+			kfree(dt_settings);
+			kfree(dt_regs);
+		}
+	} else {
+		kfree(dt_settings);
+		kfree(dt_regs);
+	}
+	return 0;
+}
+
+static enum cam_ahb_clk_vote msm_isp47_get_cam_clk_vote(
+	 enum msm_vfe_ahb_clk_vote vote)
+{
+	switch (vote) {
+	case MSM_ISP_CAMERA_AHB_SVS_VOTE:
+		return CAM_AHB_SVS_VOTE;
+	case MSM_ISP_CAMERA_AHB_TURBO_VOTE:
+		return CAM_AHB_TURBO_VOTE;
+	case MSM_ISP_CAMERA_AHB_NOMINAL_VOTE:
+		return CAM_AHB_NOMINAL_VOTE;
+	case MSM_ISP_CAMERA_AHB_SUSPEND_VOTE:
+		return CAM_AHB_SUSPEND_VOTE;
+	}
+	return 0;
+}
+
+int msm_isp47_ahb_clk_cfg(struct vfe_device *vfe_dev,
+			struct msm_isp_ahb_clk_cfg *ahb_cfg)
+{
+	int rc = 0;
+	enum cam_ahb_clk_vote vote;
+	enum cam_ahb_clk_vote src_clk_vote;
+	struct msm_isp_clk_rates clk_rates;
+
+	if (ahb_cfg) {
+		vote = msm_isp47_get_cam_clk_vote(ahb_cfg->vote);
+		vfe_dev->user_requested_ahb_vote = vote;
+	} else {
+		vote = vfe_dev->user_requested_ahb_vote;
+	}
+
+	vfe_dev->hw_info->vfe_ops.platform_ops.get_clk_rates(vfe_dev,
+							&clk_rates);
+	if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate <=
+		clk_rates.svs_rate)
+		src_clk_vote = CAM_AHB_SVS_VOTE;
+	else if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate
+		<= clk_rates.nominal_rate)
+		src_clk_vote = CAM_AHB_NOMINAL_VOTE;
+	else
+		src_clk_vote = CAM_AHB_TURBO_VOTE;
+
+	/* vote for higher of the user requested or src clock matched vote */
+	if (vote < src_clk_vote)
+		vote = src_clk_vote;
+
+	if (vote && vfe_dev->ahb_vote != vote) {
+		rc = cam_config_ahb_clk(NULL, 0,
+			(vfe_dev->pdev->id  == ISP_VFE0 ?
+			CAM_AHB_CLIENT_VFE0 : CAM_AHB_CLIENT_VFE1), vote);
+		if (rc)
+			pr_err("%s: failed to set ahb vote to %x\n",
+				__func__, vote);
+		else
+			vfe_dev->ahb_vote = vote;
+	}
+	return rc;
+}
+
+int msm_vfe47_init_hardware(struct vfe_device *vfe_dev)
+{
+	int rc = -1;
+	enum cam_ahb_clk_client id;
+
+	if (vfe_dev->pdev->id == 0)
+		id = CAM_AHB_CLIENT_VFE0;
+	else
+		id = CAM_AHB_CLIENT_VFE1;
+
+	rc = vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(
+								vfe_dev, 1);
+	if (rc)
+		goto enable_regulators_failed;
+
+	rc = vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
+							vfe_dev, 1);
+	if (rc)
+		goto clk_enable_failed;
+
+	vfe_dev->user_requested_ahb_vote = CAM_AHB_SVS_VOTE;
+	rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		goto ahb_vote_fail;
+	}
+	vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE;
+
+	vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] =
+		vfe_dev->vfe_base;
+
+	rc = msm_camera_enable_irq(vfe_dev->vfe_irq, 1);
+	if (rc < 0)
+		goto irq_enable_fail;
+
+	return rc;
+irq_enable_fail:
+	vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
+	if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
+ahb_vote_fail:
+	vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0);
+clk_enable_failed:
+	vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
+enable_regulators_failed:
+	return rc;
+}
+
+void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
+{
+	enum cam_ahb_clk_client id;
+	unsigned long rate = 0;
+
+	/* when closing node, disable all irq */
+	vfe_dev->irq0_mask = 0;
+	vfe_dev->irq1_mask = 0;
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				vfe_dev->irq0_mask, vfe_dev->irq1_mask,
+				MSM_ISP_IRQ_SET);
+	msm_camera_enable_irq(vfe_dev->vfe_irq, 0);
+	tasklet_kill(&(vfe_dev->common_data->tasklets[vfe_dev->pdev->id].
+			tasklet));
+	msm_isp_flush_tasklet(vfe_dev);
+
+	vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
+
+	msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, 0, 0);
+
+	if (vfe_dev->pdev->id == 0)
+		id = CAM_AHB_CLIENT_VFE0;
+	else
+		id = CAM_AHB_CLIENT_VFE1;
+
+	vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate(vfe_dev, &rate);
+
+	if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to vote for AHB\n", __func__);
+
+	vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
+
+	vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
+							vfe_dev, 0);
+	msm_vfe47_configure_hvx(vfe_dev, 0);
+	vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
+}
+
+void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_hw_init_parms qos_parms;
+	struct msm_vfe_hw_init_parms vbif_parms;
+	struct msm_vfe_hw_init_parms ds_parms;
+
+	memset(&qos_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+	memset(&vbif_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+	memset(&ds_parms, 0, sizeof(struct msm_vfe_hw_init_parms));
+
+	qos_parms.entries = "qos-entries";
+	qos_parms.regs = "qos-regs";
+	qos_parms.settings = "qos-settings";
+	vbif_parms.entries = "vbif-entries";
+	vbif_parms.regs = "vbif-regs";
+	vbif_parms.settings = "vbif-settings";
+	ds_parms.entries = "ds-entries";
+	ds_parms.regs = "ds-regs";
+	ds_parms.settings = "ds-settings";
+
+	msm_vfe47_init_dt_parms(vfe_dev, &qos_parms, vfe_dev->vfe_base);
+	msm_vfe47_init_dt_parms(vfe_dev, &ds_parms, vfe_dev->vfe_base);
+	msm_vfe47_init_dt_parms(vfe_dev, &vbif_parms, vfe_dev->vfe_vbif_base);
+
+
+	/* BUS_CFG */
+	msm_camera_io_w(0x00000101, vfe_dev->vfe_base + 0x84);
+	/* IRQ_MASK/CLEAR */
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+			0x810000E0, 0xFFFFFF7E, MSM_ISP_IRQ_ENABLE);
+}
+
+void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev)
+{
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+			0x80000000, 0x0, MSM_ISP_IRQ_SET);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
+	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
+	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
+}
+
+void msm_vfe47_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	unsigned long flags;
+
+	if (irq_status0 & (1 << 31)) {
+		spin_lock_irqsave(&vfe_dev->completion_lock, flags);
+		complete(&vfe_dev->reset_complete);
+		vfe_dev->reset_pending = 0;
+		spin_unlock_irqrestore(&vfe_dev->completion_lock, flags);
+	}
+}
+
+void msm_vfe47_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	uint32_t val = 0;
+
+	if (irq_status1 & (1 << 8)) {
+		complete(&vfe_dev->halt_complete);
+		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x400);
+	}
+
+	val = msm_camera_io_r(vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET);
+	val &= ~(0x1);
+	msm_camera_io_w(val, vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET);
+}
+
+void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0x1000003))
+		return;
+
+	if (irq_status0 & (1 << 0)) {
+		ISP_DBG("%s: SOF IRQ\n", __func__);
+		msm_isp_increment_frame_id(vfe_dev, VFE_PIX_0, ts);
+	}
+
+	if (irq_status0 & (1 << 24)) {
+		ISP_DBG("%s: Fetch Engine Read IRQ\n", __func__);
+		msm_isp_fetch_engine_done_notify(vfe_dev,
+			&vfe_dev->fetch_engine_info);
+	}
+
+
+	if (irq_status0 & (1 << 1))
+		ISP_DBG("%s: EOF IRQ\n", __func__);
+}
+
+void msm_vfe47_process_violation_status(
+	struct vfe_device *vfe_dev)
+{
+	uint32_t violation_status = vfe_dev->error_info.violation_status;
+
+	if (violation_status > 39) {
+		pr_err("%s: invalid violation status %d\n",
+			__func__, violation_status);
+		return;
+	}
+
+	pr_err_ratelimited("%s: VFE pipeline violation status %d\n", __func__,
+		violation_status);
+}
+
+void msm_vfe47_process_error_status(struct vfe_device *vfe_dev)
+{
+	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
+
+	if (error_status1 & (1 << 0)) {
+		pr_err("%s: camif error status: 0x%x\n",
+			__func__, vfe_dev->error_info.camif_status);
+		/* dump camif registers on camif error */
+		msm_camera_io_dump(vfe_dev->vfe_base + 0x478, 0x3C, 1);
+		/* testgen */
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_dump(vfe_dev->vfe_base + 0xC58, 0x28, 1);
+	}
+	if (error_status1 & (1 << 1))
+		pr_err("%s: stats bhist overwrite\n", __func__);
+	if (error_status1 & (1 << 2))
+		pr_err("%s: stats cs overwrite\n", __func__);
+	if (error_status1 & (1 << 3))
+		pr_err("%s: stats ihist overwrite\n", __func__);
+	if (error_status1 & (1 << 4))
+		pr_err("%s: realign buf y overflow\n", __func__);
+	if (error_status1 & (1 << 5))
+		pr_err("%s: realign buf cb overflow\n", __func__);
+	if (error_status1 & (1 << 6))
+		pr_err("%s: realign buf cr overflow\n", __func__);
+	if (error_status1 & (1 << 7))
+		msm_vfe47_process_violation_status(vfe_dev);
+	if (error_status1 & (1 << 9))
+		pr_err("%s: image master 0 bus overflow\n", __func__);
+	if (error_status1 & (1 << 10))
+		pr_err("%s: image master 1 bus overflow\n", __func__);
+	if (error_status1 & (1 << 11))
+		pr_err("%s: image master 2 bus overflow\n", __func__);
+	if (error_status1 & (1 << 12))
+		pr_err("%s: image master 3 bus overflow\n", __func__);
+	if (error_status1 & (1 << 13))
+		pr_err("%s: image master 4 bus overflow\n", __func__);
+	if (error_status1 & (1 << 14))
+		pr_err("%s: image master 5 bus overflow\n", __func__);
+	if (error_status1 & (1 << 15))
+		pr_err("%s: image master 6 bus overflow\n", __func__);
+	if (error_status1 & (1 << 16))
+		pr_err("%s: status hdr be bus overflow\n", __func__);
+	if (error_status1 & (1 << 17))
+		pr_err("%s: status bg bus overflow\n", __func__);
+	if (error_status1 & (1 << 18))
+		pr_err("%s: status bf bus overflow\n", __func__);
+	if (error_status1 & (1 << 19))
+		pr_err("%s: status hdr bhist bus overflow\n", __func__);
+	if (error_status1 & (1 << 20))
+		pr_err("%s: status rs bus overflow\n", __func__);
+	if (error_status1 & (1 << 21))
+		pr_err("%s: status cs bus overflow\n", __func__);
+	if (error_status1 & (1 << 22))
+		pr_err("%s: status ihist bus overflow\n", __func__);
+	if (error_status1 & (1 << 23))
+		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	if (error_status1 & (1 << 24))
+		pr_err("%s: status aec bg bus overflow\n", __func__);
+	if (error_status1 & (1 << 25))
+		pr_err("%s: status dsp error\n", __func__);
+}
+
+void msm_vfe47_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	uint32_t count = 0;
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
+	/* Mask off bits that are not enabled */
+	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x64);
+	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x68);
+	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x58);
+	*irq_status0 &= vfe_dev->irq0_mask;
+	*irq_status1 &= vfe_dev->irq1_mask;
+	/* check if status register is cleared if not clear again*/
+	while (*irq_status0 &&
+		(*irq_status0 & msm_camera_io_r(vfe_dev->vfe_base + 0x6C)) &&
+		(count < MAX_RECOVERY_THRESHOLD)) {
+		msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x58);
+		count++;
+	}
+
+	if (*irq_status1 & (1 << 0)) {
+		vfe_dev->error_info.camif_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x4A4);
+		/* mask off camif error after first occurrance */
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev, 0,
+					(1 << 0), MSM_ISP_IRQ_DISABLE);
+	}
+
+	if (*irq_status1 & (1 << 7))
+		vfe_dev->error_info.violation_status =
+		msm_camera_io_r(vfe_dev->vfe_base + 0x7C);
+
+}
+
+void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1)
+{
+	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x6C);
+	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x70);
+}
+
+void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	enum msm_vfe_input_src i;
+	uint32_t shift_irq;
+	uint8_t reg_updated = 0;
+	unsigned long flags;
+
+	if (!(irq_status0 & 0xF0))
+		return;
+	/* Shift status bits so that PIX SOF is 1st bit */
+	shift_irq = ((irq_status0 & 0xF0) >> 4);
+
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		if (shift_irq & BIT(i)) {
+			reg_updated |= BIT(i);
+			ISP_DBG("%s REG_UPDATE IRQ %x vfe %d\n", __func__,
+				(uint32_t)BIT(i), vfe_dev->pdev->id);
+			switch (i) {
+			case VFE_PIX_0:
+				msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE,
+					VFE_PIX_0, ts);
+				msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+						MSM_ISP_COMP_IRQ_REG_UPD);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				/*
+				 * if only camif raw streams active then force
+				 * reg update
+				 */
+				if (vfe_dev->axi_data.src_info[VFE_PIX_0].
+					raw_stream_count > 0 &&
+					vfe_dev->axi_data.src_info[VFE_PIX_0].
+						stream_count == 0)
+					vfe_dev->hw_info->vfe_ops.core_ops.
+						reg_update(vfe_dev, i);
+				break;
+			case VFE_RAW_0:
+			case VFE_RAW_1:
+			case VFE_RAW_2:
+				msm_isp_increment_frame_id(vfe_dev, i, ts);
+				msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_REG_UPD, ts);
+				/*
+				 * Reg Update is pseudo SOF for RDI,
+				 * so request every frame
+				 */
+				vfe_dev->hw_info->vfe_ops.core_ops.
+					reg_update(vfe_dev, i);
+				/* reg upd is also epoch for RDI */
+				msm_isp_process_reg_upd_epoch_irq(vfe_dev, i,
+						MSM_ISP_COMP_IRQ_EPOCH, ts);
+				break;
+			default:
+				pr_err("%s: Error case\n", __func__);
+				return;
+			}
+		}
+	}
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	if (reg_updated & BIT(VFE_PIX_0))
+		vfe_dev->reg_updated = 1;
+
+	vfe_dev->reg_update_requested &= ~reg_updated;
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	if (!(irq_status0 & 0xc))
+		return;
+
+	if (irq_status0 & BIT(2)) {
+		ISP_DBG("%s: EPOCH0 IRQ\n", __func__);
+		msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+					MSM_ISP_COMP_IRQ_EPOCH, ts);
+		msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
+					MSM_ISP_COMP_IRQ_EPOCH);
+		msm_isp_update_error_frame_count(vfe_dev);
+		msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+			stream_count == 0) {
+			msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0,
+					MSM_ISP_COMP_IRQ_REG_UPD, ts);
+			vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+				vfe_dev, VFE_PIX_0);
+		}
+	}
+}
+
+void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0)
+{
+	if (irq_status0 & BIT(3))
+		vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false;
+	if (irq_status0 & BIT(0))
+		vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true;
+}
+
+void msm_vfe47_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	uint32_t update_mask = 0;
+	unsigned long flags;
+
+	/* This HW supports upto VFE_RAW_2 */
+	if (frame_src > VFE_RAW_2 && frame_src != VFE_SRC_MAX) {
+		pr_err("%s Error case\n", __func__);
+		return;
+	}
+
+	/*
+	 * If frame_src == VFE_SRC_MAX request reg_update on all
+	 * supported INTF
+	 */
+	if (frame_src == VFE_SRC_MAX)
+		update_mask = 0xF;
+	else
+		update_mask = BIT((uint32_t)frame_src);
+	ISP_DBG("%s update_mask %x\n", __func__, update_mask);
+
+	spin_lock_irqsave(&vfe_dev->reg_update_lock, flags);
+	vfe_dev->axi_data.src_info[VFE_PIX_0].reg_update_frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	vfe_dev->reg_update_requested |= update_mask;
+	vfe_dev->common_data->dual_vfe_res->reg_update_mask[vfe_dev->pdev->id] =
+		vfe_dev->reg_update_requested;
+	if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) &&
+		((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) {
+		if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) {
+			pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__);
+			spin_unlock_irqrestore(&vfe_dev->reg_update_lock,
+				flags);
+			return;
+		}
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+			+ 0x4AC);
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x4AC);
+	} else if (!vfe_dev->is_split ||
+		((frame_src == VFE_PIX_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].
+					raw_stream_count == 0)) ||
+		(frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) {
+		msm_camera_io_w_mb(update_mask,
+			vfe_dev->vfe_base + 0x4AC);
+	}
+	spin_unlock_irqrestore(&vfe_dev->reg_update_lock, flags);
+}
+
+long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking_call)
+{
+	long rc = 0;
+	uint32_t reset;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe_dev->completion_lock, flags);
+	init_completion(&vfe_dev->reset_complete);
+	spin_unlock_irqrestore(&vfe_dev->completion_lock, flags);
+
+	if (blocking_call)
+		vfe_dev->reset_pending = 1;
+
+	if (first_start) {
+		if (msm_vfe_is_vfe48(vfe_dev))
+			reset = 0x3F7;
+		else
+			reset = 0x3FF;
+		msm_camera_io_w_mb(reset, vfe_dev->vfe_base + 0x18);
+	} else {
+		if (msm_vfe_is_vfe48(vfe_dev))
+			reset = 0x3E7;
+		else
+			reset = 0x3EF;
+		msm_camera_io_w_mb(reset, vfe_dev->vfe_base + 0x18);
+		msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x64);
+		msm_camera_io_w(0xFFFFFEFF, vfe_dev->vfe_base + 0x68);
+		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58);
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			reload_wm(vfe_dev, vfe_dev->vfe_base, 0x0011FFFF);
+	}
+
+	if (blocking_call) {
+		rc = wait_for_completion_interruptible_timeout(
+			&vfe_dev->reset_complete, msecs_to_jiffies(100));
+		if (rc <= 0) {
+			pr_err("%s:%d failed: reset timeout\n", __func__,
+				__LINE__);
+			vfe_dev->reset_pending = 0;
+		}
+	}
+
+	return rc;
+}
+
+void msm_vfe47_axi_reload_wm(struct vfe_device *vfe_dev,
+	void __iomem *vfe_base, uint32_t reload_mask)
+{
+	msm_camera_io_w_mb(reload_mask, vfe_base + 0x80);
+}
+
+void msm_vfe47_axi_update_cgc_override(struct vfe_device *vfe_dev,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	/* Change CGC override */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+	if (enable)
+		val |= (1 << wm_idx);
+	else
+		val &= ~(1 << wm_idx);
+	msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x3C);
+}
+
+static void msm_vfe47_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	val = msm_camera_io_r(vfe_base + VFE47_WM_BASE(wm_idx));
+	if (enable)
+		val |= 0x1;
+	else
+		val &= ~0x1;
+	msm_camera_io_w_mb(val,
+		vfe_base + VFE47_WM_BASE(wm_idx));
+}
+
+void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+	int i;
+	uint32_t overflow_mask = 0;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		overflow_mask |= (1 << (stream_info->wm[vfe_idx][i] + 9));
+
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << (comp_mask_index + 25), overflow_mask,
+				MSM_ISP_IRQ_ENABLE);
+}
+
+void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t comp_mask, comp_mask_index;
+
+	comp_mask_index = stream_info->comp_mask_index[vfe_idx];
+	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74);
+	comp_mask &= ~(0x7F << (comp_mask_index * 8));
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
+
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				(1 << (comp_mask_index + 25)), 0,
+				MSM_ISP_IRQ_DISABLE);
+}
+
+void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << (stream_info->wm[vfe_idx][0] + 8),
+				1 << (stream_info->wm[vfe_idx][0] + 9),
+				MSM_ISP_IRQ_ENABLE);
+}
+
+void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				(1 << (stream_info->wm[vfe_idx][0] + 8)),
+				0, MSM_ISP_IRQ_DISABLE);
+}
+
+void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	uint32_t i, temp;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		msm_camera_io_w(framedrop_pattern, vfe_base +
+			VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24);
+		temp = msm_camera_io_r(vfe_base +
+			VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14);
+		temp &= 0xFFFFFF83;
+		msm_camera_io_w(temp | (framedrop_period - 1) << 2,
+		vfe_base + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14);
+	}
+}
+
+void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		msm_camera_io_w(0, vfe_dev->vfe_base +
+			VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24);
+}
+
+static int32_t msm_vfe47_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg)
+{
+	int rc = 0;
+
+	switch (bpp) {
+	case 8:
+		*bpp_reg = 0;
+		break;
+	case 10:
+		*bpp_reg = 1;
+		break;
+	case 12:
+		*bpp_reg = 2;
+		break;
+	case 14:
+		*bpp_reg = 3;
+		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_vfe47_convert_io_fmt_to_reg(
+	enum msm_isp_pack_fmt pack_format, uint32_t *pack_reg)
+{
+	int rc = 0;
+
+	switch (pack_format) {
+	case QCOM:
+		*pack_reg = 0x0;
+		break;
+	case MIPI:
+		*pack_reg = 0x1;
+		break;
+	case DPCM6:
+		*pack_reg = 0x2;
+		break;
+	case DPCM8:
+		*pack_reg = 0x3;
+		break;
+	case PLAIN8:
+		*pack_reg = 0x4;
+		break;
+	case PLAIN16:
+		*pack_reg = 0x5;
+		break;
+	case DPCM10:
+		*pack_reg = 0x6;
+		break;
+	default:
+		pr_err("%s: invalid pack fmt %d!\n", __func__, pack_format);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
+{
+	int rc = 0;
+	int bpp = 0, read_bpp = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0, read_pack_fmt = 0;
+	uint32_t bpp_reg = 0, pack_reg = 0;
+	uint32_t read_bpp_reg = 0, read_pack_reg = 0;
+	uint32_t io_format_reg = 0; /*io format register bit*/
+
+	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x88);
+
+	/*input config*/
+	if ((stream_src < RDI_INTF_0) &&
+		(vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux ==
+		EXTERNAL_READ)) {
+		read_bpp = msm_isp_get_bit_per_pixel(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe47_convert_bpp_to_reg(read_bpp, &read_bpp_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_bpp_to_reg err! in_bpp %d rc %d\n",
+				__func__, read_bpp, rc);
+			return rc;
+		}
+
+		read_pack_fmt = msm_isp_get_pack_format(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+		rc = msm_vfe47_convert_io_fmt_to_reg(
+			read_pack_fmt, &read_pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		/*use input format(v4l2_pix_fmt) to get pack format*/
+		io_format_reg &= 0xFFC8FFFF;
+		io_format_reg |= (read_bpp_reg << 20 | read_pack_reg << 16);
+	}
+
+	bpp = msm_isp_get_bit_per_pixel(io_format);
+	rc = msm_vfe47_convert_bpp_to_reg(bpp, &bpp_reg);
+	if (rc < 0) {
+		pr_err("%s: convert_bpp_to_reg err! bpp %d rc = %d\n",
+			__func__, bpp, rc);
+		return rc;
+	}
+
+	switch (stream_src) {
+	case PIX_VIDEO:
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case CAMIF_RAW:
+		io_format_reg &= 0xFFFFCFFF;
+		io_format_reg |= bpp_reg << 12;
+		break;
+	case IDEAL_RAW:
+		/*use output format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		rc = msm_vfe47_convert_io_fmt_to_reg(pack_fmt, &pack_reg);
+		if (rc < 0) {
+			pr_err("%s: convert_io_fmt_to_reg err! rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		io_format_reg &= 0xFFFFFFC8;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
+		break;
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+	default:
+		pr_err("%s: Invalid stream source\n", __func__);
+		return -EINVAL;
+	}
+	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x88);
+	return 0;
+}
+
+int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+
+	/* There is other option of passing buffer address from user,
+	 * in such case, driver needs to map the buffer and use it
+	 */
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+			vfe_dev->buf_mgr, fe_cfg->session_id,
+			fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+		if (rc < 0) {
+			pr_err("%s: can not map buffer\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr, vfe_dev->vfe_base + 0x2F4);
+
+	msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
+	msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);
+
+	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+
+	return 0;
+}
+
+int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+	struct msm_isp_buffer_mapped_info mapped_info;
+
+	if (vfe_dev->fetch_engine_info.is_busy == 1) {
+		pr_err("%s: fetch engine busy\n", __func__);
+		return -EINVAL;
+	}
+
+	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+
+	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+	if (!fe_cfg->offline_mode) {
+		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+			vfe_dev->buf_mgr, fe_cfg->session_id,
+			fe_cfg->stream_id);
+		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+		mapped_info = buf->mapped_info[0];
+		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+	} else {
+		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+			&mapped_info, fe_cfg->fd);
+		if (rc < 0) {
+			pr_err("%s: can not map buffer\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+	vfe_dev->fetch_engine_info.is_busy = 1;
+
+	msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
+		vfe_dev->vfe_base + 0x2F4);
+	msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
+	msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);
+
+	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+
+	return 0;
+}
+
+void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t x_size_word, temp;
+	struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
+	uint32_t main_unpack_pattern = 0;
+
+	if (pix_cfg->input_mux == EXTERNAL_READ) {
+		fe_cfg = &pix_cfg->fetch_engine_cfg;
+		pr_debug("%s:VFE%d wd x ht buf = %d x %d, fe = %d x %d\n",
+			__func__, vfe_dev->pdev->id, fe_cfg->buf_width,
+			fe_cfg->buf_height,
+			fe_cfg->fetch_width, fe_cfg->fetch_height);
+
+		vfe_dev->hw_info->vfe_ops.axi_ops.update_cgc_override(vfe_dev,
+			VFE47_BUS_RD_CGC_OVERRIDE_BIT, 1);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x84);
+		temp &= 0xFFFFFFFD;
+		temp |= (1 << 1);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84);
+
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				(1 << 24), 0,
+				MSM_ISP_IRQ_ENABLE);
+
+		temp = fe_cfg->fetch_height - 1;
+		msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x308);
+
+		x_size_word = msm_isp_cal_word_per_line(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+			fe_cfg->buf_width);
+		msm_camera_io_w((x_size_word - 1) << 16,
+			vfe_dev->vfe_base + 0x30c);
+
+		x_size_word = msm_isp_cal_word_per_line(
+			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+			fe_cfg->fetch_width);
+		msm_camera_io_w(x_size_word << 16 |
+			(temp & 0x3FFF) << 2 | VFE47_FETCH_BURST_LEN,
+			vfe_dev->vfe_base + 0x310);
+
+		temp = ((fe_cfg->buf_width - 1) & 0x3FFF) << 16 |
+			((fe_cfg->buf_height - 1) & 0x3FFF);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x314);
+
+		/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
+		switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
+		case V4L2_PIX_FMT_P16BGGR10:
+		case V4L2_PIX_FMT_P16GBRG10:
+		case V4L2_PIX_FMT_P16GRBG10:
+		case V4L2_PIX_FMT_P16RGGB10:
+			main_unpack_pattern = 0xB210;
+			break;
+		default:
+			main_unpack_pattern = 0xF6543210;
+			break;
+		}
+		msm_camera_io_w(main_unpack_pattern,
+			vfe_dev->vfe_base + 0x318);
+		msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x334);
+
+		temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+		temp |= 2 << 5;
+		temp |= 128 << 8;
+		temp |= (pix_cfg->pixel_pattern & 0x3);
+		msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+	} else {
+		pr_err("%s: Invalid mux configuration - mux: %d", __func__,
+			pix_cfg->input_mux);
+	}
+}
+
+void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev,
+	struct msm_vfe_testgen_cfg *testgen_cfg)
+{
+	uint32_t temp;
+	uint32_t bit_per_pixel = 0;
+	uint32_t bpp_reg = 0;
+	uint32_t bayer_pix_pattern_reg = 0;
+	uint32_t unicolorbar_reg = 0;
+	uint32_t unicolor_enb = 0;
+
+	bit_per_pixel = msm_isp_get_bit_per_pixel(
+		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format);
+
+	switch (bit_per_pixel) {
+	case 8:
+		bpp_reg = 0x0;
+		break;
+	case 10:
+		bpp_reg = 0x1;
+		break;
+	case 12:
+		bpp_reg = 0x10;
+		break;
+	case 14:
+		bpp_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid bpp %d\n", __func__, bit_per_pixel);
+		break;
+	}
+
+	msm_camera_io_w(bpp_reg << 16 | testgen_cfg->burst_num_frame,
+		vfe_dev->vfe_base + 0xC5C);
+
+	msm_camera_io_w(((testgen_cfg->lines_per_frame - 1) << 16) |
+		(testgen_cfg->pixels_per_line - 1), vfe_dev->vfe_base + 0xC60);
+
+	temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+	temp |= (((testgen_cfg->h_blank) & 0x3FFF) << 8);
+	temp |= (1 << 22);
+	msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
+
+	msm_camera_io_w((1 << 16) | testgen_cfg->v_blank,
+		vfe_dev->vfe_base + 0xC70);
+
+	switch (testgen_cfg->pixel_bayer_pattern) {
+	case ISP_BAYER_RGRGRG:
+		bayer_pix_pattern_reg = 0x0;
+		break;
+	case ISP_BAYER_GRGRGR:
+		bayer_pix_pattern_reg = 0x1;
+		break;
+	case ISP_BAYER_BGBGBG:
+		bayer_pix_pattern_reg = 0x10;
+		break;
+	case ISP_BAYER_GBGBGB:
+		bayer_pix_pattern_reg = 0x11;
+		break;
+	default:
+		pr_err("%s: invalid pix pattern %d\n",
+			__func__, bit_per_pixel);
+		break;
+	}
+
+	if (testgen_cfg->color_bar_pattern == COLOR_BAR_8_COLOR) {
+		unicolor_enb = 0x0;
+	} else {
+		unicolor_enb = 0x1;
+		switch (testgen_cfg->color_bar_pattern) {
+		case UNICOLOR_WHITE:
+			unicolorbar_reg = 0x0;
+			break;
+		case UNICOLOR_YELLOW:
+			unicolorbar_reg = 0x1;
+			break;
+		case UNICOLOR_CYAN:
+			unicolorbar_reg = 0x10;
+			break;
+		case UNICOLOR_GREEN:
+			unicolorbar_reg = 0x11;
+			break;
+		case UNICOLOR_MAGENTA:
+			unicolorbar_reg = 0x100;
+			break;
+		case UNICOLOR_RED:
+			unicolorbar_reg = 0x101;
+			break;
+		case UNICOLOR_BLUE:
+			unicolorbar_reg = 0x110;
+			break;
+		case UNICOLOR_BLACK:
+			unicolorbar_reg = 0x111;
+			break;
+		default:
+			pr_err("%s: invalid colorbar %d\n",
+				__func__, testgen_cfg->color_bar_pattern);
+			break;
+		}
+	}
+
+	msm_camera_io_w((testgen_cfg->rotate_period << 8) |
+		(bayer_pix_pattern_reg << 6) | (unicolor_enb << 4) |
+		(unicolorbar_reg), vfe_dev->vfe_base + 0xC78);
+}
+
+void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint16_t first_pixel, last_pixel, first_line, last_line;
+	uint16_t epoch_line1;
+	struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
+	struct msm_vfe_testgen_cfg *testgen_cfg = &pix_cfg->testgen_cfg;
+	uint32_t val, subsample_period, subsample_pattern;
+	uint32_t irq_sub_period = 32;
+	uint32_t frame_sub_period = 32;
+	struct msm_vfe_camif_subsample_cfg *subsample_cfg =
+		&pix_cfg->camif_cfg.subsample_cfg;
+	uint16_t bus_sub_en = 0;
+
+	if (subsample_cfg->pixel_skip || subsample_cfg->line_skip)
+		bus_sub_en = 1;
+	else
+		bus_sub_en = 0;
+
+	vfe_dev->dual_vfe_enable = camif_cfg->is_split;
+
+	msm_camera_io_w(pix_cfg->input_mux << 5 | pix_cfg->pixel_pattern,
+		vfe_dev->vfe_base + 0x50);
+
+	first_pixel = camif_cfg->first_pixel;
+	last_pixel = camif_cfg->last_pixel;
+	first_line = camif_cfg->first_line;
+	last_line = camif_cfg->last_line;
+	epoch_line1 = camif_cfg->epoch_line1;
+
+	if ((epoch_line1 <= 0) || (epoch_line1 > last_line))
+		epoch_line1 = last_line - 50;
+
+	if ((last_line - epoch_line1) > 100)
+		epoch_line1 = last_line - 100;
+
+	subsample_period = camif_cfg->subsample_cfg.irq_subsample_period;
+	subsample_pattern = camif_cfg->subsample_cfg.irq_subsample_pattern;
+
+	if (pix_cfg->input_mux == TESTGEN)
+		msm_camera_io_w((testgen_cfg->lines_per_frame - 1) << 16 |
+			(testgen_cfg->pixels_per_line - 1),
+			vfe_dev->vfe_base + 0x484);
+	else
+		msm_camera_io_w((camif_cfg->lines_per_frame - 1) << 16 |
+			(camif_cfg->pixels_per_line - 1),
+			vfe_dev->vfe_base + 0x484);
+
+	if (bus_sub_en) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C);
+		val &= 0xFFFFFFDF;
+		val = val | bus_sub_en << 5;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x47C);
+		subsample_cfg->pixel_skip &= 0x0000FFFF;
+		subsample_cfg->line_skip  &= 0x0000FFFF;
+		msm_camera_io_w((subsample_cfg->line_skip << 16) |
+			subsample_cfg->pixel_skip, vfe_dev->vfe_base + 0x490);
+	}
+
+
+	msm_camera_io_w(first_pixel << 16 | last_pixel,
+	vfe_dev->vfe_base + 0x488);
+
+	msm_camera_io_w(first_line << 16 | last_line,
+	vfe_dev->vfe_base + 0x48C);
+
+	/* configure EPOCH0: 20 lines, and
+	 * configure EPOCH1: epoch_line1 before EOF
+	 */
+	msm_camera_io_w_mb(0x140000 | epoch_line1,
+		vfe_dev->vfe_base + 0x4A0);
+	pr_debug("%s:%d: epoch_line1: %d\n",
+		__func__, __LINE__, epoch_line1);
+	msm_camera_io_w(((irq_sub_period - 1) << 8) | 0 << 5 |
+		(frame_sub_period - 1), vfe_dev->vfe_base + 0x494);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x498);
+	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x49C);
+	if (subsample_period && subsample_pattern) {
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x494);
+		val &= 0xFFFFE0FF;
+		val |= (subsample_period - 1) << 8;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x494);
+		ISP_DBG("%s:camif PERIOD %x PATTERN %x\n",
+			__func__,  subsample_period, subsample_pattern);
+
+		val = subsample_pattern;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x49C);
+	} else {
+		msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x49C);
+	}
+
+	if (subsample_cfg->first_pixel ||
+		subsample_cfg->last_pixel ||
+		subsample_cfg->first_line ||
+		subsample_cfg->last_line) {
+		msm_camera_io_w(
+		subsample_cfg->first_pixel << 16 |
+			subsample_cfg->last_pixel,
+			vfe_dev->vfe_base + 0xCE4);
+		msm_camera_io_w(
+		subsample_cfg->first_line << 16 |
+			subsample_cfg->last_line,
+			vfe_dev->vfe_base + 0xCE8);
+		val = msm_camera_io_r(
+			vfe_dev->vfe_base + 0x47C);
+		ISP_DBG("%s: camif raw crop enabled\n", __func__);
+		val |= 1 << 22;
+		msm_camera_io_w(val,
+			vfe_dev->vfe_base + 0x47C);
+	}
+
+	ISP_DBG("%s: camif raw op fmt %d\n",
+		__func__, subsample_cfg->output_format);
+	/* Pdaf output can be sent in below formats */
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x88);
+	switch (subsample_cfg->output_format) {
+	case CAMIF_PLAIN_8:
+		val |= PLAIN8 << 9;
+		break;
+	case CAMIF_PLAIN_16:
+		val |= PLAIN16 << 9;
+		break;
+	case CAMIF_MIPI_RAW:
+		val |= MIPI << 9;
+		break;
+	case CAMIF_QCOM_RAW:
+		val |= QCOM << 9;
+		break;
+	default:
+		break;
+	}
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x88);
+
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x46C);
+	val |= camif_cfg->camif_input;
+	msm_camera_io_w(val, vfe_dev->vfe_base + 0x46C);
+}
+
+void msm_vfe47_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg)
+{
+	uint32_t core_cfg = 0;
+	uint32_t val = 0;
+
+	core_cfg =  msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+	core_cfg &= 0xFFFFFF9F;
+
+	switch (pix_cfg->input_mux) {
+	case CAMIF:
+		core_cfg |= 0x0 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe47_cfg_camif(vfe_dev, pix_cfg);
+		break;
+	case TESTGEN:
+		/* Change CGC override */
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+		val |= (1 << 31);
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x3C);
+
+		/* CAMIF and TESTGEN will both go thorugh CAMIF*/
+		core_cfg |= 0x1 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe47_cfg_camif(vfe_dev, pix_cfg);
+		msm_vfe47_cfg_testgen(vfe_dev, &pix_cfg->testgen_cfg);
+		break;
+	case EXTERNAL_READ:
+		core_cfg |= 0x2 << 5;
+		msm_camera_io_w_mb(core_cfg, vfe_dev->vfe_base + 0x50);
+		msm_vfe47_cfg_fetch_engine(vfe_dev, pix_cfg);
+		break;
+	default:
+		pr_err("%s: Unsupported input mux %d\n",
+			__func__, pix_cfg->input_mux);
+		break;
+	}
+}
+
+void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
+	uint8_t is_stream_on)
+{
+	uint32_t val;
+	int rc = 0;
+
+	if (is_stream_on == vfe_dev->cur_hvx_state) {
+		ISP_DBG("already in same hvx state\n");
+		return;
+	}
+	if (vfe_dev->buf_mgr->secure_enable == SECURE_MODE) {
+		pr_err("%s: Cannot configure hvx, secure_mode: %d\n",
+			__func__,
+			vfe_dev->buf_mgr->secure_enable);
+		return;
+	}
+	if (!vfe_dev->hvx_clk) {
+		pr_err("%s: no stream_clk\n", __func__);
+		return;
+	}
+	if (is_stream_on) {
+		/* Enable HVX */
+		if (!vfe_dev->hvx_clk_state) {
+			rc = msm_camera_clk_enable(&vfe_dev->pdev->dev,
+				vfe_dev->hvx_clk_info, vfe_dev->hvx_clk,
+				vfe_dev->num_hvx_clk, is_stream_on);
+			if (rc) {
+				pr_err("%s: stream_clk enable failed\n",
+						__func__);
+				return;
+			}
+			vfe_dev->hvx_clk_state = true;
+		}
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+		val |= (1 << 3);
+		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
+		val &= 0xFF7FFFFF;
+		if (vfe_dev->hvx_cmd == HVX_ROUND_TRIP)
+			val |= (1 << 23);
+		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
+	} else {
+		/* Disable HVX */
+		if (!vfe_dev->hvx_clk_state)
+			return;
+		rc = msm_camera_clk_enable(&vfe_dev->pdev->dev,
+			vfe_dev->hvx_clk_info, vfe_dev->hvx_clk,
+			vfe_dev->num_hvx_clk, is_stream_on);
+		if (rc) {
+			pr_err("%s: stream_clk disable failed\n",
+					__func__);
+			return;
+		}
+		vfe_dev->hvx_clk_state = false;
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
+		val &= 0xFFFFFFF7;
+		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
+	}
+	vfe_dev->cur_hvx_state = is_stream_on;
+}
+
+void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state)
+{
+	uint32_t val;
+	bool bus_en, vfe_en;
+
+	if (update_state == NO_UPDATE)
+		return;
+
+	val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C);
+	if (update_state == ENABLE_CAMIF) {
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+					0x1F, 0x91,
+					MSM_ISP_IRQ_ENABLE);
+
+		if ((vfe_dev->hvx_cmd > HVX_DISABLE) &&
+			(vfe_dev->hvx_cmd <= HVX_ROUND_TRIP))
+			msm_vfe47_configure_hvx(vfe_dev, 1);
+		else
+			msm_vfe47_configure_hvx(vfe_dev, 0);
+
+		bus_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
+		vfe_en =
+			((vfe_dev->axi_data.
+			src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C);
+		val &= 0xFFFFFF3F;
+		val = val | bus_en << 7 | vfe_en << 6;
+		msm_camera_io_w(val, vfe_dev->vfe_base + 0x47C);
+		msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x478);
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x478);
+		/* testgen GO*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1, vfe_dev->vfe_base + 0xC58);
+	} else if (update_state == DISABLE_CAMIF ||
+		update_state == DISABLE_CAMIF_IMMEDIATELY) {
+		uint32_t poll_val;
+
+		/* For testgen always halt on camif boundary */
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			update_state = DISABLE_CAMIF;
+		/* turn off camif, violation and write master overwrite irq */
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev, 0, 0x91,
+					MSM_ISP_IRQ_DISABLE);
+		val = msm_camera_io_r(vfe_dev->vfe_base + 0x464);
+		/* disable danger signal */
+		msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464);
+		msm_camera_io_w_mb((update_state == DISABLE_CAMIF ? 0x0 : 0x6),
+				vfe_dev->vfe_base + 0x478);
+		if (readl_poll_timeout_atomic(vfe_dev->vfe_base + 0x4A4,
+			poll_val, poll_val & 0x80000000, 1000, 2000000))
+			pr_err("%s: camif disable failed %x\n",
+				__func__, poll_val);
+		/* testgen OFF*/
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
+			msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0xC58);
+
+		if ((vfe_dev->hvx_cmd > HVX_DISABLE) &&
+			(vfe_dev->hvx_cmd <= HVX_ROUND_TRIP))
+			msm_vfe47_configure_hvx(vfe_dev, 0);
+
+	}
+}
+
+void msm_vfe47_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src)
+{
+	uint8_t rdi = input_src - VFE_RAW_0;
+	uint32_t rdi_reg_cfg;
+
+	rdi_reg_cfg = msm_camera_io_r(
+		vfe_dev->vfe_base + VFE47_RDI_BASE(rdi));
+	rdi_reg_cfg &= 0x3;
+	rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 1 << 2;
+	msm_camera_io_w(
+		rdi_reg_cfg, vfe_dev->vfe_base + VFE47_RDI_BASE(rdi));
+}
+
+void msm_vfe47_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	uint32_t val;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+	val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0x14);
+	val &= ~0x2;
+	if (stream_info->frame_based)
+		val |= 0x2;
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	if (!stream_info->frame_based) {
+		/* WR_IMAGE_SIZE */
+		val = ((msm_isp_cal_word_per_line(
+			stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_width)+3)/4 - 1) << 16 |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_height - 1);
+		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C);
+		/* WR_BUFFER_CFG */
+		val = VFE47_BURST_LEN |
+			(stream_info->plane_cfg[vfe_idx][plane_idx].
+							output_height - 1) <<
+			2 |
+			((msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[vfe_idx][plane_idx].
+			output_stride)+1)/2) << 16;
+	}
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + wm_base + 0x28);
+}
+
+void msm_vfe47_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	uint32_t val = 0;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint32_t wm_base;
+
+	wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
+	/* WR_ADDR_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+	/* WR_IMAGE_SIZE */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C);
+	/* WR_BUFFER_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x28);
+}
+
+void msm_vfe47_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	struct msm_vfe_axi_plane_cfg *plane_cfg;
+	uint8_t wm;
+	uint32_t xbar_cfg = 0;
+	uint32_t xbar_reg_cfg = 0;
+
+	plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx];
+	wm = stream_info->wm[vfe_idx][plane_idx];
+	switch (stream_info->stream_src) {
+	case PIX_VIDEO:
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER: {
+		if (plane_cfg->output_plane_format != CRCB_PLANE &&
+			plane_cfg->output_plane_format != CBCR_PLANE) {
+			/* SINGLE_STREAM_SEL */
+			xbar_cfg |= plane_cfg->output_plane_format << 8;
+		} else {
+			switch (stream_info->output_format) {
+			case V4L2_PIX_FMT_NV12:
+			case V4L2_PIX_FMT_NV14:
+			case V4L2_PIX_FMT_NV16:
+			case V4L2_PIX_FMT_NV24:
+				/* PAIR_STREAM_SWAP_CTRL */
+				xbar_cfg |= 0x3 << 4;
+				break;
+			}
+			xbar_cfg |= 0x1 << 2; /* PAIR_STREAM_EN */
+		}
+		if (stream_info->stream_src == PIX_VIEWFINDER)
+			xbar_cfg |= 0x1; /* VIEW_STREAM_EN */
+		else if (stream_info->stream_src == PIX_VIDEO)
+			xbar_cfg |= 0x2;
+		break;
+	}
+	case CAMIF_RAW:
+		xbar_cfg = 0x300;
+		break;
+	case IDEAL_RAW:
+		xbar_cfg = 0x400;
+		break;
+	case RDI_INTF_0:
+		xbar_cfg = 0xC00;
+		break;
+	case RDI_INTF_1:
+		xbar_cfg = 0xD00;
+		break;
+	case RDI_INTF_2:
+		xbar_cfg = 0xE00;
+		break;
+	default:
+		pr_err("%s: Invalid stream src\n", __func__);
+		break;
+	}
+
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE47_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE47_XBAR_SHIFT(wm));
+	xbar_reg_cfg |= (xbar_cfg << VFE47_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE47_XBAR_BASE(wm));
+}
+
+void msm_vfe47_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	uint8_t wm;
+	uint32_t xbar_reg_cfg = 0;
+
+	wm = stream_info->wm[vfe_idx][plane_idx];
+	xbar_reg_cfg =
+		msm_camera_io_r(vfe_dev->vfe_base + VFE47_XBAR_BASE(wm));
+	xbar_reg_cfg &= ~(0xFFFF << VFE47_XBAR_SHIFT(wm));
+	msm_camera_io_w(xbar_reg_cfg,
+		vfe_dev->vfe_base + VFE47_XBAR_BASE(wm));
+}
+
+
+void msm_vfe47_cfg_axi_ub_equal_default(
+	struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	int i;
+	uint32_t ub_offset = 0;
+	struct msm_vfe_axi_shared_data *axi_data =
+		&vfe_dev->axi_data;
+	uint32_t total_image_size = 0;
+	uint8_t num_used_wms = 0;
+	uint32_t prop_size = 0;
+	uint32_t wm_ub_size;
+	uint64_t delta;
+
+	if (frame_src == VFE_PIX_0) {
+		for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+			if (axi_data->free_wm[i] &&
+				SRC_TO_INTF(
+				HANDLE_TO_IDX(axi_data->free_wm[i])) ==
+				VFE_PIX_0) {
+				num_used_wms++;
+				total_image_size +=
+					axi_data->wm_image_size[i];
+			}
+		}
+		ub_offset = (axi_data->hw_info->num_rdi * 2) *
+			axi_data->hw_info->min_wm_ub;
+		prop_size = vfe_dev->hw_info->vfe_ops.axi_ops.
+			get_ub_size(vfe_dev) -
+			axi_data->hw_info->min_wm_ub * (num_used_wms +
+			axi_data->hw_info->num_rdi * 2);
+	}
+
+	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+		if (!axi_data->free_wm[i]) {
+			msm_camera_io_w(0,
+				vfe_dev->vfe_base +
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+						ub_reg_offset(vfe_dev, i));
+			continue;
+		}
+
+		if (frame_src != SRC_TO_INTF(
+			HANDLE_TO_IDX(axi_data->free_wm[i])))
+			continue;
+
+		if (frame_src == VFE_PIX_0) {
+			if (total_image_size) {
+				delta = (uint64_t)axi_data->wm_image_size[i] *
+					(uint64_t)prop_size;
+					do_div(delta, total_image_size);
+				wm_ub_size = axi_data->hw_info->min_wm_ub +
+					(uint32_t)delta;
+				msm_camera_io_w(ub_offset << 16 |
+					(wm_ub_size - 1),
+					vfe_dev->vfe_base +
+					vfe_dev->hw_info->vfe_ops.axi_ops.
+						ub_reg_offset(vfe_dev, i));
+				ub_offset += wm_ub_size;
+			} else {
+				pr_err("%s: image size is zero\n", __func__);
+			}
+		} else {
+			uint32_t rdi_ub_offset;
+			int plane;
+			int vfe_idx;
+			struct msm_vfe_axi_stream *stream_info;
+
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+					HANDLE_TO_IDX(axi_data->free_wm[i]));
+			if (!stream_info) {
+				pr_err("%s: stream_info is NULL!", __func__);
+				return;
+			}
+			vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev,
+							stream_info);
+			for (plane = 0; plane < stream_info->num_planes;
+				plane++)
+				if (stream_info->wm[vfe_idx][plane] ==
+					axi_data->free_wm[i])
+					break;
+
+			rdi_ub_offset = (SRC_TO_INTF(
+					HANDLE_TO_IDX(axi_data->free_wm[i])) -
+					VFE_RAW_0) *
+					axi_data->hw_info->min_wm_ub * 2;
+			wm_ub_size = axi_data->hw_info->min_wm_ub * 2;
+			msm_camera_io_w(rdi_ub_offset << 16 | (wm_ub_size - 1),
+				vfe_dev->vfe_base +
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+						ub_reg_offset(vfe_dev, i));
+		}
+	}
+}
+
+void msm_vfe47_cfg_axi_ub_equal_slicing(
+	struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = 0;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	uint32_t ub_equal_slice = 0;
+
+	ub_equal_slice = vfe_dev->hw_info->vfe_ops.axi_ops.
+				get_ub_size(vfe_dev) /
+				axi_data->hw_info->num_wm;
+	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+		msm_camera_io_w(ub_offset << 16 | (ub_equal_slice - 1),
+			vfe_dev->vfe_base +
+			vfe_dev->hw_info->vfe_ops.axi_ops.
+					ub_reg_offset(vfe_dev, i));
+		ub_offset += ub_equal_slice;
+	}
+}
+
+void msm_vfe47_cfg_axi_ub(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
+	if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
+		msm_vfe47_cfg_axi_ub_equal_slicing(vfe_dev);
+	else
+		msm_vfe47_cfg_axi_ub_equal_default(vfe_dev, frame_src);
+}
+
+void msm_vfe47_read_wm_ping_pong_addr(
+	struct vfe_device *vfe_dev)
+{
+	msm_camera_io_dump(vfe_dev->vfe_base +
+		(VFE47_WM_BASE(0) & 0xFFFFFFF0), 0x200, 1);
+}
+
+void msm_vfe47_update_ping_pong_addr(
+	void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size)
+{
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	uint32_t paddr32_max = 0;
+
+	if (buf_size < 0)
+		buf_size = 0;
+
+	paddr32_max = (paddr + buf_size) & 0xFFFFFFE0;
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE47_PING_PONG_BASE(wm_idx, pingpong_bit));
+	msm_camera_io_w(paddr32_max, vfe_base +
+		VFE47_PING_PONG_BASE(wm_idx, pingpong_bit) + 0x4);
+
+}
+
+void msm_vfe47_set_halt_restart_mask(struct vfe_device *vfe_dev)
+{
+	msm_vfe47_config_irq(vfe_dev, BIT(31), BIT(8), MSM_ISP_IRQ_SET);
+}
+
+int msm_vfe47_axi_halt(struct vfe_device *vfe_dev,
+	uint32_t blocking)
+{
+	int rc = 0;
+	enum msm_vfe_input_src i;
+	uint32_t val = 0;
+	struct msm_isp_timestamp ts;
+
+	val = msm_camera_io_r(vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET);
+	val |= 0x1;
+	msm_camera_io_w(val, vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET);
+
+	/* Keep only halt and reset mask */
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				(1 << 31), (1 << 8),
+				MSM_ISP_IRQ_SET);
+
+	if (atomic_read(&vfe_dev->error_info.overflow_state)
+		== OVERFLOW_DETECTED)
+		pr_err_ratelimited("%s: VFE%d halt for recovery, blocking %d\n",
+			__func__, vfe_dev->pdev->id, blocking);
+
+	if (blocking) {
+		init_completion(&vfe_dev->halt_complete);
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400);
+		rc = wait_for_completion_interruptible_timeout(
+			&vfe_dev->halt_complete, msecs_to_jiffies(500));
+		if (rc <= 0)
+			pr_err("%s:VFE%d halt timeout rc=%d\n", __func__,
+				vfe_dev->pdev->id, rc);
+
+	} else {
+		/* Halt AXI Bus Bridge */
+		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400);
+	}
+
+	msm_isp_get_timestamp(&ts, vfe_dev);
+	for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) {
+		/* if any stream is waiting for update, signal fake completes */
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+		msm_isp_axi_stream_update(vfe_dev, i, &ts);
+	}
+
+	msm_isp_stats_stream_update(vfe_dev);
+	msm_isp_stats_stream_update(vfe_dev);
+
+	return rc;
+}
+
+void msm_vfe47_axi_restart(struct vfe_device *vfe_dev,
+	uint32_t blocking, uint32_t enable_camif)
+{
+	vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+			vfe_dev->recovery_irq0_mask,
+			vfe_dev->recovery_irq1_mask,
+			MSM_ISP_IRQ_ENABLE);
+	/* Start AXI */
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x400);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, VFE_SRC_MAX);
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+	if (enable_camif)
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, ENABLE_CAMIF);
+}
+
+uint32_t msm_vfe47_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 8) & 0x7F;
+}
+
+uint32_t msm_vfe47_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 25) & 0xF;
+}
+
+uint32_t msm_vfe47_get_pingpong_status(
+	struct vfe_device *vfe_dev)
+{
+	return msm_camera_io_r(vfe_dev->vfe_base + 0x338);
+}
+
+int msm_vfe47_get_stats_idx(enum msm_isp_stats_type stats_type)
+{
+	/*idx use for composite, need to map to irq status*/
+	switch (stats_type) {
+	case MSM_ISP_STATS_HDR_BE:
+		return STATS_COMP_IDX_HDR_BE;
+	case MSM_ISP_STATS_BG:
+		return STATS_COMP_IDX_BG;
+	case MSM_ISP_STATS_BF:
+		return STATS_COMP_IDX_BF;
+	case MSM_ISP_STATS_HDR_BHIST:
+		return STATS_COMP_IDX_HDR_BHIST;
+	case MSM_ISP_STATS_RS:
+		return STATS_COMP_IDX_RS;
+	case MSM_ISP_STATS_CS:
+		return STATS_COMP_IDX_CS;
+	case MSM_ISP_STATS_IHIST:
+		return STATS_COMP_IDX_IHIST;
+	case MSM_ISP_STATS_BHIST:
+		return STATS_COMP_IDX_BHIST;
+	case MSM_ISP_STATS_AEC_BG:
+		return STATS_COMP_IDX_AEC_BG;
+	default:
+		pr_err("%s: Invalid stats type\n", __func__);
+		return -EINVAL;
+	}
+}
+
+int msm_vfe47_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	return 0;
+}
+
+void msm_vfe47_stats_cfg_comp_mask(
+	struct vfe_device *vfe_dev, uint32_t stats_mask,
+	uint8_t request_comp_index, uint8_t enable)
+{
+	uint32_t comp_mask_reg;
+	atomic_t *stats_comp_mask;
+	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask < 1)
+		return;
+
+	if (request_comp_index >= MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__, request_comp_index,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask >
+			MAX_NUM_STATS_COMP_MASK) {
+		pr_err("%s: num of comp masks %d exceed max %d\n",
+			__func__,
+			vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask,
+			MAX_NUM_STATS_COMP_MASK);
+		return;
+	}
+
+	stats_mask = stats_mask & 0x1FF;
+
+	stats_comp_mask = &stats_data->stats_comp_mask[request_comp_index];
+	comp_mask_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x78);
+
+	if (enable) {
+		comp_mask_reg |= stats_mask << (request_comp_index * 16);
+		atomic_set(stats_comp_mask, stats_mask |
+				atomic_read(stats_comp_mask));
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << (29 + request_comp_index),
+				0, MSM_ISP_IRQ_ENABLE);
+	} else {
+		if (!(atomic_read(stats_comp_mask) & stats_mask))
+			return;
+
+		atomic_set(stats_comp_mask,
+				~stats_mask & atomic_read(stats_comp_mask));
+		comp_mask_reg &= ~(stats_mask << (request_comp_index * 16));
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << (29 + request_comp_index),
+				0, MSM_ISP_IRQ_DISABLE);
+	}
+
+	msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78);
+
+	ISP_DBG("%s: comp_mask_reg: %x comp mask0 %x mask1: %x\n",
+		__func__, comp_mask_reg,
+		atomic_read(&stats_data->stats_comp_mask[0]),
+		atomic_read(&stats_data->stats_comp_mask[1]));
+
+}
+
+void msm_vfe47_stats_cfg_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+					stream_info);
+
+	switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) {
+	case STATS_COMP_IDX_AEC_BG:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 15, 1 << 24, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_HDR_BE:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 16, 1 << 16, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_BG:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 17, 1 << 17, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_BF:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 18, 1 << 26 | 1 << 18,
+				MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_HDR_BHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 19, 1 << 19, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_RS:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 20, 1 << 20, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_CS:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 21, 1 << 21, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_IHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 22, 1 << 22, MSM_ISP_IRQ_ENABLE);
+		break;
+	case STATS_COMP_IDX_BHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 23, 1 << 23, MSM_ISP_IRQ_ENABLE);
+		break;
+	default:
+		pr_err("%s: Invalid stats idx %d\n", __func__,
+			STATS_IDX(stream_info->stream_handle[vfe_idx]));
+	}
+}
+
+void msm_vfe47_stats_clear_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+
+	switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) {
+	case STATS_COMP_IDX_AEC_BG:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 15, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_HDR_BE:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 16, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_BG:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 17, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_BF:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 18, 1 << 26,
+				MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_HDR_BHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 19, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_RS:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 20, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_CS:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 21, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_IHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 22, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	case STATS_COMP_IDX_BHIST:
+		vfe_dev->hw_info->vfe_ops.irq_ops.config_irq(vfe_dev,
+				1 << 23, 0, MSM_ISP_IRQ_DISABLE);
+		break;
+	default:
+		pr_err("%s: Invalid stats idx %d\n", __func__,
+			STATS_IDX(stream_info->stream_handle[vfe_idx]));
+	}
+}
+
+void msm_vfe47_stats_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE47_STATS_BASE(stats_idx);
+
+	/* WR_ADDR_CFG */
+	msm_camera_io_w((stream_info->framedrop_period - 1) << 2,
+		vfe_dev->vfe_base + stats_base + 0x10);
+	/* WR_IRQ_FRAMEDROP_PATTERN */
+	msm_camera_io_w(stream_info->framedrop_pattern,
+		vfe_dev->vfe_base + stats_base + 0x18);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(0xFFFFFFFF,
+		vfe_dev->vfe_base + stats_base + 0x1C);
+}
+
+void msm_vfe47_stats_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+				stream_info);
+	uint32_t val = 0;
+	int stats_idx;
+	uint32_t stats_base;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+	stats_base = VFE47_STATS_BASE(stats_idx);
+
+	/* WR_ADDR_CFG */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10);
+	/* WR_IRQ_FRAMEDROP_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x18);
+	/* WR_IRQ_SUBSAMPLE_PATTERN */
+	msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x1C);
+}
+
+void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = 0;
+	uint32_t ub_size[VFE47_NUM_STATS_TYPE] = {
+		16, /* MSM_ISP_STATS_HDR_BE */
+		16, /* MSM_ISP_STATS_BG */
+		16, /* MSM_ISP_STATS_BF */
+		16, /* MSM_ISP_STATS_HDR_BHIST */
+		16, /* MSM_ISP_STATS_RS */
+		16, /* MSM_ISP_STATS_CS */
+		16, /* MSM_ISP_STATS_IHIST */
+		16, /* MSM_ISP_STATS_BHIST */
+		16, /* MSM_ISP_STATS_AEC_BG */
+	};
+	if (vfe_dev->pdev->id == ISP_VFE1)
+		ub_offset = VFE47_UB_SIZE_VFE1;
+	else if (vfe_dev->pdev->id == ISP_VFE0)
+		ub_offset = VFE47_UB_SIZE_VFE0;
+	else
+		pr_err("%s: incorrect VFE device\n", __func__);
+
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(VFE47_STATS_BURST_LEN << 30 |
+			ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE47_STATS_BASE(i) + 0x14);
+	}
+}
+
+void msm_vfe47_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, cgc_mask = 0;
+
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_COMP_IDX_HDR_BE:
+				cgc_mask |= 1;
+				break;
+			case STATS_COMP_IDX_BG:
+				cgc_mask |= (1 << 3);
+				break;
+			case STATS_COMP_IDX_BHIST:
+				cgc_mask |= (1 << 4);
+				break;
+			case STATS_COMP_IDX_RS:
+				cgc_mask |= (1 << 5);
+				break;
+			case STATS_COMP_IDX_CS:
+				cgc_mask |= (1 << 6);
+				break;
+			case STATS_COMP_IDX_IHIST:
+				cgc_mask |= (1 << 7);
+				break;
+			case STATS_COMP_IDX_AEC_BG:
+				cgc_mask |= (1 << 8);
+				break;
+			case STATS_COMP_IDX_BF:
+				cgc_mask |= (1 << 2);
+				break;
+			case STATS_COMP_IDX_HDR_BHIST:
+				cgc_mask |= (1 << 1);
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	/* CGC override: enforce BAF for DMI */
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
+	if (enable)
+		module_cfg |= cgc_mask;
+	else
+		module_cfg &= ~cgc_mask;
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x30);
+}
+
+bool msm_vfe47_is_module_cfg_lock_needed(
+	uint32_t reg_offset)
+{
+	return false;
+}
+
+void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+	uint32_t module_cfg, module_cfg_mask = 0;
+
+	/* BF stats involve DMI cfg, ignore*/
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
+		if ((stats_mask >> i) & 0x1) {
+			switch (i) {
+			case STATS_COMP_IDX_HDR_BE:
+				module_cfg_mask |= 1;
+				break;
+			case STATS_COMP_IDX_HDR_BHIST:
+				module_cfg_mask |= 1 << 1;
+				break;
+			case STATS_COMP_IDX_BF:
+				module_cfg_mask |= 1 << 2;
+				break;
+			case STATS_COMP_IDX_BG:
+				module_cfg_mask |= 1 << 3;
+				break;
+			case STATS_COMP_IDX_BHIST:
+				module_cfg_mask |= 1 << 4;
+				break;
+			case STATS_COMP_IDX_RS:
+				module_cfg_mask |= 1 << 5;
+				break;
+			case STATS_COMP_IDX_CS:
+				module_cfg_mask |= 1 << 6;
+				break;
+			case STATS_COMP_IDX_IHIST:
+				module_cfg_mask |= 1 << 7;
+				break;
+			case STATS_COMP_IDX_AEC_BG:
+				module_cfg_mask |= 1 << 8;
+				break;
+			default:
+				pr_err("%s: Invalid stats mask\n", __func__);
+				return;
+			}
+		}
+	}
+
+	module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x44);
+	if (enable)
+		module_cfg |= module_cfg_mask;
+	else
+		module_cfg &= ~module_cfg_mask;
+
+	msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x44);
+	/* enable wm if needed */
+	if (vfe_dev->hw_info->vfe_ops.stats_ops.enable_stats_wm)
+		vfe_dev->hw_info->vfe_ops.stats_ops.enable_stats_wm(vfe_dev,
+						stats_mask, enable);
+}
+
+void msm_vfe47_stats_update_ping_pong_addr(
+	struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
+	uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size)
+{
+	void __iomem *vfe_base = vfe_dev->vfe_base;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
+			stream_info);
+	uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+	uint32_t paddr32_max;
+	int stats_idx;
+
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+
+	msm_camera_io_w(paddr32, vfe_base +
+		VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+
+	paddr32_max = (paddr + buf_size) & 0xFFFFFFE0;
+	msm_camera_io_w(paddr32_max, vfe_base +
+		VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status) + 0x4);
+}
+
+uint32_t msm_vfe47_stats_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	/* TODO: define  bf early done irq in status_0 and
+	 * bf pingpong done in  status_1
+	 */
+	uint32_t comp_mapped_irq_mask = 0;
+	int i = 0;
+
+	/* remove early done and handle separately,
+	 * add bf idx on status 1
+	 */
+	irq_status0 &= ~(1 << 18);
+
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++)
+		if ((irq_status0 >> stats_irq_map_comp_mask[i]) & 0x1)
+			comp_mapped_irq_mask |= (1 << i);
+	if ((irq_status1 >> 26) & 0x1)
+		comp_mapped_irq_mask |= (1 << STATS_COMP_IDX_BF);
+
+	return comp_mapped_irq_mask;
+}
+
+uint32_t msm_vfe47_stats_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	return (irq_status0 >> 29) & 0x3;
+}
+
+uint32_t msm_vfe47_stats_get_frame_id(
+	struct vfe_device *vfe_dev)
+{
+	return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+}
+
+void msm_vfe47_deinit_bandwidth_mgr(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	msm_bus_scale_client_update_request(
+	   isp_bandwidth_mgr->bus_client, 0);
+	msm_bus_scale_unregister_client(isp_bandwidth_mgr->bus_client);
+	isp_bandwidth_mgr->bus_client = 0;
+}
+
+int msm_vfe47_init_bandwidth_mgr(struct vfe_device *vfe_dev,
+	struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	int rc = 0;
+
+	isp_bandwidth_mgr->bus_client =
+		msm_bus_scale_register_client(&msm_isp_bus_client_pdata);
+	if (!isp_bandwidth_mgr->bus_client) {
+		pr_err("%s: client register failed\n", __func__);
+		return -EINVAL;
+	}
+	isp_bandwidth_mgr->bus_vector_active_idx = 1;
+	rc = msm_bus_scale_client_update_request(
+		isp_bandwidth_mgr->bus_client,
+		isp_bandwidth_mgr->bus_vector_active_idx);
+	if (rc)
+		msm_vfe47_deinit_bandwidth_mgr(isp_bandwidth_mgr);
+	return rc;
+}
+
+int msm_vfe47_update_bandwidth(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	int i;
+	uint64_t ab = 0;
+	uint64_t ib = 0;
+	struct msm_bus_paths *path = NULL;
+
+	ALT_VECTOR_IDX(isp_bandwidth_mgr->bus_vector_active_idx);
+	path = &(msm_isp_bus_client_pdata.usecase[
+			isp_bandwidth_mgr->bus_vector_active_idx]);
+	path->vectors[0].ab = 0;
+	path->vectors[0].ib = 0;
+	for (i = 0; i < MAX_ISP_CLIENT; i++) {
+		if (isp_bandwidth_mgr->client_info[i].active) {
+			path->vectors[0].ab +=
+				isp_bandwidth_mgr->client_info[i].ab;
+			path->vectors[0].ib +=
+				isp_bandwidth_mgr->client_info[i].ib;
+			ab += isp_bandwidth_mgr->client_info[i].ab;
+			ib += isp_bandwidth_mgr->client_info[i].ib;
+		}
+	}
+	msm_bus_scale_client_update_request(isp_bandwidth_mgr->bus_client,
+		isp_bandwidth_mgr->bus_vector_active_idx);
+	/* Insert into circular buffer */
+	msm_isp_update_req_history(isp_bandwidth_mgr->bus_client,
+		ab, ib,
+		isp_bandwidth_mgr->client_info,
+		sched_clock());
+	return 0;
+}
+
+int msm_vfe47_get_clks(struct vfe_device *vfe_dev)
+{
+	int i, rc;
+	struct clk *stream_clk;
+	struct msm_cam_clk_info clk_info;
+
+	rc = msm_camera_get_clk_info(vfe_dev->pdev, &vfe_dev->vfe_clk_info,
+			&vfe_dev->vfe_clk, &vfe_dev->num_clk);
+	if (rc)
+		return rc;
+
+	vfe_dev->num_norm_clk = vfe_dev->num_clk;
+	for (i = 0; i < vfe_dev->num_clk; i++) {
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+				"camss_vfe_stream_clk") == 0) {
+			stream_clk = vfe_dev->vfe_clk[i];
+			clk_info = vfe_dev->vfe_clk_info[i];
+			vfe_dev->num_hvx_clk = 1;
+			vfe_dev->num_norm_clk = vfe_dev->num_clk - 1;
+			break;
+		}
+	}
+	if (i >= vfe_dev->num_clk)
+		pr_err("%s: cannot find camss_vfe_stream_clk\n", __func__);
+	else {
+		/* Switch stream_clk to the last element*/
+		for (; i < vfe_dev->num_clk - 1; i++) {
+			vfe_dev->vfe_clk[i] = vfe_dev->vfe_clk[i+1];
+			vfe_dev->vfe_clk_info[i] = vfe_dev->vfe_clk_info[i+1];
+		}
+		vfe_dev->vfe_clk_info[vfe_dev->num_clk-1] = clk_info;
+		vfe_dev->vfe_clk[vfe_dev->num_clk-1] = stream_clk;
+		vfe_dev->hvx_clk_info =
+			&vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
+		vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+		vfe_dev->hvx_clk_state = false;
+	}
+
+	for (i = 0; i < vfe_dev->num_clk; i++) {
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+					"vfe_clk_src") == 0)
+			vfe_dev->hw_info->vfe_clk_idx = i;
+	}
+	return 0;
+}
+
+void msm_vfe47_put_clks(struct vfe_device *vfe_dev)
+{
+	msm_camera_put_clk_info(vfe_dev->pdev, &vfe_dev->vfe_clk_info,
+			&vfe_dev->vfe_clk, vfe_dev->num_clk);
+
+	vfe_dev->num_clk = 0;
+	vfe_dev->hvx_clk = NULL;
+	vfe_dev->hvx_clk_info = NULL;
+	vfe_dev->num_hvx_clk = 0;
+	vfe_dev->num_norm_clk = 0;
+}
+
+int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable)
+{
+	return msm_camera_clk_enable(&vfe_dev->pdev->dev,
+		vfe_dev->vfe_clk_info,
+		vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable);
+}
+
+int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
+{
+	int rc = 0;
+	int clk_idx = vfe_dev->hw_info->vfe_clk_idx;
+	int ret;
+	long clk_rate, prev_clk_rate;
+
+	clk_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
+	if (vfe_dev->vfe_clk_info[clk_idx].clk_rate == clk_rate)
+		return rc;
+
+	prev_clk_rate =
+		vfe_dev->vfe_clk_info[clk_idx].clk_rate;
+	vfe_dev->vfe_clk_info[clk_idx].clk_rate =
+		clk_rate;
+	/*
+	 * if cx_ipeak is supported vote first so that dsp throttling is
+	 * reduced before we go to turbo
+	 */
+	if ((vfe_dev->vfe_cx_ipeak) &&
+		(vfe_dev->vfe_clk_info[clk_idx].clk_rate >=
+		vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
+		[vfe_dev->hw_info->vfe_clk_idx]) &&
+		prev_clk_rate <
+		vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
+		[vfe_dev->hw_info->vfe_clk_idx]) {
+		ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true);
+		if (ret) {
+			pr_err("%s: cx_ipeak_update failed %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	/*set vfe clock*/
+	rc = msm_camera_clk_set_rate(&vfe_dev->pdev->dev,
+				vfe_dev->vfe_clk[clk_idx], *rate);
+	if (rc < 0)
+		return rc;
+	/*
+	 * if cx_ipeak is supported remove the vote for non-turbo clock and
+	 * if voting done earlier
+	 */
+	if ((vfe_dev->vfe_cx_ipeak) &&
+		(vfe_dev->vfe_clk_info[clk_idx].clk_rate <
+		vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
+		[vfe_dev->hw_info->vfe_clk_idx]) &&
+		prev_clk_rate >=
+		vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
+		[vfe_dev->hw_info->vfe_clk_idx]) {
+		ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false);
+		if (ret) {
+			pr_err("%s: cx_ipeak_update failed %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	if (vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg)
+		vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg(vfe_dev, NULL);
+	return 0;
+}
+
+int msm_vfe47_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate)
+{
+	int	   clk_idx = 0;
+	unsigned long max_value = ~0;
+	long	  round_rate = 0;
+
+	if (!vfe_dev || !rate) {
+		pr_err("%s:%d failed: vfe_dev %pK rate %pK\n", __func__,
+			__LINE__, vfe_dev, rate);
+		return -EINVAL;
+	}
+
+	*rate = 0;
+	if (!vfe_dev->hw_info) {
+		pr_err("%s:%d failed: vfe_dev->hw_info %pK\n", __func__,
+			__LINE__, vfe_dev->hw_info);
+		return -EINVAL;
+	}
+
+	clk_idx = vfe_dev->hw_info->vfe_clk_idx;
+	if (clk_idx >= vfe_dev->num_clk) {
+		pr_err("%s:%d failed: clk_idx %d max array size %zd\n",
+			__func__, __LINE__, clk_idx,
+			vfe_dev->num_clk);
+		return -EINVAL;
+	}
+
+	round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value);
+	if (round_rate < 0) {
+		pr_err("%s: Invalid vfe clock rate\n", __func__);
+		return -EINVAL;
+	}
+
+	*rate = round_rate;
+	return 0;
+}
+
+int msm_vfe47_get_clk_rates(struct vfe_device *vfe_dev,
+	struct msm_isp_clk_rates *rates)
+{
+	struct device_node *of_node;
+	int32_t  rc = 0;
+	uint32_t svs = 0, nominal = 0, turbo = 0;
+
+	if (!vfe_dev || !rates) {
+		pr_err("%s:%d failed: vfe_dev %pK rates %pK\n", __func__,
+			__LINE__, vfe_dev, rates);
+		return -EINVAL;
+	}
+
+	if (!vfe_dev->pdev) {
+		pr_err("%s:%d failed: vfe_dev->pdev %pK\n", __func__,
+			__LINE__, vfe_dev->pdev);
+		return -EINVAL;
+	}
+
+	of_node = vfe_dev->pdev->dev.of_node;
+
+	if (!of_node) {
+		pr_err("%s %d failed: of_node = %pK\n", __func__,
+		 __LINE__, of_node);
+		return -EINVAL;
+	}
+
+	/*
+	 * Many older targets dont define svs.
+	 * return svs=0 for older targets.
+	 */
+	rc = of_property_read_u32(of_node, "max-clk-svs",
+		&svs);
+	if (rc < 0)
+		svs = 0;
+
+	rc = of_property_read_u32(of_node, "max-clk-nominal",
+		&nominal);
+	if (rc < 0 || !nominal) {
+		pr_err("%s: nominal rate error\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(of_node, "max-clk-turbo",
+		&turbo);
+	if (rc < 0 || !turbo) {
+		pr_err("%s: turbo rate error\n", __func__);
+			return -EINVAL;
+	}
+	rates->svs_rate = svs;
+	rates->nominal_rate = nominal;
+	rates->high_rate = turbo;
+	return 0;
+}
+
+void msm_vfe47_put_regulators(struct vfe_device *vfe_dev)
+{
+	int i;
+
+	for (i = 0; i < vfe_dev->vfe_num_regulators; i++)
+		regulator_put(vfe_dev->regulator_info[i].vdd);
+
+	vfe_dev->vfe_num_regulators = 0;
+	kfree(vfe_dev->regulator_info);
+	vfe_dev->regulator_info = NULL;
+}
+
+int msm_vfe47_get_regulators(struct vfe_device *vfe_dev)
+{
+	int rc = 0;
+	int i;
+
+	vfe_dev->vfe_num_regulators =
+		sizeof(*vfe_dev->hw_info->regulator_names) / sizeof(char *);
+
+	vfe_dev->regulator_info = kzalloc(sizeof(struct msm_cam_regulator) *
+				vfe_dev->vfe_num_regulators, GFP_KERNEL);
+	if (!vfe_dev->regulator_info)
+		return -ENOMEM;
+
+	for (i = 0; i < vfe_dev->vfe_num_regulators; i++) {
+		vfe_dev->regulator_info[i].vdd = regulator_get(
+					&vfe_dev->pdev->dev,
+					vfe_dev->hw_info->regulator_names[i]);
+		if (IS_ERR(vfe_dev->regulator_info[i].vdd)) {
+			pr_err("%s: Regulator vfe get failed %ld\n", __func__,
+			PTR_ERR(vfe_dev->regulator_info[i].vdd));
+			rc = -ENODEV;
+			goto reg_get_fail;
+		}
+	}
+	return 0;
+
+reg_get_fail:
+	for (i--; i >= 0; i--)
+		regulator_put(vfe_dev->regulator_info[i].vdd);
+	kfree(vfe_dev->regulator_info);
+	vfe_dev->regulator_info = NULL;
+	return rc;
+}
+
+int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable)
+{
+	return msm_camera_regulator_enable(vfe_dev->regulator_info,
+					vfe_dev->vfe_num_regulators, enable);
+}
+
+int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev)
+{
+	int rc = 0;
+	void __iomem *vfe_fuse_base;
+	uint32_t vfe_fuse_base_size;
+
+	vfe_dev->vfe_base = msm_camera_get_reg_base(vfe_dev->pdev, "vfe", 0);
+	if (!vfe_dev->vfe_base)
+		return -ENOMEM;
+	vfe_dev->vfe_vbif_base = msm_camera_get_reg_base(vfe_dev->pdev,
+					"vfe_vbif", 0);
+	if (!vfe_dev->vfe_vbif_base) {
+		rc = -ENOMEM;
+		goto vbif_base_fail;
+	}
+
+	vfe_dev->vfe_irq = msm_camera_get_irq(vfe_dev->pdev, "vfe");
+	if (!vfe_dev->vfe_irq) {
+		rc = -ENODEV;
+		goto vfe_irq_fail;
+	}
+
+	vfe_dev->vfe_base_size = msm_camera_get_res_size(vfe_dev->pdev, "vfe");
+	vfe_dev->vfe_vbif_base_size = msm_camera_get_res_size(vfe_dev->pdev,
+						"vfe_vbif");
+	if (!vfe_dev->vfe_base_size || !vfe_dev->vfe_vbif_base_size) {
+		rc = -ENOMEM;
+		goto get_res_fail;
+	}
+	vfe_dev->vfe_hw_limit = 0;
+	vfe_fuse_base = msm_camera_get_reg_base(vfe_dev->pdev,
+					"vfe_fuse", 0);
+	vfe_fuse_base_size = msm_camera_get_res_size(vfe_dev->pdev,
+						"vfe_fuse");
+	if (vfe_fuse_base) {
+		if (vfe_fuse_base_size)
+			vfe_dev->vfe_hw_limit =
+				(msm_camera_io_r(vfe_fuse_base) >> 5) & 0x1;
+		msm_camera_put_reg_base(vfe_dev->pdev, vfe_fuse_base,
+				"vfe_fuse", 0);
+	}
+	rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_regulators(vfe_dev);
+	if (rc)
+		goto get_regulator_fail;
+
+	rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_clks(vfe_dev);
+	if (rc)
+		goto get_clkcs_fail;
+
+	rc = msm_camera_register_irq(vfe_dev->pdev, vfe_dev->vfe_irq,
+		msm_isp_process_irq,
+		IRQF_TRIGGER_RISING, "vfe", vfe_dev);
+	if (rc < 0)
+		goto irq_register_fail;
+
+	msm_camera_enable_irq(vfe_dev->vfe_irq, 0);
+
+	rc = msm_isp_init_bandwidth_mgr(vfe_dev, ISP_VFE0 + vfe_dev->pdev->id);
+	if (rc)
+		goto init_bw_fail;
+
+	return 0;
+
+init_bw_fail:
+	msm_camera_unregister_irq(vfe_dev->pdev, vfe_dev->vfe_irq, "vfe");
+irq_register_fail:
+	vfe_dev->hw_info->vfe_ops.platform_ops.put_clks(vfe_dev);
+get_clkcs_fail:
+	vfe_dev->hw_info->vfe_ops.platform_ops.put_regulators(vfe_dev);
+get_regulator_fail:
+get_res_fail:
+	vfe_dev->vfe_vbif_base_size = 0;
+	vfe_dev->vfe_base_size = 0;
+vfe_irq_fail:
+	msm_camera_put_reg_base(vfe_dev->pdev, vfe_dev->vfe_base,
+					"vfe_vbif", 0);
+vbif_base_fail:
+	msm_camera_put_reg_base(vfe_dev->pdev, vfe_dev->vfe_base, "vfe", 0);
+	return rc;
+}
+
+void msm_vfe47_get_error_mask(
+	uint32_t *error_mask0, uint32_t *error_mask1)
+{
+	*error_mask0 = 0x00000000;
+	*error_mask1 = 0x0BFFFEFF;
+}
+
+void msm_vfe47_get_overflow_mask(uint32_t *overflow_mask)
+{
+	*overflow_mask = 0x09FFFE7E;
+}
+
+void msm_vfe47_get_rdi_wm_mask(struct vfe_device *vfe_dev,
+	uint32_t *rdi_wm_mask)
+{
+	*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
+}
+
+void msm_vfe47_get_irq_mask(struct vfe_device *vfe_dev,
+	uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+	*irq0_mask = vfe_dev->irq0_mask;
+	*irq1_mask = vfe_dev->irq1_mask;
+}
+
+void msm_vfe47_get_halt_restart_mask(uint32_t *irq0_mask,
+	uint32_t *irq1_mask)
+{
+	*irq0_mask = BIT(31);
+	*irq1_mask = BIT(8);
+}
+
+static struct msm_vfe_axi_hardware_info msm_vfe47_axi_hw_info = {
+	.num_wm = 7,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 96,
+	.scratch_buf_range = SZ_32M + SZ_4M,
+};
+
+static struct msm_vfe_stats_hardware_info msm_vfe47_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_HDR_BE    | 1 << MSM_ISP_STATS_BF    |
+		1 << MSM_ISP_STATS_BG        | 1 << MSM_ISP_STATS_BHIST |
+		1 << MSM_ISP_STATS_HDR_BHIST | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS        | 1 << MSM_ISP_STATS_CS    |
+		1 << MSM_ISP_STATS_AEC_BG,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.num_stats_type = VFE47_NUM_STATS_TYPE,
+	.num_stats_comp_mask = VFE47_NUM_STATS_COMP,
+};
+
+struct msm_vfe_hardware_info vfe47_hw_info = {
+	.num_iommu_ctx = 1,
+	.num_iommu_secure_ctx = 0,
+	.vfe_clk_idx = VFE47_SRC_CLK_DTSI_IDX,
+	.runtime_axi_update = 1,
+	.min_ib = 100000000,
+	.min_ab = 100000000,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe47_read_and_clear_irq_status,
+			.process_camif_irq = msm_vfe47_process_input_irq,
+			.process_reset_irq = msm_vfe47_process_reset_irq,
+			.process_halt_irq = msm_vfe47_process_halt_irq,
+			.process_reg_update = msm_vfe47_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe47_process_epoch_irq,
+			.config_irq = msm_vfe47_config_irq,
+			.read_irq_status = msm_vfe47_read_irq_status,
+			.preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe47_axi_reload_wm,
+			.enable_wm = msm_vfe47_axi_enable_wm,
+			.cfg_io_format = msm_vfe47_cfg_io_format,
+			.cfg_comp_mask = msm_vfe47_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe47_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe47_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe47_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe47_cfg_framedrop,
+			.clear_framedrop = msm_vfe47_clear_framedrop,
+			.cfg_wm_reg = msm_vfe47_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe47_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe47_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe47_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.read_wm_ping_pong_addr =
+				msm_vfe47_read_wm_ping_pong_addr,
+			.update_ping_pong_addr =
+				msm_vfe47_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe47_get_comp_mask,
+			.get_wm_mask = msm_vfe47_get_wm_mask,
+			.get_pingpong_status = msm_vfe47_get_pingpong_status,
+			.halt = msm_vfe47_axi_halt,
+			.restart = msm_vfe47_axi_restart,
+			.update_cgc_override =
+				msm_vfe47_axi_update_cgc_override,
+			.ub_reg_offset = msm_vfe47_ub_reg_offset,
+			.get_ub_size = msm_vfe47_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe47_reg_update,
+			.cfg_input_mux = msm_vfe47_cfg_input_mux,
+			.update_camif_state = msm_vfe47_update_camif_state,
+			.start_fetch_eng = msm_vfe47_start_fetch_engine,
+			.cfg_rdi_reg = msm_vfe47_cfg_rdi_reg,
+			.reset_hw = msm_vfe47_reset_hardware,
+			.init_hw = msm_vfe47_init_hardware,
+			.init_hw_reg = msm_vfe47_init_hardware_reg,
+			.clear_status_reg = msm_vfe47_clear_status_reg,
+			.release_hw = msm_vfe47_release_hardware,
+			.get_error_mask = msm_vfe47_get_error_mask,
+			.get_overflow_mask = msm_vfe47_get_overflow_mask,
+			.get_rdi_wm_mask = msm_vfe47_get_rdi_wm_mask,
+			.get_irq_mask = msm_vfe47_get_irq_mask,
+			.get_halt_restart_mask =
+				msm_vfe47_get_halt_restart_mask,
+			.process_error_status = msm_vfe47_process_error_status,
+			.is_module_cfg_lock_needed =
+				msm_vfe47_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
+			.start_fetch_eng_multi_pass =
+				msm_vfe47_start_fetch_engine_multi_pass,
+			.set_halt_restart_mask =
+				msm_vfe47_set_halt_restart_mask,
+			.set_bus_err_ign_mask = NULL,
+			.get_bus_err_mask = NULL,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe47_get_stats_idx,
+			.check_streams = msm_vfe47_stats_check_streams,
+			.cfg_comp_mask = msm_vfe47_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe47_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe47_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe47_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe47_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe47_stats_cfg_ub,
+			.enable_module = msm_vfe47_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe47_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe47_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe47_stats_get_wm_mask,
+			.get_frame_id = msm_vfe47_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe47_get_pingpong_status,
+			.update_cgc_override =
+				msm_vfe47_stats_update_cgc_override,
+			.enable_stats_wm = NULL,
+		},
+		.platform_ops = {
+			.get_platform_data = msm_vfe47_get_platform_data,
+			.enable_regulators = msm_vfe47_enable_regulators,
+			.get_regulators = msm_vfe47_get_regulators,
+			.put_regulators = msm_vfe47_put_regulators,
+			.enable_clks = msm_vfe47_enable_clks,
+			.get_clks = msm_vfe47_get_clks,
+			.put_clks = msm_vfe47_put_clks,
+			.get_clk_rates = msm_vfe47_get_clk_rates,
+			.get_max_clk_rate = msm_vfe47_get_max_clk_rate,
+			.set_clk_rate = msm_vfe47_set_clk_rate,
+			.init_bw_mgr = msm_vfe47_init_bandwidth_mgr,
+			.deinit_bw_mgr = msm_vfe47_deinit_bandwidth_mgr,
+			.update_bw = msm_vfe47_update_bandwidth,
+		}
+	},
+	.dmi_reg_offset = 0xC2C,
+	.axi_hw_info = &msm_vfe47_axi_hw_info,
+	.stats_hw_info = &msm_vfe47_stats_hw_info,
+	.regulator_names = {"vdd", "camss-vdd", "mmagic-vdd"},
+};
+EXPORT_SYMBOL(vfe47_hw_info);
+
+static const struct of_device_id msm_vfe47_dt_match[] = {
+	{
+		.compatible = "qcom,vfe47",
+		.data = &vfe47_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe47_dt_match);
+
+static struct platform_driver vfe47_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe47",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe47_dt_match,
+	},
+};
+
+static int __init msm_vfe47_init_module(void)
+{
+	return platform_driver_register(&vfe47_driver);
+}
+
+static void __exit msm_vfe47_exit_module(void)
+{
+	platform_driver_unregister(&vfe47_driver);
+}
+
+module_init(msm_vfe47_init_module);
+module_exit(msm_vfe47_exit_module);
+MODULE_DESCRIPTION("MSM VFE47 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
new file mode 100644
index 0000000..d08ee27
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
@@ -0,0 +1,209 @@
+/* Copyright (c) 2013-2014,2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP47_H__
+#define __MSM_ISP47_H__
+
+#define VFE47_NUM_STATS_COMP 2
+#define VFE47_NUM_STATS_TYPE 9
+/*composite mask order*/
+enum msm_vfe47_stats_comp_idx {
+	STATS_COMP_IDX_HDR_BE = 0,
+	STATS_COMP_IDX_BG,
+	STATS_COMP_IDX_BF,
+	STATS_COMP_IDX_HDR_BHIST,
+	STATS_COMP_IDX_RS,
+	STATS_COMP_IDX_CS,
+	STATS_COMP_IDX_IHIST,
+	STATS_COMP_IDX_BHIST,
+	STATS_COMP_IDX_AEC_BG,
+};
+
+extern struct msm_vfe_hardware_info vfe47_hw_info;
+
+void msm_vfe47_read_and_clear_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1);
+void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1);
+void msm_vfe47_enable_camif_error(struct vfe_device *vfe_dev,
+			int enable);
+void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts);
+void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts);
+void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0);
+void msm_vfe47_reg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src);
+long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev,
+	uint32_t first_start, uint32_t blocking_call);
+void msm_vfe47_axi_reload_wm(struct vfe_device *vfe_dev,
+	void __iomem *vfe_base, uint32_t reload_mask);
+void msm_vfe47_axi_update_cgc_override(struct vfe_device *vfe_dev,
+	uint8_t wm_idx, uint8_t enable);
+void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
+	uint32_t framedrop_period);
+void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev,
+	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format);
+int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg);
+int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+	void *arg);
+void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg);
+void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev,
+	struct msm_vfe_testgen_cfg *testgen_cfg);
+void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg);
+void msm_vfe47_cfg_input_mux(struct vfe_device *vfe_dev,
+	struct msm_vfe_pix_cfg *pix_cfg);
+void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
+	uint8_t is_stream_on);
+void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
+	enum msm_isp_camif_update_state update_state);
+void msm_vfe47_cfg_rdi_reg(
+	struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+	enum msm_vfe_input_src input_src);
+void msm_vfe47_axi_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx);
+void msm_vfe47_axi_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
+void msm_vfe47_axi_cfg_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint8_t plane_idx);
+void msm_vfe47_axi_clear_wm_xbar_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
+void msm_vfe47_cfg_axi_ub_equal_default(
+	struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src);
+void msm_vfe47_cfg_axi_ub_equal_slicing(
+	struct vfe_device *vfe_dev);
+void msm_vfe47_cfg_axi_ub(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src);
+void msm_vfe47_read_wm_ping_pong_addr(
+	struct vfe_device *vfe_dev);
+void msm_vfe47_update_ping_pong_addr(
+	void __iomem *vfe_base,
+	uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
+	int32_t buf_size);
+int msm_vfe47_axi_halt(struct vfe_device *vfe_dev,
+	uint32_t blocking);
+void msm_vfe47_axi_restart(struct vfe_device *vfe_dev,
+	uint32_t blocking, uint32_t enable_camif);
+uint32_t msm_vfe47_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1);
+uint32_t msm_vfe47_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1);
+uint32_t msm_vfe47_get_pingpong_status(
+	struct vfe_device *vfe_dev);
+int msm_vfe47_get_stats_idx(enum msm_isp_stats_type stats_type);
+int msm_vfe47_stats_check_streams(
+	struct msm_vfe_stats_stream *stream_info);
+void msm_vfe47_stats_cfg_comp_mask(
+	struct vfe_device *vfe_dev, uint32_t stats_mask,
+	uint8_t request_comp_index, uint8_t enable);
+void msm_vfe47_stats_cfg_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info);
+void msm_vfe47_stats_clear_wm_irq_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info);
+void msm_vfe47_stats_cfg_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info);
+void msm_vfe47_stats_clear_wm_reg(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream *stream_info);
+void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev);
+void msm_vfe47_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable);
+bool msm_vfe47_is_module_cfg_lock_needed(
+	uint32_t reg_offset);
+void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev,
+	uint32_t stats_mask, uint8_t enable);
+void msm_vfe47_stats_update_ping_pong_addr(
+	struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
+	uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size);
+uint32_t msm_vfe47_stats_get_wm_mask(
+	uint32_t irq_status0, uint32_t irq_status1);
+uint32_t msm_vfe47_stats_get_comp_mask(
+	uint32_t irq_status0, uint32_t irq_status1);
+uint32_t msm_vfe47_stats_get_frame_id(
+	struct vfe_device *vfe_dev);
+void msm_vfe47_get_error_mask(
+	uint32_t *error_mask0, uint32_t *error_mask1);
+void msm_vfe47_get_overflow_mask(uint32_t *overflow_mask);
+void msm_vfe47_get_rdi_wm_mask(struct vfe_device *vfe_dev,
+	uint32_t *rdi_wm_mask);
+void msm_vfe47_get_irq_mask(struct vfe_device *vfe_dev,
+	uint32_t *irq0_mask, uint32_t *irq1_mask);
+void msm_vfe47_restore_irq_mask(struct vfe_device *vfe_dev);
+void msm_vfe47_get_halt_restart_mask(uint32_t *irq0_mask,
+	uint32_t *irq1_mask);
+int msm_vfe47_init_hardware(struct vfe_device *vfe_dev);
+void msm_vfe47_release_hardware(struct vfe_device *vfe_dev);
+void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev);
+void msm_vfe47_process_reset_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1);
+void msm_vfe47_process_halt_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1);
+void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts);
+void msm_vfe47_process_violation_status(
+	struct vfe_device *vfe_dev);
+void msm_vfe47_process_error_status(struct vfe_device *vfe_dev);
+void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev);
+int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev);
+int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable);
+int msm_vfe47_get_regulators(struct vfe_device *vfe_dev);
+void msm_vfe47_put_regulators(struct vfe_device *vfe_dev);
+int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable);
+int msm_vfe47_get_clks(struct vfe_device *vfe_dev);
+void msm_vfe47_put_clks(struct vfe_device *vfe_dev);
+int msm_vfe47_get_clk_rates(struct vfe_device *vfe_dev,
+			struct msm_isp_clk_rates *rates);
+int msm_vfe47_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate);
+int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate);
+int msm_vfe47_init_bandwidth_mgr(struct vfe_device *vfe_dev,
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+void msm_vfe47_deinit_bandwidth_mgr(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+int msm_vfe47_update_bandwidth(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
+void msm_vfe47_config_irq(struct vfe_device *vfe_dev,
+		uint32_t irq0_mask, uint32_t irq1_mask,
+		enum msm_isp_irq_operation oper);
+int msm_isp47_ahb_clk_cfg(struct vfe_device *vfe_dev,
+			struct msm_isp_ahb_clk_cfg *ahb_cfg);
+void msm_vfe47_set_halt_restart_mask(struct vfe_device *vfe_dev);
+uint32_t msm_vfe47_ub_reg_offset(struct vfe_device *vfe_dev, int wm_idx);
+uint32_t msm_vfe47_get_ub_size(struct vfe_device *vfe_dev);
+#endif /* __MSM_ISP47_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
new file mode 100644
index 0000000..9bece18
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
@@ -0,0 +1,505 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/clk/msm-clk.h>
+
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp.h"
+#include "msm.h"
+#include "msm_camera_io_util.h"
+#include "cam_hw_ops.h"
+#include "msm_isp47.h"
+#include "msm_isp48.h"
+#include "cam_soc_api.h"
+
+#define MSM_VFE48_BUS_CLIENT_INIT 0xABAB
+#define VFE48_STATS_BURST_LEN 3
+#define VFE48_UB_SIZE_VFE 2048 /* 2048 * 256 bits = 64KB */
+#define VFE48_UB_STATS_SIZE 144
+#define MSM_ISP48_TOTAL_IMAGE_UB_VFE (VFE48_UB_SIZE_VFE - VFE48_UB_STATS_SIZE)
+
+
+static uint32_t stats_base_addr[] = {
+	0x1D4, /* HDR_BE */
+	0x254, /* BG(AWB_BG) */
+	0x214, /* BF */
+	0x1F4, /* HDR_BHIST */
+	0x294, /* RS */
+	0x2B4, /* CS */
+	0x2D4, /* IHIST */
+	0x274, /* BHIST (SKIN_BHIST) */
+	0x234, /* AEC_BG */
+};
+
+#define VFE48_STATS_BASE(idx) (stats_base_addr[idx])
+
+static struct msm_vfe_axi_hardware_info msm_vfe48_axi_hw_info = {
+	.num_wm = 7,
+	.num_comp_mask = 3,
+	.num_rdi = 3,
+	.num_rdi_master = 3,
+	.min_wm_ub = 96,
+	.scratch_buf_range = SZ_32M,
+};
+
+static uint8_t stats_pingpong_offset_map[] = {
+	 8, /* HDR_BE */
+	12, /* BG(AWB_BG) */
+	10, /* BF */
+	 9, /* HDR_BHIST */
+	14, /* RS */
+	15, /* CS */
+	16, /* IHIST */
+	13, /* BHIST (SKIN_BHIST) */
+	11, /* AEC_BG */
+};
+
+static uint8_t stats_wm_index[] = {
+	 7, /* HDR_BE */
+	11, /* BG(AWB_BG) */
+	 9, /* BF */
+	 8, /* HDR_BHIST */
+	13, /* RS */
+	14, /* CS */
+	15, /* IHIST */
+	12, /* BHIST (SKIN_BHIST) */
+	10, /* AEC_BG */
+};
+
+#define VFE48_SRC_CLK_DTSI_IDX 3
+
+static struct msm_vfe_stats_hardware_info msm_vfe48_stats_hw_info = {
+	.stats_capability_mask =
+		1 << MSM_ISP_STATS_HDR_BE    | 1 << MSM_ISP_STATS_BF    |
+		1 << MSM_ISP_STATS_BG	| 1 << MSM_ISP_STATS_BHIST |
+		1 << MSM_ISP_STATS_HDR_BHIST | 1 << MSM_ISP_STATS_IHIST |
+		1 << MSM_ISP_STATS_RS	| 1 << MSM_ISP_STATS_CS    |
+		1 << MSM_ISP_STATS_AEC_BG,
+	.stats_ping_pong_offset = stats_pingpong_offset_map,
+	.stats_wm_index = stats_wm_index,
+	.num_stats_type = VFE47_NUM_STATS_TYPE,
+	.num_stats_comp_mask = VFE47_NUM_STATS_COMP,
+};
+
+static void msm_vfe48_axi_enable_wm(void __iomem *vfe_base,
+	uint8_t wm_idx, uint8_t enable)
+{
+	uint32_t val;
+
+	if (enable)
+		val = (0x2 << (2 * wm_idx));
+	else
+		val = (0x1 << (2 * wm_idx));
+
+	msm_camera_io_w_mb(val, vfe_base + 0xCEC);
+}
+
+static void msm_vfe48_enable_stats_wm(struct vfe_device *vfe_dev,
+		uint32_t stats_mask, uint8_t enable)
+{
+	int i;
+
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
+		if (!(stats_mask & 0x1)) {
+			stats_mask >>= 1;
+			continue;
+		}
+		stats_mask >>= 1;
+		msm_vfe48_axi_enable_wm(vfe_dev->vfe_base,
+			vfe_dev->hw_info->stats_hw_info->stats_wm_index[i],
+			enable);
+	}
+}
+
+static void msm_vfe48_deinit_bandwidth_mgr(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	msm_camera_unregister_bus_client(CAM_BUS_CLIENT_VFE);
+	isp_bandwidth_mgr->bus_client = 0;
+}
+
+static int msm_vfe48_init_bandwidth_mgr(struct vfe_device *vfe_dev,
+	struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	int rc = 0;
+
+	rc = msm_camera_register_bus_client(vfe_dev->pdev, CAM_BUS_CLIENT_VFE);
+	if (rc) {
+		/*
+		 * Fallback to the older method of registration. While testing
+		 * this the bus apis that the soc api uses were not
+		 * enabled and hence we need to use the old api for now
+		 */
+		vfe_dev->hw_info->vfe_ops.platform_ops.init_bw_mgr =
+					msm_vfe47_init_bandwidth_mgr;
+		vfe_dev->hw_info->vfe_ops.platform_ops.deinit_bw_mgr =
+					msm_vfe47_deinit_bandwidth_mgr;
+		vfe_dev->hw_info->vfe_ops.platform_ops.update_bw =
+					msm_vfe47_update_bandwidth;
+		return vfe_dev->hw_info->vfe_ops.platform_ops.init_bw_mgr(
+						vfe_dev, isp_bandwidth_mgr);
+	}
+	isp_bandwidth_mgr->bus_client = MSM_VFE48_BUS_CLIENT_INIT;
+	return rc;
+}
+
+static int msm_vfe48_update_bandwidth(
+		struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr)
+{
+	int i;
+	uint64_t ab = 0;
+	uint64_t ib = 0;
+	int rc = 0;
+
+	for (i = 0; i < MAX_ISP_CLIENT; i++) {
+		if (isp_bandwidth_mgr->client_info[i].active) {
+			ab += isp_bandwidth_mgr->client_info[i].ab;
+			ib += isp_bandwidth_mgr->client_info[i].ib;
+		}
+	}
+	rc = msm_camera_update_bus_bw(CAM_BUS_CLIENT_VFE, ab, ib);
+	/* Insert into circular buffer */
+	if (!rc)
+		msm_isp_update_req_history(isp_bandwidth_mgr->bus_client,
+			ab, ib,
+			isp_bandwidth_mgr->client_info,
+			sched_clock());
+	return rc;
+}
+
+static void msm_vfe48_put_clks(struct vfe_device *vfe_dev)
+{
+	msm_camera_put_clk_info_and_rates(vfe_dev->pdev, &vfe_dev->vfe_clk_info,
+			&vfe_dev->vfe_clk, &vfe_dev->vfe_clk_rates,
+			vfe_dev->num_rates,
+			vfe_dev->num_clk);
+
+	vfe_dev->num_clk = 0;
+	vfe_dev->num_rates = 0;
+	vfe_dev->hvx_clk = NULL;
+	vfe_dev->hvx_clk_info = NULL;
+	vfe_dev->num_hvx_clk = 0;
+	vfe_dev->num_norm_clk = 0;
+}
+
+static int msm_vfe48_get_clks(struct vfe_device *vfe_dev)
+{
+	int rc;
+	int i, j;
+	struct clk *stream_clk;
+	struct msm_cam_clk_info clk_info;
+
+	rc = msm_camera_get_clk_info_and_rates(vfe_dev->pdev,
+			&vfe_dev->vfe_clk_info, &vfe_dev->vfe_clk,
+			&vfe_dev->vfe_clk_rates,
+			&vfe_dev->num_rates,
+			&vfe_dev->num_clk);
+
+	if (rc)
+		return rc;
+	vfe_dev->num_norm_clk = vfe_dev->num_clk;
+	for (i = 0; i < vfe_dev->num_clk; i++) {
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+				"camss_vfe_stream_clk") == 0) {
+			stream_clk = vfe_dev->vfe_clk[i];
+			clk_info = vfe_dev->vfe_clk_info[i];
+			vfe_dev->num_hvx_clk = 1;
+			vfe_dev->num_norm_clk = vfe_dev->num_clk - 1;
+			break;
+		}
+	}
+	if (i >= vfe_dev->num_clk)
+		pr_err("%s: cannot find camss_vfe_stream_clk\n", __func__);
+	else {
+		/* Switch stream_clk to the last element*/
+		for (; i < vfe_dev->num_clk - 1; i++) {
+			vfe_dev->vfe_clk[i] = vfe_dev->vfe_clk[i+1];
+			vfe_dev->vfe_clk_info[i] = vfe_dev->vfe_clk_info[i+1];
+			for (j = 0; j < MSM_VFE_MAX_CLK_RATES; j++)
+				vfe_dev->vfe_clk_rates[j][i] =
+					vfe_dev->vfe_clk_rates[j][i+1];
+		}
+		vfe_dev->vfe_clk_info[vfe_dev->num_clk-1] = clk_info;
+		vfe_dev->vfe_clk[vfe_dev->num_clk-1] = stream_clk;
+		vfe_dev->hvx_clk_info =
+			&vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
+		vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+		vfe_dev->hvx_clk_state = false;
+	}
+
+	for (i = 0; i < vfe_dev->num_clk; i++) {
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+					"vfe_clk_src") == 0) {
+			vfe_dev->hw_info->vfe_clk_idx = i;
+			/* set initial clk rate to svs */
+			msm_camera_clk_set_rate(&vfe_dev->pdev->dev,
+				vfe_dev->vfe_clk[i],
+				vfe_dev->vfe_clk_rates
+					[MSM_VFE_CLK_RATE_SVS][i]);
+		}
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+					"mnoc_maxi_clk") == 0)
+			vfe_dev->vfe_clk_info[i].clk_rate = INIT_RATE;
+		/* set no memory retention */
+		if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+				"camss_vfe_clk") == 0 ||
+			strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+				"camss_csi_vfe_clk") == 0 ||
+			strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+				"camss_vfe_vbif_axi_clk") == 0) {
+			msm_camera_set_clk_flags(vfe_dev->vfe_clk[i],
+				 CLKFLAG_NORETAIN_MEM);
+			msm_camera_set_clk_flags(vfe_dev->vfe_clk[i],
+				 CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+	return 0;
+}
+
+static int msm_vfe48_get_clk_rates(struct vfe_device *vfe_dev,
+			struct msm_isp_clk_rates *rates)
+{
+	rates->svs_rate = vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_SVS]
+					[vfe_dev->hw_info->vfe_clk_idx];
+	rates->nominal_rate = vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
+					[vfe_dev->hw_info->vfe_clk_idx];
+	rates->high_rate = vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO]
+					[vfe_dev->hw_info->vfe_clk_idx];
+
+	return 0;
+}
+
+static int msm_vfe48_get_regulators(struct vfe_device *vfe_dev)
+{
+	return msm_camera_get_regulator_info(vfe_dev->pdev,
+			&vfe_dev->regulator_info, &vfe_dev->vfe_num_regulators);
+}
+
+static void msm_vfe48_put_regulators(struct vfe_device *vfe_dev)
+{
+	msm_camera_put_regulators(vfe_dev->pdev,
+			&vfe_dev->regulator_info, vfe_dev->vfe_num_regulators);
+	vfe_dev->vfe_num_regulators = 0;
+}
+
+static void msm_vfe48_get_bus_err_mask(struct vfe_device *vfe_dev,
+		uint32_t *bus_err, uint32_t *irq_status1)
+{
+	*bus_err = msm_camera_io_r(vfe_dev->vfe_base + 0xC94);
+
+	*bus_err &= ~vfe_dev->bus_err_ign_mask;
+	if (*bus_err == 0)
+		*irq_status1 &= ~(1 << 4);
+}
+
+static void msm_vfe48_set_bus_err_ign_mask(struct vfe_device *vfe_dev,
+				int wm, int enable)
+{
+	if (enable)
+		vfe_dev->bus_err_ign_mask |= (1 << wm);
+	else
+		vfe_dev->bus_err_ign_mask &= ~(1 << wm);
+}
+
+void msm_vfe48_stats_cfg_ub(struct vfe_device *vfe_dev)
+{
+	int i;
+	uint32_t ub_offset = 0, stats_burst_len;
+	uint32_t ub_size[VFE47_NUM_STATS_TYPE] = {
+		16, /* MSM_ISP_STATS_HDR_BE */
+		16, /* MSM_ISP_STATS_BG */
+		16, /* MSM_ISP_STATS_BF */
+		16, /* MSM_ISP_STATS_HDR_BHIST */
+		16, /* MSM_ISP_STATS_RS */
+		16, /* MSM_ISP_STATS_CS */
+		16, /* MSM_ISP_STATS_IHIST */
+		16, /* MSM_ISP_STATS_BHIST */
+		16, /* MSM_ISP_STATS_AEC_BG */
+	};
+
+	stats_burst_len = VFE48_STATS_BURST_LEN;
+	ub_offset = VFE48_UB_SIZE_VFE;
+
+	for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
+		ub_offset -= ub_size[i];
+		msm_camera_io_w(stats_burst_len << 30 |
+			ub_offset << 16 | (ub_size[i] - 1),
+			vfe_dev->vfe_base + VFE48_STATS_BASE(i) + 0x14);
+	}
+}
+
+uint32_t msm_vfe48_get_ub_size(struct vfe_device *vfe_dev)
+{
+	return MSM_ISP48_TOTAL_IMAGE_UB_VFE;
+}
+
+
+
+struct msm_vfe_hardware_info vfe48_hw_info = {
+	.num_iommu_ctx = 1,
+	.num_iommu_secure_ctx = 0,
+	.vfe_clk_idx = VFE48_SRC_CLK_DTSI_IDX,
+	.runtime_axi_update = 1,
+	.min_ib = 100000000,
+	.min_ab = 100000000,
+	.vfe_ops = {
+		.irq_ops = {
+			.read_and_clear_irq_status =
+				msm_vfe47_read_and_clear_irq_status,
+			.read_irq_status = msm_vfe47_read_irq_status,
+			.process_camif_irq = msm_vfe47_process_input_irq,
+			.process_reset_irq = msm_vfe47_process_reset_irq,
+			.process_halt_irq = msm_vfe47_process_halt_irq,
+			.process_reg_update = msm_vfe47_process_reg_update,
+			.process_axi_irq = msm_isp_process_axi_irq,
+			.process_stats_irq = msm_isp_process_stats_irq,
+			.process_epoch_irq = msm_vfe47_process_epoch_irq,
+			.config_irq = msm_vfe47_config_irq,
+			.preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
+		},
+		.axi_ops = {
+			.reload_wm = msm_vfe47_axi_reload_wm,
+			.enable_wm = msm_vfe48_axi_enable_wm,
+			.cfg_io_format = msm_vfe47_cfg_io_format,
+			.cfg_comp_mask = msm_vfe47_axi_cfg_comp_mask,
+			.clear_comp_mask = msm_vfe47_axi_clear_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe47_axi_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe47_axi_clear_wm_irq_mask,
+			.cfg_framedrop = msm_vfe47_cfg_framedrop,
+			.clear_framedrop = msm_vfe47_clear_framedrop,
+			.cfg_wm_reg = msm_vfe47_axi_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe47_axi_clear_wm_reg,
+			.cfg_wm_xbar_reg = msm_vfe47_axi_cfg_wm_xbar_reg,
+			.clear_wm_xbar_reg = msm_vfe47_axi_clear_wm_xbar_reg,
+			.cfg_ub = msm_vfe47_cfg_axi_ub,
+			.read_wm_ping_pong_addr =
+				msm_vfe47_read_wm_ping_pong_addr,
+			.update_ping_pong_addr =
+				msm_vfe47_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe47_get_comp_mask,
+			.get_wm_mask = msm_vfe47_get_wm_mask,
+			.get_pingpong_status = msm_vfe47_get_pingpong_status,
+			.halt = msm_vfe47_axi_halt,
+			.restart = msm_vfe47_axi_restart,
+			.update_cgc_override =
+				msm_vfe47_axi_update_cgc_override,
+			.ub_reg_offset = msm_vfe47_ub_reg_offset,
+			.get_ub_size = msm_vfe48_get_ub_size,
+		},
+		.core_ops = {
+			.reg_update = msm_vfe47_reg_update,
+			.cfg_input_mux = msm_vfe47_cfg_input_mux,
+			.update_camif_state = msm_vfe47_update_camif_state,
+			.start_fetch_eng = msm_vfe47_start_fetch_engine,
+			.cfg_rdi_reg = msm_vfe47_cfg_rdi_reg,
+			.reset_hw = msm_vfe47_reset_hardware,
+			.init_hw = msm_vfe47_init_hardware,
+			.init_hw_reg = msm_vfe47_init_hardware_reg,
+			.clear_status_reg = msm_vfe47_clear_status_reg,
+			.release_hw = msm_vfe47_release_hardware,
+			.get_error_mask = msm_vfe47_get_error_mask,
+			.get_overflow_mask = msm_vfe47_get_overflow_mask,
+			.get_rdi_wm_mask = msm_vfe47_get_rdi_wm_mask,
+			.get_irq_mask = msm_vfe47_get_irq_mask,
+			.get_halt_restart_mask =
+				msm_vfe47_get_halt_restart_mask,
+			.process_error_status = msm_vfe47_process_error_status,
+			.is_module_cfg_lock_needed =
+				msm_vfe47_is_module_cfg_lock_needed,
+			.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
+			.start_fetch_eng_multi_pass =
+				msm_vfe47_start_fetch_engine_multi_pass,
+			.set_halt_restart_mask =
+				msm_vfe47_set_halt_restart_mask,
+			.set_bus_err_ign_mask = msm_vfe48_set_bus_err_ign_mask,
+			.get_bus_err_mask = msm_vfe48_get_bus_err_mask,
+		},
+		.stats_ops = {
+			.get_stats_idx = msm_vfe47_get_stats_idx,
+			.check_streams = msm_vfe47_stats_check_streams,
+			.cfg_comp_mask = msm_vfe47_stats_cfg_comp_mask,
+			.cfg_wm_irq_mask = msm_vfe47_stats_cfg_wm_irq_mask,
+			.clear_wm_irq_mask = msm_vfe47_stats_clear_wm_irq_mask,
+			.cfg_wm_reg = msm_vfe47_stats_cfg_wm_reg,
+			.clear_wm_reg = msm_vfe47_stats_clear_wm_reg,
+			.cfg_ub = msm_vfe48_stats_cfg_ub,
+			.enable_module = msm_vfe47_stats_enable_module,
+			.update_ping_pong_addr =
+				msm_vfe47_stats_update_ping_pong_addr,
+			.get_comp_mask = msm_vfe47_stats_get_comp_mask,
+			.get_wm_mask = msm_vfe47_stats_get_wm_mask,
+			.get_frame_id = msm_vfe47_stats_get_frame_id,
+			.get_pingpong_status = msm_vfe47_get_pingpong_status,
+			.update_cgc_override =
+				msm_vfe47_stats_update_cgc_override,
+			.enable_stats_wm = msm_vfe48_enable_stats_wm,
+		},
+		.platform_ops = {
+			.get_platform_data = msm_vfe47_get_platform_data,
+			.enable_regulators = msm_vfe47_enable_regulators,
+			.get_regulators = msm_vfe48_get_regulators,
+			.put_regulators = msm_vfe48_put_regulators,
+			.enable_clks = msm_vfe47_enable_clks,
+			.update_bw = msm_vfe48_update_bandwidth,
+			.init_bw_mgr = msm_vfe48_init_bandwidth_mgr,
+			.deinit_bw_mgr = msm_vfe48_deinit_bandwidth_mgr,
+			.get_clks = msm_vfe48_get_clks,
+			.put_clks = msm_vfe48_put_clks,
+			.set_clk_rate = msm_vfe47_set_clk_rate,
+			.get_max_clk_rate = msm_vfe47_get_max_clk_rate,
+			.get_clk_rates = msm_vfe48_get_clk_rates,
+		},
+	},
+	.dmi_reg_offset = 0xC2C,
+	.axi_hw_info = &msm_vfe48_axi_hw_info,
+	.stats_hw_info = &msm_vfe48_stats_hw_info,
+};
+EXPORT_SYMBOL(vfe48_hw_info);
+
+static const struct of_device_id msm_vfe48_dt_match[] = {
+	{
+		.compatible = "qcom,vfe48",
+		.data = &vfe48_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe48_dt_match);
+
+static struct platform_driver vfe48_driver = {
+	.probe = vfe_hw_probe,
+	.driver = {
+		.name = "msm_vfe48",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe48_dt_match,
+	},
+};
+
+static int __init msm_vfe47_init_module(void)
+{
+	return platform_driver_register(&vfe48_driver);
+}
+
+static void __exit msm_vfe47_exit_module(void)
+{
+	platform_driver_unregister(&vfe48_driver);
+}
+
+module_init(msm_vfe47_init_module);
+module_exit(msm_vfe47_exit_module);
+MODULE_DESCRIPTION("MSM VFE48 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.h
new file mode 100644
index 0000000..cc052bc
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISP48_H__
+#define __MSM_ISP48_H__
+
+extern struct msm_vfe_hardware_info vfe48_hw_info;
+
+enum msm_vfe_clk_rates {
+	MSM_VFE_CLK_RATE_SVS = 0,
+	MSM_VFE_CLK_RATE_NOMINAL = 1,
+	MSM_VFE_CLK_RATE_TURBO = 2,
+	MSM_VFE_MAX_CLK_RATES = 3,
+};
+
+#define MSM_VFE48_HW_VERSION 0x8
+#define MSM_VFE48_HW_VERSION_SHIFT 28
+#define MSM_VFE48_HW_VERSION_MASK 0xF
+
+static inline int msm_vfe_is_vfe48(struct vfe_device *vfe_dev)
+{
+	return (((vfe_dev->vfe_hw_version >> MSM_VFE48_HW_VERSION_SHIFT) &
+		MSM_VFE48_HW_VERSION_MASK) == MSM_VFE48_HW_VERSION);
+}
+
+void msm_vfe48_stats_cfg_ub(struct vfe_device *vfe_dev);
+uint32_t msm_vfe48_get_ub_size(struct vfe_device *vfe_dev);
+
+
+#endif /* __MSM_ISP48_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
new file mode 100644
index 0000000..6295d27
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -0,0 +1,4390 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+#include <asm/div64.h>
+#include "msm_isp_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp48.h"
+
+#define HANDLE_TO_IDX(handle) (handle & 0xFF)
+#define ISP_SOF_DEBUG_COUNT 0
+
+#ifdef CONFIG_MSM_AVTIMER
+static struct avtimer_fptr_t avtimer_func;
+#endif
+static void msm_isp_reload_ping_pong_offset(
+		struct msm_vfe_axi_stream *stream_info);
+
+static void __msm_isp_axi_stream_update(
+			struct msm_vfe_axi_stream *stream_info,
+			struct msm_isp_timestamp *ts);
+
+static int msm_isp_update_stream_bandwidth(
+		struct msm_vfe_axi_stream *stream_info, int enable);
+
+#define DUAL_VFE_AND_VFE1(s, v) ((s->stream_src < RDI_INTF_0) && \
+			v->is_split && vfe_dev->pdev->id == ISP_VFE1)
+
+#define RDI_OR_NOT_DUAL_VFE(v, s) (!v->is_split || \
+			((s->stream_src >= RDI_INTF_0) && \
+			(stream_info->stream_src <= RDI_INTF_2)))
+
+static int msm_isp_axi_create_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_shared_data *axi_data,
+	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t i = 0;
+	int rc = 0;
+
+	if (stream_info->state != AVAILABLE) {
+		pr_err("%s:%d invalid state %d expected %d\n",
+			__func__, __LINE__, stream_info->state,
+			AVAILABLE);
+		return -EINVAL;
+	}
+
+	if (stream_info->num_isp == 0) {
+		stream_info->session_id = stream_cfg_cmd->session_id;
+		stream_info->stream_id = stream_cfg_cmd->stream_id;
+		stream_info->buf_divert = stream_cfg_cmd->buf_divert;
+		stream_info->stream_src = stream_cfg_cmd->stream_src;
+		stream_info->controllable_output =
+			stream_cfg_cmd->controllable_output;
+		stream_info->activated_framedrop_period =
+					MSM_VFE_STREAM_STOP_PERIOD;
+		if (stream_cfg_cmd->controllable_output)
+			stream_cfg_cmd->frame_skip_pattern = SKIP_ALL;
+		INIT_LIST_HEAD(&stream_info->request_q);
+	} else {
+		/* check if the stream has been added for the vfe-device */
+		if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) {
+			pr_err("%s: stream %pK/%x is already added for vfe dev %d vfe_mask %x\n",
+				__func__, stream_info, stream_info->stream_id,
+				vfe_dev->pdev->id, stream_info->vfe_mask);
+			return -EINVAL;
+		}
+		if (stream_info->session_id != stream_cfg_cmd->session_id) {
+			pr_err("%s: dual stream session id mismatch %d/%d\n",
+				__func__, stream_info->session_id,
+				stream_cfg_cmd->session_id);
+			rc = -EINVAL;
+		}
+		if (stream_info->stream_id != stream_cfg_cmd->stream_id) {
+			pr_err("%s: dual stream stream id mismatch %d/%d\n",
+				__func__, stream_info->stream_id,
+				stream_cfg_cmd->stream_id);
+			rc = -EINVAL;
+		}
+		if (stream_info->controllable_output !=
+			stream_cfg_cmd->controllable_output) {
+			pr_err("%s: dual stream controllable_op mismatch %d/%d\n",
+				__func__, stream_info->controllable_output,
+				stream_cfg_cmd->controllable_output);
+			rc = -EINVAL;
+		}
+		if (stream_info->buf_divert != stream_cfg_cmd->buf_divert) {
+			pr_err("%s: dual stream buf_divert mismatch %d/%d\n",
+				__func__, stream_info->buf_divert,
+				stream_cfg_cmd->buf_divert);
+			rc = -EINVAL;
+		}
+		if (rc)
+			return rc;
+	}
+	stream_info->vfe_dev[stream_info->num_isp] = vfe_dev;
+	stream_info->num_isp++;
+
+	if ((axi_data->stream_handle_cnt << 8) == 0)
+		axi_data->stream_handle_cnt++;
+
+	stream_cfg_cmd->axi_stream_handle =
+		(++axi_data->stream_handle_cnt) << 8 | stream_info->stream_src;
+
+	ISP_DBG("%s: vfe %d handle %x\n", __func__, vfe_dev->pdev->id,
+		stream_cfg_cmd->axi_stream_handle);
+
+	stream_info->stream_handle[stream_info->num_isp - 1] =
+		stream_cfg_cmd->axi_stream_handle;
+	stream_info->vfe_mask |= (1 << vfe_dev->pdev->id);
+
+	if (!vfe_dev->is_split || stream_cfg_cmd->stream_src >= RDI_INTF_0 ||
+		stream_info->num_isp == MAX_VFE) {
+		stream_info->state = INACTIVE;
+
+		for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++)
+			stream_info->composite_irq[i] = 0;
+	}
+	return 0;
+}
+
+static void msm_isp_axi_destroy_stream(
+	struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info)
+{
+	int k;
+	int j;
+	int i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	/*
+	 * For the index being removed, shift everything to it's right by 1
+	 * so that the index being removed becomes the last index
+	 */
+	for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) {
+		stream_info->vfe_dev[i] = stream_info->vfe_dev[k];
+		stream_info->stream_handle[i] = stream_info->stream_handle[k];
+		stream_info->bandwidth[i] = stream_info->bandwidth[k];
+		stream_info->max_width[i] = stream_info->max_width[k];
+		stream_info->comp_mask_index[i] =
+				stream_info->comp_mask_index[k];
+		for (j = 0; j < stream_info->num_planes; j++) {
+			stream_info->plane_cfg[i][j] =
+				stream_info->plane_cfg[k][j];
+			stream_info->wm[i][j] = stream_info->wm[k][j];
+		}
+	}
+
+	stream_info->num_isp--;
+	stream_info->vfe_dev[stream_info->num_isp] = NULL;
+	stream_info->stream_handle[stream_info->num_isp] = 0;
+	stream_info->bandwidth[stream_info->num_isp] = 0;
+	stream_info->max_width[stream_info->num_isp] = 0;
+	stream_info->comp_mask_index[stream_info->num_isp] = -1;
+	stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id);
+	for (j = 0; j < stream_info->num_planes; j++) {
+		stream_info->wm[stream_info->num_isp][j] = -1;
+		memset(&stream_info->plane_cfg[stream_info->num_isp][j],
+			0, sizeof(
+			stream_info->plane_cfg[stream_info->num_isp][j]));
+	}
+
+	if (stream_info->num_isp == 0) {
+		/* release the bufq */
+		for (k = 0; k < VFE_BUF_QUEUE_MAX; k++)
+			stream_info->bufq_handle[k] = 0;
+		stream_info->vfe_mask = 0;
+		stream_info->state = AVAILABLE;
+	}
+}
+
+static int msm_isp_validate_axi_request(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+{
+	int rc = -1, i;
+	int vfe_idx;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	switch (stream_cfg_cmd->output_format) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR10DPCM6:
+	case V4L2_PIX_FMT_SGBRG10DPCM6:
+	case V4L2_PIX_FMT_SGRBG10DPCM6:
+	case V4L2_PIX_FMT_SRGGB10DPCM6:
+	case V4L2_PIX_FMT_SBGGR10DPCM8:
+	case V4L2_PIX_FMT_SGBRG10DPCM8:
+	case V4L2_PIX_FMT_SGRBG10DPCM8:
+	case V4L2_PIX_FMT_SRGGB10DPCM8:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SBGGR14:
+	case V4L2_PIX_FMT_SGBRG14:
+	case V4L2_PIX_FMT_SGRBG14:
+	case V4L2_PIX_FMT_SRGGB14:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_QBGGR14:
+	case V4L2_PIX_FMT_QGBRG14:
+	case V4L2_PIX_FMT_QGRBG14:
+	case V4L2_PIX_FMT_QRGGB14:
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_META10:
+	case V4L2_PIX_FMT_GREY:
+		stream_info->num_planes = 1;
+		stream_info->format_factor = ISP_Q2;
+		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+		stream_info->num_planes = 2;
+		stream_info->format_factor = 1.5 * ISP_Q2;
+		break;
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		stream_info->num_planes = 2;
+		stream_info->format_factor = 2 * ISP_Q2;
+		break;
+	case V4L2_PIX_FMT_NV24:
+	case V4L2_PIX_FMT_NV42:
+		stream_info->num_planes = 2;
+		stream_info->format_factor = 3 * ISP_Q2;
+		break;
+	/*TD: Add more image format*/
+	default:
+		msm_isp_print_fourcc_error(__func__,
+				stream_cfg_cmd->output_format);
+		return rc;
+	}
+
+	if (axi_data->hw_info->num_wm - axi_data->num_used_wm <
+		stream_info->num_planes) {
+		pr_err("%s: No free write masters\n", __func__);
+		return rc;
+	}
+
+	if ((stream_info->num_planes > 1) &&
+			(axi_data->hw_info->num_comp_mask -
+			axi_data->num_used_composite_mask < 1)) {
+		pr_err("%s: No free composite mask\n", __func__);
+		return rc;
+	}
+
+	if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) {
+		pr_err("%s: Invalid skip pattern\n", __func__);
+		return rc;
+	}
+
+	if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) {
+		pr_err("%s: Invalid skip pattern\n", __func__);
+		return rc;
+	}
+
+	vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		stream_info->plane_cfg[vfe_idx][i] =
+			stream_cfg_cmd->plane_cfg[i];
+		stream_info->max_width[vfe_idx] =
+			max(stream_info->max_width[vfe_idx],
+			stream_cfg_cmd->plane_cfg[i].output_width);
+	}
+
+	stream_info->output_format = stream_cfg_cmd->output_format;
+	stream_info->runtime_output_format = stream_info->output_format;
+	stream_info->stream_src = stream_cfg_cmd->stream_src;
+	stream_info->frame_based = stream_cfg_cmd->frame_base;
+	return 0;
+}
+
+static uint32_t msm_isp_axi_get_plane_size(
+	struct msm_vfe_axi_stream *stream_info, int vfe_idx, int plane_idx)
+{
+	uint32_t size = 0;
+	struct msm_vfe_axi_plane_cfg *plane_cfg =
+				stream_info->plane_cfg[vfe_idx];
+	switch (stream_info->output_format) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_GREY:
+		size = plane_cfg[plane_idx].output_height *
+		plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR10DPCM6:
+	case V4L2_PIX_FMT_SGBRG10DPCM6:
+	case V4L2_PIX_FMT_SGRBG10DPCM6:
+	case V4L2_PIX_FMT_SRGGB10DPCM6:
+	case V4L2_PIX_FMT_SBGGR10DPCM8:
+	case V4L2_PIX_FMT_SGBRG10DPCM8:
+	case V4L2_PIX_FMT_SGRBG10DPCM8:
+	case V4L2_PIX_FMT_SRGGB10DPCM8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_META10:
+		/* TODO: fix me */
+		size = plane_cfg[plane_idx].output_height *
+		plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_SBGGR14:
+	case V4L2_PIX_FMT_SGBRG14:
+	case V4L2_PIX_FMT_SGRBG14:
+	case V4L2_PIX_FMT_SRGGB14:
+	case V4L2_PIX_FMT_QBGGR14:
+	case V4L2_PIX_FMT_QGBRG14:
+	case V4L2_PIX_FMT_QGRBG14:
+	case V4L2_PIX_FMT_QRGGB14:
+		/* TODO: fix me */
+		size = plane_cfg[plane_idx].output_height *
+		plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+		size = plane_cfg[plane_idx].output_height *
+		plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+		if (plane_cfg[plane_idx].output_plane_format == Y_PLANE)
+			size = plane_cfg[plane_idx].output_height *
+				plane_cfg[plane_idx].output_width;
+		else
+			size = plane_cfg[plane_idx].output_height *
+				plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+		if (plane_cfg[plane_idx].output_plane_format == Y_PLANE)
+			size = plane_cfg[plane_idx].output_height *
+				plane_cfg[plane_idx].output_width;
+		else
+			size = plane_cfg[plane_idx].output_height *
+				plane_cfg[plane_idx].output_width;
+		break;
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_NV24:
+	case V4L2_PIX_FMT_NV42:
+		size = plane_cfg[plane_idx].output_height *
+			plane_cfg[plane_idx].output_width;
+		break;
+	/*TD: Add more image format*/
+	default:
+		msm_isp_print_fourcc_error(__func__,
+				stream_info->output_format);
+		break;
+	}
+	return size;
+}
+
+static void msm_isp_axi_reserve_wm(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int i, j;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		for (j = 0; j < axi_data->hw_info->num_wm; j++) {
+			if (!axi_data->free_wm[j]) {
+				axi_data->free_wm[j] =
+					stream_info->stream_handle[vfe_idx];
+				axi_data->wm_image_size[j] =
+					msm_isp_axi_get_plane_size(
+						stream_info, vfe_idx, i);
+				axi_data->num_used_wm++;
+				break;
+			}
+		}
+		ISP_DBG("%s vfe %d stream_handle %x wm %d\n", __func__,
+			vfe_dev->pdev->id,
+			stream_info->stream_handle[vfe_idx], j);
+		stream_info->wm[vfe_idx][i] = j;
+		/* setup var to ignore bus error from RDI wm */
+		if (stream_info->stream_src >= RDI_INTF_0) {
+			if (vfe_dev->hw_info->vfe_ops.core_ops.
+				set_bus_err_ign_mask)
+				vfe_dev->hw_info->vfe_ops.core_ops.
+					set_bus_err_ign_mask(vfe_dev, j, 1);
+		}
+	}
+}
+
+void msm_isp_axi_free_wm(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		axi_data->free_wm[stream_info->wm[vfe_idx][i]] = 0;
+		axi_data->num_used_wm--;
+		if (stream_info->stream_src >= RDI_INTF_0) {
+			if (vfe_dev->hw_info->vfe_ops.core_ops.
+				set_bus_err_ign_mask)
+				vfe_dev->hw_info->vfe_ops.core_ops.
+					set_bus_err_ign_mask(vfe_dev,
+						stream_info->wm[vfe_idx][i], 0);
+		}
+	}
+	if (stream_info->stream_src <= IDEAL_RAW)
+		axi_data->num_pix_stream++;
+	else if (stream_info->stream_src < VFE_AXI_SRC_MAX)
+		axi_data->num_rdi_stream++;
+}
+
+static void msm_isp_axi_reserve_comp_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int i;
+	uint8_t comp_mask = 0;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		comp_mask |= 1 << stream_info->wm[vfe_idx][i];
+
+	for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
+		if (!axi_data->composite_info[i].stream_handle) {
+			axi_data->composite_info[i].stream_handle =
+				stream_info->stream_handle[vfe_idx];
+			axi_data->composite_info[i].
+				stream_composite_mask = comp_mask;
+			axi_data->num_used_composite_mask++;
+			break;
+		}
+	}
+	stream_info->comp_mask_index[vfe_idx] = i;
+}
+
+static void msm_isp_axi_free_comp_mask(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]].
+		stream_composite_mask = 0;
+	axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]].
+		stream_handle = 0;
+	axi_data->num_used_composite_mask--;
+}
+
+/**
+ * msm_isp_cfg_framedrop_reg() - Program the period and pattern
+ * @stream_info: The stream for which programming is done
+ *
+ * This function calculates the period and pattern to be configured
+ * for the stream based on the current frame id of the stream's input
+ * source and the initial framedrops.
+ *
+ * Returns void.
+ */
+static void msm_isp_cfg_framedrop_reg(
+	struct msm_vfe_axi_stream *stream_info)
+{
+	struct vfe_device *vfe_dev = stream_info->vfe_dev[0];
+	uint32_t runtime_init_frame_drop;
+	uint32_t framedrop_pattern = 0;
+	uint32_t framedrop_period = MSM_VFE_STREAM_STOP_PERIOD;
+	enum msm_vfe_input_src frame_src = SRC_TO_INTF(stream_info->stream_src);
+	int i;
+
+	if (vfe_dev->axi_data.src_info[frame_src].frame_id >=
+		stream_info->init_frame_drop)
+		runtime_init_frame_drop = 0;
+	else
+		runtime_init_frame_drop = stream_info->init_frame_drop -
+			vfe_dev->axi_data.src_info[frame_src].frame_id;
+
+	if (!runtime_init_frame_drop)
+		framedrop_period = stream_info->current_framedrop_period;
+
+	if (framedrop_period != MSM_VFE_STREAM_STOP_PERIOD)
+		framedrop_pattern = 0x1;
+
+	if (WARN_ON(framedrop_period == 0))
+		pr_err("%s framedrop_period is 0", __func__);
+
+	for (i = 0; i < stream_info->num_isp; i++) {
+		vfe_dev = stream_info->vfe_dev[i];
+		vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(
+					vfe_dev, stream_info, framedrop_pattern,
+					framedrop_period);
+	}
+
+	ISP_DBG("%s: stream %x src %x framedrop pattern %x period %u\n",
+			__func__,
+			stream_info->stream_handle[0], stream_info->stream_src,
+			framedrop_pattern, framedrop_period);
+
+	stream_info->requested_framedrop_period = framedrop_period;
+}
+
+static int msm_isp_composite_irq(struct vfe_device *vfe_dev,
+				struct msm_vfe_axi_stream *stream_info,
+				enum msm_isp_comp_irq_types irq)
+{
+	/* interrupt recv on same vfe w/o recv on other vfe */
+	if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) {
+		msm_isp_dump_ping_pong_mismatch(vfe_dev);
+		pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n",
+			__func__, irq, vfe_dev->pdev->id);
+		return -EINVAL;
+	}
+
+	stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id);
+	if (stream_info->composite_irq[irq] != stream_info->vfe_mask)
+		return 1;
+
+	stream_info->composite_irq[irq] = 0;
+
+	return 0;
+}
+
+/**
+ * msm_isp_update_framedrop_reg() - Update frame period pattern on h/w
+ * @stream_info: Stream for which update is to be performed
+ *
+ * If the period and pattern needs to be updated for a stream then it is
+ * updated here. Updates happen if initial frame drop reaches 0 or burst
+ * streams have been provided new skip pattern from user space.
+ *
+ * Returns void
+ */
+static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info)
+{
+	if (stream_info->stream_type == BURST_STREAM) {
+		if (stream_info->runtime_num_burst_capture == 0 ||
+			(stream_info->runtime_num_burst_capture == 1 &&
+			stream_info->activated_framedrop_period == 1))
+			stream_info->current_framedrop_period =
+				MSM_VFE_STREAM_STOP_PERIOD;
+	}
+
+	if (stream_info->undelivered_request_cnt > 0)
+		stream_info->current_framedrop_period =
+			MSM_VFE_STREAM_STOP_PERIOD;
+
+	/*
+	 * re-configure the period pattern, only if it's not already
+	 * set to what we want
+	 */
+	if (stream_info->current_framedrop_period !=
+		stream_info->requested_framedrop_period) {
+		msm_isp_cfg_framedrop_reg(stream_info);
+	}
+}
+
+void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src,
+	enum msm_isp_comp_irq_types irq,
+	struct msm_isp_timestamp *ts)
+{
+	int i;
+	struct msm_vfe_axi_stream *stream_info;
+	unsigned long flags;
+	int ret;
+
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev, i);
+		if (SRC_TO_INTF(stream_info->stream_src) !=
+			frame_src) {
+			continue;
+		}
+		if (stream_info->state == AVAILABLE ||
+			stream_info->state == INACTIVE)
+			continue;
+
+		spin_lock_irqsave(&stream_info->lock, flags);
+
+		ret = msm_isp_composite_irq(vfe_dev, stream_info, irq);
+		if (ret) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			if (ret < 0) {
+				msm_isp_halt_send_error(vfe_dev,
+						ISP_EVENT_PING_PONG_MISMATCH);
+				return;
+			}
+			continue;
+		}
+
+		switch (irq) {
+		case MSM_ISP_COMP_IRQ_REG_UPD:
+			stream_info->activated_framedrop_period =
+				stream_info->requested_framedrop_period;
+			__msm_isp_axi_stream_update(stream_info, ts);
+			break;
+		case MSM_ISP_COMP_IRQ_EPOCH:
+			if (stream_info->state == ACTIVE)
+				msm_isp_update_framedrop_reg(stream_info);
+			break;
+		default:
+			WARN(1, "Invalid irq %d\n", irq);
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+}
+
+/**
+ * msm_isp_reset_framedrop() - Compute the framedrop period pattern
+ * @vfe_dev: Device for which the period and pattern is computed
+ * @stream_info: The stream for the which period and pattern is generated
+ *
+ * This function is called when stream starts or is reset. It's main
+ * purpose is to setup the runtime parameters of framedrop required
+ * for the stream.
+ *
+ * Returms void
+ */
+void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info)
+{
+	uint32_t framedrop_period = 0;
+
+	stream_info->runtime_num_burst_capture = stream_info->num_burst_capture;
+
+	/**
+	 *  only reset none controllable output stream, since the
+	 *  controllable stream framedrop period will be controlled
+	 *  by the request frame api
+	 */
+	if (!stream_info->controllable_output) {
+		framedrop_period =
+			msm_isp_get_framedrop_period(
+			stream_info->frame_skip_pattern);
+		if (stream_info->frame_skip_pattern == SKIP_ALL)
+			stream_info->current_framedrop_period =
+				MSM_VFE_STREAM_STOP_PERIOD;
+		else
+			stream_info->current_framedrop_period =
+				framedrop_period;
+	}
+
+	msm_isp_cfg_framedrop_reg(stream_info);
+	ISP_DBG("%s: init frame drop: %d\n", __func__,
+		stream_info->init_frame_drop);
+	ISP_DBG("%s: num_burst_capture: %d\n", __func__,
+		stream_info->runtime_num_burst_capture);
+}
+
+void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
+	struct msm_isp_timestamp *ts, struct msm_isp_sof_info *sof_info)
+{
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data;
+	int i;
+	uint32_t stream_idx;
+
+	if (!vfe_dev || !sof_info) {
+		pr_err("%s %d failed: vfe_dev %pK sof_info %pK\n", __func__,
+			__LINE__, vfe_dev, sof_info);
+		return;
+	}
+	sof_info->regs_not_updated = 0;
+	sof_info->reg_update_fail_mask = 0;
+	sof_info->stream_get_buf_fail_mask = 0;
+
+	axi_data = &vfe_dev->axi_data;
+
+	for (i = 0; i < RDI_INTF_0; i++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+								i);
+		stream_idx = HANDLE_TO_IDX(stream_info->stream_handle[0]);
+
+		/*
+		 * Process drop only if controllable ACTIVE PIX stream &&
+		 * reg_not_updated
+		 * OR stream is in RESUMING state.
+		 * Other cases there is no drop to report, so continue.
+		 */
+		if (!((stream_info->state == ACTIVE &&
+			stream_info->controllable_output &&
+			(SRC_TO_INTF(stream_info->stream_src) ==
+			VFE_PIX_0)) ||
+			stream_info->state == RESUMING))
+			continue;
+
+		if (stream_info->controllable_output &&
+			!vfe_dev->reg_updated) {
+			if (stream_info->undelivered_request_cnt) {
+				/* report that registers are not updated
+				 * and return empty buffer for controllable
+				 * outputs
+				 */
+				sof_info->regs_not_updated =
+					!vfe_dev->reg_updated;
+				pr_err("Drop frame no reg update\n");
+				if (msm_isp_drop_frame(vfe_dev, stream_info, ts,
+					sof_info)) {
+					pr_err("drop frame failed\n");
+				}
+			}
+		}
+
+		if (stream_info->state == RESUMING &&
+			!stream_info->controllable_output) {
+			ISP_DBG("%s: axi_updating_mask strm_id %x frm_id %d\n",
+				__func__, stream_idx, vfe_dev->axi_data.
+				src_info[SRC_TO_INTF(stream_info->stream_src)]
+				.frame_id);
+			sof_info->axi_updating_mask |=
+				1 << stream_idx;
+		}
+	}
+
+	vfe_dev->reg_updated = 0;
+
+	/* report frame drop per stream */
+	if (vfe_dev->error_info.framedrop_flag) {
+		for (i = 0; i < BUF_MGR_NUM_BUF_Q; i++) {
+			if (vfe_dev->error_info.stream_framedrop_count[i]) {
+				ISP_DBG("%s: get buf failed i %d\n", __func__,
+					i);
+				sof_info->stream_get_buf_fail_mask |= (1 << i);
+				vfe_dev->error_info.
+					stream_framedrop_count[i] = 0;
+			}
+		}
+		vfe_dev->error_info.framedrop_flag = 0;
+	}
+}
+
+static void msm_isp_sync_dual_cam_frame_id(
+		struct vfe_device *vfe_dev,
+		struct master_slave_resource_info *ms_res,
+		enum msm_vfe_input_src frame_src,
+		struct msm_isp_timestamp *ts)
+{
+	struct msm_vfe_src_info *src_info =
+		&vfe_dev->axi_data.src_info[frame_src];
+	int i;
+	uint32_t frame_id = src_info->frame_id;
+	uint32_t master_time = 0, current_time;
+
+	if (src_info->dual_hw_ms_info.sync_state ==
+		ms_res->dual_sync_mode) {
+		(frame_src == VFE_PIX_0) ? src_info->frame_id +=
+				vfe_dev->axi_data.src_info[frame_src].
+				sof_counter_step :
+			src_info->frame_id++;
+		return;
+	}
+
+	/* find highest frame id */
+	for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+		if (ms_res->src_info[i] == NULL)
+			continue;
+		if (src_info == ms_res->src_info[i] ||
+			ms_res->src_info[i]->active == 0)
+			continue;
+		if (frame_id >= ms_res->src_info[i]->frame_id)
+			continue;
+		frame_id = ms_res->src_info[i]->frame_id;
+		master_time = ms_res->src_info[i]->
+			dual_hw_ms_info.sof_info.mono_timestamp_ms;
+	}
+	/* copy highest frame id to the intf based on sof delta */
+	current_time = ts->buf_time.tv_sec * 1000 +
+		ts->buf_time.tv_usec / 1000;
+
+	if (current_time > master_time &&
+		(current_time - master_time) > ms_res->sof_delta_threshold) {
+		if (frame_src == VFE_PIX_0)
+			frame_id += vfe_dev->axi_data.src_info[frame_src].
+					sof_counter_step;
+		else
+			frame_id += 1;
+	} else {
+		for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+			if (ms_res->src_info[i] == NULL)
+				continue;
+			if (src_info == ms_res->src_info[i] ||
+				((1 << ms_res->src_info[i]->
+					dual_hw_ms_info.index) &
+				ms_res->active_src_mask) == 0)
+				continue;
+			if (ms_res->src_info[i]->frame_id == frame_id)
+				ms_res->src_sof_mask |= (1 <<
+				ms_res->src_info[i]->dual_hw_ms_info.index);
+		}
+	}
+	ms_res->active_src_mask |= (1 << src_info->dual_hw_ms_info.index);
+	src_info->frame_id = frame_id;
+	src_info->dual_hw_ms_info.sync_state = MSM_ISP_DUAL_CAM_SYNC;
+}
+
+void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts)
+{
+	struct msm_vfe_src_info *src_info = NULL;
+	struct msm_vfe_sof_info *sof_info = NULL;
+	enum msm_vfe_dual_hw_type dual_hw_type;
+	enum msm_vfe_dual_hw_ms_type ms_type;
+	unsigned long flags;
+	int i;
+	struct master_slave_resource_info *ms_res =
+				&vfe_dev->common_data->ms_resource;
+
+	spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags);
+	dual_hw_type =
+		vfe_dev->axi_data.src_info[frame_src].dual_hw_type;
+	ms_type =
+		vfe_dev->axi_data.src_info[frame_src].
+		dual_hw_ms_info.dual_hw_ms_type;
+
+	src_info = &vfe_dev->axi_data.src_info[frame_src];
+	if (dual_hw_type == DUAL_HW_MASTER_SLAVE) {
+		msm_isp_sync_dual_cam_frame_id(vfe_dev, ms_res, frame_src, ts);
+		if (src_info->dual_hw_ms_info.sync_state ==
+			MSM_ISP_DUAL_CAM_SYNC) {
+			/*
+			 * for dual hw check that we recv sof from all
+			 * linked intf
+			 */
+			if (ms_res->src_sof_mask & (1 <<
+				src_info->dual_hw_ms_info.index)) {
+				pr_err_ratelimited("Frame out of sync on vfe %d\n",
+					vfe_dev->pdev->id);
+				/*
+				 * set this isp as async mode to force
+				 *it sync again at the next sof
+				 */
+				src_info->dual_hw_ms_info.sync_state =
+							MSM_ISP_DUAL_CAM_ASYNC;
+				/*
+				 * set the other isp as async mode to force
+				 * it sync again at the next sof
+				 */
+				for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+					if (ms_res->src_info[i] == NULL)
+						continue;
+					if (src_info == ms_res->src_info[i] ||
+						ms_res->src_info[i]->
+								active == 0)
+						continue;
+					ms_res->src_info[i]->dual_hw_ms_info.
+							sync_state =
+							MSM_ISP_DUAL_CAM_ASYNC;
+				}
+			}
+			ms_res->src_sof_mask |= (1 <<
+					src_info->dual_hw_ms_info.index);
+			if (ms_res->active_src_mask == ms_res->src_sof_mask)
+				ms_res->src_sof_mask = 0;
+		}
+		sof_info = &vfe_dev->axi_data.src_info[frame_src].
+			dual_hw_ms_info.sof_info;
+		sof_info->frame_id = vfe_dev->axi_data.src_info[frame_src].
+			frame_id;
+		sof_info->timestamp_ms = ts->event_time.tv_sec * 1000 +
+			ts->event_time.tv_usec / 1000;
+		sof_info->mono_timestamp_ms = ts->buf_time.tv_sec * 1000 +
+			ts->buf_time.tv_usec / 1000;
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+	} else {
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+		if (frame_src == VFE_PIX_0) {
+			vfe_dev->axi_data.src_info[frame_src].frame_id +=
+				vfe_dev->axi_data.src_info[frame_src].
+				sof_counter_step;
+			ISP_DBG("%s: vfe %d sof_step %d\n", __func__,
+			vfe_dev->pdev->id,
+			vfe_dev->axi_data.src_info[frame_src].
+				sof_counter_step);
+		} else {
+			vfe_dev->axi_data.src_info[frame_src].frame_id++;
+		}
+	}
+
+	if (frame_src == VFE_PIX_0) {
+		if (vfe_dev->isp_page == NULL)
+			pr_err("Invalid ISP PAGE");
+		else
+			vfe_dev->isp_page->kernel_sofid =
+				vfe_dev->axi_data.src_info[frame_src].frame_id;
+
+		if (!src_info->frame_id &&
+			!src_info->reg_update_frame_id &&
+			((src_info->frame_id -
+			src_info->reg_update_frame_id) >
+			(MAX_REG_UPDATE_THRESHOLD *
+			src_info->sof_counter_step))) {
+			pr_err("%s:%d reg_update not received for %d frames\n",
+				__func__, __LINE__,
+				src_info->frame_id -
+				src_info->reg_update_frame_id);
+
+			msm_isp_halt_send_error(vfe_dev,
+				ISP_EVENT_REG_UPDATE_MISSING);
+		}
+	}
+}
+
+static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src)
+{
+	struct msm_vfe_axi_stream *pd_stream_info = NULL;
+	uint32_t pingpong_status = 0, pingpong_bit = 0;
+	struct msm_isp_buffer *done_buf = NULL;
+	int vfe_idx = -1;
+	unsigned long flags;
+
+	if (frame_src < VFE_RAW_0 || frame_src >  VFE_RAW_2)
+		return;
+
+	pd_stream_info = msm_isp_get_stream_common_data(vfe_dev,
+		RDI_INTF_0 + frame_src - VFE_RAW_0);
+
+	if (pd_stream_info && (pd_stream_info->state == ACTIVE) &&
+		(pd_stream_info->rdi_input_type ==
+		MSM_CAMERA_RDI_PDAF)) {
+		vfe_idx = msm_isp_get_vfe_idx_for_stream(
+				vfe_dev, pd_stream_info);
+		pingpong_status = vfe_dev->hw_info->vfe_ops.axi_ops.
+					get_pingpong_status(vfe_dev);
+		pingpong_bit = ((pingpong_status >>
+			pd_stream_info->wm[vfe_idx][0]) & 0x1);
+		done_buf = pd_stream_info->buf[pingpong_bit];
+		spin_lock_irqsave(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+		if (done_buf)
+			vfe_dev->common_data->pd_buf_idx = done_buf->buf_idx;
+		else
+			vfe_dev->common_data->pd_buf_idx = 0xF;
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+	}
+}
+
+void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts)
+{
+	struct msm_isp_event_data event_data;
+	struct msm_vfe_sof_info *sof_info = NULL, *self_sof = NULL;
+	enum msm_vfe_dual_hw_ms_type ms_type;
+	unsigned long flags;
+
+	memset(&event_data, 0, sizeof(event_data));
+
+	switch (event_type) {
+	case ISP_EVENT_SOF:
+		if (frame_src == VFE_PIX_0) {
+			if (vfe_dev->isp_sof_debug < ISP_SOF_DEBUG_COUNT)
+				pr_err("%s: PIX0 frame id: %u\n", __func__,
+				vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+			vfe_dev->isp_sof_debug++;
+		} else if (frame_src == VFE_RAW_0) {
+			if (vfe_dev->isp_raw0_debug < ISP_SOF_DEBUG_COUNT)
+				pr_err("%s: RAW_0 frame id: %u\n", __func__,
+				vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id);
+			vfe_dev->isp_raw0_debug++;
+		} else if (frame_src == VFE_RAW_1) {
+			if (vfe_dev->isp_raw1_debug < ISP_SOF_DEBUG_COUNT)
+				pr_err("%s: RAW_1 frame id: %u\n", __func__,
+				vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id);
+			vfe_dev->isp_raw1_debug++;
+		} else if (frame_src == VFE_RAW_2) {
+			if (vfe_dev->isp_raw2_debug < ISP_SOF_DEBUG_COUNT)
+				pr_err("%s: RAW_2 frame id: %u\n", __func__,
+				vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id);
+			vfe_dev->isp_raw2_debug++;
+		}
+
+		ISP_DBG("%s: vfe %d frame_src %d\n", __func__,
+			vfe_dev->pdev->id, frame_src);
+
+		/*
+		 * Cannot support dual_cam and framedrop same time in union.
+		 * If need to support framedrop as well, move delta calculation
+		 * to userspace
+		 */
+		spin_lock_irqsave(
+			&vfe_dev->common_data->common_dev_data_lock,
+			flags);
+		if (vfe_dev->common_data->ms_resource.dual_sync_mode ==
+						MSM_ISP_DUAL_CAM_SYNC &&
+			vfe_dev->axi_data.src_info[frame_src].dual_hw_type ==
+			DUAL_HW_MASTER_SLAVE) {
+			struct master_slave_resource_info *ms_res =
+				&vfe_dev->common_data->ms_resource;
+			self_sof = &vfe_dev->axi_data.src_info[frame_src].
+				dual_hw_ms_info.sof_info;
+			ms_type = vfe_dev->axi_data.src_info[frame_src].
+				dual_hw_ms_info.dual_hw_ms_type;
+			/* only send back time delta for primatry intf */
+			if (ms_res->primary_slv_idx > 0 &&
+					ms_type == MS_TYPE_MASTER)
+				sof_info = &ms_res->src_info[
+					ms_res->primary_slv_idx]->
+					dual_hw_ms_info.sof_info;
+			if (ms_type != MS_TYPE_MASTER &&
+				ms_res->master_index > 0)
+				sof_info = &ms_res->src_info[
+					ms_res->master_index]->
+					dual_hw_ms_info.sof_info;
+			if (sof_info) {
+				event_data.u.sof_info.ms_delta_info.
+					delta[0] =
+					self_sof->mono_timestamp_ms -
+					sof_info->mono_timestamp_ms;
+				event_data.u.sof_info.ms_delta_info.
+				num_delta_info = 1;
+			}
+		}
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+		if (frame_src == VFE_PIX_0)
+			msm_isp_check_for_output_error(vfe_dev, ts,
+					&event_data.u.sof_info);
+		/*
+		 * Get and store the buf idx for PD stats
+		 * this is to send the PD stats buffer address
+		 * in BF stats done.
+		 */
+		msm_isp_update_pd_stats_idx(vfe_dev, frame_src);
+		break;
+
+	default:
+		break;
+	}
+
+	event_data.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
+	event_data.timestamp = ts->event_time;
+	event_data.mono_timestamp = ts->buf_time;
+	msm_isp_send_event(vfe_dev, event_type | frame_src, &event_data);
+}
+
+/**
+ * msm_isp_calculate_framedrop() - Setup frame period and pattern
+ * @vfe_dev: vfe device.
+ * @stream_cfg_cmd: User space input parameter for perion/pattern.
+ *
+ * Initialize the h/w stream framedrop period and pattern sent
+ * by user space.
+ *
+ * Returns 0 on success else error code.
+ */
+static int msm_isp_calculate_framedrop(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+{
+	uint32_t framedrop_period = 0;
+	struct msm_vfe_axi_stream *stream_info = NULL;
+
+	if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)
+		< VFE_AXI_SRC_MAX) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+			HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle));
+	} else {
+		pr_err("%s: Invalid stream handle", __func__);
+		return -EINVAL;
+	}
+	if (!stream_info) {
+		pr_err("%s: Stream info is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	framedrop_period = msm_isp_get_framedrop_period(
+	   stream_cfg_cmd->frame_skip_pattern);
+	stream_info->frame_skip_pattern =
+		stream_cfg_cmd->frame_skip_pattern;
+	if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
+		stream_info->current_framedrop_period =
+			MSM_VFE_STREAM_STOP_PERIOD;
+	else
+		stream_info->current_framedrop_period = framedrop_period;
+
+	stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop;
+
+	if (stream_cfg_cmd->burst_count > 0) {
+		stream_info->stream_type = BURST_STREAM;
+		stream_info->num_burst_capture =
+			stream_cfg_cmd->burst_count;
+	} else {
+		stream_info->stream_type = CONTINUOUS_STREAM;
+	}
+	return 0;
+}
+
+static void msm_isp_calculate_bandwidth(
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int bpp = 0;
+	struct vfe_device *vfe_dev;
+	struct msm_vfe_axi_shared_data *axi_data;
+	int i;
+
+	for (i = 0; i < stream_info->num_isp; i++) {
+		vfe_dev = stream_info->vfe_dev[i];
+		axi_data = &vfe_dev->axi_data;
+		if (stream_info->stream_src < RDI_INTF_0) {
+			stream_info->bandwidth[i] =
+				(vfe_dev->vfe_clk_info[
+				vfe_dev->hw_info->vfe_clk_idx].clk_rate /
+				axi_data->src_info[VFE_PIX_0].width) *
+				stream_info->max_width[i];
+			stream_info->bandwidth[i] =
+				(unsigned long)stream_info->bandwidth[i] *
+				stream_info->format_factor / ISP_Q2;
+		} else {
+			int rdi = SRC_TO_INTF(stream_info->stream_src);
+
+			bpp = msm_isp_get_bit_per_pixel(
+					stream_info->output_format);
+			if (rdi < VFE_SRC_MAX) {
+				stream_info->bandwidth[i] =
+				(vfe_dev->vfe_clk_info[
+				vfe_dev->hw_info->vfe_clk_idx].clk_rate /
+				8) * bpp;
+			} else {
+				pr_err("%s: Invalid rdi interface\n", __func__);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_MSM_AVTIMER
+/**
+ * msm_isp_set_avtimer_fptr() - Set avtimer function pointer
+ * @avtimer: struct of type avtimer_fptr_t to hold function pointer.
+ *
+ * Initialize the function pointers sent by the avtimer driver
+ *
+ */
+void msm_isp_set_avtimer_fptr(struct avtimer_fptr_t avtimer)
+{
+	avtimer_func.fptr_avtimer_open   = avtimer.fptr_avtimer_open;
+	avtimer_func.fptr_avtimer_enable = avtimer.fptr_avtimer_enable;
+	avtimer_func.fptr_avtimer_get_time = avtimer.fptr_avtimer_get_time;
+}
+EXPORT_SYMBOL(msm_isp_set_avtimer_fptr);
+
+void msm_isp_start_avtimer(void)
+{
+	if (avtimer_func.fptr_avtimer_open &&
+			avtimer_func.fptr_avtimer_enable) {
+		avtimer_func.fptr_avtimer_open();
+		avtimer_func.fptr_avtimer_enable(1);
+	}
+}
+void msm_isp_stop_avtimer(void)
+{
+	if (avtimer_func.fptr_avtimer_enable) {
+		avtimer_func.fptr_avtimer_enable(0);
+	}
+}
+
+void msm_isp_get_avtimer_ts(
+		struct msm_isp_timestamp *time_stamp)
+{
+	int rc = 0;
+	uint32_t avtimer_usec = 0;
+	uint64_t avtimer_tick = 0;
+
+	if (avtimer_func.fptr_avtimer_get_time) {
+		rc = avtimer_func.fptr_avtimer_get_time(&avtimer_tick);
+		if (rc < 0) {
+			pr_err_ratelimited("%s: Error: Invalid AVTimer Tick, rc=%d\n",
+				   __func__, rc);
+			/* In case of error return zero AVTimer Tick Value */
+			time_stamp->vt_time.tv_sec = 0;
+			time_stamp->vt_time.tv_usec = 0;
+		} else {
+			avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC);
+			time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick);
+			time_stamp->vt_time.tv_usec = avtimer_usec;
+			pr_debug("%s: AVTimer TS = %u:%u\n", __func__,
+				(uint32_t)(avtimer_tick), avtimer_usec);
+		}
+	}
+}
+#else
+void msm_isp_start_avtimer(void)
+{
+	pr_err("AV Timer is not supported\n");
+}
+
+void msm_isp_get_avtimer_ts(
+		struct msm_isp_timestamp *time_stamp)
+{
+	struct timespec ts;
+
+	pr_debug("%s: AVTimer driver not available using system time\n",
+		__func__);
+
+	get_monotonic_boottime(&ts);
+	time_stamp->vt_time.tv_sec    = ts.tv_sec;
+	time_stamp->vt_time.tv_usec   = ts.tv_nsec/1000;
+}
+#endif
+
+int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i = 0;
+	uint32_t io_format = 0;
+	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
+	struct msm_vfe_axi_stream *stream_info;
+
+	if (stream_cfg_cmd->stream_src >= VFE_AXI_SRC_MAX) {
+		pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__,
+			stream_cfg_cmd->stream_src);
+		return -EINVAL;
+	}
+	stream_info = msm_isp_get_stream_common_data(vfe_dev,
+					stream_cfg_cmd->stream_src);
+
+	rc = msm_isp_axi_create_stream(vfe_dev,
+		&vfe_dev->axi_data, stream_cfg_cmd, stream_info);
+	if (rc) {
+		pr_err("%s: create stream failed\n", __func__);
+		return rc;
+	}
+
+	rc = msm_isp_validate_axi_request(
+		vfe_dev, stream_info, stream_cfg_cmd);
+	if (rc) {
+		msm_isp_axi_destroy_stream(vfe_dev, stream_info);
+		pr_err("%s: Request validation failed\n", __func__);
+		return rc;
+	}
+
+	stream_info->rdi_input_type = stream_cfg_cmd->rdi_input_type;
+	vfe_dev->reg_update_requested &=
+		~(BIT(SRC_TO_INTF(stream_info->stream_src)));
+
+	msm_isp_axi_reserve_wm(vfe_dev, stream_info);
+
+	if (stream_info->stream_src < RDI_INTF_0) {
+		io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format;
+		if (stream_info->stream_src == CAMIF_RAW ||
+			stream_info->stream_src == IDEAL_RAW) {
+			if (stream_info->stream_src == CAMIF_RAW &&
+				io_format != stream_info->output_format)
+				pr_debug("%s: Overriding input format\n",
+					__func__);
+
+			io_format = stream_info->output_format;
+		}
+		rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+			vfe_dev, stream_info->stream_src, io_format);
+		if (rc) {
+			pr_err("%s: cfg io format failed\n", __func__);
+			goto done;
+		}
+	}
+
+	if (!stream_info->controllable_output) {
+		/*
+		 * check that the parameters passed from second vfe is same
+		 * as first vfe, do this only for non controllable stream
+		 * right now because user driver has bug where it sends
+		 * mismatch info for controllable streams
+		 */
+		if (stream_info->num_isp > 1) {
+			if (stream_cfg_cmd->init_frame_drop !=
+				stream_info->init_frame_drop) {
+				pr_err("%s: stream %d init drop mismatch %d/%d\n",
+					__func__, stream_info->stream_id,
+					stream_info->init_frame_drop,
+					stream_cfg_cmd->init_frame_drop);
+				rc = -EINVAL;
+			}
+			if (stream_cfg_cmd->frame_skip_pattern !=
+				stream_info->frame_skip_pattern) {
+				pr_err("%s: stream %d skip pattern mismatch %d/%d\n",
+					__func__, stream_info->stream_id,
+					stream_info->frame_skip_pattern,
+					stream_cfg_cmd->frame_skip_pattern);
+				rc = -EINVAL;
+			}
+			if (stream_info->stream_type == CONTINUOUS_STREAM &&
+				stream_cfg_cmd->burst_count > 0) {
+				pr_err("%s: stream %d stream type mismatch\n",
+					__func__, stream_info->stream_id);
+				rc = -EINVAL;
+			}
+			if (stream_info->stream_type == BURST_STREAM &&
+				stream_info->num_burst_capture !=
+				stream_cfg_cmd->burst_count) {
+				pr_err("%s: stream %d stream burst count mismatch %d/%d\n",
+					__func__, stream_info->stream_id,
+					stream_info->num_burst_capture,
+					stream_cfg_cmd->burst_count);
+				rc = -EINVAL;
+			}
+		} else {
+			rc = msm_isp_calculate_framedrop(vfe_dev,
+							stream_cfg_cmd);
+		}
+		if (rc)
+			goto done;
+	} else {
+		stream_info->stream_type = BURST_STREAM;
+		stream_info->num_burst_capture = 0;
+		stream_info->frame_skip_pattern = NO_SKIP;
+		stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop;
+		stream_info->current_framedrop_period =
+				MSM_VFE_STREAM_STOP_PERIOD;
+	}
+	if (stream_cfg_cmd->vt_enable && !vfe_dev->vt_enable) {
+		vfe_dev->vt_enable = stream_cfg_cmd->vt_enable;
+		msm_isp_start_avtimer();
+	}
+
+	if (stream_info->num_planes > 1)
+		msm_isp_axi_reserve_comp_mask(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			cfg_wm_reg(vfe_dev, stream_info, i);
+
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			cfg_wm_xbar_reg(vfe_dev, stream_info, i);
+	}
+	if (stream_info->state == INACTIVE) {
+		/* initialize the WM ping pong with scratch buffer */
+		msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG);
+		msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG);
+	}
+done:
+	if (rc) {
+		msm_isp_axi_free_wm(vfe_dev, stream_info);
+		msm_isp_axi_destroy_stream(vfe_dev, stream_info);
+	}
+	return rc;
+}
+
+int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i = 0;
+	struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
+	int vfe_idx;
+
+	if (HANDLE_TO_IDX(stream_release_cmd->stream_handle) >=
+		VFE_AXI_SRC_MAX) {
+		pr_err("%s: Invalid stream handle\n", __func__);
+		return -EINVAL;
+	}
+	stream_info = msm_isp_get_stream_common_data(vfe_dev,
+		HANDLE_TO_IDX(stream_release_cmd->stream_handle));
+
+	vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info);
+	if (vfe_idx == -ENOTTY ||
+		stream_release_cmd->stream_handle !=
+		stream_info->stream_handle[vfe_idx]) {
+		pr_err("%s: Invalid stream %pK handle %x/%x vfe_idx %d vfe_dev %d num_isp %d\n",
+			__func__, stream_info,
+			stream_release_cmd->stream_handle,
+			vfe_idx != -ENOTTY ?
+			stream_info->stream_handle[vfe_idx] : 0, vfe_idx,
+			vfe_dev->pdev->id, stream_info->num_isp);
+		return -EINVAL;
+	}
+
+	if (stream_info->state != INACTIVE && stream_info->state != AVAILABLE) {
+		stream_cfg.cmd = STOP_STREAM;
+		stream_cfg.num_streams = 1;
+		stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle;
+		msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg);
+	}
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			clear_wm_reg(vfe_dev, stream_info, i);
+
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+		clear_wm_xbar_reg(vfe_dev, stream_info, i);
+	}
+
+	if (stream_info->num_planes > 1)
+		msm_isp_axi_free_comp_mask(vfe_dev, stream_info);
+
+	vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info);
+	msm_isp_axi_free_wm(vfe_dev, stream_info);
+
+	msm_isp_axi_destroy_stream(vfe_dev, stream_info);
+
+	return rc;
+}
+
+void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_axi_stream_release_cmd
+			stream_release_cmd[VFE_AXI_SRC_MAX];
+	struct msm_vfe_axi_stream_cfg_cmd stream_cfg_cmd;
+	struct msm_vfe_axi_stream *stream_info;
+	int i;
+	int vfe_idx;
+	int num_stream = 0;
+	unsigned long flags;
+
+	stream_cfg_cmd.cmd = STOP_STREAM;
+	stream_cfg_cmd.num_streams = 0;
+
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev, i);
+		spin_lock_irqsave(&stream_info->lock, flags);
+		vfe_idx = msm_isp_get_vfe_idx_for_stream_user(
+						vfe_dev, stream_info);
+		if (-ENOTTY == vfe_idx) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		stream_release_cmd[num_stream++].stream_handle =
+			stream_info->stream_handle[vfe_idx];
+		if (stream_info->state == INACTIVE) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		stream_cfg_cmd.stream_handle[
+			stream_cfg_cmd.num_streams] =
+			stream_info->stream_handle[vfe_idx];
+		stream_cfg_cmd.num_streams++;
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+	if (stream_cfg_cmd.num_streams)
+		msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg_cmd);
+
+	for (i = 0; i < num_stream; i++)
+		msm_isp_release_axi_stream(vfe_dev, &stream_release_cmd[i]);
+}
+
+static void msm_isp_axi_stream_enable_cfg(
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int enable_wm = 0;
+	struct vfe_device *vfe_dev;
+	struct msm_vfe_axi_shared_data *axi_data;
+	uint32_t stream_idx = stream_info->stream_src;
+	int k;
+	int i;
+
+	WARN_ON(stream_idx >= VFE_AXI_SRC_MAX);
+
+	WARN_ON(stream_info->state != START_PENDING &&
+		stream_info->state != RESUME_PENDING &&
+		stream_info->state != STOP_PENDING &&
+		stream_info->state != PAUSE_PENDING);
+
+	if (stream_info->state == START_PENDING ||
+		stream_info->state == RESUME_PENDING) {
+		enable_wm = 1;
+	} else {
+		enable_wm = 0;
+	}
+
+	for (k = 0; k < stream_info->num_isp; k++) {
+		vfe_dev = stream_info->vfe_dev[k];
+		axi_data = &vfe_dev->axi_data;
+		for (i = 0; i < stream_info->num_planes; i++) {
+			vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm(
+				vfe_dev->vfe_base,
+				stream_info->wm[k][i], enable_wm);
+			if (enable_wm)
+				continue;
+			/*
+			 * Issue a reg update for Raw Snapshot Case
+			 * since we dont have reg update ack
+			 */
+			if (vfe_dev->axi_data.src_info[VFE_PIX_0].
+				raw_stream_count > 0
+				&& vfe_dev->axi_data.src_info[VFE_PIX_0].
+				stream_count == 0) {
+				if (stream_info->stream_src == CAMIF_RAW ||
+					stream_info->stream_src == IDEAL_RAW) {
+					vfe_dev->hw_info->vfe_ops.core_ops.
+						reg_update(vfe_dev,
+						VFE_PIX_0);
+				}
+			}
+		}
+		if (stream_info->state == START_PENDING)
+			axi_data->num_active_stream++;
+		else if (stream_info->state == STOP_PENDING)
+			axi_data->num_active_stream--;
+	}
+}
+
+static void __msm_isp_axi_stream_update(
+			struct msm_vfe_axi_stream *stream_info,
+			struct msm_isp_timestamp *ts)
+{
+	int j;
+	int intf = SRC_TO_INTF(stream_info->stream_src);
+	struct vfe_device *vfe_dev;
+	int k;
+
+	switch (stream_info->state) {
+	case UPDATING:
+		stream_info->state = ACTIVE;
+		complete_all(&stream_info->active_comp);
+		break;
+	case STOP_PENDING:
+		msm_isp_axi_stream_enable_cfg(stream_info);
+		stream_info->state = STOPPING;
+		break;
+	case START_PENDING:
+		msm_isp_axi_stream_enable_cfg(stream_info);
+		stream_info->state = STARTING;
+		break;
+	case STOPPING:
+		stream_info->state = INACTIVE;
+		for (k = 0; k < MSM_ISP_COMP_IRQ_MAX; k++)
+			stream_info->composite_irq[k] = 0;
+		complete_all(&stream_info->inactive_comp);
+		break;
+	case STARTING:
+		stream_info->state = ACTIVE;
+		complete_all(&stream_info->active_comp);
+		break;
+	case PAUSING:
+		stream_info->state = PAUSED;
+		msm_isp_reload_ping_pong_offset(stream_info);
+		for (j = 0; j < stream_info->num_planes; j++) {
+			for (k = 0; k < stream_info->num_isp; k++) {
+				vfe_dev = stream_info->vfe_dev[k];
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_wm_reg(vfe_dev, stream_info, j);
+			}
+		}
+		stream_info->state = RESUME_PENDING;
+		msm_isp_axi_stream_enable_cfg(stream_info);
+		stream_info->state = RESUMING;
+		break;
+	case RESUMING:
+		stream_info->runtime_output_format = stream_info->output_format;
+		stream_info->state = ACTIVE;
+		complete_all(&stream_info->active_comp);
+		for (j = 0; j < stream_info->num_isp; j++) {
+			/* notify that all streams have been updated */
+			msm_isp_notify(stream_info->vfe_dev[j],
+				ISP_EVENT_STREAM_UPDATE_DONE, intf, ts);
+			atomic_set(&stream_info->vfe_dev[j]->
+				axi_data.axi_cfg_update[intf], 0);
+		}
+		stream_info->update_vfe_mask = 0;
+		break;
+	default:
+		break;
+	}
+}
+
+void msm_isp_axi_stream_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src,
+	struct msm_isp_timestamp *ts)
+{
+	int i;
+	unsigned long flags;
+	struct msm_vfe_axi_stream *stream_info;
+
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev, i);
+		if (SRC_TO_INTF(stream_info->stream_src) !=
+			frame_src) {
+			ISP_DBG("%s stream_src %d frame_src %d\n", __func__,
+				SRC_TO_INTF(
+				stream_info->stream_src),
+				frame_src);
+			continue;
+		}
+		if (stream_info->state == AVAILABLE)
+			continue;
+		spin_lock_irqsave(&stream_info->lock, flags);
+		__msm_isp_axi_stream_update(stream_info, ts);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+}
+
+static void msm_isp_reload_ping_pong_offset(
+		struct msm_vfe_axi_stream *stream_info)
+{
+	int i, j;
+	uint32_t bit;
+	struct msm_isp_buffer *buf;
+	int32_t buf_size_byte = 0;
+	int32_t word_per_line = 0;
+	int k;
+	struct vfe_device *vfe_dev;
+
+	for (k = 0; k < stream_info->num_isp; k++) {
+		vfe_dev = stream_info->vfe_dev[k];
+		for (i = 0; i < 2; i++) {
+			buf = stream_info->buf[i];
+			if (!buf)
+				continue;
+
+			bit = i ? 0 : 1;
+
+			for (j = 0; j < stream_info->num_planes; j++) {
+				word_per_line = msm_isp_cal_word_per_line(
+				stream_info->output_format, stream_info->
+				plane_cfg[k][j].output_stride);
+				if (word_per_line < 0) {
+					/* 0 means no prefetch*/
+					word_per_line = 0;
+					buf_size_byte = 0;
+				} else {
+					buf_size_byte = (word_per_line * 8 *
+					stream_info->plane_cfg[k][j].
+					output_scan_lines) - stream_info->
+					plane_cfg[k][j].plane_addr_offset;
+				}
+
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					update_ping_pong_addr(
+					vfe_dev->vfe_base,
+					stream_info->wm[k][j],
+					bit,
+					buf->mapped_info[j].paddr +
+					stream_info->plane_cfg[k][j].
+							plane_addr_offset,
+					buf_size_byte);
+			}
+		}
+	}
+}
+
+static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit,
+	struct msm_isp_buffer *done_buf)
+{
+	int rc = 0;
+
+	if (!stream_info->controllable_output)
+		goto done;
+
+	if (!stream_info->undelivered_request_cnt ||
+		(done_buf == NULL)) {
+		pr_err_ratelimited("%s:%d error undelivered_request_cnt 0\n",
+			__func__, __LINE__);
+		rc = -EINVAL;
+		goto done;
+	} else {
+		if ((done_buf->is_drop_reconfig == 1) &&
+			(stream_info->sw_ping_pong_bit == -1)) {
+			goto done;
+		}
+		/*After wm reload, we get bufdone for ping buffer*/
+		if (stream_info->sw_ping_pong_bit == -1)
+			stream_info->sw_ping_pong_bit = 0;
+		if (done_buf->is_drop_reconfig != 1)
+			stream_info->undelivered_request_cnt--;
+		if (pingpong_bit != stream_info->sw_ping_pong_bit) {
+			pr_err("%s:%d ping pong bit actual %d sw %d\n",
+				__func__, __LINE__, pingpong_bit,
+				stream_info->sw_ping_pong_bit);
+			rc = -EINVAL;
+			goto done;
+		}
+		stream_info->sw_ping_pong_bit ^= 1;
+	}
+done:
+	return rc;
+}
+
+void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event)
+{
+	struct msm_isp_event_data error_event;
+	struct msm_vfe_axi_halt_cmd halt_cmd;
+	struct vfe_device *temp_dev = NULL;
+	uint32_t irq_status0 = 0, irq_status1 = 0;
+
+	if (atomic_read(&vfe_dev->error_info.overflow_state) !=
+		NO_OVERFLOW)
+		/* Recovery is already in Progress */
+		return;
+
+	if (event == ISP_EVENT_PING_PONG_MISMATCH &&
+		vfe_dev->axi_data.recovery_count < MAX_RECOVERY_THRESHOLD) {
+		pr_err("%s: ping pong mismatch on vfe%d recovery count %d\n",
+			__func__, vfe_dev->pdev->id,
+			vfe_dev->axi_data.recovery_count);
+		msm_isp_process_overflow_irq(vfe_dev,
+			&irq_status0, &irq_status1, 1);
+		vfe_dev->axi_data.recovery_count++;
+		return;
+	}
+	memset(&halt_cmd, 0, sizeof(struct msm_vfe_axi_halt_cmd));
+	memset(&error_event, 0, sizeof(struct msm_isp_event_data));
+	halt_cmd.stop_camif = 1;
+	halt_cmd.overflow_detected = 0;
+	halt_cmd.blocking_halt = 0;
+
+	pr_err("%s: vfe%d fatal error!\n", __func__, vfe_dev->pdev->id);
+
+	atomic_set(&vfe_dev->error_info.overflow_state,
+		HALT_ENFORCED);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.set_halt_restart_mask(vfe_dev);
+	if (vfe_dev->is_split) {
+		int other_vfe_id = (vfe_dev->pdev->id == ISP_VFE0 ?
+					ISP_VFE1 : ISP_VFE0);
+		temp_dev = vfe_dev->common_data->
+			dual_vfe_res->vfe_dev[other_vfe_id];
+		atomic_set(&temp_dev->error_info.overflow_state,
+			HALT_ENFORCED);
+		temp_dev->hw_info->vfe_ops.core_ops.
+				set_halt_restart_mask(temp_dev);
+	}
+	error_event.frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+
+	msm_isp_send_event(vfe_dev, event, &error_event);
+}
+
+int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev,
+	unsigned long fault_addr)
+{
+	int i, j;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t pingpong_bit;
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	int k;
+
+	for (j = 0; j < VFE_AXI_SRC_MAX; j++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev, j);
+		if (stream_info->state == INACTIVE ||
+			stream_info->state == AVAILABLE)
+			continue;
+
+		for (pingpong_bit = 0; pingpong_bit < 2; pingpong_bit++) {
+			dma_addr_t temp;
+
+			buf = stream_info->buf[pingpong_bit];
+			if (buf == NULL) {
+				pr_err("%s: buf NULL for stream %x num_isp %d\n",
+					__func__,
+					stream_info->stream_src,
+					stream_info->num_isp);
+				continue;
+			}
+			temp = buf->mapped_info[0].paddr +
+				buf->mapped_info[0].len;
+			pr_err("%s: stream %x ping bit %d uses buffer %pK-%pK, num_isp %d\n",
+				__func__, stream_info->stream_src,
+				pingpong_bit,
+				&buf->mapped_info[0].paddr, &temp,
+				stream_info->num_isp);
+
+			for (i = 0; i < stream_info->num_planes; i++) {
+				for (k = 0; k < stream_info->num_isp; k++) {
+					pr_debug(
+					"%s: stream_id %x ping-pong %d	plane %d start_addr %pK	addr_offset %x len %zx stride %d scanline %d\n"
+					, __func__, stream_info->stream_id,
+					pingpong_bit, i,
+					(void *)buf->mapped_info[i].paddr,
+					stream_info->
+					plane_cfg[k][i].plane_addr_offset,
+					buf->mapped_info[i].len,
+					stream_info->
+					plane_cfg[k][i].output_stride,
+					stream_info->
+					plane_cfg[k][i].output_scan_lines
+					);
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct msm_isp_buffer *msm_isp_get_stream_buffer(
+			struct vfe_device *vfe_dev,
+			struct msm_vfe_axi_stream *stream_info)
+{
+	int rc = 0;
+	uint32_t bufq_handle = 0;
+	struct msm_isp_buffer *buf = NULL;
+	struct msm_vfe_frame_request_queue *queue_req;
+	uint32_t buf_index = MSM_ISP_INVALID_BUF_INDEX;
+
+	if (!stream_info->controllable_output) {
+		bufq_handle = stream_info->bufq_handle
+					[VFE_BUF_QUEUE_DEFAULT];
+	} else {
+		queue_req = list_first_entry_or_null(
+			&stream_info->request_q,
+			struct msm_vfe_frame_request_queue, list);
+		if (!queue_req)
+			return buf;
+
+		bufq_handle = stream_info->
+			bufq_handle[queue_req->buff_queue_id];
+
+		if (!bufq_handle ||
+			stream_info->request_q_cnt <= 0) {
+			pr_err_ratelimited("%s: Drop request. Shared stream is stopped.\n",
+			__func__);
+			return buf;
+		}
+		buf_index = queue_req->buf_index;
+		queue_req->cmd_used = 0;
+		list_del(&queue_req->list);
+		stream_info->request_q_cnt--;
+	}
+	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
+		vfe_dev->pdev->id, bufq_handle, buf_index, &buf);
+
+	if (rc == -EFAULT) {
+		msm_isp_halt_send_error(vfe_dev,
+			ISP_EVENT_BUF_FATAL_ERROR);
+		return buf;
+	}
+	if (rc < 0)
+		return buf;
+
+	if (buf->num_planes != stream_info->num_planes) {
+		pr_err("%s: Invalid buffer\n", __func__);
+		vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+				bufq_handle, buf->buf_idx);
+		buf = NULL;
+	}
+	return buf;
+}
+
+int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+	uint32_t buf_idx)
+{
+	int i, rc = 0;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t pingpong_bit;
+	uint32_t buffer_size_byte = 0;
+	int32_t word_per_line = 0;
+	dma_addr_t paddr;
+	uint32_t bufq_handle = 0;
+	int vfe_idx;
+
+	bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT];
+
+	if (!vfe_dev->is_split) {
+		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+			vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf);
+		if (rc < 0 || !buf) {
+			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+				__func__, rc, buf);
+			return -EINVAL;
+		}
+
+		if (buf->num_planes != stream_info->num_planes) {
+			pr_err("%s: Invalid buffer\n", __func__);
+			vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+				bufq_handle, buf->buf_idx);
+			return -EINVAL;
+		}
+		vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+		pingpong_bit = ((pingpong_status >>
+			stream_info->wm[vfe_idx][0]) & 0x1);
+
+		for (i = 0; i < stream_info->num_planes; i++) {
+			word_per_line = msm_isp_cal_word_per_line(
+				stream_info->output_format,
+				stream_info->plane_cfg[vfe_idx][i].
+				output_stride);
+			if (word_per_line < 0) {
+				/* 0 means no prefetch*/
+				word_per_line = 0;
+				buffer_size_byte = 0;
+			} else {
+				buffer_size_byte = (word_per_line * 8 *
+					stream_info->plane_cfg[vfe_idx][i].
+					output_scan_lines) -
+					stream_info->
+					plane_cfg[vfe_idx][i].plane_addr_offset;
+			}
+			paddr = buf->mapped_info[i].paddr;
+
+			vfe_dev->hw_info->vfe_ops.axi_ops.
+				update_ping_pong_addr(
+				vfe_dev->vfe_base, stream_info->wm[vfe_idx][i],
+				pingpong_bit, paddr +
+				stream_info->
+				plane_cfg[vfe_idx][i].plane_addr_offset,
+				buffer_size_byte);
+				stream_info->buf[!pingpong_bit] = buf;
+				buf->pingpong_bit = !pingpong_bit;
+		}
+		buf->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
+		stream_info->buf[!pingpong_bit] = buf;
+		buf->pingpong_bit = !pingpong_bit;
+	}
+	return rc;
+
+}
+
+static int msm_isp_cfg_ping_pong_address(
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+	struct msm_isp_buffer *buf)
+{
+	int i;
+	int j;
+	uint32_t pingpong_bit;
+	struct vfe_device *vfe_dev = stream_info->vfe_dev[0];
+	uint32_t buffer_size_byte = 0;
+	int32_t word_per_line = 0;
+	dma_addr_t paddr;
+
+
+	/* Isolate pingpong_bit from pingpong_status */
+	pingpong_bit = ((pingpong_status >>
+		stream_info->wm[0][0]) & 0x1);
+
+	/* return if buffer already present */
+	if (stream_info->buf[!pingpong_bit]) {
+		pr_err("stream %x buffer already set for pingpong %d\n",
+			stream_info->stream_src, !pingpong_bit);
+		return 1;
+	}
+
+	if (buf == NULL)
+		buf = msm_isp_get_stream_buffer(vfe_dev, stream_info);
+
+	if (!buf) {
+		msm_isp_cfg_stream_scratch(stream_info, pingpong_status);
+		return 0;
+	}
+
+	for (i = 0; i < stream_info->num_planes; i++) {
+		paddr = buf->mapped_info[i].paddr;
+		ISP_DBG(
+			"%s: vfe %d config buf %d to pingpong %d stream %x\n",
+			__func__, vfe_dev->pdev->id,
+			buf->buf_idx, !pingpong_bit,
+			stream_info->stream_id);
+		for (j = 0; j < stream_info->num_isp; j++) {
+			vfe_dev = stream_info->vfe_dev[j];
+			word_per_line =
+				msm_isp_cal_word_per_line(
+				stream_info->output_format,
+				stream_info->plane_cfg[j][i].output_stride);
+			if (word_per_line < 0) {
+				/* 0 means no prefetch*/
+				word_per_line = 0;
+				buffer_size_byte = 0;
+			} else {
+				buffer_size_byte =
+					(word_per_line * 8 *
+					stream_info->plane_cfg[j][i].
+					output_scan_lines) -
+					stream_info->plane_cfg[j][i].
+					plane_addr_offset;
+			}
+			vfe_dev->hw_info->vfe_ops.axi_ops.
+					update_ping_pong_addr(
+					vfe_dev->vfe_base,
+					stream_info->wm[j][i],
+					pingpong_bit, paddr +
+					stream_info->plane_cfg[j][i].
+					plane_addr_offset,
+					buffer_size_byte);
+		}
+	}
+	stream_info->buf[!pingpong_bit] = buf;
+	buf->pingpong_bit = !pingpong_bit;
+	return 0;
+}
+
+static void msm_isp_handle_done_buf_frame_id_mismatch(
+	struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info,
+	struct msm_isp_buffer *buf, struct timeval *time_stamp,
+	uint32_t frame_id)
+{
+	struct msm_isp_event_data error_event;
+	int ret = 0;
+
+	memset(&error_event, 0, sizeof(error_event));
+	error_event.frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	error_event.u.error_info.err_type =
+		ISP_ERROR_FRAME_ID_MISMATCH;
+	if (stream_info->buf_divert)
+		vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+			buf->bufq_handle, buf->buf_idx);
+	else
+		ret = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
+			buf->bufq_handle, buf->buf_idx, time_stamp,
+			frame_id,
+			stream_info->runtime_output_format);
+	if (ret == -EFAULT) {
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
+		return;
+	}
+	msm_isp_send_event(vfe_dev, ISP_EVENT_ERROR,
+		&error_event);
+	pr_err("%s: Error! frame id mismatch!! 1st buf frame %d,curr frame %d\n",
+		__func__, buf->frame_id, frame_id);
+	vfe_dev->buf_mgr->frameId_mismatch_recovery = 1;
+}
+
+static int msm_isp_process_done_buf(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf,
+	struct timeval *time_stamp, uint32_t frame_id)
+{
+	int rc;
+	unsigned long flags;
+	struct msm_isp_event_data buf_event;
+	uint32_t stream_idx = stream_info->stream_src;
+	uint32_t buf_src;
+	uint8_t drop_frame = 0;
+	struct msm_isp_bufq *bufq = NULL;
+
+	memset(&buf_event, 0, sizeof(buf_event));
+
+	if (stream_idx >= VFE_AXI_SRC_MAX) {
+		pr_err_ratelimited("%s: Invalid stream_idx", __func__);
+		return -EINVAL;
+	}
+
+	if (SRC_TO_INTF(stream_info->stream_src) >= VFE_SRC_MAX) {
+		pr_err_ratelimited("%s: Invalid stream index, put buf back to vb2 queue\n",
+			__func__);
+		rc = vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+			buf->bufq_handle, buf->buf_idx);
+		return -EINVAL;
+	}
+
+	if (stream_info->stream_type != BURST_STREAM &&
+		(stream_info->sw_skip.stream_src_mask &
+		(1 << stream_info->stream_src))) {
+		/* Hw stream output of this src is requested for drop */
+		if (stream_info->sw_skip.skip_mode == SKIP_ALL) {
+			/* drop all buffers */
+			drop_frame = 1;
+		} else if (stream_info->sw_skip.skip_mode == SKIP_RANGE &&
+			(stream_info->sw_skip.min_frame_id <= frame_id &&
+			stream_info->sw_skip.max_frame_id >= frame_id)) {
+			drop_frame = 1;
+		} else if (frame_id > stream_info->sw_skip.max_frame_id) {
+			spin_lock_irqsave(&stream_info->lock, flags);
+			memset(&stream_info->sw_skip, 0,
+					sizeof(struct msm_isp_sw_framskip));
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+		}
+	}
+
+	rc = vfe_dev->buf_mgr->ops->get_buf_src(vfe_dev->buf_mgr,
+					buf->bufq_handle, &buf_src);
+	if (rc != 0) {
+		pr_err_ratelimited("%s: Error getting buf_src\n", __func__);
+		return -EINVAL;
+	}
+
+	if (drop_frame) {
+		buf->buf_debug.put_state[
+			buf->buf_debug.put_state_last] =
+			MSM_ISP_BUFFER_STATE_DROP_SKIP;
+		buf->buf_debug.put_state_last ^= 1;
+		if (stream_info->buf_divert)
+			vfe_dev->buf_mgr->ops->put_buf(
+				vfe_dev->buf_mgr,
+				buf->bufq_handle, buf->buf_idx);
+		else
+			rc = vfe_dev->buf_mgr->ops->buf_done(
+				vfe_dev->buf_mgr,
+				buf->bufq_handle, buf->buf_idx,
+				time_stamp, frame_id,
+				stream_info->runtime_output_format);
+
+		if (rc == -EFAULT) {
+			msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_BUF_FATAL_ERROR);
+			return rc;
+		}
+		if (!rc) {
+			ISP_DBG("%s:%d vfe_id %d Buffer dropped %d\n",
+				__func__, __LINE__, vfe_dev->pdev->id,
+				frame_id);
+			/*
+			 * Return rc which is 0 at this point so that
+			 * we can cfg ping pong and we can continue
+			 * streaming
+			 */
+			return rc;
+		}
+	}
+
+	buf_event.frame_id = frame_id;
+	buf_event.timestamp = *time_stamp;
+	buf_event.u.buf_done.session_id = stream_info->session_id;
+	buf_event.u.buf_done.stream_id = stream_info->stream_id;
+	buf_event.u.buf_done.handle = buf->bufq_handle;
+	buf_event.u.buf_done.buf_idx = buf->buf_idx;
+	buf_event.u.buf_done.output_format =
+		stream_info->runtime_output_format;
+	if (vfe_dev->fetch_engine_info.is_busy &&
+		SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) {
+		vfe_dev->fetch_engine_info.is_busy = 0;
+	}
+
+	if (stream_info->buf_divert &&
+		buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) {
+
+		bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr,
+			buf->bufq_handle);
+		if (!bufq) {
+			pr_err("%s: Invalid bufq buf_handle %x\n",
+				__func__, buf->bufq_handle);
+			return -EINVAL;
+		}
+
+		/* divert native buffers */
+		vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
+			buf->bufq_handle, buf->buf_idx, time_stamp,
+			frame_id);
+
+		if ((bufq != NULL) && bufq->buf_type == ISP_SHARE_BUF)
+			msm_isp_send_event(vfe_dev->common_data->
+				dual_vfe_res->vfe_dev[ISP_VFE1],
+				ISP_EVENT_BUF_DIVERT, &buf_event);
+		else
+			msm_isp_send_event(vfe_dev,
+			ISP_EVENT_BUF_DIVERT, &buf_event);
+	} else {
+		ISP_DBG("%s: vfe_id %d send buf done buf-id %d bufq %x\n",
+			__func__, vfe_dev->pdev->id, buf->buf_idx,
+			buf->bufq_handle);
+		msm_isp_send_event(vfe_dev, ISP_EVENT_BUF_DONE,
+			&buf_event);
+		buf->buf_debug.put_state[
+			buf->buf_debug.put_state_last] =
+			MSM_ISP_BUFFER_STATE_PUT_BUF;
+		buf->buf_debug.put_state_last ^= 1;
+		rc = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
+			buf->bufq_handle, buf->buf_idx, time_stamp,
+			frame_id, stream_info->runtime_output_format);
+		if (rc == -EFAULT) {
+			msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_BUF_FATAL_ERROR);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int msm_isp_drop_frame(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts,
+	struct msm_isp_sof_info *sof_info)
+{
+	struct msm_isp_buffer *done_buf = NULL;
+	uint32_t pingpong_status;
+	unsigned long flags;
+	struct msm_isp_bufq *bufq = NULL;
+	uint32_t pingpong_bit;
+	int vfe_idx;
+	int rc = -1;
+
+	if (!vfe_dev || !stream_info || !ts || !sof_info) {
+		pr_err("%s %d vfe_dev %pK stream_info %pK ts %pK op_info %pK\n",
+			 __func__, __LINE__, vfe_dev, stream_info, ts,
+			sof_info);
+		return -EINVAL;
+	}
+	vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	pingpong_status =
+		~vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+	pingpong_bit =
+		(~(pingpong_status >> stream_info->wm[vfe_idx][0]) & 0x1);
+	done_buf = stream_info->buf[pingpong_bit];
+	if (done_buf &&
+		(stream_info->composite_irq[MSM_ISP_COMP_IRQ_EPOCH] == 0)) {
+		if ((stream_info->sw_ping_pong_bit != -1) &&
+			!vfe_dev->reg_updated) {
+			rc = msm_isp_cfg_ping_pong_address(
+				stream_info, ~pingpong_status, done_buf);
+			if (rc < 0) {
+				ISP_DBG("%s: Error configuring ping_pong\n",
+					__func__);
+				bufq = vfe_dev->buf_mgr->ops->get_bufq(
+					vfe_dev->buf_mgr,
+					done_buf->bufq_handle);
+				if (!bufq) {
+					spin_unlock_irqrestore(
+						&stream_info->lock,
+						flags);
+					pr_err("%s: Invalid bufq buf_handle %x\n",
+						__func__,
+						done_buf->bufq_handle);
+					return -EINVAL;
+				}
+				sof_info->reg_update_fail_mask_ext |=
+					(bufq->bufq_handle & 0xFF);
+			}
+		}
+		/*Avoid Drop Frame and re-issue pingpong cfg*/
+		/*this notify is per ping and pong buffer*/
+		done_buf->is_drop_reconfig = 1;
+		stream_info->current_framedrop_period = 1;
+		/*Avoid Multiple request frames for single SOF*/
+		vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false;
+
+		if (stream_info->current_framedrop_period !=
+			stream_info->requested_framedrop_period) {
+			msm_isp_cfg_framedrop_reg(stream_info);
+		}
+	}
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+
+	/* if buf done will not come, we need to process it ourself */
+	if (stream_info->activated_framedrop_period ==
+		MSM_VFE_STREAM_STOP_PERIOD) {
+		/* no buf done come */
+		msm_isp_process_axi_irq_stream(vfe_dev, stream_info,
+			pingpong_status, ts);
+		if (done_buf)
+			done_buf->is_drop_reconfig = 0;
+	}
+	return 0;
+}
+
+/**
+ * msm_isp_input_disable() - Disable the input for given vfe
+ * @vfe_dev: The vfe device whose input is to be disabled
+ *
+ * Returns - void
+ *
+ * If stream count on an input line is 0 then disable the input
+ */
+static void msm_isp_input_disable(struct vfe_device *vfe_dev, int cmd_type)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int stream_count;
+	int total_stream_count = 0;
+	int i;
+	struct msm_vfe_src_info *src_info;
+	int ext_read =
+		(axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ);
+
+	for (i = 0; i < VFE_SRC_MAX; i++)
+		total_stream_count += axi_data->src_info[i].stream_count +
+				axi_data->src_info[i].raw_stream_count;
+
+	for (i = 0; i < VFE_SRC_MAX; i++) {
+		stream_count = axi_data->src_info[i].stream_count +
+				axi_data->src_info[i].raw_stream_count;
+		if (stream_count)
+			continue;
+		if (axi_data->src_info[i].active == 0)
+			continue;
+		/* deactivate the input line */
+		axi_data->src_info[i].active = 0;
+		src_info = &axi_data->src_info[i];
+
+		if (src_info->dual_hw_type == DUAL_HW_MASTER_SLAVE) {
+			struct master_slave_resource_info *ms_res =
+				&vfe_dev->common_data->ms_resource;
+			unsigned long flags;
+
+			spin_lock_irqsave(
+				&vfe_dev->common_data->common_dev_data_lock,
+				flags);
+			if (src_info->dual_hw_ms_info.index ==
+				ms_res->master_index)
+				ms_res->master_index = -1;
+			if (src_info->dual_hw_ms_info.index ==
+				ms_res->primary_slv_idx)
+				ms_res->primary_slv_idx = -1;
+			ms_res->active_src_mask &= ~(1 <<
+				src_info->dual_hw_ms_info.index);
+			ms_res->src_sof_mask &= ~(1 <<
+				src_info->dual_hw_ms_info.index);
+			ms_res->src_info[src_info->dual_hw_ms_info.index] =
+				NULL;
+			ms_res->num_src--;
+			if (ms_res->num_src == 0)
+				ms_res->dual_sync_mode = MSM_ISP_DUAL_CAM_ASYNC;
+			src_info->dual_hw_ms_info.sync_state =
+						MSM_ISP_DUAL_CAM_ASYNC;
+			src_info->dual_hw_type = DUAL_NONE;
+			src_info->dual_hw_ms_info.index = -1;
+			spin_unlock_irqrestore(
+				&vfe_dev->common_data->common_dev_data_lock,
+				flags);
+		}
+		if (i != VFE_PIX_0 || ext_read)
+			continue;
+		if (total_stream_count == 0 || cmd_type == STOP_IMMEDIATELY)
+			vfe_dev->hw_info->vfe_ops.core_ops.
+				update_camif_state(vfe_dev,
+				DISABLE_CAMIF_IMMEDIATELY);
+		else
+			vfe_dev->hw_info->vfe_ops.core_ops.
+				update_camif_state(vfe_dev,
+				DISABLE_CAMIF);
+	}
+	/*
+	 * halt and reset hardware if all streams are disabled, in this case
+	 * ispif is halted immediately as well
+	 */
+	if (total_stream_count == 0) {
+		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
+		msm_isp_flush_tasklet(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1);
+		if (msm_vfe_is_vfe48(vfe_dev))
+			vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev,
+								0, 1);
+		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
+	}
+
+}
+
+/**
+ * msm_isp_input_enable() - Enable the input for given vfe
+ * @vfe_dev: The vfe device whose input is to be enabled
+ *
+ * Returns - void
+ *
+ * Enable inout line if it is not enabled
+ */
+static void msm_isp_input_enable(struct vfe_device *vfe_dev,
+				int sync_frame_id_src)
+{
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int ext_read =
+		(axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ);
+	int stream_count;
+	int i;
+
+	for (i = 0; i < VFE_SRC_MAX; i++) {
+		stream_count = axi_data->src_info[i].stream_count +
+				axi_data->src_info[i].raw_stream_count;
+		if (stream_count == 0)
+			continue;
+		if (axi_data->src_info[i].active)
+			continue;
+		/* activate the input since it is deactivated */
+		axi_data->src_info[i].frame_id = 0;
+		if (axi_data->src_info[i].input_mux != EXTERNAL_READ)
+			axi_data->src_info[i].active = 1;
+		if (i >= VFE_RAW_0 && sync_frame_id_src) {
+			/*
+			 * Incase PIX and RDI streams are part
+			 * of same session, this will ensure
+			 * RDI stream will have same frame id
+			 * as of PIX stream
+			 */
+			axi_data->src_info[i].frame_id =
+				axi_data->src_info[VFE_PIX_0].frame_id;
+		}
+		/* when start reset overflow state and cfg ub for this intf */
+		vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev, i);
+		atomic_set(&vfe_dev->error_info.overflow_state,
+			NO_OVERFLOW);
+		if (i != VFE_PIX_0 || ext_read)
+			continue;
+		/* for camif input the camif needs enabling */
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, ENABLE_CAMIF);
+	}
+}
+
+/**
+ * msm_isp_update_intf_stream_cnt() - Update the stream count in axi interface
+ * @stream_info: The stream that is either being enabled/disabled
+ * @enable: 0 means stream is being disabled, else enabled
+ *
+ * Returns - void
+ */
+static void msm_isp_update_intf_stream_cnt(
+	struct msm_vfe_axi_stream *stream_info,
+	int enable)
+{
+	int i;
+
+	switch (stream_info->stream_src) {
+	case PIX_ENCODER:
+	case PIX_VIEWFINDER:
+	case PIX_VIDEO:
+	case IDEAL_RAW:
+	case RDI_INTF_0:
+	case RDI_INTF_1:
+	case RDI_INTF_2:
+		for (i = 0; i < stream_info->num_isp; i++) {
+			if (enable)
+				stream_info->vfe_dev[i]->axi_data.src_info[
+					SRC_TO_INTF(stream_info->stream_src)].
+					stream_count++;
+			else
+				stream_info->vfe_dev[i]->axi_data.src_info[
+					SRC_TO_INTF(stream_info->stream_src)].
+					stream_count--;
+		}
+		break;
+	case CAMIF_RAW:
+		for (i = 0; i < stream_info->num_isp; i++) {
+			if (enable)
+				stream_info->vfe_dev[i]->axi_data.src_info[
+					SRC_TO_INTF(stream_info->stream_src)].
+					raw_stream_count++;
+			else
+				stream_info->vfe_dev[i]->axi_data.src_info[
+					SRC_TO_INTF(stream_info->stream_src)].
+					raw_stream_count--;
+		}
+		break;
+	default:
+		WARN(1, "Invalid steam src %d\n", stream_info->stream_src);
+	}
+}
+
+/*Factor in Q2 format*/
+#define ISP_DEFAULT_FORMAT_FACTOR 6
+#define ISP_BUS_UTILIZATION_FACTOR 6
+static int msm_isp_update_stream_bandwidth(
+	struct msm_vfe_axi_stream *stream_info, int enable)
+{
+	int i, rc = 0;
+	uint64_t total_bandwidth = 0;
+	int vfe_idx;
+	struct vfe_device *vfe_dev;
+
+	for (i = 0; i < stream_info->num_isp; i++) {
+		vfe_dev = stream_info->vfe_dev[i];
+		vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev,
+					stream_info);
+		if (enable) {
+			total_bandwidth =
+				vfe_dev->total_bandwidth +
+				stream_info->bandwidth[vfe_idx];
+		} else {
+			total_bandwidth = vfe_dev->total_bandwidth -
+				stream_info->bandwidth[vfe_idx];
+		}
+		vfe_dev->total_bandwidth = total_bandwidth;
+		rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id,
+			(total_bandwidth + vfe_dev->hw_info->min_ab),
+			(total_bandwidth + vfe_dev->hw_info->min_ib));
+
+		if (rc < 0)
+			pr_err("%s: update failed rc %d stream src %d vfe dev %d\n",
+				__func__, rc, stream_info->stream_src,
+				vfe_dev->pdev->id);
+	}
+	return rc;
+}
+
+int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
+{
+	int i, rc = 0;
+	uint32_t intf;
+	unsigned long flags;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_dual_lpm_mode *ab_ib_vote = NULL;
+
+	ab_ib_vote = (struct msm_vfe_dual_lpm_mode *)arg;
+	if (!ab_ib_vote) {
+		pr_err("%s: ab_ib_vote is NULL !!!\n", __func__);
+		rc = -1;
+		return rc;
+	}
+	if (ab_ib_vote->num_src >= VFE_AXI_SRC_MAX) {
+		pr_err("%s: ab_ib_vote num_src is exceeding limit\n",
+			__func__);
+		rc = -1;
+		return rc;
+	}
+	if (ab_ib_vote->num_src >= VFE_AXI_SRC_MAX) {
+		pr_err("%s: ab_ib_vote num_src is exceeding limit\n",
+			__func__);
+		rc = -1;
+		return rc;
+	}
+	if (ab_ib_vote->lpm_mode) {
+		for (i = 0; i < ab_ib_vote->num_src; i++) {
+			stream_info =
+				msm_isp_get_stream_common_data(vfe_dev,
+					ab_ib_vote->stream_src[i]);
+			if (stream_info == NULL)
+				continue;
+			/* loop all stream on current session */
+			spin_lock_irqsave(&stream_info->lock, flags);
+			intf = SRC_TO_INTF(stream_info->stream_src);
+			vfe_dev->axi_data.src_info[intf].lpm =
+				ab_ib_vote->lpm_mode;
+			if (stream_info->lpm_mode ||
+				stream_info->state == INACTIVE) {
+				spin_unlock_irqrestore(&stream_info->lock,
+							flags);
+				continue;
+			}
+			stream_info->lpm_mode = ab_ib_vote->lpm_mode;
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			msm_isp_update_stream_bandwidth(stream_info, 0);
+		}
+	} else {
+		for (i = 0; i < ab_ib_vote->num_src; i++) {
+			stream_info =
+				msm_isp_get_stream_common_data(vfe_dev,
+					ab_ib_vote->stream_src[i]);
+			if (stream_info == NULL)
+				continue;
+			spin_lock_irqsave(&stream_info->lock, flags);
+			intf = SRC_TO_INTF(stream_info->stream_src);
+			vfe_dev->axi_data.src_info[intf].lpm =
+				ab_ib_vote->lpm_mode;
+			if (stream_info->lpm_mode == 0 ||
+				stream_info->state == INACTIVE) {
+				spin_unlock_irqrestore(&stream_info->lock,
+							flags);
+				continue;
+			}
+			stream_info->lpm_mode = 0;
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			msm_isp_update_stream_bandwidth(stream_info, 1);
+		}
+	}
+	return rc;
+}
+
+static int msm_isp_init_stream_ping_pong_reg(
+	struct msm_vfe_axi_stream *stream_info)
+{
+	int rc = 0;
+
+	/* Set address for both PING & PO NG register */
+	rc = msm_isp_cfg_ping_pong_address(
+		stream_info, VFE_PING_FLAG, NULL);
+	/* No buffer available on start is not error */
+	if (rc == -ENOMEM && stream_info->stream_type != BURST_STREAM)
+		return 0;
+	if (rc < 0) {
+		pr_err("%s: No free buffer for ping\n",
+			   __func__);
+		return rc;
+	}
+	if (stream_info->stream_type != BURST_STREAM ||
+		stream_info->runtime_num_burst_capture > 1) {
+		rc = msm_isp_cfg_ping_pong_address(
+			stream_info, VFE_PONG_FLAG, NULL);
+		/* No buffer available on start is not error */
+		if (rc == -ENOMEM)
+			return 0;
+	}
+
+	if (rc < 0) {
+		pr_err("%s: No free buffer for pong\n",
+			__func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void msm_isp_get_stream_wm_mask(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint32_t *wm_reload_mask)
+{
+	int i;
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (i = 0; i < stream_info->num_planes; i++)
+		*wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]);
+}
+
+int msm_isp_axi_halt(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_halt_cmd *halt_cmd)
+{
+	int rc = 0;
+
+	if (atomic_read(&vfe_dev->error_info.overflow_state) ==
+		OVERFLOW_DETECTED)
+		pr_err("%s: VFE%d Bus overflow detected: start recovery!\n",
+			__func__, vfe_dev->pdev->id);
+
+	/* take care of pending items in tasklet before halt */
+	msm_isp_flush_tasklet(vfe_dev);
+
+	if (halt_cmd->stop_camif) {
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev,
+				DISABLE_CAMIF_IMMEDIATELY);
+	}
+	rc |= vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev,
+		halt_cmd->blocking_halt);
+
+	return rc;
+}
+
+int msm_isp_axi_reset(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_reset_cmd *reset_cmd)
+{
+	int rc = 0, i, k;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	uint32_t bufq_handle = 0, bufq_id = 0;
+	struct msm_isp_timestamp timestamp;
+	struct msm_vfe_frame_request_queue *queue_req;
+	unsigned long flags;
+	int vfe_idx;
+
+	if (!reset_cmd) {
+		pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd);
+		rc = -1;
+		return rc;
+	}
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev);
+
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(
+						vfe_dev, i);
+		if (stream_info->stream_src >= VFE_AXI_SRC_MAX) {
+			rc = -1;
+			pr_err("%s invalid  stream src = %d\n",
+				__func__,
+				stream_info->stream_src);
+			break;
+		}
+		if (stream_info->state == AVAILABLE ||
+			stream_info->state == INACTIVE)
+			continue;
+
+		/* handle dual stream on ISP_VFE1 turn */
+		if (stream_info->num_isp > 1 &&
+			vfe_dev->pdev->id == ISP_VFE0)
+			continue;
+
+		/* set ping pong to scratch before flush */
+		spin_lock_irqsave(&stream_info->lock, flags);
+		msm_isp_cfg_stream_scratch(stream_info,
+					VFE_PING_FLAG);
+		msm_isp_cfg_stream_scratch(stream_info,
+					VFE_PONG_FLAG);
+		stream_info->undelivered_request_cnt = 0;
+		spin_unlock_irqrestore(&stream_info->lock,
+					flags);
+		while (!list_empty(&stream_info->request_q)) {
+			queue_req = list_first_entry_or_null(
+				&stream_info->request_q,
+				struct msm_vfe_frame_request_queue, list);
+			if (queue_req) {
+				queue_req->cmd_used = 0;
+				list_del(&queue_req->list);
+			}
+		}
+		for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX;
+			bufq_id++) {
+			bufq_handle = stream_info->bufq_handle[bufq_id];
+			if (!bufq_handle)
+				continue;
+			rc = vfe_dev->buf_mgr->ops->flush_buf(
+				vfe_dev->buf_mgr,
+				bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL,
+				&timestamp.buf_time,
+				reset_cmd->frame_id);
+			if (rc == -EFAULT) {
+				msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_BUF_FATAL_ERROR);
+				return rc;
+			}
+		}
+
+		for (k = 0; k < stream_info->num_isp; k++) {
+			struct vfe_device *temp_vfe_dev =
+					stream_info->vfe_dev[k];
+			vfe_idx = msm_isp_get_vfe_idx_for_stream(
+					temp_vfe_dev, stream_info);
+			if (stream_info->num_planes > 1) {
+				temp_vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_comp_mask(temp_vfe_dev,
+							stream_info);
+			} else {
+				temp_vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_wm_irq_mask(temp_vfe_dev,
+							stream_info);
+			}
+			axi_data = &temp_vfe_dev->axi_data;
+			axi_data->src_info[SRC_TO_INTF(stream_info->
+				stream_src)].frame_id =
+				reset_cmd->frame_id;
+		}
+		msm_isp_reset_burst_count_and_frame_drop(
+			vfe_dev, stream_info);
+	}
+
+	vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev,
+		0, reset_cmd->blocking);
+	/*
+	 * call reset a second time for vfe48, calling
+	 * only once causes bus error on camif enable
+	 */
+	if (msm_vfe_is_vfe48(vfe_dev))
+		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev,
+			0, reset_cmd->blocking);
+
+	if (rc < 0)
+		pr_err("%s Error! reset hw Timed out\n", __func__);
+
+	return 0;
+}
+
+int msm_isp_axi_restart(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_restart_cmd *restart_cmd)
+{
+	int rc = 0, i, k, j;
+	struct msm_vfe_axi_stream *stream_info;
+	uint32_t wm_reload_mask[MAX_VFE] = {0, 0};
+	unsigned long flags;
+	int vfe_idx;
+
+	vfe_dev->buf_mgr->frameId_mismatch_recovery = 0;
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(
+					vfe_dev, i);
+		if (stream_info->state == AVAILABLE ||
+			stream_info->state == INACTIVE)
+			continue;
+		/* handle dual stream on ISP_VFE1 turn */
+		if (stream_info->num_isp > 1 &&
+			vfe_dev->pdev->id == ISP_VFE0)
+			continue;
+		spin_lock_irqsave(&stream_info->lock, flags);
+		for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++)
+			stream_info->composite_irq[j] = 0;
+		for (k = 0; k < stream_info->num_isp; k++) {
+			struct vfe_device *temp_vfe_dev =
+				stream_info->vfe_dev[k];
+			vfe_idx = msm_isp_get_vfe_idx_for_stream(
+					temp_vfe_dev, stream_info);
+			for (j = 0; j < stream_info->num_planes; j++)
+				temp_vfe_dev->hw_info->vfe_ops.axi_ops.
+					enable_wm(
+					temp_vfe_dev->vfe_base,
+					stream_info->wm[vfe_idx][j], 1);
+			msm_isp_get_stream_wm_mask(temp_vfe_dev, stream_info,
+				&wm_reload_mask[temp_vfe_dev->pdev->id]);
+		}
+		msm_isp_init_stream_ping_pong_reg(stream_info);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	for (k = 0; k < MAX_VFE; k++) {
+		struct vfe_device *temp_vfe_dev =
+			vfe_dev->common_data->dual_vfe_res->vfe_dev[k];
+		if (wm_reload_mask[k])
+			temp_vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(
+				temp_vfe_dev,
+				temp_vfe_dev->vfe_base, wm_reload_mask[k]);
+	}
+
+	vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0,
+		restart_cmd->enable_camif);
+
+	return rc;
+}
+
+static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev_ioctl,
+	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd,
+	uint8_t cgc_override)
+{
+	int i = 0, j = 0;
+	struct msm_vfe_axi_stream *stream_info;
+	int k;
+	struct vfe_device *vfe_dev;
+	int vfe_idx;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM)
+		return -EINVAL;
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >=
+				VFE_AXI_SRC_MAX) {
+			return -EINVAL;
+		}
+		stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl,
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]));
+		if (!stream_info) {
+			pr_err("%s: stream_info is NULL", __func__);
+			return -EINVAL;
+		}
+		for (j = 0; j < stream_info->num_planes; j++) {
+			for (k = 0; k < stream_info->num_isp; k++) {
+				vfe_dev = stream_info->vfe_dev[k];
+				if (!vfe_dev->hw_info->vfe_ops.axi_ops.
+					update_cgc_override)
+					continue;
+				vfe_idx = msm_isp_get_vfe_idx_for_stream(
+						vfe_dev, stream_info);
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					update_cgc_override(vfe_dev,
+					stream_info->wm[vfe_idx][j],
+					cgc_override);
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * msm_isp_axi_wait_for_stream_cfg_done() - Wait for a stream completion
+ * @stream_info: The stream to wait on
+ * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE
+ *
+ * Returns - 0 on success else error code
+ */
+static int msm_isp_axi_wait_for_stream_cfg_done(
+			struct msm_vfe_axi_stream *stream_info, int active)
+{
+	int rc = -1;
+	unsigned long flags;
+
+	/* No need to wait if stream is already in required state */
+	spin_lock_irqsave(&stream_info->lock, flags);
+	if (active && ACTIVE == stream_info->state)
+		rc = 0;
+	if (!active && INACTIVE == stream_info->state)
+		rc = 0;
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+	if (rc == 0)
+		return rc;
+
+	rc = wait_for_completion_timeout(
+			active ? &stream_info->active_comp :
+			&stream_info->inactive_comp,
+			msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
+
+	if (rc <= 0) {
+		rc = rc ? rc : -ETIMEDOUT;
+		pr_err("%s: wait for stream %x/%x state %d config failed %d\n",
+			__func__,
+			stream_info->stream_id,
+			stream_info->stream_src,
+			stream_info->state,
+			rc);
+		rc = -EINVAL;
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+/**
+ * msm_isp_axi_wait_for_streams() - Wait for completion of a number of streams
+ * @streams: The streams to wait on
+ * @num_stream: Number of streams to wait on
+ * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE
+ *
+ * Returns - 0 on success else error code
+ */
+static int msm_isp_axi_wait_for_streams(struct msm_vfe_axi_stream **streams,
+		int num_stream, int active)
+{
+	int i;
+	int rc = 0;
+	struct msm_vfe_axi_stream *stream_info;
+
+	for (i = 0; i < num_stream; i++) {
+		stream_info = streams[i];
+		rc |= msm_isp_axi_wait_for_stream_cfg_done(stream_info, active);
+	}
+	return rc;
+}
+
+static int __msm_isp_check_stream_state(struct msm_vfe_axi_stream *stream_info,
+					int cmd)
+{
+	switch (stream_info->state) {
+	case AVAILABLE:
+		return -EINVAL;
+	case PAUSING:
+	case RESUMING:
+	case RESUME_PENDING:
+	case ACTIVE:
+	case PAUSED:
+		if (cmd != 0)
+			return -EALREADY;
+		break;
+	case INACTIVE:
+		if (cmd == 0)
+			return -EALREADY;
+		break;
+	/*
+	 * stream cannot be in following states since we always
+	 * wait in ioctl for stream to be active or inactive
+	 */
+	case UPDATING:
+	case START_PENDING:
+	case STARTING:
+	case STOPPING:
+	case STOP_PENDING:
+	case PAUSE_PENDING:
+	default:
+		WARN(1, "Invalid state %d\n", stream_info->state);
+	}
+	return 0;
+}
+
+
+static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream **streams, int num_streams, int cmd_type)
+{
+	int i;
+	struct msm_vfe_axi_shared_data *axi_data;
+	struct msm_isp_timestamp timestamp;
+	uint32_t bufq_id = 0, bufq_handle = 0;
+	struct msm_vfe_axi_stream *stream_info;
+	unsigned long flags;
+	uint32_t intf;
+	int rc;
+	struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL};
+	int k;
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev);
+
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		msm_isp_update_intf_stream_cnt(stream_info, 0);
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			update_vfes[vfe_dev->pdev->id] = vfe_dev;
+		}
+	}
+	for (k = 0; k < MAX_VFE; k++) {
+		if (!update_vfes[k])
+			continue;
+		msm_isp_input_disable(update_vfes[k], cmd_type);
+	}
+
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		spin_lock_irqsave(&stream_info->lock, flags);
+		/*
+		 * since we can get here from start axi stream error path due
+		 * to which the stream may be intermittent state like
+		 * STARTING/START_PENDING, force the stream to move out of
+		 * intermittent state so it can be made INACTIVE. The
+		 * intermittent states update variables so better to go through
+		 * those state transitions instead of directly forcing stream to
+		 * be INACTIVE
+		 */
+		memset(&stream_info->sw_skip, 0,
+			sizeof(struct msm_isp_sw_framskip));
+		intf = SRC_TO_INTF(stream_info->stream_src);
+		if (stream_info->lpm_mode == 0 &&
+			stream_info->state != PAUSED) {
+			while (stream_info->state != ACTIVE)
+				__msm_isp_axi_stream_update(stream_info,
+						&timestamp);
+		}
+		msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG);
+		msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG);
+		stream_info->undelivered_request_cnt = 0;
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			if (stream_info->num_planes > 1)
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+				clear_comp_mask(vfe_dev, stream_info);
+			else
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+				clear_wm_irq_mask(vfe_dev, stream_info);
+		}
+		init_completion(&stream_info->inactive_comp);
+		stream_info->state = STOP_PENDING;
+		if (stream_info->lpm_mode ||
+			stream_info->state == PAUSED) {
+			/* don't wait for reg update */
+			while (stream_info->state != INACTIVE)
+				__msm_isp_axi_stream_update(stream_info,
+							&timestamp);
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	for (k = 0; k < MAX_VFE; k++) {
+		if (!update_vfes[k])
+			continue;
+		vfe_dev = update_vfes[k];
+		/* make sure all stats are stopped if camif is stopped */
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].active == 0)
+			msm_isp_stop_all_stats_stream(vfe_dev);
+	}
+
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		spin_lock_irqsave(&stream_info->lock, flags);
+		intf = SRC_TO_INTF(stream_info->stream_src);
+		if (((stream_info->stream_type == BURST_STREAM) &&
+			stream_info->runtime_num_burst_capture == 0) ||
+			(stream_info->vfe_dev[0]->axi_data.src_info[intf].
+							active == 0)) {
+			while (stream_info->state != INACTIVE)
+				__msm_isp_axi_stream_update(
+					stream_info, &timestamp);
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0);
+	if (rc) {
+		pr_err("%s: wait for stream comp failed, retry...\n", __func__);
+		for (i = 0; i < num_streams; i++) {
+			stream_info = streams[i];
+			if (stream_info->state == INACTIVE)
+				continue;
+			spin_lock_irqsave(&stream_info->lock, flags);
+			__msm_isp_axi_stream_update(stream_info,
+						&timestamp);
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+		}
+		rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0);
+		if (rc) {
+			pr_err("%s: wait for stream comp failed, force streams to inactive\n",
+				__func__);
+			for (i = 0; i < num_streams; i++) {
+				stream_info = streams[i];
+				if (stream_info->state == INACTIVE)
+					continue;
+				spin_lock_irqsave(&stream_info->lock, flags);
+				while (stream_info->state != INACTIVE)
+					__msm_isp_axi_stream_update(
+						stream_info, &timestamp);
+				spin_unlock_irqrestore(&stream_info->lock,
+						flags);
+			}
+		}
+	}
+	/* clear buffers that are dequeued */
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		if (stream_info->lpm_mode == 0)
+			msm_isp_update_stream_bandwidth(stream_info, 0);
+		for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) {
+			bufq_handle = stream_info->bufq_handle[bufq_id];
+			if (!bufq_handle)
+				continue;
+			vfe_dev = stream_info->vfe_dev[0];
+			rc = vfe_dev->buf_mgr->ops->flush_buf(
+				vfe_dev->buf_mgr,
+				bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL,
+				&timestamp.buf_time, 0);
+			if (rc == -EFAULT)
+				msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_BUF_FATAL_ERROR);
+		}
+	}
+
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		intf = SRC_TO_INTF(stream_info->stream_src);
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			axi_data = &vfe_dev->axi_data;
+			if (axi_data->src_info[intf].stream_count == 0)
+				vfe_dev->reg_update_requested &=
+				~(BIT(intf));
+		}
+	}
+}
+
+static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl,
+			struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i, rc = 0;
+	uint8_t src_state;
+	uint32_t wm_reload_mask[MAX_VFE] = {0, 0};
+	struct msm_vfe_axi_stream *stream_info;
+	uint32_t src_mask = 0;
+	unsigned long flags;
+	struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM];
+	int num_streams = 0;
+	struct msm_isp_timestamp timestamp;
+	struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL};
+	int k;
+	struct vfe_device *vfe_dev;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev_ioctl->axi_data;
+	uint32_t intf;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM)
+		return -EINVAL;
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev_ioctl);
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (stream_cfg_cmd->stream_handle[i] == 0)
+			continue;
+		stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl,
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]));
+		if (!stream_info) {
+			pr_err("%s: stream_info is NULL", __func__);
+			return -EINVAL;
+		}
+		if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX)
+			src_state = axi_data->src_info[
+				SRC_TO_INTF(stream_info->stream_src)].active;
+
+		else {
+			ISP_DBG("%s: invalid src info index\n", __func__);
+			rc = -EINVAL;
+			goto error;
+		}
+		spin_lock_irqsave(&stream_info->lock, flags);
+		rc = __msm_isp_check_stream_state(stream_info, 1);
+		if (-EALREADY == rc) {
+			rc = 0;
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		if (rc) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			goto error;
+		}
+
+		msm_isp_calculate_bandwidth(stream_info);
+		for (k = 0; k < stream_info->num_isp; k++) {
+			msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k],
+				stream_info, &wm_reload_mask[
+					stream_info->vfe_dev[k]->pdev->id]);
+			src_state = stream_info->vfe_dev[k]->axi_data.src_info[
+				SRC_TO_INTF(stream_info->stream_src)].active;
+			if (update_vfes[stream_info->vfe_dev[k]->pdev->id])
+				continue;
+			update_vfes[stream_info->vfe_dev[k]->pdev->id] =
+							stream_info->vfe_dev[k];
+		}
+		msm_isp_reset_framedrop(vfe_dev_ioctl, stream_info);
+		rc = msm_isp_init_stream_ping_pong_reg(stream_info);
+		if (rc < 0) {
+			pr_err("%s: No buffer for stream%d\n", __func__,
+				HANDLE_TO_IDX(
+				stream_cfg_cmd->stream_handle[i]));
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			goto error;
+		}
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			if (stream_info->num_planes > 1) {
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_comp_mask(vfe_dev, stream_info);
+			} else {
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_wm_irq_mask(vfe_dev, stream_info);
+			}
+		}
+		intf = SRC_TO_INTF(stream_info->stream_src);
+		stream_info->lpm_mode = vfe_dev_ioctl->
+					axi_data.src_info[intf].lpm;
+		if (stream_info->lpm_mode == 0) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			msm_isp_update_stream_bandwidth(stream_info, 1);
+			spin_lock_irqsave(&stream_info->lock, flags);
+		}
+		init_completion(&stream_info->active_comp);
+		stream_info->state = START_PENDING;
+		msm_isp_update_intf_stream_cnt(stream_info, 1);
+
+		ISP_DBG("%s, Stream 0x%x src_state %d on vfe %d\n", __func__,
+			stream_info->stream_src, src_state,
+			vfe_dev_ioctl->pdev->id);
+		if (src_state) {
+			src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src));
+			if (stream_info->lpm_mode) {
+				while (stream_info->state != ACTIVE)
+					__msm_isp_axi_stream_update(
+						stream_info, &timestamp);
+			}
+		} else {
+			for (k = 0; k < stream_info->num_isp; k++) {
+				vfe_dev = stream_info->vfe_dev[k];
+
+				if (vfe_dev->dump_reg)
+					msm_camera_io_dump(vfe_dev->vfe_base,
+						0x1000, 1);
+			}
+
+			/* Configure AXI start bits to start immediately */
+			while (stream_info->state != ACTIVE)
+				__msm_isp_axi_stream_update(
+						stream_info, &timestamp);
+
+			for (k = 0; k < stream_info->num_isp; k++) {
+				vfe_dev = stream_info->vfe_dev[k];
+				vfe_dev->hw_info->vfe_ops.core_ops.reg_update(
+					vfe_dev,
+					SRC_TO_INTF(stream_info->stream_src));
+			}
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		streams[num_streams++] = stream_info;
+	}
+
+	for (i = 0; i < MAX_VFE; i++) {
+		vfe_dev = update_vfes[i];
+		if (!vfe_dev)
+			continue;
+		vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev,
+			vfe_dev->vfe_base, wm_reload_mask[i]);
+
+		msm_isp_input_enable(vfe_dev,
+			stream_cfg_cmd->sync_frame_id_src);
+	}
+
+	rc = msm_isp_axi_wait_for_streams(streams, num_streams, 1);
+	if (rc < 0) {
+		pr_err("%s: wait for config done failed\n", __func__);
+		goto error;
+	}
+
+	return 0;
+error:
+	__msm_isp_stop_axi_streams(vfe_dev_ioctl, streams, num_streams,
+				STOP_STREAM);
+
+	return rc;
+}
+
+static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev_ioctl,
+			struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i, rc = 0;
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM];
+	int num_streams = 0;
+	unsigned long flags;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM ||
+		stream_cfg_cmd->num_streams == 0)
+		return -EINVAL;
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (stream_cfg_cmd->stream_handle[i] == 0)
+			continue;
+		stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl,
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]));
+		if (!stream_info) {
+			pr_err("%s: stream_info is NULL", __func__);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&stream_info->lock, flags);
+		rc = __msm_isp_check_stream_state(stream_info, 0);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		if (rc) {
+			/*
+			 * continue stopping other streams as error here means
+			 * stream is already not active
+			 */
+			rc = 0;
+			continue;
+		}
+		streams[num_streams++] = stream_info;
+	}
+	__msm_isp_stop_axi_streams(vfe_dev_ioctl, streams, num_streams,
+				stream_cfg_cmd->cmd);
+
+	return rc;
+}
+
+int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0;
+	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
+	uint32_t stream_idx[MAX_NUM_STREAM];
+	int i;
+	int vfe_idx;
+	struct msm_vfe_axi_stream *stream_info;
+
+	memset(stream_idx, 0, sizeof(stream_idx));
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >=
+			VFE_AXI_SRC_MAX)
+			return -EINVAL;
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]));
+		if (!stream_info) {
+			pr_err("%s: stream_info is NULL", __func__);
+			return -EINVAL;
+		}
+		vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev,
+								stream_info);
+		if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] !=
+					stream_cfg_cmd->stream_handle[i]) {
+			pr_err("%s: Invalid stream handle %x vfe_idx %d expected %x\n",
+				__func__, stream_cfg_cmd->stream_handle[i],
+				vfe_idx,
+				(vfe_idx != -ENOTTY) ?
+				stream_info->stream_handle[vfe_idx] : 0);
+			return -EINVAL;
+		}
+		/* check for duplicate stream handle */
+		if (stream_idx[stream_info->stream_src] ==
+			stream_cfg_cmd->stream_handle[i])
+			stream_cfg_cmd->stream_handle[i] = 0;
+		else
+			stream_idx[stream_info->stream_src] =
+				stream_cfg_cmd->stream_handle[i];
+	}
+	if (stream_cfg_cmd->cmd == START_STREAM) {
+		msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 1);
+
+		rc = msm_isp_start_axi_stream(
+			vfe_dev, stream_cfg_cmd);
+	} else {
+		rc = msm_isp_stop_axi_stream(
+			vfe_dev, stream_cfg_cmd);
+
+		msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 0);
+
+		/*
+		 * Use different ret value to not overwrite the error from
+		 * msm_isp_stop_axi_stream
+		 */
+		if (vfe_dev->axi_data.num_active_stream == 0)
+			vfe_dev->hvx_cmd = HVX_DISABLE;
+		if (vfe_dev->is_split) {
+			struct vfe_device *vfe_temp =
+				vfe_dev->common_data->
+				dual_vfe_res->vfe_dev[ISP_VFE0];
+			if (vfe_temp->axi_data.num_active_stream == 0)
+				vfe_temp->hvx_cmd = HVX_DISABLE;
+		}
+	}
+
+	if (rc < 0)
+		pr_err("%s: start/stop %d stream failed\n", __func__,
+			stream_cfg_cmd->cmd);
+	return rc;
+}
+
+static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t user_stream_id,
+	uint32_t frame_id, uint32_t buf_index,
+	enum msm_vfe_input_src frame_src)
+{
+	int rc = -1;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t bufq_handle = 0;
+	uint32_t stream_idx;
+	struct msm_isp_event_data error_event;
+	struct msm_isp_timestamp timestamp;
+
+	if (!vfe_dev || !stream_info) {
+		pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__,
+			__LINE__, vfe_dev, stream_info);
+		return -EINVAL;
+	}
+
+	stream_idx = stream_info->stream_src;
+	if (!stream_info->controllable_output)
+		return -EINVAL;
+
+	if (frame_src >= VFE_SRC_MAX) {
+		pr_err("%s: Invalid frame_src %d", __func__, frame_src);
+		return -EINVAL;
+	}
+
+	if (stream_idx >= VFE_AXI_SRC_MAX) {
+		pr_err("%s: Invalid stream_idx", __func__);
+		return rc;
+	}
+
+	if (user_stream_id == stream_info->stream_id)
+		bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT];
+	else
+		bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_SHARED];
+
+
+	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
+		vfe_dev->pdev->id, bufq_handle, buf_index, &buf);
+	if (rc == -EFAULT) {
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
+		return rc;
+	}
+
+	if (rc < 0 || buf == NULL) {
+		pr_err("Skip framedrop report due to no buffer\n");
+		return rc;
+	}
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev);
+	buf->buf_debug.put_state[buf->buf_debug.put_state_last] =
+		MSM_ISP_BUFFER_STATE_DROP_REG;
+	buf->buf_debug.put_state_last ^= 1;
+	rc = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
+		buf->bufq_handle, buf->buf_idx,
+		&timestamp.buf_time, frame_id,
+		stream_info->runtime_output_format);
+	if (rc == -EFAULT) {
+		msm_isp_halt_send_error(vfe_dev,
+			ISP_EVENT_BUF_FATAL_ERROR);
+		return rc;
+	}
+
+	memset(&error_event, 0, sizeof(error_event));
+	error_event.frame_id = frame_id;
+	error_event.u.error_info.err_type = ISP_ERROR_RETURN_EMPTY_BUFFER;
+	error_event.u.error_info.session_id = stream_info->session_id;
+	error_event.u.error_info.stream_id_mask =
+		1 << (bufq_handle & 0xFF);
+	msm_isp_send_event(vfe_dev, ISP_EVENT_ERROR, &error_event);
+
+	return 0;
+}
+
+static int msm_isp_request_frame(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t user_stream_id,
+	uint32_t frame_id, uint32_t buf_index)
+{
+	struct msm_vfe_axi_stream_request_cmd stream_cfg_cmd;
+	struct msm_vfe_frame_request_queue *queue_req;
+	uint32_t pingpong_status;
+	unsigned long flags;
+	int rc = 0;
+	enum msm_vfe_input_src frame_src = 0;
+	int k;
+	uint32_t wm_mask = 0;
+	int vfe_idx;
+	uint32_t pingpong_bit = 0;
+
+	if (!vfe_dev || !stream_info) {
+		pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__,
+			__LINE__, vfe_dev, stream_info);
+		return -EINVAL;
+	}
+
+	/* return early for dual vfe0 */
+	if (stream_info->num_isp > 1 && vfe_dev->pdev->id == ISP_VFE0)
+		return 0;
+
+	if (stream_info->stream_src >= VFE_AXI_SRC_MAX) {
+		pr_err("%s:%d invalid stream src %d\n", __func__, __LINE__,
+			stream_info->stream_src);
+		return -EINVAL;
+	}
+
+	frame_src = SRC_TO_INTF(stream_info->stream_src);
+	pingpong_status = vfe_dev->hw_info->
+		vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
+	/*
+	 * If PIX stream is active then RDI path uses SOF frame ID of PIX
+	 * In case of standalone RDI streaming, SOF are used from
+	 * individual intf.
+	 */
+	/*
+	 * If frame_id = 1 then no eof check is needed
+	 */
+	if (vfe_dev->axi_data.src_info[frame_src].active &&
+		frame_src == VFE_PIX_0 &&
+		vfe_dev->axi_data.src_info[frame_src].accept_frame == false) {
+		pr_debug("%s:%d invalid time to request frame %d\n",
+			__func__, __LINE__, frame_id);
+		goto error;
+	}
+	if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id !=
+		vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev->
+		axi_data.src_info[frame_src].sof_counter_step)) ||
+		((!vfe_dev->axi_data.src_info[frame_src].active))) {
+		pr_debug("%s:%d invalid frame id %d cur frame id %d pix %d\n",
+			__func__, __LINE__, frame_id,
+			vfe_dev->axi_data.src_info[frame_src].frame_id,
+			vfe_dev->axi_data.src_info[frame_src].active);
+		goto error;
+	}
+	if (stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) {
+		pr_debug("%s:%d invalid undelivered_request_cnt %d frame id %d\n",
+			__func__, __LINE__,
+			stream_info->undelivered_request_cnt,
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+		goto error;
+	}
+	if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt &&
+		MSM_VFE_STREAM_STOP_PERIOD !=
+		stream_info->activated_framedrop_period) {
+		pr_debug("%s:%d vfe %d frame_id %d prev_pattern %x stream_id %x\n",
+			__func__, __LINE__, vfe_dev->pdev->id, frame_id,
+			stream_info->activated_framedrop_period,
+			stream_info->stream_id);
+
+		rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
+			user_stream_id, frame_id, buf_index, frame_src);
+		if (rc < 0)
+			pr_err("%s:%d failed: return_empty_buffer src %d\n",
+				__func__, __LINE__, frame_src);
+		stream_info->current_framedrop_period =
+			MSM_VFE_STREAM_STOP_PERIOD;
+		msm_isp_cfg_framedrop_reg(stream_info);
+		return 0;
+	}
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+	vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	/* When wm reloaded, pingpong status register would be stale, pingpong
+	 * status would be updated only after AXI_DONE interrupt processed.
+	 * So, we should avoid reading value from pingpong status register
+	 * until buf_done happens for ping buffer.
+	 */
+	if ((stream_info->undelivered_request_cnt == 1) &&
+		(stream_info->sw_ping_pong_bit != -1)) {
+		pingpong_status =
+			vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(
+				vfe_dev);
+		pingpong_bit = ((pingpong_status >>
+					stream_info->wm[vfe_idx][0]) & 0x1);
+		if (stream_info->sw_ping_pong_bit == !pingpong_bit) {
+			ISP_DBG("%s:Return Empty Buffer stream id 0x%X\n",
+				__func__, stream_info->stream_id);
+			rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
+				user_stream_id, frame_id, buf_index,
+				frame_src);
+			spin_unlock_irqrestore(&stream_info->lock,
+					flags);
+			return 0;
+		}
+	}
+
+	queue_req = &stream_info->request_queue_cmd[stream_info->request_q_idx];
+	if (queue_req->cmd_used) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		pr_err_ratelimited("%s: Request queue overflow.\n", __func__);
+		return -EINVAL;
+	}
+
+	if (user_stream_id == stream_info->stream_id)
+		queue_req->buff_queue_id = VFE_BUF_QUEUE_DEFAULT;
+	else
+		queue_req->buff_queue_id = VFE_BUF_QUEUE_SHARED;
+
+	if (!stream_info->bufq_handle[queue_req->buff_queue_id]) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		pr_err("%s:%d request frame failed on hw stream 0x%x, request stream %d due to no bufq idx: %d\n",
+			__func__, __LINE__,
+			stream_info->stream_handle[0],
+			user_stream_id, queue_req->buff_queue_id);
+		return 0;
+	}
+	queue_req->buf_index = buf_index;
+	queue_req->cmd_used = 1;
+
+	stream_info->request_q_idx =
+		(stream_info->request_q_idx + 1) % MSM_VFE_REQUESTQ_SIZE;
+	list_add_tail(&queue_req->list, &stream_info->request_q);
+	stream_info->request_q_cnt++;
+
+	stream_info->undelivered_request_cnt++;
+	stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle[vfe_idx];
+	stream_cfg_cmd.frame_skip_pattern = NO_SKIP;
+	stream_cfg_cmd.init_frame_drop = 0;
+	stream_cfg_cmd.burst_count = stream_info->request_q_cnt;
+
+	if (stream_info->undelivered_request_cnt == 1) {
+		rc = msm_isp_cfg_ping_pong_address(stream_info,
+			VFE_PING_FLAG, NULL);
+		if (rc) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			stream_info->undelivered_request_cnt--;
+			pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n",
+				__func__, __LINE__);
+			return rc;
+		}
+
+		for (k = 0; k < stream_info->num_isp; k++) {
+			wm_mask = 0;
+			msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k],
+				stream_info, &wm_mask);
+			stream_info->vfe_dev[k]->
+				hw_info->vfe_ops.axi_ops.reload_wm(
+				stream_info->vfe_dev[k],
+				stream_info->vfe_dev[k]->vfe_base, wm_mask);
+
+		}
+		/* sw_ping_pong_bit is updated only when AXI_DONE.
+		 * so now reset this bit to -1.
+		 */
+		stream_info->sw_ping_pong_bit = -1;
+	} else if (stream_info->undelivered_request_cnt == 2) {
+		if (stream_info->sw_ping_pong_bit == -1) {
+			/* This means wm is reloaded & ping buffer is
+			 * already configured. And AXI_DONE for ping
+			 * is still pending. So, config pong buffer
+			 * now.
+			 */
+			rc = msm_isp_cfg_ping_pong_address(stream_info,
+				VFE_PONG_FLAG, NULL);
+		} else {
+			rc = msm_isp_cfg_ping_pong_address(
+					stream_info, pingpong_status, NULL);
+		}
+		if (rc) {
+			stream_info->undelivered_request_cnt--;
+			spin_unlock_irqrestore(&stream_info->lock,
+						flags);
+			pr_err_ratelimited("%s:%d fail to cfg HAL buffer\n",
+				__func__, __LINE__);
+			return rc;
+		}
+	} else {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		stream_info->undelivered_request_cnt--;
+		pr_err_ratelimited("%s: Invalid undeliver frame count %d\n",
+			__func__, stream_info->undelivered_request_cnt);
+		return -EINVAL;
+	}
+
+	rc = msm_isp_calculate_framedrop(vfe_dev, &stream_cfg_cmd);
+	if (rc == 0)
+		msm_isp_reset_framedrop(vfe_dev, stream_info);
+
+	/*Avoid Multiple request frames for single SOF*/
+	vfe_dev->axi_data.src_info[frame_src].accept_frame = false;
+
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+
+	return rc;
+error:
+	rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
+		user_stream_id, frame_id, buf_index, frame_src);
+	if (rc < 0)
+		pr_err("%s:%d failed: return_empty_buffer src %d\n",
+		__func__, __LINE__, frame_src);
+	return 0;
+
+}
+
+static int msm_isp_add_buf_queue(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t stream_id)
+{
+	int rc = 0;
+	uint32_t bufq_id = 0;
+	unsigned long flags;
+
+	if (stream_id == stream_info->stream_id)
+		bufq_id = VFE_BUF_QUEUE_DEFAULT;
+	else
+		bufq_id = VFE_BUF_QUEUE_SHARED;
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+
+	if (stream_info->bufq_handle[bufq_id] == 0) {
+		stream_info->bufq_handle[bufq_id] =
+			vfe_dev->buf_mgr->ops->get_bufq_handle(vfe_dev->buf_mgr,
+				stream_info->session_id, stream_id);
+		if (stream_info->bufq_handle[bufq_id] == 0) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			pr_err("%s: failed: No valid buffer queue for stream: 0x%x\n",
+				__func__, stream_id);
+			return -EINVAL;
+		}
+	} else {
+		uint32_t bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+						vfe_dev->buf_mgr,
+						stream_info->session_id,
+						stream_id);
+		if (bufq_handle != stream_info->bufq_handle[bufq_id]) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			pr_err("%s: Stream %x already has buffer q %x cannot add handle %x\n",
+				__func__, stream_id,
+				stream_info->bufq_handle[bufq_id], bufq_handle);
+			return -EINVAL;
+		}
+	}
+
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+
+	ISP_DBG("%d: Add bufq handle:0x%x, idx:%d, for stream %d on VFE %d\n",
+		__LINE__, stream_info->bufq_handle[bufq_id],
+		bufq_id, stream_info->stream_handle[0],
+		vfe_dev->pdev->id);
+
+	return rc;
+}
+
+static void msm_isp_remove_buf_queue(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t stream_id)
+{
+	uint32_t bufq_id = 0;
+	unsigned long flags;
+
+	if (stream_id == stream_info->stream_id)
+		bufq_id = VFE_BUF_QUEUE_DEFAULT;
+	else
+		bufq_id = VFE_BUF_QUEUE_SHARED;
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+
+	if (stream_info->bufq_handle[bufq_id]) {
+		stream_info->bufq_handle[bufq_id] = 0;
+		if (stream_info->state == ACTIVE) {
+			init_completion(&stream_info->active_comp);
+			stream_info->state = UPDATING;
+		}
+	}
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+	if (stream_info->state == UPDATING)
+		msm_isp_axi_wait_for_stream_cfg_done(stream_info, 1);
+
+}
+
+/**
+ * msm_isp_stream_axi_cfg_update() - Apply axi config update to a stream
+ * @vfe_dev: The vfe device on which the update is to be applied
+ * @stream_info: Stream for which update is to be applied
+ * @update_info: Parameters of the update
+ *
+ * Returns - 0 on success else error code
+ *
+ * For dual vfe stream apply the update once update for both vfe is
+ * received.
+ */
+static int msm_isp_stream_axi_cfg_update(struct vfe_device *vfe_dev,
+			struct msm_vfe_axi_stream *stream_info,
+			struct msm_vfe_axi_stream_cfg_update_info *update_info)
+{
+	int j;
+	int k;
+	unsigned long flags;
+	int vfe_idx;
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+	if (stream_info->state != ACTIVE) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		pr_err("Invalid stream state for axi update %d\n",
+			stream_info->state);
+		return -EINVAL;
+	}
+	if (stream_info->update_vfe_mask) {
+		if (stream_info->update_vfe_mask & (1 << vfe_dev->pdev->id)) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			pr_err("%s: Stream %pK/%x Update already in progress for vfe %d\n",
+				__func__, stream_info, stream_info->stream_src,
+				vfe_dev->pdev->id);
+			return -EINVAL;
+		}
+	}
+	vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+
+	for (j = 0; j < stream_info->num_planes; j++)
+		stream_info->plane_cfg[vfe_idx][j] = update_info->plane_cfg[j];
+
+	stream_info->update_vfe_mask |= (1 << vfe_dev->pdev->id);
+	/* wait for update from all vfe's under stream before applying */
+	if (stream_info->update_vfe_mask != stream_info->vfe_mask) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		return 0;
+	}
+
+	atomic_set(&vfe_dev->axi_data.axi_cfg_update[
+		SRC_TO_INTF(stream_info->stream_src)], 1);
+	stream_info->output_format = update_info->output_format;
+	init_completion(&stream_info->active_comp);
+	if (((vfe_dev->hw_info->runtime_axi_update == 0) ||
+		(vfe_dev->dual_vfe_enable == 1)))  {
+		stream_info->state = PAUSE_PENDING;
+		msm_isp_axi_stream_enable_cfg(stream_info);
+		stream_info->state = PAUSING;
+	} else {
+		for (j = 0; j < stream_info->num_planes; j++) {
+			for (k = 0; k < stream_info->num_isp; k++) {
+				vfe_dev = stream_info->vfe_dev[k];
+				vfe_dev->hw_info->vfe_ops.axi_ops.
+					cfg_wm_reg(vfe_dev, stream_info, j);
+			}
+		}
+		stream_info->state = RESUMING;
+	}
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+	return 0;
+}
+
+int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
+	struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL;
+	struct msm_isp_sw_framskip *sw_skip_info = NULL;
+	unsigned long flags;
+	struct msm_isp_timestamp timestamp;
+	uint32_t frame_id;
+	int vfe_idx;
+
+	/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
+	if (update_cmd->num_streams > MAX_NUM_STREAM)
+		return -EINVAL;
+
+	for (i = 0; i < update_cmd->num_streams; i++) {
+		update_info = (struct msm_vfe_axi_stream_cfg_update_info *)
+			&update_cmd->update_info[i];
+		/*check array reference bounds*/
+		if (HANDLE_TO_IDX(update_info->stream_handle) >=
+			VFE_AXI_SRC_MAX) {
+			return -EINVAL;
+		}
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+			HANDLE_TO_IDX(update_info->stream_handle));
+		if (!stream_info) {
+			pr_err("%s: stream_info is null", __func__);
+			return -EINVAL;
+		}
+		if (SRC_TO_INTF(stream_info->stream_src) >= VFE_SRC_MAX)
+			continue;
+		if (stream_info->state != ACTIVE &&
+			stream_info->state != INACTIVE &&
+			update_cmd->update_type !=
+			UPDATE_STREAM_REQUEST_FRAMES &&
+			update_cmd->update_type !=
+			UPDATE_STREAM_REMOVE_BUFQ &&
+			update_cmd->update_type !=
+			UPDATE_STREAM_SW_FRAME_DROP) {
+			pr_err("%s: Invalid stream state %d, update cmd %d\n",
+				__func__, stream_info->state,
+				stream_info->stream_id);
+			return -EINVAL;
+		}
+		if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG &&
+			stream_info->state != ACTIVE) {
+			pr_err("%s: AXI stream config updating\n", __func__);
+			return -EBUSY;
+		}
+	}
+
+	switch (update_cmd->update_type) {
+	case ENABLE_STREAM_BUF_DIVERT:
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			stream_info->buf_divert = 1;
+		}
+		break;
+	case DISABLE_STREAM_BUF_DIVERT:
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			stream_info->buf_divert = 0;
+			msm_isp_get_timestamp(&timestamp, vfe_dev);
+			frame_id = vfe_dev->axi_data.src_info[
+				SRC_TO_INTF(stream_info->stream_src)].frame_id;
+			/* set ping pong address to scratch before flush */
+			spin_lock_irqsave(&stream_info->lock, flags);
+			msm_isp_cfg_stream_scratch(stream_info,
+					VFE_PING_FLAG);
+			msm_isp_cfg_stream_scratch(stream_info,
+					VFE_PONG_FLAG);
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			rc = vfe_dev->buf_mgr->ops->flush_buf(
+				vfe_dev->buf_mgr,
+				stream_info->bufq_handle
+					[VFE_BUF_QUEUE_DEFAULT],
+				MSM_ISP_BUFFER_FLUSH_DIVERTED,
+				&timestamp.buf_time, frame_id);
+			if (rc == -EFAULT) {
+				msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_BUF_FATAL_ERROR);
+				return rc;
+			}
+		}
+		break;
+	case UPDATE_STREAM_FRAMEDROP_PATTERN: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			uint32_t framedrop_period =
+				msm_isp_get_framedrop_period(
+					update_info->skip_pattern);
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&stream_info->lock, flags);
+			/* no change then break early */
+			if (stream_info->current_framedrop_period ==
+				framedrop_period) {
+				spin_unlock_irqrestore(&stream_info->lock,
+					flags);
+				break;
+			}
+			if (stream_info->controllable_output) {
+				pr_err("Controllable output streams does not support custom frame skip pattern\n");
+				spin_unlock_irqrestore(&stream_info->lock,
+					flags);
+				return -EINVAL;
+			}
+			if (update_info->skip_pattern == SKIP_ALL)
+				stream_info->current_framedrop_period =
+					MSM_VFE_STREAM_STOP_PERIOD;
+			else
+				stream_info->current_framedrop_period =
+					framedrop_period;
+			if (stream_info->stream_type != BURST_STREAM)
+				msm_isp_cfg_framedrop_reg(stream_info);
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+		}
+		break;
+	}
+	case UPDATE_STREAM_SW_FRAME_DROP: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			sw_skip_info = &update_info->sw_skip_info;
+			if (sw_skip_info &&
+				sw_skip_info->stream_src_mask != 0) {
+				/* SW image buffer drop */
+				pr_debug("%x sw skip type %x mode %d min %d max %d\n",
+					stream_info->stream_id,
+					sw_skip_info->stats_type_mask,
+					sw_skip_info->skip_mode,
+					sw_skip_info->min_frame_id,
+					sw_skip_info->max_frame_id);
+				spin_lock_irqsave(&stream_info->lock, flags);
+				stream_info->sw_skip = *sw_skip_info;
+				spin_unlock_irqrestore(&stream_info->lock,
+					flags);
+			}
+		}
+		break;
+	}
+	case UPDATE_STREAM_AXI_CONFIG: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			rc = msm_isp_stream_axi_cfg_update(vfe_dev, stream_info,
+						update_info);
+			if (rc)
+				return rc;
+		}
+		break;
+	}
+	case UPDATE_STREAM_REQUEST_FRAMES: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			rc = msm_isp_request_frame(vfe_dev, stream_info,
+				update_info->user_stream_id,
+				update_info->frame_id,
+				MSM_ISP_INVALID_BUF_INDEX);
+			if (rc)
+				pr_err("%s failed to request frame!\n",
+					__func__);
+		}
+		break;
+	}
+	case UPDATE_STREAM_ADD_BUFQ: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			rc = msm_isp_add_buf_queue(vfe_dev, stream_info,
+				update_info->user_stream_id);
+			if (rc)
+				pr_err("%s failed to add bufq!\n", __func__);
+		}
+		break;
+	}
+	case UPDATE_STREAM_REMOVE_BUFQ: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			msm_isp_remove_buf_queue(vfe_dev, stream_info,
+				update_info->user_stream_id);
+			pr_debug("%s, Remove bufq for Stream 0x%x\n",
+				__func__, stream_info->stream_id);
+		}
+		break;
+	}
+	case UPDATE_STREAM_REQUEST_FRAMES_VER2: {
+		struct msm_vfe_axi_stream_cfg_update_info_req_frm *req_frm =
+			&update_cmd->req_frm_ver2;
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(req_frm->stream_handle));
+		if (!stream_info) {
+			pr_err("%s: stream_info is null", __func__);
+			return -EINVAL;
+		}
+		rc = msm_isp_request_frame(vfe_dev, stream_info,
+			req_frm->user_stream_id,
+			req_frm->frame_id,
+			req_frm->buf_index);
+		if (rc)
+			pr_err("%s failed to request frame!\n",
+				__func__);
+		break;
+	}
+	case UPDATE_STREAM_OFFLINE_AXI_CONFIG: {
+		for (i = 0; i < update_cmd->num_streams; i++) {
+			update_info =
+				(struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+				HANDLE_TO_IDX(update_info->stream_handle));
+			if (!stream_info) {
+				pr_err("%s: stream_info is null", __func__);
+				return -EINVAL;
+			}
+			vfe_idx = msm_isp_get_vfe_idx_for_stream(
+				vfe_dev, stream_info);
+			msm_isp_stream_axi_cfg_update(vfe_dev, stream_info,
+				update_info);
+		}
+		break;
+	}
+	default:
+		pr_err("%s: Invalid update type %d\n", __func__,
+			update_cmd->update_type);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
+		struct msm_vfe_axi_stream *stream_info,
+		uint32_t pingpong_status,
+		struct msm_isp_timestamp *ts)
+{
+	int rc = -1;
+	uint32_t pingpong_bit = 0, i;
+	struct msm_isp_buffer *done_buf = NULL;
+	unsigned long flags;
+	struct timeval *time_stamp;
+	uint32_t frame_id, buf_index = -1;
+	int vfe_idx;
+
+	if (!ts) {
+		pr_err("%s: Error! Invalid argument\n", __func__);
+		return;
+	}
+
+	if (vfe_dev->vt_enable) {
+		msm_isp_get_avtimer_ts(ts);
+		time_stamp = &ts->vt_time;
+	} else {
+		time_stamp = &ts->buf_time;
+	}
+
+	frame_id = vfe_dev->axi_data.
+		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+	vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+	pingpong_bit = (~(pingpong_status >>
+			stream_info->wm[vfe_idx][0]) & 0x1);
+	for (i = 0; i < stream_info->num_planes; i++) {
+		if (pingpong_bit !=
+			(~(pingpong_status >>
+			stream_info->wm[vfe_idx][i]) & 0x1)) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			msm_isp_dump_ping_pong_mismatch(vfe_dev);
+			pr_err("%s: Write master ping pong mismatch. Status: 0x%x %x\n",
+				__func__, pingpong_status,
+				stream_info->stream_src);
+			msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_PING_PONG_MISMATCH);
+			return;
+		}
+	}
+	if (stream_info->state == INACTIVE) {
+		WARN_ON(stream_info->buf[pingpong_bit] != NULL);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		return;
+	}
+
+	/* composite the irq for dual vfe */
+	rc = msm_isp_composite_irq(vfe_dev, stream_info,
+		MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit);
+	if (rc) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		if (rc < 0)
+			msm_isp_halt_send_error(vfe_dev,
+					ISP_EVENT_PING_PONG_MISMATCH);
+		return;
+	}
+
+	done_buf = stream_info->buf[pingpong_bit];
+
+	if (vfe_dev->buf_mgr->frameId_mismatch_recovery == 1) {
+		if (done_buf) {
+			if (done_buf->is_drop_reconfig == 1)
+				done_buf->is_drop_reconfig = 0;
+		}
+		pr_err_ratelimited("%s: Mismatch Recovery in progress, drop frame!\n",
+			__func__);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		return;
+	}
+
+	if (done_buf)
+		buf_index = done_buf->buf_idx;
+
+	ISP_DBG("%s: vfe %d: stream 0x%x, frame id %d, pingpong bit %d\n",
+		__func__,
+		vfe_dev->pdev->id,
+		stream_info->stream_id,
+		frame_id,
+		pingpong_bit);
+
+	stream_info->frame_id++;
+	stream_info->buf[pingpong_bit] = NULL;
+
+	if (stream_info->controllable_output &&
+		(done_buf != NULL) &&
+		(stream_info->sw_ping_pong_bit == -1) &&
+		(done_buf->is_drop_reconfig == 1)) {
+		/* When wm reloaded and corresponding reg_update fail
+		 * then buffer is reconfig as PING buffer. so, avoid
+		 * NULL assignment to PING buffer and eventually
+		 * next AXI_DONE or buf_done can be successful
+		 */
+		stream_info->buf[pingpong_bit] = done_buf;
+	}
+
+	if (stream_info->stream_type == CONTINUOUS_STREAM ||
+		stream_info->runtime_num_burst_capture > 1) {
+		rc = msm_isp_cfg_ping_pong_address(
+			stream_info, pingpong_status, NULL);
+		if (rc < 0)
+			ISP_DBG("%s: Error configuring ping_pong\n",
+				__func__);
+	} else if (done_buf && (done_buf->is_drop_reconfig != 1)) {
+		msm_isp_cfg_stream_scratch(stream_info, pingpong_status);
+	}
+
+	if (!done_buf) {
+		if (stream_info->buf_divert) {
+			vfe_dev->error_info.stream_framedrop_count[
+				stream_info->bufq_handle[
+				VFE_BUF_QUEUE_DEFAULT] & 0xFF]++;
+			vfe_dev->error_info.framedrop_flag = 1;
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		return;
+	}
+
+	if (stream_info->stream_type == BURST_STREAM &&
+		stream_info->runtime_num_burst_capture) {
+		ISP_DBG("%s: burst_frame_count: %d\n",
+			__func__,
+			stream_info->runtime_num_burst_capture);
+		stream_info->runtime_num_burst_capture--;
+	}
+
+	rc = msm_isp_update_deliver_count(vfe_dev, stream_info,
+					pingpong_bit, done_buf);
+	if (rc) {
+		if (done_buf->is_drop_reconfig == 1)
+			done_buf->is_drop_reconfig = 0;
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		pr_err_ratelimited("%s:VFE%d get done buf fail\n",
+			__func__, vfe_dev->pdev->id);
+		msm_isp_halt_send_error(vfe_dev,
+			ISP_EVENT_PING_PONG_MISMATCH);
+		return;
+	}
+
+
+	if ((done_buf->frame_id != frame_id) &&
+		vfe_dev->axi_data.enable_frameid_recovery) {
+		if (done_buf->is_drop_reconfig == 1)
+			done_buf->is_drop_reconfig = 0;
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		msm_isp_handle_done_buf_frame_id_mismatch(vfe_dev,
+			stream_info, done_buf, time_stamp, frame_id);
+		return;
+	}
+
+	if (done_buf->is_drop_reconfig == 1) {
+	/* When ping/pong buf is already reconfigured
+	 * then dont issue buf-done for current buffer
+	 */
+		done_buf->is_drop_reconfig = 0;
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	} else {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		msm_isp_process_done_buf(vfe_dev, stream_info,
+			done_buf, time_stamp, frame_id);
+	}
+}
+
+void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	int i, rc = 0;
+	uint32_t comp_mask = 0, wm_mask = 0;
+	uint32_t pingpong_status, stream_idx;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_composite_info *comp_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int wm;
+
+	comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops.
+		get_comp_mask(irq_status0, irq_status1);
+	wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops.
+		get_wm_mask(irq_status0, irq_status1);
+	if (!(comp_mask || wm_mask))
+		return;
+
+	ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
+	pingpong_status =
+		vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
+
+	for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
+		rc = 0;
+		comp_info = &axi_data->composite_info[i];
+		wm_mask &= ~(comp_info->stream_composite_mask);
+		if (comp_mask & (1 << i)) {
+			stream_idx = HANDLE_TO_IDX(comp_info->stream_handle);
+			if ((!comp_info->stream_handle) ||
+				(stream_idx >= VFE_AXI_SRC_MAX)) {
+				pr_err_ratelimited("%s: Invalid handle for composite irq\n",
+					__func__);
+				for (wm = 0; wm < axi_data->hw_info->num_wm;
+					wm++)
+					if (comp_info->stream_composite_mask &
+						(1 << wm))
+						msm_isp_cfg_wm_scratch(vfe_dev,
+							wm, pingpong_status);
+				continue;
+			}
+			stream_idx = HANDLE_TO_IDX(comp_info->stream_handle);
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+								stream_idx);
+
+			msm_isp_process_axi_irq_stream(vfe_dev, stream_info,
+						pingpong_status, ts);
+
+		}
+	}
+
+	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+		if (wm_mask & (1 << i)) {
+			stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]);
+			if ((!axi_data->free_wm[i]) ||
+				(stream_idx >= VFE_AXI_SRC_MAX)) {
+				pr_err("%s: Invalid handle for wm irq\n",
+					__func__);
+				msm_isp_cfg_wm_scratch(vfe_dev, i,
+					pingpong_status);
+				continue;
+			}
+			stream_info = msm_isp_get_stream_common_data(vfe_dev,
+								stream_idx);
+
+			msm_isp_process_axi_irq_stream(vfe_dev, stream_info,
+						pingpong_status, ts);
+		}
+	}
+}
+
+void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	int i, j;
+	int vfe_idx;
+
+	if (!vfe_dev || !axi_data) {
+		pr_err("%s: error  %pK %pK\n", __func__, vfe_dev, axi_data);
+		return;
+	}
+
+	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev, i);
+
+		if (stream_info->state != ACTIVE)
+			continue;
+
+		vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev,
+				stream_info);
+		for (j = 0; j < stream_info->num_planes; j++)
+			vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm(
+				vfe_dev->vfe_base,
+				stream_info->wm[vfe_idx][j], 0);
+	}
+}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
new file mode 100644
index 0000000..5dcd967
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_ISP_AXI_UTIL_H__
+#define __MSM_ISP_AXI_UTIL_H__
+
+#include "msm_isp.h"
+
+#define HANDLE_TO_IDX(handle) (handle & 0xFF)
+#define SRC_TO_INTF(src) \
+	((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \
+	(VFE_RAW_0 + src - RDI_INTF_0))
+
+int msm_isp_axi_check_stream_state(
+	struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd);
+
+void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+
+int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg);
+void msm_isp_start_avtimer(void);
+void msm_isp_stop_avtimer(void);
+void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp);
+int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg);
+void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src);
+int msm_isp_axi_halt(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_halt_cmd *halt_cmd);
+int msm_isp_axi_reset(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_reset_cmd *reset_cmd);
+int msm_isp_axi_restart(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_restart_cmd *restart_cmd);
+
+void msm_isp_axi_stream_update(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src,
+	struct msm_isp_timestamp *ts);
+
+void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src,
+	enum msm_isp_comp_irq_types irq,
+	struct msm_isp_timestamp *ts);
+
+void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
+
+void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts);
+
+void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev);
+
+int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev,
+	unsigned long fault_addr);
+
+void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
+	enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
+
+int msm_isp_drop_frame(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts,
+	struct msm_isp_sof_info *sof_info);
+
+void msm_isp_halt(struct vfe_device *vfe_dev);
+void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event);
+
+void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info,
+	uint32_t pingpong_status,
+	struct msm_isp_timestamp *ts);
+
+void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev);
+void msm_isp_axi_free_wm(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info);
+void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
+	struct msm_isp_timestamp *ts, struct msm_isp_sof_info *sof_info);
+
+static inline int msm_isp_get_vfe_idx_for_stream_user(
+				struct vfe_device *vfe_dev,
+				struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx;
+
+	for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++) {
+		if (stream_info->vfe_dev[vfe_idx] == vfe_dev)
+			return vfe_idx;
+	}
+	return -ENOTTY;
+}
+
+static inline int msm_isp_get_vfe_idx_for_stream(struct vfe_device *vfe_dev,
+				struct msm_vfe_axi_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info);
+
+	if (vfe_idx < 0) {
+		WARN(1, "%s vfe index misssing for stream %d, vfe %d\n",
+			__func__, stream_info->stream_src, vfe_dev->pdev->id);
+		vfe_idx = 0;
+	}
+	return vfe_idx;
+}
+
+static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev,
+				int wm,
+				uint32_t pingpong_bit)
+{
+	vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
+		vfe_dev->vfe_base, wm,
+		pingpong_bit, vfe_dev->buf_mgr->scratch_buf_addr, 0);
+}
+
+static inline void msm_isp_cfg_stream_scratch(
+				struct msm_vfe_axi_stream *stream_info,
+				uint32_t pingpong_status)
+{
+	int i;
+	int j;
+	uint32_t pingpong_bit;
+	int vfe_idx;
+
+	pingpong_bit = (~(pingpong_status >> stream_info->wm[0][0]) & 0x1);
+	for (i = 0; i < stream_info->num_planes; i++) {
+		for (j = 0; j < stream_info->num_isp; j++) {
+			vfe_idx = msm_isp_get_vfe_idx_for_stream(
+					stream_info->vfe_dev[j], stream_info);
+			msm_isp_cfg_wm_scratch(stream_info->vfe_dev[j],
+				stream_info->wm[vfe_idx][i],
+				~pingpong_bit);
+		}
+	}
+	stream_info->buf[pingpong_bit] = NULL;
+}
+
+static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data(
+			struct vfe_device *vfe_dev, uint32_t stream_idx)
+{
+	struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data;
+	struct msm_vfe_axi_stream *stream_info;
+
+	if (stream_idx >= VFE_AXI_SRC_MAX) {
+		pr_err("invalid stream_idx %d\n", stream_idx);
+		return NULL;
+	}
+
+	if (vfe_dev->is_split &&  stream_idx < RDI_INTF_0)
+		stream_info = &common_data->streams[stream_idx];
+	else
+		stream_info = &common_data->streams[VFE_AXI_SRC_MAX *
+				vfe_dev->pdev->id + stream_idx];
+	return stream_info;
+}
+
+static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream(
+			struct dual_vfe_resource *dual_vfe_res,
+			int vfe_id, uint32_t index)
+{
+	return msm_isp_get_stream_common_data(dual_vfe_res->vfe_dev[vfe_id],
+						index);
+}
+
+int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
+	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+	uint32_t buf_idx);
+int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev,
+	void *arg);
+#endif /* __MSM_ISP_AXI_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
new file mode 100644
index 0000000..98be3dd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -0,0 +1,1356 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_isp.h>
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+
+static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev,
+				struct msm_vfe_stats_stream *stream_info,
+				uint32_t pingpong_status)
+{
+	vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
+		vfe_dev, stream_info,
+		pingpong_status, vfe_dev->buf_mgr->scratch_buf_stats_addr,
+		SZ_32M);
+}
+
+static inline void msm_isp_stats_cfg_stream_scratch(
+				struct msm_vfe_stats_stream *stream_info,
+				uint32_t pingpong_status)
+{
+	uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]);
+	uint32_t pingpong_bit;
+	uint32_t stats_pingpong_offset;
+	struct vfe_device *vfe_dev;
+	int i;
+
+	stats_pingpong_offset = stream_info->vfe_dev[0]->hw_info->
+			stats_hw_info->stats_ping_pong_offset[stats_idx];
+	pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
+
+	for (i = 0; i < stream_info->num_isp; i++) {
+		vfe_dev = stream_info->vfe_dev[i];
+		msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info,
+						pingpong_status);
+	}
+
+	stream_info->buf[pingpong_bit] = NULL;
+}
+
+static int msm_isp_composite_stats_irq(struct vfe_device *vfe_dev,
+				struct msm_vfe_stats_stream *stream_info,
+				enum msm_isp_comp_irq_types irq)
+{
+	/* interrupt recv on same vfe w/o recv on other vfe */
+	if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) {
+		pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n",
+			__func__, irq, vfe_dev->pdev->id);
+		return -EFAULT;
+	}
+
+	stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id);
+	if (stream_info->composite_irq[irq] != stream_info->vfe_mask)
+		return 1;
+
+	stream_info->composite_irq[irq] = 0;
+
+	return 0;
+}
+
+static int msm_isp_stats_cfg_ping_pong_address(
+	struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status)
+{
+	int rc = -1;
+	struct msm_isp_buffer *buf = NULL;
+	uint32_t bufq_handle = stream_info->bufq_handle;
+	uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]);
+	struct vfe_device *vfe_dev = stream_info->vfe_dev[0];
+	uint32_t stats_pingpong_offset;
+	uint32_t pingpong_bit;
+	int k;
+
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type ||
+		stats_idx >= MSM_ISP_STATS_MAX) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
+	}
+	stats_pingpong_offset = vfe_dev->hw_info->stats_hw_info->
+					stats_ping_pong_offset[stats_idx];
+	pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
+	/* if buffer already exists then no need to replace */
+	if (stream_info->buf[pingpong_bit])
+		return 0;
+
+	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
+			vfe_dev->pdev->id, bufq_handle,
+			MSM_ISP_INVALID_BUF_INDEX, &buf);
+	if (rc == -EFAULT) {
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
+		return rc;
+	}
+	if (rc < 0 || NULL == buf) {
+		for (k = 0; k < stream_info->num_isp; k++)
+			stream_info->vfe_dev[k]->error_info.
+				stats_framedrop_count[stats_idx]++;
+	}
+
+	if (buf && buf->num_planes != 1) {
+		pr_err("%s: Invalid buffer\n", __func__);
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
+		rc = -EINVAL;
+		goto buf_error;
+	}
+
+	if (!buf) {
+		msm_isp_stats_cfg_stream_scratch(stream_info,
+							pingpong_status);
+		return 0;
+	}
+	for (k = 0; k < stream_info->num_isp; k++) {
+		vfe_dev = stream_info->vfe_dev[k];
+		vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
+			vfe_dev, stream_info, pingpong_status,
+			buf->mapped_info[0].paddr +
+			stream_info->buffer_offset[k],
+			buf->mapped_info[0].len);
+	}
+	stream_info->buf[pingpong_bit] = buf;
+	buf->pingpong_bit = pingpong_bit;
+
+	return 0;
+buf_error:
+	vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+		buf->bufq_handle, buf->buf_idx);
+	return rc;
+}
+
+static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
+	struct msm_isp_timestamp *ts,
+	struct msm_isp_event_data *buf_event,
+	struct msm_vfe_stats_stream *stream_info,
+	uint32_t *comp_stats_type_mask, uint32_t pingpong_status)
+{
+	int32_t rc = 0, frame_id = 0, drop_buffer = 0;
+	struct msm_isp_stats_event *stats_event = NULL;
+	struct msm_isp_sw_framskip *sw_skip = NULL;
+	int32_t buf_index = -1;
+	uint32_t pingpong_bit;
+	struct msm_isp_buffer *done_buf;
+	uint32_t stats_pingpong_offset;
+	uint32_t stats_idx;
+	int vfe_idx;
+	unsigned long flags;
+
+	if (!vfe_dev || !ts || !buf_event || !stream_info) {
+		pr_err("%s:%d failed: invalid params %pK %pK %pK %pK\n",
+			__func__, __LINE__, vfe_dev, ts, buf_event,
+			stream_info);
+		return -EINVAL;
+	}
+	frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+
+	spin_lock_irqsave(&stream_info->lock, flags);
+
+	sw_skip = &stream_info->sw_skip;
+	stats_event = &buf_event->u.stats;
+
+	if (sw_skip->stats_type_mask &
+		(1 << stream_info->stats_type)) {
+		/* Hw stream output of this src is requested
+		 * for drop
+		 */
+		if (sw_skip->skip_mode == SKIP_ALL) {
+			/* drop all buffers */
+			drop_buffer = 1;
+		} else if (sw_skip->skip_mode == SKIP_RANGE &&
+		(sw_skip->min_frame_id <= frame_id &&
+		sw_skip->max_frame_id >= frame_id)) {
+			drop_buffer = 1;
+		} else if (frame_id > sw_skip->max_frame_id) {
+			memset(sw_skip, 0, sizeof
+				(struct msm_isp_sw_framskip));
+		}
+	}
+	vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, stream_info);
+	stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
+
+	stats_pingpong_offset =
+			vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[
+			stats_idx];
+	pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
+
+	rc = msm_isp_composite_stats_irq(vfe_dev, stream_info,
+			MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit);
+	if (rc) {
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		if (rc < 0)
+			msm_isp_halt_send_error(vfe_dev,
+				ISP_EVENT_PING_PONG_MISMATCH);
+		return rc;
+	}
+
+	done_buf = stream_info->buf[pingpong_bit];
+	/* Program next buffer */
+	stream_info->buf[pingpong_bit] = NULL;
+	rc = msm_isp_stats_cfg_ping_pong_address(stream_info,
+						pingpong_status);
+	spin_unlock_irqrestore(&stream_info->lock, flags);
+
+	if (!done_buf)
+		return rc;
+
+	buf_index = done_buf->buf_idx;
+	if (drop_buffer) {
+		vfe_dev->buf_mgr->ops->put_buf(
+			vfe_dev->buf_mgr,
+			done_buf->bufq_handle,
+			done_buf->buf_idx);
+	} else {
+		/* divert native buffers */
+		vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
+			done_buf->bufq_handle, done_buf->buf_idx,
+			&ts->buf_time, frame_id);
+	}
+	stats_event->stats_buf_idxs
+		[stream_info->stats_type] =
+		done_buf->buf_idx;
+
+	stats_event->pd_stats_idx = 0xF;
+	if (stream_info->stats_type == MSM_ISP_STATS_BF) {
+		spin_lock_irqsave(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+		stats_event->pd_stats_idx = vfe_dev->common_data->pd_buf_idx;
+		vfe_dev->common_data->pd_buf_idx = 0xF;
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+	}
+	if (comp_stats_type_mask == NULL) {
+		stats_event->stats_mask =
+			1 << stream_info->stats_type;
+		ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n",
+			__func__, buf_event->frame_id,
+			stream_info->stats_type, done_buf->bufq_handle);
+		msm_isp_send_event(vfe_dev,
+			ISP_EVENT_STATS_NOTIFY +
+			stream_info->stats_type,
+			buf_event);
+	} else {
+		*comp_stats_type_mask |=
+			1 << stream_info->stats_type;
+	}
+
+	return rc;
+}
+
+static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev,
+	uint32_t stats_irq_mask, struct msm_isp_timestamp *ts,
+	bool is_composite)
+{
+	int i, rc = 0;
+	struct msm_isp_event_data buf_event;
+	struct msm_isp_stats_event *stats_event = &buf_event.u.stats;
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	uint32_t pingpong_status;
+	uint32_t comp_stats_type_mask = 0;
+	int result = 0;
+
+	memset(&buf_event, 0, sizeof(struct msm_isp_event_data));
+	buf_event.timestamp = ts->event_time;
+	buf_event.mono_timestamp = ts->buf_time;
+
+	buf_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	pingpong_status = vfe_dev->hw_info->
+		vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
+
+	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
+		if (!(stats_irq_mask & (1 << i)))
+			continue;
+		stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i);
+		if (stream_info->state == STATS_INACTIVE ||
+			stream_info->state == STATS_STOPPING) {
+			pr_debug("%s: Warning! Stream already inactive. Drop irq handling\n",
+				__func__);
+			continue;
+		}
+
+		rc = msm_isp_stats_buf_divert(vfe_dev, ts,
+				&buf_event, stream_info,
+				is_composite ? &comp_stats_type_mask : NULL,
+				pingpong_status);
+		if (rc < 0) {
+			pr_err("%s:%d failed: stats buf divert rc %d\n",
+				__func__, __LINE__, rc);
+			result = rc;
+		}
+	}
+	if (is_composite && comp_stats_type_mask) {
+		ISP_DBG("%s:vfe_id %d comp_stats frameid %x,comp_mask %x\n",
+			__func__, vfe_dev->pdev->id, buf_event.frame_id,
+			comp_stats_type_mask);
+		stats_event->stats_mask = comp_stats_type_mask;
+		msm_isp_send_event(vfe_dev,
+			ISP_EVENT_COMP_STATS_NOTIFY, &buf_event);
+		comp_stats_type_mask = 0;
+	}
+	return result;
+}
+
+void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts)
+{
+	int j, rc;
+	uint32_t atomic_stats_mask = 0;
+	uint32_t stats_comp_mask = 0, stats_irq_mask = 0;
+	bool comp_flag = false;
+	uint32_t num_stats_comp_mask =
+		vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
+
+	stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
+		get_comp_mask(irq_status0, irq_status1);
+	stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
+		get_wm_mask(irq_status0, irq_status1);
+	if (!(stats_comp_mask || stats_irq_mask))
+		return;
+
+	ISP_DBG("%s: vfe %d status: 0x%x\n", __func__, vfe_dev->pdev->id,
+		irq_status0);
+
+	/* Clear composite mask irq bits, they will be restored by comp mask */
+	for (j = 0; j < num_stats_comp_mask; j++) {
+		stats_irq_mask &= ~atomic_read(
+			&vfe_dev->stats_data.stats_comp_mask[j]);
+	}
+
+	/* Process non-composite irq */
+	if (stats_irq_mask) {
+		rc = msm_isp_stats_configure(vfe_dev, stats_irq_mask, ts,
+			comp_flag);
+	}
+
+	/* Process composite irq */
+	if (stats_comp_mask) {
+		for (j = 0; j < num_stats_comp_mask; j++) {
+			if (!(stats_comp_mask & (1 << j)))
+				continue;
+
+			atomic_stats_mask = atomic_read(
+				&vfe_dev->stats_data.stats_comp_mask[j]);
+
+			rc = msm_isp_stats_configure(vfe_dev, atomic_stats_mask,
+				ts, !comp_flag);
+		}
+	}
+}
+
+int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_request_cmd *stream_req_cmd,
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int rc = 0;
+	uint32_t stats_idx;
+	uint32_t framedrop_pattern;
+	uint32_t framedrop_period;
+	int i;
+
+	stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
+		get_stats_idx(stream_req_cmd->stats_type);
+
+	if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask &
+		(1 << stream_req_cmd->stats_type))) {
+		pr_err("%s: Stats type not supported\n", __func__);
+		return rc;
+	}
+
+	if (stream_info->state != STATS_AVAILABLE) {
+		pr_err("%s: Stats already requested\n", __func__);
+		return rc;
+	}
+
+	if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) {
+		pr_err("%s: Invalid framedrop pattern\n", __func__);
+		return rc;
+	}
+
+	if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) {
+		pr_err("%s: Invalid irq subsample pattern\n", __func__);
+		return rc;
+	}
+
+	if (stream_req_cmd->composite_flag >
+		vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask) {
+		pr_err("%s: comp grp %d exceed max %d\n",
+			__func__, stream_req_cmd->composite_flag,
+			vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask);
+		return -EINVAL;
+	}
+
+	if (stream_info->num_isp == 0) {
+		stream_info->session_id = stream_req_cmd->session_id;
+		stream_info->stream_id = stream_req_cmd->stream_id;
+		stream_info->composite_flag = stream_req_cmd->composite_flag;
+		stream_info->stats_type = stream_req_cmd->stats_type;
+		framedrop_pattern = stream_req_cmd->framedrop_pattern;
+		if (framedrop_pattern == SKIP_ALL)
+			framedrop_pattern = 0;
+		else
+			framedrop_pattern = 1;
+		stream_info->framedrop_pattern = framedrop_pattern;
+		stream_info->init_stats_frame_drop =
+			stream_req_cmd->init_frame_drop;
+		stream_info->irq_subsample_pattern =
+			stream_req_cmd->irq_subsample_pattern;
+		framedrop_period = msm_isp_get_framedrop_period(
+			stream_req_cmd->framedrop_pattern);
+		stream_info->framedrop_period = framedrop_period;
+	} else {
+		if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) {
+			pr_err("%s: stats %d already requested for vfe %d\n",
+				__func__, stats_idx, vfe_dev->pdev->id);
+			return -EINVAL;
+		}
+		if (stream_info->session_id != stream_req_cmd->session_id)
+			rc = -EINVAL;
+		if (stream_info->session_id != stream_req_cmd->session_id)
+			rc = -EINVAL;
+		if (stream_info->composite_flag !=
+			stream_req_cmd->composite_flag)
+			rc = -EINVAL;
+		if (stream_info->stats_type != stream_req_cmd->stats_type)
+			rc = -EINVAL;
+		framedrop_pattern = stream_req_cmd->framedrop_pattern;
+		if (framedrop_pattern == SKIP_ALL)
+			framedrop_pattern = 0;
+		else
+			framedrop_pattern = 1;
+		if (stream_info->framedrop_pattern != framedrop_pattern)
+			rc = -EINVAL;
+		framedrop_period = msm_isp_get_framedrop_period(
+			stream_req_cmd->framedrop_pattern);
+		if (stream_info->framedrop_period != framedrop_period)
+			rc = -EINVAL;
+		if (rc) {
+			pr_err("%s: Stats stream param mismatch between vfe\n",
+				__func__);
+			return rc;
+		}
+	}
+	stream_info->buffer_offset[stream_info->num_isp] =
+					stream_req_cmd->buffer_offset;
+	stream_info->vfe_dev[stream_info->num_isp] = vfe_dev;
+	stream_info->vfe_mask |= (1 << vfe_dev->pdev->id);
+	stream_info->num_isp++;
+	if (!vfe_dev->is_split || stream_info->num_isp == MAX_VFE) {
+		stream_info->state = STATS_INACTIVE;
+		for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++)
+			stream_info->composite_irq[i] = 0;
+	}
+
+	if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0)
+		vfe_dev->stats_data.stream_handle_cnt++;
+
+	stream_req_cmd->stream_handle =
+		(++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx;
+
+	stream_info->stream_handle[stream_info->num_isp - 1] =
+				stream_req_cmd->stream_handle;
+	return 0;
+}
+
+int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = -1;
+	struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	uint32_t stats_idx;
+
+	stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
+		get_stats_idx(stream_req_cmd->stats_type);
+
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
+	}
+
+	stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx);
+
+	rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd, stream_info);
+	if (rc < 0) {
+		pr_err("%s: create stream failed\n", __func__);
+		return rc;
+	}
+
+	if (stream_info->init_stats_frame_drop == 0)
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev,
+			stream_info);
+
+	if (stream_info->state == STATS_INACTIVE) {
+		msm_isp_stats_cfg_stream_scratch(stream_info,
+					VFE_PING_FLAG);
+		msm_isp_stats_cfg_stream_scratch(stream_info,
+					VFE_PONG_FLAG);
+	}
+	return rc;
+}
+
+int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = -1;
+	struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd;
+	struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
+	int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	int vfe_idx;
+	int i;
+	int k;
+
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
+	}
+
+	stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx);
+	vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(
+					vfe_dev, stream_info);
+	if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] !=
+			stream_release_cmd->stream_handle) {
+		pr_err("%s: Invalid stream handle %x, expected %x\n",
+			__func__, stream_release_cmd->stream_handle,
+			vfe_idx != -ENOTTY ?
+			stream_info->stream_handle[vfe_idx] : 0);
+		return -EINVAL;
+	}
+	if (stream_info->state == STATS_AVAILABLE) {
+		pr_err("%s: stream already release\n", __func__);
+		return rc;
+	}
+	vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info);
+
+	if (stream_info->state != STATS_INACTIVE) {
+		stream_cfg_cmd.enable = 0;
+		stream_cfg_cmd.num_streams = 1;
+		stream_cfg_cmd.stream_handle[0] =
+			stream_release_cmd->stream_handle;
+		msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
+	}
+
+	for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) {
+		stream_info->vfe_dev[i] = stream_info->vfe_dev[k];
+		stream_info->stream_handle[i] = stream_info->stream_handle[k];
+		stream_info->buffer_offset[i] = stream_info->buffer_offset[k];
+	}
+
+	stream_info->vfe_dev[stream_info->num_isp] = NULL;
+	stream_info->stream_handle[stream_info->num_isp] = 0;
+	stream_info->buffer_offset[stream_info->num_isp] = 0;
+	stream_info->num_isp--;
+	stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id);
+	if (stream_info->num_isp == 0)
+		stream_info->state = STATS_AVAILABLE;
+
+	return 0;
+}
+
+void msm_isp_stop_all_stats_stream(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd;
+	struct msm_vfe_stats_stream *stream_info;
+	int i;
+	int vfe_idx;
+	unsigned long flags;
+
+	stream_cfg_cmd.enable = 0;
+	stream_cfg_cmd.num_streams = 0;
+
+	for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		stream_info =  msm_isp_get_stats_stream_common_data(vfe_dev, i);
+		spin_lock_irqsave(&stream_info->lock, flags);
+		if (stream_info->state == STATS_AVAILABLE ||
+			stream_info->state == STATS_INACTIVE) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev,
+							stream_info);
+		if (vfe_idx == -ENOTTY) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		stream_cfg_cmd.stream_handle[
+			stream_cfg_cmd.num_streams] =
+			stream_info->stream_handle[vfe_idx];
+		stream_cfg_cmd.num_streams++;
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+	if (stream_cfg_cmd.num_streams)
+		msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
+}
+
+void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_stats_stream_release_cmd
+				stream_release_cmd[MSM_ISP_STATS_MAX];
+	struct msm_vfe_stats_stream *stream_info;
+	int i;
+	int vfe_idx;
+	int num_stream = 0;
+	unsigned long flags;
+
+	msm_isp_stop_all_stats_stream(vfe_dev);
+
+	for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		stream_info =  msm_isp_get_stats_stream_common_data(vfe_dev, i);
+		spin_lock_irqsave(&stream_info->lock, flags);
+		if (stream_info->state == STATS_AVAILABLE) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev,
+							stream_info);
+		if (vfe_idx == -ENOTTY) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			continue;
+		}
+		stream_release_cmd[num_stream++].stream_handle =
+				stream_info->stream_handle[vfe_idx];
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	for (i = 0; i < num_stream; i++)
+		msm_isp_release_stats_stream(vfe_dev, &stream_release_cmd[i]);
+}
+
+static int msm_isp_init_stats_ping_pong_reg(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int rc = 0;
+
+	stream_info->bufq_handle =
+		stream_info->vfe_dev[0]->buf_mgr->ops->get_bufq_handle(
+		stream_info->vfe_dev[0]->buf_mgr, stream_info->session_id,
+		stream_info->stream_id);
+	if (stream_info->bufq_handle == 0) {
+		pr_err("%s: no buf configured for stream: 0x%x\n",
+			__func__, stream_info->stream_handle[0]);
+		return -EINVAL;
+	}
+
+	rc = msm_isp_stats_cfg_ping_pong_address(
+		stream_info, VFE_PING_FLAG);
+	if (rc < 0) {
+		pr_err("%s: No free buffer for ping\n", __func__);
+		return rc;
+	}
+	rc = msm_isp_stats_cfg_ping_pong_address(
+		stream_info, VFE_PONG_FLAG);
+	if (rc < 0) {
+		pr_err("%s: No free buffer for pong\n", __func__);
+		return rc;
+	}
+	return rc;
+}
+
+static void __msm_isp_update_stats_framedrop_reg(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	int k;
+	struct vfe_device *vfe_dev;
+
+	if (!stream_info->init_stats_frame_drop)
+		return;
+	stream_info->init_stats_frame_drop--;
+	if (stream_info->init_stats_frame_drop)
+		return;
+
+	for (k = 0; k < stream_info->num_isp; k++) {
+		vfe_dev = stream_info->vfe_dev[k];
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev,
+						stream_info);
+
+	}
+}
+
+static void __msm_isp_stats_stream_update(
+	struct msm_vfe_stats_stream *stream_info)
+{
+	uint32_t enable = 0;
+	uint8_t comp_flag = 0;
+	int k;
+	struct vfe_device *vfe_dev;
+	int index = STATS_IDX(stream_info->stream_handle[0]);
+
+	switch (stream_info->state) {
+	case STATS_INACTIVE:
+	case STATS_ACTIVE:
+	case STATS_AVAILABLE:
+		break;
+	case STATS_START_PENDING:
+		enable = 1;
+	case STATS_STOP_PENDING:
+		stream_info->state =
+			(stream_info->state == STATS_START_PENDING ?
+			STATS_STARTING : STATS_STOPPING);
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
+				vfe_dev, BIT(index), enable);
+			comp_flag = stream_info->composite_flag;
+			if (comp_flag) {
+				vfe_dev->hw_info->vfe_ops.stats_ops.
+					cfg_comp_mask(vfe_dev, BIT(index),
+					(comp_flag - 1), enable);
+			} else {
+				if (enable)
+					vfe_dev->hw_info->vfe_ops.stats_ops.
+						cfg_wm_irq_mask(vfe_dev,
+								stream_info);
+				else
+					vfe_dev->hw_info->vfe_ops.stats_ops.
+						clear_wm_irq_mask(vfe_dev,
+								stream_info);
+			}
+		}
+		break;
+	case STATS_STARTING:
+		stream_info->state = STATS_ACTIVE;
+		complete_all(&stream_info->active_comp);
+		break;
+	case STATS_STOPPING:
+		stream_info->state = STATS_INACTIVE;
+		complete_all(&stream_info->inactive_comp);
+		break;
+	}
+}
+
+
+void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
+{
+	int i;
+	struct msm_vfe_stats_stream *stream_info;
+	unsigned long flags;
+
+	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
+		stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i);
+		if (stream_info->state == STATS_AVAILABLE ||
+			stream_info->state == STATS_INACTIVE)
+			continue;
+		spin_lock_irqsave(&stream_info->lock, flags);
+		__msm_isp_stats_stream_update(stream_info);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+}
+
+void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev,
+			enum msm_isp_comp_irq_types irq)
+{
+	int i;
+	struct msm_vfe_stats_stream *stream_info;
+	unsigned long flags;
+	int rc;
+
+	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
+		stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i);
+		if (stream_info->state == STATS_AVAILABLE ||
+			stream_info->state == STATS_INACTIVE)
+			continue;
+
+		spin_lock_irqsave(&stream_info->lock, flags);
+
+		rc = msm_isp_composite_stats_irq(vfe_dev, stream_info, irq);
+
+		if (rc) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			if (-EFAULT == rc) {
+				msm_isp_halt_send_error(vfe_dev,
+						ISP_EVENT_PING_PONG_MISMATCH);
+				return;
+			}
+			continue;
+		}
+
+		if (irq == MSM_ISP_COMP_IRQ_REG_UPD)
+			__msm_isp_stats_stream_update(stream_info);
+		else if (irq == MSM_ISP_COMP_IRQ_EPOCH &&
+			stream_info->state == STATS_ACTIVE)
+			__msm_isp_update_stats_framedrop_reg(stream_info);
+
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+}
+
+static int msm_isp_stats_wait_for_stream_cfg_done(
+		struct msm_vfe_stats_stream *stream_info,
+		int active)
+{
+	int rc = -1;
+
+	if (active && stream_info->state == STATS_ACTIVE)
+		rc = 0;
+	if (!active && stream_info->state == STATS_INACTIVE)
+		rc = 0;
+	if (rc == 0)
+		return rc;
+
+	rc = wait_for_completion_timeout(active ? &stream_info->active_comp :
+		&stream_info->inactive_comp,
+		msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
+	if (rc <= 0) {
+		rc = rc ? rc : -ETIMEDOUT;
+		pr_err("%s: wait for stats stream %x idx %d state %d active %d config failed %d\n",
+			__func__, stream_info->stream_id,
+			STATS_IDX(stream_info->stream_handle[0]),
+			stream_info->state, active, rc);
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+static int msm_isp_stats_wait_for_streams(
+		struct msm_vfe_stats_stream **streams,
+		int num_stream, int active)
+{
+	int rc = 0;
+	int i;
+	struct msm_vfe_stats_stream *stream_info;
+
+	for (i = 0; i < num_stream; i++) {
+		stream_info = streams[i];
+		rc |= msm_isp_stats_wait_for_stream_cfg_done(stream_info,
+								active);
+	}
+	return rc;
+}
+
+static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i;
+	uint32_t stats_mask = 0, idx;
+	struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL};
+	struct msm_vfe_stats_stream *stream_info;
+	int k;
+
+	if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
+		pr_err("%s invalid num_streams %d\n", __func__,
+			stream_cfg_cmd->num_streams);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+		stream_info =  msm_isp_get_stats_stream_common_data(vfe_dev,
+					idx);
+		if (stream_info->state == STATS_AVAILABLE)
+			continue;
+
+		/*
+		 * we update cgc after making streams inactive or before
+		 * starting streams, so stream should be in inactive state
+		 */
+		if (stream_info->state == STATS_INACTIVE)
+			stats_mask |= 1 << idx;
+		for (k = 0; k < stream_info->num_isp; k++) {
+			if (update_vfes[stream_info->vfe_dev[k]->pdev->id])
+				continue;
+			update_vfes[stream_info->vfe_dev[k]->pdev->id] =
+				stream_info->vfe_dev[k];
+		}
+	}
+
+	for (k = 0; k < MAX_VFE; k++) {
+		if (!update_vfes[k])
+			continue;
+		vfe_dev = update_vfes[k];
+		if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) {
+			vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override(
+				vfe_dev, stats_mask, stream_cfg_cmd->enable);
+		}
+	}
+	return 0;
+}
+
+int msm_isp_stats_reset(struct vfe_device *vfe_dev)
+{
+	int i = 0, rc = 0;
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	struct msm_isp_timestamp timestamp;
+	unsigned long flags;
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev);
+
+	for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		stream_info = msm_isp_get_stats_stream_common_data(
+				vfe_dev, i);
+		if (stream_info->state == STATS_AVAILABLE ||
+			stream_info->state == STATS_INACTIVE)
+			continue;
+
+		if (stream_info->num_isp > 1 &&
+			vfe_dev->pdev->id == ISP_VFE0)
+			continue;
+		spin_lock_irqsave(&stream_info->lock, flags);
+		msm_isp_stats_cfg_stream_scratch(stream_info,
+						VFE_PING_FLAG);
+		msm_isp_stats_cfg_stream_scratch(stream_info,
+						VFE_PONG_FLAG);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
+			stream_info->bufq_handle,
+			MSM_ISP_BUFFER_FLUSH_ALL, &timestamp.buf_time,
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+		if (rc == -EFAULT) {
+			msm_isp_halt_send_error(vfe_dev,
+				ISP_EVENT_BUF_FATAL_ERROR);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+int msm_isp_stats_restart(struct vfe_device *vfe_dev)
+{
+	int i = 0;
+	struct msm_vfe_stats_stream *stream_info = NULL;
+	unsigned long flags;
+	int j;
+
+	for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		stream_info = msm_isp_get_stats_stream_common_data(
+				vfe_dev, i);
+		if (stream_info->state == STATS_AVAILABLE ||
+			stream_info->state == STATS_INACTIVE)
+			continue;
+		if (stream_info->num_isp > 1 &&
+			vfe_dev->pdev->id == ISP_VFE0)
+			continue;
+		spin_lock_irqsave(&stream_info->lock, flags);
+		for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++)
+			stream_info->composite_irq[j] = 0;
+		msm_isp_init_stats_ping_pong_reg(
+				stream_info);
+		for (j = 0; j < stream_info->num_isp; j++) {
+			struct vfe_device *temp_vfe_dev =
+					stream_info->vfe_dev[j];
+			uint8_t comp_flag = stream_info->composite_flag;
+
+			temp_vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
+				temp_vfe_dev, BIT(i), 1);
+			if (comp_flag)
+				temp_vfe_dev->hw_info->vfe_ops.stats_ops.
+					cfg_comp_mask(temp_vfe_dev, BIT(i),
+					(comp_flag - 1), 1);
+			else
+				temp_vfe_dev->hw_info->vfe_ops.stats_ops.
+					cfg_wm_irq_mask(
+						temp_vfe_dev, stream_info);
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	return 0;
+}
+
+static int msm_isp_check_stream_cfg_cmd(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i;
+	struct msm_vfe_stats_stream *stream_info;
+	uint32_t idx;
+	int vfe_idx;
+	uint32_t stats_idx[MSM_ISP_STATS_MAX];
+
+	if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
+		pr_err("%s invalid num_streams %d\n", __func__,
+			stream_cfg_cmd->num_streams);
+		return -EINVAL;
+	}
+	memset(stats_idx, 0, sizeof(stats_idx));
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+		stream_info = msm_isp_get_stats_stream_common_data(
+				vfe_dev, idx);
+		vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev,
+							stream_info);
+		if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] !=
+			stream_cfg_cmd->stream_handle[i]) {
+			pr_err("%s: Invalid stream handle: 0x%x received expected %x\n",
+				__func__, stream_cfg_cmd->stream_handle[i],
+				vfe_idx == -ENOTTY ? 0 :
+				stream_info->stream_handle[vfe_idx]);
+			return -EINVAL;
+		}
+		/* remove duplicate handles */
+		if (stats_idx[idx] == stream_cfg_cmd->stream_handle[i])
+			stream_cfg_cmd->stream_handle[i] = 0;
+		else
+			stats_idx[idx] = stream_cfg_cmd->stream_handle[i];
+	}
+	return 0;
+}
+
+static void __msm_isp_stop_stats_streams(
+		struct msm_vfe_stats_stream **streams,
+		int num_streams,
+		struct msm_isp_timestamp timestamp)
+{
+	int i;
+	int k;
+	struct msm_vfe_stats_stream *stream_info;
+	struct vfe_device *vfe_dev;
+	struct msm_vfe_stats_shared_data *stats_data;
+	unsigned long flags;
+
+	for (i = 0; i < num_streams; i++) {
+		stream_info = streams[i];
+		spin_lock_irqsave(&stream_info->lock, flags);
+		init_completion(&stream_info->inactive_comp);
+		stream_info->state = STATS_STOP_PENDING;
+		if (stream_info->vfe_dev[0]->
+			axi_data.src_info[VFE_PIX_0].active == 0) {
+			while (stream_info->state != STATS_INACTIVE)
+				__msm_isp_stats_stream_update(stream_info);
+		}
+		for (k = 0; k < stream_info->num_isp; k++) {
+			stats_data = &stream_info->vfe_dev[k]->stats_data;
+			stats_data->num_active_stream--;
+		}
+
+		msm_isp_stats_cfg_stream_scratch(
+			stream_info, VFE_PING_FLAG);
+		msm_isp_stats_cfg_stream_scratch(
+			stream_info, VFE_PONG_FLAG);
+		vfe_dev = stream_info->vfe_dev[0];
+		if (vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
+			stream_info->bufq_handle,
+			MSM_ISP_BUFFER_FLUSH_ALL, &timestamp.buf_time,
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id ==
+			-EFAULT))
+			msm_isp_halt_send_error(vfe_dev,
+				ISP_EVENT_BUF_FATAL_ERROR);
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+	}
+
+	if (msm_isp_stats_wait_for_streams(streams, num_streams, 0)) {
+		for (i = 0; i < num_streams; i++) {
+			stream_info = streams[i];
+			if (stream_info->state == STATS_INACTIVE)
+				continue;
+			spin_lock_irqsave(&stream_info->lock, flags);
+			while (stream_info->state != STATS_INACTIVE)
+				__msm_isp_stats_stream_update(stream_info);
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+		}
+	}
+}
+
+static int msm_isp_check_stats_stream_state(
+			struct msm_vfe_stats_stream *stream_info,
+			int cmd)
+{
+	switch (stream_info->state) {
+	case STATS_AVAILABLE:
+		return -EINVAL;
+	case STATS_INACTIVE:
+		if (cmd == 0)
+			return -EALREADY;
+		break;
+	case STATS_ACTIVE:
+		if (cmd)
+			return -EALREADY;
+		break;
+	default:
+		WARN(1, "Invalid stats state %d\n", stream_info->state);
+	}
+	return 0;
+}
+
+static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i, rc = 0;
+	uint32_t stats_mask = 0, idx;
+	uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0};
+	uint32_t num_stats_comp_mask = 0;
+	struct msm_vfe_stats_stream *stream_info;
+	struct msm_vfe_stats_shared_data *stats_data = NULL;
+	int num_stream = 0;
+	struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX];
+	struct msm_isp_timestamp timestamp;
+	unsigned long flags;
+	int k;
+	struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL};
+	uint32_t num_active_streams[MAX_VFE] = {0, 0};
+	struct vfe_device *vfe_dev;
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev_ioctl);
+
+	num_stats_comp_mask =
+		vfe_dev_ioctl->hw_info->stats_hw_info->num_stats_comp_mask;
+	if (stream_cfg_cmd->num_streams >= MSM_ISP_STATS_MAX)
+		stream_cfg_cmd->num_streams = MSM_ISP_STATS_MAX;
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (stream_cfg_cmd->stream_handle[i] == 0)
+			continue;
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+		stream_info = msm_isp_get_stats_stream_common_data(
+						vfe_dev_ioctl, idx);
+		spin_lock_irqsave(&stream_info->lock, flags);
+		rc = msm_isp_check_stats_stream_state(stream_info, 1);
+		if (rc == -EALREADY) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			rc = 0;
+			continue;
+		}
+		if (rc) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			goto error;
+		}
+		rc = msm_isp_init_stats_ping_pong_reg(
+							stream_info);
+		if (rc < 0) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			pr_err("%s: No buffer for stream%d\n", __func__, idx);
+			return rc;
+		}
+		init_completion(&stream_info->active_comp);
+		stream_info->state = STATS_START_PENDING;
+		if (vfe_dev_ioctl->axi_data.src_info[VFE_PIX_0].active == 0) {
+			while (stream_info->state != STATS_ACTIVE)
+				__msm_isp_stats_stream_update(stream_info);
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+
+		stats_mask |= 1 << idx;
+		for (k = 0; k < stream_info->num_isp; k++) {
+			vfe_dev = stream_info->vfe_dev[k];
+			stats_data = &vfe_dev->stats_data;
+			if (update_vfes[vfe_dev->pdev->id] == NULL) {
+				update_vfes[vfe_dev->pdev->id] = vfe_dev;
+				num_active_streams[vfe_dev->pdev->id] =
+					stats_data->num_active_stream;
+			}
+			stats_data->num_active_stream++;
+		}
+
+		if (stream_info->composite_flag)
+			comp_stats_mask[stream_info->composite_flag-1] |=
+				1 << idx;
+
+		ISP_DBG("%s: stats_mask %x %x\n",
+			__func__, comp_stats_mask[0],
+			comp_stats_mask[1]);
+		if (stats_data)
+			ISP_DBG("%s: active_streams = %d\n", __func__,
+				stats_data->num_active_stream);
+		streams[num_stream++] = stream_info;
+	}
+
+	for (k = 0; k < MAX_VFE; k++) {
+		if (!update_vfes[k] || num_active_streams[k])
+			continue;
+		vfe_dev = update_vfes[k];
+		vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
+	}
+
+	rc = msm_isp_stats_wait_for_streams(streams, num_stream, 1);
+	if (rc)
+		goto error;
+	return 0;
+error:
+	__msm_isp_stop_stats_streams(streams, num_stream, timestamp);
+	return rc;
+}
+
+static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i, rc = 0;
+	uint32_t idx;
+	uint32_t num_stats_comp_mask = 0;
+	struct msm_vfe_stats_stream *stream_info;
+	struct msm_isp_timestamp timestamp;
+	int num_stream = 0;
+	struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX];
+	unsigned long flags;
+
+	msm_isp_get_timestamp(&timestamp, vfe_dev);
+
+	num_stats_comp_mask =
+		vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (stream_cfg_cmd->stream_handle[i] == 0)
+			continue;
+		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		stream_info = msm_isp_get_stats_stream_common_data(
+					vfe_dev, idx);
+		spin_lock_irqsave(&stream_info->lock, flags);
+		rc = msm_isp_check_stats_stream_state(stream_info, 0);
+		if (rc) {
+			spin_unlock_irqrestore(&stream_info->lock, flags);
+			rc = 0;
+			continue;
+		}
+		spin_unlock_irqrestore(&stream_info->lock, flags);
+		streams[num_stream++] = stream_info;
+	}
+
+	__msm_isp_stop_stats_streams(streams, num_stream, timestamp);
+
+	return rc;
+}
+
+int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0;
+	struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+
+	rc = msm_isp_check_stream_cfg_cmd(vfe_dev, stream_cfg_cmd);
+	if (rc)
+		return rc;
+
+	if (stream_cfg_cmd->enable) {
+		msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
+
+		rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd);
+	} else {
+		rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd);
+
+		msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
+	}
+
+	return rc;
+}
+
+int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i;
+	struct msm_vfe_stats_stream *stream_info;
+	struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
+	struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL;
+	struct msm_isp_sw_framskip *sw_skip_info = NULL;
+	int vfe_idx;
+	int k;
+
+	if (update_cmd->num_streams > MSM_ISP_STATS_MAX) {
+		pr_err("%s: Invalid num_streams %d\n",
+			__func__, update_cmd->num_streams);
+		return -EINVAL;
+	}
+
+	/*validate request*/
+	for (i = 0; i < update_cmd->num_streams; i++) {
+		update_info = (struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+		/*check array reference bounds*/
+		if (STATS_IDX(update_info->stream_handle)
+			>= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s: stats idx %d out of bound!", __func__,
+			STATS_IDX(update_info->stream_handle));
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < update_cmd->num_streams; i++) {
+		update_info = (struct msm_vfe_axi_stream_cfg_update_info *)
+				&update_cmd->update_info[i];
+		stream_info = msm_isp_get_stats_stream_common_data(vfe_dev,
+					STATS_IDX(update_info->stream_handle));
+		vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev,
+						stream_info);
+		if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] !=
+			update_info->stream_handle) {
+			pr_err("%s: stats stream handle %x %x mismatch!\n",
+				__func__, vfe_idx != -ENOTTY ?
+				stream_info->stream_handle[vfe_idx] : 0,
+				update_info->stream_handle);
+			continue;
+		}
+
+		switch (update_cmd->update_type) {
+		case UPDATE_STREAM_STATS_FRAMEDROP_PATTERN: {
+			uint32_t framedrop_period =
+				msm_isp_get_framedrop_period(
+				   update_info->skip_pattern);
+			if (update_info->skip_pattern ==
+				SKIP_ALL)
+				stream_info->framedrop_pattern = 0x0;
+			else
+				stream_info->framedrop_pattern = 0x1;
+			stream_info->framedrop_period = framedrop_period;
+			if (stream_info->init_stats_frame_drop == 0)
+				for (k = 0; k < stream_info->num_isp; k++)
+					stream_info->vfe_dev[k]->hw_info->
+					vfe_ops.stats_ops.cfg_wm_reg(
+						vfe_dev, stream_info);
+			break;
+		}
+		case UPDATE_STREAM_SW_FRAME_DROP: {
+			sw_skip_info =
+			&update_info->sw_skip_info;
+			if (!stream_info->sw_skip.stream_src_mask)
+				stream_info->sw_skip = *sw_skip_info;
+
+			if (sw_skip_info->stats_type_mask != 0) {
+				/* No image buffer skip, only stats skip */
+				pr_debug("%s:%x skip type %x mode %d min %d max %d\n",
+					__func__, stream_info->stream_id,
+					sw_skip_info->stats_type_mask,
+					sw_skip_info->skip_mode,
+					sw_skip_info->min_frame_id,
+					sw_skip_info->max_frame_id);
+				stream_info->sw_skip.stats_type_mask =
+					sw_skip_info->stats_type_mask;
+			}
+			break;
+		}
+
+		default:
+			pr_err("%s: Invalid update type\n", __func__);
+			return -EINVAL;
+		}
+	}
+	return rc;
+}
+
+void msm_isp_stats_disable(struct vfe_device *vfe_dev)
+{
+	int i;
+	unsigned int mask = 0;
+
+	if (!vfe_dev) {
+		pr_err("%s:  error NULL ptr\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++)
+		mask |= 1 << i;
+
+	vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(vfe_dev, mask, 0);
+}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
new file mode 100644
index 0000000..9d5ae8c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_ISP_STATS_UTIL_H__
+#define __MSM_ISP_STATS_UTIL_H__
+
+#include "msm_isp.h"
+#define STATS_IDX(idx) (idx & 0xFF)
+
+void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp *ts);
+int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
+	struct msm_vfe_stats_stream_request_cmd *stream_req_cmd,
+	struct msm_vfe_stats_stream *stream_info);
+void msm_isp_stats_stream_update(struct vfe_device *vfe_dev);
+int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
+void msm_isp_stats_disable(struct vfe_device *vfe_dev);
+int msm_isp_stats_reset(struct vfe_device *vfe_dev);
+int msm_isp_stats_restart(struct vfe_device *vfe_dev);
+void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev);
+void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev,
+		enum msm_isp_comp_irq_types irq);
+void msm_isp_stop_all_stats_stream(struct vfe_device *vfe_dev);
+
+static inline int msm_isp_get_vfe_idx_for_stats_stream_user(
+				struct vfe_device *vfe_dev,
+				struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx;
+
+	for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++)
+		if (stream_info->vfe_dev[vfe_idx] == vfe_dev)
+			return vfe_idx;
+	return -ENOTTY;
+}
+
+static inline int msm_isp_get_vfe_idx_for_stats_stream(
+				struct vfe_device *vfe_dev,
+				struct msm_vfe_stats_stream *stream_info)
+{
+	int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev,
+							stream_info);
+
+	if (vfe_idx < 0) {
+		WARN(1, "%s vfe index missing for stream %d vfe %d\n",
+			__func__, stream_info->stats_type, vfe_dev->pdev->id);
+		vfe_idx = 0;
+	}
+	return vfe_idx;
+}
+
+static inline struct msm_vfe_stats_stream *
+				msm_isp_get_stats_stream_common_data(
+				struct vfe_device *vfe_dev,
+				enum msm_isp_stats_type idx)
+{
+	if (vfe_dev->is_split)
+		return &vfe_dev->common_data->stats_streams[idx];
+	else
+		return &vfe_dev->common_data->stats_streams[idx +
+					MSM_ISP_STATS_MAX * vfe_dev->pdev->id];
+}
+
+static inline struct msm_vfe_stats_stream *
+	msm_isp_get_stats_stream(struct dual_vfe_resource *dual_vfe_res,
+					int vfe_id,
+					enum msm_isp_stats_type idx)
+{
+	return msm_isp_get_stats_stream_common_data(
+				dual_vfe_res->vfe_dev[vfe_id], idx);
+}
+#endif /* __MSM_ISP_STATS_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
new file mode 100644
index 0000000..290bdc0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -0,0 +1,2501 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+#include <linux/ratelimit.h>
+
+#include "msm.h"
+#include "msm_isp_util.h"
+#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
+#include "msm_camera_io_util.h"
+#include "cam_smmu_api.h"
+#include "msm_isp48.h"
+#define CREATE_TRACE_POINTS
+#include "trace/events/msm_cam.h"
+
+
+#define MAX_ISP_V4l2_EVENTS 100
+#define MAX_ISP_REG_LIST 100
+static DEFINE_MUTEX(bandwidth_mgr_mutex);
+static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr;
+
+#define MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev) { \
+	if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \
+		struct vfe_device *vfe1_dev = vfe_dev->common_data-> \
+					dual_vfe_res->vfe_dev[ISP_VFE1]; \
+		mutex_lock(&vfe1_dev->core_mutex); \
+	} \
+}
+
+#define MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev) { \
+	if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \
+		struct vfe_device *vfe1_dev = vfe_dev->common_data-> \
+					dual_vfe_res->vfe_dev[ISP_VFE1]; \
+		mutex_unlock(&vfe1_dev->core_mutex); \
+	} \
+}
+
+static uint64_t msm_isp_cpp_clk_rate;
+
+#define VFE40_8974V2_VERSION 0x1001001A
+
+void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format)
+{
+	int i;
+	char text[5];
+
+	text[4] = '\0';
+	for (i = 0; i < 4; i++) {
+		text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+		if ((text[i] < '0') || (text[i] > 'z')) {
+			pr_err("%s: Invalid output format %d (unprintable)\n",
+				origin, fourcc_format);
+			return;
+		}
+	}
+	pr_err("%s: Invalid output format %s\n",
+		origin, text);
+}
+
+int msm_isp_init_bandwidth_mgr(struct vfe_device *vfe_dev,
+			enum msm_isp_hw_client client)
+{
+	int rc = 0;
+
+	mutex_lock(&bandwidth_mgr_mutex);
+	if (isp_bandwidth_mgr.client_info[client].active) {
+		mutex_unlock(&bandwidth_mgr_mutex);
+		return rc;
+	}
+	isp_bandwidth_mgr.client_info[client].active = 1;
+	isp_bandwidth_mgr.use_count++;
+	if (vfe_dev && !isp_bandwidth_mgr.bus_client) {
+		rc = vfe_dev->hw_info->vfe_ops.platform_ops.init_bw_mgr(vfe_dev,
+				&isp_bandwidth_mgr);
+		if (!rc) {
+			isp_bandwidth_mgr.update_bw =
+			vfe_dev->hw_info->vfe_ops.platform_ops.update_bw;
+			isp_bandwidth_mgr.deinit_bw_mgr =
+			vfe_dev->hw_info->vfe_ops.platform_ops.deinit_bw_mgr;
+		}
+	}
+	if (rc) {
+		isp_bandwidth_mgr.use_count--;
+		isp_bandwidth_mgr.client_info[client].active = 0;
+	}
+
+	mutex_unlock(&bandwidth_mgr_mutex);
+	return rc;
+}
+
+int msm_isp_update_bandwidth(enum msm_isp_hw_client client,
+	uint64_t ab, uint64_t ib)
+{
+	int rc;
+
+	mutex_lock(&bandwidth_mgr_mutex);
+	if (!isp_bandwidth_mgr.use_count ||
+		!isp_bandwidth_mgr.bus_client) {
+		pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n",
+			__func__, isp_bandwidth_mgr.use_count,
+			isp_bandwidth_mgr.bus_client);
+		mutex_unlock(&bandwidth_mgr_mutex);
+		return -EINVAL;
+	}
+
+	isp_bandwidth_mgr.client_info[client].ab = ab;
+	isp_bandwidth_mgr.client_info[client].ib = ib;
+	rc = isp_bandwidth_mgr.update_bw(&isp_bandwidth_mgr);
+	mutex_unlock(&bandwidth_mgr_mutex);
+	return 0;
+}
+
+void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client)
+{
+	if (client >= MAX_ISP_CLIENT) {
+		pr_err("invalid Client id %d", client);
+		return;
+	}
+	mutex_lock(&bandwidth_mgr_mutex);
+	memset(&isp_bandwidth_mgr.client_info[client], 0,
+			sizeof(struct msm_isp_bandwidth_info));
+	if (isp_bandwidth_mgr.use_count) {
+		isp_bandwidth_mgr.use_count--;
+		if (isp_bandwidth_mgr.use_count) {
+			mutex_unlock(&bandwidth_mgr_mutex);
+			return;
+		}
+
+		if (!isp_bandwidth_mgr.bus_client) {
+			pr_err("%s:%d error: bus client invalid\n",
+				__func__, __LINE__);
+			mutex_unlock(&bandwidth_mgr_mutex);
+			return;
+		}
+
+		isp_bandwidth_mgr.deinit_bw_mgr(
+				&isp_bandwidth_mgr);
+	}
+	mutex_unlock(&bandwidth_mgr_mutex);
+}
+
+void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev,
+				      struct msm_isp_statistics *stats)
+{
+	stats->isp_vfe0_active = isp_bandwidth_mgr.client_info[ISP_VFE0].active;
+	stats->isp_vfe0_ab = isp_bandwidth_mgr.client_info[ISP_VFE0].ab;
+	stats->isp_vfe0_ib = isp_bandwidth_mgr.client_info[ISP_VFE0].ib;
+
+	stats->isp_vfe1_active = isp_bandwidth_mgr.client_info[ISP_VFE1].active;
+	stats->isp_vfe1_ab = isp_bandwidth_mgr.client_info[ISP_VFE1].ab;
+	stats->isp_vfe1_ib = isp_bandwidth_mgr.client_info[ISP_VFE1].ib;
+
+	stats->isp_cpp_active = isp_bandwidth_mgr.client_info[ISP_CPP].active;
+	stats->isp_cpp_ab = isp_bandwidth_mgr.client_info[ISP_CPP].ab;
+	stats->isp_cpp_ib = isp_bandwidth_mgr.client_info[ISP_CPP].ib;
+	stats->last_overflow_ab = vfe_dev->msm_isp_last_overflow_ab;
+	stats->last_overflow_ib = vfe_dev->msm_isp_last_overflow_ib;
+	stats->vfe_clk_rate = vfe_dev->vfe_clk_info[
+				vfe_dev->hw_info->vfe_clk_idx].clk_rate;
+	stats->cpp_clk_rate = msm_isp_cpp_clk_rate;
+}
+
+void msm_isp_util_update_clk_rate(long clock_rate)
+{
+	msm_isp_cpp_clk_rate = clock_rate;
+}
+
+uint32_t msm_isp_get_framedrop_period(
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern)
+{
+	switch (frame_skip_pattern) {
+	case NO_SKIP:
+	case EVERY_2FRAME:
+	case EVERY_3FRAME:
+	case EVERY_4FRAME:
+	case EVERY_5FRAME:
+	case EVERY_6FRAME:
+	case EVERY_7FRAME:
+	case EVERY_8FRAME:
+		return frame_skip_pattern + 1;
+	case EVERY_16FRAME:
+		return 16;
+	case EVERY_32FRAME:
+		return 32;
+	case SKIP_ALL:
+		return SKIP_ALL;
+	default:
+		return 1;
+	}
+	return 1;
+}
+
+void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
+	struct vfe_device *vfe_dev)
+{
+	struct timespec ts;
+
+	do_gettimeofday(&(time_stamp->event_time));
+	if (vfe_dev->vt_enable) {
+		msm_isp_get_avtimer_ts(time_stamp);
+		time_stamp->buf_time.tv_sec    = time_stamp->vt_time.tv_sec;
+		time_stamp->buf_time.tv_usec   = time_stamp->vt_time.tv_usec;
+	} else {
+		get_monotonic_boottime(&ts);
+		time_stamp->buf_time.tv_sec    = ts.tv_sec;
+		time_stamp->buf_time.tv_usec   = ts.tv_nsec/1000;
+	}
+}
+
+static inline u32 msm_isp_evt_mask_to_isp_event(u32 evt_mask)
+{
+	u32 evt_id = ISP_EVENT_SUBS_MASK_NONE;
+
+	switch (evt_mask) {
+	case ISP_EVENT_MASK_INDEX_STATS_NOTIFY:
+		evt_id = ISP_EVENT_STATS_NOTIFY;
+		break;
+	case ISP_EVENT_MASK_INDEX_ERROR:
+		evt_id = ISP_EVENT_ERROR;
+		break;
+	case ISP_EVENT_MASK_INDEX_IOMMU_P_FAULT:
+		evt_id = ISP_EVENT_IOMMU_P_FAULT;
+		break;
+	case ISP_EVENT_MASK_INDEX_STREAM_UPDATE_DONE:
+		evt_id = ISP_EVENT_STREAM_UPDATE_DONE;
+		break;
+	case ISP_EVENT_MASK_INDEX_REG_UPDATE:
+		evt_id = ISP_EVENT_REG_UPDATE;
+		break;
+	case ISP_EVENT_MASK_INDEX_SOF:
+		evt_id = ISP_EVENT_SOF;
+		break;
+	case ISP_EVENT_MASK_INDEX_BUF_DIVERT:
+		evt_id = ISP_EVENT_BUF_DIVERT;
+		break;
+	case ISP_EVENT_MASK_INDEX_BUF_DONE:
+		evt_id = ISP_EVENT_BUF_DONE;
+		break;
+	case ISP_EVENT_MASK_INDEX_COMP_STATS_NOTIFY:
+		evt_id = ISP_EVENT_COMP_STATS_NOTIFY;
+		break;
+	case ISP_EVENT_MASK_INDEX_MASK_FE_READ_DONE:
+		evt_id = ISP_EVENT_FE_READ_DONE;
+		break;
+	case ISP_EVENT_MASK_INDEX_PING_PONG_MISMATCH:
+		evt_id = ISP_EVENT_PING_PONG_MISMATCH;
+		break;
+	case ISP_EVENT_MASK_INDEX_REG_UPDATE_MISSING:
+		evt_id = ISP_EVENT_REG_UPDATE_MISSING;
+		break;
+	case ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR:
+		evt_id = ISP_EVENT_BUF_FATAL_ERROR;
+		break;
+	default:
+		evt_id = ISP_EVENT_SUBS_MASK_NONE;
+		break;
+	}
+
+	return evt_id;
+}
+
+static inline int msm_isp_subscribe_event_mask(struct v4l2_fh *fh,
+		struct v4l2_event_subscription *sub, int evt_mask_index,
+		u32 evt_id, bool subscribe_flag)
+{
+	int rc = 0, i, interface;
+
+	if (evt_mask_index == ISP_EVENT_MASK_INDEX_STATS_NOTIFY) {
+		for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+			sub->type = evt_id + i;
+			if (subscribe_flag)
+				rc = v4l2_event_subscribe(fh, sub,
+					MAX_ISP_V4l2_EVENTS, NULL);
+			else
+				rc = v4l2_event_unsubscribe(fh, sub);
+			if (rc != 0) {
+				pr_err("%s: Subs event_type =0x%x failed\n",
+					__func__, sub->type);
+				return rc;
+			}
+		}
+	} else if (evt_mask_index == ISP_EVENT_MASK_INDEX_SOF ||
+		   evt_mask_index == ISP_EVENT_MASK_INDEX_REG_UPDATE ||
+		   evt_mask_index == ISP_EVENT_MASK_INDEX_STREAM_UPDATE_DONE) {
+		for (interface = 0; interface < VFE_SRC_MAX; interface++) {
+			sub->type = evt_id | interface;
+			if (subscribe_flag)
+				rc = v4l2_event_subscribe(fh, sub,
+					MAX_ISP_V4l2_EVENTS, NULL);
+			else
+				rc = v4l2_event_unsubscribe(fh, sub);
+			if (rc != 0) {
+				pr_err("%s: Subs event_type =0x%x failed\n",
+					__func__, sub->type);
+				return rc;
+			}
+		}
+	} else {
+		sub->type = evt_id;
+		if (subscribe_flag)
+			rc = v4l2_event_subscribe(fh, sub,
+				MAX_ISP_V4l2_EVENTS, NULL);
+		else
+			rc = v4l2_event_unsubscribe(fh, sub);
+		if (rc != 0) {
+			pr_err("%s: Subs event_type =0x%x failed\n",
+				__func__, sub->type);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static inline int msm_isp_process_event_subscription(struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub, bool subscribe_flag)
+{
+	int rc = 0, evt_mask_index = 0;
+	u32 evt_mask = sub->type;
+	u32 evt_id = 0;
+
+	if (evt_mask == ISP_EVENT_SUBS_MASK_NONE) {
+		pr_err("%s: Subs event_type is None=0x%x\n",
+			__func__, evt_mask);
+		return 0;
+	}
+
+	for (evt_mask_index = ISP_EVENT_MASK_INDEX_STATS_NOTIFY;
+		evt_mask_index <= ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR;
+		evt_mask_index++) {
+		if (evt_mask & (1<<evt_mask_index)) {
+			evt_id = msm_isp_evt_mask_to_isp_event(evt_mask_index);
+			rc = msm_isp_subscribe_event_mask(fh, sub,
+				evt_mask_index, evt_id, subscribe_flag);
+			if (rc != 0) {
+				pr_err("%s: Subs event index:%d failed\n",
+					__func__, evt_mask_index);
+				return rc;
+			}
+		}
+	}
+	return rc;
+}
+
+int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	return msm_isp_process_event_subscription(fh, sub, true);
+}
+
+int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	return msm_isp_process_event_subscription(fh, sub, false);
+}
+
+static int msm_isp_start_fetch_engine(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	struct msm_vfe_fetch_eng_start *fe_cfg = arg;
+	/*
+	 * For Offline VFE, HAL expects same frame id
+	 * for offline output which it requested in do_reprocess.
+	 */
+	vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id =
+		fe_cfg->frame_id;
+	return vfe_dev->hw_info->vfe_ops.core_ops.
+		start_fetch_eng(vfe_dev, arg);
+}
+
+static int msm_isp_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+	void *arg)
+{
+	struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	int i = 0, rc;
+	uint32_t wm_reload_mask = 0;
+	int vfe_idx;
+	/*
+	 * For Offline VFE, HAL expects same frame id
+	 * for offline output which it requested in do_reprocess.
+	 */
+	vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id =
+		fe_cfg->frame_id;
+	if (fe_cfg->offline_pass == OFFLINE_SECOND_PASS) {
+		stream_info = msm_isp_get_stream_common_data(vfe_dev,
+			HANDLE_TO_IDX(fe_cfg->output_stream_id));
+		if (stream_info == NULL) {
+			pr_err("%s: Error in Offline process\n", __func__);
+			return -EINVAL;
+		}
+		vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+		msm_isp_reset_framedrop(vfe_dev, stream_info);
+
+		rc = msm_isp_cfg_offline_ping_pong_address(vfe_dev, stream_info,
+			VFE_PING_FLAG, fe_cfg->output_buf_idx);
+		if (rc < 0) {
+			pr_err("%s: Fetch engine config failed\n", __func__);
+			return -EINVAL;
+		}
+		for (i = 0; i < stream_info->num_planes; i++)
+			wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]);
+		vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
+			VFE_SRC_MAX);
+		vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev,
+			vfe_dev->vfe_base, wm_reload_mask);
+	}
+	return vfe_dev->hw_info->vfe_ops.core_ops.
+		start_fetch_eng_multi_pass(vfe_dev, arg);
+}
+
+void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
+	struct msm_vfe_fetch_engine_info *fetch_engine_info)
+{
+	struct msm_isp_event_data fe_rd_done_event;
+
+	memset(&fe_rd_done_event, 0, sizeof(struct msm_isp_event_data));
+	fe_rd_done_event.frame_id =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	fe_rd_done_event.u.fetch_done.session_id =
+		fetch_engine_info->session_id;
+	fe_rd_done_event.u.fetch_done.stream_id = fetch_engine_info->stream_id;
+	fe_rd_done_event.u.fetch_done.handle = fetch_engine_info->bufq_handle;
+	fe_rd_done_event.u.fetch_done.buf_idx = fetch_engine_info->buf_idx;
+	fe_rd_done_event.u.fetch_done.fd = fetch_engine_info->fd;
+	fe_rd_done_event.u.fetch_done.offline_mode =
+		fetch_engine_info->offline_mode;
+
+	ISP_DBG("%s:VFE%d ISP_EVENT_FE_READ_DONE buf_idx %d\n",
+		__func__, vfe_dev->pdev->id, fetch_engine_info->buf_idx);
+	fetch_engine_info->is_busy = 0;
+	msm_isp_send_event(vfe_dev, ISP_EVENT_FE_READ_DONE, &fe_rd_done_event);
+}
+
+static int msm_isp_cfg_pix(struct vfe_device *vfe_dev,
+	struct msm_vfe_input_cfg *input_cfg)
+{
+	int rc = 0;
+	struct msm_vfe_pix_cfg *pix_cfg = NULL;
+
+	if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
+		pr_err("%s: src %d path is active\n", __func__, VFE_PIX_0);
+		return -EINVAL;
+	}
+
+	pix_cfg = &input_cfg->d.pix_cfg;
+	vfe_dev->hvx_cmd = pix_cfg->hvx_cmd;
+	vfe_dev->is_split = input_cfg->d.pix_cfg.is_split;
+
+	vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock =
+		input_cfg->input_pix_clk;
+	vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux =
+		input_cfg->d.pix_cfg.input_mux;
+	vfe_dev->axi_data.src_info[VFE_PIX_0].input_format =
+		input_cfg->d.pix_cfg.input_format;
+	vfe_dev->axi_data.src_info[VFE_PIX_0].sof_counter_step = 1;
+
+	/*
+	 * Fill pixel_clock into input_pix_clk so that user space
+	 * can use rounded clk rate
+	 */
+	input_cfg->input_pix_clk =
+		vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock;
+
+	ISP_DBG("%s: input mux is %d CAMIF %d io_format 0x%x\n", __func__,
+		input_cfg->d.pix_cfg.input_mux, CAMIF,
+		input_cfg->d.pix_cfg.input_format);
+
+	if (input_cfg->d.pix_cfg.input_mux == CAMIF ||
+		input_cfg->d.pix_cfg.input_mux == TESTGEN) {
+		if (input_cfg->d.pix_cfg.input_mux == CAMIF)
+			vfe_dev->axi_data.src_info[VFE_PIX_0].width =
+				input_cfg->d.pix_cfg.camif_cfg.pixels_per_line;
+		if (input_cfg->d.pix_cfg.input_mux == TESTGEN)
+			vfe_dev->axi_data.src_info[VFE_PIX_0].width =
+			input_cfg->d.pix_cfg.testgen_cfg.pixels_per_line;
+		if (input_cfg->d.pix_cfg.camif_cfg.subsample_cfg.
+			sof_counter_step > 0) {
+			vfe_dev->axi_data.src_info[VFE_PIX_0].
+				sof_counter_step = input_cfg->d.pix_cfg.
+				camif_cfg.subsample_cfg.sof_counter_step;
+		}
+	} else if (input_cfg->d.pix_cfg.input_mux == EXTERNAL_READ) {
+		vfe_dev->axi_data.src_info[VFE_PIX_0].width =
+			input_cfg->d.pix_cfg.fetch_engine_cfg.buf_stride;
+	}
+	vfe_dev->hw_info->vfe_ops.core_ops.cfg_input_mux(
+			vfe_dev, &input_cfg->d.pix_cfg);
+	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, VFE_PIX_0);
+	return rc;
+}
+
+static int msm_isp_cfg_rdi(struct vfe_device *vfe_dev,
+	struct msm_vfe_input_cfg *input_cfg)
+{
+	int rc = 0;
+
+	if (vfe_dev->axi_data.src_info[input_cfg->input_src].active) {
+		pr_err("%s: RAW%d path is active\n", __func__,
+			   input_cfg->input_src - VFE_RAW_0);
+		return -EINVAL;
+	}
+
+	vfe_dev->axi_data.
+		src_info[input_cfg->input_src].sof_counter_step = 1;
+
+	vfe_dev->axi_data.src_info[input_cfg->input_src].pixel_clock =
+		input_cfg->input_pix_clk;
+	vfe_dev->hw_info->vfe_ops.core_ops.cfg_rdi_reg(
+		vfe_dev, &input_cfg->d.rdi_cfg, input_cfg->input_src);
+	return rc;
+}
+
+int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0;
+	struct msm_vfe_input_cfg *input_cfg = arg;
+	long pixel_clock = 0;
+
+	switch (input_cfg->input_src) {
+	case VFE_PIX_0:
+		rc = msm_isp_cfg_pix(vfe_dev, input_cfg);
+		break;
+	case VFE_RAW_0:
+	case VFE_RAW_1:
+	case VFE_RAW_2:
+		rc = msm_isp_cfg_rdi(vfe_dev, input_cfg);
+		break;
+	default:
+		pr_err("%s: Invalid input source\n", __func__);
+		rc = -EINVAL;
+	}
+
+	pixel_clock = input_cfg->input_pix_clk;
+	/*
+	 * Only set rate to higher, do not lower higher
+	 * rate needed by another input
+	 */
+	if (pixel_clock > vfe_dev->vfe_clk_info[
+				vfe_dev->hw_info->vfe_clk_idx].clk_rate) {
+		rc = vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate(
+			vfe_dev,
+			&pixel_clock);
+		if (rc < 0) {
+			pr_err("%s: clock set rate failed\n", __func__);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int msm_isp_dual_hw_master_slave_sync(struct vfe_device *vfe_dev,
+						void *arg)
+{
+	int rc = 0;
+
+	struct msm_isp_dual_hw_master_slave_sync *link = arg;
+	unsigned long flags;
+	struct master_slave_resource_info *ms_res =
+			&vfe_dev->common_data->ms_resource;
+	int i;
+	struct msm_vfe_src_info *src_info = NULL;
+
+	spin_lock_irqsave(
+			&vfe_dev->common_data->common_dev_data_lock,
+			flags);
+	ms_res->dual_sync_mode = link->sync_mode;
+	if (ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC) {
+		for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+			if (ms_res->src_info[i] == NULL)
+				continue;
+			src_info = ms_res->src_info[i];
+			if (src_info->dual_hw_ms_info.sync_state ==
+				MSM_ISP_DUAL_CAM_ASYNC)
+				continue;
+			ms_res->active_src_mask &= ~(1 <<
+				src_info->dual_hw_ms_info.index);
+			ms_res->src_sof_mask &= ~(1 <<
+				src_info->dual_hw_ms_info.index);
+			src_info->dual_hw_ms_info.sync_state =
+				MSM_ISP_DUAL_CAM_ASYNC;
+		}
+	}
+	spin_unlock_irqrestore(
+			&vfe_dev->common_data->common_dev_data_lock,
+			flags);
+	return rc;
+}
+
+static int msm_isp_set_dual_HW_master_slave_mode(
+	struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i;
+	struct msm_isp_set_dual_hw_ms_cmd *dual_hw_ms_cmd = NULL;
+	struct msm_vfe_src_info *src_info = NULL;
+	unsigned long flags;
+	struct master_slave_resource_info *ms_res =
+			&vfe_dev->common_data->ms_resource;
+
+	if (!vfe_dev || !arg) {
+		pr_err("%s: Error! Invalid input vfe_dev %pK arg %pK\n",
+			__func__, vfe_dev, arg);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags);
+	dual_hw_ms_cmd = (struct msm_isp_set_dual_hw_ms_cmd *)arg;
+	vfe_dev->common_data->ms_resource.dual_hw_type = DUAL_HW_MASTER_SLAVE;
+	vfe_dev->vfe_ub_policy = MSM_WM_UB_EQUAL_SLICING;
+	if (dual_hw_ms_cmd->primary_intf < VFE_SRC_MAX) {
+		ISP_DBG("%s: vfe %d primary_intf %d\n", __func__,
+			vfe_dev->pdev->id, dual_hw_ms_cmd->primary_intf);
+		src_info = &vfe_dev->axi_data.
+			src_info[dual_hw_ms_cmd->primary_intf];
+		src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
+		src_info->dual_hw_ms_info.dual_hw_ms_type =
+			dual_hw_ms_cmd->dual_hw_ms_type;
+		src_info->dual_hw_ms_info.index = dual_hw_ms_cmd->
+			primary_intf + VFE_SRC_MAX * vfe_dev->pdev->id;
+		ms_res->src_info[src_info->dual_hw_ms_info.index] = src_info;
+		ms_res->num_src++;
+		if (dual_hw_ms_cmd->dual_hw_ms_type == MS_TYPE_MASTER) {
+			ms_res->master_index = src_info->dual_hw_ms_info.index;
+			ms_res->sof_delta_threshold =
+				dual_hw_ms_cmd->sof_delta_threshold;
+		} else {
+			ms_res->primary_slv_idx =
+				src_info->dual_hw_ms_info.index;
+		}
+	}
+	ISP_DBG("%s: vfe %d num_src %d\n", __func__, vfe_dev->pdev->id,
+		dual_hw_ms_cmd->num_src);
+	if (dual_hw_ms_cmd->num_src > VFE_SRC_MAX) {
+		pr_err("%s: Error! Invalid num_src %d\n", __func__,
+			dual_hw_ms_cmd->num_src);
+		spin_unlock_irqrestore(&vfe_dev->common_data->
+			common_dev_data_lock, flags);
+		return -EINVAL;
+	}
+	/* This for loop is for non-primary intf to be marked with Master/Slave
+	 * in order for frame id sync. But their timestamp is not saved.
+	 * So no sof_info resource is allocated
+	 */
+	for (i = 0; i < dual_hw_ms_cmd->num_src; i++) {
+		if (dual_hw_ms_cmd->input_src[i] >= VFE_SRC_MAX) {
+			pr_err("%s: Error! Invalid SRC param %d\n", __func__,
+				dual_hw_ms_cmd->input_src[i]);
+			spin_unlock_irqrestore(&vfe_dev->common_data->
+					common_dev_data_lock, flags);
+			return -EINVAL;
+		}
+		ISP_DBG("%s: vfe %d src %d type %d\n", __func__,
+			vfe_dev->pdev->id, dual_hw_ms_cmd->input_src[i],
+			dual_hw_ms_cmd->dual_hw_ms_type);
+		src_info = &vfe_dev->axi_data.
+			src_info[dual_hw_ms_cmd->input_src[i]];
+		src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
+		src_info->dual_hw_ms_info.dual_hw_ms_type =
+			dual_hw_ms_cmd->dual_hw_ms_type;
+		src_info->dual_hw_ms_info.index = dual_hw_ms_cmd->
+			input_src[i] + VFE_SRC_MAX * vfe_dev->pdev->id;
+		ms_res->src_info[src_info->dual_hw_ms_info.index] = src_info;
+		ms_res->num_src++;
+	}
+	spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock,
+				flags);
+	return rc;
+}
+
+static int msm_isp_proc_cmd_list_unlocked(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0;
+	uint32_t count = 0;
+	struct msm_vfe_cfg_cmd_list *proc_cmd =
+		(struct msm_vfe_cfg_cmd_list *)arg;
+	struct msm_vfe_cfg_cmd_list cmd, cmd_next;
+
+	if (!vfe_dev || !arg) {
+		pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__,
+			vfe_dev, arg);
+		return -EINVAL;
+	}
+
+	rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd->cfg_cmd);
+	if (rc < 0)
+		pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc);
+
+	cmd = *proc_cmd;
+
+	while (cmd.next) {
+		if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list)) {
+			pr_err("%s:%d failed: next size %u != expected %zu\n",
+				__func__, __LINE__, cmd.next_size,
+				sizeof(struct msm_vfe_cfg_cmd_list));
+			break;
+		}
+		if (++count >= MAX_ISP_REG_LIST) {
+			pr_err("%s:%d Error exceeding the max register count:%u\n",
+				__func__, __LINE__, count);
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&cmd_next, (void __user *)cmd.next,
+			sizeof(struct msm_vfe_cfg_cmd_list))) {
+			rc = -EFAULT;
+			continue;
+		}
+
+		rc = msm_isp_proc_cmd(vfe_dev, &cmd_next.cfg_cmd);
+		if (rc < 0)
+			pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc);
+
+		cmd = cmd_next;
+	}
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_vfe_cfg_cmd2_32 {
+	uint16_t num_cfg;
+	uint16_t cmd_len;
+	compat_caddr_t cfg_data;
+	compat_caddr_t cfg_cmd;
+};
+
+struct msm_vfe_cfg_cmd_list_32 {
+	struct msm_vfe_cfg_cmd2_32   cfg_cmd;
+	compat_caddr_t               next;
+	uint32_t                     next_size;
+};
+
+#define VIDIOC_MSM_VFE_REG_CFG_COMPAT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2_32)
+#define VIDIOC_MSM_VFE_REG_LIST_CFG_COMPAT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE+14, struct msm_vfe_cfg_cmd_list_32)
+
+static void msm_isp_compat_to_proc_cmd(struct msm_vfe_cfg_cmd2 *proc_cmd,
+	struct msm_vfe_cfg_cmd2_32 *proc_cmd_ptr32)
+{
+	proc_cmd->num_cfg = proc_cmd_ptr32->num_cfg;
+	proc_cmd->cmd_len = proc_cmd_ptr32->cmd_len;
+	proc_cmd->cfg_data = compat_ptr(proc_cmd_ptr32->cfg_data);
+	proc_cmd->cfg_cmd = compat_ptr(proc_cmd_ptr32->cfg_cmd);
+}
+
+static int msm_isp_proc_cmd_list_compat(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0;
+	uint32_t count = 0;
+	struct msm_vfe_cfg_cmd_list_32 *proc_cmd =
+		(struct msm_vfe_cfg_cmd_list_32 *)arg;
+	struct msm_vfe_cfg_cmd_list_32 cmd, cmd_next;
+	struct msm_vfe_cfg_cmd2 current_cmd;
+
+	if (!vfe_dev || !arg) {
+		pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__,
+			vfe_dev, arg);
+		return -EINVAL;
+	}
+	msm_isp_compat_to_proc_cmd(&current_cmd, &proc_cmd->cfg_cmd);
+	rc = msm_isp_proc_cmd(vfe_dev, &current_cmd);
+	if (rc < 0)
+		pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc);
+
+	cmd = *proc_cmd;
+
+	while (compat_ptr(cmd.next) != NULL) {
+		if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list_32)) {
+			pr_err("%s:%d failed: next size %u != expected %zu\n",
+				__func__, __LINE__, cmd.next_size,
+				sizeof(struct msm_vfe_cfg_cmd_list));
+			break;
+		}
+		if (++count >= MAX_ISP_REG_LIST) {
+			pr_err("%s:%d Error exceeding the max register count:%u\n",
+				__func__, __LINE__, count);
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&cmd_next, compat_ptr(cmd.next),
+			sizeof(struct msm_vfe_cfg_cmd_list_32))) {
+			rc = -EFAULT;
+			continue;
+		}
+
+		msm_isp_compat_to_proc_cmd(&current_cmd, &cmd_next.cfg_cmd);
+		rc = msm_isp_proc_cmd(vfe_dev, &current_cmd);
+		if (rc < 0)
+			pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc);
+
+		cmd = cmd_next;
+	}
+	return rc;
+}
+
+static int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg)
+{
+	if (is_compat_task())
+		return msm_isp_proc_cmd_list_compat(vfe_dev, arg);
+	else
+		return msm_isp_proc_cmd_list_unlocked(vfe_dev, arg);
+}
+#else /* CONFIG_COMPAT */
+static int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg)
+{
+	return msm_isp_proc_cmd_list_unlocked(vfe_dev, arg);
+}
+#endif /* CONFIG_COMPAT */
+
+static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc = 0;
+	long rc2 = 0;
+	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
+
+	if (!vfe_dev || !vfe_dev->vfe_base) {
+		pr_err("%s:%d failed: invalid params %pK\n",
+			__func__, __LINE__, vfe_dev);
+		if (vfe_dev)
+			pr_err("%s:%d failed %pK\n", __func__,
+				__LINE__, vfe_dev->vfe_base);
+		return -EINVAL;
+	}
+
+	/* use real time mutex for hard real-time ioctls such as
+	 * buffer operations and register updates.
+	 * Use core mutex for other ioctls that could take
+	 * longer time to complete such as start/stop ISP streams
+	 * which blocks until the hardware start/stop streaming
+	 */
+	ISP_DBG("%s: cmd: %d\n", __func__, _IOC_TYPE(cmd));
+	switch (cmd) {
+	case VIDIOC_MSM_VFE_REG_CFG: {
+		mutex_lock(&vfe_dev->realtime_mutex);
+		rc = msm_isp_proc_cmd(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		break;
+	}
+	case VIDIOC_MSM_VFE_REG_LIST_CFG: {
+		mutex_lock(&vfe_dev->realtime_mutex);
+		rc = msm_isp_proc_cmd_list(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		break;
+	}
+	case VIDIOC_MSM_ISP_REQUEST_BUF:
+	case VIDIOC_MSM_ISP_REQUEST_BUF_VER2:
+		/* fallthrough */
+	case VIDIOC_MSM_ISP_ENQUEUE_BUF:
+		/* fallthrough */
+	case VIDIOC_MSM_ISP_DEQUEUE_BUF:
+		/* fallthrough */
+	case VIDIOC_MSM_ISP_UNMAP_BUF: {
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		break;
+	}
+	case VIDIOC_MSM_ISP_RELEASE_BUF: {
+		if (vfe_dev->buf_mgr == NULL) {
+			pr_err("%s: buf mgr NULL! rc = -1\n", __func__);
+			rc = -EINVAL;
+			return rc;
+		}
+		mutex_lock(&vfe_dev->buf_mgr->lock);
+		rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
+		mutex_unlock(&vfe_dev->buf_mgr->lock);
+		break;
+	}
+	case VIDIOC_MSM_ISP_REQUEST_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_request_axi_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_RELEASE_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_release_axi_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_CFG_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_cfg_axi_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_AXI_HALT:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_axi_halt(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_AXI_RESET:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		if (atomic_read(&vfe_dev->error_info.overflow_state)
+			!= HALT_ENFORCED) {
+			rc = msm_isp_stats_reset(vfe_dev);
+			rc2 = msm_isp_axi_reset(vfe_dev, arg);
+			if (!rc && rc2)
+				rc = rc2;
+		} else {
+			pr_err_ratelimited("%s: no HW reset, halt enforced.\n",
+				__func__);
+		}
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_AXI_RESTART:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		if (atomic_read(&vfe_dev->error_info.overflow_state)
+			!= HALT_ENFORCED) {
+			rc = msm_isp_stats_restart(vfe_dev);
+			rc2 = msm_isp_axi_restart(vfe_dev, arg);
+			if (!rc && rc2)
+				rc = rc2;
+		} else {
+			pr_err_ratelimited("%s: no AXI restart, halt enforced.\n",
+				__func__);
+		}
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_INPUT_CFG:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_cfg_input(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_AHB_CLK_CFG:
+		mutex_lock(&vfe_dev->core_mutex);
+		if (vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg)
+			rc = vfe_dev->hw_info->vfe_ops.core_ops.
+					ahb_clk_cfg(vfe_dev, arg);
+		else
+			rc = -EOPNOTSUPP;
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_SET_DUAL_HW_MASTER_SLAVE:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_set_dual_HW_master_slave_mode(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_dual_hw_master_slave_sync(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_DUAL_HW_LPM_MODE:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_ab_ib_update_lpm_mode(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_FETCH_ENG_START:
+	case VIDIOC_MSM_ISP_MAP_BUF_START_FE:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_start_fetch_engine(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+
+	case VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START:
+	case VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_start_fetch_engine_multi_pass(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_REG_UPDATE_CMD:
+		if (arg) {
+			enum msm_vfe_input_src frame_src =
+				*((enum msm_vfe_input_src *)arg);
+			vfe_dev->hw_info->vfe_ops.core_ops.
+				reg_update(vfe_dev, frame_src);
+		}
+		break;
+	case VIDIOC_MSM_ISP_SET_SRC_STATE:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_set_src_state(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_request_stats_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_release_stats_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_CFG_STATS_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_cfg_stats_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_update_stats_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_UPDATE_STREAM:
+		mutex_lock(&vfe_dev->core_mutex);
+		MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+		rc = msm_isp_update_axi_stream(vfe_dev, arg);
+		MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case VIDIOC_MSM_ISP_SMMU_ATTACH:
+		mutex_lock(&vfe_dev->core_mutex);
+		rc = msm_isp_smmu_attach(vfe_dev->buf_mgr, arg);
+		mutex_unlock(&vfe_dev->core_mutex);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		vfe_dev->isp_sof_debug = 0;
+		vfe_dev->isp_raw0_debug = 0;
+		vfe_dev->isp_raw1_debug = 0;
+		vfe_dev->isp_raw2_debug = 0;
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+	case MSM_SD_SHUTDOWN:
+		break;
+
+	default:
+		pr_err_ratelimited("%s: Invalid ISP command %d\n", __func__,
+				    cmd);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+
+#ifdef CONFIG_COMPAT
+static long msm_isp_ioctl_compat(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
+	long rc = 0;
+
+	if (!vfe_dev || !vfe_dev->vfe_base) {
+		pr_err("%s:%d failed: invalid params %pK\n",
+			__func__, __LINE__, vfe_dev);
+		if (vfe_dev)
+			pr_err("%s:%d failed %pK\n", __func__,
+				__LINE__, vfe_dev->vfe_base);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case VIDIOC_MSM_VFE_REG_CFG_COMPAT: {
+		struct msm_vfe_cfg_cmd2 proc_cmd;
+
+		mutex_lock(&vfe_dev->realtime_mutex);
+		msm_isp_compat_to_proc_cmd(&proc_cmd,
+			(struct msm_vfe_cfg_cmd2_32 *) arg);
+		rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		break;
+	}
+	case VIDIOC_MSM_VFE_REG_LIST_CFG_COMPAT: {
+		mutex_lock(&vfe_dev->realtime_mutex);
+		rc = msm_isp_proc_cmd_list(vfe_dev, arg);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		break;
+	}
+	default:
+		return msm_isp_ioctl_unlocked(sd, cmd, arg);
+	}
+
+	return rc;
+}
+
+long msm_isp_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	return msm_isp_ioctl_compat(sd, cmd, arg);
+}
+#else /* CONFIG_COMPAT */
+long msm_isp_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	return msm_isp_ioctl_unlocked(sd, cmd, arg);
+}
+#endif /* CONFIG_COMPAT */
+
+static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
+	struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd,
+	uint32_t *cfg_data, uint32_t cmd_len)
+{
+	if (!vfe_dev || !reg_cfg_cmd) {
+		pr_err("%s:%d failed: vfe_dev %pK reg_cfg_cmd %pK\n", __func__,
+			__LINE__, vfe_dev, reg_cfg_cmd);
+		return -EINVAL;
+	}
+	if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) &&
+		(!cfg_data || !cmd_len)) {
+		pr_err("%s:%d failed: cmd type %d cfg_data %pK cmd_len %d\n",
+			__func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data,
+			cmd_len);
+		return -EINVAL;
+	}
+
+	/* Validate input parameters */
+	switch (reg_cfg_cmd->cmd_type) {
+	case VFE_WRITE:
+	case VFE_READ:
+	case VFE_WRITE_MB: {
+		if ((reg_cfg_cmd->u.rw_info.reg_offset >
+			(UINT_MAX - reg_cfg_cmd->u.rw_info.len)) ||
+			((reg_cfg_cmd->u.rw_info.reg_offset +
+			reg_cfg_cmd->u.rw_info.len) >
+			vfe_dev->vfe_base_size) ||
+			(reg_cfg_cmd->u.rw_info.reg_offset & 0x3)) {
+			pr_err_ratelimited("%s:%d regoffset %d len %d res %d\n",
+				__func__, __LINE__,
+				reg_cfg_cmd->u.rw_info.reg_offset,
+				reg_cfg_cmd->u.rw_info.len,
+				(uint32_t)vfe_dev->vfe_base_size);
+			return -EINVAL;
+		}
+
+		if ((reg_cfg_cmd->u.rw_info.cmd_data_offset >
+			(UINT_MAX - reg_cfg_cmd->u.rw_info.len)) ||
+			((reg_cfg_cmd->u.rw_info.cmd_data_offset +
+			reg_cfg_cmd->u.rw_info.len) > cmd_len)) {
+			pr_err_ratelimited("%s:%d cmd_data_offset %d len %d cmd_len %d\n",
+				__func__, __LINE__,
+				reg_cfg_cmd->u.rw_info.cmd_data_offset,
+				reg_cfg_cmd->u.rw_info.len, cmd_len);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case VFE_WRITE_DMI_16BIT:
+	case VFE_WRITE_DMI_32BIT:
+	case VFE_WRITE_DMI_64BIT:
+	case VFE_READ_DMI_16BIT:
+	case VFE_READ_DMI_32BIT:
+	case VFE_READ_DMI_64BIT: {
+		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT ||
+			reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
+			if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <=
+				reg_cfg_cmd->u.dmi_info.lo_tbl_offset) ||
+				(reg_cfg_cmd->u.dmi_info.hi_tbl_offset -
+				reg_cfg_cmd->u.dmi_info.lo_tbl_offset !=
+				(sizeof(uint32_t)))) {
+				pr_err("%s:%d hi %d lo %d\n",
+					__func__, __LINE__,
+					reg_cfg_cmd->u.dmi_info.hi_tbl_offset,
+					reg_cfg_cmd->u.dmi_info.hi_tbl_offset);
+				return -EINVAL;
+			}
+			if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) {
+				pr_err("%s:%d len %d\n",
+					__func__, __LINE__,
+					reg_cfg_cmd->u.dmi_info.len);
+				return -EINVAL;
+			}
+			if (((UINT_MAX -
+				reg_cfg_cmd->u.dmi_info.hi_tbl_offset) <
+				(reg_cfg_cmd->u.dmi_info.len -
+				sizeof(uint32_t))) ||
+				((reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
+				reg_cfg_cmd->u.dmi_info.len -
+				sizeof(uint32_t)) > cmd_len)) {
+				pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n",
+					__func__, __LINE__,
+					reg_cfg_cmd->u.dmi_info.hi_tbl_offset,
+					reg_cfg_cmd->u.dmi_info.len, cmd_len);
+				return -EINVAL;
+			}
+		}
+		if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset >
+			(UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) ||
+			((reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
+			reg_cfg_cmd->u.dmi_info.len) > cmd_len)) {
+			pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n",
+				__func__, __LINE__,
+				reg_cfg_cmd->u.dmi_info.lo_tbl_offset,
+				reg_cfg_cmd->u.dmi_info.len, cmd_len);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	switch (reg_cfg_cmd->cmd_type) {
+	case VFE_WRITE: {
+		msm_camera_io_memcpy(vfe_dev->vfe_base +
+			reg_cfg_cmd->u.rw_info.reg_offset,
+			cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4,
+			reg_cfg_cmd->u.rw_info.len);
+		break;
+	}
+	case VFE_WRITE_MB: {
+		msm_camera_io_memcpy_mb(vfe_dev->vfe_base +
+			reg_cfg_cmd->u.rw_info.reg_offset,
+			cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4,
+			reg_cfg_cmd->u.rw_info.len);
+		break;
+	}
+	case VFE_CFG_MASK: {
+		uint32_t temp;
+		bool grab_lock;
+		unsigned long flags;
+
+		if ((UINT_MAX - sizeof(temp) <
+			reg_cfg_cmd->u.mask_info.reg_offset) ||
+			(vfe_dev->vfe_base_size <
+			reg_cfg_cmd->u.mask_info.reg_offset +
+			sizeof(temp)) ||
+			(reg_cfg_cmd->u.mask_info.reg_offset & 0x3)) {
+			pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__);
+			return -EINVAL;
+		}
+		grab_lock = vfe_dev->hw_info->vfe_ops.core_ops.
+			is_module_cfg_lock_needed(reg_cfg_cmd->
+			u.mask_info.reg_offset);
+		if (grab_lock)
+			spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
+		else
+			__acquire(&vfe_dev->shared_data_lock);
+		temp = msm_camera_io_r(vfe_dev->vfe_base +
+			reg_cfg_cmd->u.mask_info.reg_offset);
+
+		temp &= ~reg_cfg_cmd->u.mask_info.mask;
+		temp |= reg_cfg_cmd->u.mask_info.val;
+		msm_camera_io_w(temp, vfe_dev->vfe_base +
+			reg_cfg_cmd->u.mask_info.reg_offset);
+		if (grab_lock)
+			spin_unlock_irqrestore(&vfe_dev->shared_data_lock,
+				flags);
+		else
+			__release(&vfe_dev->shared_data_lock);
+		break;
+	}
+	case VFE_WRITE_DMI_16BIT:
+	case VFE_WRITE_DMI_32BIT:
+	case VFE_WRITE_DMI_64BIT: {
+		int i;
+		uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
+		uint32_t hi_val, lo_val, lo_val1;
+
+		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) {
+			hi_tbl_ptr = cfg_data +
+				reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
+		}
+		lo_tbl_ptr = cfg_data +
+			reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
+		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT)
+			reg_cfg_cmd->u.dmi_info.len =
+				reg_cfg_cmd->u.dmi_info.len / 2;
+		for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
+			lo_val = *lo_tbl_ptr++;
+			if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) {
+				lo_val1 = lo_val & 0x0000FFFF;
+				lo_val = (lo_val & 0xFFFF0000)>>16;
+				msm_camera_io_w(lo_val1, vfe_dev->vfe_base +
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
+			} else if (reg_cfg_cmd->cmd_type ==
+					   VFE_WRITE_DMI_64BIT) {
+				lo_tbl_ptr++;
+				hi_val = *hi_tbl_ptr;
+				hi_tbl_ptr = hi_tbl_ptr + 2;
+				msm_camera_io_w(hi_val, vfe_dev->vfe_base +
+					vfe_dev->hw_info->dmi_reg_offset);
+			}
+			msm_camera_io_w(lo_val, vfe_dev->vfe_base +
+				vfe_dev->hw_info->dmi_reg_offset + 0x4);
+		}
+		break;
+	}
+	case VFE_READ_DMI_16BIT:
+	case VFE_READ_DMI_32BIT:
+	case VFE_READ_DMI_64BIT: {
+		int i;
+		uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
+		uint32_t hi_val, lo_val, lo_val1;
+
+		if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
+			hi_tbl_ptr = cfg_data +
+				reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
+		}
+
+		lo_tbl_ptr = cfg_data +
+			reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
+
+		if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT)
+			reg_cfg_cmd->u.dmi_info.len =
+				reg_cfg_cmd->u.dmi_info.len / 2;
+
+		for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
+			lo_val = msm_camera_io_r(vfe_dev->vfe_base +
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
+
+			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) {
+				lo_val1 = msm_camera_io_r(vfe_dev->vfe_base +
+					vfe_dev->hw_info->dmi_reg_offset + 0x4);
+				lo_val |= lo_val1 << 16;
+			}
+			*lo_tbl_ptr++ = lo_val;
+			if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
+				hi_val = msm_camera_io_r(vfe_dev->vfe_base +
+					vfe_dev->hw_info->dmi_reg_offset);
+				*hi_tbl_ptr = hi_val;
+				hi_tbl_ptr += 2;
+				lo_tbl_ptr++;
+			}
+		}
+		break;
+	}
+	case VFE_HW_UPDATE_LOCK: {
+		uint32_t update_id =
+			vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id;
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id != *cfg_data
+			|| update_id == *cfg_data) {
+			pr_err("%s hw update lock failed acq %d, cur id %u, last id %u\n",
+				__func__,
+				*cfg_data,
+				vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id,
+				update_id);
+			return -EINVAL;
+		}
+		break;
+	}
+	case VFE_HW_UPDATE_UNLOCK: {
+		if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id
+			!= *cfg_data) {
+			pr_err("hw update across frame boundary,begin id %u, end id %d\n",
+				*cfg_data,
+				vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+		}
+		vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id =
+			vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+		break;
+	}
+	case VFE_READ: {
+		int i;
+		uint32_t *data_ptr = cfg_data +
+			reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
+		for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) {
+			if ((data_ptr < cfg_data) ||
+				(UINT_MAX / sizeof(*data_ptr) <
+				 (data_ptr - cfg_data)) ||
+				(sizeof(*data_ptr) * (data_ptr - cfg_data) >=
+				 cmd_len))
+				return -EINVAL;
+			*data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base +
+				reg_cfg_cmd->u.rw_info.reg_offset);
+			reg_cfg_cmd->u.rw_info.reg_offset += 4;
+		}
+		break;
+	}
+	case GET_MAX_CLK_RATE: {
+		int rc = 0;
+		unsigned long rate;
+
+		if (cmd_len != sizeof(__u32)) {
+			pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(__u32));
+			return -EINVAL;
+		}
+		rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_max_clk_rate(
+							vfe_dev, &rate);
+		if (rc < 0) {
+			pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc);
+			return -EINVAL;
+		}
+
+		*(__u32 *)cfg_data = (__u32)rate;
+
+		break;
+	}
+	case GET_CLK_RATES: {
+		int rc = 0;
+		struct msm_isp_clk_rates rates;
+		struct msm_isp_clk_rates *user_data =
+			(struct msm_isp_clk_rates *)cfg_data;
+		if (cmd_len != sizeof(struct msm_isp_clk_rates)) {
+			pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(struct msm_isp_clk_rates));
+			return -EINVAL;
+		}
+		rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_clk_rates(
+							vfe_dev, &rates);
+		if (rc < 0) {
+			pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc);
+			return -EINVAL;
+		}
+		user_data->svs_rate = rates.svs_rate;
+		user_data->nominal_rate = rates.nominal_rate;
+		user_data->high_rate = rates.high_rate;
+		break;
+	}
+	case GET_ISP_ID: {
+		uint32_t *isp_id = NULL;
+
+		if (cmd_len < sizeof(uint32_t)) {
+			pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(uint32_t));
+			return -EINVAL;
+		}
+
+		isp_id = (uint32_t *)cfg_data;
+		*isp_id = vfe_dev->pdev->id;
+		break;
+	}
+	case SET_WM_UB_SIZE:
+		break;
+	case SET_UB_POLICY: {
+
+		if (cmd_len < sizeof(vfe_dev->vfe_ub_policy)) {
+			pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(vfe_dev->vfe_ub_policy));
+			return -EINVAL;
+		}
+		vfe_dev->vfe_ub_policy = *cfg_data;
+		break;
+	}
+	case GET_VFE_HW_LIMIT: {
+		uint32_t *hw_limit = NULL;
+
+		if (cmd_len < sizeof(uint32_t)) {
+			pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(uint32_t));
+			return -EINVAL;
+		}
+
+		hw_limit = (uint32_t *)cfg_data;
+		*hw_limit = vfe_dev->vfe_hw_limit;
+		break;
+	}
+	}
+	return 0;
+}
+
+int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg)
+{
+	int rc = 0, i;
+	struct msm_vfe_cfg_cmd2 *proc_cmd = arg;
+	struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd;
+	uint32_t *cfg_data = NULL;
+
+	if (!proc_cmd->num_cfg) {
+		pr_err("%s: Passed num_cfg as 0\n", __func__);
+		return -EINVAL;
+	}
+
+	reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)*
+		proc_cmd->num_cfg, GFP_KERNEL);
+	if (!reg_cfg_cmd) {
+		rc = -ENOMEM;
+		goto reg_cfg_failed;
+	}
+
+	if (copy_from_user(reg_cfg_cmd,
+		(void __user *)(proc_cmd->cfg_cmd),
+		sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) {
+		rc = -EFAULT;
+		goto copy_cmd_failed;
+	}
+
+	if (proc_cmd->cmd_len > 0) {
+		cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL);
+		if (!cfg_data) {
+			pr_err("%s: cfg_data alloc failed\n", __func__);
+			rc = -ENOMEM;
+			goto cfg_data_failed;
+		}
+
+		if (copy_from_user(cfg_data,
+			(void __user *)(proc_cmd->cfg_data),
+			proc_cmd->cmd_len)) {
+			rc = -EFAULT;
+			goto copy_cmd_failed;
+		}
+	}
+
+	for (i = 0; i < proc_cmd->num_cfg; i++)
+		rc = msm_isp_send_hw_cmd(vfe_dev, &reg_cfg_cmd[i],
+			cfg_data, proc_cmd->cmd_len);
+
+	if (copy_to_user(proc_cmd->cfg_data,
+			cfg_data, proc_cmd->cmd_len)) {
+		rc = -EFAULT;
+		goto copy_cmd_failed;
+	}
+
+copy_cmd_failed:
+	kfree(cfg_data);
+cfg_data_failed:
+	kfree(reg_cfg_cmd);
+reg_cfg_failed:
+	return rc;
+}
+
+int msm_isp_send_event(struct vfe_device *vfe_dev,
+	uint32_t event_type,
+	struct msm_isp_event_data *event_data)
+{
+	struct v4l2_event isp_event;
+
+	memset(&isp_event, 0, sizeof(struct v4l2_event));
+	isp_event.id = 0;
+	isp_event.type = event_type;
+	memcpy(&isp_event.u.data[0], event_data,
+		sizeof(struct msm_isp_event_data));
+	v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event);
+	return 0;
+}
+
+#define CAL_WORD(width, M, N) ((width * M + N - 1) / N)
+
+int msm_isp_cal_word_per_line(uint32_t output_format,
+	uint32_t pixel_per_line)
+{
+	int val = -1;
+
+	switch (output_format) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_GREY:
+		val = CAL_WORD(pixel_per_line, 1, 8);
+		break;
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR10DPCM6:
+	case V4L2_PIX_FMT_SGBRG10DPCM6:
+	case V4L2_PIX_FMT_SGRBG10DPCM6:
+	case V4L2_PIX_FMT_SRGGB10DPCM6:
+	case V4L2_PIX_FMT_SBGGR10DPCM8:
+	case V4L2_PIX_FMT_SGBRG10DPCM8:
+	case V4L2_PIX_FMT_SGRBG10DPCM8:
+	case V4L2_PIX_FMT_SRGGB10DPCM8:
+	case V4L2_PIX_FMT_META10:
+		val = CAL_WORD(pixel_per_line, 5, 32);
+		break;
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+		val = CAL_WORD(pixel_per_line, 3, 16);
+		break;
+	case V4L2_PIX_FMT_SBGGR14:
+	case V4L2_PIX_FMT_SGBRG14:
+	case V4L2_PIX_FMT_SGRBG14:
+	case V4L2_PIX_FMT_SRGGB14:
+		val = CAL_WORD(pixel_per_line, 7, 32);
+		break;
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+		val = CAL_WORD(pixel_per_line, 1, 6);
+		break;
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+		val = CAL_WORD(pixel_per_line, 1, 5);
+		break;
+	case V4L2_PIX_FMT_QBGGR14:
+	case V4L2_PIX_FMT_QGBRG14:
+	case V4L2_PIX_FMT_QGRBG14:
+	case V4L2_PIX_FMT_QRGGB14:
+		val = CAL_WORD(pixel_per_line, 1, 4);
+		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		val = CAL_WORD(pixel_per_line, 1, 8);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+		val = CAL_WORD(pixel_per_line, 2, 8);
+	break;
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+		val = CAL_WORD(pixel_per_line, 1, 4);
+	break;
+	case V4L2_PIX_FMT_NV24:
+	case V4L2_PIX_FMT_NV42:
+		val = CAL_WORD(pixel_per_line, 1, 8);
+	break;
+		/*TD: Add more image format*/
+	default:
+		msm_isp_print_fourcc_error(__func__, output_format);
+		break;
+	}
+	return val;
+}
+
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format)
+{
+	switch (output_format) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR10DPCM6:
+	case V4L2_PIX_FMT_SGBRG10DPCM6:
+	case V4L2_PIX_FMT_SGRBG10DPCM6:
+	case V4L2_PIX_FMT_SRGGB10DPCM6:
+	case V4L2_PIX_FMT_SBGGR10DPCM8:
+	case V4L2_PIX_FMT_SGBRG10DPCM8:
+	case V4L2_PIX_FMT_SGRBG10DPCM8:
+	case V4L2_PIX_FMT_SRGGB10DPCM8:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SBGGR14:
+	case V4L2_PIX_FMT_SGBRG14:
+	case V4L2_PIX_FMT_SGRBG14:
+	case V4L2_PIX_FMT_SRGGB14:
+		return MIPI;
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_QBGGR14:
+	case V4L2_PIX_FMT_QGBRG14:
+	case V4L2_PIX_FMT_QGRBG14:
+	case V4L2_PIX_FMT_QRGGB14:
+		return QCOM;
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+		return PLAIN16;
+	default:
+		msm_isp_print_fourcc_error(__func__, output_format);
+		break;
+	}
+	return -EINVAL;
+}
+
+int msm_isp_get_bit_per_pixel(uint32_t output_format)
+{
+	switch (output_format) {
+	case V4L2_PIX_FMT_Y4:
+		return 4;
+	case V4L2_PIX_FMT_Y6:
+		return 6;
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+	case V4L2_PIX_FMT_YVU410:
+	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YYUV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_YUV422P:
+	case V4L2_PIX_FMT_YUV411P:
+	case V4L2_PIX_FMT_Y41P:
+	case V4L2_PIX_FMT_YUV444:
+	case V4L2_PIX_FMT_YUV555:
+	case V4L2_PIX_FMT_YUV565:
+	case V4L2_PIX_FMT_YUV32:
+	case V4L2_PIX_FMT_YUV410:
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_PAL8:
+	case V4L2_PIX_FMT_UV8:
+	case MSM_V4L2_PIX_FMT_META:
+		return 8;
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR10DPCM6:
+	case V4L2_PIX_FMT_SGBRG10DPCM6:
+	case V4L2_PIX_FMT_SGRBG10DPCM6:
+	case V4L2_PIX_FMT_SRGGB10DPCM6:
+	case V4L2_PIX_FMT_SBGGR10DPCM8:
+	case V4L2_PIX_FMT_SGBRG10DPCM8:
+	case V4L2_PIX_FMT_SGRBG10DPCM8:
+	case V4L2_PIX_FMT_SRGGB10DPCM8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y10BPACK:
+	case V4L2_PIX_FMT_P16BGGR10:
+	case V4L2_PIX_FMT_P16GBRG10:
+	case V4L2_PIX_FMT_P16GRBG10:
+	case V4L2_PIX_FMT_P16RGGB10:
+	case V4L2_PIX_FMT_META10:
+	case MSM_V4L2_PIX_FMT_META10:
+		return 10;
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_Y12:
+		return 12;
+	case V4L2_PIX_FMT_SBGGR14:
+	case V4L2_PIX_FMT_SGBRG14:
+	case V4L2_PIX_FMT_SGRBG14:
+	case V4L2_PIX_FMT_SRGGB14:
+	case V4L2_PIX_FMT_QBGGR14:
+	case V4L2_PIX_FMT_QGBRG14:
+	case V4L2_PIX_FMT_QGRBG14:
+	case V4L2_PIX_FMT_QRGGB14:
+		return 14;
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_Y16:
+		return 16;
+	case V4L2_PIX_FMT_NV24:
+	case V4L2_PIX_FMT_NV42:
+		return 24;
+		/*TD: Add more image format*/
+	default:
+		msm_isp_print_fourcc_error(__func__, output_format);
+		pr_err("%s: Invalid output format %x\n",
+			__func__, output_format);
+		return -EINVAL;
+	}
+}
+
+void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
+
+	error_info->info_dump_frame_count++;
+}
+
+
+static int msm_isp_process_iommu_page_fault(struct vfe_device *vfe_dev)
+{
+	int rc = vfe_dev->buf_mgr->pagefault_debug_disable;
+	uint32_t irq_status0, irq_status1;
+	uint32_t overflow_mask;
+	unsigned long irq_flags;
+
+	/* Check if any overflow bit is set */
+	vfe_dev->hw_info->vfe_ops.core_ops.
+		get_overflow_mask(&overflow_mask);
+	vfe_dev->hw_info->vfe_ops.irq_ops.
+		read_irq_status(vfe_dev, &irq_status0, &irq_status1);
+	overflow_mask &= irq_status1;
+	spin_lock_irqsave(
+		&vfe_dev->common_data->common_dev_data_lock, irq_flags);
+	if (overflow_mask ||
+		atomic_read(&vfe_dev->error_info.overflow_state) !=
+			NO_OVERFLOW) {
+		spin_unlock_irqrestore(
+			&vfe_dev->common_data->common_dev_data_lock, irq_flags);
+		pr_err_ratelimited("%s: overflow detected during IOMMU\n",
+			__func__);
+		/* Don't treat the Overflow + Page fault scenario as fatal.
+		 * Instead try to do a recovery. Using an existing event as
+		 * as opposed to creating a new event.
+		 */
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_PING_PONG_MISMATCH);
+	} else {
+		spin_unlock_irqrestore(
+			&vfe_dev->common_data->common_dev_data_lock, irq_flags);
+		pr_err("%s:%d] VFE%d Handle Page fault! vfe_dev %pK\n",
+			__func__, __LINE__,  vfe_dev->pdev->id, vfe_dev);
+		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0);
+		msm_isp_halt_send_error(vfe_dev, ISP_EVENT_IOMMU_P_FAULT);
+	}
+
+	if (vfe_dev->buf_mgr->pagefault_debug_disable == 0) {
+		vfe_dev->buf_mgr->pagefault_debug_disable = 1;
+		vfe_dev->buf_mgr->ops->buf_mgr_debug(vfe_dev->buf_mgr,
+			vfe_dev->page_fault_addr);
+		msm_isp_print_ping_pong_address(vfe_dev,
+			vfe_dev->page_fault_addr);
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			read_wm_ping_pong_addr(vfe_dev);
+	}
+	return rc;
+}
+
+void msm_isp_process_error_info(struct vfe_device *vfe_dev)
+{
+	struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
+
+	if (error_info->error_count == 1 ||
+		!(error_info->info_dump_frame_count % 100)) {
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			process_error_status(vfe_dev);
+		error_info->error_mask0 = 0;
+		error_info->error_mask1 = 0;
+		error_info->camif_status = 0;
+		error_info->violation_status = 0;
+	}
+}
+
+static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev,
+	uint32_t error_mask0, uint32_t error_mask1)
+{
+	vfe_dev->error_info.error_mask0 |= error_mask0;
+	vfe_dev->error_info.error_mask1 |= error_mask1;
+	vfe_dev->error_info.error_count++;
+}
+
+int msm_isp_process_overflow_irq(
+	struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1,
+	uint8_t force_overflow)
+{
+	uint32_t overflow_mask;
+	uint32_t bus_err = 0;
+	unsigned long flags;
+
+	/* if there are no active streams - do not start recovery */
+	if (!vfe_dev->axi_data.num_active_stream)
+		return 0;
+
+	if (vfe_dev->hw_info->vfe_ops.core_ops.
+		get_bus_err_mask)
+		vfe_dev->hw_info->vfe_ops.core_ops.get_bus_err_mask(
+			vfe_dev, &bus_err, irq_status1);
+	/* Mask out all other irqs if recovery is started */
+	if (atomic_read(&vfe_dev->error_info.overflow_state) != NO_OVERFLOW) {
+		uint32_t halt_restart_mask0, halt_restart_mask1;
+
+		vfe_dev->hw_info->vfe_ops.core_ops.
+		get_halt_restart_mask(&halt_restart_mask0,
+			&halt_restart_mask1);
+		*irq_status0 &= halt_restart_mask0;
+		*irq_status1 &= halt_restart_mask1;
+
+		return 0;
+	}
+
+	/* Check if any overflow bit is set */
+	vfe_dev->hw_info->vfe_ops.core_ops.
+		get_overflow_mask(&overflow_mask);
+	overflow_mask &= *irq_status1;
+
+	if (overflow_mask || force_overflow) {
+		struct msm_isp_event_data error_event;
+		int i;
+		struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+		spin_lock_irqsave(
+			&vfe_dev->common_data->common_dev_data_lock, flags);
+
+		if (atomic_cmpxchg(&vfe_dev->error_info.overflow_state,
+				NO_OVERFLOW, OVERFLOW_DETECTED)) {
+			spin_unlock_irqrestore(
+				 &vfe_dev->common_data->common_dev_data_lock,
+				 flags);
+			return 0;
+		}
+
+		if (vfe_dev->reset_pending == 1) {
+			pr_err_ratelimited("%s:%d overflow %x during reset\n",
+				__func__, __LINE__, overflow_mask);
+			/* Clear overflow bits since reset is pending */
+			*irq_status1 &= ~overflow_mask;
+			spin_unlock_irqrestore(
+				 &vfe_dev->common_data->common_dev_data_lock,
+				 flags);
+			return 0;
+		}
+		pr_err_ratelimited("%s: vfe %d overflowmask %x,bus_error %x\n",
+			__func__, vfe_dev->pdev->id, overflow_mask, bus_err);
+		for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+			if (!axi_data->free_wm[i])
+				continue;
+			ISP_DBG("%s:wm %d assigned to stream handle %x\n",
+				__func__, i, axi_data->free_wm[i]);
+		}
+		vfe_dev->recovery_irq0_mask = vfe_dev->irq0_mask;
+		vfe_dev->recovery_irq1_mask = vfe_dev->irq1_mask;
+		vfe_dev->hw_info->vfe_ops.core_ops.
+				set_halt_restart_mask(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0);
+		/* mask off other vfe if dual vfe is used */
+		if (vfe_dev->is_split) {
+			int other_vfe_id;
+			struct vfe_device *temp_vfe;
+
+			other_vfe_id = (vfe_dev->pdev->id == ISP_VFE0) ?
+				ISP_VFE1 : ISP_VFE0;
+			temp_vfe = vfe_dev->common_data->
+				dual_vfe_res->vfe_dev[other_vfe_id];
+
+			atomic_set(&temp_vfe->error_info.overflow_state,
+				OVERFLOW_DETECTED);
+			temp_vfe->recovery_irq0_mask = temp_vfe->irq0_mask;
+			temp_vfe->recovery_irq1_mask = temp_vfe->irq1_mask;
+			temp_vfe->hw_info->vfe_ops.core_ops.
+				set_halt_restart_mask(temp_vfe);
+			temp_vfe->hw_info->vfe_ops.axi_ops.halt(temp_vfe, 0);
+		}
+
+		/* reset irq status so skip further process */
+		*irq_status0 = 0;
+		*irq_status1 = 0;
+
+		if (atomic_read(&vfe_dev->error_info.overflow_state)
+			!= HALT_ENFORCED) {
+			memset(&error_event, 0, sizeof(error_event));
+			error_event.frame_id =
+				vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+			error_event.u.error_info.err_type =
+				ISP_ERROR_BUS_OVERFLOW;
+			msm_isp_send_event(vfe_dev,
+				ISP_EVENT_ERROR, &error_event);
+		}
+		spin_unlock_irqrestore(
+			&vfe_dev->common_data->common_dev_data_lock,
+			flags);
+		return 1;
+	}
+	return 0;
+}
+
+void msm_isp_reset_burst_count_and_frame_drop(
+	struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info)
+{
+	if (stream_info->state != ACTIVE ||
+		stream_info->stream_type != BURST_STREAM) {
+		return;
+	}
+	if (stream_info->num_burst_capture != 0)
+		msm_isp_reset_framedrop(vfe_dev, stream_info);
+}
+
+void msm_isp_prepare_irq_debug_info(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+
+	unsigned long flags;
+	struct msm_vfe_irq_debug_info *irq_debug;
+	uint8_t current_index;
+
+	spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_irq_dump_lock, flags);
+	/* Fill current VFE debug info */
+	current_index = vfe_dev->common_data->vfe_irq_dump.
+		current_irq_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE;
+	irq_debug = &vfe_dev->common_data->vfe_irq_dump.
+		irq_debug[current_index];
+	irq_debug->vfe_id = vfe_dev->pdev->id;
+	irq_debug->core_id = smp_processor_id();
+	msm_isp_get_timestamp(&irq_debug->ts, vfe_dev);
+	irq_debug->irq_status0[vfe_dev->pdev->id] = irq_status0;
+	irq_debug->irq_status1[vfe_dev->pdev->id] = irq_status1;
+	irq_debug->ping_pong_status[vfe_dev->pdev->id] =
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+			get_pingpong_status(vfe_dev);
+	if (vfe_dev->is_split &&
+		(vfe_dev->common_data->
+		dual_vfe_res->vfe_dev[!vfe_dev->pdev->id])
+		&& (vfe_dev->common_data->dual_vfe_res->
+		vfe_dev[!vfe_dev->pdev->id]->vfe_open_cnt)) {
+		/* Fill other VFE debug Info */
+		vfe_dev->hw_info->vfe_ops.irq_ops.read_irq_status(
+			vfe_dev->common_data->dual_vfe_res->
+			vfe_dev[!vfe_dev->pdev->id],
+			&irq_debug->irq_status0[!vfe_dev->pdev->id],
+			&irq_debug->irq_status1[!vfe_dev->pdev->id]);
+		irq_debug->ping_pong_status[!vfe_dev->pdev->id] =
+			vfe_dev->hw_info->vfe_ops.axi_ops.
+			get_pingpong_status(vfe_dev->common_data->
+			dual_vfe_res->vfe_dev[!vfe_dev->pdev->id]);
+	}
+	vfe_dev->common_data->vfe_irq_dump.current_irq_index++;
+	spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_irq_dump_lock, flags);
+}
+
+void msm_isp_prepare_tasklet_debug_info(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp ts)
+{
+	struct msm_vfe_irq_debug_info *irq_debug;
+	uint8_t current_index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_tasklet_dump_lock, flags);
+	current_index = vfe_dev->common_data->vfe_irq_dump.
+		current_tasklet_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE;
+	irq_debug = &vfe_dev->common_data->vfe_irq_dump.
+		tasklet_debug[current_index];
+	irq_debug->vfe_id = vfe_dev->pdev->id;
+	irq_debug->core_id = smp_processor_id();
+	irq_debug->ts = ts;
+	irq_debug->irq_status0[vfe_dev->pdev->id] = irq_status0;
+	irq_debug->irq_status1[vfe_dev->pdev->id] = irq_status1;
+	irq_debug->ping_pong_status[vfe_dev->pdev->id] =
+		vfe_dev->hw_info->vfe_ops.axi_ops.
+		get_pingpong_status(vfe_dev);
+	vfe_dev->common_data->vfe_irq_dump.current_tasklet_index++;
+	spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_tasklet_dump_lock, flags);
+}
+
+static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1)
+{
+	unsigned long flags;
+	struct msm_vfe_tasklet_queue_cmd *queue_cmd = NULL;
+	struct msm_vfe_tasklet *tasklet;
+
+	if (vfe_dev->is_split)
+		tasklet = &vfe_dev->common_data->tasklets[MAX_VFE];
+	else
+		tasklet = &vfe_dev->common_data->tasklets[vfe_dev->pdev->id];
+
+	spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+	queue_cmd = &tasklet->tasklet_queue_cmd[tasklet->taskletq_idx];
+	if (queue_cmd->cmd_used) {
+		pr_err_ratelimited("%s: Tasklet queue overflow: %d\n",
+			__func__, vfe_dev->pdev->id);
+		spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+		return;
+	}
+	atomic_add(1, &vfe_dev->irq_cnt);
+	queue_cmd->vfeInterruptStatus0 = irq_status0;
+	queue_cmd->vfeInterruptStatus1 = irq_status1;
+	msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev);
+
+	queue_cmd->cmd_used = 1;
+	queue_cmd->vfe_dev = vfe_dev;
+
+	tasklet->taskletq_idx = (tasklet->taskletq_idx + 1) %
+		MSM_VFE_TASKLETQ_SIZE;
+	list_add_tail(&queue_cmd->list, &tasklet->tasklet_q);
+	spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+	tasklet_schedule(&tasklet->tasklet);
+}
+
+irqreturn_t msm_isp_process_irq(int irq_num, void *data)
+{
+	struct vfe_device *vfe_dev = (struct vfe_device *) data;
+	uint32_t irq_status0, irq_status1;
+	uint32_t error_mask0, error_mask1;
+
+	vfe_dev->hw_info->vfe_ops.irq_ops.
+		read_and_clear_irq_status(vfe_dev, &irq_status0, &irq_status1);
+
+	if ((irq_status0 == 0) && (irq_status1 == 0)) {
+		ISP_DBG("%s:VFE%d irq_status0 & 1 are both 0\n",
+			__func__, vfe_dev->pdev->id);
+		return IRQ_HANDLED;
+	}
+	if (vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq) {
+		vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq(
+				vfe_dev, irq_status0);
+	}
+	if (msm_isp_process_overflow_irq(vfe_dev,
+		&irq_status0, &irq_status1, 0)) {
+		/* if overflow initiated no need to handle the interrupts */
+		pr_err("overflow processed\n");
+		return IRQ_HANDLED;
+	}
+
+	vfe_dev->hw_info->vfe_ops.core_ops.
+		get_error_mask(&error_mask0, &error_mask1);
+	error_mask0 &= irq_status0;
+	error_mask1 &= irq_status1;
+	irq_status0 &= ~error_mask0;
+	irq_status1 &= ~error_mask1;
+	if ((error_mask0 != 0) || (error_mask1 != 0))
+		msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1);
+
+	if ((irq_status0 == 0) && (irq_status1 == 0) &&
+		(!(((error_mask0 != 0) || (error_mask1 != 0)) &&
+		 vfe_dev->error_info.error_count == 1))) {
+		ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__);
+		return IRQ_HANDLED;
+	}
+	msm_isp_prepare_irq_debug_info(vfe_dev, irq_status0, irq_status1);
+	msm_isp_enqueue_tasklet_cmd(vfe_dev, irq_status0, irq_status1);
+
+	return IRQ_HANDLED;
+}
+
+void msm_isp_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct msm_vfe_tasklet *tasklet = (struct msm_vfe_tasklet *)data;
+	struct vfe_device *vfe_dev;
+	struct msm_vfe_irq_ops *irq_ops;
+	struct msm_vfe_tasklet_queue_cmd *queue_cmd;
+	struct msm_isp_timestamp ts;
+	uint32_t irq_status0, irq_status1;
+
+	while (1) {
+		spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+		queue_cmd = list_first_entry_or_null(&tasklet->tasklet_q,
+			struct msm_vfe_tasklet_queue_cmd, list);
+		if (!queue_cmd) {
+			spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+			break;
+		}
+		list_del_init(&queue_cmd->list);
+		vfe_dev = queue_cmd->vfe_dev;
+		queue_cmd->cmd_used = 0;
+		queue_cmd->vfe_dev = NULL;
+		irq_status0 = queue_cmd->vfeInterruptStatus0;
+		irq_status1 = queue_cmd->vfeInterruptStatus1;
+		ts = queue_cmd->ts;
+		spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+		if (vfe_dev->vfe_open_cnt == 0) {
+			pr_err("%s: VFE%d open cnt = %d, irq %x/%x\n",
+			__func__, vfe_dev->pdev->id, vfe_dev->vfe_open_cnt,
+			irq_status0, irq_status1);
+			continue;
+		}
+		atomic_sub(1, &vfe_dev->irq_cnt);
+		msm_isp_prepare_tasklet_debug_info(vfe_dev,
+			irq_status0, irq_status1, ts);
+		irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
+		irq_ops->process_reset_irq(vfe_dev,
+			irq_status0, irq_status1);
+		irq_ops->process_halt_irq(vfe_dev,
+			irq_status0, irq_status1);
+		if (atomic_read(&vfe_dev->error_info.overflow_state)
+			!= NO_OVERFLOW) {
+			ISP_DBG("%s: Recovery in processing, Ignore IRQs!!!\n",
+				__func__);
+			continue;
+		}
+		msm_isp_process_error_info(vfe_dev);
+		irq_ops->process_stats_irq(vfe_dev,
+			irq_status0, irq_status1, &ts);
+		irq_ops->process_axi_irq(vfe_dev,
+			irq_status0, irq_status1, &ts);
+		irq_ops->process_camif_irq(vfe_dev,
+			irq_status0, irq_status1, &ts);
+		irq_ops->process_reg_update(vfe_dev,
+			irq_status0, irq_status1, &ts);
+		irq_ops->process_epoch_irq(vfe_dev,
+			irq_status0, irq_status1, &ts);
+	}
+}
+
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
+{
+	struct msm_vfe_axi_src_state *src_state = arg;
+
+	if (src_state->input_src >= VFE_SRC_MAX)
+		return -EINVAL;
+	vfe_dev->axi_data.src_info[src_state->input_src].active =
+	src_state->src_active;
+	vfe_dev->axi_data.src_info[src_state->input_src].frame_id =
+	src_state->src_frame_id;
+	return 0;
+}
+
+static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain,
+	struct device *dev, unsigned long iova, int flags, void *token)
+{
+	struct vfe_device *vfe_dev = NULL;
+
+	if (token) {
+		vfe_dev = (struct vfe_device *)token;
+		vfe_dev->page_fault_addr = iova;
+		if (!vfe_dev->buf_mgr || !vfe_dev->buf_mgr->ops ||
+			!vfe_dev->axi_data.num_active_stream) {
+			pr_err("%s:%d buf_mgr %pK active strms %d\n", __func__,
+				__LINE__, vfe_dev->buf_mgr,
+				vfe_dev->axi_data.num_active_stream);
+			goto end;
+		}
+
+		mutex_lock(&vfe_dev->core_mutex);
+		if (vfe_dev->vfe_open_cnt > 0) {
+			pr_err_ratelimited("%s: fault address is %lx\n",
+				__func__, iova);
+			msm_isp_process_iommu_page_fault(vfe_dev);
+		} else {
+			pr_err("%s: no handling, vfe open cnt = %d\n",
+				__func__, vfe_dev->vfe_open_cnt);
+		}
+		mutex_unlock(&vfe_dev->core_mutex);
+	} else {
+		ISP_DBG("%s:%d] no token received: %pK\n",
+			__func__, __LINE__, token);
+		goto end;
+	}
+end:
+	return;
+}
+
+int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
+	long rc = 0;
+
+	ISP_DBG("%s open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt);
+
+	if (vfe_dev->common_data == NULL ||
+		vfe_dev->common_data->dual_vfe_res == NULL) {
+		pr_err("%s: Error in probe. No common_data or dual vfe res\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vfe_dev->realtime_mutex);
+	mutex_lock(&vfe_dev->core_mutex);
+
+	if (vfe_dev->vfe_open_cnt++) {
+		mutex_unlock(&vfe_dev->core_mutex);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		return 0;
+	}
+
+	vfe_dev->reset_pending = 0;
+	vfe_dev->isp_sof_debug = 0;
+	vfe_dev->isp_raw0_debug = 0;
+	vfe_dev->isp_raw1_debug = 0;
+	vfe_dev->isp_raw2_debug = 0;
+
+	if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) {
+		pr_err("%s: init hardware failed\n", __func__);
+		vfe_dev->vfe_open_cnt--;
+		mutex_unlock(&vfe_dev->core_mutex);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		return -EBUSY;
+	}
+
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.clear_status_reg(vfe_dev);
+
+	vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base);
+	ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version);
+	rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 1, 1);
+	if (rc <= 0) {
+		pr_err("%s: reset timeout\n", __func__);
+		vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
+		vfe_dev->vfe_open_cnt--;
+		mutex_unlock(&vfe_dev->core_mutex);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		return -EINVAL;
+	}
+
+	vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
+
+	vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr,
+		"msm_isp");
+
+	memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
+	memset(&vfe_dev->stats_data, 0,
+		sizeof(struct msm_vfe_stats_shared_data));
+	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+	memset(&vfe_dev->fetch_engine_info, 0,
+		sizeof(vfe_dev->fetch_engine_info));
+	vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
+	vfe_dev->axi_data.enable_frameid_recovery = 0;
+	vfe_dev->vt_enable = 0;
+	vfe_dev->reg_update_requested = 0;
+	/* Register page fault handler */
+	vfe_dev->buf_mgr->pagefault_debug_disable = 0;
+	/* initialize pd_buf_idx with an invalid index 0xF */
+	vfe_dev->common_data->pd_buf_idx = 0xF;
+
+	cam_smmu_reg_client_page_fault_handler(
+			vfe_dev->buf_mgr->iommu_hdl,
+			msm_vfe_iommu_fault_handler,
+			NULL,
+			vfe_dev);
+	mutex_unlock(&vfe_dev->core_mutex);
+	mutex_unlock(&vfe_dev->realtime_mutex);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_AVTIMER
+static void msm_isp_end_avtimer(void)
+{
+	msm_isp_stop_avtimer();
+}
+#else
+static void msm_isp_end_avtimer(void)
+{
+	pr_err("AV Timer is not supported\n");
+}
+#endif
+
+int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	long rc = 0;
+	int wm;
+	int i;
+	struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
+
+	ISP_DBG("%s E open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt);
+	mutex_lock(&vfe_dev->realtime_mutex);
+	mutex_lock(&vfe_dev->core_mutex);
+
+	if (!vfe_dev->vfe_open_cnt) {
+		pr_err("%s invalid state open cnt %d\n", __func__,
+			vfe_dev->vfe_open_cnt);
+		mutex_unlock(&vfe_dev->core_mutex);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		return -EINVAL;
+	}
+
+	if (vfe_dev->vfe_open_cnt > 1) {
+		vfe_dev->vfe_open_cnt--;
+		mutex_unlock(&vfe_dev->core_mutex);
+		mutex_unlock(&vfe_dev->realtime_mutex);
+		return 0;
+	}
+	MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev);
+	msm_isp_release_all_axi_stream(vfe_dev);
+	msm_isp_release_all_stats_stream(vfe_dev);
+
+	/* Unregister page fault handler */
+	cam_smmu_reg_client_page_fault_handler(
+		vfe_dev->buf_mgr->iommu_hdl,
+		NULL, NULL, vfe_dev);
+
+	rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
+	if (rc <= 0)
+		pr_err("%s: halt timeout rc=%ld\n", __func__, rc);
+
+	vfe_dev->hw_info->vfe_ops.core_ops.
+		update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
+	vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 0);
+
+	/* put scratch buf in all the wm */
+	for (wm = 0; wm < vfe_dev->axi_data.hw_info->num_wm; wm++) {
+		msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PING_FLAG);
+		msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PONG_FLAG);
+	}
+	vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
+	/* after regular hw stop, reduce open cnt */
+	vfe_dev->vfe_open_cnt--;
+	vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
+	if (vfe_dev->vt_enable) {
+		msm_isp_end_avtimer();
+		vfe_dev->vt_enable = 0;
+	}
+	for (i = 0; i < VFE_SRC_MAX; i++)
+		vfe_dev->axi_data.src_info[i].lpm = 0;
+	MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev);
+	vfe_dev->is_split = 0;
+
+	mutex_unlock(&vfe_dev->core_mutex);
+	mutex_unlock(&vfe_dev->realtime_mutex);
+	return 0;
+}
+
+void msm_isp_flush_tasklet(struct vfe_device *vfe_dev)
+{
+	unsigned long flags;
+	int i;
+	struct msm_vfe_tasklet_queue_cmd *queue_cmd, *q_cmd_next;
+	struct msm_vfe_tasklet *tasklet;
+
+	for (i = 0; i <= MAX_VFE; i++) {
+		if (i != vfe_dev->pdev->id &&
+			i != MAX_VFE)
+			continue;
+		tasklet = &vfe_dev->common_data->tasklets[i];
+		spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+		list_for_each_entry_safe(queue_cmd, q_cmd_next,
+			&tasklet->tasklet_q, list) {
+			if (queue_cmd->vfe_dev != vfe_dev)
+				continue;
+			list_del_init(&queue_cmd->list);
+			queue_cmd->cmd_used = 0;
+		}
+		spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+		tasklet_kill(&tasklet->tasklet);
+	}
+	atomic_set(&vfe_dev->irq_cnt, 0);
+
+}
+
+void msm_isp_irq_debug_dump(struct vfe_device *vfe_dev)
+{
+
+	uint8_t i, dump_index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_irq_dump_lock, flags);
+	dump_index = vfe_dev->common_data->vfe_irq_dump.
+		current_irq_index;
+	for (i = 0; i < MAX_VFE_IRQ_DEBUG_DUMP_SIZE; i++) {
+		trace_msm_cam_ping_pong_debug_dump(
+			vfe_dev->common_data->vfe_irq_dump.
+			irq_debug[dump_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE]);
+		dump_index++;
+	}
+	spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_irq_dump_lock, flags);
+}
+
+
+void msm_isp_tasklet_debug_dump(struct vfe_device *vfe_dev)
+{
+
+	uint8_t i, dump_index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_tasklet_dump_lock, flags);
+	dump_index = vfe_dev->common_data->vfe_irq_dump.
+		current_tasklet_index;
+	for (i = 0; i < MAX_VFE_IRQ_DEBUG_DUMP_SIZE; i++) {
+		trace_msm_cam_tasklet_debug_dump(
+			vfe_dev->common_data->vfe_irq_dump.
+			tasklet_debug[
+			dump_index % MAX_VFE_IRQ_DEBUG_DUMP_SIZE]);
+		dump_index++;
+	}
+	spin_unlock_irqrestore(&vfe_dev->common_data->vfe_irq_dump.
+		common_dev_tasklet_dump_lock, flags);
+}
+
+void msm_isp_dump_ping_pong_mismatch(struct vfe_device *vfe_dev)
+{
+
+	trace_msm_cam_string(" ***** msm_isp_dump_irq_debug ****");
+	msm_isp_irq_debug_dump(vfe_dev);
+	trace_msm_cam_string(" ***** msm_isp_dump_taskelet_debug ****");
+	msm_isp_tasklet_debug_dump(vfe_dev);
+}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
new file mode 100644
index 0000000..3ce5c47
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_ISP_UTIL_H__
+#define __MSM_ISP_UTIL_H__
+
+#include "msm_isp.h"
+#include <soc/qcom/camera2.h>
+#include "msm_camera_io_util.h"
+
+/* #define CONFIG_MSM_ISP_DBG 1 */
+
+#ifdef CONFIG_MSM_ISP_DBG
+#define ISP_DBG(fmt, args...) printk(fmt, ##args)
+#else
+#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define ALT_VECTOR_IDX(x) {x = 3 - x; }
+
+uint32_t msm_isp_get_framedrop_period(
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern);
+void msm_isp_reset_burst_count_and_frame_drop(
+	struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info);
+
+int msm_isp_init_bandwidth_mgr(struct vfe_device *vfe_dev,
+			enum msm_isp_hw_client client);
+int msm_isp_update_bandwidth(enum msm_isp_hw_client client,
+			uint64_t ab, uint64_t ib);
+void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev,
+				      struct msm_isp_statistics *stats);
+void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
+void msm_isp_util_update_clk_rate(long clock_rate);
+void msm_isp_update_req_history(uint32_t client, uint64_t ab,
+				uint64_t ib,
+				struct msm_isp_bandwidth_info *client_info,
+				unsigned long long ts);
+void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client);
+
+int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub);
+
+int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub);
+
+int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_send_event(struct vfe_device *vfe_dev,
+	uint32_t type, struct msm_isp_event_data *event_data);
+int msm_isp_cal_word_per_line(uint32_t output_format,
+	uint32_t pixel_per_line);
+int msm_isp_get_bit_per_pixel(uint32_t output_format);
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
+irqreturn_t msm_isp_process_irq(int irq_num, void *data);
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
+void msm_isp_do_tasklet(unsigned long data);
+void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev);
+void msm_isp_process_error_info(struct vfe_device *vfe_dev);
+int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
+int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
+long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
+	struct msm_vfe_fetch_engine_info *fetch_engine_info);
+void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format);
+void msm_isp_flush_tasklet(struct vfe_device *vfe_dev);
+void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
+	struct vfe_device *vfe_dev);
+void msm_isp_dump_ping_pong_mismatch(struct vfe_device *vfe_dev);
+int msm_isp_process_overflow_irq(
+	struct vfe_device *vfe_dev,
+	uint32_t *irq_status0, uint32_t *irq_status1,
+	uint8_t force_overflow);
+void msm_isp_prepare_irq_debug_info(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1);
+void msm_isp_prepare_tasklet_debug_info(struct vfe_device *vfe_dev,
+	uint32_t irq_status0, uint32_t irq_status1,
+	struct msm_isp_timestamp ts);
+void msm_isp_irq_debug_dump(struct vfe_device *vfe_dev);
+void msm_isp_tasklet_debug_dump(struct vfe_device *vfe_dev);
+int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg);
+#endif /* __MSM_ISP_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/ispif/Makefile b/drivers/media/platform/msm/camera_v2/ispif/Makefile
new file mode 100644
index 0000000..236ec73
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSM_CSID) += msm_ispif.o
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
new file mode 100644
index 0000000..512fdb9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -0,0 +1,2148 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/compat.h>
+#include <media/msmb_isp.h>
+#include <linux/ratelimit.h>
+
+#include "msm_ispif.h"
+#include "msm.h"
+#include "msm_sd.h"
+#include "msm_camera_io_util.h"
+#include "cam_hw_ops.h"
+#include "cam_soc_api.h"
+
+#ifdef CONFIG_MSM_ISPIF_V1
+#include "msm_ispif_hwreg_v1.h"
+#elif defined CONFIG_MSM_ISPIF_V2
+#include "msm_ispif_hwreg_v2.h"
+#else
+#include "msm_ispif_hwreg_v3.h"
+#endif
+
+#define V4L2_IDENT_ISPIF                      50001
+#define MSM_ISPIF_DRV_NAME                    "msm_ispif"
+
+#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00
+#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY  0x01
+#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY    0x02
+
+#define ISPIF_TIMEOUT_SLEEP_US                1000
+#define ISPIF_TIMEOUT_ALL_US               1000000
+#define ISPIF_SOF_DEBUG_COUNT                    5
+
+/* 3D Threshold value according guidelines for line width 1280 */
+#define STEREO_DEFAULT_3D_THRESHOLD           0x36
+
+/*
+ * Overflows before restarting interface during stereo usecase
+ * to give some tolerance for cases when the two sensors sync fails
+ * this value is chosen by experiment
+ */
+#define MAX_PIX_OVERFLOW_ERROR_COUNT 10
+static int pix_overflow_error_count[VFE_MAX] = { 0 };
+
+
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define CDBG(fmt, args...)
+#endif
+
+/* Backward interface compatibility for 3D THRESHOLD calculation */
+#define ISPIF_USE_DEFAULT_THRESHOLD (0)
+#define ISPIF_CALCULATE_THRESHOLD (1)
+
+static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable);
+static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
+static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
+				struct ispif_device *ispif,
+				struct msm_ispif_param_data_ext *params);
+
+static int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
+	struct platform_device *pdev);
+
+static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
+{
+	if (!ispif->enb_dump_reg)
+		return;
+
+	if (!ispif->base) {
+		pr_err("%s: null pointer for the ispif base\n", __func__);
+		return;
+	}
+
+	msm_camera_io_dump(ispif->base, 0x250, 0);
+}
+
+
+static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
+	enum msm_ispif_vfe_intf intf_type)
+{
+	return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ||
+		(intf_type >= VFE_MAX)) ? false : true;
+}
+
+#ifdef CONFIG_COMPAT
+struct ispif_cfg_data_ext_32 {
+	enum ispif_cfg_type_t cfg_type;
+	compat_caddr_t data;
+	uint32_t size;
+};
+
+#define VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext_32)
+#endif
+
+static void msm_ispif_get_pack_mask_from_cfg(
+	struct msm_ispif_pack_cfg *pack_cfg,
+	struct msm_ispif_params_entry *entry,
+	uint32_t *pack_mask)
+{
+	int i;
+	uint32_t temp;
+
+	if (WARN_ON(!entry))
+		return;
+
+	memset(pack_mask, 0, sizeof(uint32_t) * 2);
+	for (i = 0; i < entry->num_cids; i++) {
+		temp = (pack_cfg[entry->cids[i]].pack_mode & 0x3)|
+			(pack_cfg[entry->cids[i]].even_odd_sel & 0x1) << 2 |
+			(pack_cfg[entry->cids[i]].pixel_swap_en & 0x1) << 3;
+		temp = (temp & 0xF) << ((entry->cids[i] % CID8) * 4);
+
+		if (entry->cids[i] > CID7)
+			pack_mask[1] |= temp;
+		else
+			pack_mask[0] |= temp;
+		CDBG("%s:num %d cid %d mode %d pack_mask %x %x\n",
+			__func__, entry->num_cids, entry->cids[i],
+			pack_cfg[entry->cids[i]].pack_mode,
+			pack_mask[0], pack_mask[1]);
+
+	}
+}
+
+static int msm_ispif_config2(struct ispif_device *ispif,
+	void *data)
+{
+	int rc = 0, i = 0;
+	enum msm_ispif_intftype intftype;
+	enum msm_ispif_vfe_intf vfe_intf;
+	uint32_t pack_cfg_mask[2];
+	struct msm_ispif_param_data_ext *params =
+		(struct msm_ispif_param_data_ext *)data;
+
+	if (WARN_ON(!ispif) || WARN_ON(!params))
+		return -EINVAL;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	for (i = 0; i < params->num; i++) {
+		int j;
+
+		if (params->entries[i].num_cids > MAX_CID_CH_PARAM_ENTRY)
+			return -EINVAL;
+		for (j = 0; j < params->entries[i].num_cids; j++)
+			if (params->entries[i].cids[j] >= CID_MAX)
+				return -EINVAL;
+	}
+
+	for (i = 0; i < params->num; i++) {
+		intftype = params->entries[i].intftype;
+		vfe_intf = params->entries[i].vfe_intf;
+
+		CDBG("%s, num %d intftype %x, vfe_intf %d, csid %d\n", __func__,
+			params->num, intftype, vfe_intf,
+			params->entries[i].csid);
+
+		if ((intftype >= INTF_MAX) ||
+			(vfe_intf >=  ispif->vfe_info.num_vfe) ||
+			(ispif->csid_version <= CSID_VERSION_V22 &&
+			(vfe_intf > VFE0))) {
+			pr_err("%s: VFEID %d and CSID version %d mismatch\n",
+				__func__, vfe_intf, ispif->csid_version);
+			return -EINVAL;
+		}
+
+		msm_ispif_get_pack_mask_from_cfg(params->pack_cfg,
+				&params->entries[i], pack_cfg_mask);
+		msm_ispif_cfg_pack_mode(ispif, intftype, vfe_intf,
+			pack_cfg_mask);
+	}
+	return rc;
+}
+
+static long msm_ispif_cmd_ext(struct v4l2_subdev *sd,
+	void *arg)
+{
+	long rc = 0;
+	struct ispif_device *ispif =
+		(struct ispif_device *)v4l2_get_subdevdata(sd);
+	struct ispif_cfg_data_ext pcdata;
+	struct msm_ispif_param_data_ext *params = NULL;
+#ifdef CONFIG_COMPAT
+	struct ispif_cfg_data_ext_32 *pcdata32 =
+		(struct ispif_cfg_data_ext_32 *)arg;
+
+	if (pcdata32 == NULL) {
+		pr_err("Invalid params passed from user\n");
+		return -EINVAL;
+	}
+	pcdata.cfg_type  = pcdata32->cfg_type;
+	pcdata.size = pcdata32->size;
+	pcdata.data = compat_ptr(pcdata32->data);
+
+#else
+	struct ispif_cfg_data_ext *pcdata64 =
+		(struct ispif_cfg_data_ext *)arg;
+
+	if (pcdata64 == NULL) {
+		pr_err("Invalid params passed from user\n");
+		return -EINVAL;
+	}
+	pcdata.cfg_type  = pcdata64->cfg_type;
+	pcdata.size = pcdata64->size;
+	pcdata.data = pcdata64->data;
+#endif
+	if (pcdata.size != sizeof(struct msm_ispif_param_data_ext)) {
+		pr_err("%s: payload size mismatch\n", __func__);
+		return -EINVAL;
+	}
+
+	params = kzalloc(sizeof(struct msm_ispif_param_data_ext), GFP_KERNEL);
+	if (!params) {
+		CDBG("%s: params alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	if (copy_from_user(params, (void __user *)(pcdata.data),
+		pcdata.size)) {
+		kfree(params);
+		return -EFAULT;
+	}
+
+	mutex_lock(&ispif->mutex);
+	rc = msm_ispif_dispatch_cmd(pcdata.cfg_type, ispif, params);
+	mutex_unlock(&ispif->mutex);
+	kfree(params);
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_ispif_subdev_ioctl_compat(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	if (WARN_ON(!sd))
+		return -EINVAL;
+
+	switch (cmd) {
+	case VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT:
+		return msm_ispif_cmd_ext(sd, arg);
+
+	default:
+		return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg);
+	}
+}
+static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	if (is_compat_task())
+		return msm_ispif_subdev_ioctl_compat(sd, cmd, arg);
+	else
+		return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg);
+}
+#else
+static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg);
+}
+#endif
+static void msm_ispif_put_regulator(struct ispif_device *ispif_dev)
+{
+	int i;
+
+	for (i = 0; i < ispif_dev->ispif_vdd_count; i++) {
+		regulator_put(ispif_dev->ispif_vdd[i]);
+		ispif_dev->ispif_vdd[i] = NULL;
+	}
+	for (i = 0; i < ispif_dev->vfe_vdd_count; i++) {
+		regulator_put(ispif_dev->vfe_vdd[i]);
+		ispif_dev->vfe_vdd[i] = NULL;
+	}
+}
+
+static inline int __get_vdd(struct platform_device *pdev,
+				struct regulator **reg, const char *vdd)
+{
+	int rc = 0;
+	*reg = regulator_get(&pdev->dev, vdd);
+	if (IS_ERR_OR_NULL(*reg)) {
+		rc = PTR_ERR(*reg);
+		rc = rc ? rc : -EINVAL;
+		pr_err("%s: Regulator %s get failed %d\n", __func__, vdd, rc);
+		*reg = NULL;
+	}
+	return rc;
+}
+
+static int msm_ispif_get_regulator_info(struct ispif_device *ispif_dev,
+					struct platform_device *pdev)
+{
+	int rc;
+	const char *vdd_name;
+	struct device_node *of_node;
+	int i;
+	int count;
+
+	of_node = pdev->dev.of_node;
+
+	count = of_property_count_strings(of_node,
+					"qcom,vdd-names");
+	if (count == 0) {
+		pr_err("%s: no regulators found\n", __func__);
+		return -EINVAL;
+	}
+
+	if (WARN_ON(count > (ISPIF_VDD_INFO_MAX + ISPIF_VFE_VDD_INFO_MAX)))
+		pr_err("%s: count is greater is 4", __func__);
+	ispif_dev->vfe_vdd_count = 0;
+	ispif_dev->ispif_vdd_count = 0;
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(
+				of_node, "qcom,vdd-names",
+				i, &vdd_name);
+		if (rc < 0) {
+			pr_err("%s: read property qcom,ispif-vdd-names at index %d failed\n",
+				__func__, i);
+			goto err;
+		}
+		if (strnstr(vdd_name, "vfe", strlen(vdd_name))) {
+			if (WARN_ON((ispif_dev->vfe_vdd_count >=
+				ISPIF_VFE_VDD_INFO_MAX))) {
+				pr_err("%s: count is greater is 4", __func__);
+				return -EINVAL;
+			};
+			rc = __get_vdd(pdev,
+				&ispif_dev->vfe_vdd[ispif_dev->vfe_vdd_count],
+				vdd_name);
+			if (rc == 0)
+				ispif_dev->vfe_vdd_count++;
+		} else {
+			if (WARN_ON((ispif_dev->vfe_vdd_count >=
+				ISPIF_VFE_VDD_INFO_MAX))) {
+				pr_err("%s: count is greater is 4", __func__);
+				return -EINVAL;
+			};
+			rc = __get_vdd(pdev,
+				&ispif_dev->ispif_vdd
+					[ispif_dev->ispif_vdd_count],
+				vdd_name);
+			if (rc == 0)
+				ispif_dev->ispif_vdd_count++;
+		}
+		if (rc)
+			goto err;
+	}
+	return 0;
+err:
+	for (i = 0; i < ispif_dev->vfe_vdd_count; i++) {
+		regulator_put(ispif_dev->vfe_vdd[i]);
+		ispif_dev->vfe_vdd[i] = NULL;
+	}
+	for (i = 0; i < ispif_dev->ispif_vdd_count; i++) {
+		regulator_put(ispif_dev->ispif_vdd[i]);
+		ispif_dev->ispif_vdd[i] = NULL;
+	}
+	ispif_dev->ispif_vdd_count = 0;
+	ispif_dev->vfe_vdd_count = 0;
+	return rc;
+}
+
+static int msm_ispif_set_regulators(struct regulator **regs, int count,
+	uint8_t enable)
+{
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (enable) {
+			rc = regulator_enable(regs[i]);
+			if (rc)
+				goto err;
+		} else {
+			rc |= regulator_disable(regs[i]);
+		}
+	}
+	if (rc)
+		pr_err("%s: Regulator disable failed\n", __func__);
+	return rc;
+err:
+	pr_err("%s: Regulator enable failed\n", __func__);
+	for (i--; i >= 0; i--)
+		regulator_disable(regs[i]);
+	return rc;
+}
+
+static int msm_ispif_reset_hw(struct ispif_device *ispif)
+{
+	int rc = 0;
+	long timeout = 0;
+
+	ispif->clk_idx = 0;
+
+	/* Turn ON VFE regulators before enabling the vfe clocks */
+	rc = msm_ispif_set_regulators(ispif->vfe_vdd, ispif->vfe_vdd_count, 1);
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camera_clk_enable(&ispif->pdev->dev,
+		ispif->clk_info, ispif->clks,
+		ispif->num_clk, 1);
+	if (rc < 0) {
+		pr_err("%s: cannot enable clock, error = %d",
+			__func__, rc);
+		goto reg_disable;
+	} else {
+		/* This is set when device is 8974 */
+		ispif->clk_idx = 1;
+	}
+	memset(ispif->stereo_configured, 0, sizeof(ispif->stereo_configured));
+	atomic_set(&ispif->reset_trig[VFE0], 1);
+	/* initiate reset of ISPIF */
+	msm_camera_io_w(ISPIF_RST_CMD_MASK,
+				ispif->base + ISPIF_RST_CMD_ADDR);
+
+	timeout = wait_for_completion_interruptible_timeout(
+			&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
+	CDBG("%s: VFE0 done\n", __func__);
+
+	if (timeout <= 0) {
+		rc = -ETIMEDOUT;
+		pr_err("%s: VFE0 reset wait timeout\n", __func__);
+		goto clk_disable;
+	}
+
+	if (ispif->hw_num_isps > 1) {
+		atomic_set(&ispif->reset_trig[VFE1], 1);
+		msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
+					ispif->base + ISPIF_RST_CMD_1_ADDR);
+		timeout = wait_for_completion_interruptible_timeout(
+				&ispif->reset_complete[VFE1],
+				msecs_to_jiffies(500));
+		CDBG("%s: VFE1 done\n", __func__);
+		if (timeout <= 0) {
+			pr_err("%s: VFE1 reset wait timeout\n", __func__);
+			rc = -ETIMEDOUT;
+		}
+	}
+
+clk_disable:
+	if (ispif->clk_idx == 1) {
+		rc = rc ? rc : msm_camera_clk_enable(&ispif->pdev->dev,
+			ispif->clk_info, ispif->clks,
+			ispif->num_clk, 0);
+	}
+
+reg_disable:
+	rc = rc ? rc :  msm_ispif_set_regulators(ispif->vfe_vdd,
+					ispif->vfe_vdd_count, 0);
+
+	return rc;
+}
+
+static int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
+	struct platform_device *pdev)
+{
+	uint32_t num_ahb_clk = 0, non_ahb_clk = 0;
+	size_t num_clks;
+	int i, rc;
+	int j;
+	struct clk **clks, **temp_clks;
+	struct msm_cam_clk_info *clk_info, *temp_clk_info;
+
+	struct device_node *of_node;
+
+	of_node = pdev->dev.of_node;
+
+	rc = msm_camera_get_clk_info(pdev, &clk_info,
+			&clks, &num_clks);
+
+	if (rc)
+		return rc;
+
+	/*
+	 * reshuffle the clock arrays so that the ahb clocks are
+	 * at the beginning of array
+	 */
+	temp_clks = kcalloc(num_clks, sizeof(struct clk *),
+				GFP_KERNEL);
+	temp_clk_info = kcalloc(num_clks, sizeof(struct msm_cam_clk_info),
+				GFP_KERNEL);
+	if (!temp_clks || !temp_clk_info) {
+		rc = -ENOMEM;
+		kfree(temp_clk_info);
+		kfree(temp_clks);
+		goto alloc_fail;
+	}
+	j = 0;
+	for (i = 0; i < num_clks; i++) {
+		if (strnstr(clk_info[i].clk_name,
+			"ahb", strlen(clk_info[i].clk_name))) {
+			temp_clk_info[j] = clk_info[i];
+			temp_clks[j] = clks[i];
+			j++;
+			num_ahb_clk++;
+		}
+	}
+	for (i = 0; i < num_clks; i++) {
+		if (!strnstr(clk_info[i].clk_name,
+			"ahb", strlen(clk_info[i].clk_name))) {
+			temp_clk_info[j] = clk_info[i];
+			temp_clks[j] = clks[i];
+			j++;
+			non_ahb_clk++;
+		}
+	}
+
+	for (i = 0; i < num_clks; i++) {
+		clk_info[i] = temp_clk_info[i];
+		clks[i] = temp_clks[i];
+	}
+	kfree(temp_clk_info);
+	kfree(temp_clks);
+
+	ispif_dev->ahb_clk = clks;
+	ispif_dev->ahb_clk_info = clk_info;
+	ispif_dev->num_ahb_clk = num_ahb_clk;
+	ispif_dev->clk_info = clk_info + num_ahb_clk;
+	ispif_dev->clks = clks + num_ahb_clk;
+	ispif_dev->num_clk = non_ahb_clk;
+
+	return 0;
+alloc_fail:
+	msm_camera_put_clk_info(pdev, &clk_info, &clks, num_clks);
+	return rc;
+}
+
+static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable)
+{
+	int rc = 0;
+
+	rc = msm_cam_clk_enable(&ispif->pdev->dev,
+		ispif->ahb_clk_info, ispif->ahb_clk,
+		ispif->num_ahb_clk, enable);
+	if (rc < 0) {
+		pr_err("%s: cannot enable clock, error = %d",
+			__func__, rc);
+	}
+
+	return rc;
+}
+
+static int msm_ispif_reset(struct ispif_device *ispif)
+{
+	int rc = 0;
+	int i;
+
+	if (WARN_ON(!ispif))
+		return -EINVAL;
+
+	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
+	for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
+
+		msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
+			ispif->base + ISPIF_VFE_m_CTRL_0(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i));
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_0(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_1(i));
+		msm_camera_io_w(0xFFFFFFFF, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_2(i));
+
+		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i));
+
+		msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+			ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
+		msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+			ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
+		pr_debug("%s: base %pK", __func__, ispif->base);
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2));
+
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0));
+		msm_camera_io_w(0, ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1));
+	}
+
+	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	return rc;
+}
+
+static void msm_ispif_sel_csid_core(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
+{
+	uint32_t data;
+
+	if (WARN_ON((!ispif)))
+		return;
+
+	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+		pr_err("%s: invalid interface type\n", __func__);
+		return;
+	}
+
+	data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf));
+	switch (intftype) {
+	case PIX0:
+		data &= ~(BIT(1) | BIT(0));
+		data |= (uint32_t) csid;
+		break;
+	case RDI0:
+		data &= ~(BIT(5) | BIT(4));
+		data |= ((uint32_t) csid) << 4;
+		break;
+	case PIX1:
+		data &= ~(BIT(9) | BIT(8));
+		data |= ((uint32_t) csid) << 8;
+		break;
+	case RDI1:
+		data &= ~(BIT(13) | BIT(12));
+		data |= ((uint32_t) csid) << 12;
+		break;
+	case RDI2:
+		data &= ~(BIT(21) | BIT(20));
+		data |= ((uint32_t) csid) << 20;
+		break;
+	}
+
+	msm_camera_io_w_mb(data, ispif->base +
+		ISPIF_VFE_m_INPUT_SEL(vfe_intf));
+}
+
+static void msm_ispif_enable_crop(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel,
+	uint16_t end_pixel)
+{
+	uint32_t data;
+
+	if (WARN_ON((!ispif)))
+		return;
+
+	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+		pr_err("%s: invalid interface type\n", __func__);
+		return;
+	}
+
+	data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+	data |= (1 << (intftype + 7));
+	if (intftype == PIX0)
+		data |= 1 << PIX0_LINE_BUF_EN_BIT;
+	msm_camera_io_w(data,
+		ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf));
+
+	if (intftype == PIX0)
+		msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+			ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0));
+	else if (intftype == PIX1)
+		msm_camera_io_w_mb(start_pixel | (end_pixel << 16),
+			ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1));
+	else {
+		pr_err("%s: invalid intftype=%d\n", __func__, intftype);
+		WARN_ON(1);
+		return;
+	}
+}
+
+static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
+	uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable)
+{
+	uint32_t intf_addr, data;
+
+	if (WARN_ON((!ispif)))
+		return;
+
+	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+		pr_err("%s: invalid interface type\n", __func__);
+		return;
+	}
+
+	switch (intftype) {
+	case PIX0:
+		intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0);
+		break;
+	case RDI0:
+		intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0);
+		break;
+	case PIX1:
+		intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1);
+		break;
+	case RDI1:
+		intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1);
+		break;
+	case RDI2:
+		intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2);
+		break;
+	default:
+		pr_err("%s: invalid intftype=%d\n", __func__, intftype);
+		WARN_ON(1);
+		return;
+	}
+
+	data = msm_camera_io_r(ispif->base + intf_addr);
+	if (enable)
+		data |=  (uint32_t) cid_mask;
+	else
+		data &= ~((uint32_t) cid_mask);
+	msm_camera_io_w_mb(data, ispif->base + intf_addr);
+}
+
+static int msm_ispif_validate_intf_status(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf)
+{
+	int rc = 0;
+	uint32_t data = 0;
+
+	if (WARN_ON((!ispif)))
+		return -EINVAL;
+
+	if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+		pr_err("%s: invalid interface type\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (intftype) {
+	case PIX0:
+		data = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0));
+		break;
+	case RDI0:
+		data = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0));
+		break;
+	case PIX1:
+		data = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1));
+		break;
+	case RDI1:
+		data = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1));
+		break;
+	case RDI2:
+		data = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2));
+		break;
+	}
+	if ((data & 0xf) != 0xf)
+		rc = -EBUSY;
+	return rc;
+}
+
+static void msm_ispif_select_clk_mux(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
+{
+	uint32_t data = 0;
+
+	switch (intftype) {
+	case PIX0:
+		data = msm_camera_io_r(ispif->clk_mux_base);
+		data &= ~(0xf << (vfe_intf * 8));
+		data |= (csid << (vfe_intf * 8));
+		msm_camera_io_w(data, ispif->clk_mux_base);
+		break;
+
+	case RDI0:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (vfe_intf * 12));
+		data |= (csid << (vfe_intf * 12));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+
+	case PIX1:
+		data = msm_camera_io_r(ispif->clk_mux_base);
+		data &= ~(0xf0 << (vfe_intf * 8));
+		data |= (csid << (4 + (vfe_intf * 8)));
+		msm_camera_io_w(data, ispif->clk_mux_base);
+		break;
+
+	case RDI1:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (4 + (vfe_intf * 12)));
+		data |= (csid << (4 + (vfe_intf * 12)));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+
+	case RDI2:
+		data = msm_camera_io_r(ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		data &= ~(0xf << (8 + (vfe_intf * 12)));
+		data |= (csid << (8 + (vfe_intf * 12)));
+		msm_camera_io_w(data, ispif->clk_mux_base +
+			ISPIF_RDI_CLK_MUX_SEL_ADDR);
+		break;
+	}
+	CDBG("%s intftype %d data %x\n", __func__, intftype, data);
+	/* ensure clk mux is enabled */
+	mb();
+}
+
+static uint16_t msm_ispif_get_cids_mask_from_cfg(
+	struct msm_ispif_params_entry *entry)
+{
+	int i;
+	uint16_t cids_mask = 0;
+
+	if (WARN_ON(!entry)) {
+		pr_err("%s: invalid entry", __func__);
+		return cids_mask;
+	}
+
+	for (i = 0; i < entry->num_cids && i < MAX_CID_CH_PARAM_ENTRY; i++)
+		cids_mask |= (1 << entry->cids[i]);
+
+	return cids_mask;
+}
+
+static uint16_t msm_ispif_get_right_cids_mask_from_cfg(
+	struct msm_ispif_right_param_entry *entry, int num_cids)
+{
+	int i;
+	uint16_t cids_mask = 0;
+
+	if (WARN_ON(!entry))
+		return cids_mask;
+
+	for (i = 0; i < num_cids && i < MAX_CID_CH_PARAM_ENTRY; i++) {
+		if (entry->cids[i] < CID_MAX)
+			cids_mask |= (1 << entry->cids[i]);
+	}
+
+	return cids_mask;
+}
+
+static int msm_ispif_config(struct ispif_device *ispif,
+	void *data)
+{
+	int rc = 0, i = 0;
+	uint16_t cid_mask = 0;
+	uint16_t cid_right_mask = 0;
+	enum msm_ispif_intftype intftype;
+	enum msm_ispif_vfe_intf vfe_intf;
+	struct msm_ispif_param_data_ext *params =
+		(struct msm_ispif_param_data_ext *)data;
+
+	if (WARN_ON(!ispif) || WARN_ON(!params))
+		return -EINVAL;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (!msm_ispif_is_intf_valid(ispif->csid_version,
+				vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			return -EINVAL;
+		}
+		msm_camera_io_w(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+		msm_camera_io_w(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+		msm_camera_io_w_mb(0x0, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
+	}
+
+	for (i = 0; i < params->num; i++) {
+		intftype = params->entries[i].intftype;
+
+		vfe_intf = params->entries[i].vfe_intf;
+
+		CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
+			intftype, vfe_intf, params->entries[i].csid);
+
+		if ((intftype >= INTF_MAX) ||
+			(vfe_intf >=  ispif->vfe_info.num_vfe) ||
+			(ispif->csid_version <= CSID_VERSION_V22 &&
+			(vfe_intf > VFE0))) {
+			pr_err("%s: VFEID %d and CSID version %d mismatch\n",
+				__func__, vfe_intf, ispif->csid_version);
+			return -EINVAL;
+		}
+
+		if (ispif->csid_version >= CSID_VERSION_V30) {
+			msm_ispif_select_clk_mux(ispif, intftype,
+				params->entries[i].csid, vfe_intf);
+			if (intftype == PIX0 && params->stereo_enable &&
+			    params->right_entries[i].csid < CSID_MAX)
+				msm_ispif_select_clk_mux(ispif, PIX1,
+					params->right_entries[i].csid,
+					vfe_intf);
+		}
+
+		rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf);
+		if (rc) {
+			pr_err("%s:validate_intf_status failed, rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		msm_ispif_sel_csid_core(ispif, intftype,
+			params->entries[i].csid, vfe_intf);
+		if (intftype == PIX0 && params->stereo_enable &&
+		    params->right_entries[i].csid < CSID_MAX)
+			/* configure right stereo csid */
+			msm_ispif_sel_csid_core(ispif, PIX1,
+				params->right_entries[i].csid, vfe_intf);
+
+		cid_mask = msm_ispif_get_cids_mask_from_cfg(
+				&params->entries[i]);
+		msm_ispif_enable_intf_cids(ispif, intftype,
+			cid_mask, vfe_intf, 1);
+		if (params->stereo_enable)
+			cid_right_mask = msm_ispif_get_right_cids_mask_from_cfg(
+					&params->right_entries[i],
+					params->entries[i].num_cids);
+		else
+			cid_right_mask = 0;
+		if (cid_right_mask && params->stereo_enable)
+			/* configure right stereo cids */
+			msm_ispif_enable_intf_cids(ispif, PIX1,
+				cid_right_mask, vfe_intf, 1);
+		if (params->entries[i].crop_enable)
+			msm_ispif_enable_crop(ispif, intftype, vfe_intf,
+				params->entries[i].crop_start_pixel,
+				params->entries[i].crop_end_pixel);
+	}
+
+	for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) {
+		msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+
+		msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
+
+		msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+
+		msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
+
+		msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
+
+		msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+			ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
+	}
+
+	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+		ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	return rc;
+}
+
+static void msm_ispif_config_stereo(struct ispif_device *ispif,
+	struct msm_ispif_param_data_ext *params, int use_line_width) {
+
+	int i;
+	enum msm_ispif_vfe_intf vfe_intf;
+	uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD;
+
+	if (params->num > MAX_PARAM_ENTRIES)
+		return;
+
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+			pr_err("%s: invalid interface type %d\n", __func__,
+				vfe_intf);
+			return;
+		}
+		if (params->entries[i].intftype == PIX0 &&
+			params->stereo_enable &&
+			params->right_entries[i].csid < CSID_MAX &&
+			!ispif->stereo_configured[vfe_intf]) {
+			msm_camera_io_w_mb(0x3,
+				ispif->base + ISPIF_VFE_m_OUTPUT_SEL(vfe_intf));
+			if (use_line_width &&
+				(params->line_width[vfe_intf] > 0))
+				stereo_3d_threshold =
+					(params->line_width[vfe_intf] +
+							2 * 6 - 1) / (2 * 6);
+			msm_camera_io_w_mb(stereo_3d_threshold,
+				ispif->base +
+					ISPIF_VFE_m_3D_THRESHOLD(vfe_intf));
+			ispif->stereo_configured[vfe_intf] = 1;
+		}
+	}
+}
+
+static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits,
+	struct msm_ispif_param_data_ext *params)
+{
+	uint8_t vc;
+	int i, k;
+	enum msm_ispif_intftype intf_type;
+	enum msm_ispif_cid cid;
+	enum msm_ispif_vfe_intf vfe_intf;
+
+	if (WARN_ON(!ispif) || WARN_ON(!params))
+		return;
+
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			return;
+		}
+		if (params->entries[i].num_cids > MAX_CID_CH_PARAM_ENTRY) {
+			pr_err("%s: out of range of cid_num %d\n",
+				__func__, params->entries[i].num_cids);
+			return;
+		}
+	}
+
+	for (i = 0; i < params->num; i++) {
+		intf_type = params->entries[i].intftype;
+		vfe_intf = params->entries[i].vfe_intf;
+		for (k = 0; k < params->entries[i].num_cids; k++) {
+			cid = params->entries[i].cids[k];
+			vc = cid / 4;
+			if (intf_type == RDI2) {
+				/* zero out two bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &=
+					~(0x3 << (vc * 2 + 8));
+				/* set cmd bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |=
+					(cmd_bits << (vc * 2 + 8));
+			} else {
+				/* zero 2 bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
+					~(0x3 << (vc * 2 + intf_type * 8));
+				/* set cmd bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
+					(cmd_bits << (vc * 2 + intf_type * 8));
+			}
+			if (intf_type == PIX0 && params->stereo_enable &&
+			    params->right_entries[i].cids[k] < CID_MAX) {
+				cid = params->right_entries[i].cids[k];
+				vc = cid / 4;
+
+				/* fill right stereo command */
+				/* zero 2 bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
+					~(0x3 << (vc * 2 + PIX1 * 8));
+				/* set cmd bits */
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
+					(cmd_bits << (vc * 2 + PIX1 * 8));
+			}
+		}
+		/* cmd for PIX0, PIX1, RDI0, RDI1 */
+		if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF)
+			msm_camera_io_w_mb(
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
+
+		/* cmd for RDI2 */
+		if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
+			msm_camera_io_w_mb(
+				ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
+	}
+}
+
+static int msm_ispif_stop_immediately(struct ispif_device *ispif,
+	struct msm_ispif_param_data_ext *params)
+{
+	int i, rc = 0;
+	uint16_t cid_mask = 0;
+
+	if (WARN_ON(!ispif) || WARN_ON(!params))
+		return -EINVAL;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params);
+
+	/* after stop the interface we need to unmask the CID enable bits */
+	for (i = 0; i < params->num; i++) {
+		cid_mask = msm_ispif_get_cids_mask_from_cfg(
+			&params->entries[i]);
+		msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
+			cid_mask, params->entries[i].vfe_intf, 0);
+		if (params->stereo_enable) {
+			ispif->stereo_configured[
+					params->entries[i].vfe_intf] = 0;
+			cid_mask = msm_ispif_get_right_cids_mask_from_cfg(
+					&params->right_entries[i],
+					params->entries[i].num_cids);
+			if (cid_mask)
+				msm_ispif_enable_intf_cids(ispif,
+					params->entries[i].intftype, cid_mask,
+					params->entries[i].vfe_intf, 0);
+		}
+	}
+
+	return rc;
+}
+
+static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
+	struct msm_ispif_param_data_ext *params)
+{
+	int rc = 0;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	msm_ispif_config_stereo(ispif, params, ISPIF_USE_DEFAULT_THRESHOLD);
+	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
+
+	return rc;
+}
+
+static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
+	struct msm_ispif_param_data_ext *params)
+{
+	int rc = 0, i;
+	long timeout = 0;
+	uint16_t cid_mask;
+	enum msm_ispif_intftype intftype;
+	enum msm_ispif_vfe_intf vfe_intf;
+	uint32_t vfe_mask = 0;
+	uint32_t intf_addr;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	for (i = 0; i < params->num; i++) {
+		vfe_intf = params->entries[i].vfe_intf;
+		if (vfe_intf >= VFE_MAX) {
+			pr_err("%s: %d invalid i %d vfe_intf %d\n", __func__,
+				__LINE__, i, vfe_intf);
+			return -EINVAL;
+		}
+		vfe_mask |= (1 << vfe_intf);
+	}
+
+	/* Turn ON regulators before enabling the clocks*/
+	rc = msm_ispif_set_regulators(ispif->vfe_vdd,
+					ispif->vfe_vdd_count, 1);
+	if (rc < 0)
+		return -EFAULT;
+
+	rc = msm_camera_clk_enable(&ispif->pdev->dev,
+		ispif->clk_info, ispif->clks,
+		ispif->num_clk, 1);
+	if (rc < 0)
+		goto disable_regulator;
+
+	if (vfe_mask & (1 << VFE0)) {
+		atomic_set(&ispif->reset_trig[VFE0], 1);
+		/* initiate reset of ISPIF */
+		msm_camera_io_w(ISPIF_RST_CMD_MASK_RESTART,
+				ispif->base + ISPIF_RST_CMD_ADDR);
+		timeout = wait_for_completion_interruptible_timeout(
+			&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
+		if (timeout <= 0) {
+			pr_err("%s: VFE0 reset wait timeout\n", __func__);
+			rc = -ETIMEDOUT;
+			goto disable_clk;
+		}
+	}
+
+	if (ispif->hw_num_isps > 1  && (vfe_mask & (1 << VFE1))) {
+		atomic_set(&ispif->reset_trig[VFE1], 1);
+		msm_camera_io_w(ISPIF_RST_CMD_1_MASK_RESTART,
+			ispif->base + ISPIF_RST_CMD_1_ADDR);
+		timeout = wait_for_completion_interruptible_timeout(
+				&ispif->reset_complete[VFE1],
+				msecs_to_jiffies(500));
+		if (timeout <= 0) {
+			pr_err("%s: VFE1 reset wait timeout\n", __func__);
+			rc = -ETIMEDOUT;
+			goto disable_clk;
+		}
+	}
+
+	pr_info("%s: ISPIF reset hw done, Restarting", __func__);
+	rc = msm_camera_clk_enable(&ispif->pdev->dev,
+		ispif->clk_info, ispif->clks,
+		ispif->num_clk, 0);
+	if (rc < 0)
+		goto disable_regulator;
+
+	/* Turn OFF regulators after disabling clocks */
+	rc = msm_ispif_set_regulators(ispif->vfe_vdd, ispif->vfe_vdd_count, 0);
+	if (rc < 0)
+		goto end;
+
+	for (i = 0; i < params->num; i++) {
+		intftype = params->entries[i].intftype;
+		vfe_intf = params->entries[i].vfe_intf;
+
+		switch (params->entries[0].intftype) {
+		case PIX0:
+			intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0);
+			break;
+		case RDI0:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0);
+			break;
+		case PIX1:
+			intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
+			break;
+		case RDI1:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1);
+			break;
+		case RDI2:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2);
+			break;
+		default:
+			pr_err("%s: invalid intftype=%d\n", __func__,
+			params->entries[i].intftype);
+			rc = -EPERM;
+			goto end;
+		}
+
+		msm_ispif_intf_cmd(ispif,
+			ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
+	}
+
+	for (i = 0; i < params->num; i++) {
+		intftype = params->entries[i].intftype;
+
+		vfe_intf = params->entries[i].vfe_intf;
+
+
+		cid_mask = msm_ispif_get_cids_mask_from_cfg(
+			&params->entries[i]);
+
+		msm_ispif_enable_intf_cids(ispif, intftype,
+			cid_mask, vfe_intf, 1);
+	}
+	return rc;
+
+disable_clk:
+	msm_camera_clk_enable(&ispif->pdev->dev,
+		ispif->clk_info, ispif->clks,
+		ispif->num_clk, 0);
+disable_regulator:
+	/* Turn OFF regulators */
+	msm_ispif_set_regulators(ispif->vfe_vdd, ispif->vfe_vdd_count, 0);
+end:
+	return rc;
+}
+
+static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
+	struct msm_ispif_param_data_ext *params)
+{
+	int i, rc = 0;
+	uint16_t cid_mask = 0;
+	uint16_t cid_right_mask = 0;
+	uint32_t intf_addr;
+	enum msm_ispif_vfe_intf vfe_intf;
+	uint32_t stop_flag = 0;
+
+	if (WARN_ON(!ispif) || WARN_ON(!params))
+		return -EINVAL;
+
+	if (ispif->ispif_state != ISPIF_POWER_UP) {
+		pr_err("%s: ispif invalid state %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	for (i = 0; i < params->num; i++) {
+		if (!msm_ispif_is_intf_valid(ispif->csid_version,
+				params->entries[i].vfe_intf)) {
+			pr_err("%s: invalid interface type\n", __func__);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+
+	msm_ispif_intf_cmd(ispif,
+		ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params);
+
+	for (i = 0; i < params->num; i++) {
+		cid_mask =
+			msm_ispif_get_cids_mask_from_cfg(&params->entries[i]);
+		if (params->stereo_enable)
+			cid_right_mask =
+				msm_ispif_get_right_cids_mask_from_cfg(
+						&params->right_entries[i],
+						params->entries[i].num_cids);
+		else
+			cid_right_mask = 0;
+		vfe_intf = params->entries[i].vfe_intf;
+
+		switch (params->entries[i].intftype) {
+		case PIX0:
+			intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0);
+			break;
+		case RDI0:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0);
+			break;
+		case PIX1:
+			intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
+			break;
+		case RDI1:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1);
+			break;
+		case RDI2:
+			intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2);
+			break;
+		default:
+			pr_err("%s: invalid intftype=%d\n", __func__,
+				params->entries[i].intftype);
+			rc = -EPERM;
+			goto end;
+		}
+
+		rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag,
+					(stop_flag & 0xF) == 0xF,
+					ISPIF_TIMEOUT_SLEEP_US,
+					ISPIF_TIMEOUT_ALL_US);
+		if (rc < 0)
+			goto end;
+		if (cid_right_mask) {
+			ispif->stereo_configured[
+					params->entries[i].vfe_intf] = 0;
+			intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
+			rc = readl_poll_timeout(ispif->base + intf_addr,
+						stop_flag,
+						(stop_flag & 0xF) == 0xF,
+						ISPIF_TIMEOUT_SLEEP_US,
+						ISPIF_TIMEOUT_ALL_US);
+			if (rc < 0)
+				goto end;
+		}
+
+		/* disable CIDs in CID_MASK register */
+		msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
+			cid_mask, vfe_intf, 0);
+		if (cid_right_mask)
+			msm_ispif_enable_intf_cids(ispif,
+				params->entries[i].intftype, cid_right_mask,
+				params->entries[i].vfe_intf, 0);
+	}
+
+end:
+	return rc;
+}
+
+static void ispif_process_irq(struct ispif_device *ispif,
+	struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id)
+{
+	if (WARN_ON(!ispif) || WARN_ON(!out)) {
+		pr_err("%s: invalid params", __func__);
+		return;
+	}
+
+	if (out[vfe_id].ispifIrqStatus0 &
+			ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+		if (ispif->ispif_sof_debug < ISPIF_SOF_DEBUG_COUNT)
+			pr_err("%s: PIX0 frame id: %u\n", __func__,
+				ispif->sof_count[vfe_id].sof_cnt[PIX0]);
+		ispif->sof_count[vfe_id].sof_cnt[PIX0]++;
+		ispif->ispif_sof_debug++;
+	}
+	if (out[vfe_id].ispifIrqStatus1 &
+			ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+		if (ispif->ispif_sof_debug < ISPIF_SOF_DEBUG_COUNT*2)
+			pr_err("%s: PIX1 frame id: %u\n", __func__,
+				ispif->sof_count[vfe_id].sof_cnt[PIX1]);
+		ispif->sof_count[vfe_id].sof_cnt[PIX1]++;
+		ispif->ispif_sof_debug++;
+	}
+	if (out[vfe_id].ispifIrqStatus0 &
+			ISPIF_IRQ_STATUS_RDI0_SOF_MASK) {
+		if (ispif->ispif_rdi0_debug < ISPIF_SOF_DEBUG_COUNT)
+			pr_err("%s: RDI0 frame id: %u\n", __func__,
+				ispif->sof_count[vfe_id].sof_cnt[RDI0]);
+		ispif->sof_count[vfe_id].sof_cnt[RDI0]++;
+		ispif->ispif_rdi0_debug++;
+	}
+	if (out[vfe_id].ispifIrqStatus1 &
+			ISPIF_IRQ_STATUS_RDI1_SOF_MASK) {
+		if (ispif->ispif_rdi1_debug < ISPIF_SOF_DEBUG_COUNT)
+			pr_err("%s: RDI1 frame id: %u\n", __func__,
+				ispif->sof_count[vfe_id].sof_cnt[RDI1]);
+		ispif->sof_count[vfe_id].sof_cnt[RDI1]++;
+		ispif->ispif_rdi1_debug++;
+	}
+	if (out[vfe_id].ispifIrqStatus2 &
+			ISPIF_IRQ_STATUS_RDI2_SOF_MASK) {
+		if (ispif->ispif_rdi2_debug < ISPIF_SOF_DEBUG_COUNT)
+			pr_err("%s: RDI2 frame id: %u\n", __func__,
+				ispif->sof_count[vfe_id].sof_cnt[RDI2]);
+		ispif->sof_count[vfe_id].sof_cnt[RDI2]++;
+		ispif->ispif_rdi2_debug++;
+	}
+}
+
+static int msm_ispif_reconfig_3d_output(struct ispif_device *ispif,
+		enum msm_ispif_vfe_intf vfe_id)
+{
+	uint32_t reg_data;
+
+	if (WARN_ON(!ispif))
+		return -EINVAL;
+
+	if (!((vfe_id == VFE0) ||  (vfe_id == VFE1))) {
+		pr_err("%s;%d Cannot reconfigure 3D mode for VFE%d", __func__,
+				__LINE__, vfe_id);
+		return -EINVAL;
+	}
+	pr_info("%s;%d Reconfiguring 3D mode for VFE%d", __func__, __LINE__,
+			vfe_id);
+	reg_data =  0xFFFCFFFC;
+	msm_camera_io_w_mb(reg_data, ispif->base +
+			ISPIF_VFE_m_INTF_CMD_0(vfe_id));
+	msm_camera_io_w_mb(reg_data, ispif->base +
+			ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	if (vfe_id == VFE0) {
+		reg_data = 0;
+		reg_data |= (PIX_0_VFE_RST_STB | PIX_1_VFE_RST_STB |
+				STROBED_RST_EN | PIX_0_CSID_RST_STB |
+				PIX_1_CSID_RST_STB | PIX_OUTPUT_0_MISR_RST_STB);
+		msm_camera_io_w_mb(reg_data, ispif->base + ISPIF_RST_CMD_ADDR);
+	} else {
+		reg_data = 0;
+		reg_data |= (PIX_0_VFE_RST_STB | PIX_1_VFE_RST_STB |
+				STROBED_RST_EN | PIX_0_CSID_RST_STB |
+				PIX_1_CSID_RST_STB | PIX_OUTPUT_0_MISR_RST_STB);
+		msm_camera_io_w_mb(reg_data, ispif->base +
+				ISPIF_RST_CMD_1_ADDR);
+	}
+
+	reg_data = 0xFFFDFFFD;
+	msm_camera_io_w_mb(reg_data, ispif->base +
+			ISPIF_VFE_m_INTF_CMD_0(vfe_id));
+	return 0;
+}
+
+static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
+	void *data)
+{
+	struct ispif_device *ispif = (struct ispif_device *)data;
+	bool fatal_err = false;
+	int i = 0;
+	uint32_t reg_data;
+
+	if (WARN_ON(!ispif) || WARN_ON(!out)) {
+		pr_err("%s: invalid params", __func__);
+		return;
+	}
+
+	out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
+		ISPIF_VFE_m_IRQ_STATUS_0(VFE0));
+	msm_camera_io_w(out[VFE0].ispifIrqStatus0,
+		ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0));
+
+	out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
+		ISPIF_VFE_m_IRQ_STATUS_1(VFE0));
+	msm_camera_io_w(out[VFE0].ispifIrqStatus1,
+		ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0));
+
+	out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+		ISPIF_VFE_m_IRQ_STATUS_2(VFE0));
+	msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2,
+		ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0));
+
+	if (ispif->vfe_info.num_vfe > 1) {
+		out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
+		msm_camera_io_w(out[VFE1].ispifIrqStatus0,
+			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
+
+		out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
+		msm_camera_io_w(out[VFE1].ispifIrqStatus1,
+				ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
+
+		out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+			ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
+		msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
+			ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
+	}
+	msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
+	ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
+		if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
+			if (atomic_dec_and_test(&ispif->reset_trig[VFE0]))
+				complete(&ispif->reset_complete[VFE0]);
+		}
+
+		if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE0 pix0 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE0].ispifIrqStatus1 & PIX_INTF_1_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE0 pix1 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE0 rdi0 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE0 rdi1 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE0 rdi2 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		ispif_process_irq(ispif, out, VFE0);
+	}
+	if (ispif->hw_num_isps > 1) {
+		if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) {
+			if (atomic_dec_and_test(&ispif->reset_trig[VFE1]))
+				complete(&ispif->reset_complete[VFE1]);
+		}
+
+		if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE1 pix0 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE1].ispifIrqStatus1 & PIX_INTF_1_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE1 pix1 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE1 rdi0 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE1 rdi1 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) {
+			pr_err_ratelimited("%s: VFE1 rdi2 overflow.\n",
+				__func__);
+			fatal_err = true;
+		}
+
+		ispif_process_irq(ispif, out, VFE1);
+	}
+
+	if ((out[VFE0].ispifIrqStatus0 &  PIX_INTF_0_OVERFLOW_IRQ) ||
+	    (out[VFE0].ispifIrqStatus1 &  PIX_INTF_0_OVERFLOW_IRQ) ||
+	    (out[VFE0].ispifIrqStatus2 &  (L_R_SOF_MISMATCH_ERR_IRQ |
+		L_R_EOF_MISMATCH_ERR_IRQ | L_R_SOL_MISMATCH_ERR_IRQ))) {
+		reg_data = msm_camera_io_r(ispif->base +
+				ISPIF_VFE_m_OUTPUT_SEL(VFE0));
+		if ((reg_data & 0x03) == VFE_PIX_INTF_SEL_3D) {
+			pix_overflow_error_count[VFE0]++;
+			if (pix_overflow_error_count[VFE0] >=
+					MAX_PIX_OVERFLOW_ERROR_COUNT) {
+				msm_ispif_reconfig_3d_output(ispif, VFE0);
+				pix_overflow_error_count[VFE0] = 0;
+			}
+			fatal_err = false;
+		}
+	}
+
+	if (ispif->vfe_info.num_vfe > 1) {
+		if ((out[VFE1].ispifIrqStatus0 &  PIX_INTF_0_OVERFLOW_IRQ) ||
+		   (out[VFE1].ispifIrqStatus1 &  PIX_INTF_0_OVERFLOW_IRQ) ||
+		   (out[VFE1].ispifIrqStatus2 &  (L_R_SOF_MISMATCH_ERR_IRQ |
+		    L_R_EOF_MISMATCH_ERR_IRQ | L_R_SOL_MISMATCH_ERR_IRQ))) {
+			reg_data = msm_camera_io_r(ispif->base +
+					ISPIF_VFE_m_OUTPUT_SEL(VFE1));
+			if ((reg_data & 0x03) == VFE_PIX_INTF_SEL_3D) {
+				pix_overflow_error_count[VFE1]++;
+				if (pix_overflow_error_count[VFE1] >=
+						MAX_PIX_OVERFLOW_ERROR_COUNT) {
+					msm_ispif_reconfig_3d_output(ispif,
+									VFE1);
+					pix_overflow_error_count[VFE1] = 0;
+				}
+			}
+			fatal_err = false;
+		}
+	}
+
+	if (fatal_err == true) {
+		pr_err_ratelimited("%s: fatal error, stop ispif immediately\n",
+				__func__);
+		for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
+			msm_camera_io_w(0x0,
+				ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i));
+			msm_camera_io_w(0x0,
+				ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i));
+			msm_camera_io_w(0x0,
+				ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i));
+			msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
+			msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+				ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
+		}
+	}
+}
+
+static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
+{
+	struct ispif_irq_status irq[VFE_MAX];
+
+	msm_ispif_read_irq_status(irq, data);
+	return IRQ_HANDLED;
+}
+
+static int msm_ispif_set_vfe_info(struct ispif_device *ispif,
+	struct msm_ispif_vfe_info *vfe_info)
+{
+	if (!vfe_info || (vfe_info->num_vfe == 0) ||
+		(vfe_info->num_vfe > ispif->hw_num_isps)) {
+		pr_err("Invalid VFE info: %pK %d\n", vfe_info,
+			   (vfe_info ? vfe_info->num_vfe : 0));
+		return -EINVAL;
+	}
+
+	memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info));
+
+	return 0;
+}
+
+static int msm_ispif_init(struct ispif_device *ispif,
+	uint32_t csid_version)
+{
+	int rc = 0;
+
+	if (WARN_ON(!ispif)) {
+		pr_err("%s: invalid ispif params", __func__);
+		return -EINVAL;
+	}
+
+	if (ispif->ispif_state == ISPIF_POWER_UP) {
+		pr_err("%s: ispif already initted state = %d\n", __func__,
+			ispif->ispif_state);
+		rc = -EPERM;
+		return rc;
+	}
+
+	/* can we set to zero? */
+	ispif->applied_intf_cmd[VFE0].intf_cmd  = 0xFFFFFFFF;
+	ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF;
+	ispif->applied_intf_cmd[VFE1].intf_cmd  = 0xFFFFFFFF;
+	ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF;
+	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
+
+	ispif->csid_version = csid_version;
+
+	if (ispif->csid_version >= CSID_VERSION_V30 && !ispif->clk_mux_base) {
+		ispif->clk_mux_base = msm_camera_get_reg_base(ispif->pdev,
+							"csi_clk_mux", 1);
+		if (!ispif->clk_mux_base)
+			return -ENOMEM;
+	}
+
+	rc = cam_config_ahb_clk(NULL, 0,
+			CAM_AHB_CLIENT_ISPIF, CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+
+	rc = msm_ispif_reset_hw(ispif);
+	if (rc)
+		goto error_ahb;
+
+	rc = msm_ispif_reset(ispif);
+	if (rc)
+		goto error_ahb;
+	ispif->ispif_state = ISPIF_POWER_UP;
+	return 0;
+
+error_ahb:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return rc;
+}
+
+static void msm_ispif_release(struct ispif_device *ispif)
+{
+	if (WARN_ON(!ispif)) {
+		pr_err("%s: invalid ispif params", __func__);
+		return;
+	}
+
+	msm_camera_enable_irq(ispif->irq, 0);
+
+	ispif->ispif_state = ISPIF_POWER_DOWN;
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+}
+
+static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
+				struct ispif_device *ispif,
+				struct msm_ispif_param_data_ext *params)
+{
+	long rc = 0;
+
+	switch (cmd) {
+	case ISPIF_CFG:
+		rc = msm_ispif_config(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_START_FRAME_BOUNDARY:
+		rc = msm_ispif_start_frame_boundary(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_RESTART_FRAME_BOUNDARY:
+		rc = msm_ispif_restart_frame_boundary(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_STOP_FRAME_BOUNDARY:
+		rc = msm_ispif_stop_frame_boundary(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_STOP_IMMEDIATELY:
+		rc = msm_ispif_stop_immediately(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_RELEASE:
+		msm_ispif_reset(ispif);
+		msm_ispif_reset_hw(ispif);
+		break;
+	case ISPIF_CFG2:
+		rc = msm_ispif_config2(ispif, params);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_CFG_STEREO:
+		msm_ispif_config_stereo(ispif, params,
+						ISPIF_CALCULATE_THRESHOLD);
+		break;
+	default:
+		pr_err("%s: invalid cfg_type\n", __func__);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
+{
+	long rc = 0;
+	struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg;
+	struct ispif_device *ispif =
+		(struct ispif_device *)v4l2_get_subdevdata(sd);
+	int i;
+	struct msm_ispif_param_data_ext params;
+
+	if (WARN_ON(!sd) || WARN_ON(!pcdata))
+		return -EINVAL;
+
+	mutex_lock(&ispif->mutex);
+	switch (pcdata->cfg_type) {
+	case ISPIF_ENABLE_REG_DUMP:
+		/* save dump config */
+		ispif->enb_dump_reg = pcdata->reg_dump;
+		break;
+	case ISPIF_INIT:
+		rc = msm_ispif_init(ispif, pcdata->csid_version);
+		msm_ispif_io_dump_reg(ispif);
+		break;
+	case ISPIF_SET_VFE_INFO:
+		rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info);
+		break;
+	default:
+		memset(&params, 0, sizeof(params));
+		if (pcdata->params.num > MAX_PARAM_ENTRIES) {
+			pr_err("%s: invalid num entries %u\n", __func__,
+					 pcdata->params.num);
+			rc = -EINVAL;
+		} else {
+			params.num = pcdata->params.num;
+			for (i = 0; i < pcdata->params.num; i++)
+				memcpy(&params.entries[i],
+					&pcdata->params.entries[i],
+					sizeof(struct msm_ispif_params_entry));
+			params.stereo_enable = 0;
+			rc = msm_ispif_dispatch_cmd(pcdata->cfg_type, ispif,
+							&params);
+		}
+		break;
+	}
+	mutex_unlock(&ispif->mutex);
+
+	return rc;
+}
+
+static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops;
+
+static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct ispif_device *ispif =
+		(struct ispif_device *)v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_MSM_ISPIF_CFG:
+		return msm_ispif_cmd(sd, arg);
+	case VIDIOC_MSM_ISPIF_CFG_EXT:
+		return msm_ispif_cmd_ext(sd, arg);
+	case MSM_SD_NOTIFY_FREEZE: {
+		ispif->ispif_sof_debug = 0;
+		ispif->ispif_rdi0_debug = 0;
+		ispif->ispif_rdi1_debug = 0;
+		ispif->ispif_rdi2_debug = 0;
+		return 0;
+	}
+	case MSM_SD_SHUTDOWN:
+		return 0;
+	default:
+		pr_err_ratelimited("%s: invalid cmd 0x%x received\n",
+			__func__, cmd);
+		return -ENOIOCTLCMD;
+	}
+}
+
+static long msm_ispif_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	return msm_ispif_subdev_ioctl(sd, cmd, arg);
+}
+
+static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl);
+}
+
+static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct ispif_device *ispif = v4l2_get_subdevdata(sd);
+	int rc = 0;
+
+	mutex_lock(&ispif->mutex);
+	if (ispif->open_cnt == 0) {
+		/* enable regulator and clocks on first open */
+		rc = msm_ispif_set_regulators(ispif->ispif_vdd,
+					ispif->ispif_vdd_count, 1);
+		if (rc)
+			goto unlock;
+
+		rc = msm_ispif_clk_ahb_enable(ispif, 1);
+		if (rc)
+			goto ahb_clk_enable_fail;
+		rc = msm_camera_enable_irq(ispif->irq, 1);
+		if (rc)
+			goto irq_enable_fail;
+	}
+	/* mem remap is done in init when the clock is on */
+	ispif->open_cnt++;
+	mutex_unlock(&ispif->mutex);
+	return rc;
+ahb_clk_enable_fail:
+	msm_ispif_set_regulators(ispif->ispif_vdd, ispif->ispif_vdd_count, 0);
+irq_enable_fail:
+	msm_ispif_clk_ahb_enable(ispif, 0);
+unlock:
+	mutex_unlock(&ispif->mutex);
+	return rc;
+}
+
+static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct ispif_device *ispif = v4l2_get_subdevdata(sd);
+
+	if (!ispif) {
+		pr_err("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ispif->mutex);
+	if (ispif->open_cnt == 0) {
+		pr_err("%s: Invalid close\n", __func__);
+		rc = -ENODEV;
+		goto end;
+	}
+	ispif->open_cnt--;
+	if (ispif->open_cnt == 0) {
+		msm_ispif_release(ispif);
+		/* disable clocks and regulator on last close */
+		msm_ispif_clk_ahb_enable(ispif, 0);
+		msm_ispif_set_regulators(ispif->ispif_vdd,
+					ispif->ispif_vdd_count, 0);
+	}
+end:
+	mutex_unlock(&ispif->mutex);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = {
+	.ioctl = &msm_ispif_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_ispif_subdev_ops = {
+	.core = &msm_ispif_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = {
+	.open = ispif_open_node,
+	.close = ispif_close_node,
+};
+
+static int ispif_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct ispif_device *ispif;
+
+	ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
+	if (!ispif)
+		return -ENOMEM;
+
+	if (pdev->dev.of_node) {
+		of_property_read_u32((&pdev->dev)->of_node,
+		"cell-index", &pdev->id);
+		rc = of_property_read_u32((&pdev->dev)->of_node,
+		"qcom,num-isps", &ispif->hw_num_isps);
+		if (rc)
+			/* backward compatibility */
+			ispif->hw_num_isps = 1;
+		/* not an error condition */
+		rc = 0;
+	}
+
+	rc = msm_ispif_get_regulator_info(ispif, pdev);
+	if (rc < 0)
+		goto regulator_fail;
+
+	rc = msm_ispif_get_clk_info(ispif, pdev);
+	if (rc < 0) {
+		pr_err("%s: msm_isp_get_clk_info() failed", __func__);
+		rc = -EFAULT;
+		goto get_clk_fail;
+	}
+	mutex_init(&ispif->mutex);
+	ispif->base = msm_camera_get_reg_base(pdev, "ispif", 1);
+	if (!ispif->base) {
+		rc = -ENOMEM;
+		goto reg_base_fail;
+	}
+
+	ispif->irq = msm_camera_get_irq(pdev, "ispif");
+	if (!ispif->irq) {
+		rc = -ENODEV;
+		goto get_irq_fail;
+	}
+	rc = msm_camera_register_irq(pdev, ispif->irq, msm_io_ispif_irq,
+			IRQF_TRIGGER_RISING, "ispif", ispif);
+	if (rc) {
+		rc = -ENODEV;
+		goto get_irq_fail;
+	}
+	rc = msm_camera_enable_irq(ispif->irq, 0);
+	if (rc)
+		goto sd_reg_fail;
+
+	ispif->pdev = pdev;
+
+	v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops);
+	ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops;
+	ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	snprintf(ispif->msm_sd.sd.name,
+		ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME);
+	v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif);
+
+	platform_set_drvdata(pdev, &ispif->msm_sd.sd);
+
+	media_entity_pads_init(&ispif->msm_sd.sd.entity, 0, NULL);
+	ispif->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ISPIF;
+	ispif->msm_sd.sd.entity.name = pdev->name;
+	ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1;
+	rc = msm_sd_register(&ispif->msm_sd);
+	if (rc) {
+		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
+		goto sd_reg_fail;
+	}
+	msm_cam_copy_v4l2_subdev_fops(&msm_ispif_v4l2_subdev_fops);
+	msm_ispif_v4l2_subdev_fops.unlocked_ioctl =
+		msm_ispif_subdev_fops_ioctl;
+#ifdef CONFIG_COMPAT
+	msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl;
+#endif
+	ispif->msm_sd.sd.devnode->fops = &msm_ispif_v4l2_subdev_fops;
+	ispif->ispif_state = ISPIF_POWER_DOWN;
+	ispif->open_cnt = 0;
+	init_completion(&ispif->reset_complete[VFE0]);
+	init_completion(&ispif->reset_complete[VFE1]);
+	atomic_set(&ispif->reset_trig[VFE0], 0);
+	atomic_set(&ispif->reset_trig[VFE1], 0);
+	return 0;
+
+sd_reg_fail:
+	msm_camera_unregister_irq(pdev, ispif->irq, ispif);
+get_irq_fail:
+	msm_camera_put_reg_base(pdev, ispif->base, "ispif", 1);
+reg_base_fail:
+	msm_camera_put_clk_info(pdev, &ispif->ahb_clk_info,
+		&ispif->ahb_clk,
+		ispif->num_ahb_clk + ispif->num_clk);
+get_clk_fail:
+	msm_ispif_put_regulator(ispif);
+regulator_fail:
+	mutex_destroy(&ispif->mutex);
+	kfree(ispif);
+	return rc;
+}
+
+static const struct of_device_id msm_ispif_dt_match[] = {
+	{.compatible = "qcom,ispif"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_ispif_dt_match);
+
+static struct platform_driver ispif_driver = {
+	.probe = ispif_probe,
+	.driver = {
+		.name = MSM_ISPIF_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ispif_dt_match,
+	},
+};
+
+static int __init msm_ispif_init_module(void)
+{
+	return platform_driver_register(&ispif_driver);
+}
+
+static void __exit msm_ispif_exit_module(void)
+{
+	platform_driver_unregister(&ispif_driver);
+}
+
+module_init(msm_ispif_init_module);
+module_exit(msm_ispif_exit_module);
+MODULE_DESCRIPTION("MSM ISP Interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
new file mode 100644
index 0000000..6d12e35
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_ISPIF_H
+#define MSM_ISPIF_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_ispif.h>
+#include "msm_sd.h"
+
+/* Maximum number of voltage supply for ispif and vfe */
+#define ISPIF_VDD_INFO_MAX 2
+#define ISPIF_VFE_VDD_INFO_MAX 2
+
+#define ISPIF_CLK_INFO_MAX 27
+
+struct ispif_irq_status {
+	uint32_t ispifIrqStatus0;
+	uint32_t ispifIrqStatus1;
+	uint32_t ispifIrqStatus2;
+};
+
+enum msm_ispif_state_t {
+	ISPIF_POWER_UP,
+	ISPIF_POWER_DOWN,
+};
+struct ispif_sof_count {
+	uint32_t sof_cnt[INTF_MAX];
+};
+
+struct ispif_intf_cmd {
+	uint32_t intf_cmd;
+	uint32_t intf_cmd1;
+};
+
+struct ispif_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct resource *irq;
+	void __iomem *base;
+	void __iomem *clk_mux_base;
+	struct mutex mutex;
+	uint8_t start_ack_pending;
+	uint32_t csid_version;
+	int enb_dump_reg;
+	uint32_t open_cnt;
+	struct ispif_sof_count sof_count[VFE_MAX];
+	struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
+	enum msm_ispif_state_t ispif_state;
+	struct msm_ispif_vfe_info vfe_info;
+	struct clk **ahb_clk;
+	struct msm_cam_clk_info *ahb_clk_info;
+	struct clk **clks;
+	struct msm_cam_clk_info *clk_info;
+	struct completion reset_complete[VFE_MAX];
+	atomic_t reset_trig[VFE_MAX];
+	uint32_t hw_num_isps;
+	uint32_t num_ahb_clk;
+	uint32_t num_clk;
+	uint32_t clk_idx;
+	uint32_t ispif_sof_debug;
+	uint32_t ispif_rdi0_debug;
+	uint32_t ispif_rdi1_debug;
+	uint32_t ispif_rdi2_debug;
+	struct regulator *ispif_vdd[ISPIF_VDD_INFO_MAX];
+	int ispif_vdd_count;
+	struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX];
+	int vfe_vdd_count;
+	int stereo_configured[VFE_MAX];
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
new file mode 100644
index 0000000..c556613
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -0,0 +1,130 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISPIF_HWREG_V1_H__
+#define __MSM_ISPIF_HWREG_V1_H__
+
+/* common registers */
+#define ISPIF_RST_CMD_ADDR                       0x0000
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR          0x0124
+#define PIX0_LINE_BUF_EN_BIT                     0
+
+#define ISPIF_VFE(m)                             (0x0)
+
+#define ISPIF_VFE_m_CTRL_0(m)                    (0x0008 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_0(m)                (0x0100 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_1(m)                (0x010C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_2(m)                (0x0118 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_0(m)              (0x0108 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_1(m)              (0x0114 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_2(m)              (0x0120 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_0(m)               (0x0104 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_1(m)               (0x0110 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_2(m)               (0x011C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INPUT_SEL(m)                 (0x000C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_0(m)                (0x0004 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_1(m)                (0x0030 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n)    (0x0010 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x0014 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x20) : 0) \
+							+ 8*(n))
+#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n)      (0x0290 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x001C + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x0020 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n)      (0x0024 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x0028 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x34) : 0) \
+							+ 8*(n))
+
+/* Defines for compatibility with newer ISPIF versions */
+#define ISPIF_RST_CMD_1_ADDR                     (0x0000)
+#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n)        (0x0000 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_THRESHOLD(m)              (0x0000 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_OUTPUT_SEL(m)                (0x0000 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_3D_DESKEW_SIZE(m)            (0x0000 + ISPIF_VFE(m))
+
+
+
+/* CSID CLK MUX SEL REGISTERS */
+#define ISPIF_RDI_CLK_MUX_SEL_ADDR              0x8
+
+/*ISPIF RESET BITS*/
+#define VFE_CLK_DOMAIN_RST                 BIT(31)
+#define RDI_CLK_DOMAIN_RST                 BIT(30)
+#define PIX_CLK_DOMAIN_RST                 BIT(29)
+#define AHB_CLK_DOMAIN_RST                 BIT(28)
+#define RDI_1_CLK_DOMAIN_RST               BIT(27)
+#define PIX_1_CLK_DOMAIN_RST               BIT(26)
+#define RDI_2_CLK_DOMAIN_RST               BIT(25)
+#define RDI_2_MISR_RST_STB                 BIT(20)
+#define RDI_2_VFE_RST_STB                  BIT(19)
+#define RDI_2_CSID_RST_STB                 BIT(18)
+#define RDI_1_MISR_RST_STB                 BIT(14)
+#define RDI_1_VFE_RST_STB                  BIT(13)
+#define RDI_1_CSID_RST_STB                 BIT(12)
+#define PIX_1_VFE_RST_STB                  BIT(10)
+#define PIX_1_CSID_RST_STB                 BIT(9)
+#define RDI_0_MISR_RST_STB                 BIT(8)
+#define RDI_0_VFE_RST_STB                  BIT(7)
+#define RDI_0_CSID_RST_STB                 BIT(6)
+#define PIX_0_MISR_RST_STB                 BIT(5)
+#define PIX_0_VFE_RST_STB                  BIT(4)
+#define PIX_0_CSID_RST_STB                 BIT(3)
+#define SW_REG_RST_STB                     BIT(2)
+#define MISC_LOGIC_RST_STB                 BIT(1)
+#define STROBED_RST_EN                     BIT(0)
+
+#define VFE_PIX_INTF_SEL_3D                      0x3
+#define PIX_OUTPUT_0_MISR_RST_STB                BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ                 BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ                 BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ                 BIT(18)
+
+#define ISPIF_RST_CMD_MASK              0xFE1C77FF
+#define ISPIF_RST_CMD_1_MASK            0xFFFFFFFF /* undefined */
+
+#define ISPIF_RST_CMD_MASK_RESTART      0x00001FF9
+#define ISPIF_RST_CMD_1_MASK_RESTART    0x00001FF9 /* undefined */
+
+/* irq_mask_0 */
+#define PIX_INTF_0_OVERFLOW_IRQ            BIT(12)
+#define RAW_INTF_0_OVERFLOW_IRQ            BIT(25)
+#define RESET_DONE_IRQ                     BIT(27)
+/* irq_mask_1 */
+#define PIX_INTF_1_OVERFLOW_IRQ            BIT(12)
+#define RAW_INTF_1_OVERFLOW_IRQ            BIT(25)
+/* irq_mask_2 */
+#define RAW_INTF_2_OVERFLOW_IRQ            BIT(12)
+
+#define ISPIF_IRQ_STATUS_MASK           0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK         0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK         0x00001249
+
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK     0x000249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK    0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK    0x492000
+#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK    0x000249
+
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD        0x000001
+
+#define ISPIF_STOP_INTF_IMMEDIATELY              0xAAAAAAAA
+
+/* ISPIF RDI pack mode not supported */
+static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
+{
+}
+#endif /* __MSM_ISPIF_HWREG_V1_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
new file mode 100644
index 0000000..dc3a75b
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISPIF_HWREG_V2_H__
+#define __MSM_ISPIF_HWREG_V2_H__
+
+/* common registers */
+#define ISPIF_RST_CMD_ADDR                       0x008
+#define ISPIF_RST_CMD_1_ADDR                     0x00C
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR          0x01C
+#define PIX0_LINE_BUF_EN_BIT                     6
+
+#define ISPIF_VFE(m)                             ((m) * 0x200)
+
+#define ISPIF_VFE_m_CTRL_0(m)                    (0x200 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_CTRL_1(m)                    (0x204 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_0(m)                (0x208 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_1(m)                (0x20C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_2(m)                (0x210 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_0(m)              (0x21C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_1(m)              (0x220 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_2(m)              (0x224 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_0(m)               (0x230 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_1(m)               (0x234 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_2(m)               (0x238 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INPUT_SEL(m)                 (0x244 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_0(m)                (0x248 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_1(m)                (0x24C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n)    (0x254 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x264 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n)        (0x278 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_THRESHOLD(m)              (0x288 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_OUTPUT_SEL(m)                (0x28C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n)      (0x290 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x298 + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x29C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n)      (0x2C0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x2D0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_DESKEW_SIZE(m)            (0x2E4 + ISPIF_VFE(m))
+
+/* CSID CLK MUX SEL REGISTERS */
+#define ISPIF_RDI_CLK_MUX_SEL_ADDR               0x8
+
+/*ISPIF RESET BITS*/
+#define VFE_CLK_DOMAIN_RST                       BIT(31)
+#define PIX_1_CLK_DOMAIN_RST                     BIT(30)
+#define PIX_CLK_DOMAIN_RST                       BIT(29)
+#define RDI_2_CLK_DOMAIN_RST                     BIT(28)
+#define RDI_1_CLK_DOMAIN_RST                     BIT(27)
+#define RDI_CLK_DOMAIN_RST                       BIT(26)
+#define AHB_CLK_DOMAIN_RST                       BIT(25)
+#define RDI_2_VFE_RST_STB                        BIT(12)
+#define RDI_2_CSID_RST_STB                       BIT(11)
+#define RDI_1_VFE_RST_STB                        BIT(10)
+#define RDI_1_CSID_RST_STB                       BIT(9)
+#define RDI_0_VFE_RST_STB                        BIT(8)
+#define RDI_0_CSID_RST_STB                       BIT(7)
+#define PIX_1_VFE_RST_STB                        BIT(6)
+#define PIX_1_CSID_RST_STB                       BIT(5)
+#define PIX_0_VFE_RST_STB                        BIT(4)
+#define PIX_0_CSID_RST_STB                       BIT(3)
+#define SW_REG_RST_STB                           BIT(2)
+#define MISC_LOGIC_RST_STB                       BIT(1)
+#define STROBED_RST_EN                           BIT(0)
+
+#define VFE_PIX_INTF_SEL_3D                      0x3
+#define PIX_OUTPUT_0_MISR_RST_STB                BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ                 BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ                 BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ                 BIT(18)
+
+#define ISPIF_RST_CMD_MASK                       0xFE0F1FFF
+#define ISPIF_RST_CMD_1_MASK                     0xFC0F1FF9
+
+#define ISPIF_RST_CMD_MASK_RESTART               0x00001FF9
+#define ISPIF_RST_CMD_1_MASK_RESTART             0x00001FF9
+
+#define PIX_INTF_0_OVERFLOW_IRQ                  BIT(12)
+#define PIX_INTF_1_OVERFLOW_IRQ                  BIT(12)
+#define RAW_INTF_0_OVERFLOW_IRQ                  BIT(25)
+#define RAW_INTF_1_OVERFLOW_IRQ                  BIT(25)
+#define RAW_INTF_2_OVERFLOW_IRQ                  BIT(12)
+#define RESET_DONE_IRQ                           BIT(27)
+
+#define ISPIF_IRQ_STATUS_MASK                    0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK                  0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK                  0x00001249
+
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK            0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK           0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK           0x492000
+#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK           0x249
+
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD               0x1
+
+#define ISPIF_STOP_INTF_IMMEDIATELY              0xAAAAAAAA
+
+/* ISPIF RDI pack mode not supported */
+static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
+{
+}
+#endif /* __MSM_ISPIF_HWREG_V2_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h
new file mode 100644
index 0000000..de9f462
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h
@@ -0,0 +1,143 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_ISPIF_HWREG_V3_H__
+#define __MSM_ISPIF_HWREG_V3_H__
+
+/* common registers */
+#define ISPIF_RST_CMD_ADDR                       0x008
+#define ISPIF_RST_CMD_1_ADDR                     0x00C
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR          0x01C
+#define PIX0_LINE_BUF_EN_BIT                     6
+
+#define ISPIF_VFE(m)                             ((m) * 0x200)
+
+#define ISPIF_VFE_m_CTRL_0(m)                    (0x200 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_CTRL_1(m)                    (0x204 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_0(m)                (0x208 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_1(m)                (0x20C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_2(m)                (0x210 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_0(m)              (0x21C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_1(m)              (0x220 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_2(m)              (0x224 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_0(m)               (0x230 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_1(m)               (0x234 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_2(m)               (0x238 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INPUT_SEL(m)                 (0x244 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_0(m)                (0x248 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_1(m)                (0x24C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n)    (0x254 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x264 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_PACK_0(m, n)      (0x270 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_PACK_1(m, n)      (0x27C + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n)        (0x288 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_THRESHOLD(m)              (0x290 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_OUTPUT_SEL(m)                (0x294 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n)      (0x298 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x29C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x2A0 + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n)      (0x2C0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x2D0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_DESKEW_SIZE(m)            (0x2E4 + ISPIF_VFE(m))
+
+/* CSID CLK MUX SEL REGISTERS */
+#define ISPIF_RDI_CLK_MUX_SEL_ADDR               0x8
+
+/*ISPIF RESET BITS*/
+#define VFE_CLK_DOMAIN_RST                       BIT(31)
+#define PIX_1_CLK_DOMAIN_RST                     BIT(30)
+#define PIX_CLK_DOMAIN_RST                       BIT(29)
+#define RDI_2_CLK_DOMAIN_RST                     BIT(28)
+#define RDI_1_CLK_DOMAIN_RST                     BIT(27)
+#define RDI_CLK_DOMAIN_RST                       BIT(26)
+#define AHB_CLK_DOMAIN_RST                       BIT(25)
+#define RDI_2_VFE_RST_STB                        BIT(12)
+#define RDI_2_CSID_RST_STB                       BIT(11)
+#define RDI_1_VFE_RST_STB                        BIT(10)
+#define RDI_1_CSID_RST_STB                       BIT(9)
+#define RDI_0_VFE_RST_STB                        BIT(8)
+#define RDI_0_CSID_RST_STB                       BIT(7)
+#define PIX_1_VFE_RST_STB                        BIT(6)
+#define PIX_1_CSID_RST_STB                       BIT(5)
+#define PIX_0_VFE_RST_STB                        BIT(4)
+#define PIX_0_CSID_RST_STB                       BIT(3)
+#define SW_REG_RST_STB                           BIT(2)
+#define MISC_LOGIC_RST_STB                       BIT(1)
+#define STROBED_RST_EN                           BIT(0)
+
+#define VFE_PIX_INTF_SEL_3D                      0x3
+#define PIX_OUTPUT_0_MISR_RST_STB                BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ                 BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ                 BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ                 BIT(18)
+
+#define ISPIF_RST_CMD_MASK                       0xFE7F1FFF
+#define ISPIF_RST_CMD_1_MASK                     0xFC7F1FF9
+
+#define ISPIF_RST_CMD_MASK_RESTART               0x7F1FF9
+#define ISPIF_RST_CMD_1_MASK_RESTART             0x7F1FF9
+
+#define PIX_INTF_0_OVERFLOW_IRQ                  BIT(12)
+#define PIX_INTF_1_OVERFLOW_IRQ                  BIT(12)
+#define RAW_INTF_0_OVERFLOW_IRQ                  BIT(25)
+#define RAW_INTF_1_OVERFLOW_IRQ                  BIT(25)
+#define RAW_INTF_2_OVERFLOW_IRQ                  BIT(12)
+#define RESET_DONE_IRQ                           BIT(27)
+
+#define ISPIF_IRQ_STATUS_MASK                    0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK                  0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK                  0x00001249
+
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK            0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK           0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK           0x492000
+#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK           0x249
+
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD               0x1
+
+#define ISPIF_STOP_INTF_IMMEDIATELY              0xAAAAAAAA
+
+/* ISPIF RDI pack mode support */
+static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
+	uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
+{
+	uint32_t pack_addr[2];
+
+	if (WARN_ON(!ispif))
+		return;
+
+	switch (intftype) {
+	case RDI0:
+		pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 0);
+		pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 0);
+		break;
+	case RDI1:
+		pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 1);
+		pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 1);
+		break;
+	case RDI2:
+		pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 2);
+		pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 2);
+		break;
+	default:
+		pr_debug("%s: pack_mode not supported on intftype=%d\n",
+			__func__, intftype);
+		return;
+	}
+	pr_debug("%s: intftype %d pack_mask %x: 0x%x, %x:0x%x\n",
+		__func__, intftype, pack_addr[0],
+		pack_cfg_mask[0], pack_addr[1],
+		pack_cfg_mask[1]);
+	msm_camera_io_w_mb(pack_cfg_mask[0], ispif->base + pack_addr[0]);
+	msm_camera_io_w_mb(pack_cfg_mask[1], ispif->base + pack_addr[1]);
+}
+#endif /* __MSM_ISPIF_HWREG_V3_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/Makefile b/drivers/media/platform/msm/camera_v2/jpeg_10/Makefile
new file mode 100644
index 0000000..0b8dc1d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/Makefile
@@ -0,0 +1,7 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/jpeg_10
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+
+obj-$(CONFIG_MSMB_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h
new file mode 100644
index 0000000..bf49086
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_common.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_COMMON_H
+#define MSM_JPEG_COMMON_H
+
+#define JPEG_DBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define JPEG_PR_ERR   pr_err
+#define JPEG_DBG_HIGH   pr_debug
+
+#define JPEG_BUS_VOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 1)
+#define JPEG_BUS_UNVOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 0)
+
+enum JPEG_MODE {
+	JPEG_MODE_DISABLE,
+	JPEG_MODE_OFFLINE,
+	JPEG_MODE_REALTIME,
+	JPEG_MODE_REALTIME_ROTATION
+};
+
+enum JPEG_ROTATION {
+	JPEG_ROTATION_0,
+	JPEG_ROTATION_90,
+	JPEG_ROTATION_180,
+	JPEG_ROTATION_270
+};
+
+#endif /* MSM_JPEG_COMMON_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
new file mode 100644
index 0000000..dc9b664
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.c
@@ -0,0 +1,384 @@
+/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
+	void *base, int size) {
+	unsigned long flags;
+	int rc = 0;
+	int tm = 500; /*500ms*/
+
+	JPEG_DBG("%s:%d] reset", __func__, __LINE__);
+	memset(&pgmn_dev->fe_pingpong_buf, 0,
+		sizeof(pgmn_dev->fe_pingpong_buf));
+	pgmn_dev->fe_pingpong_buf.is_fe = 1;
+	memset(&pgmn_dev->we_pingpong_buf, 0,
+		sizeof(pgmn_dev->we_pingpong_buf));
+	spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+	pgmn_dev->reset_done_ack = 0;
+	if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC)
+		msm_jpeg_hw_reset(base, size);
+	else
+		msm_jpeg_hw_reset_dma(base, size);
+
+	spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+	rc = wait_event_timeout(
+			pgmn_dev->reset_wait,
+			pgmn_dev->reset_done_ack,
+			msecs_to_jiffies(tm));
+
+	if (!pgmn_dev->reset_done_ack) {
+		JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
+		return -EBUSY;
+	}
+
+	JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
+	spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+	pgmn_dev->reset_done_ack = 0;
+	pgmn_dev->state = MSM_JPEG_RESET;
+	spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+
+	return 0;
+}
+
+void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev)
+{
+	int i = 0;
+
+	for (i = 0; i < 2; i++) {
+		if (pgmn_dev->we_pingpong_buf.buf_status[i] &&
+			pgmn_dev->release_buf)
+			msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl,
+				pgmn_dev->we_pingpong_buf.buf[i].ion_fd);
+		pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
+	}
+}
+
+void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev)
+{
+	init_waitqueue_head(&pgmn_dev->reset_wait);
+	spin_lock_init(&pgmn_dev->reset_lock);
+}
+
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev)
+{
+	msm_jpeg_hw_fe_start(pgmn_dev->base);
+	return 0;
+}
+
+/* fetch engine */
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf)
+{
+	int rc = 0;
+
+	if (buf->cbcr_len == 0)
+		buf->cbcr_buffer_addr = 0x0;
+
+	JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, buf->y_len,
+		(int) buf->cbcr_buffer_addr, buf->cbcr_len);
+
+	if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
+		rc = msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf,
+			buf, pgmn_dev->base);
+		if (rc < 0)
+			return rc;
+		msm_jpeg_hw_fe_mmu_prefetch(buf, pgmn_dev->base,
+			pgmn_dev->decode_flag);
+	} else {
+		rc = msm_jpegdma_hw_pingpong_update(
+			&pgmn_dev->fe_pingpong_buf, buf, pgmn_dev->base);
+		if (rc < 0)
+			return rc;
+		msm_jpegdma_hw_fe_mmu_prefetch(buf, pgmn_dev->base);
+	}
+
+	return rc;
+}
+
+static void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
+{
+	return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf) {
+
+	JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+		buf->y_len);
+
+	pgmn_dev->we_pingpong_buf.buf[0] = *buf;
+	pgmn_dev->we_pingpong_buf.buf_status[0] = 1;
+
+	if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
+		msm_jpeg_hw_we_buffer_update(
+			&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
+		msm_jpeg_hw_we_mmu_prefetch(buf, pgmn_dev->base,
+			pgmn_dev->decode_flag);
+	} else {
+		msm_jpegdma_hw_we_buffer_update(
+			&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
+		msm_jpegdma_hw_we_mmu_prefetch(buf, pgmn_dev->base);
+	}
+
+	return 0;
+}
+
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_hw_buf *buf)
+{
+	int i = 0;
+
+	for (i = 0; i < 2; i++) {
+		if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr
+			== buf->y_buffer_addr)
+			pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
+	}
+	return 0;
+}
+
+static void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf);
+}
+
+static void *msm_jpeg_core_framedone_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
+{
+	struct msm_jpeg_hw_buf *buf_p;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	buf_p = msm_jpeg_hw_pingpong_active_buffer(
+		&pgmn_dev->we_pingpong_buf);
+	if (buf_p && !pgmn_dev->decode_flag) {
+		buf_p->framedone_len =
+			msm_jpeg_hw_encode_output_size(pgmn_dev->base);
+		JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+			buf_p->framedone_len);
+	}
+
+	return buf_p;
+}
+
+static void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
+{
+	/* @todo return the status back to msm_jpeg_core_reset */
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return NULL;
+}
+
+static void *msm_jpeg_core_err_irq(int jpeg_irq_status,
+	struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status);
+	return NULL;
+}
+
+static int (*msm_jpeg_irq_handler)(int, void *, void *);
+
+static void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev,
+	 int jpeg_irq_status)
+{
+	void *data = NULL;
+
+	data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+		pgmn_dev);
+	if (msm_jpeg_irq_handler)
+		msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+			pgmn_dev, data);
+	data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status,
+		pgmn_dev);
+	if (msm_jpeg_irq_handler)
+		msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE,
+			pgmn_dev, data);
+}
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	int jpeg_irq_status;
+	struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context;
+
+	JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+	jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base);
+
+	JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
+		jpeg_irq_status);
+
+	/*For reset and framedone IRQs, clear all bits*/
+	if (pgmn_dev->state == MSM_JPEG_IDLE) {
+		JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
+		__func__, __LINE__, pgmn_dev->state);
+		JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
+		__LINE__);
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+		return IRQ_HANDLED;
+	} else if (jpeg_irq_status & 0x10000000) {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+	} else if (jpeg_irq_status & 0x1) {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+		if (pgmn_dev->decode_flag)
+			msm_jpeg_decode_status(pgmn_dev->base);
+	} else {
+		msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			jpeg_irq_status, pgmn_dev->base);
+	}
+
+	if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
+		/* send fe ping pong irq */
+		JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
+		data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+			pgmn_dev);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+				context, data);
+		data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
+			pgmn_dev);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
+				context, data);
+		pgmn_dev->state = MSM_JPEG_INIT;
+	}
+	if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
+		data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
+			pgmn_dev);
+		spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+		pgmn_dev->reset_done_ack = 1;
+		spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+		wake_up(&pgmn_dev->reset_wait);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_RESET_ACK,
+				context, data);
+	}
+
+	/* Unexpected/unintended HW interrupt */
+	if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
+		if (pgmn_dev->state != MSM_JPEG_EXECUTING) {
+			/*Clear all the bits and ignore the IRQ*/
+			JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
+			__func__, __LINE__, pgmn_dev->state);
+			JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
+			__LINE__);
+			msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+			JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
+		} else {
+			if (pgmn_dev->decode_flag)
+				msm_jpeg_decode_status(pgmn_dev->base);
+			msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
+			data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
+			if (msm_jpeg_irq_handler) {
+				msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
+					context, data);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	int jpeg_irq_status;
+	struct msm_jpeg_device *pgmn_dev = context;
+
+	JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+	jpeg_irq_status = msm_jpegdma_hw_irq_get_status(pgmn_dev->base);
+
+	JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
+		jpeg_irq_status);
+
+	/*For reset and framedone IRQs, clear all bits*/
+	if (pgmn_dev->state == MSM_JPEG_IDLE) {
+		JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
+		__func__, __LINE__, pgmn_dev->state);
+		JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
+		__LINE__);
+		msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
+			JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
+		return IRQ_HANDLED;
+	} else if (jpeg_irq_status & 0x00000400) {
+		msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
+			JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
+	} else if (jpeg_irq_status & 0x1) {
+		msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
+			JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
+	} else {
+		msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
+			jpeg_irq_status, pgmn_dev->base);
+	}
+
+	if (msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status)) {
+		/* send fe ping pong irq */
+		JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
+		data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
+			pgmn_dev);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
+				context, data);
+		data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
+			pgmn_dev);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
+				context, data);
+		pgmn_dev->state = MSM_JPEG_INIT;
+	}
+	if (msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status)) {
+		data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
+			pgmn_dev);
+		spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
+		pgmn_dev->reset_done_ack = 1;
+		spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
+		wake_up(&pgmn_dev->reset_wait);
+		if (msm_jpeg_irq_handler)
+			msm_jpeg_irq_handler(
+				MSM_JPEG_HW_MASK_COMP_RESET_ACK,
+				context, data);
+	}
+
+	return IRQ_HANDLED;
+}
+
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+	msm_jpeg_irq_handler = irq_handler;
+}
+
+void msm_jpeg_core_irq_remove(void)
+{
+	msm_jpeg_irq_handler = NULL;
+}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.h
new file mode 100644
index 0000000..4ca2ccb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_core.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, 2014-2015, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_CORE_H
+#define MSM_JPEG_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_sync.h"
+
+#define msm_jpeg_core_buf msm_jpeg_hw_buf
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context);
+irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context);
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_jpeg_core_irq_remove(void);
+
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_hw_buf *buf);
+
+int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
+	void *base, int size);
+int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev);
+
+void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev);
+void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev);
+#endif /* MSM_JPEG_CORE_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
new file mode 100644
index 0000000..7d37d7e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
@@ -0,0 +1,318 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_jpeg.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+
+#define MSM_JPEG_NAME "jpeg"
+#define DEV_NAME_LEN 10
+
+static int msm_jpeg_open(struct inode *inode, struct file *filp)
+{
+	int rc = 0;
+
+	struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev,
+		struct msm_jpeg_device, cdev);
+	filp->private_data = pgmn_dev;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_jpeg_open(pgmn_dev);
+
+	JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+	return rc;
+}
+
+static int msm_jpeg_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+	JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_jpeg_release(pgmn_dev);
+
+	JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+	return rc;
+}
+#ifdef CONFIG_COMPAT
+static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc;
+	struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+	JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
+		__LINE__, _IOC_NR(cmd), pgmn_dev,
+	(unsigned long)arg);
+
+	rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+#endif
+static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc;
+	struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+	JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
+		__LINE__, _IOC_NR(cmd), pgmn_dev,
+	(unsigned long)arg);
+
+	rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+static const struct file_operations msm_jpeg_fops = {
+	.owner		= THIS_MODULE,
+	.open		 = msm_jpeg_open,
+	.release	= msm_jpeg_release,
+	.unlocked_ioctl = msm_jpeg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = msm_jpeg_compat_ioctl,
+#endif
+};
+
+static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *)sd->host_priv;
+
+	JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
+
+	JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev);
+
+	JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
+
+	rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+	pr_debug("%s: X\n", __func__);
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = {
+	.ioctl = msm_jpeg_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = {
+	.core = &msm_jpeg_subdev_core_ops,
+};
+
+struct msm_jpeg_priv_data {
+	enum msm_jpeg_core_type core_type;
+};
+
+static const struct msm_jpeg_priv_data msm_jpeg_priv_data_jpg = {
+	.core_type = MSM_JPEG_CORE_CODEC
+};
+static const struct msm_jpeg_priv_data msm_jpeg_priv_data_dma = {
+	.core_type = MSM_JPEG_CORE_DMA
+};
+
+static const struct of_device_id msm_jpeg_dt_match[] = {
+	{.compatible = "qcom,jpeg", .data = &msm_jpeg_priv_data_jpg},
+	{.compatible = "qcom,jpeg_dma", .data = &msm_jpeg_priv_data_dma},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
+
+static int msm_jpeg_init_dev(struct platform_device *pdev)
+{
+	int rc = -1;
+	struct device *dev;
+	struct msm_jpeg_device *msm_jpeg_device_p;
+	const struct of_device_id *device_id;
+	const struct msm_jpeg_priv_data *priv_data;
+	char devname[DEV_NAME_LEN];
+
+	msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
+	if (!msm_jpeg_device_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+
+	msm_jpeg_device_p->pdev = pdev;
+
+	device_id = of_match_device(msm_jpeg_dt_match, &pdev->dev);
+	if (!device_id) {
+		JPEG_PR_ERR("%s: device_id is NULL\n", __func__);
+		goto fail;
+	}
+
+	priv_data = device_id->data;
+	msm_jpeg_device_p->core_type = priv_data->core_type;
+
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+			&pdev->id);
+
+	snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
+
+	rc = __msm_jpeg_init(msm_jpeg_device_p);
+	if (rc < -1) {
+		JPEG_PR_ERR("%s: initialization failed\n", __func__);
+		goto fail;
+	}
+
+	v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops);
+	v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p);
+	JPEG_DBG("%s: msm_jpeg_device_p 0x%lx", __func__,
+			(unsigned long)msm_jpeg_device_p);
+
+	rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1,
+				devname);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+		goto fail_1;
+	}
+
+	if (!msm_jpeg_device_p->msm_jpeg_class) {
+		msm_jpeg_device_p->msm_jpeg_class =
+				class_create(THIS_MODULE, devname);
+		if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) {
+			rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class);
+			JPEG_PR_ERR("%s: create device class failed\n",
+				__func__);
+			goto fail_2;
+		}
+	}
+
+	dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL,
+		MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno),
+		MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL,
+		"%s%d", MSM_JPEG_NAME, pdev->id);
+	if (IS_ERR(dev)) {
+		JPEG_PR_ERR("%s: error creating device\n", __func__);
+		rc = -ENODEV;
+		goto fail_3;
+	}
+
+	cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops);
+	msm_jpeg_device_p->cdev.owner = THIS_MODULE;
+	msm_jpeg_device_p->cdev.ops	 =
+		(const struct file_operations *) &msm_jpeg_fops;
+	rc = cdev_add(&msm_jpeg_device_p->cdev,
+			msm_jpeg_device_p->msm_jpeg_devno, 1);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: error adding cdev\n", __func__);
+		rc = -ENODEV;
+		goto fail_4;
+	}
+
+	platform_set_drvdata(pdev, msm_jpeg_device_p);
+
+	JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id);
+
+	return rc;
+
+fail_4:
+	device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+			msm_jpeg_device_p->msm_jpeg_devno);
+
+fail_3:
+	class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+
+fail_2:
+	unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+
+fail_1:
+	__msm_jpeg_exit(msm_jpeg_device_p);
+	return rc;
+
+fail:
+	kfree(msm_jpeg_device_p);
+	return rc;
+
+}
+
+static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p)
+{
+	cdev_del(&msm_jpeg_device_p->cdev);
+	device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+			msm_jpeg_device_p->msm_jpeg_devno);
+	class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+	unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+	cam_smmu_destroy_handle(msm_jpeg_device_p->iommu_hdl);
+
+	__msm_jpeg_exit(msm_jpeg_device_p);
+}
+
+static int __msm_jpeg_probe(struct platform_device *pdev)
+{
+	return msm_jpeg_init_dev(pdev);
+}
+
+static int __msm_jpeg_remove(struct platform_device *pdev)
+{
+	struct msm_jpeg_device *msm_jpegd_device_p;
+
+	msm_jpegd_device_p = platform_get_drvdata(pdev);
+	if (msm_jpegd_device_p)
+		msm_jpeg_exit(msm_jpegd_device_p);
+
+	return 0;
+}
+
+static struct platform_driver msm_jpeg_driver = {
+	.probe	= __msm_jpeg_probe,
+	.remove = __msm_jpeg_remove,
+	.driver = {
+		.name = "msm_jpeg",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_jpeg_dt_match,
+	},
+};
+
+static int __init msm_jpeg_driver_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&msm_jpeg_driver);
+	return rc;
+}
+
+static void __exit msm_jpeg_driver_exit(void)
+{
+	platform_driver_unregister(&msm_jpeg_driver);
+}
+
+MODULE_DESCRIPTION("msm jpeg jpeg driver");
+
+module_init(msm_jpeg_driver_init);
+module_exit(msm_jpeg_driver_exit);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
new file mode 100644
index 0000000..ea82832
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -0,0 +1,955 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_common.h"
+#include "msm_camera_io_util.h"
+
+#include <linux/io.h>
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf, void *base)
+{
+	int buf_free_index = -1;
+
+	if (!pingpong_hw->buf_status[0]) {
+		buf_free_index = 0;
+	} else if (!pingpong_hw->buf_status[1]) {
+		buf_free_index = 1;
+	} else {
+		JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
+		__func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pingpong_hw->buf[buf_free_index] = *buf;
+	pingpong_hw->buf_status[buf_free_index] = 1;
+
+	if (pingpong_hw->is_fe) {
+		/* it is fe */
+		msm_jpeg_hw_fe_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
+	} else {
+		/* it is we */
+		msm_jpeg_hw_we_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
+	}
+	return 0;
+}
+
+int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf, void *base)
+{
+	int buf_free_index = -1;
+
+	if (!pingpong_hw->buf_status[0]) {
+		buf_free_index = 0;
+	} else if (!pingpong_hw->buf_status[1]) {
+		buf_free_index = 1;
+	} else {
+		JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
+		__func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pingpong_hw->buf[buf_free_index] = *buf;
+	pingpong_hw->buf_status[buf_free_index] = 1;
+
+	if (pingpong_hw->is_fe) {
+		/* it is fe */
+		msm_jpegdma_hw_fe_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
+	} else {
+		/* it is we */
+		msm_jpegdma_hw_we_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index,
+			base);
+	}
+	return 0;
+}
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+	struct msm_jpeg_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+		pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+	}
+
+	pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+	return (void *) buf_p;
+}
+
+void *msm_jpeg_hw_pingpong_active_buffer(
+	struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+	struct msm_jpeg_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+	return (void *) buf_p;
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR,
+		JPEG_IRQ_STATUS_BMSK, {0} },
+};
+
+int msm_jpeg_hw_irq_get_status(void *base)
+{
+	uint32_t n_irq_status = 0;
+
+	n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base);
+	return n_irq_status;
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_irq_get_dmastatus[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEGDMA_IRQ_STATUS_ADDR,
+		JPEGDMA_IRQ_STATUS_BMSK, {0} },
+};
+
+int msm_jpegdma_hw_irq_get_status(void *base)
+{
+	uint32_t n_irq_status = 0;
+
+	n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_dmastatus[0], base);
+	return n_irq_status;
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_READ, 1,
+	JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR,
+	JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} },
+};
+
+long msm_jpeg_hw_encode_output_size(void *base)
+{
+	uint32_t encode_output_size = 0;
+
+	encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0],
+		base);
+
+	return encode_output_size;
+}
+
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
+{
+	struct msm_jpeg_hw_cmd cmd_irq_clear;
+
+	cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE;
+	cmd_irq_clear.n = 1;
+	cmd_irq_clear.offset = JPEG_IRQ_CLEAR_ADDR;
+	cmd_irq_clear.mask = mask;
+	cmd_irq_clear.data = data;
+	JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+	msm_jpeg_hw_write(&cmd_irq_clear, base);
+}
+
+void msm_jpegdma_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
+{
+	struct msm_jpeg_hw_cmd cmd_irq_clear;
+
+	cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE;
+	cmd_irq_clear.n = 1;
+	cmd_irq_clear.offset = JPEGDMA_IRQ_CLEAR_ADDR;
+	cmd_irq_clear.mask = mask;
+	cmd_irq_clear.data = data;
+	JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+	msm_jpeg_hw_write(&cmd_irq_clear, base);
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+		JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR,
+		JPEG_PLN0_RD_OFFSET_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR,
+		JPEG_PLN0_RD_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR,
+		JPEG_PLN1_RD_OFFSET_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR,
+		JPEG_PLN1_RD_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR,
+		JPEG_PLN1_RD_OFFSET_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR,
+		JPEG_PLN2_RD_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_fe_ping_update[0];
+		/* ensure write is done */
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		/* ensure write is done */
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		/* ensure write is done */
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		/* ensure write is done */
+		wmb();
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->y_buffer_addr;
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+		/* ensure write is done */
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		/* ensure write is done */
+		wmb();
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+		/* ensure write is done */
+		wmb();
+		msm_jpeg_hw_write(hw_cmd_p++, base);
+		/* ensure write is done */
+		wmb();
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->pln2_addr;
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+		/* ensure write is done */
+		wmb();
+	}
+}
+
+static struct msm_jpeg_hw_cmd hw_dma_cmd_fe_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
+		JPEGDMA_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR,
+		JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_0_RD_PNTR,
+		JPEG_PLN0_RD_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_1_RD_PNTR,
+		JPEG_PLN1_RD_PNTR_BMSK, {0} },
+};
+
+void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	if (pingpong_index != 0)
+		return;
+
+	hw_cmd_p = &hw_dma_cmd_fe_ping_update[0];
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = p_input->y_buffer_addr;
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+		JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_jpeg_hw_fe_start(void *base)
+{
+	msm_jpeg_hw_write(&hw_cmd_fe_start[0], base);
+
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_decode_status(void *base)
+{
+	uint32_t data;
+
+	data = msm_camera_io_r(
+		(void __iomem *)(base + JPEG_DECODE_MCUS_DECODED_STATUS));
+	JPEG_DBG_HIGH("Decode MCUs decode status %u", data);
+	data = msm_camera_io_r(
+		(void __iomem *)(base + JPEG_DECODE_BITS_CONSUMED_STATUS));
+	JPEG_DBG_HIGH("Decode bits consumed status %u", data);
+	data = msm_camera_io_r(
+		(void __iomem *)(base + JPEG_DECODE_PRED_Y_STATE));
+	JPEG_DBG_HIGH("Decode prediction Y state %u", data);
+	data = msm_camera_io_r(
+		(void __iomem *)(base + JPEG_DECODE_PRED_C_STATE));
+	JPEG_DBG_HIGH("Decode prediction C state %u", data);
+	data = msm_camera_io_r(
+		(void __iomem *)(base + JPEG_DECODE_RSM_STATE));
+	JPEG_DBG_HIGH("Decode prediction RSM state %u", data);
+}
+
+
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_we_ping_update[0];
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->y_buffer_addr;
+		JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__,
+			p_input->y_buffer_addr);
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
+		JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__,
+			p_input->cbcr_buffer_addr);
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = p_input->pln2_addr;
+		JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__,
+			p_input->pln2_addr);
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	}
+}
+
+static struct msm_jpeg_hw_cmd hw_dma_cmd_we_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR,
+		JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_0_WR_PNTR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_1_WR_PNTR,
+		JPEG_PLN0_WR_PNTR_BMSK, {0} },
+};
+void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	if (pingpong_index != 0)
+		return;
+
+	hw_cmd_p = &hw_dma_cmd_we_ping_update[0];
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+
+	/* ensure write is done */
+	wmb();
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = p_input->y_buffer_addr;
+	JPEG_DBG_HIGH("%s Output we 0 buffer address is %x\n", __func__,
+			p_input->y_buffer_addr);
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
+	JPEG_DBG_HIGH("%s Output we 1 buffer address is %x\n", __func__,
+			p_input->cbcr_buffer_addr);
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_fe_mmu_prefetch[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} },
+};
+
+/*
+ * msm_jpeg_hw_fe_mmu_prefetch() - writes fe min/max addrs for each plane to
+ * MMU prefetch registers.
+ * @buf: Pointer to jpeg hw buffer.
+ * @base: Pointer to base address.
+ * @decode_flag: Jpeg decode flag.
+ *
+ * This function writes fe min/max address for each plane to MMU prefetch
+ * registers, MMU prefetch hardware will only prefetch address translations
+ * within this min/max boundary.
+ *
+ * Return: None.
+ */
+void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
+	uint8_t decode_flag)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	hw_cmd_p = &hw_cmd_fe_mmu_prefetch[0];
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+
+	JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
+		__func__, __LINE__, tmp_hw_cmd.data);
+
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+	if (buf->y_len)
+		tmp_hw_cmd.data += buf->y_len - 1;
+
+	JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
+		__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
+
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+	if (!decode_flag) {
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->cbcr_buffer_addr;
+
+		JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->cbcr_buffer_addr;
+		if (buf->cbcr_len)
+			tmp_hw_cmd.data	+= buf->cbcr_len - 1;
+
+		JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n"
+			, __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->pln2_addr;
+
+		JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->pln2_addr;
+		if (buf->pln2_len)
+			tmp_hw_cmd.data += buf->pln2_len - 1;
+
+		JPEG_DBG("%s:%d: MAX pln2_buf_addr %08x, pln2_len %d\n"
+			, __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	}
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_we_mmu_prefetch[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MIN,
+		MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MAX,
+		MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK, {0} },
+};
+
+/*
+ * msm_jpeg_hw_we_mmu_prefetch() - write we min/max addrs for each plane to
+ * MMU prefetch registers.
+ * @buf: Pointer to jpeg hw buffer.
+ * @base: Pointer to base address.
+ * @decode_flag: Jpeg decode flag.
+ *
+ * This function writes we min/max address for each plane to MMU prefetch
+ * registers, MMU prefetch hardware will only prefetch address translations
+ * within this min/max boundary.
+ *
+ * Return: None.
+ */
+void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
+	uint8_t decode_flag)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	hw_cmd_p = &hw_cmd_we_mmu_prefetch[0];
+
+	/* ensure write is done */
+	wmb();
+	if (decode_flag) {
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->y_buffer_addr;
+
+		JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->y_buffer_addr;
+		if (buf->y_len)
+			tmp_hw_cmd.data += buf->y_len - 1;
+
+		JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
+			__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->cbcr_buffer_addr;
+
+		JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->cbcr_buffer_addr;
+		if (buf->cbcr_len)
+			tmp_hw_cmd.data += buf->cbcr_len - 1;
+
+		JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n"
+			, __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->pln2_addr;
+
+		JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->pln2_addr;
+		if (buf->pln2_len)
+			tmp_hw_cmd.data += buf->pln2_len - 1;
+
+		JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x, pln2_len %d\n"
+			, __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	} else {
+		hw_cmd_p += 4;
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->y_buffer_addr;
+
+		JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
+			__func__, __LINE__, tmp_hw_cmd.data);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+		tmp_hw_cmd = *hw_cmd_p++;
+		tmp_hw_cmd.data = buf->y_buffer_addr;
+		if (buf->y_len)
+			tmp_hw_cmd.data += buf->y_len - 1;
+
+		JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
+			__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
+
+		msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	}
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_dma_cmd_fe_mmu_prefetch[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN,
+		MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX,
+		MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK, {0} },
+};
+
+/*
+ * msm_jpegdma_hw_fe_mmu_prefetch() - write DMA fe min/max addrs to
+ * MMU prefetch registers.
+ * @buf: Pointer to jpeg hw buffer.
+ * @base: Pointer to base address.
+ *
+ * This function writes DMA fe min/max address for each plane to MMU prefetch
+ * registers, MMU prefetch hardware will only prefetch address translations
+ * with in this min/max boundary.
+ *
+ * Return: None.
+ */
+void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	hw_cmd_p = &hw_dma_cmd_fe_mmu_prefetch[0];
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+
+	JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n",
+		__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset);
+
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+	if (buf->y_len)
+		tmp_hw_cmd.data += buf->y_len - 1;
+
+	JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n",
+		__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset,
+		buf->y_len);
+
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_dma_cmd_we_mmu_prefetch[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN,
+		MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX,
+		MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
+};
+
+/*
+ * msm_jpegdma_hw_we_mmu_prefetch() - write DMA we min/max addrs to
+ * MMU prefetch registers.
+ * @buf: Pointer to jpeg hw buffer.
+ * @base: Pointer to base address.
+ *
+ * This function writes DMA we min/max address for each plane to MMU prefetch
+ * registers, MMU prefetch hardware will only prefetch address translations
+ * with in this min/max boundary.
+ *
+ * Return: None.
+ */
+void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+	struct msm_jpeg_hw_cmd tmp_hw_cmd;
+
+	hw_cmd_p = &hw_dma_cmd_we_mmu_prefetch[0];
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+
+	JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n",
+		__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset);
+
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+
+	tmp_hw_cmd = *hw_cmd_p++;
+	tmp_hw_cmd.data = buf->y_buffer_addr;
+	if (buf->y_len)
+		tmp_hw_cmd.data += buf->y_len - 1;
+
+	JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n",
+		__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset,
+		buf->y_len);
+
+	msm_jpeg_hw_write(&tmp_hw_cmd, base);
+	/* ensure write is done */
+	wmb();
+}
+
+static struct msm_jpeg_hw_cmd hw_cmd_reset[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+		JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR,
+		JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_jpeg_hw_reset(void *base, int size)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	hw_cmd_p = &hw_cmd_reset[0];
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p, base);
+	/* ensure write is done */
+	wmb();
+
+}
+static struct msm_jpeg_hw_cmd hw_cmd_reset_dma[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
+		JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_DISABLE_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_CLEAR_ADDR,
+		JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_CLEAR_ALL} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
+		JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_RESET_CMD_ADDR,
+		JPEGDMA_RESET_CMD_BMSK, {JPEGDMA_RESET_DEFAULT} },
+};
+
+void msm_jpeg_hw_reset_dma(void *base, int size)
+{
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	hw_cmd_p = &hw_cmd_reset_dma[0];
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p++, base);
+	/* ensure write is done */
+	wmb();
+	msm_jpeg_hw_write(hw_cmd_p, base);
+	/* ensure write is done */
+	wmb();
+
+}
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p,
+	 void *jpeg_region_base)
+{
+	uint32_t *paddr;
+	uint32_t data;
+
+	paddr = jpeg_region_base + hw_cmd_p->offset;
+
+	data = msm_camera_io_r((void __iomem *)paddr);
+	data &= hw_cmd_p->mask;
+
+	return data;
+}
+
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p,
+	void *jpeg_region_base)
+{
+	uint32_t *paddr;
+	uint32_t old_data, new_data;
+
+	paddr = jpeg_region_base + hw_cmd_p->offset;
+
+	if (hw_cmd_p->mask == 0xffffffff) {
+		old_data = 0;
+	} else {
+		old_data = msm_camera_io_r((void __iomem *)paddr);
+		old_data &= ~hw_cmd_p->mask;
+	}
+
+	new_data = hw_cmd_p->data & hw_cmd_p->mask;
+	new_data |= old_data;
+	JPEG_DBG("%s:%d] %pK %08x\n", __func__, __LINE__,
+		paddr, new_data);
+	msm_camera_io_w(new_data, (void __iomem *)paddr);
+}
+
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us,
+	void *base)
+{
+	int tm = hw_cmd_p->n;
+	uint32_t data;
+	uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+	data = msm_jpeg_hw_read(hw_cmd_p, base);
+	if (data != wait_data) {
+		while (tm) {
+			udelay(m_us);
+			data = msm_jpeg_hw_read(hw_cmd_p, base);
+			if (data == wait_data)
+				break;
+			tm--;
+		}
+	}
+	hw_cmd_p->data = data;
+	return tm;
+}
+
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+
+	while (tm) {
+		udelay(m_us);
+		tm--;
+	}
+}
+
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
+	uint32_t max_size, void *base)
+{
+	int is_copy_to_user = 0;
+	uint32_t data;
+
+	while (m_cmds--) {
+		if (hw_cmd_p->offset >= max_size) {
+			JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+				__LINE__, hw_cmd_p->offset, max_size);
+			return -EFAULT;
+		}
+		if (hw_cmd_p->offset & 0x3) {
+			JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__,
+					__LINE__, hw_cmd_p->offset);
+			return -EFAULT;
+		}
+
+		switch (hw_cmd_p->type) {
+		case MSM_JPEG_HW_CMD_TYPE_READ:
+			hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base);
+			is_copy_to_user = 1;
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_WRITE:
+			msm_jpeg_hw_write(hw_cmd_p, base);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
+			data = msm_jpeg_hw_read(hw_cmd_p, base);
+			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+				data;
+			msm_jpeg_hw_write(hw_cmd_p, base);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_UWAIT:
+			msm_jpeg_hw_wait(hw_cmd_p, 1, base);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_MWAIT:
+			msm_jpeg_hw_wait(hw_cmd_p, 1000, base);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_UDELAY:
+			msm_jpeg_hw_delay(hw_cmd_p, 1);
+			break;
+
+		case MSM_JPEG_HW_CMD_TYPE_MDELAY:
+			msm_jpeg_hw_delay(hw_cmd_p, 1000);
+			break;
+
+		default:
+			JPEG_PR_ERR("wrong hw command type\n");
+			break;
+		}
+
+		hw_cmd_p++;
+	}
+	return is_copy_to_user;
+}
+
+void msm_jpeg_io_dump(void *base, int size)
+{
+	char line_str[128];
+	void __iomem *addr = (void __iomem *)base;
+	int i;
+	void __iomem *p = addr;
+	size_t offset = 0;
+	size_t used = 0;
+	size_t min_range = 0;
+	size_t sizeof_line_str = sizeof(line_str);
+	u32 data;
+
+	JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size);
+	line_str[0] = '\0';
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			used = snprintf(line_str + offset,
+				sizeof_line_str - offset, "%pK ", p);
+			if ((used < min_range) ||
+				(offset + used >= sizeof_line_str)) {
+				JPEG_PR_ERR("%s\n", line_str);
+				offset = 0;
+				line_str[0] = '\0';
+			} else {
+				offset += used;
+			}
+		}
+		data = msm_camera_io_r(p++);
+		used = snprintf(line_str + offset,
+			sizeof_line_str - offset, "%08x ", data);
+		if ((used < min_range) ||
+			(offset + used >= sizeof_line_str)) {
+			JPEG_PR_ERR("%s\n", line_str);
+			offset = 0;
+			line_str[0] = '\0';
+		} else {
+			offset += used;
+		}
+		if ((i + 1) % 4 == 0) {
+			JPEG_DBG_HIGH("%s\n", line_str);
+			line_str[0] = '\0';
+			offset = 0;
+		}
+	}
+	if (line_str[0] != '\0')
+		JPEG_DBG_HIGH("%s\n", line_str);
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
new file mode 100644
index 0000000..5d35e4e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
@@ -0,0 +1,142 @@
+/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_HW_H
+#define MSM_JPEG_HW_H
+
+#include <media/msm_jpeg.h>
+#include "msm_jpeg_hw_reg.h"
+#include <linux/ion.h>
+
+struct msm_jpeg_hw_buf {
+	struct msm_jpeg_buf vbuf;
+	struct file  *file;
+	uint32_t framedone_len;
+	uint32_t y_buffer_addr;
+	uint32_t y_len;
+	uint32_t cbcr_buffer_addr;
+	uint32_t cbcr_len;
+	uint32_t num_of_mcu_rows;
+	int ion_fd;
+	uint32_t pln2_addr;
+	uint32_t pln2_len;
+};
+
+struct msm_jpeg_hw_pingpong {
+	uint8_t is_fe; /* 1: fe; 0: we */
+	struct  msm_jpeg_hw_buf buf[2];
+	int     buf_status[2];
+	int     buf_active_index;
+};
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf, void *base);
+int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+	struct msm_jpeg_hw_buf *buf, void *base);
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw);
+void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong
+	*pingpong_hw);
+
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base);
+void msm_jpegdma_hw_irq_clear(uint32_t mask, uint32_t data, void *base);
+int msm_jpeg_hw_irq_get_status(void *base);
+int msm_jpegdma_hw_irq_get_status(void *base);
+long msm_jpeg_hw_encode_output_size(void *base);
+#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \
+		MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_FE \
+		MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_WE \
+		(MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+		 MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \
+		MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_JPEG_HW_MASK_COMP_ERR \
+		(MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \
+		MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \
+		MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE)
+#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE)
+#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE)
+#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK)
+#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR)
+
+
+#define MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE \
+		MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_JPEGDMA_HW_MASK_COMP_FE \
+		MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_JPEGDMA_HW_MASK_COMP_WE \
+		(MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK)
+#define MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK \
+		MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK
+
+
+#define msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE)
+#define msm_jpegdma_hw_irq_is_fe_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FE)
+#define msm_jpegdma_hw_irq_is_we_pingpong(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_WE)
+#define msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status) \
+	(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK)
+
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base);
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base);
+void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base);
+void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+	uint8_t pingpong_index, void *base);
+
+
+void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
+	uint8_t decode_flag);
+void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
+	uint8_t decode_flag);
+void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base);
+void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base);
+
+void msm_jpeg_hw_fe_start(void *base);
+void msm_jpeg_hw_clk_cfg(void);
+
+void msm_jpeg_hw_reset(void *base, int size);
+void msm_jpeg_hw_irq_cfg(void);
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p, void *base);
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p, void *base);
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us, void *base);
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p,
+	uint32_t m_cmds, uint32_t max_size, void *base);
+void msm_jpeg_hw_region_dump(int size);
+void msm_jpeg_io_dump(void *base, int size);
+void msm_jpeg_decode_status(void *base);
+void msm_jpeg_hw_reset_dma(void *base, int size);
+
+#endif /* MSM_JPEG_HW_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h
new file mode 100644
index 0000000..a1c00d0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw_reg.h
@@ -0,0 +1,210 @@
+/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_HW_REG_H
+#define MSM_JPEG_HW_REG_H
+
+#define JPEG_REG_BASE 0
+
+#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018
+#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF
+#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF
+
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF      (0x1<<19)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR     (0x1<<20)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR   (0x1<<21)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW    (0x1<<23)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM       (0x1<<24)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ   (0x1<<25)
+#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM       (0x1<<26)
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK        (0x1<<29)
+
+#define JPEG_OFFLINE_CMD_START 0x00000001
+
+#define JPEG_RESET_DEFAULT 0x00032093
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
+
+#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038)
+#define JPEG_PLN0_RD_PNTR_BMSK  0xFFFFFFFF
+
+#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C
+#define JPEG_PLN0_RD_OFFSET_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044)
+#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048
+#define JPEG_PLN1_RD_OFFSET_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050)
+#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054
+#define JPEG_PLN2_RD_OFFSET_BMSK 0xFFFFFFFF
+
+#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010)
+#define JPEG_CMD_BMSK 0xFFFFFFFF
+#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700
+
+#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc)
+#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
+#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4)
+#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018)
+#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
+
+#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c)
+#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF
+
+#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
+#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020)
+#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000310)
+#define MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000314)
+#define MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x0000031C)
+#define MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000320)
+#define MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S2_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000328)
+#define MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S2_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x0000032C)
+#define MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S3_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000334)
+#define MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEG_S3_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000338)
+#define MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
+
+#define JPEG_DECODE_MCUS_DECODED_STATUS   (JPEG_REG_BASE + 0x00000258)
+#define JPEG_DECODE_BITS_CONSUMED_STATUS  (JPEG_REG_BASE + 0x0000025C)
+#define JPEG_DECODE_PRED_Y_STATE          (JPEG_REG_BASE + 0x00000260)
+#define JPEG_DECODE_PRED_C_STATE          (JPEG_REG_BASE + 0x00000264)
+#define JPEG_DECODE_RSM_STATE             (JPEG_REG_BASE + 0x00000268)
+
+#define JPEG_HW_VERSION                   (JPEG_REG_BASE + 0x00000000)
+
+#define VBIF_BASE_ADDRESS                      0xFDA60000
+#define VBIF_REGION_SIZE                       0xC30
+#define JPEG_VBIF_CLKON                        0x4
+#define JPEG_VBIF_IN_RD_LIM_CONF0              0xB0
+#define JPEG_VBIF_IN_RD_LIM_CONF1              0xB4
+#define JPEG_VBIF_IN_RD_LIM_CONF2              0xB8
+#define JPEG_VBIF_IN_WR_LIM_CONF0              0xC0
+#define JPEG_VBIF_IN_WR_LIM_CONF1              0xC4
+#define JPEG_VBIF_IN_WR_LIM_CONF2              0xC8
+#define JPEG_VBIF_OUT_RD_LIM_CONF0             0xD0
+#define JPEG_VBIF_OUT_WR_LIM_CONF0             0xD4
+#define JPEG_VBIF_DDR_OUT_MAX_BURST            0xD8
+#define JPEG_VBIF_OCMEM_OUT_MAX_BURST          0xDC
+#define JPEG_VBIF_ARB_CTL                      0xF0
+#define JPEG_VBIF_OUT_AXI_AOOO_EN              0x178
+#define JPEG_VBIF_OUT_AXI_AOOO                 0x17c
+#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB          0x124
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0       0x160
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1       0x164
+
+#define JPEGDMA_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x0000000C)
+#define JPEGDMA_IRQ_MASK_BMSK 0xFFFFFFFF
+#define JPEGDMA_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
+
+#define JPEGDMA_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x00000014)
+#define JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF
+
+#define JPEGDMA_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
+#define JPEGDMA_RESET_CMD_BMSK 0xFFFFFFFF
+
+#define JPEGDMA_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000010)
+#define JPEGDMA_IRQ_STATUS_BMSK 0xFFFFFFFF
+#define JPEGDMA_RESET_DEFAULT 0x00032083
+
+
+#define JPEGDMA_CMD_ADDR (JPEG_REG_BASE + 0x0000001C)
+#define JPEGDMA_CMD_BMSK (0xFFFFFFFF)
+#define JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES  0x030
+#define JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES 0x300
+
+#define JPEGDMA_IRQ_DISABLE_ALL 0x00000000
+#define JPEGDMA_IRQ_CLEAR_ALL 0x00001FFF
+#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK  0x00000001
+#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000006
+#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK 0x00000060
+#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_SHIFT 0x00000005
+#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK  0x00000400
+#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_JPEGDMA_FE_0_RD_PNTR (JPEG_REG_BASE + 0x00000034)
+#define MSM_JPEGDMA_FE_1_RD_PNTR (JPEG_REG_BASE + 0x00000078)
+#define MSM_JPEGDMA_WE_0_WR_PNTR (JPEG_REG_BASE + 0x000000BC)
+#define MSM_JPEGDMA_WE_1_WR_PNTR (JPEG_REG_BASE + 0x000000EC)
+
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000190)
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000198)
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x000001A4)
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
+
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x000001AC)
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
+
+#endif /* MSM_JPEG_HW_REG_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
new file mode 100644
index 0000000..bb06e0a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -0,0 +1,549 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/iommu.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-buf.h>
+
+#include "msm_camera_io_util.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+#include "msm_jpeg_hw.h"
+
+#define JPEG_DT_PROP_CNT 2
+
+
+static int msm_jpeg_get_clock_index(struct msm_jpeg_device *pgmn_dev,
+	const char *clk_name)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < pgmn_dev->num_clk; i++) {
+		if (!strcmp(clk_name, pgmn_dev->jpeg_clk_info[i].clk_name))
+			return i;
+	}
+	return -EINVAL;
+}
+
+int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+		long clk_rate)
+{
+	int rc = 0;
+	int msm_jpeg_idx;
+
+	/* retrieve clock index from list of clocks */
+	msm_jpeg_idx = msm_jpeg_get_clock_index(pgmn_dev,
+		"core_clk");
+	if (msm_jpeg_idx < 0)  {
+		JPEG_PR_ERR("%s:Fail to get clock index\n", __func__);
+		return -EINVAL;
+	}
+
+	/* set the rate */
+	msm_camera_clk_set_rate(&pgmn_dev->pdev->dev,
+		pgmn_dev->jpeg_clk[msm_jpeg_idx], clk_rate);
+
+	return rc;
+}
+
+void msm_jpeg_platform_p2v(int iommu_hdl, int fd)
+{
+	cam_smmu_put_phy_addr(iommu_hdl, fd);
+}
+
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
+	uint32_t len, int iommu_hdl)
+{
+	dma_addr_t paddr;
+	size_t size;
+	int rc;
+
+	rc = cam_smmu_get_phy_addr(pgmn_dev->iommu_hdl, fd, CAM_SMMU_MAP_RW,
+			&paddr, &size);
+	JPEG_DBG("%s:%d] addr 0x%x size %zu", __func__, __LINE__,
+		(uint32_t)paddr, size);
+
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: fd %d got phy addr error %d\n", __func__, fd,
+			rc);
+		goto err_get_phy;
+	}
+
+	/* validate user input */
+	if (len > size) {
+		JPEG_PR_ERR("%s: invalid offset + len\n", __func__);
+		goto err_size;
+	}
+
+	return paddr;
+err_size:
+	cam_smmu_put_phy_addr(pgmn_dev->iommu_hdl, fd);
+err_get_phy:
+	return 0;
+}
+
+static void set_vbif_params(struct msm_jpeg_device *pgmn_dev,
+	 void *jpeg_vbif_base)
+{
+	msm_camera_io_w(0x1,
+		(void __iomem *)(jpeg_vbif_base + JPEG_VBIF_CLKON));
+
+	if (pgmn_dev->hw_version != JPEG_8994) {
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_RD_LIM_CONF0));
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_RD_LIM_CONF1));
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_RD_LIM_CONF2));
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_WR_LIM_CONF0));
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_WR_LIM_CONF1));
+		msm_camera_io_w(0x10101010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_IN_WR_LIM_CONF2));
+		msm_camera_io_w(0x00001010,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_OUT_RD_LIM_CONF0));
+		msm_camera_io_w(0x00000110,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_OUT_WR_LIM_CONF0));
+		msm_camera_io_w(0x00000707,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_DDR_OUT_MAX_BURST));
+		msm_camera_io_w(0x00000FFF,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_OUT_AXI_AOOO_EN));
+		msm_camera_io_w(0x0FFF0FFF,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_OUT_AXI_AOOO));
+		msm_camera_io_w(0x2222,
+			(void __iomem *)(jpeg_vbif_base +
+			JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1));
+	}
+
+	msm_camera_io_w(0x7,
+		(void __iomem *)(jpeg_vbif_base +
+		JPEG_VBIF_OCMEM_OUT_MAX_BURST));
+	msm_camera_io_w(0x00000030,
+		(void __iomem *)(jpeg_vbif_base +
+		JPEG_VBIF_ARB_CTL));
+
+	/* FE and WE QOS configuration need to be set when
+	 * QOS RR arbitration is enabled
+	 */
+	if (pgmn_dev->hw_version != JPEG_8974_V1)
+		msm_camera_io_w(0x00000003,
+				(void __iomem *)(jpeg_vbif_base +
+				JPEG_VBIF_ROUND_ROBIN_QOS_ARB));
+	else
+		msm_camera_io_w(0x00000001,
+				(void __iomem *)(jpeg_vbif_base +
+				JPEG_VBIF_ROUND_ROBIN_QOS_ARB));
+
+	msm_camera_io_w(0x22222222,
+		(void __iomem *)(jpeg_vbif_base +
+		JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0));
+
+}
+
+/*
+ * msm_jpeg_set_init_dt_parms() - get device tree config and write to registers.
+ * @pgmn_dev: Pointer to jpeg device.
+ * @dt_prop_name: Device tree property name.
+ * @base: Base address.
+ *
+ * This function reads register offsets and values from dtsi based on
+ * device tree property name and writes to jpeg registers.
+ *
+ * Return: 0 on success and negative error on failure.
+ */
+static int32_t msm_jpeg_set_init_dt_parms(struct msm_jpeg_device *pgmn_dev,
+	const char *dt_prop_name,
+	void *base)
+{
+	struct device_node *of_node;
+	int32_t i = 0, rc = 0;
+	uint32_t *dt_reg_settings = NULL;
+	uint32_t dt_count = 0;
+
+	of_node = pgmn_dev->pdev->dev.of_node;
+	JPEG_DBG("%s:%d E\n", __func__, __LINE__);
+
+	if (!of_get_property(of_node, dt_prop_name,
+				&dt_count)) {
+		JPEG_DBG("%s: Error property does not exist\n",
+				__func__);
+		return -ENOENT;
+	}
+	if (dt_count % 8) {
+		JPEG_PR_ERR("%s: Error invalid entries\n",
+				__func__);
+		return -EINVAL;
+	}
+	dt_count /= 4;
+	if (dt_count != 0) {
+		dt_reg_settings = kcalloc(dt_count, sizeof(uint32_t),
+			GFP_KERNEL);
+		if (!dt_reg_settings) {
+			JPEG_PR_ERR("%s:%d No memory\n",
+				__func__, __LINE__);
+			return -ENOMEM;
+		}
+		rc = of_property_read_u32_array(of_node,
+				dt_prop_name,
+				dt_reg_settings,
+				dt_count);
+		if (rc < 0) {
+			JPEG_PR_ERR("%s: No reg info\n",
+				__func__);
+			kfree(dt_reg_settings);
+			return -EINVAL;
+		}
+		for (i = 0; i < dt_count; i = i + 2) {
+			JPEG_DBG("%s:%d] %pK %08x\n",
+					__func__, __LINE__,
+					base + dt_reg_settings[i],
+					dt_reg_settings[i + 1]);
+			msm_camera_io_w(dt_reg_settings[i + 1],
+					(void __iomem *)
+					(base + dt_reg_settings[i]));
+		}
+		kfree(dt_reg_settings);
+	}
+	return 0;
+}
+
+static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc;
+
+	rc = cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_ATTACH);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: Device attach failed\n", __func__);
+		return -ENODEV;
+	}
+	JPEG_DBG("%s:%d] handle %d attach\n",
+			__func__, __LINE__, pgmn_dev->iommu_hdl);
+	return 0;
+}
+
+static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] handle %d detach\n",
+			__func__, __LINE__, pgmn_dev->iommu_hdl);
+	cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_DETACH);
+	return 0;
+}
+
+
+int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *),
+	void *context)
+{
+	int rc = -1;
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+	struct platform_device *pdev = pgmn_dev->pdev;
+
+	pgmn_dev->state = MSM_JPEG_IDLE;
+
+	/* enable all regulators */
+	rc = msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
+		pgmn_dev->num_reg, true);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: failed to enable regulators\n", __func__);
+		goto err_reg_enable;
+	}
+
+	/* enable all clocks */
+	rc = msm_camera_clk_enable(&pgmn_dev->pdev->dev,
+			pgmn_dev->jpeg_clk_info, pgmn_dev->jpeg_clk,
+			pgmn_dev->num_clk, true);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: clk enable failed\n", __func__);
+		goto err_clk_enable;
+	}
+
+	/* attach the smmu context banks */
+	rc = msm_jpeg_attach_iommu(pgmn_dev);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: iommu attach failed\n", __func__);
+		goto err_fail_iommu;
+	}
+	rc = msm_jpeg_set_init_dt_parms(pgmn_dev, "qcom,vbif-reg-settings",
+		pgmn_dev->vbif_base);
+	if (rc == -ENOENT) {
+		JPEG_DBG("%s: No qcom,vbif-reg-settings property\n", __func__);
+		set_vbif_params(pgmn_dev, pgmn_dev->vbif_base);
+	} else if (rc < 0) {
+		JPEG_PR_ERR("%s: vbif params set fail\n", __func__);
+		goto err_fail_set_vbif;
+	}
+
+	/* register the interrupt handler */
+	rc = msm_camera_register_irq(pgmn_dev->pdev,
+		pgmn_dev->jpeg_irq_res, handler, IRQF_TRIGGER_RISING,
+		"jpeg", context);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: irq request fail\n", __func__);
+		goto err_reg_irq_fail;
+	}
+
+	pgmn_dev->hw_version = msm_camera_io_r((void __iomem *)(pgmn_dev->base +
+		JPEG_HW_VERSION));
+	JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__,
+		pgmn_dev->hw_version);
+	pgmn_dev->state = MSM_JPEG_INIT;
+
+	return 0;
+err_reg_irq_fail:
+err_fail_set_vbif:
+	msm_jpeg_detach_iommu(pgmn_dev);
+err_fail_iommu:
+	msm_camera_clk_enable(&pdev->dev, pgmn_dev->jpeg_clk_info,
+		pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
+err_clk_enable:
+	msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
+		pgmn_dev->num_reg, false);
+err_reg_enable:
+	return rc;
+}
+
+int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc = -1;
+	int i;
+	struct resource *jpeg_irq_res;
+	void __iomem *jpeg_base, *vbif_base;
+	struct platform_device *pdev = pgmn_dev->pdev;
+
+	/* get the jpeg hardware device address */
+	jpeg_base = msm_camera_get_reg_base(pdev, "jpeg_hw", true);
+	if (!jpeg_base) {
+		JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	/* get the jpeg vbif device address */
+	vbif_base = msm_camera_get_reg_base(pdev, "jpeg_vbif", false);
+	if (!vbif_base) {
+		JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__);
+		rc = -ENXIO;
+		goto err_vbif_base;
+	}
+
+	/* get the irq resource for the jpeg hardware */
+	jpeg_irq_res = msm_camera_get_irq(pdev, "jpeg");
+	if (!jpeg_irq_res) {
+		JPEG_PR_ERR("%s: no irq resource?\n", __func__);
+		rc = -ENXIO;
+		goto err_jpeg_irq_res;
+	}
+
+	/* get all the clocks information */
+	rc = msm_camera_get_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
+		&pgmn_dev->jpeg_clk, &pgmn_dev->num_clk);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: failed to get the clocks\n", __func__);
+		rc = -ENXIO;
+		goto err_jpeg_clk;
+	}
+
+	/*set memcore and mem periphery logic flags to 0*/
+	for (i = 0; i < pgmn_dev->num_clk; i++) {
+		if ((strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
+				"core_clk") == 0) ||
+			(strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
+				"mmss_camss_jpeg_axi_clk") == 0)) {
+			msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
+				CLKFLAG_NORETAIN_MEM);
+			msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
+				CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+
+	/* get all the regulators information */
+	rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd,
+		&pgmn_dev->num_reg);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: failed to get the regulators\n", __func__);
+		rc = -ENXIO;
+		goto err_jpeg_get_reg;
+	}
+
+	/* map the dtsi cell id to bus client id */
+	switch (pgmn_dev->pdev->id) {
+	case 0:
+		pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC0;
+		break;
+	case 1:
+		pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC1;
+		break;
+	case 2:
+		pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DEC;
+		break;
+	case 3:
+		pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DMA;
+		break;
+	default:
+		JPEG_PR_ERR("%s: invalid cell id :%d\n",
+			__func__, pgmn_dev->pdev->id);
+		goto err_jpeg_get_reg;
+	}
+
+	/* register the bus client */
+	rc = msm_camera_register_bus_client(pgmn_dev->pdev,
+			pgmn_dev->bus_client);
+	if (rc < 0) {
+		JPEG_PR_ERR("Fail to register bus client\n");
+		rc = -EINVAL;
+		goto err_reg_bus;
+	}
+
+	/* get the resource size of jpeg hardware */
+	pgmn_dev->res_size = msm_camera_get_res_size(pdev, "jpeg_hw");
+	if (!pgmn_dev->res_size) {
+		JPEG_PR_ERR("Fail to resource size\n");
+		rc = -EINVAL;
+		goto err_res_size;
+	}
+
+	pgmn_dev->base = (__force void *)jpeg_base;
+	pgmn_dev->vbif_base = (__force void *)vbif_base;
+	pgmn_dev->jpeg_irq_res = jpeg_irq_res;
+
+	return 0;
+
+err_res_size:
+	msm_camera_unregister_bus_client(pgmn_dev->bus_client);
+err_reg_bus:
+	msm_camera_put_regulators(pdev, &pgmn_dev->jpeg_vdd,
+		pgmn_dev->num_reg);
+err_jpeg_get_reg:
+	msm_camera_put_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
+		&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
+err_jpeg_clk:
+err_jpeg_irq_res:
+	msm_camera_put_reg_base(pdev, vbif_base, "jpeg_vbif", false);
+err_vbif_base:
+	msm_camera_put_reg_base(pdev, jpeg_base, "jpeg_hw", true);
+out:
+	return rc;
+}
+
+void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev)
+{
+	/* unregister the bus client */
+	msm_camera_unregister_bus_client(pgmn_dev->bus_client);
+	/* release the regulators */
+	msm_camera_put_regulators(pgmn_dev->pdev, &pgmn_dev->jpeg_vdd,
+		pgmn_dev->num_reg);
+	/* release all the clocks */
+	msm_camera_put_clk_info(pgmn_dev->pdev, &pgmn_dev->jpeg_clk_info,
+		&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
+	/* release the jpeg device memory */
+	msm_camera_put_reg_base(pgmn_dev->pdev,
+		(void __iomem *)pgmn_dev->vbif_base,
+		"jpeg_vbif", false);
+	/* release the jpeg vbif device memory */
+	msm_camera_put_reg_base(pgmn_dev->pdev,
+		(void __iomem *)pgmn_dev->base,
+		"jpeg_hw", true);
+}
+
+int msm_jpeg_platform_release(void *context)
+{
+	int result = 0;
+
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+
+	/* release the irq */
+	msm_camera_unregister_irq(pgmn_dev->pdev,
+		pgmn_dev->jpeg_irq_res, context);
+
+	msm_jpeg_detach_iommu(pgmn_dev);
+
+	if (pgmn_dev->bus_client) {
+		if (pgmn_dev->jpeg_bus_vote) {
+			/* update the bw with zeroth vector */
+			msm_camera_update_bus_vector(pgmn_dev->bus_client, 0);
+			JPEG_BUS_UNVOTED(pgmn_dev);
+			JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__);
+		}
+	}
+
+	/* disable all the clocks */
+	msm_camera_clk_enable(&pgmn_dev->pdev->dev, pgmn_dev->jpeg_clk_info,
+		pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
+	JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
+
+	/* disable all the regulators */
+	msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
+		pgmn_dev->num_reg, false);
+	JPEG_DBG("%s:%d] regulator disable done", __func__, __LINE__);
+
+	pgmn_dev->state = MSM_JPEG_IDLE;
+	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+	return result;
+}
+
+/*
+ * msm_jpeg_platform_set_dt_config() - set jpeg device tree configuration.
+ * @pgmn_dev: Pointer to jpeg device.
+ *
+ * This function holds an array of device tree property names and calls
+ * msm_jpeg_set_init_dt_parms() for each property.
+ *
+ * Return: 0 on success and negative error on failure.
+ */
+int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc = 0;
+	uint8_t dt_prop_cnt = JPEG_DT_PROP_CNT;
+	char *dt_prop_name[JPEG_DT_PROP_CNT] = {"qcom,qos-reg-settings",
+		"qcom,prefetch-reg-settings"};
+
+	while (dt_prop_cnt) {
+		dt_prop_cnt--;
+		rc = msm_jpeg_set_init_dt_parms(pgmn_dev,
+			dt_prop_name[dt_prop_cnt],
+			pgmn_dev->base);
+		if (rc == -ENOENT) {
+			JPEG_DBG("%s: No %s property\n", __func__,
+				dt_prop_name[dt_prop_cnt]);
+		} else if (rc < 0) {
+			JPEG_PR_ERR("%s: %s params set fail\n", __func__,
+				dt_prop_name[dt_prop_cnt]);
+			return rc;
+		}
+	}
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
new file mode 100644
index 0000000..678582d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_PLATFORM_H
+#define MSM_JPEG_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+#include "msm_jpeg_sync.h"
+#define JPEG_CLK_RATE 266670000
+
+int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+		long clk_rate);
+void msm_jpeg_platform_p2v(int iommu_hdl, int fd);
+uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
+		uint32_t len, int iommu_hdl);
+
+int msm_jpeg_platform_clk_enable(void);
+int msm_jpeg_platform_clk_disable(void);
+
+int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *),
+	void *context);
+int msm_jpeg_platform_release(void *context);
+int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev);
+int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev);
+void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev);
+
+#endif /* MSM_JPEG_PLATFORM_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
new file mode 100644
index 0000000..3daee21
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -0,0 +1,1593 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/ratelimit.h>
+#include <media/msm_jpeg.h>
+#include <linux/msm-bus.h>
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+#include "cam_hw_ops.h"
+
+#define JPEG_REG_SIZE 0x308
+#define JPEG_DEV_CNT 4
+#define JPEG_DEC_ID 2
+#define UINT32_MAX (0xFFFFFFFFU)
+#define MAX_WAIT_TIMEOUT UINT_MAX
+
+
+#ifdef CONFIG_COMPAT
+
+#define MSM_JPEG_IOCTL_GET_HW_VERSION32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd32)
+
+#define MSM_JPEG_IOCTL_RESET32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32)
+
+#define MSM_JPEG_IOCTL_STOP32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_START32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_INPUT_GET32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_EVT_GET32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32)
+
+#define MSM_JPEG_IOCTL_HW_CMD32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd32)
+
+#define MSM_JPEG_IOCTL_HW_CMDS32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t)
+
+struct msm_jpeg_ctrl_cmd32 {
+	uint32_t type;
+	uint32_t len;
+	compat_uptr_t value;
+};
+struct msm_jpeg_buf32 {
+	uint32_t type;
+	int fd;
+
+	compat_uptr_t vaddr;
+
+	uint32_t y_off;
+	uint32_t y_len;
+	uint32_t framedone_len;
+
+	uint32_t cbcr_off;
+	uint32_t cbcr_len;
+
+	uint32_t num_of_mcu_rows;
+	uint32_t offset;
+	uint32_t pln2_off;
+	uint32_t pln2_len;
+};
+
+struct msm_jpeg_hw_cmd32 {
+
+	uint32_t type:4;
+
+	/* n microseconds of timeout for WAIT */
+	/* n microseconds of time for DELAY */
+	/* repeat n times for READ/WRITE */
+	/* max is 0xFFF, 4095 */
+	uint32_t n:12;
+	uint32_t offset:16;
+	uint32_t mask;
+	union {
+		uint32_t data;   /* for single READ/WRITE/WAIT, n = 1 */
+		compat_uptr_t pdata;   /* for multiple READ/WRITE/WAIT, n > 1 */
+	};
+};
+
+struct msm_jpeg_hw_cmds32 {
+	uint32_t m; /* number of elements in the hw_cmd array */
+	struct msm_jpeg_hw_cmd32 hw_cmd[1];
+};
+#endif
+
+
+inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+	q_p->name = name;
+	spin_lock_init(&q_p->lck);
+	INIT_LIST_HEAD(&q_p->q);
+	init_waitqueue_head(&q_p->wait);
+	q_p->unblck = 0;
+}
+
+inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p)
+{
+	unsigned long flags;
+	struct msm_jpeg_q_entry *q_entry_p = NULL;
+	void *data = NULL;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	spin_lock_irqsave(&q_p->lck, flags);
+	if (!list_empty(&q_p->q)) {
+		q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry,
+			list);
+		list_del_init(&q_entry_p->list);
+	}
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	if (q_entry_p) {
+		data = q_entry_p->data;
+		kfree(q_entry_p);
+	} else {
+		JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+			q_p->name);
+	}
+
+	return data;
+}
+
+inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data)
+{
+	unsigned long flags;
+
+	struct msm_jpeg_q_entry *q_entry_p;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+	q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC);
+	if (!q_entry_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+	q_entry_p->data = data;
+
+	spin_lock_irqsave(&q_p->lck, flags);
+	list_add_tail(&q_entry_p->list, &q_p->q);
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	return 0;
+}
+
+inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p,
+	struct msm_jpeg_core_buf *buf)
+{
+	struct msm_jpeg_core_buf *buf_p;
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s: no mem\n", __func__);
+		return -EFAULT;
+	}
+
+	memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf));
+
+	msm_jpeg_q_in(q_p, buf_p);
+	return 0;
+}
+
+inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p)
+{
+	long tm = MAX_WAIT_TIMEOUT; /* 500ms */
+	int rc;
+
+	JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+	rc = wait_event_timeout(q_p->wait,
+		(!list_empty_careful(&q_p->q) || q_p->unblck),
+		msecs_to_jiffies(tm));
+	JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+	if (list_empty_careful(&q_p->q)) {
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+				q_p->name);
+		} else if (q_p->unblck) {
+			JPEG_DBG("%s:%d] %s unblock is true\n", __func__,
+				__LINE__, q_p->name);
+			q_p->unblck = 0;
+			rc = -ECANCELED;
+		}
+	}
+	return rc;
+}
+
+inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p)
+{
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = 1;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_q *q_p)
+{
+	struct msm_jpeg_core_buf *buf_p;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		buf_p = msm_jpeg_q_out(q_p);
+		if (buf_p) {
+			msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl,
+					buf_p->ion_fd);
+			JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(buf_p);
+		}
+	} while (buf_p);
+	q_p->unblck = 0;
+}
+
+inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p)
+{
+	void *data;
+
+	JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		data = msm_jpeg_q_out(q_p);
+		if (data) {
+			JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(data);
+		}
+	} while (data);
+	q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+static int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	int rc = 0;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	if (buf_in) {
+		buf_in->vbuf.framedone_len = buf_in->framedone_len;
+		buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE;
+		JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+			__func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len,
+			buf_in->vbuf.framedone_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in);
+	} else {
+		JPEG_PR_ERR("%s:%d] no output return buffer\n",
+			__func__, __LINE__);
+		rc = -1;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+	return rc;
+}
+
+static int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_jpeg_q_wait(&pgmn_dev->evt_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
+	ctrl_cmd.type = buf_p->vbuf.type;
+	kfree(buf_p);
+
+	if (ctrl_cmd.type == MSM_JPEG_EVT_SESSION_DONE) {
+		/* update the bw with zeroth vector */
+		msm_camera_update_bus_vector(pgmn_dev->bus_client, 0);
+		JPEG_BUS_UNVOTED(pgmn_dev);
+		JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__);
+	}
+
+	JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+		(unsigned long) ctrl_cmd.value, ctrl_cmd.len);
+
+	if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+		JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->evt_q);
+	return 0;
+}
+
+static void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+static void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev,
+	int event)
+{
+	int rc = 0;
+	struct msm_jpeg_core_buf buf;
+
+	JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+	buf.vbuf.type = MSM_JPEG_EVT_ERR;
+	rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf);
+	if (!rc)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+	if (!rc)
+		JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+}
+
+/*************** output queue ****************/
+
+static int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	int rc = 0;
+	struct msm_jpeg_core_buf *buf_out;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+	} else {
+		JPEG_DBG("%s:%d] no output return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+		return rc;
+	}
+
+	buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+	if (buf_out) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_out->y_buffer_addr, buf_out->y_len);
+		rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out);
+		kfree(buf_out);
+	} else {
+		msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in);
+		JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q);
+
+	return rc;
+}
+
+static int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_jpeg_q_wait(&pgmn_dev->output_rtn_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no output buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd);
+	kfree(buf_p);
+
+	JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+		(unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		JPEG_PR_ERR("%s:%d]", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q);
+	return 0;
+}
+
+static inline int msm_jpeg_add_u32_check(uint32_t *p, uint32_t n, uint32_t *res)
+{
+	*res = 0;
+
+	while (n--) {
+		if ((*res + *p) < *res)
+			return -EFAULT;
+		*res += *p++;
+	}
+	return 0;
+}
+
+static int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_jpeg_buf buf_cmd;
+	struct msm_jpeg_core_buf *buf_p;
+	uint32_t buf_len_params[10];
+	uint32_t total_len = 0;
+	int n = 0;
+
+	memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_len_params[n++] = buf_cmd.y_len;
+	buf_len_params[n++] = buf_cmd.cbcr_len;
+	buf_len_params[n++] = buf_cmd.pln2_len;
+	buf_len_params[n++] = buf_cmd.offset;
+	buf_len_params[n++] = buf_cmd.y_off;
+	if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+
+	JPEG_DBG("%s:%d] vaddr = 0x%08lx y_len = %d\n, fd = %d",
+		__func__, __LINE__, (unsigned long) buf_cmd.vaddr,
+		buf_cmd.y_len, buf_cmd.fd);
+
+	buf_p->ion_fd = buf_cmd.fd;
+	buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
+		total_len, pgmn_dev->iommu_hdl);
+
+	if (!buf_p->y_buffer_addr) {
+		JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -EFAULT;
+	}
+
+	buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off;
+
+	if (buf_cmd.cbcr_len)
+		buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+			buf_cmd.y_len;
+	else
+		buf_p->cbcr_buffer_addr = 0x0;
+
+	if (buf_cmd.pln2_len)
+		buf_p->pln2_addr = buf_p->cbcr_buffer_addr +
+			buf_cmd.cbcr_len;
+	else
+		buf_p->pln2_addr = 0x0;
+
+	JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d",
+		__func__, __LINE__, buf_p->y_buffer_addr,
+		buf_cmd.y_len);
+
+	JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d",
+		buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr,
+		buf_p->pln2_addr, buf_cmd.pln2_len);
+
+	buf_p->y_len = buf_cmd.y_len;
+	buf_p->cbcr_len = buf_cmd.cbcr_len;
+	buf_p->pln2_len = buf_cmd.pln2_len;
+	buf_p->vbuf = buf_cmd;
+
+	msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
+	return 0;
+}
+
+/*************** input queue ****************/
+
+static int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+	struct msm_jpeg_core_buf *buf_in)
+{
+	struct msm_jpeg_core_buf *buf_out;
+	int rc = 0;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+	} else {
+		JPEG_DBG("%s:%d] no input return buffer\n", __func__,
+			__LINE__);
+		rc = -EFAULT;
+	}
+
+	buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+	if (buf_out) {
+		rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
+		kfree(buf_out);
+		msm_jpeg_core_fe_start(pgmn_dev);
+	} else {
+		JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+		rc = -EFAULT;
+	}
+
+	if (buf_in)
+		rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q);
+
+	return rc;
+}
+
+static int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_wait(&pgmn_dev->input_rtn_q);
+	buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q);
+
+	if (!buf_p) {
+		JPEG_DBG("%s:%d] no input buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+
+	msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd);
+	kfree(buf_p);
+
+	JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+		(unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q);
+	return 0;
+}
+
+static int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_jpeg_core_buf *buf_p;
+	struct msm_jpeg_buf buf_cmd;
+	uint32_t buf_len_params[10];
+	uint32_t total_len = 0;
+	int n = 0;
+
+	memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
+
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	buf_len_params[n++] = buf_cmd.y_len;
+	buf_len_params[n++] = buf_cmd.cbcr_len;
+	buf_len_params[n++] = buf_cmd.pln2_len;
+	buf_len_params[n++] = buf_cmd.offset;
+	buf_len_params[n++] = buf_cmd.y_off;
+	if (buf_cmd.cbcr_len)
+		buf_len_params[n++] = buf_cmd.cbcr_off;
+	if (buf_cmd.pln2_len)
+		buf_len_params[n++] = buf_cmd.pln2_off;
+
+	if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+		(unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+	buf_p->ion_fd = buf_cmd.fd;
+	buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
+		total_len, pgmn_dev->iommu_hdl);
+
+	if (!buf_p->y_buffer_addr) {
+		JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -EFAULT;
+	}
+
+	buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off;
+
+	buf_p->y_len          = buf_cmd.y_len;
+	buf_p->cbcr_len       = buf_cmd.cbcr_len;
+	buf_p->pln2_len       = buf_cmd.pln2_len;
+	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+
+	if (buf_cmd.cbcr_len)
+		buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+		buf_cmd.y_len + buf_cmd.cbcr_off;
+	else
+		buf_p->cbcr_buffer_addr = 0x0;
+
+	if (buf_cmd.pln2_len)
+		buf_p->pln2_addr = buf_p->cbcr_buffer_addr +
+		buf_cmd.cbcr_len + buf_cmd.pln2_off;
+	else
+		buf_p->pln2_addr = 0x0;
+
+	JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d",
+		__func__, buf_p->y_buffer_addr, buf_p->y_len,
+		buf_p->cbcr_buffer_addr, buf_p->cbcr_len);
+	JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n",
+		buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd);
+
+	buf_p->vbuf           = buf_cmd;
+
+	msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+	return 0;
+}
+
+static int msm_jpeg_irq(int event, void *context, void *data)
+{
+	struct msm_jpeg_device *pgmn_dev =
+		(struct msm_jpeg_device *) context;
+
+	switch (event) {
+	case MSM_JPEG_EVT_SESSION_DONE:
+		msm_jpeg_framedone_irq(pgmn_dev, data);
+		msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_FE:
+		msm_jpeg_fe_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_WE:
+		msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_RESET_ACK:
+		msm_jpeg_reset_ack_irq(pgmn_dev);
+		break;
+
+	case MSM_JPEG_HW_MASK_COMP_ERR:
+	default:
+		msm_jpeg_err_irq(pgmn_dev, event);
+		break;
+	}
+
+	return 0;
+}
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc;
+	irqreturn_t (*core_irq)(int, void *);
+
+	mutex_lock(&pgmn_dev->lock);
+	if (pgmn_dev->open_count) {
+		/* only open once */
+		JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EBUSY;
+	}
+	pgmn_dev->open_count++;
+	if (pgmn_dev->open_count == 1)
+		pgmn_dev->state = MSM_JPEG_INIT;
+
+	mutex_unlock(&pgmn_dev->lock);
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+
+	msm_jpeg_core_irq_install(msm_jpeg_irq);
+	if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC)
+		core_irq = msm_jpeg_core_irq;
+	else
+		core_irq = msm_jpegdma_core_irq;
+
+	/* initialize the platform resources */
+	rc = msm_jpeg_platform_init(core_irq, pgmn_dev);
+	if (rc) {
+		JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+			__LINE__, rc);
+		goto platform_init_fail;
+	}
+	JPEG_DBG("%s:%d] platform resources - base %pK, irq %d\n",
+		__func__, __LINE__,
+		pgmn_dev->base, (int)pgmn_dev->jpeg_irq_res->start);
+	msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q);
+	msm_jpeg_core_init(pgmn_dev);
+
+	JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+	return rc;
+
+platform_init_fail:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return rc;
+}
+
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	mutex_lock(&pgmn_dev->lock);
+	if (!pgmn_dev->open_count) {
+		JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EINVAL;
+	}
+	pgmn_dev->open_count--;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_jpeg_core_release(pgmn_dev);
+	msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q);
+	msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+	if (pgmn_dev->open_count)
+		JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+	/* release the platform resources */
+	msm_jpeg_platform_release(pgmn_dev);
+
+	JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+
+	return 0;
+}
+
+static int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_jpeg_hw_cmd hw_cmd;
+	int is_copy_to_user;
+
+	if (copy_from_user(&hw_cmd, (const void __user *)arg,
+		sizeof(struct msm_jpeg_hw_cmd))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+		pgmn_dev->res_size, pgmn_dev->base);
+	JPEG_DBG(
+	"%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %lx\n",
+		__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+		hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user((void __user *)arg, &hw_cmd, sizeof(hw_cmd))) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	} else {
+		return is_copy_to_user;
+	}
+
+	return 0;
+}
+
+static int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	int is_copy_to_user;
+	uint32_t len;
+	uint32_t m;
+	struct msm_jpeg_hw_cmds *hw_cmds_p;
+	struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) /
+		sizeof(struct msm_jpeg_hw_cmd)))) {
+		JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len = sizeof(struct msm_jpeg_hw_cmds) +
+		sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+	hw_cmds_p = kmalloc(len, GFP_KERNEL);
+	if (!hw_cmds_p) {
+		JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(hw_cmds_p, (const void __user *)arg, len)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		kfree(hw_cmds_p);
+		return -EFAULT;
+	}
+
+	hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m,
+		 pgmn_dev->res_size, pgmn_dev->base);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, hw_cmds_p, len)) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(hw_cmds_p);
+			return -EFAULT;
+		}
+	} else {
+		kfree(hw_cmds_p);
+		return is_copy_to_user;
+	}
+	kfree(hw_cmds_p);
+	return 0;
+}
+
+static int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void __user *arg,
+	int (*hw_ioctl)(struct msm_jpeg_device *, void __user *))
+{
+	struct msm_jpeg_core_buf *buf_out;
+	struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL};
+	int i, rc;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_jpeg_platform_set_dt_config(pgmn_dev);
+
+	/* update the bw with vector index "1" */
+	msm_camera_update_bus_vector(pgmn_dev->bus_client, 1);
+	JPEG_BUS_VOTED(pgmn_dev);
+	JPEG_DBG("%s:%d] Bus Voted\n", __func__, __LINE__);
+
+	pgmn_dev->release_buf = 1;
+	for (i = 0; i < 2; i++) {
+		buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+		if (buf_out) {
+			msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
+			kfree(buf_out);
+		} else {
+			JPEG_DBG("%s:%d] no input buffer\n", __func__,
+					__LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++) {
+		buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+		if (buf_out_free[i]) {
+			msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]);
+			pgmn_dev->release_buf = 0;
+		} else {
+			JPEG_DBG("%s:%d] no output buffer\n",
+			__func__, __LINE__);
+			break;
+		}
+	}
+
+	for (i = 0; i < 2; i++)
+		kfree(buf_out_free[i]);
+
+	JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__);
+	pgmn_dev->state = MSM_JPEG_EXECUTING;
+	/* ensure write is done */
+	wmb();
+	rc = hw_ioctl(pgmn_dev, arg);
+	/* ensure write is done */
+	wmb();
+	JPEG_DBG("%s:%d]", __func__, __LINE__);
+	return rc;
+}
+
+static int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	int rc;
+	struct msm_jpeg_ctrl_cmd ctrl_cmd, *p_ctrl_cmd;
+
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	p_ctrl_cmd = &ctrl_cmd;
+
+	if (pgmn_dev->state == MSM_JPEG_INIT) {
+		if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+		pgmn_dev->op_mode = p_ctrl_cmd->type;
+
+		rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode,
+			pgmn_dev->base, pgmn_dev->res_size);
+	} else {
+		JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n",
+			__func__, __LINE__);
+		rc = -1;
+	}
+	return rc;
+}
+
+static int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev,
+	unsigned long arg)
+{
+	JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
+	return 0;
+}
+
+static int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	long clk_rate;
+	int rc;
+
+	if ((pgmn_dev->state != MSM_JPEG_INIT) &&
+		(pgmn_dev->state != MSM_JPEG_RESET)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	if (get_user(clk_rate, (unsigned int __user *)arg)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__,
+		clk_rate);
+	if (clk_rate < 0) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+#ifdef CONFIG_COMPAT
+static int msm_jpeg_get_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd,
+	void __user  *arg)
+{
+	struct msm_jpeg_ctrl_cmd32 ctrl_cmd32;
+	unsigned long temp;
+
+	if (copy_from_user(&ctrl_cmd32, arg,
+		sizeof(struct msm_jpeg_ctrl_cmd32))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	ctrl_cmd->type = ctrl_cmd32.type;
+	ctrl_cmd->len = ctrl_cmd32.len;
+	temp = (unsigned long) ctrl_cmd32.value;
+	ctrl_cmd->value = (void *) temp;
+
+	return 0;
+}
+static int msm_jpeg_put_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd,
+	void __user  *arg)
+{
+	struct msm_jpeg_ctrl_cmd32 ctrl_cmd32;
+	unsigned long temp;
+
+	ctrl_cmd32.type   = ctrl_cmd->type;
+	ctrl_cmd32.len    = ctrl_cmd->len;
+	temp = (unsigned long) ctrl_cmd->value;
+	ctrl_cmd32.value  = (compat_uptr_t) temp;
+
+	if (copy_to_user(arg, &ctrl_cmd32,
+		sizeof(struct msm_jpeg_ctrl_cmd32))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int msm_jpeg_get_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf,
+	void __user  *arg)
+{
+	struct msm_jpeg_buf32 jpeg_buf32;
+	unsigned long temp;
+
+	if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	jpeg_buf->type            = jpeg_buf32.type;
+	jpeg_buf->fd              = jpeg_buf32.fd;
+	temp = (unsigned long) jpeg_buf32.vaddr;
+	jpeg_buf->vaddr           = (void *) temp;
+	jpeg_buf->y_off           = jpeg_buf32.y_off;
+	jpeg_buf->y_len           = jpeg_buf32.y_len;
+	jpeg_buf->framedone_len   = jpeg_buf32.framedone_len;
+	jpeg_buf->cbcr_off        = jpeg_buf32.cbcr_off;
+	jpeg_buf->cbcr_len        = jpeg_buf32.cbcr_len;
+	jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows;
+	jpeg_buf->offset          = jpeg_buf32.offset;
+	jpeg_buf->pln2_off        = jpeg_buf32.pln2_off;
+	jpeg_buf->pln2_len        = jpeg_buf32.pln2_len;
+
+	return 0;
+}
+static int msm_jpeg_put_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf,
+	void __user  *arg)
+{
+	struct msm_jpeg_buf32 jpeg_buf32;
+	unsigned long temp;
+
+	jpeg_buf32.type            = jpeg_buf->type;
+	jpeg_buf32.fd              = jpeg_buf->fd;
+	temp = (unsigned long) jpeg_buf->vaddr;
+	jpeg_buf32.vaddr           = (compat_uptr_t) temp;
+	jpeg_buf32.y_off           = jpeg_buf->y_off;
+	jpeg_buf32.y_len           = jpeg_buf->y_len;
+	jpeg_buf32.framedone_len   = jpeg_buf->framedone_len;
+	jpeg_buf32.cbcr_off        = jpeg_buf->cbcr_off;
+	jpeg_buf32.cbcr_len        = jpeg_buf->cbcr_len;
+	jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows;
+	jpeg_buf32.offset          = jpeg_buf->offset;
+	jpeg_buf32.pln2_off        = jpeg_buf->pln2_off;
+	jpeg_buf32.pln2_len        = jpeg_buf->pln2_len;
+
+	if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int msm_jpeg_put_hw_cmd32(void __user *arg,
+	struct msm_jpeg_hw_cmd *phw_cmd, int copy)
+{
+	struct msm_jpeg_hw_cmd32 hw_cmd32;
+	struct msm_jpeg_hw_cmd32 *phw_cmd32;
+
+	phw_cmd32 = (__force struct msm_jpeg_hw_cmd32 *) arg;
+	if (copy)
+		phw_cmd32 = &hw_cmd32;
+
+
+	phw_cmd32->type   =  phw_cmd->type;
+	phw_cmd32->n      =  phw_cmd->n;
+	phw_cmd32->offset =  phw_cmd->offset;
+	phw_cmd32->mask   =  phw_cmd->mask;
+	phw_cmd32->data   =  phw_cmd->data;
+
+	if (copy && copy_to_user(arg, &hw_cmd32, sizeof(hw_cmd32))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+static int msm_jpeg_get_hw_cmd32(struct msm_jpeg_hw_cmd *phw_cmd,
+	void __user *arg, int copy)
+{
+	struct msm_jpeg_hw_cmd32 hw_cmd32;
+	struct msm_jpeg_hw_cmd32 *phw_cmd32;
+
+	if (copy) {
+		phw_cmd32 = &hw_cmd32;
+		if (copy_from_user(&hw_cmd32, arg, sizeof(hw_cmd32))) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	} else {
+		phw_cmd32 = (__force struct msm_jpeg_hw_cmd32 *) arg;
+	}
+	phw_cmd->type   = phw_cmd32->type;
+	phw_cmd->n      = phw_cmd32->n;
+	phw_cmd->offset = phw_cmd32->offset;
+	phw_cmd->mask   = phw_cmd32->mask;
+	phw_cmd->data   = phw_cmd32->data;
+
+	return 0;
+}
+static int msm_jpeg_ioctl_hw_cmds32(struct msm_jpeg_device *pgmn_dev,
+	void __user *arg)
+{
+	int is_copy_to_user;
+	uint32_t len, len32;
+	uint32_t m;
+	struct msm_jpeg_hw_cmds32 *phw_cmds32;
+	struct msm_jpeg_hw_cmds   *phw_cmds;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds32)) /
+			sizeof(struct msm_jpeg_hw_cmd32)))) {
+		JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len32 = sizeof(struct msm_jpeg_hw_cmds32) +
+			sizeof(struct msm_jpeg_hw_cmd32) * (m - 1);
+	phw_cmds32 = kmalloc(len32, GFP_KERNEL);
+	if (!phw_cmds32) {
+		JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len32);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(phw_cmds32, arg, len32)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		kfree(phw_cmds32);
+		return -EFAULT;
+	}
+	len = sizeof(struct msm_jpeg_hw_cmds) +
+			sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+	phw_cmds = kmalloc(len, GFP_KERNEL);
+	if (!phw_cmds) {
+		JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+		kfree(phw_cmds32);
+		return -EFAULT;
+	}
+	(phw_cmds)->m = m;
+	while (m--) {
+		struct msm_jpeg_hw_cmd32 *src;
+		struct msm_jpeg_hw_cmd *dst;
+
+		src = &phw_cmds32->hw_cmd[m];
+		dst = &(phw_cmds)->hw_cmd[m];
+		msm_jpeg_get_hw_cmd32(dst, (void __user *)src, 0);
+	}
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(phw_cmds->hw_cmd,
+			phw_cmds->m,
+			pgmn_dev->res_size, pgmn_dev->base);
+
+	if (is_copy_to_user >= 0) {
+		m = phw_cmds->m;
+		while (m--) {
+			struct msm_jpeg_hw_cmd *src;
+			struct msm_jpeg_hw_cmd32 *dst;
+
+			dst = &phw_cmds32->hw_cmd[m];
+			src = &phw_cmds->hw_cmd[m];
+
+			msm_jpeg_put_hw_cmd32((void __user *)dst, src, 0);
+		}
+		if (copy_to_user(arg, phw_cmds32, len32)) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(phw_cmds);
+			kfree(phw_cmds32);
+			return -EFAULT;
+		}
+
+	} else {
+		kfree(phw_cmds);
+		kfree(phw_cmds32);
+		return is_copy_to_user;
+	}
+	kfree(phw_cmds);
+	kfree(phw_cmds32);
+
+	return 0;
+}
+static int msm_jpeg_ioctl_hw_cmd32(struct msm_jpeg_device *pgmn_dev,
+		void __user *arg)
+{
+	struct msm_jpeg_hw_cmd hw_cmd;
+	int is_copy_to_user;
+
+	if (msm_jpeg_get_hw_cmd32(&hw_cmd, (void __user *)arg, 1)) {
+		JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+			pgmn_dev->res_size, pgmn_dev->base);
+	JPEG_DBG("%s:%d] type %d, n %d, offst %d, mask %x, data %x pdata %lx\n",
+		__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+		hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata);
+
+	if (is_copy_to_user >= 0) {
+		if (msm_jpeg_put_hw_cmd32((void __user *)arg, &hw_cmd, 1)) {
+			JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	} else
+		return is_copy_to_user;
+
+
+	return 0;
+}
+
+long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	struct msm_jpeg_ctrl_cmd *pctrl_cmd = NULL, ctrl_cmd;
+	struct msm_jpeg_buf jpeg_buf;
+	mm_segment_t old_fs;
+
+	old_fs = get_fs();
+
+	switch (cmd) {
+	case MSM_JPEG_IOCTL_GET_HW_VERSION:
+		JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+	case MSM_JPEG_IOCTL_GET_HW_VERSION32:
+		JPEG_DBG("%s:%d] VERSION 1 32bit\n", __func__, __LINE__);
+		rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_RESET:
+		rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_RESET32:
+		rc = msm_jpeg_get_ctrl_cmd32(&ctrl_cmd,
+			(void __user *) arg);
+		if (rc < 0)
+			break;
+
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd);
+		set_fs(old_fs);
+		kfree(pctrl_cmd);
+		break;
+
+	case MSM_JPEG_IOCTL_STOP:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		pgmn_dev->state = MSM_JPEG_STOPPED;
+		break;
+
+	case MSM_JPEG_IOCTL_STOP32:
+		rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg);
+		pgmn_dev->state = MSM_JPEG_STOPPED;
+		break;
+
+	case MSM_JPEG_IOCTL_START:
+		rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+			msm_jpeg_ioctl_hw_cmds);
+		break;
+
+	case MSM_JPEG_IOCTL_START32:
+		rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+				msm_jpeg_ioctl_hw_cmds32);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32:
+		rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+		if (rc < 0)
+			break;
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+			(void __user *) &jpeg_buf);
+		set_fs(old_fs);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET:
+		rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET32:
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf);
+		set_fs(old_fs);
+		if (rc < 0)
+			break;
+		rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+		rc = msm_jpeg_input_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32:
+		rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+		if (rc < 0)
+			break;
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+			(void __user *) &jpeg_buf);
+		set_fs(old_fs);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET:
+		rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET32:
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf);
+		set_fs(old_fs);
+		if (rc < 0)
+			break;
+		rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+		rc = msm_jpeg_output_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET:
+		rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET32:
+		set_fs(KERNEL_DS);
+		rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd);
+		set_fs(old_fs);
+		if (rc < 0)
+			break;
+		msm_jpeg_put_ctrl_cmd32(&ctrl_cmd, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMD32:
+		rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMD:
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMDS32:
+		rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMDS:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+		rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+		break;
+
+	case MSM_JPEG_IOCTL_TEST_DUMP_REGION32:
+		rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+		break;
+
+	case MSM_JPEG_IOCTL_SET_CLK_RATE:
+		rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	default:
+		JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+		__func__, __LINE__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+#else
+long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+#endif
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case MSM_JPEG_IOCTL_GET_HW_VERSION:
+		JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_RESET:
+		rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_STOP:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		pgmn_dev->state = MSM_JPEG_STOPPED;
+		break;
+
+	case MSM_JPEG_IOCTL_START:
+		rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+			msm_jpeg_ioctl_hw_cmds);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET:
+		rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+		rc = msm_jpeg_input_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+		rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET:
+		rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+		rc = msm_jpeg_output_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET:
+		rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMD:
+		rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_HW_CMDS:
+		rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+		rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+		break;
+
+	case MSM_JPEG_IOCTL_SET_CLK_RATE:
+		rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg);
+		break;
+	default:
+		pr_err_ratelimited("%s:%d] cmd = %d not supported\n",
+			__func__, __LINE__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
+{
+	int rc = 0;
+	int idx = 0;
+
+	char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1",
+		"jpeg_dec", "jpeg_dma"};
+
+
+	mutex_init(&pgmn_dev->lock);
+
+	pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__,
+		   pgmn_dev->pdev->id);
+	idx = pgmn_dev->pdev->id;
+	pgmn_dev->idx = idx;
+	pgmn_dev->decode_flag = (idx == JPEG_DEC_ID);
+
+	msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
+	msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+	msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+	msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+	msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+	/*get device context for IOMMU*/
+	rc = cam_smmu_get_handle(iommu_name[idx], &pgmn_dev->iommu_hdl);
+	JPEG_DBG("%s:%d] hdl %d", __func__, __LINE__,
+			pgmn_dev->iommu_hdl);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: No iommu fw context found\n",
+				__func__);
+		goto err_smmu;
+	}
+
+	/* setup all the resources for the jpeg driver */
+	rc = msm_jpeg_platform_setup(pgmn_dev);
+	if (rc < 0) {
+		JPEG_PR_ERR("%s: setup failed\n",
+				__func__);
+		goto err_setup;
+	}
+
+	return rc;
+err_setup:
+err_smmu:
+	mutex_destroy(&pgmn_dev->lock);
+	return -EFAULT;
+}
+
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev)
+{
+	msm_jpeg_platform_cleanup(pgmn_dev);
+	mutex_destroy(&pgmn_dev->lock);
+	kfree(pgmn_dev);
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h
new file mode 100644
index 0000000..acf945e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.h
@@ -0,0 +1,141 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#ifndef MSM_JPEG_SYNC_H
+#define MSM_JPEG_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_io_util.h"
+#include "msm_jpeg_hw.h"
+#include "cam_smmu_api.h"
+#include "cam_soc_api.h"
+
+#define JPEG_8974_V1 0x10000000
+#define JPEG_8974_V2 0x10010000
+#define JPEG_8994 0x10020000
+#define JPEG_CLK_MAX 16
+#define JPEG_REGULATOR_MAX 3
+
+enum msm_jpeg_state {
+	MSM_JPEG_INIT,
+	MSM_JPEG_RESET,
+	MSM_JPEG_EXECUTING,
+	MSM_JPEG_STOPPED,
+	MSM_JPEG_IDLE
+};
+
+enum msm_jpeg_core_type {
+	MSM_JPEG_CORE_CODEC,
+	MSM_JPEG_CORE_DMA
+};
+
+struct msm_jpeg_q {
+	char const	*name;
+	struct list_head  q;
+	spinlock_t	lck;
+	wait_queue_head_t wait;
+	int	       unblck;
+};
+
+struct msm_jpeg_q_entry {
+	struct list_head list;
+	void   *data;
+};
+
+struct msm_jpeg_device {
+	struct platform_device *pdev;
+	struct resource        *jpeg_irq_res;
+	void                   *base;
+	void                   *vbif_base;
+	struct clk **jpeg_clk;
+	struct msm_cam_clk_info *jpeg_clk_info;
+	size_t num_clk;
+	int num_reg;
+	struct msm_cam_regulator *jpeg_vdd;
+	uint32_t hw_version;
+
+	struct device *device;
+	struct cdev   cdev;
+	struct mutex  lock;
+	char	  open_count;
+	uint8_t       op_mode;
+
+	/* Flag to store the jpeg bus vote state
+	 */
+	int jpeg_bus_vote;
+
+	/* event queue including frame done & err indications
+	 */
+	struct msm_jpeg_q evt_q;
+
+	/* output return queue
+	 */
+	struct msm_jpeg_q output_rtn_q;
+
+	/* output buf queue
+	 */
+	struct msm_jpeg_q output_buf_q;
+
+	/* input return queue
+	 */
+	struct msm_jpeg_q input_rtn_q;
+
+	/* input buf queue
+	 */
+	struct msm_jpeg_q input_buf_q;
+
+	struct v4l2_subdev subdev;
+
+	struct class *msm_jpeg_class;
+
+	dev_t msm_jpeg_devno;
+
+	/*iommu domain and context*/
+	int idx;
+	int iommu_hdl;
+	int decode_flag;
+	void *jpeg_vbif;
+	int release_buf;
+	struct msm_jpeg_hw_pingpong fe_pingpong_buf;
+	struct msm_jpeg_hw_pingpong we_pingpong_buf;
+	int we_pingpong_index;
+	int reset_done_ack;
+	spinlock_t reset_lock;
+	wait_queue_head_t reset_wait;
+	uint32_t res_size;
+	enum msm_jpeg_state state;
+	enum msm_jpeg_core_type core_type;
+	enum cam_bus_client bus_client;
+};
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev);
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_COMPAT
+long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg);
+#endif
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev);
+
+#endif /* MSM_JPEG_SYNC_H */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/Makefile b/drivers/media/platform/msm/camera_v2/jpeg_dma/Makefile
new file mode 100644
index 0000000..21cbadb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/Makefile
@@ -0,0 +1,4 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+obj-$(CONFIG_MSM_JPEGDMA) += msm_jpeg_dma_dev.o msm_jpeg_dma_hw.o
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
new file mode 100644
index 0000000..55e2646
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
@@ -0,0 +1,1502 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+#include <linux/msm_ion.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/msm_jpeg_dma.h>
+#include <linux/clk/msm-clk.h>
+
+#include "msm_jpeg_dma_dev.h"
+#include "msm_jpeg_dma_hw.h"
+#include "cam_hw_ops.h"
+
+#define MSM_JPEGDMA_DRV_NAME "msm_jpegdma"
+
+/* Jpeg dma stream off timeout */
+#define MSM_JPEGDMA_STREAM_OFF_TIMEOUT_MS 500
+
+/* Jpeg dma formats lookup table */
+static struct msm_jpegdma_format formats[] = {
+	{
+		.name = "Greyscale",
+		.fourcc = V4L2_PIX_FMT_GREY,
+		.depth = 8,
+		.num_planes = 1,
+		.colplane_h = 1,
+		.colplane_v = 1,
+		.h_align = 1,
+		.v_align = 1,
+		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
+	},
+	{
+		.name = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.depth = 12,
+		.num_planes = 2,
+		.colplane_h = 1,
+		.colplane_v = 2,
+		.h_align = 2,
+		.v_align = 2,
+		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
+		.planes[1] = JPEGDMA_PLANE_TYPE_CBCR,
+	},
+	{
+		.name = "Y/CrCb 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.depth = 12,
+		.num_planes = 2,
+		.colplane_h = 1,
+		.colplane_v = 2,
+		.h_align = 2,
+		.v_align = 2,
+		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
+		.planes[1] = JPEGDMA_PLANE_TYPE_CBCR,
+	},
+	{
+		.name = "YVU 4:2:0 planar, YCrCb",
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.depth = 12,
+		.num_planes = 3,
+		.colplane_h = 1,
+		.colplane_v = 4,
+		.h_align = 2,
+		.v_align = 2,
+		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
+		.planes[1] = JPEGDMA_PLANE_TYPE_CR,
+		.planes[2] = JPEGDMA_PLANE_TYPE_CB,
+	},
+	{
+		.name = "YUV 4:2:0 planar, YCbCr",
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.depth = 12,
+		.num_planes = 3,
+		.colplane_h = 1,
+		.colplane_v = 4,
+		.h_align = 2,
+		.v_align = 2,
+		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
+		.planes[1] = JPEGDMA_PLANE_TYPE_CB,
+		.planes[2] = JPEGDMA_PLANE_TYPE_CR,
+	},
+};
+
+/*
+ * msm_jpegdma_ctx_from_fh - Get dma context from v4l2 fh.
+ * @fh: Pointer to v4l2 fh.
+ */
+static inline struct jpegdma_ctx *msm_jpegdma_ctx_from_fh(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct jpegdma_ctx, fh);
+}
+
+/*
+ * msm_jpegdma_get_next_config_idx - get next configuration index.
+ * @ctx: Pointer to jpegdma context.
+ */
+static inline int msm_jpegdma_get_next_config_idx(struct jpegdma_ctx *ctx)
+{
+	return (ctx->config_idx + 1) % MSM_JPEGDMA_MAX_CONFIGS;
+}
+
+/*
+ * msm_jpegdma_schedule_next_config - Schedule next configuration.
+ * @ctx: Pointer to jpegdma context.
+ */
+static inline void msm_jpegdma_schedule_next_config(struct jpegdma_ctx *ctx)
+{
+	ctx->config_idx = (ctx->config_idx + 1) % MSM_JPEGDMA_MAX_CONFIGS;
+}
+
+/*
+ * msm_jpegdma_cast_long_to_buff_ptr - Cast long to buffer pointer.
+ * @vaddr: vaddr as long
+ * @buff_ptr_head: buffer pointer head
+ */
+static inline void msm_jpegdma_cast_long_to_buff_ptr(unsigned long vaddr,
+	struct msm_jpeg_dma_buff __user **buff_ptr_head)
+{
+#ifdef CONFIG_COMPAT
+	*buff_ptr_head = compat_ptr(vaddr);
+#else
+	*buff_ptr_head = (struct msm_jpeg_dma_buff *) vaddr;
+#endif
+}
+
+/*
+ * msm_jpegdma_get_format_idx - Get jpeg dma format lookup index.
+ * @ctx: Pointer to dma ctx.
+ * @f: v4l2 format.
+ */
+static int msm_jpegdma_get_format_idx(struct jpegdma_ctx *ctx,
+	struct v4l2_format *f)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == f->fmt.pix.pixelformat)
+			break;
+
+	if (i == ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	return i;
+}
+
+/*
+ * msm_jpegdma_fill_size_from_ctx - Fill jpeg dma format lookup index.
+ * @ctx: Pointer to dma ctx.
+ * @size: Size config.
+ */
+static void msm_jpegdma_fill_size_from_ctx(struct jpegdma_ctx *ctx,
+	struct msm_jpegdma_size_config *size)
+{
+
+	size->in_size.top = ctx->crop.top;
+	size->in_size.left = ctx->crop.left;
+	size->in_size.width = ctx->crop.width;
+	size->in_size.height = ctx->crop.height;
+	size->in_size.scanline = ctx->format_out.fmt.pix.height;
+	size->in_size.stride = ctx->format_out.fmt.pix.bytesperline;
+
+	size->out_size.top = 0;
+	size->out_size.left = 0;
+	size->out_size.width = ctx->format_cap.fmt.pix.width;
+	size->out_size.height = ctx->format_cap.fmt.pix.height;
+	size->out_size.scanline = ctx->format_cap.fmt.pix.height;
+	size->out_size.stride = ctx->format_cap.fmt.pix.bytesperline;
+}
+
+/*
+ * msm_jpegdma_align_format - Align jpeg dma format.
+ * @f: v4l2 format.
+ * @format_idx: format lookup index.
+ */
+static void msm_jpegdma_align_format(struct v4l2_format *f, int format_idx)
+{
+	unsigned int size_image;
+	int i;
+
+	if (f->fmt.pix.width > MSM_JPEGDMA_MAX_WIDTH)
+		f->fmt.pix.width = MSM_JPEGDMA_MAX_WIDTH;
+
+	if (f->fmt.pix.width < MSM_JPEGDMA_MIN_WIDTH)
+		f->fmt.pix.width = MSM_JPEGDMA_MIN_WIDTH;
+
+	if (f->fmt.pix.height > MSM_JPEGDMA_MAX_HEIGHT)
+		f->fmt.pix.height = MSM_JPEGDMA_MAX_HEIGHT;
+
+	if (f->fmt.pix.height < MSM_JPEGDMA_MIN_HEIGHT)
+		f->fmt.pix.height = MSM_JPEGDMA_MIN_HEIGHT;
+
+	if (formats[format_idx].h_align > 1)
+		f->fmt.pix.width &= ~(formats[format_idx].h_align - 1);
+
+	if (formats[format_idx].v_align > 1)
+		f->fmt.pix.height &= ~(formats[format_idx].v_align - 1);
+
+	if (f->fmt.pix.bytesperline < f->fmt.pix.width)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+
+	f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline,
+		MSM_JPEGDMA_STRIDE_ALIGN);
+
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+
+	size_image = f->fmt.pix.bytesperline * f->fmt.pix.height;
+
+	if (formats[format_idx].num_planes > 1)
+		for (i = 1; i < formats[format_idx].num_planes; i++)
+			size_image += (f->fmt.pix.bytesperline *
+				(f->fmt.pix.height /
+				formats[format_idx].colplane_v));
+
+	f->fmt.pix.sizeimage = size_image;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+}
+
+/*
+ * msm_jpegdma_config_ok - Check if jpeg dma format is ok for processing.
+ * @ctx: Pointer to dma ctx.
+ */
+static int msm_jpegdma_config_ok(struct jpegdma_ctx *ctx)
+{
+	int ret;
+	int cap_idx;
+	int out_idx;
+	struct msm_jpegdma_size_config size;
+
+	cap_idx = msm_jpegdma_get_format_idx(ctx, &ctx->format_cap);
+	if (cap_idx < 0)
+		return 0;
+
+	out_idx = msm_jpegdma_get_format_idx(ctx, &ctx->format_out);
+	if (out_idx < 0)
+		return 0;
+
+	/* jpeg dma can not convert formats */
+	if (cap_idx != out_idx)
+		return 0;
+
+	msm_jpegdma_fill_size_from_ctx(ctx, &size);
+
+	size.format = formats[ctx->format_idx];
+
+	ret = msm_jpegdma_hw_check_config(ctx->jdma_device, &size);
+	if (ret < 0)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * msm_jpegdma_update_hw_config - Update dma hw configuration/
+ * @ctx: Pointer to dma ctx.
+ */
+static int msm_jpegdma_update_hw_config(struct jpegdma_ctx *ctx)
+{
+	struct msm_jpegdma_size_config size;
+	int idx;
+	int ret = 0;
+
+	if (msm_jpegdma_config_ok(ctx)) {
+		size.fps = ctx->timeperframe.denominator /
+			ctx->timeperframe.numerator;
+
+		size.in_offset = ctx->in_offset;
+		size.out_offset = ctx->out_offset;
+
+		size.format = formats[ctx->format_idx];
+
+		msm_jpegdma_fill_size_from_ctx(ctx, &size);
+
+		idx = msm_jpegdma_get_next_config_idx(ctx);
+
+		ret = msm_jpegdma_hw_set_config(ctx->jdma_device,
+			&size, &ctx->plane_config[idx]);
+		if (ret < 0)
+			dev_err(ctx->jdma_device->dev, "Can not get hw cfg\n");
+		else
+			ctx->pending_config = 1;
+	}
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_queue_setup - vb2_ops queue_setup callback.
+ * @q: Pointer to vb2 queue struct.
+ * @fmt: Pointer to v4l2 format struct (NULL is valid argument).
+ * @num_buffers: Pointer of number of buffers requested.
+ * @num_planes: Pointer to number of planes requested.
+ * @sizes: Array containing sizes of planes.
+ * @alloc_ctxs: Array of allocated contexts for each plane.
+ */
+static int msm_jpegdma_queue_setup(struct vb2_queue *q,
+//	const void *parg,
+	unsigned int *num_buffers, unsigned int *num_planes,
+	unsigned int sizes[], struct device *alloc_ctxs[])
+{
+	struct jpegdma_ctx *ctx = vb2_get_drv_priv(q);
+	//struct v4l2_format *fmt = (struct v4l2_format *)parg;
+	struct v4l2_format *fmt = NULL;
+
+	if (fmt == NULL) {
+		switch (q->type) {
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			sizes[0] = ctx->format_out.fmt.pix.sizeimage;
+			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			sizes[0] = ctx->format_cap.fmt.pix.sizeimage;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		sizes[0] = fmt->fmt.pix.sizeimage;
+	}
+
+	*num_planes = 1;
+	alloc_ctxs[0] = (struct device *)ctx->jdma_device;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_buf_queue - vb2_ops buf_queue callback.
+ * @vb: Pointer to vb2 buffer struct.
+ */
+static void msm_jpegdma_buf_queue(struct vb2_buffer *vb)
+{
+	struct jpegdma_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = to_vb2_v4l2_buffer(vb);
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2_buf);
+
+}
+
+/*
+ * msm_jpegdma_start_streaming - vb2_ops start_streaming callback.
+ * @q: Pointer to vb2 queue struct.
+ * @count: Number of buffer queued before stream on call.
+ */
+static int msm_jpegdma_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct jpegdma_ctx *ctx = vb2_get_drv_priv(q);
+	int ret;
+
+	ret = msm_jpegdma_hw_get(ctx->jdma_device);
+	if (ret < 0) {
+		dev_err(ctx->jdma_device->dev, "Fail to get dma hw\n");
+		return ret;
+	}
+	if (!atomic_read(&ctx->active)) {
+		ret =  msm_jpegdma_update_hw_config(ctx);
+		if (ret < 0) {
+			dev_err(ctx->jdma_device->dev, "Fail to configure hw\n");
+			return ret;
+		}
+		atomic_set(&ctx->active, 1);
+	}
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_stop_streaming - vb2_ops stop_streaming callback.
+ * @q: Pointer to vb2 queue struct.
+ */
+static void msm_jpegdma_stop_streaming(struct vb2_queue *q)
+{
+	struct jpegdma_ctx *ctx = vb2_get_drv_priv(q);
+	unsigned long time;
+	int ret = 0;
+
+	atomic_set(&ctx->active, 0);
+
+	time = wait_for_completion_timeout(&ctx->completion,
+		msecs_to_jiffies(MSM_JPEGDMA_STREAM_OFF_TIMEOUT_MS));
+	if (!time) {
+		dev_err(ctx->jdma_device->dev, "Ctx wait timeout\n");
+		ret = -ETIME;
+	}
+
+	if (ctx->jdma_device->ref_count > 0)
+		msm_jpegdma_hw_put(ctx->jdma_device);
+}
+
+/* Videobuf2 queue callbacks. */
+static struct vb2_ops msm_jpegdma_vb2_q_ops = {
+	.queue_setup     = msm_jpegdma_queue_setup,
+	.buf_queue       = msm_jpegdma_buf_queue,
+	.start_streaming = msm_jpegdma_start_streaming,
+	.stop_streaming  = msm_jpegdma_stop_streaming,
+};
+
+/*
+ * msm_jpegdma_get_userptr - Map and get buffer handler for user pointer buffer.
+ * @alloc_ctx: Contexts allocated in buf_setup.
+ * @vaddr: Virtual addr passed from userpsace (in our case ion fd)
+ * @size: Size of the buffer
+ * @write: True if buffer will be used for writing the data.
+ */
+static void *msm_jpegdma_get_userptr(struct device *alloc_ctx,
+	unsigned long vaddr, unsigned long size,
+	enum dma_data_direction dma_dir)
+{
+	struct msm_jpegdma_device *dma = (void *)alloc_ctx;
+	struct msm_jpegdma_buf_handle *buf;
+	struct msm_jpeg_dma_buff __user *up_buff;
+	struct msm_jpeg_dma_buff kp_buff;
+	int ret;
+
+	msm_jpegdma_cast_long_to_buff_ptr(vaddr, &up_buff);
+
+	if (!access_ok(VERIFY_READ, up_buff,
+		sizeof(struct msm_jpeg_dma_buff)) ||
+		get_user(kp_buff.fd, &up_buff->fd)) {
+		dev_err(dma->dev, "Error getting user data\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (!access_ok(VERIFY_WRITE, up_buff,
+		sizeof(struct msm_jpeg_dma_buff)) ||
+		put_user(kp_buff.fd, &up_buff->fd)) {
+		dev_err(dma->dev, "Error putting user data\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	ret = msm_jpegdma_hw_map_buffer(dma, kp_buff.fd, buf);
+	if (ret < 0 || buf->size < size)
+		goto error;
+
+	return buf;
+error:
+	kzfree(buf);
+	return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * msm_jpegdma_put_userptr - Unmap and free buffer handler.
+ * @buf_priv: Buffer handler allocated get_userptr callback.
+ */
+static void msm_jpegdma_put_userptr(void *buf_priv)
+{
+	if (IS_ERR_OR_NULL(buf_priv))
+		return;
+
+	msm_jpegdma_hw_unmap_buffer(buf_priv);
+
+	kzfree(buf_priv);
+}
+
+/* Videobuf2 memory callbacks. */
+static struct vb2_mem_ops msm_jpegdma_vb2_mem_ops = {
+	.get_userptr = msm_jpegdma_get_userptr,
+	.put_userptr = msm_jpegdma_put_userptr,
+};
+
+/*
+ * msm_jpegdma_queue_init - m2m_ops queue_setup callback.
+ * @priv: Pointer to jpegdma ctx.
+ * @src_vq: vb2 source queue.
+ * @dst_vq: vb2 destination queue.
+ */
+static int msm_jpegdma_queue_init(void *priv, struct vb2_queue *src_vq,
+	struct vb2_queue *dst_vq)
+{
+	struct jpegdma_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_USERPTR;
+	src_vq->drv_priv = ctx;
+	src_vq->mem_ops = &msm_jpegdma_vb2_mem_ops;
+	src_vq->ops = &msm_jpegdma_vb2_q_ops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret) {
+		dev_err(ctx->jdma_device->dev, "Can not init src queue\n");
+		return ret;
+	}
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_USERPTR;
+	dst_vq->drv_priv = ctx;
+	dst_vq->mem_ops = &msm_jpegdma_vb2_mem_ops;
+	dst_vq->ops = &msm_jpegdma_vb2_q_ops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	ret = vb2_queue_init(dst_vq);
+	if (ret) {
+		dev_err(ctx->jdma_device->dev, "Can not init dst queue\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_open - Fd device open method.
+ * @file: Pointer to file struct.
+ */
+static int msm_jpegdma_open(struct file *file)
+{
+	struct msm_jpegdma_device *device = video_drvdata(file);
+	struct video_device *video = video_devdata(file);
+	struct jpegdma_ctx *ctx;
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mutex_init(&ctx->lock);
+	ctx->jdma_device = device;
+	dev_dbg(ctx->jdma_device->dev, "Jpeg v4l2 dma open\n");
+	/* Set ctx defaults */
+	ctx->timeperframe.numerator = 1;
+	ctx->timeperframe.denominator = MSM_JPEGDMA_DEFAULT_FPS;
+	atomic_set(&ctx->active, 0);
+
+	v4l2_fh_init(&ctx->fh, video);
+
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(device->m2m_dev,
+		ctx, msm_jpegdma_queue_init);
+	if (IS_ERR_OR_NULL(ctx->m2m_ctx)) {
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_m2m_init;
+	}
+	ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+			CAM_AHB_SVS_VOTE);
+	if (ret < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		goto ahb_vote_fail;
+	}
+	init_completion(&ctx->completion);
+	complete_all(&ctx->completion);
+	dev_dbg(ctx->jdma_device->dev, "Jpeg v4l2 dma open success\n");
+
+	return 0;
+
+ahb_vote_fail:
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+error_m2m_init:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_release - Fd device release method.
+ * @file: Pointer to file struct.
+ */
+static int msm_jpegdma_release(struct file *file)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(file->private_data);
+
+	/* release all the resources */
+	if (ctx->jdma_device->ref_count > 0)
+		msm_jpegdma_hw_put(ctx->jdma_device);
+
+	atomic_set(&ctx->active, 0);
+	complete_all(&ctx->completion);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_poll - Fd device pool method.
+ * @file: Pointer to file struct.
+ * @wait: Pointer to pool table struct.
+ */
+static unsigned int msm_jpegdma_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(file->private_data);
+
+	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+/* Dma device file operations callbacks */
+static const struct v4l2_file_operations fd_fops = {
+	.owner          = THIS_MODULE,
+	.open           = msm_jpegdma_open,
+	.release        = msm_jpegdma_release,
+	.poll           = msm_jpegdma_poll,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+/*
+ * msm_jpegdma_querycap - V4l2 ioctl query capability handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @cap: Pointer to v4l2_capability struct need to be filled.
+ */
+static int msm_jpegdma_querycap(struct file *file,
+	void *fh, struct v4l2_capability *cap)
+{
+	cap->bus_info[0] = 0;
+	strlcpy(cap->driver, MSM_JPEGDMA_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_JPEGDMA_DRV_NAME, sizeof(cap->card));
+	cap->capabilities = V4L2_CAP_STREAMING |
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_enum_fmt_vid_cap - V4l2 ioctl enumerate output format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_fmtdesc struct need to be filled.
+ */
+static int msm_jpegdma_enum_fmt_vid_cap(struct file *file,
+	void *fh, struct v4l2_fmtdesc *f)
+{
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	f->pixelformat = formats[f->index].fourcc;
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_enum_fmt_vid_out - V4l2 ioctl enumerate capture format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_fmtdesc struct need to be filled.
+ */
+static int msm_jpegdma_enum_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_fmtdesc *f)
+{
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	f->pixelformat = formats[f->index].fourcc;
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_g_fmt_cap - V4l2 ioctl get capture format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct need to be filled.
+ */
+static int msm_jpegdma_g_fmt_cap(struct file *file, void *fh,
+	struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	*f = ctx->format_cap;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_g_fmt_out - V4l2 ioctl get output format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct need to be filled.
+ */
+static int msm_jpegdma_g_fmt_out(struct file *file, void *fh,
+	struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	*f = ctx->format_out;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_try_fmt_vid_cap - V4l2 ioctl try capture format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_jpegdma_try_fmt_vid_cap(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	msm_jpegdma_align_format(f, ctx->format_idx);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_try_fmt_vid_out - V4l2 ioctl try output format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_jpegdma_try_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	msm_jpegdma_align_format(f, ctx->format_idx);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_s_fmt_vid_cap - V4l2 ioctl set capture format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_jpegdma_s_fmt_vid_cap(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	int ret;
+
+	ret = msm_jpegdma_get_format_idx(ctx, f);
+	if (ret < 0)
+		return -EINVAL;
+
+	ctx->format_idx = ret;
+
+	msm_jpegdma_align_format(f, ctx->format_idx);
+
+	/* Initialize crop with output height */
+	ctx->crop.top = 0;
+	ctx->crop.left = 0;
+	ctx->crop.width = ctx->format_out.fmt.pix.width;
+	ctx->crop.height = ctx->format_out.fmt.pix.height;
+
+	ctx->format_cap = *f;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_s_fmt_vid_out - V4l2 ioctl set output format handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @f: Pointer to v4l2_format struct.
+ */
+static int msm_jpegdma_s_fmt_vid_out(struct file *file,
+	void *fh, struct v4l2_format *f)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	int ret;
+
+	ret = msm_jpegdma_get_format_idx(ctx, f);
+	if (ret < 0)
+		return -EINVAL;
+
+	ctx->format_idx = ret;
+
+	msm_jpegdma_align_format(f, ctx->format_idx);
+
+	/* Initialize crop */
+	ctx->crop.top = 0;
+	ctx->crop.left = 0;
+	ctx->crop.width = f->fmt.pix.width;
+	ctx->crop.height = f->fmt.pix.height;
+
+	ctx->format_out = *f;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_reqbufs - V4l2 ioctl request buffers handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @req: Pointer to v4l2_requestbuffer struct.
+ */
+static int msm_jpegdma_reqbufs(struct file *file,
+	void *fh, struct v4l2_requestbuffers *req)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, req);
+}
+
+/*
+ * msm_jpegdma_qbuf - V4l2 ioctl queue buffer handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf: Pointer to v4l2_buffer struct.
+ */
+static int msm_jpegdma_qbuf(struct file *file, void *fh,
+	struct v4l2_buffer *buf)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	struct msm_jpeg_dma_buff __user *up_buff;
+	struct msm_jpeg_dma_buff kp_buff;
+	int ret;
+
+	msm_jpegdma_cast_long_to_buff_ptr(buf->m.userptr, &up_buff);
+	mutex_lock(&ctx->lock);
+	if (!access_ok(VERIFY_READ, up_buff,
+		sizeof(struct msm_jpeg_dma_buff)) ||
+		get_user(kp_buff.fd, &up_buff->fd) ||
+		get_user(kp_buff.offset, &up_buff->offset)) {
+		dev_err(ctx->jdma_device->dev, "Error getting user data\n");
+		mutex_unlock(&ctx->lock);
+		return -EFAULT;
+	}
+
+	if (!access_ok(VERIFY_WRITE, up_buff,
+		sizeof(struct msm_jpeg_dma_buff)) ||
+		put_user(kp_buff.fd, &up_buff->fd) ||
+		put_user(kp_buff.offset, &up_buff->offset)) {
+		dev_err(ctx->jdma_device->dev, "Error putting user data\n");
+		mutex_unlock(&ctx->lock);
+		return -EFAULT;
+	}
+
+	switch (buf->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		ctx->in_offset = kp_buff.offset;
+		dev_dbg(ctx->jdma_device->dev, "input buf offset %d\n",
+			ctx->in_offset);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		ctx->out_offset = kp_buff.offset;
+		dev_dbg(ctx->jdma_device->dev, "output buf offset %d\n",
+			ctx->out_offset);
+		break;
+	}
+
+	if (atomic_read(&ctx->active))
+		ret = msm_jpegdma_update_hw_config(ctx);
+
+	ret = v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+	if (ret < 0)
+		dev_err(ctx->jdma_device->dev, "QBuf fail\n");
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_dqbuf - V4l2 ioctl dequeue buffer handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf: Pointer to v4l2_buffer struct.
+ */
+static int msm_jpegdma_dqbuf(struct file *file,
+	void *fh, struct v4l2_buffer *buf)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+/*
+ * msm_jpegdma_streamon - V4l2 ioctl stream on handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf_type: V4l2 buffer type.
+ */
+static int msm_jpegdma_streamon(struct file *file,
+	void *fh, enum v4l2_buf_type buf_type)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	int ret;
+
+	if (!msm_jpegdma_config_ok(ctx))
+		return -EINVAL;
+
+	ret = v4l2_m2m_streamon(file, ctx->m2m_ctx, buf_type);
+	if (ret < 0)
+		dev_err(ctx->jdma_device->dev, "Stream on fail\n");
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_streamoff - V4l2 ioctl stream off handler.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @buf_type: V4l2 buffer type.
+ */
+static int msm_jpegdma_streamoff(struct file *file,
+	void *fh, enum v4l2_buf_type buf_type)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	int ret;
+
+	ret = v4l2_m2m_streamoff(file, ctx->m2m_ctx, buf_type);
+	if (ret < 0)
+		dev_err(ctx->jdma_device->dev, "Stream off fails\n");
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_cropcap - V4l2 ioctl crop capabilities.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @a: Pointer to v4l2_cropcap struct need to be set.
+ */
+static int msm_jpegdma_cropcap(struct file *file, void *fh,
+	struct v4l2_cropcap *a)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	struct v4l2_format *format;
+
+	switch (a->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		format = &ctx->format_out;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		format = &ctx->format_cap;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	a->bounds.top = 0;
+	a->bounds.left = 0;
+	a->bounds.width = format->fmt.pix.width;
+	a->bounds.height = format->fmt.pix.height;
+
+	a->defrect = ctx->crop;
+
+	a->pixelaspect.numerator = 1;
+	a->pixelaspect.denominator = 1;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_g_crop - V4l2 ioctl get crop.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @crop: Pointer to v4l2_crop struct need to be set.
+ */
+static int msm_jpegdma_g_crop(struct file *file, void *fh,
+	struct v4l2_crop *crop)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	switch (crop->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		crop->c = ctx->crop;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		crop->c.left = 0;
+		crop->c.top = 0;
+		crop->c.width = ctx->format_cap.fmt.pix.width;
+		crop->c.height = ctx->format_cap.fmt.pix.height;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * msm_jpegdma_s_crop - V4l2 ioctl set crop.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @crop: Pointer to v4l2_crop struct need to be set.
+ */
+static int msm_jpegdma_s_crop(struct file *file, void *fh,
+	const struct v4l2_crop *crop)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	int ret = 0;
+
+	/* Crop is supported only for input buffers */
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (crop->c.left < 0 || crop->c.top < 0 ||
+	    crop->c.height == 0 || crop->c.width == 0)
+		return -EINVAL;
+
+	/* Upscale is not supported */
+	if (crop->c.width < ctx->format_cap.fmt.pix.width)
+		return -EINVAL;
+
+	if (crop->c.height < ctx->format_cap.fmt.pix.height)
+		return -EINVAL;
+
+	if (crop->c.width + crop->c.left > ctx->format_out.fmt.pix.width)
+		return -EINVAL;
+
+	if (crop->c.height + crop->c.top > ctx->format_out.fmt.pix.height)
+		return -EINVAL;
+
+	if (crop->c.width % formats[ctx->format_idx].h_align)
+		return -EINVAL;
+
+	if (crop->c.height % formats[ctx->format_idx].v_align)
+		return -EINVAL;
+
+	mutex_lock(&ctx->lock);
+	ctx->crop = crop->c;
+	if (atomic_read(&ctx->active))
+		ret = msm_jpegdma_update_hw_config(ctx);
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_g_crop - V4l2 ioctl get parm.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @a: Pointer to v4l2_streamparm struct need to be filled.
+ */
+static int msm_jpegdma_g_parm(struct file *file, void *fh,
+	struct v4l2_streamparm *a)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	/* Get param is supported only for input buffers */
+	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	a->parm.output.capability = 0;
+	a->parm.output.extendedmode = 0;
+	a->parm.output.outputmode = 0;
+	a->parm.output.writebuffers = 0;
+	a->parm.output.timeperframe = ctx->timeperframe;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_s_crop - V4l2 ioctl set parm.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @a: Pointer to v4l2_streamparm struct need to be set.
+ */
+static int msm_jpegdma_s_parm(struct file *file, void *fh,
+	struct v4l2_streamparm *a)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+	/* Set param is supported only for input buffers */
+	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (!a->parm.output.timeperframe.numerator ||
+		!a->parm.output.timeperframe.denominator)
+		return -EINVAL;
+
+	/* Frame rate is not supported during streaming */
+	if (atomic_read(&ctx->active))
+		return -EINVAL;
+
+	ctx->timeperframe = a->parm.output.timeperframe;
+	return 0;
+}
+
+/*
+ * msm_fd_g_ctrl - V4l2 ioctl get control.
+ * @file: Pointer to file struct.
+ * @fh: V4l2 File handle.
+ * @sub: Pointer to v4l2_control struct need to be filled.
+ */
+static int msm_jpegdma_g_ctrl(struct file *file, void *fh,
+	struct v4l2_control *a)
+{
+	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
+
+	switch (a->id) {
+	case V4L2_CID_JPEG_DMA_MAX_DOWN_SCALE:
+		a->value = msm_jpegdma_hw_get_max_downscale(ctx->jdma_device);
+		if (a->value < 0)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* V4l2 ioctl handlers */
+static const struct v4l2_ioctl_ops fd_ioctl_ops = {
+	.vidioc_querycap          = msm_jpegdma_querycap,
+	.vidioc_enum_fmt_vid_out  = msm_jpegdma_enum_fmt_vid_out,
+	.vidioc_enum_fmt_vid_cap  = msm_jpegdma_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_out     = msm_jpegdma_g_fmt_out,
+	.vidioc_g_fmt_vid_cap     = msm_jpegdma_g_fmt_cap,
+	.vidioc_try_fmt_vid_out   = msm_jpegdma_try_fmt_vid_out,
+	.vidioc_try_fmt_vid_cap   = msm_jpegdma_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out     = msm_jpegdma_s_fmt_vid_out,
+	.vidioc_s_fmt_vid_cap     = msm_jpegdma_s_fmt_vid_cap,
+	.vidioc_reqbufs           = msm_jpegdma_reqbufs,
+	.vidioc_qbuf              = msm_jpegdma_qbuf,
+	.vidioc_dqbuf             = msm_jpegdma_dqbuf,
+	.vidioc_streamon          = msm_jpegdma_streamon,
+	.vidioc_streamoff         = msm_jpegdma_streamoff,
+	.vidioc_cropcap           = msm_jpegdma_cropcap,
+	.vidioc_g_crop            = msm_jpegdma_g_crop,
+	.vidioc_s_crop            = msm_jpegdma_s_crop,
+	.vidioc_g_parm            = msm_jpegdma_g_parm,
+	.vidioc_s_parm            = msm_jpegdma_s_parm,
+	.vidioc_g_ctrl            = msm_jpegdma_g_ctrl,
+};
+
+/*
+ * msm_jpegdma_process_buffers - Start dma processing.
+ * @ctx: Pointer dma context.
+ * @src_buf: Pointer to Vb2 source buffer.
+ * @dst_buf: Pointer to Vb2 destination buffer.
+ */
+static void msm_jpegdma_process_buffers(struct jpegdma_ctx *ctx,
+	struct vb2_v4l2_buffer *src_buf, struct vb2_v4l2_buffer *dst_buf)
+{
+	struct msm_jpegdma_buf_handle *buf_handle;
+	struct msm_jpegdma_addr addr;
+	int plane_idx;
+	int config_idx;
+
+	buf_handle = dst_buf->vb2_buf.planes[0].mem_priv;
+	addr.out_addr = buf_handle->addr;
+
+	buf_handle = src_buf->vb2_buf.planes[0].mem_priv;
+	addr.in_addr = buf_handle->addr;
+
+	plane_idx = ctx->plane_idx;
+	config_idx = ctx->config_idx;
+	msm_jpegdma_hw_start(ctx->jdma_device, &addr,
+		&ctx->plane_config[config_idx].plane[plane_idx],
+		&ctx->plane_config[config_idx].speed);
+}
+
+/*
+ * msm_jpegdma_device_run - Dma device run.
+ * @priv: Pointer dma context.
+ */
+static void msm_jpegdma_device_run(void *priv)
+{
+	struct vb2_v4l2_buffer *src_buf;
+	struct vb2_v4l2_buffer *dst_buf;
+	struct jpegdma_ctx *ctx = priv;
+
+	dev_dbg(ctx->jdma_device->dev, "Jpeg v4l2 dma device run E\n");
+
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	if (src_buf == NULL || dst_buf == NULL) {
+		dev_err(ctx->jdma_device->dev, "Error, buffer list empty\n");
+		return;
+	}
+
+	if (ctx->pending_config) {
+		msm_jpegdma_schedule_next_config(ctx);
+		ctx->pending_config = 0;
+	}
+
+	msm_jpegdma_process_buffers(ctx, src_buf, dst_buf);
+	dev_dbg(ctx->jdma_device->dev, "Jpeg v4l2 dma device run X\n");
+}
+
+/*
+ * msm_jpegdma_job_abort - Dma abort job.
+ * @priv: Pointer dma context.
+ */
+static void msm_jpegdma_job_abort(void *priv)
+{
+	struct jpegdma_ctx *ctx = priv;
+
+	msm_jpegdma_hw_abort(ctx->jdma_device);
+	v4l2_m2m_job_finish(ctx->jdma_device->m2m_dev, ctx->m2m_ctx);
+}
+
+/*
+ * msm_jpegdma_job_ready - Dma check if job is ready
+ * @priv: Pointer dma context.
+ */
+static int msm_jpegdma_job_ready(void *priv)
+{
+	struct jpegdma_ctx *ctx = priv;
+
+	if (atomic_read(&ctx->active)) {
+		init_completion(&ctx->completion);
+		return 1;
+	}
+	return 0;
+}
+
+/* V4l2 mem2mem handlers */
+static struct v4l2_m2m_ops msm_jpegdma_m2m_ops = {
+	.device_run = msm_jpegdma_device_run,
+	.job_abort = msm_jpegdma_job_abort,
+	.job_ready = msm_jpegdma_job_ready,
+};
+
+/*
+ * msm_jpegdma_isr_processing_done - Invoked by dma_hw when processing is done.
+ * @dma: Pointer dma device.
+ */
+void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma)
+{
+	struct vb2_v4l2_buffer *src_buf;
+	struct vb2_v4l2_buffer *dst_buf;
+	struct jpegdma_ctx *ctx;
+
+	mutex_lock(&dma->lock);
+
+	ctx = v4l2_m2m_get_curr_priv(dma->m2m_dev);
+	if (ctx) {
+		mutex_lock(&ctx->lock);
+		ctx->plane_idx++;
+		if (ctx->plane_idx >= formats[ctx->format_idx].num_planes) {
+			src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+			dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+			if (src_buf == NULL || dst_buf == NULL) {
+				dev_err(ctx->jdma_device->dev, "Error, buffer list empty\n");
+				mutex_unlock(&ctx->lock);
+				mutex_unlock(&dma->lock);
+				return;
+			}
+			complete_all(&ctx->completion);
+			ctx->plane_idx = 0;
+
+			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+			v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+			v4l2_m2m_job_finish(ctx->jdma_device->m2m_dev,
+				ctx->m2m_ctx);
+		} else {
+			dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+			src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+			if (src_buf == NULL || dst_buf == NULL) {
+				dev_err(ctx->jdma_device->dev, "Error, buffer list empty\n");
+				mutex_unlock(&ctx->lock);
+				mutex_unlock(&dma->lock);
+				return;
+			}
+			msm_jpegdma_process_buffers(ctx, src_buf, dst_buf);
+		}
+		mutex_unlock(&ctx->lock);
+	}
+	mutex_unlock(&dma->lock);
+}
+
+/*
+ * jpegdma_probe - Dma device probe method.
+ * @pdev: Pointer Dma platform device.
+ */
+static int jpegdma_probe(struct platform_device *pdev)
+{
+	struct msm_jpegdma_device *jpegdma;
+	int ret;
+	int i;
+
+	dev_dbg(&pdev->dev, "jpeg v4l2 DMA probed\n");
+	/* Jpeg dma device struct */
+	jpegdma = kzalloc(sizeof(struct msm_jpegdma_device), GFP_KERNEL);
+	if (!jpegdma)
+		return -ENOMEM;
+
+	mutex_init(&jpegdma->lock);
+
+	init_completion(&jpegdma->hw_reset_completion);
+	init_completion(&jpegdma->hw_halt_completion);
+	jpegdma->dev = &pdev->dev;
+	jpegdma->pdev = pdev;
+
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+			&pdev->id);
+
+	/* Get resources */
+	ret = msm_jpegdma_hw_get_mem_resources(pdev, jpegdma);
+	if (ret < 0)
+		goto error_mem_resources;
+
+	/* get all the regulators */
+	ret = msm_camera_get_regulator_info(pdev, &jpegdma->dma_vdd,
+		&jpegdma->num_reg);
+	if (ret < 0)
+		goto error_get_regulators;
+
+	/* get all the clocks */
+	ret = msm_camera_get_clk_info(pdev, &jpegdma->jpeg_clk_info,
+		&jpegdma->clk, &jpegdma->num_clk);
+	if (ret < 0)
+		goto error_get_clocks;
+
+	/*set memcore and mem periphery logic flags to 0*/
+	for (i = 0; i < jpegdma->num_clk; i++) {
+		if ((strcmp(jpegdma->jpeg_clk_info[i].clk_name,
+				"core_clk") == 0) ||
+			(strcmp(jpegdma->jpeg_clk_info[i].clk_name,
+				"mmss_camss_jpeg_axi_clk") == 0)) {
+			msm_camera_set_clk_flags(jpegdma->clk[i],
+				CLKFLAG_NORETAIN_MEM);
+			msm_camera_set_clk_flags(jpegdma->clk[i],
+				CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+
+	ret = msm_jpegdma_hw_get_qos(jpegdma);
+	if (ret < 0)
+		goto error_qos_get;
+
+	ret = msm_jpegdma_hw_get_vbif(jpegdma);
+	if (ret < 0)
+		goto error_vbif_get;
+
+	ret = msm_jpegdma_hw_get_prefetch(jpegdma);
+	if (ret < 0)
+		goto error_prefetch_get;
+
+	/* get the irq resource */
+	jpegdma->irq = msm_camera_get_irq(pdev, "jpeg");
+	if (!jpegdma->irq)
+		goto error_hw_get_irq;
+
+	switch (pdev->id) {
+	case 3:
+		jpegdma->bus_client = CAM_BUS_CLIENT_JPEG_DMA;
+		break;
+	default:
+		pr_err("%s: invalid cell id :%d\n",
+			__func__, pdev->id);
+		goto error_reg_bus;
+	}
+
+	/* register bus client */
+	ret = msm_camera_register_bus_client(pdev,
+			jpegdma->bus_client);
+	if (ret < 0) {
+		pr_err("Fail to register bus client\n");
+		ret = -EINVAL;
+		goto error_reg_bus;
+	}
+
+	ret = msm_jpegdma_hw_get_capabilities(jpegdma);
+	if (ret < 0)
+		goto error_hw_get_cap;
+
+	/* mem2mem device */
+	jpegdma->m2m_dev = v4l2_m2m_init(&msm_jpegdma_m2m_ops);
+	if (IS_ERR(jpegdma->m2m_dev)) {
+		dev_err(&pdev->dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(jpegdma->m2m_dev);
+		goto error_m2m_init;
+	}
+
+	/* v4l2 device */
+	ret = v4l2_device_register(&pdev->dev, &jpegdma->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+		goto error_v4l2_register;
+	}
+
+	jpegdma->video.fops = &fd_fops;
+	jpegdma->video.ioctl_ops = &fd_ioctl_ops;
+	jpegdma->video.minor = -1;
+	jpegdma->video.release = video_device_release;
+	jpegdma->video.v4l2_dev = &jpegdma->v4l2_dev;
+	jpegdma->video.vfl_dir = VFL_DIR_M2M;
+	jpegdma->video.vfl_type = VFL_TYPE_GRABBER;
+	strlcpy(jpegdma->video.name, MSM_JPEGDMA_DRV_NAME,
+		sizeof(jpegdma->video.name));
+
+	ret = video_register_device(&jpegdma->video, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register video device\n");
+		goto error_video_register;
+	}
+
+	video_set_drvdata(&jpegdma->video, jpegdma);
+
+	platform_set_drvdata(pdev, jpegdma);
+
+	dev_dbg(&pdev->dev, "jpeg v4l2 DMA probe success\n");
+	return 0;
+
+error_video_register:
+	v4l2_device_unregister(&jpegdma->v4l2_dev);
+error_v4l2_register:
+	v4l2_m2m_release(jpegdma->m2m_dev);
+error_m2m_init:
+error_hw_get_cap:
+	msm_camera_unregister_bus_client(jpegdma->bus_client);
+error_reg_bus:
+error_hw_get_irq:
+	msm_jpegdma_hw_put_prefetch(jpegdma);
+error_prefetch_get:
+	msm_jpegdma_hw_put_vbif(jpegdma);
+error_vbif_get:
+	msm_jpegdma_hw_put_qos(jpegdma);
+error_qos_get:
+	msm_camera_put_clk_info(pdev, &jpegdma->jpeg_clk_info,
+		&jpegdma->clk, jpegdma->num_clk);
+error_get_clocks:
+	msm_camera_put_regulators(pdev, &jpegdma->dma_vdd,
+		jpegdma->num_reg);
+error_get_regulators:
+	msm_jpegdma_hw_release_mem_resources(jpegdma);
+error_mem_resources:
+	kfree(jpegdma);
+	return ret;
+}
+
+/*
+ * jpegdma_device_remove - Jpegdma device remove method.
+ * @pdev: Pointer jpegdma platform device.
+ */
+static int jpegdma_device_remove(struct platform_device *pdev)
+{
+	struct msm_jpegdma_device *dma;
+
+	dma = platform_get_drvdata(pdev);
+	if (dma == NULL) {
+		dev_err(&pdev->dev, "Can not get jpeg dma drvdata\n");
+		return 0;
+	}
+	video_unregister_device(&dma->video);
+	v4l2_device_unregister(&dma->v4l2_dev);
+	v4l2_m2m_release(dma->m2m_dev);
+	/* unregister bus client */
+	msm_camera_unregister_bus_client(dma->bus_client);
+	/* release all the regulators */
+	msm_camera_put_regulators(dma->pdev, &dma->dma_vdd,
+		dma->num_reg);
+	/* release all the clocks */
+	msm_camera_put_clk_info(dma->pdev, &dma->jpeg_clk_info,
+		&dma->clk, dma->num_clk);
+	msm_jpegdma_hw_release_mem_resources(dma);
+	kfree(dma);
+
+	return 0;
+}
+
+/* Device tree match struct */
+static const struct of_device_id msm_jpegdma_dt_match[] = {
+	{.compatible = "qcom,jpegdma"},
+	{}
+};
+
+/* Jpeg dma platform driver definition */
+static struct platform_driver jpegdma_driver = {
+	.probe = jpegdma_probe,
+	.remove = jpegdma_device_remove,
+	.driver = {
+		.name = MSM_JPEGDMA_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_jpegdma_dt_match,
+	},
+};
+
+static int __init msm_jpegdma_init_module(void)
+{
+	return platform_driver_register(&jpegdma_driver);
+}
+
+static void __exit msm_jpegdma_exit_module(void)
+{
+	platform_driver_unregister(&jpegdma_driver);
+}
+
+module_init(msm_jpegdma_init_module);
+module_exit(msm_jpegdma_exit_module);
+MODULE_DESCRIPTION("MSM JPEG DMA driver");
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h
new file mode 100644
index 0000000..50b7941
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.h
@@ -0,0 +1,378 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_JPEG_DMA_DEV_H__
+#define __MSM_JPEG_DMA_DEV_H__
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/msm-bus.h>
+#include "cam_soc_api.h"
+
+/* Max number of clocks defined in device tree */
+#define MSM_JPEGDMA_MAX_CLK 10
+/* Core clock index */
+#define MSM_JPEGDMA_CORE_CLK "core_clk"
+/* Max number of regulators defined in device tree */
+#define MSM_JPEGDMA_MAX_REGULATOR_NUM 3
+/* Max number of planes supported */
+#define MSM_JPEGDMA_MAX_PLANES 3
+/* Max number of hw pipes supported */
+#define MSM_JPEGDMA_MAX_PIPES 2
+/* Max number of hw configurations supported */
+#define MSM_JPEGDMA_MAX_CONFIGS 2
+/* Dma default fps */
+#define MSM_JPEGDMA_DEFAULT_FPS 30
+
+/* Dma input output size limitations */
+#define MSM_JPEGDMA_MAX_WIDTH 65536
+#define MSM_JPEGDMA_MIN_WIDTH 8
+#define MSM_JPEGDMA_MAX_HEIGHT 65536
+#define MSM_JPEGDMA_MIN_HEIGHT 8
+#define MSM_JPEGDMA_STRIDE_ALIGN 8
+
+/*
+ * enum msm_jpegdma_plane_type - Dma format.
+ * @JPEGDMA_PLANE_TYPE_Y: Y plane type.
+ * @JPEGDMA_PLANE_TYPE_CR: Chroma CB plane.
+ * @JPEGDMA_PLANE_TYPE_CB:  Chroma CR plane.
+ * @JPEGDMA_PLANE_TYPE_CBCR: Interlevaed CbCr plane.
+ */
+enum msm_jpegdma_plane_type {
+	JPEGDMA_PLANE_TYPE_Y,
+	JPEGDMA_PLANE_TYPE_CR,
+	JPEGDMA_PLANE_TYPE_CB,
+	JPEGDMA_PLANE_TYPE_CBCR,
+};
+
+/*
+ * struct msm_jpegdma_format - Dma format.
+ * @name: Format name.
+ * @fourcc: v4l2 fourcc code.
+ * @depth: Number of bits per pix.
+ * @num_planes: number of planes.
+ * @colplane_h: Color plane horizontal subsample.
+ * @colplane_v: Color plane vertical subsample.
+ * @h_align: Horizontal align.
+ * @v_align: Vertical align.
+ * @planes: Array with plane types.
+ */
+struct msm_jpegdma_format {
+	char *name;
+	u32 fourcc;
+	int depth;
+	int num_planes;
+	int colplane_h;
+	int colplane_v;
+	int h_align;
+	int v_align;
+	enum msm_jpegdma_plane_type planes[MSM_JPEGDMA_MAX_PLANES];
+};
+
+/*
+ * struct msm_jpegdma_size - Dma size.
+ * @top: Top position.
+ * @left: Left position
+ * @width: Width
+ * @height: height.
+ * @scanline: Number of lines per plane.
+ * @stride: Stride bytes per line.
+ */
+struct msm_jpegdma_size {
+	unsigned int top;
+	unsigned int left;
+	unsigned int width;
+	unsigned int height;
+	unsigned int scanline;
+	unsigned int stride;
+};
+
+/*
+ * struct msm_jpegdma_size_config - Dma engine size configuration.
+ * @in_size: Input size.
+ * @out_size: Output size.
+ * @format: Format.
+ * @fps: Requested frames per second.
+ */
+struct msm_jpegdma_size_config {
+	struct msm_jpegdma_size in_size;
+	struct msm_jpegdma_size out_size;
+	struct msm_jpegdma_format format;
+	unsigned int fps;
+	unsigned int in_offset;
+	unsigned int out_offset;
+};
+
+/*
+ * struct msm_jpegdma_block - Dma hw block.
+ * @div: Block divider.
+ * @width: Block width.
+ * @reg_val: Block register value.
+ */
+struct msm_jpegdma_block {
+	unsigned int div;
+	unsigned int width;
+	unsigned int reg_val;
+};
+
+/*
+ * struct msm_jpegdma_block_config - Dma hw block configuration.
+ * @block: Block settings.
+ * @blocks_per_row: Blocks per row.
+ * @blocks_per_col: Blocks per column.
+ * @h_step: Horizontal step value
+ * @v_step: Vertical step value
+ * @h_step_last: Last horizontal step.
+ * @v_step_last: Last vertical step.
+ */
+struct msm_jpegdma_block_config {
+	struct msm_jpegdma_block block;
+	unsigned int blocks_per_row;
+	unsigned int blocks_per_col;
+	unsigned int h_step;
+	unsigned int v_step;
+	unsigned int h_step_last;
+	unsigned int v_step_last;
+};
+
+/*
+ * msm_jpegdma_scale - Dma hw scale configuration.
+ * @enable: Scale enable.
+ * @hor_scale: Horizontal scale factor in Q21 format.
+ * @ver_scale: Vertical scale factor in Q21 format.
+ */
+struct msm_jpegdma_scale {
+	int enable;
+	unsigned int hor_scale;
+	unsigned int ver_scale;
+};
+
+/*
+ * struct msm_jpegdma_config - Dma hw configuration.
+ * @size_cfg: Size configuration.
+ * @scale_cfg: Scale configuration
+ * @block_cfg: Block configuration.
+ * @phase: Starting phase.
+ * @in_offset: Input offset.
+ * @out_offset: Output offset.
+ */
+struct msm_jpegdma_config {
+	struct msm_jpegdma_size_config size_cfg;
+	struct msm_jpegdma_scale scale_cfg;
+	struct msm_jpegdma_block_config block_cfg;
+	unsigned int phase;
+	unsigned int in_offset;
+	unsigned int out_offset;
+};
+
+/*
+ * struct msm_jpegdma_plane_config - Contain input output address.
+ * @bus_ab: Bus average bandwidth.
+ * @bus_ib: Bus instantaneous bandwidth.
+ * @core_clock: Core clock freq.
+ */
+struct msm_jpegdma_speed {
+	u64 bus_ab;
+	u64 bus_ib;
+	u64 core_clock;
+};
+
+/*
+ * struct msm_jpegdma_plane_config - Contain input output address.
+ * @active_pipes: Number of active pipes.
+ * @config: Plane configurations.
+ * @type: Plane type.
+ */
+struct msm_jpegdma_plane {
+	unsigned int active_pipes;
+	struct msm_jpegdma_config config[MSM_JPEGDMA_MAX_PIPES];
+	enum msm_jpegdma_plane_type type;
+};
+
+/*
+ * struct msm_jpegdma_plane_config - Contain input output address.
+ * @num_planes: Number of planes.
+ * @plane: Plane configuration.
+ * @speed: Processing speed.
+ */
+struct msm_jpegdma_plane_config {
+	unsigned int num_planes;
+	struct msm_jpegdma_plane plane[MSM_JPEGDMA_MAX_PLANES];
+	struct msm_jpegdma_speed speed;
+};
+
+/*
+ * struct msm_jpegdma_addr - Contain input output address.
+ * @in_addr: Input dma address.
+ * @out_addr: Output dma address.
+ */
+struct msm_jpegdma_addr {
+	u32 in_addr;
+	u32 out_addr;
+};
+
+/*
+ * struct msm_jpegdma_buf_handle - Structure contain dma buffer information.
+ * @fd: ion dma from which this buffer is imported.
+ * @dma: Pointer to jpeg dma device.
+ * @size: Size of the buffer.
+ * @addr: Adders of dma mmu mapped buffer. This address should be set to dma hw.
+ */
+struct msm_jpegdma_buf_handle {
+	int fd;
+	struct msm_jpegdma_device *dma;
+	unsigned long size;
+	ion_phys_addr_t addr;
+};
+
+/*
+ * @jpegdma_ctx - Structure contains per open file handle context.
+ * @lock: Lock protecting dma ctx.
+ * @jdma_device: Pointer to dma device.
+ * @active: Set if context is active.
+ * @completion: Context processing completion.
+ * @fh: V4l2 file handle.
+ * @m2m_ctx: Memory to memory context.
+ * @format_cap: Current capture format.
+ * @format_out: Current output format.
+ * @crop: Current crop.
+ * @timeperframe: Time per frame in seconds.
+ * @config_idx: Plane configuration active index.
+ * @plane_config: Array of plane configurations.
+ * @pending_config: Flag set if there is pending plane configuration.
+ * @plane_idx: Processing plane index.
+ * @format_idx: Current format index.
+ */
+struct jpegdma_ctx {
+	struct mutex lock;
+	struct msm_jpegdma_device *jdma_device;
+	atomic_t active;
+	struct completion completion;
+	struct v4l2_fh fh;
+	struct v4l2_m2m_ctx *m2m_ctx;
+	struct v4l2_format format_cap;
+	struct v4l2_format format_out;
+	struct v4l2_rect crop;
+	struct v4l2_fract timeperframe;
+	unsigned int in_offset;
+	unsigned int out_offset;
+
+	unsigned int config_idx;
+	struct msm_jpegdma_plane_config plane_config[MSM_JPEGDMA_MAX_CONFIGS];
+	unsigned int pending_config;
+
+	unsigned int plane_idx;
+	unsigned int format_idx;
+};
+
+/*
+ * struct jpegdma_reg_cfg - Registry values configuration
+ * @reg: Register offset.
+ * @val: Register value.
+ */
+struct jpegdma_reg_cfg {
+	unsigned int reg;
+	unsigned int val;
+};
+
+/*
+ * enum msm_jpegdma_mem_resources - jpegdma device iomem resources.
+ * @MSM_JPEGDMA_IOMEM_CORE: Index of jpegdma core registers.
+ * @MSM_JPEGDMA_IOMEM_VBIF: Index of jpegdma vbif registers.
+ * @MSM_JPEGDMA_IOMEM_LAST: Not valid.
+ */
+enum msm_jpegdma_mem_resources {
+	MSM_JPEGDMA_IOMEM_CORE,
+	MSM_JPEGDMA_IOMEM_VBIF,
+	MSM_JPEGDMA_IOMEM_LAST
+};
+
+/*
+ * struct msm_jpegdma_device - FD device structure.
+ * @lock: Lock protecting dma device.
+ * @ref_count: Device reference count.
+ * @irq_num: Face detection irq number.
+ * @res_mem: Array of memory resources used by Dma device.
+ * @iomem_base: Array of register mappings used by Dma device.
+ * @ioarea: Array of register ioarea used by Dma device.
+ * @vdd: Pointer to vdd regulator.
+ * @regulator_num: Number of regulators attached to the device.
+ * @clk_num: Number of clocks attached to the device.
+ * @clk: Array of clock resources used by dma device.
+ * @clk_rates: Array of clock rates.
+ * @vbif_regs_num: number of vbif  regs.
+ * @vbif_regs: Array of vbif regs need to be set.
+ * @qos_regs_num: Number of qos regs .
+ * @qos_regs: Array of qos regs need to be set.
+ * @bus_client: Memory access bus client.
+ * @bus_vectors: Bus vector
+ * @bus_paths: Bus path.
+ * @bus_scale_data: Memory access bus scale data.
+ * @iommu_hndl: Dma device iommu handle.
+ * @iommu_attached_cnt: Iommu attached devices reference count.
+ * @iommu_dev: Pointer to Ion iommu device.
+ * @dev: Pointer to device struct.
+ * @v4l2_dev: V4l2 device.
+ * @video: Video device.
+ * @m2m_dev: Memory to memory device.
+ * @hw_num_pipes: Number of dma hw pipes.
+ * @active_clock_rate: Active clock rate index.
+ * @hw_reset_completion: Dma reset completion.
+ * @hw_halt_completion: Dma halt completion.
+ */
+struct msm_jpegdma_device {
+	struct mutex lock;
+	int ref_count;
+
+	int irq_num;
+	void __iomem *iomem_base[MSM_JPEGDMA_IOMEM_LAST];
+
+	struct resource *irq;
+	struct msm_cam_regulator *dma_vdd;
+	int num_reg;
+
+	struct clk **clk;
+	size_t num_clk;
+	struct msm_cam_clk_info *jpeg_clk_info;
+
+	unsigned int vbif_regs_num;
+	struct jpegdma_reg_cfg *vbif_regs;
+	unsigned int qos_regs_num;
+	struct jpegdma_reg_cfg *qos_regs;
+	unsigned int prefetch_regs_num;
+	struct jpegdma_reg_cfg *prefetch_regs;
+
+	enum cam_bus_client bus_client;
+	struct msm_bus_vectors bus_vectors;
+	struct msm_bus_paths bus_paths;
+	struct msm_bus_scale_pdata bus_scale_data;
+
+	int iommu_hndl;
+	unsigned int iommu_attached_cnt;
+
+	struct device *iommu_dev;
+	struct device *dev;
+	struct v4l2_device v4l2_dev;
+	struct video_device video;
+	struct v4l2_m2m_dev *m2m_dev;
+
+	int hw_num_pipes;
+	struct completion hw_reset_completion;
+	struct completion hw_halt_completion;
+	u64 active_clock_rate;
+	struct platform_device *pdev;
+};
+
+void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma);
+
+#endif /* __MSM_JPEG_DMA_DEV_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
new file mode 100644
index 0000000..702be49
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.c
@@ -0,0 +1,1874 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/iommu.h>
+#include <linux/msm_ion.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <media/videobuf2-core.h>
+
+#include "msm_camera_io_util.h"
+#include "cam_smmu_api.h"
+#include "msm_jpeg_dma_dev.h"
+#include "msm_jpeg_dma_hw.h"
+#include "msm_jpeg_dma_regs.h"
+
+/* Jpeg dma scale unity */
+#define MSM_JPEGDMA_SCALE_UNI (1 << 21)
+/* Jpeg dma bw numerator */
+#define MSM_JPEGDMA_BW_NUM 38
+/* Jpeg dma bw denominator */
+#define MSM_JPEGDMA_BW_DEN 10
+/* Jpeg bus client name */
+#define MSM_JPEGDMA_BUS_CLIENT_NAME "msm_jpeg_dma"
+/* Jpeg dma engine timeout in ms */
+#define MSM_JPEGDMA_TIMEOUT_MS 500
+/* Jpeg dma smmu name */
+#define MSM_JPEGDMA_SMMU_NAME "jpeg_dma"
+
+static const struct msm_jpegdma_block msm_jpegdma_block_sel[] = {
+	{
+		.div = 0x3C0000,
+		.width = 256,
+		.reg_val = 4,
+	},
+	{
+		.div = 0x7C0000,
+		.width = 128,
+		.reg_val = 3,
+	},
+	{
+		.div = 0xFC0000,
+		.width = 64,
+		.reg_val = 2,
+	},
+	{
+		.div = 0x1FC0000,
+		.width = 32,
+		.reg_val = 1,
+	},
+	{
+		.div = 0x4000000,
+		.width = 16,
+		.reg_val = 0,
+	},
+};
+
+/*
+ * jpegdma_do_div - long division.
+ * @num: dividend
+ * @den: divisor
+ * returns quotient value.
+ */
+static inline long long jpegdma_do_div(long long num, long long den)
+{
+	do_div(num, den);
+	return num;
+}
+
+/*
+ * msm_jpegdma_hw_read_reg - dma read from register.
+ * @dma: Pointer to dma device.
+ * @base_idx: dma memory resource index.
+ * @reg: Register addr need to be read from.
+ */
+static inline u32 msm_jpegdma_hw_read_reg(struct msm_jpegdma_device *dma,
+	enum msm_jpegdma_mem_resources base_idx, u32 reg)
+{
+	return msm_camera_io_r(dma->iomem_base[base_idx] + reg);
+}
+
+/*
+ * msm_jpegdma_hw_write_reg - dma write to register.
+ * @dma: Pointer to dma device.
+ * @base_idx: dma memory resource index.
+ * @reg: Register addr need to be read from.
+ * @value: Value to be written.
+ */
+static inline void msm_jpegdma_hw_write_reg(struct msm_jpegdma_device *dma,
+	enum msm_jpegdma_mem_resources base_idx, u32 reg, u32 value)
+{
+	pr_debug("%s:%d]%pK %08x\n", __func__, __LINE__,
+		dma->iomem_base[base_idx] + reg,
+		value);
+	msm_camera_io_w(value, dma->iomem_base[base_idx] + reg);
+}
+
+/*
+ * msm_jpegdma_hw_enable_irq - Enable dma interrupts.
+ * @dma: Pointer to dma device.
+ */
+static void msm_jpegdma_hw_enable_irq(struct msm_jpegdma_device *dma)
+{
+	u32 reg;
+
+	reg = MSM_JPEGDMA_IRQ_MASK_SESSION_DONE |
+		MSM_JPEGDMA_IRQ_MASK_AXI_HALT |
+		MSM_JPEGDMA_IRQ_MASK_RST_DONE;
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_IRQ_MASK_ADDR, reg);
+}
+
+/*
+ * msm_jpegdma_hw_disable_irq - Disable dma interrupts.
+ * @dma: Pointer to dma device.
+ */
+static void msm_jpegdma_hw_disable_irq(struct msm_jpegdma_device *dma)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_IRQ_MASK_ADDR, 0);
+}
+
+/*
+ * msm_jpegdma_hw_clear_irq - Clear dma interrupts.
+ * @dma: Pointer to dma device.
+ * @status: Status to clear.
+ */
+static void msm_jpegdma_hw_clear_irq(struct msm_jpegdma_device *dma,
+	u32 status)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_IRQ_CLEAR_ADDR, status);
+}
+
+/*
+ * msm_jpegdma_hw_get_irq_status - Get dma irq status
+ * @dma: Pointer to dma device.
+ */
+static u32 msm_jpegdma_hw_get_irq_status(struct msm_jpegdma_device *dma)
+{
+	return msm_jpegdma_hw_read_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_IRQ_STATUS);
+}
+
+/*
+ * msm_jpegdma_hw_get_num_pipes - Get number of dma pipes
+ * @dma: Pointer to dma device.
+ */
+static int msm_jpegdma_hw_get_num_pipes(struct msm_jpegdma_device *dma)
+{
+	int num_pipes;
+	u32 reg;
+
+	reg = msm_jpegdma_hw_read_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_HW_CAPABILITY);
+
+	num_pipes = (reg & MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_BMSK) >>
+		MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_SHFT;
+
+	return num_pipes;
+}
+
+/*
+ * msm_jpegdma_hw_get_clock_index - Get clock index by name
+ * @dma: Pointer to dma device.
+ * @clk_name: clock name.
+ */
+static int msm_jpegdma_hw_get_clock_index(struct msm_jpegdma_device *dma,
+		const char *clk_name)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < dma->num_clk; i++) {
+		if (!strcmp(clk_name, dma->jpeg_clk_info[i].clk_name))
+			return i;
+	}
+	return -EINVAL;
+}
+
+/*
+ * msm_jpegdma_hw_reset - Reset jpeg dma core.
+ * @dma: Pointer to dma device.
+ */
+static int msm_jpegdma_hw_reset(struct msm_jpegdma_device *dma)
+{
+	unsigned long time;
+
+	init_completion(&dma->hw_reset_completion);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_HW_JPEGDMA_RESET, MSM_HW_JPEGDMA_RESET_DEFAULT);
+
+	time = wait_for_completion_timeout(&dma->hw_reset_completion,
+		msecs_to_jiffies(MSM_JPEGDMA_TIMEOUT_MS));
+	if (!time) {
+		dev_err(dma->dev, "Jpeg dma detection reset timeout\n");
+		return -ETIME;
+	}
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_halt - Halt jpeg dma core.
+ * @dma: Pointer to dma device.
+ */
+static int msm_jpegdma_hw_halt(struct msm_jpegdma_device *dma)
+{
+	unsigned long time;
+
+	init_completion(&dma->hw_halt_completion);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_CMD_ADDR, 0x4);
+
+	time = wait_for_completion_timeout(&dma->hw_halt_completion,
+		msecs_to_jiffies(MSM_JPEGDMA_TIMEOUT_MS));
+	if (!time) {
+		dev_err(dma->dev, "Jpeg dma detection halt timeout\n");
+		return -ETIME;
+	}
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_run - Enable dma processing.
+ * @dma: Pointer to dma device.
+ */
+static int msm_jpegdma_hw_run(struct msm_jpegdma_device *dma)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_CMD_ADDR, 0x1);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_core_config - Set jpeg dma core configuration.
+ * @dma: Pointer to dma device.
+ * @num_pipes: Number of pipes.
+ * @scale_0: Scaler 0 enable.
+ * @scale_1: Scaler 1 enable.
+ */
+static int msm_jpegdma_hw_core_config(struct msm_jpegdma_device *dma,
+	int num_pipes, int scale_0, int scale_1)
+{
+	u32 reg;
+
+	reg = (scale_0 << MSM_JPEGDMA_CORE_CFG_SCALE_0_ENABLE_SHFT) |
+		(0x1 << MSM_JPEGDMA_CORE_CFG_TEST_BUS_ENABLE_SHFT) |
+		(0x1 << MSM_JPEGDMA_CORE_CFG_BRIDGE_ENABLE_SHFT) |
+		(0x1 << MSM_JPEGDMA_CORE_CFG_WE_0_ENABLE_SHFT) |
+		(0x1 << MSM_JPEGDMA_CORE_CFG_FE_0_ENABLE_SHFT);
+
+	/* Enable read write ports for second pipe */
+	if (num_pipes > 1) {
+		reg |= (scale_1 << MSM_JPEGDMA_CORE_CFG_SCALE_1_ENABLE_SHFT) |
+			(0x1 << MSM_JPEGDMA_CORE_CFG_WE_1_ENABLE_SHFT) |
+			(0x1 << MSM_JPEGDMA_CORE_CFG_FE_1_ENABLE_SHFT);
+	}
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_CORE_CFG_ADDR, reg);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_0_block - Fetch engine 0 block configuration.
+ * @dma: Pointer to dma device.
+ * @block_config: Pointer to block configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_fe_0_block(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_block_config *block_config,
+	enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	switch (plane_type) {
+	case JPEGDMA_PLANE_TYPE_Y:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CB:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CR:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CBCR:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	default:
+		dev_err(dma->dev, "Unsupported plane type %d\n", plane_type);
+		return -EINVAL;
+	}
+
+	reg |= (block_config->block.reg_val <<
+		MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT) |
+		(0x1 << MSM_JPEGDMA_FE_CFG_MAL_BOUNDARY_SHFT) |
+		(0x1 << MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT) |
+		(0xF << MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_0_CFG_ADDR, reg);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_1_block - Fetch engine 1 block configuration.
+ * @dma: Pointer to dma device.
+ * @block_config: Pointer to block configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_fe_1_block(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_block_config *block_config,
+	enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	switch (plane_type) {
+	case JPEGDMA_PLANE_TYPE_Y:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CB:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CR:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	case JPEGDMA_PLANE_TYPE_CBCR:
+		reg = MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR <<
+			MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT;
+		break;
+	default:
+		dev_err(dma->dev, "Unsupported plane type %d\n", plane_type);
+		return -EINVAL;
+	}
+
+	reg |= (block_config->block.reg_val <<
+		MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT) |
+		(0xF << MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT) |
+		(0x1 << MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_1_CFG_ADDR, reg);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_0_phase - Fetch engine 0 phase configuration.
+ * @dma: Pointer to dma device.
+ * @phase: Fetch engine 0 phase.
+ */
+static int msm_jpegdma_hw_fe_0_phase(struct msm_jpegdma_device *dma, int phase)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_HINIT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, phase);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_1_phase - Fetch engine 1 phase configuration.
+ * @dma: Pointer to dma device.
+ * @phase: Fetch engine 1 phase.
+ */
+static int msm_jpegdma_hw_fe_1_phase(struct msm_jpegdma_device *dma, int phase)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_HINIT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, 0x00);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, phase);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_0_size - Fetch engine 0 size configuration.
+ * @dma: Pointer to dma device.
+ * @size: Pointer to size configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_fe_0_size(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size *size, enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	reg = (size->width + size->left - 1) |
+		((size->height + size->top - 1) <<
+		MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_BUFFER_SIZE_0_ADDR, reg);
+
+	if (size->left && plane_type == JPEGDMA_PLANE_TYPE_CBCR)
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, size->left / 2);
+	else
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR, size->left);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR, size->top);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_STRIDE_ADDR, size->stride);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_1_size - Fetch engine 1 size configuration.
+ * @dma: Pointer to dma device.
+ * @size: Pointer to size configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_fe_1_size(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size *size, enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	reg = (size->width + size->left - 1) |
+		((size->height + size->top - 1) <<
+		MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_BUFFER_SIZE_1_ADDR, reg);
+
+	if (size->left && plane_type == JPEGDMA_PLANE_TYPE_CBCR)
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, size->left / 2);
+	else
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR, size->left);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR, size->top);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_STRIDE_ADDR, size->stride);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_0_addr - Set fetch engine 0 address.
+ * @dma: Pointer to dma device.
+ * @addr: Fetch engine address.
+ */
+static int msm_jpegdma_hw_fe_0_addr(struct msm_jpegdma_device *dma, u32 addr)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_CMD_ADDR, MSM_JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_0_PNTR_ADDR, addr);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_1_addr - Set fetch engine 1 address.
+ * @dma: Pointer to dma device.
+ * @addr: Fetch engine address.
+ */
+static int msm_jpegdma_hw_fe_1_addr(struct msm_jpegdma_device *dma, u32 addr)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_FE_RD_1_PNTR_ADDR, addr);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_fe_0_block - Write engine 0 block configuration.
+ * @dma: Pointer to dma device.
+ * @block_config: Pointer to block configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_we_0_block(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_block_config *block,
+	enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	reg = (0xF << MSM_JPEGDMA_WE_CFG_BURST_LENGTH_MAX_SHFT) |
+		(0x1 << MSM_JPEGDMA_WE_CFG_MAL_BOUNDARY_SHFT) |
+		(0x1 << MSM_JPEGDMA_WE_CFG_MAL_EN_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_CFG_ADDR, reg);
+
+	reg = ((block->blocks_per_row - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT) |
+		(block->blocks_per_col - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_CFG_0_ADDR, reg);
+
+	reg = ((block->h_step_last - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT) |
+		(block->h_step - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_CFG_1_ADDR, reg);
+
+	reg = ((block->v_step_last - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT) |
+		(block->v_step - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_CFG_2_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_CFG_3_ADDR, 0x0);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_we_1_block - Write engine 1 block configuration.
+ * @dma: Pointer to dma device.
+ * @block_config: Pointer to block configuration.
+ * @plane_type: Plane type.
+ */
+static int msm_jpegdma_hw_we_1_block(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_block_config *block,
+	enum msm_jpegdma_plane_type plane_type)
+{
+	u32 reg;
+
+	reg = ((block->blocks_per_row - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT) |
+		(block->blocks_per_col - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_CFG_0_ADDR, reg);
+
+	reg = ((block->h_step_last - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT) |
+		(block->h_step - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_CFG_1_ADDR, reg);
+
+	reg = ((block->v_step_last - 1) <<
+		MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT) |
+		(block->v_step - 1);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_CFG_2_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_CFG_3_ADDR, 0x0);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_we_0_size - Write engine 0 size configuration.
+ * @dma: Pointer to dma device.
+ * @size: Pointer to size configuration.
+ */
+static int msm_jpegdma_hw_we_0_size(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size *size)
+{
+	u32 reg;
+
+	reg = (size->width) | ((size->height) <<
+		MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_0_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_STRIDE_ADDR, size->stride);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_we_1_size - Write engine 1 size configuration.
+ * @dma: Pointer to dma device.
+ * @size: Pointer to size configuration.
+ */
+static int msm_jpegdma_hw_we_1_size(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size *size)
+{
+	u32 reg;
+
+	reg = (size->width) | ((size->height) <<
+		MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_1_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_STRIDE_ADDR, size->stride);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_we_0_addr - Set write engine 0 address.
+ * @dma: Pointer to dma device.
+ * @addr: Fetch engine address.
+ */
+static int msm_jpegdma_hw_we_0_addr(struct msm_jpegdma_device *dma, u32 addr)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_CMD_ADDR, MSM_JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_0_WR_PNTR_ADDR, addr);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_we_1_addr - Set write engine 1 address.
+ * @dma: Pointer to dma device.
+ * @addr: Fetch engine address.
+ */
+static int msm_jpegdma_hw_we_1_addr(struct msm_jpegdma_device *dma, u32 addr)
+{
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_WE_PLN_1_WR_PNTR_ADDR, addr);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_scale_0_config - Scale configuration for 0 pipeline.
+ * @dma: Pointer to dma device.
+ * @scale: Scale configuration.
+ */
+static int msm_jpegdma_hw_scale_0_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_scale *scale)
+{
+	u32 reg;
+	u32 h_down_en;
+	u32 v_down_en;
+
+	h_down_en = (scale->hor_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1;
+	v_down_en = (scale->ver_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1;
+
+	reg = (h_down_en << MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT) |
+		(v_down_en << MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_0_SCALE_CFG_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_0_SCALE_PHASEH_STEP_ADDR, scale->hor_scale);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_0_SCALE_PHASEV_STEP_ADDR, scale->ver_scale);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_scale_1_config - Scale configuration for 1 pipeline.
+ * @dma: Pointer to dma device.
+ * @scale: Scale configuration.
+ */
+static int msm_jpegdma_hw_scale_1_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_scale *scale)
+{
+	u32 reg;
+	u32 h_down_en;
+	u32 v_down_en;
+
+	h_down_en = (scale->hor_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1;
+	v_down_en = (scale->ver_scale == MSM_JPEGDMA_SCALE_UNI) ? 0 : 1;
+
+	reg = (h_down_en << MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT) |
+		(v_down_en << MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_1_SCALE_CFG_ADDR, reg);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_1_SCALE_PHASEH_STEP_ADDR, scale->hor_scale);
+
+	msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+		MSM_JPEGDMA_PP_1_SCALE_PHASEV_STEP_ADDR, scale->ver_scale);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_config_qos - Configure qos registers.
+ * @dma: Pointer to dma device.
+ */
+static void msm_jpegdma_hw_config_qos(struct msm_jpegdma_device *dma)
+{
+	int i;
+
+	if (!dma->qos_regs_num)
+		return;
+
+	for (i = 0; i < dma->qos_regs_num; i++)
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			dma->qos_regs[i].reg, dma->qos_regs[i].val);
+
+}
+
+/*
+ * msm_jpegdma_hw_config_vbif - Configure and vbif interface.
+ * @dma: Pointer to dma device.
+ */
+static void msm_jpegdma_hw_config_vbif(struct msm_jpegdma_device *dma)
+{
+	int i;
+
+	if (!dma->vbif_regs_num)
+		return;
+
+	for (i = 0; i < dma->vbif_regs_num; i++)
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_VBIF,
+			dma->vbif_regs[i].reg, dma->vbif_regs[i].val);
+
+}
+
+/*
+ * msm_jpegdma_hw_config_mmu_prefetch - Configure mmu prefetch registers.
+ * @dma: Pointer to dma device.
+ * @min_addr: Pointer to jpeg dma addr, containing min addrs of the plane.
+ * @max_addr: Pointer to jpeg dma addr, containing max addrs of the plane.
+ */
+static void msm_jpegdma_hw_config_mmu_prefetch(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_addr *min_addr,
+	struct msm_jpegdma_addr *max_addr)
+{
+	int i;
+
+	if (!dma->prefetch_regs_num)
+		return;
+
+	for (i = 0; i < dma->prefetch_regs_num; i++)
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_VBIF,
+			dma->prefetch_regs[i].reg, dma->prefetch_regs[i].val);
+
+	if (min_addr != NULL && max_addr != NULL) {
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN, min_addr->in_addr);
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX, max_addr->in_addr);
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN, min_addr->out_addr);
+		msm_jpegdma_hw_write_reg(dma, MSM_JPEGDMA_IOMEM_CORE,
+			MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX, max_addr->out_addr);
+	}
+}
+
+/*
+ * msm_jpegdma_hw_calc_speed - Calculate speed based on framerate and size.
+ * @dma: Pointer to dma device.
+ * @size: Dma user size configuration.
+ * @speed: Calculated speed.
+ */
+static int msm_jpegdma_hw_calc_speed(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size,
+	struct msm_jpegdma_speed *speed)
+{
+	u64 width;
+	u64 height;
+	long real_clock;
+	u64 calc_rate;
+	int core_clk_idx;
+
+	width = size->in_size.width + size->in_size.left;
+	height = size->in_size.height + size->in_size.top;
+
+	calc_rate = (width * height * size->format.depth * size->fps) / 16;
+	core_clk_idx = msm_jpegdma_hw_get_clock_index(dma,
+		MSM_JPEGDMA_CORE_CLK);
+	if (core_clk_idx < 0) {
+		dev_err(dma->dev, "Can get clock index for dma %s\n",
+			MSM_JPEGDMA_CORE_CLK);
+	}
+
+	real_clock = clk_round_rate(dma->clk[core_clk_idx], calc_rate);
+	if (real_clock < 0) {
+		dev_err(dma->dev, "Can not round core clock\n");
+		return -EINVAL;
+	}
+
+	speed->bus_ab = calc_rate * 2;
+	speed->bus_ib = jpegdma_do_div((real_clock *
+		(MSM_JPEGDMA_BW_NUM + MSM_JPEGDMA_BW_DEN - 1)),
+		MSM_JPEGDMA_BW_DEN);
+	speed->core_clock = real_clock;
+	dev_dbg(dma->dev, "Speed core clk %llu ab %llu ib %llu fps %d\n",
+		speed->core_clock, speed->bus_ab, speed->bus_ib, size->fps);
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_set_speed - Configure clock and bus bandwidth based on
+ *   requested speed and dma clients.
+ * @size: Jpeg dma size configuration.
+ * @speed: Requested dma speed.
+ */
+static int msm_jpegdma_hw_set_speed(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size,
+	struct msm_jpegdma_speed *speed)
+{
+	struct msm_jpegdma_speed new_sp;
+	struct msm_jpegdma_size_config new_size;
+	int ret;
+	int core_clk_idx;
+
+	if (dma->active_clock_rate >= speed->core_clock)
+		return 0;
+
+	new_sp = *speed;
+	if (dma->ref_count > 2) {
+		new_size = *size;
+		new_size.fps = size->fps * ((dma->ref_count + 1) / 2);
+		ret = msm_jpegdma_hw_calc_speed(dma, &new_size, &new_sp);
+		if (ret < 0)
+			return -EINVAL;
+	}
+
+	core_clk_idx = msm_jpegdma_hw_get_clock_index(dma,
+		MSM_JPEGDMA_CORE_CLK);
+	if (core_clk_idx < 0) {
+		dev_err(dma->dev, "Can get clock index for dma %s\n",
+			MSM_JPEGDMA_CORE_CLK);
+	}
+
+	ret = clk_set_rate(dma->clk[core_clk_idx], new_sp.core_clock);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail Core clock rate %d\n", ret);
+		return -EINVAL;
+	}
+	dma->active_clock_rate = speed->core_clock;
+
+	dma->bus_vectors.ab = new_sp.bus_ab;
+	dma->bus_vectors.ib = new_sp.bus_ib;
+
+	ret = msm_bus_scale_client_update_request(dma->bus_client, 0);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail bus scale update %d\n", ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_add_plane_offset - Add plane offset to all pipelines.
+ * @plane: Jpeg dma plane configuration.
+ * @in_offset: Input plane offset.
+ * @out_offset: Output plane offset.
+ */
+static int msm_jpegdma_hw_add_plane_offset(struct msm_jpegdma_plane *plane,
+	unsigned int in_offset, unsigned int out_offset)
+{
+	int i;
+
+	for (i = 0; i < plane->active_pipes; i++) {
+		plane->config[i].in_offset += in_offset;
+		plane->config[i].out_offset += out_offset;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_calc_config - Calculate plane configuration.
+ * @size_cfg: Size configuration.
+ * @plane: Plane configuration need to be calculated.
+ */
+static int msm_jpegdma_hw_calc_config(struct msm_jpegdma_size_config *size_cfg,
+	struct msm_jpegdma_plane *plane)
+{
+	u64 scale_hor, scale_ver, phase;
+	u64 in_width, in_height;
+	u64 out_width, out_height;
+	struct msm_jpegdma_config *config;
+	int i;
+
+	if (!size_cfg->out_size.width || !size_cfg->out_size.height)
+		return -EINVAL;
+
+	config = &plane->config[0];
+	config->scale_cfg.enable = 0;
+
+	in_width = size_cfg->in_size.width;
+	out_width = size_cfg->out_size.width;
+	scale_hor = jpegdma_do_div((in_width * MSM_JPEGDMA_SCALE_UNI),
+		out_width);
+	if (scale_hor != MSM_JPEGDMA_SCALE_UNI)
+		config->scale_cfg.enable = 1;
+
+	in_height = size_cfg->in_size.height;
+	out_height = size_cfg->out_size.height;
+	scale_ver = jpegdma_do_div((in_height * MSM_JPEGDMA_SCALE_UNI),
+		out_height);
+	if (scale_ver != MSM_JPEGDMA_SCALE_UNI)
+		config->scale_cfg.enable = 1;
+
+	config->scale_cfg.ver_scale = scale_ver;
+	config->scale_cfg.hor_scale = scale_hor;
+
+	for (i = 0; ARRAY_SIZE(msm_jpegdma_block_sel); i++)
+		if (scale_hor <= msm_jpegdma_block_sel[i].div)
+			break;
+
+	if (i == ARRAY_SIZE(msm_jpegdma_block_sel))
+		return -EINVAL;
+
+	config->block_cfg.block = msm_jpegdma_block_sel[i];
+
+	if (plane->active_pipes > 1) {
+		phase = jpegdma_do_div((out_height * scale_ver +
+			(plane->active_pipes - 1)), plane->active_pipes);
+		phase &= (u64)(MSM_JPEGDMA_SCALE_UNI - 1);
+		out_height = jpegdma_do_div((out_height +
+			(plane->active_pipes - 1)), plane->active_pipes);
+		in_height = (out_height * scale_ver) / MSM_JPEGDMA_SCALE_UNI;
+	}
+
+	config->block_cfg.blocks_per_row = (uint32_t) jpegdma_do_div(out_width,
+		config->block_cfg.block.width);
+
+	config->block_cfg.blocks_per_col = out_height;
+
+	config->block_cfg.h_step = config->block_cfg.block.width;
+	config->size_cfg.out_size.width = out_width;
+	config->block_cfg.h_step_last = (uint32_t) do_div(out_width,
+		config->block_cfg.block.width);
+	if (!config->block_cfg.h_step_last)
+		config->block_cfg.h_step_last = config->block_cfg.h_step;
+	else
+		config->block_cfg.blocks_per_row++;
+
+	config->block_cfg.v_step = 1;
+	config->block_cfg.v_step_last = 1;
+
+	config->size_cfg = *size_cfg;
+	config->size_cfg.in_size.width = in_width;
+	config->size_cfg.in_size.height = in_height;
+	config->size_cfg.out_size.height = out_height;
+	config->in_offset = 0;
+	config->out_offset = 0;
+
+	if (plane->active_pipes > 1) {
+		plane->config[1] = *config;
+		/* Recalculate offset for second pipe */
+		plane->config[1].in_offset =
+			config->size_cfg.in_size.scanline *
+			config->size_cfg.in_size.stride;
+
+		plane->config[1].out_offset =
+			config->size_cfg.out_size.scanline *
+			config->size_cfg.out_size.stride;
+
+		plane->config[1].phase = phase;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_check_config - Check configuration based on size is possible.
+ *@dma: Pointer to dma device.
+ * @size_cfg: Size configuration.
+ */
+int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size_cfg)
+{
+	u64 in_width, in_height;
+	u64 out_width, out_height;
+	u64 scale;
+
+	if (!size_cfg->out_size.width || !size_cfg->out_size.height)
+		return -EINVAL;
+
+	in_width = size_cfg->in_size.width;
+	out_width = size_cfg->out_size.width;
+	scale = jpegdma_do_div(((in_width * MSM_JPEGDMA_SCALE_UNI)),
+		out_width);
+	if (scale < MSM_JPEGDMA_SCALE_UNI)
+		return -EINVAL;
+
+
+	in_height = size_cfg->in_size.height;
+	out_height = size_cfg->out_size.height;
+	scale = jpegdma_do_div((in_height * MSM_JPEGDMA_SCALE_UNI),
+		out_height);
+	if (scale < MSM_JPEGDMA_SCALE_UNI)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_set_config - Set dma configuration based on size.
+ *@dma: Pointer to dma device.
+ * @size_cfg: Size configuration.
+ * @plane_cfg: Calculated plane configuration.
+ */
+int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size_cfg,
+	struct msm_jpegdma_plane_config *plane_cfg)
+{
+	unsigned int in_offset;
+	unsigned int out_offset;
+	struct msm_jpegdma_size_config plane_size;
+	int ret;
+	int i;
+
+	if (!size_cfg->format.colplane_h || !size_cfg->format.colplane_v)
+		return -EINVAL;
+
+	ret = msm_jpegdma_hw_calc_speed(dma, size_cfg, &plane_cfg->speed);
+	if (ret < 0)
+		return -EINVAL;
+
+	dma->active_clock_rate = 0;
+
+	plane_cfg->plane[0].active_pipes = dma->hw_num_pipes;
+	plane_cfg->plane[0].type = size_cfg->format.planes[0];
+	msm_jpegdma_hw_calc_config(size_cfg, &plane_cfg->plane[0]);
+
+	in_offset = size_cfg->in_offset;
+	out_offset = size_cfg->out_offset;
+
+	msm_jpegdma_hw_add_plane_offset(&plane_cfg->plane[0],
+		in_offset, out_offset);
+
+	if (size_cfg->format.num_planes == 1)
+		return 0;
+
+	in_offset += (size_cfg->in_size.scanline *
+		size_cfg->in_size.stride);
+	out_offset += (size_cfg->out_size.scanline *
+		size_cfg->out_size.stride);
+
+	memset(&plane_size, 0x00, sizeof(plane_size));
+	for (i = 1; i < size_cfg->format.num_planes; i++) {
+		plane_cfg->plane[i].active_pipes = dma->hw_num_pipes;
+		plane_cfg->plane[i].type = size_cfg->format.planes[i];
+
+		if (size_cfg->in_size.top)
+			plane_size.in_size.top = size_cfg->in_size.top /
+				size_cfg->format.colplane_v;
+
+		if (size_cfg->in_size.left)
+			plane_size.in_size.left = size_cfg->in_size.left /
+				size_cfg->format.colplane_h;
+
+		plane_size.in_size.width = size_cfg->in_size.width /
+			size_cfg->format.colplane_h;
+		plane_size.in_size.height = size_cfg->in_size.height /
+			size_cfg->format.colplane_v;
+		plane_size.in_size.scanline = size_cfg->in_size.scanline /
+			size_cfg->format.colplane_v;
+
+		plane_size.in_size.stride = size_cfg->in_size.stride;
+
+		plane_size.out_size.width = size_cfg->out_size.width /
+			size_cfg->format.colplane_h;
+		plane_size.out_size.height = size_cfg->out_size.height /
+			size_cfg->format.colplane_v;
+		plane_size.out_size.scanline = size_cfg->out_size.scanline /
+			size_cfg->format.colplane_v;
+
+		plane_size.out_size.stride = size_cfg->out_size.stride;
+
+		plane_size.format = size_cfg->format;
+		plane_size.fps = size_cfg->fps;
+
+		msm_jpegdma_hw_calc_config(&plane_size,
+			&plane_cfg->plane[i]);
+
+		msm_jpegdma_hw_add_plane_offset(&plane_cfg->plane[i],
+			in_offset, out_offset);
+
+		in_offset += (plane_size.in_size.scanline *
+			plane_size.in_size.stride);
+		out_offset += (plane_size.out_size.scanline *
+			plane_size.out_size.stride);
+	}
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_start - Start dma processing.
+ *@dma: Pointer to dma device.
+ * @addr: Input address.
+ * @plane: Plane configuration.
+ * @speed: Clock and bus bandwidth configuration.
+ */
+int msm_jpegdma_hw_start(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_addr *addr,
+	struct msm_jpegdma_plane *plane,
+	struct msm_jpegdma_speed *speed)
+{
+	struct msm_jpegdma_config *cfg;
+	struct msm_jpegdma_addr prefetch_max_addr;
+	unsigned int prefetch_in_size;
+	unsigned int prefetch_out_size;
+
+	int ret;
+
+	if (!plane->active_pipes)
+		return -EINVAL;
+
+	if (plane->active_pipes > MSM_JPEGDMA_MAX_PIPES)
+		return -EINVAL;
+	ret = msm_jpegdma_hw_set_speed(dma, &plane->config[0].size_cfg, speed);
+	if (ret < 0)
+		return -EINVAL;
+
+	msm_jpegdma_hw_core_config(dma, plane->active_pipes,
+		plane->config[0].scale_cfg.enable,
+		plane->config[1].scale_cfg.enable);
+
+	cfg = &plane->config[0];
+	msm_jpegdma_hw_scale_0_config(dma, &cfg->scale_cfg);
+
+	msm_jpegdma_hw_fe_0_block(dma, &cfg->block_cfg, plane->type);
+	msm_jpegdma_hw_fe_0_phase(dma, cfg->phase);
+	msm_jpegdma_hw_fe_0_size(dma, &cfg->size_cfg.in_size, plane->type);
+	msm_jpegdma_hw_fe_0_addr(dma, addr->in_addr + cfg->in_offset);
+	prefetch_in_size = cfg->size_cfg.in_size.stride *
+		cfg->size_cfg.in_size.scanline;
+
+	msm_jpegdma_hw_we_0_block(dma, &cfg->block_cfg, plane->type);
+	msm_jpegdma_hw_we_0_size(dma, &cfg->size_cfg.out_size);
+	msm_jpegdma_hw_we_0_addr(dma, addr->out_addr + cfg->out_offset);
+	prefetch_out_size = cfg->size_cfg.out_size.stride *
+		cfg->size_cfg.out_size.scanline;
+
+	if (plane->active_pipes > 1) {
+		cfg = &plane->config[1];
+		msm_jpegdma_hw_scale_1_config(dma, &cfg->scale_cfg);
+
+		msm_jpegdma_hw_fe_1_block(dma, &cfg->block_cfg, plane->type);
+		msm_jpegdma_hw_fe_1_phase(dma, cfg->phase);
+		msm_jpegdma_hw_fe_1_size(dma, &cfg->size_cfg.in_size,
+			plane->type);
+		msm_jpegdma_hw_fe_1_addr(dma, addr->in_addr + cfg->in_offset);
+		prefetch_in_size += (cfg->size_cfg.in_size.stride *
+			cfg->size_cfg.in_size.scanline);
+
+		msm_jpegdma_hw_we_1_block(dma, &cfg->block_cfg, plane->type);
+		msm_jpegdma_hw_we_1_size(dma, &cfg->size_cfg.out_size);
+		msm_jpegdma_hw_we_1_addr(dma, addr->out_addr + cfg->out_offset);
+		prefetch_out_size += (cfg->size_cfg.out_size.stride *
+			cfg->size_cfg.out_size.scanline);
+	}
+
+	if (prefetch_in_size > 0 && prefetch_out_size > 0) {
+		prefetch_max_addr.in_addr = addr->in_addr +
+			(prefetch_in_size - 1);
+		prefetch_max_addr.out_addr = addr->out_addr +
+			(prefetch_out_size - 1);
+		msm_jpegdma_hw_config_mmu_prefetch(dma, addr,
+			&prefetch_max_addr);
+	}
+
+	msm_jpegdma_hw_run(dma);
+
+	return 1;
+}
+
+/*
+ * msm_jpegdma_hw_abort - abort dma processing.
+ *@dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_abort(struct msm_jpegdma_device *dma)
+{
+	int ret;
+
+	ret = msm_jpegdma_hw_halt(dma);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail to halt hw\n");
+		return ret;
+	}
+
+	ret = msm_jpegdma_hw_reset(dma);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail to reset hw\n");
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * msm_jpegdma_hw_irq - Dma irq handler.
+ * @irq: Irq number.
+ * @dev_id: Pointer to dma device.
+ */
+static irqreturn_t msm_jpegdma_hw_irq(int irq, void *dev_id)
+{
+	struct msm_jpegdma_device *dma = dev_id;
+
+	u32 irq_status;
+
+	irq_status = msm_jpegdma_hw_get_irq_status(dma);
+	msm_jpegdma_hw_clear_irq(dma, irq_status);
+
+	if (irq_status & MSM_JPEGDMA_IRQ_STATUS_RST_DONE) {
+		dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ reset done\n");
+		complete_all(&dma->hw_reset_completion);
+	}
+
+	if (irq_status & MSM_JPEGDMA_IRQ_STATUS_AXI_HALT) {
+		dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ AXI halt\n");
+		complete_all(&dma->hw_halt_completion);
+	}
+
+	if (irq_status & MSM_JPEGDMA_IRQ_STATUS_SESSION_DONE) {
+		dev_dbg(dma->dev, "Jpeg v4l2 dma IRQ session done\n");
+		msm_jpegdma_isr_processing_done(dma);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * msm_jpegdma_hw_request_irq - Request dma irq.
+ * @pdev: Pointer to platform device.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_request_irq(struct platform_device *pdev,
+	struct msm_jpegdma_device *dma)
+{
+	int ret;
+
+	dma->irq_num = platform_get_irq(pdev, 0);
+	if (dma->irq_num < 0) {
+		dev_err(dma->dev, "Can not get dma core irq resource\n");
+		ret = -ENODEV;
+		goto error_irq;
+	}
+
+	ret = request_threaded_irq(dma->irq_num, NULL,
+		msm_jpegdma_hw_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+		dev_name(&pdev->dev), dma);
+	if (ret) {
+		dev_err(dma->dev, "Can not claim wrapper IRQ %d\n",
+			dma->irq_num);
+		goto error_irq;
+	}
+
+	return 0;
+
+error_irq:
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_release_mem_resources - Releases memory resources.
+ * @dma: Pointer to dma device.
+ */
+void msm_jpegdma_hw_release_mem_resources(struct msm_jpegdma_device *dma)
+{
+	int i, reserve_mem_flag;
+	char *dev_name;
+
+	/* Prepare memory resources */
+	for (i = 0; i < MSM_JPEGDMA_IOMEM_LAST; i++) {
+
+		switch (i) {
+		case MSM_JPEGDMA_IOMEM_CORE:
+			dev_name = "jpeg_hw";
+			reserve_mem_flag = true;
+			break;
+		case MSM_JPEGDMA_IOMEM_VBIF:
+			dev_name = "jpeg_vbif";
+			reserve_mem_flag = false;
+			break;
+		default:
+			pr_err("%s: Invalid device : %d\n", __func__, i);
+			return;
+		}
+		/* release the device address */
+		msm_camera_put_reg_base(dma->pdev, dma->iomem_base[i], dev_name,
+			reserve_mem_flag);
+	}
+}
+
+/*
+ * msm_jpegdma_hw_get_mem_resources - Get memory resources.
+ * @pdev: Pointer to dma platform device.
+ * @dma: Pointer to dma device.
+ *
+ * Get and ioremap platform memory resources.
+ */
+int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev,
+	struct msm_jpegdma_device *dma)
+{
+	int i;
+	int ret = 0;
+	char *dev_name;
+	int reserve_mem_flag;
+
+	/* Prepare memory resources */
+	for (i = 0; i < MSM_JPEGDMA_IOMEM_LAST; i++) {
+
+		switch (i) {
+		case MSM_JPEGDMA_IOMEM_CORE:
+			dev_name = "jpeg_hw";
+			reserve_mem_flag = true;
+			break;
+		case MSM_JPEGDMA_IOMEM_VBIF:
+			dev_name = "jpeg_vbif";
+			reserve_mem_flag = false;
+			break;
+		default:
+			pr_err("%s: Invalid device : %d\n", __func__, i);
+			return -EINVAL;
+		}
+		/* get the device address base */
+		dma->iomem_base[i] =
+			msm_camera_get_reg_base(pdev, dev_name,
+				reserve_mem_flag);
+		if (!dma->iomem_base[i]) {
+			dev_err(dma->dev, "%s can not remap region\n",
+				dev_name);
+			ret = -ENODEV;
+			break;
+		}
+	}
+
+	if (ret < 0)
+		msm_jpegdma_hw_release_mem_resources(dma);
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_get_max_downscale - Get max downscale factor from dtsi.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma)
+{
+	int ret;
+	int max_ds_factor;
+
+	ret = of_property_read_u32(dma->dev->of_node,
+		"qcom,max-ds-factor", &max_ds_factor);
+	if (ret < 0) {
+		dev_err(dma->dev, "cannot read qcom,max-ds-factor from dtsi\n");
+		return ret;
+	}
+	dev_dbg(dma->dev, "max_ds_factor is %d\n", max_ds_factor);
+	return max_ds_factor;
+}
+
+/*
+ * msm_jpegdma_hw_get_qos - Get dma qos settings from device-tree.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma)
+{
+	int i, j;
+	int ret;
+	unsigned int cnt;
+	const void *property;
+
+	property = of_get_property(dma->dev->of_node,
+		"qcom,qos-reg-settings", &cnt);
+	if (!property || !cnt) {
+		dev_dbg(dma->dev, "Missing qos settings\n");
+		return 0;
+	}
+
+	cnt /= 4;
+	if (cnt % 2)
+		return -EINVAL;
+
+	dma->qos_regs_num = cnt / 2;
+
+	dma->qos_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) *
+		dma->qos_regs_num), GFP_KERNEL);
+	if (!dma->qos_regs)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < cnt; i += 2, j++) {
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,qos-reg-settings", i,
+			&dma->qos_regs[j].reg);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read qos reg %d\n", j);
+			goto error;
+		}
+
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,qos-reg-settings", i + 1,
+			&dma->qos_regs[j].val);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read qos setting %d\n", j);
+			goto error;
+		}
+		dev_dbg(dma->dev, "Qos idx %d, reg %x val %x\n", j,
+			dma->qos_regs[j].reg, dma->qos_regs[j].val);
+	}
+
+	return 0;
+error:
+	kfree(dma->qos_regs);
+	dma->qos_regs = NULL;
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_put_qos - Free dma qos settings.
+ * @dma: Pointer to dma device.
+ */
+void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma)
+{
+	kfree(dma->qos_regs);
+	dma->qos_regs = NULL;
+}
+
+/*
+ * msm_jpegdma_hw_get_vbif - Get dma vbif settings from device-tree.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma)
+{
+	int i, j;
+	int ret;
+	unsigned int cnt;
+	const void *property;
+
+	property = of_get_property(dma->dev->of_node, "qcom,vbif-reg-settings",
+		&cnt);
+	if (!property || !cnt) {
+		dev_dbg(dma->dev, "Missing vbif settings\n");
+		return 0;
+	}
+
+	cnt /= 4;
+	if (cnt % 2)
+		return -EINVAL;
+
+	dma->vbif_regs_num = cnt / 2;
+
+	dma->vbif_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) *
+		dma->vbif_regs_num), GFP_KERNEL);
+	if (!dma->vbif_regs)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < cnt; i += 2, j++) {
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,vbif-reg-settings", i,
+			&dma->vbif_regs[j].reg);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read vbif reg %d\n", j);
+			goto error;
+		}
+
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,vbif-reg-settings", i + 1,
+			&dma->vbif_regs[j].val);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read vbif setting %d\n", j);
+			goto error;
+		}
+
+		dev_dbg(dma->dev, "Vbif idx %d, reg %x val %x\n", j,
+			dma->vbif_regs[j].reg, dma->vbif_regs[j].val);
+	}
+
+	return 0;
+error:
+	kfree(dma->vbif_regs);
+	dma->vbif_regs = NULL;
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_put_vbif - Put dma clocks.
+ * @dma: Pointer to dma device.
+ */
+void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma)
+{
+	kfree(dma->vbif_regs);
+	dma->vbif_regs = NULL;
+}
+
+/*
+ * msm_jpegdma_hw_get_prefetch - Get dma prefetch settings from device-tree.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma)
+{
+	int i, j;
+	int ret;
+	unsigned int cnt;
+	const void *property;
+
+	property = of_get_property(dma->dev->of_node,
+		"qcom,prefetch-reg-settings", &cnt);
+	if (!property || !cnt) {
+		dev_dbg(dma->dev, "Missing prefetch settings\n");
+		return 0;
+	}
+
+	cnt /= 4;
+	if (cnt % 2)
+		return -EINVAL;
+
+	dma->prefetch_regs_num = cnt / 2;
+
+	dma->prefetch_regs = kzalloc((sizeof(struct jpegdma_reg_cfg) *
+		dma->prefetch_regs_num), GFP_KERNEL);
+	if (!dma->prefetch_regs)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < cnt; i += 2, j++) {
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,prefetch-reg-settings", i,
+			&dma->prefetch_regs[j].reg);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read prefetch reg %d\n", j);
+			goto error;
+		}
+
+		ret = of_property_read_u32_index(dma->dev->of_node,
+			"qcom,prefetch-reg-settings", i + 1,
+			&dma->prefetch_regs[j].val);
+		if (ret < 0) {
+			dev_err(dma->dev, "can not read prefetch setting %d\n",
+				j);
+			goto error;
+		}
+
+		dev_dbg(dma->dev, "Prefetch idx %d, reg %x val %x\n", j,
+			dma->prefetch_regs[j].reg, dma->prefetch_regs[j].val);
+	}
+
+	return 0;
+error:
+	kfree(dma->prefetch_regs);
+	dma->prefetch_regs = NULL;
+
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_put_prefetch - free prefetch settings.
+ * @dma: Pointer to dma device.
+ */
+void msm_jpegdma_hw_put_prefetch(struct msm_jpegdma_device *dma)
+{
+	kfree(dma->prefetch_regs);
+	dma->prefetch_regs = NULL;
+}
+
+/*
+ * msm_jpegdma_hw_get_capabilities - Get dma hw for performing any hw operation.
+ * @dma: Pointer to dma device.
+ */
+int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma)
+{
+	int ret = 0;
+
+	mutex_lock(&dma->lock);
+
+	/* enable all the regulators */
+	ret = msm_camera_regulator_enable(dma->dma_vdd,
+			dma->num_reg, true);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail to enable regulators\n");
+		goto error_regulators_get;
+	}
+
+	/* enable all the clocks */
+	ret = msm_camera_clk_enable(&dma->pdev->dev,
+			dma->jpeg_clk_info, dma->clk,
+			dma->num_clk, true);
+	if (ret < 0) {
+		dev_err(dma->dev, "Fail to enable clocks\n");
+		goto error_clocks;
+	}
+
+	dma->hw_num_pipes = msm_jpegdma_hw_get_num_pipes(dma);
+
+	/* disable all the clocks */
+	msm_camera_clk_enable(&dma->pdev->dev,
+		dma->jpeg_clk_info, dma->clk,
+		dma->num_clk, false);
+	/* disable all the regulators */
+	msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false);
+
+	mutex_unlock(&dma->lock);
+
+	return 0;
+
+error_clocks:
+	msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false);
+error_regulators_get:
+	mutex_unlock(&dma->lock);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_get - Get dma hw for performing any hw operation.
+ * @dma: Pointer to dma device.
+ * @clock_rate_idx: Clock rate index.
+ *
+ * Prepare dma hw for operation. Have reference count protected by
+ * dma device mutex.
+ */
+int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma)
+{
+	int ret;
+
+	mutex_lock(&dma->lock);
+	if (dma->ref_count == 0) {
+
+		dev_dbg(dma->dev, "msm_jpegdma_hw_get E\n");
+		/* enable all the regulators */
+		ret = msm_camera_regulator_enable(dma->dma_vdd,
+				dma->num_reg, true);
+		if (ret < 0) {
+			dev_err(dma->dev, "Fail to enable regulators\n");
+			goto error_regulators_get;
+		}
+
+		/* enable all the clocks */
+		ret = msm_camera_clk_enable(&dma->pdev->dev,
+			dma->jpeg_clk_info, dma->clk,
+			dma->num_clk, true);
+		if (ret < 0) {
+			dev_err(dma->dev, "Fail to enable clocks\n");
+			goto error_clocks;
+		}
+
+		/* update the bus vector with valid bw */
+		msm_camera_update_bus_vector(dma->bus_client, 1);
+		msm_jpegdma_hw_config_qos(dma);
+		msm_jpegdma_hw_config_vbif(dma);
+
+		msm_camera_register_threaded_irq(dma->pdev, dma->irq, NULL,
+			msm_jpegdma_hw_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+			dev_name(&dma->pdev->dev), dma);
+		msm_jpegdma_hw_enable_irq(dma);
+
+		ret = msm_jpegdma_hw_reset(dma);
+		if (ret < 0) {
+			dev_err(dma->dev, "Fail to reset hw\n");
+			goto error_hw_reset;
+		}
+		msm_jpegdma_hw_config_qos(dma);
+		msm_jpegdma_hw_config_mmu_prefetch(dma, NULL, NULL);
+		msm_jpegdma_hw_enable_irq(dma);
+	}
+	dma->ref_count++;
+	dev_dbg(dma->dev, "msm_jpegdma_hw_get X\n");
+	mutex_unlock(&dma->lock);
+
+	return 0;
+
+error_hw_reset:
+	msm_jpegdma_hw_disable_irq(dma);
+	msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info,
+		dma->clk, dma->num_clk, false);
+error_clocks:
+	msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false);
+error_regulators_get:
+	mutex_unlock(&dma->lock);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_put - Put dma hw.
+ * @dma: Pointer to dma device.
+ *
+ * Release dma hw. Have reference count protected by
+ * dma device mutex.
+ */
+void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma)
+{
+	mutex_lock(&dma->lock);
+
+	if (WARN_ON(!dma->ref_count))
+		goto err;
+
+	if (--dma->ref_count == 0) {
+		msm_jpegdma_hw_halt(dma);
+		msm_jpegdma_hw_disable_irq(dma);
+		/* release the irq */
+		msm_camera_unregister_irq(dma->pdev,
+			dma->irq, dma);
+		/* update the bus vector with zeroth vector */
+		msm_camera_update_bus_vector(dma->bus_client, 0);
+		/* disable all the clocks */
+		msm_camera_clk_enable(&dma->pdev->dev, dma->jpeg_clk_info,
+			dma->clk, dma->num_clk, false);
+		/* disable all the regulators */
+		msm_camera_regulator_enable(dma->dma_vdd, dma->num_reg, false);
+	}
+	/* Reset clock rate, need to be updated on next processing */
+	dma->active_clock_rate = -1;
+err:
+	mutex_unlock(&dma->lock);
+}
+
+/*
+ * msm_jpegdma_hw_attach_iommu - Attach iommu to jpeg dma engine.
+ * @dma: Pointer to dma device.
+ *
+ * Iommu attach have reference count protected by
+ * dma device mutex.
+ */
+static int msm_jpegdma_hw_attach_iommu(struct msm_jpegdma_device *dma)
+{
+	int ret = -EINVAL;
+
+	mutex_lock(&dma->lock);
+
+	if (dma->iommu_attached_cnt == UINT_MAX) {
+		dev_err(dma->dev, "Max count reached! can not attach iommu\n");
+		goto error;
+	}
+
+	if (dma->iommu_attached_cnt == 0) {
+		ret = cam_smmu_get_handle(MSM_JPEGDMA_SMMU_NAME,
+			&dma->iommu_hndl);
+		if (ret < 0) {
+			dev_err(dma->dev, "Smmu get handle failed\n");
+			ret = -ENOMEM;
+			goto error;
+		}
+		ret = cam_smmu_ops(dma->iommu_hndl, CAM_SMMU_ATTACH);
+		if (ret < 0) {
+			dev_err(dma->dev, "Can not attach smmu.\n");
+			goto error_attach;
+		}
+	}
+	dma->iommu_attached_cnt++;
+	mutex_unlock(&dma->lock);
+
+	return 0;
+error_attach:
+	cam_smmu_destroy_handle(dma->iommu_hndl);
+error:
+	mutex_unlock(&dma->lock);
+	return ret;
+}
+
+/*
+ * msm_jpegdma_hw_detach_iommu - Detach iommu from jpeg dma engine.
+ * @dma: Pointer to dma device.
+ *
+ * Iommu detach have reference count protected by
+ * dma device mutex.
+ */
+static void msm_jpegdma_hw_detach_iommu(struct msm_jpegdma_device *dma)
+{
+	mutex_lock(&dma->lock);
+
+	if (dma->iommu_attached_cnt == 0) {
+		dev_err(dma->dev, "There is no attached device\n");
+		mutex_unlock(&dma->lock);
+		return;
+	}
+
+	if (--dma->iommu_attached_cnt == 0) {
+		cam_smmu_ops(dma->iommu_hndl, CAM_SMMU_DETACH);
+		cam_smmu_destroy_handle(dma->iommu_hndl);
+	}
+
+	mutex_unlock(&dma->lock);
+}
+
+/*
+ * msm_jpegdma_hw_map_buffer - Map buffer to dma hw mmu.
+ * @dma: Pointer to dma device.
+ * @fd: Ion fd.
+ * @buf: dma buffer handle, for storing mapped buffer information.
+ *
+ * It will map ion fd to dma hw smmu.
+ */
+int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd,
+	struct msm_jpegdma_buf_handle *buf)
+{
+	int ret;
+
+	if (!dma || fd < 0)
+		return -EINVAL;
+
+	ret = msm_jpegdma_hw_attach_iommu(dma);
+	if (ret < 0)
+		goto error;
+
+	buf->dma = dma;
+	buf->fd = fd;
+
+	ret = cam_smmu_get_phy_addr(dma->iommu_hndl, buf->fd,
+		CAM_SMMU_MAP_RW, &buf->addr, (size_t *)&buf->size);
+	if (ret < 0) {
+		dev_err(dma->dev, "Can not get physical address\n");
+		goto error_get_phy;
+	}
+
+	return buf->size;
+
+error_get_phy:
+	msm_jpegdma_hw_detach_iommu(dma);
+error:
+	return -ENOMEM;
+}
+
+/*
+ * msm_jpegdma_hw_unmap_buffer - Unmap buffer from dma hw mmu.
+ * @buf: dma buffer handle, for storing mapped buffer information.
+ */
+void msm_jpegdma_hw_unmap_buffer(struct msm_jpegdma_buf_handle *buf)
+{
+	if (buf->size && buf->dma) {
+		cam_smmu_put_phy_addr(buf->dma->iommu_hndl,
+			buf->fd);
+		msm_jpegdma_hw_detach_iommu(buf->dma);
+		buf->size = 0;
+	}
+	buf->fd = -1;
+	buf->dma = NULL;
+}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h
new file mode 100644
index 0000000..29dbb90
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_hw.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_JPEG_DMA_HW_H__
+#define __MSM_JPEG_DMA_HW_H__
+
+#include "msm_jpeg_dma_dev.h"
+
+int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size_cfg);
+
+int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_size_config *size_cfg,
+	struct msm_jpegdma_plane_config *plane_cfg);
+
+int msm_jpegdma_hw_start(struct msm_jpegdma_device *dma,
+	struct msm_jpegdma_addr *addr,
+	struct msm_jpegdma_plane *plane,
+	struct msm_jpegdma_speed *speed);
+
+int msm_jpegdma_hw_abort(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_update_bus_data(struct msm_jpegdma_device *dma,
+	u64 ab, u64 ib);
+
+int msm_jpegdma_hw_handle_irq(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_request_irq(struct platform_device *pdev,
+	struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_release_irq(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_release_mem_resources(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev,
+	struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_regulators(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_put_regulators(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_clocks(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_put_clocks(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_max_downscale(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_put_prefetch(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma);
+
+void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma);
+
+int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd,
+	struct msm_jpegdma_buf_handle *buf);
+
+void msm_jpegdma_hw_unmap_buffer(struct msm_jpegdma_buf_handle *buf);
+
+#endif /* __MSM_JPEG_DMA_HW_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_regs.h b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_regs.h
new file mode 100644
index 0000000..157c743
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_regs.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_JPEGDMA_REGS_H__
+#define __MSM_JPEGDMA_REGS_H__
+
+#define MSM_JPEGDMA_HW_REVISION                  0x00
+#define MSM_JPEGDMA_HW_CAPABILITY                0x04
+#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_BMSK 0x06
+#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_SHFT 0x01
+
+#define MSM_JPEGDMA_IRQ_MASK_ADDR         0x0C
+#define MSM_JPEGDMA_IRQ_MASK_SESSION_DONE (1 << 0)
+#define MSM_JPEGDMA_IRQ_MASK_RD_BUF_DONE  (1 << 1)
+#define MSM_JPEGDMA_IRQ_MASK_WR_BUF_DONE  (1 << 5)
+#define MSM_JPEGDMA_IRQ_MASK_AXI_HALT     (1 << 9)
+#define MSM_JPEGDMA_IRQ_MASK_RST_DONE     (1 << 10)
+
+#define MSM_JPEGDMA_IRQ_STATUS              0x10
+#define MSM_JPEGDMA_IRQ_STATUS_SESSION_DONE (1 << 0)
+#define MSM_JPEGDMA_IRQ_STATUS_RD_BUF_DONE  (1 << 1)
+#define MSM_JPEGDMA_IRQ_STATUS_WR_BUF_DONE  (1 << 5)
+#define MSM_JPEGDMA_IRQ_STATUS_AXI_HALT     (1 << 9)
+#define MSM_JPEGDMA_IRQ_STATUS_RST_DONE     (1 << 10)
+
+#define MSM_JPEGDMA_IRQ_CLEAR_ADDR 0x14
+#define MSM_JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF
+
+#define MSM_JPEGDMA_CORE_CFG_ADDR  0x18
+#define MSM_JPEGDMA_CMD_ADDR       0x1C
+
+#define MSM_JPEGDMA_CORE_CFG_TEST_BUS_ENABLE_SHFT  19
+#define MSM_JPEGDMA_CORE_CFG_BRIDGE_ENABLE_SHFT    6
+#define MSM_JPEGDMA_CORE_CFG_SCALE_1_ENABLE_SHFT   5
+#define MSM_JPEGDMA_CORE_CFG_SCALE_0_ENABLE_SHFT   4
+
+#define MSM_JPEGDMA_CORE_CFG_WE_1_ENABLE_SHFT 0x03
+#define MSM_JPEGDMA_CORE_CFG_WE_0_ENABLE_SHFT 0x02
+#define MSM_JPEGDMA_CORE_CFG_FE_1_ENABLE_SHFT 0x01
+#define MSM_JPEGDMA_CORE_CFG_FE_0_ENABLE_SHFT 0x00
+
+#define MSM_JPEGDMA_FE_0_CFG_ADDR                0x2C
+#define MSM_JPEGDMA_FE_1_CFG_ADDR                0x70
+#define MSM_JPEGDMA_FE_CFG_MAL_BOUNDARY_SHFT     25
+#define MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT           21
+#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR   0x03
+#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR     0x02
+#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB     0x01
+#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y      0x00
+#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT   19
+#define MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT      0x04
+#define MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT 0x00
+
+#define MSM_JPEGDMA_FE_RD_0_PNTR_ADDR               0x34
+#define MSM_JPEGDMA_FE_RD_1_PNTR_ADDR               0x78
+#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_0_ADDR        0x44
+#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_1_ADDR        0x88
+#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT   16
+#define MSM_JPEGDMA_FE_RD_0_STRIDE_ADDR             0x48
+#define MSM_JPEGDMA_FE_RD_1_STRIDE_ADDR             0x8C
+#define MSM_JPEGDMA_FE_RD_0_HINIT_ADDR              0x4C
+#define MSM_JPEGDMA_FE_RD_1_HINIT_ADDR              0x90
+#define MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR          0x50
+#define MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR          0x94
+#define MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR          0x58
+#define MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR          0x9C
+
+#define MSM_JPEGDMA_WE_CFG_ADDR                          0xB8
+#define MSM_JPEGDMA_WE_CFG_MAL_BOUNDARY_SHFT             0x08
+#define MSM_JPEGDMA_WE_CFG_MAL_EN_SHFT                   0x07
+#define MSM_JPEGDMA_WE_CFG_BURST_LENGTH_MAX_SHFT         0x00
+#define MSM_JPEGDMA_WE_PLN_0_WR_PNTR_ADDR                0xBC
+#define MSM_JPEGDMA_WE_PLN_1_WR_PNTR_ADDR                0xEC
+#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_0_ADDR         0xC4
+#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_1_ADDR         0xF4
+#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT    16
+#define MSM_JPEGDMA_WE_PLN_0_WR_STRIDE_ADDR              0xC8
+#define MSM_JPEGDMA_WE_PLN_1_WR_STRIDE_ADDR              0xF8
+#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_0_ADDR               0xCC
+#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_0_ADDR               0xFC
+#define MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT  16
+#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_1_ADDR               0xD0
+#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_1_ADDR               0x100
+#define MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT     16
+#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_2_ADDR               0xD4
+#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_2_ADDR               0x104
+#define MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT     16
+#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_3_ADDR               0xD8
+#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_3_ADDR               0x108
+
+#define MSM_JPEGDMA_PP_0_SCALE_PHASEV_STEP_ADDR       0x19C
+#define MSM_JPEGDMA_PP_1_SCALE_PHASEV_STEP_ADDR       0x1BC
+#define MSM_JPEGDMA_PP_0_SCALE_PHASEH_STEP_ADDR       0x194
+#define MSM_JPEGDMA_PP_1_SCALE_PHASEH_STEP_ADDR       0x1B4
+#define MSM_JPEGDMA_PP_0_SCALE_CFG_ADDR               0x188
+#define MSM_JPEGDMA_PP_1_SCALE_CFG_ADDR               0x1A8
+#define MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT   0x05
+#define MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT   0x04
+
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN                0x190
+#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX                0x198
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN                0x1A4
+#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX                0x1AC
+
+#define MSM_JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES         0x030
+#define MSM_JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES        0x300
+
+#define MSM_HW_JPEGDMA_RESET                          0x08
+#define MSM_HW_JPEGDMA_RESET_DEFAULT                  0x32083
+
+#define MSM_JPEGDMA_RESET_CMD_BMSK                    0xFFFFFFFF
+
+#endif /* __MSM_JPEG_DMA_REGS_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
new file mode 100644
index 0000000..d52d8bc
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -0,0 +1,1486 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/atomic.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <media/v4l2-fh.h>
+#include "msm.h"
+#include "msm_vb2.h"
+#include "msm_sd.h"
+#include "cam_hw_ops.h"
+#include <media/msmb_generic_buf_mgr.h>
+
+static struct v4l2_device *msm_v4l2_dev;
+static struct list_head    ordered_sd_list;
+static struct mutex        ordered_sd_mtx;
+static struct mutex        v4l2_event_mtx;
+
+static struct pm_qos_request msm_v4l2_pm_qos_request;
+
+static struct msm_queue_head *msm_session_q;
+
+/* This variable represent daemon status
+ * true = daemon present (default state)
+ * false = daemon is NOT present
+ */
+bool is_daemon_status = true;
+
+/* config node envent queue */
+static struct v4l2_fh  *msm_eventq;
+static spinlock_t msm_eventq_lock;
+
+static struct pid *msm_pid;
+static spinlock_t msm_pid_lock;
+
+static uint32_t gpu_limit;
+
+/*
+ * It takes 20 bytes + NULL character to write the
+ * largest decimal value of an uint64_t
+ */
+#define LOGSYNC_PACKET_SIZE 21
+
+#define msm_dequeue(queue, type, member) ({				\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		__q->len--;					\
+		node = list_first_entry(&__q->list,		\
+				type, member);	\
+		if ((node) && (&node->member) && (&node->member.next))	\
+			list_del_init(&node->member);			\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);	\
+	node;							\
+})
+
+#define msm_delete_sd_entry(queue, type, member, q_node) ({		\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		list_for_each_entry(node, &__q->list, member)	\
+		if (node->sd == q_node) {				\
+			__q->len--;				\
+			list_del_init(&node->member);		\
+			kzfree(node);				\
+			break;					\
+		}						\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+})
+
+#define msm_delete_entry(queue, type, member, q_node) ({		\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) {				\
+		list_for_each_entry(node, &__q->list, member)	\
+		if (node == q_node) {				\
+			__q->len--;				\
+			list_del_init(&node->member);		\
+			kzfree(node);				\
+			break;					\
+		}						\
+	}							\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+})
+
+#define msm_queue_drain(queue, type, member) do {			\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL;				\
+	spin_lock_irqsave(&__q->lock, flags);			\
+	while (!list_empty(&__q->list)) {			\
+		__q->len--;					\
+		node = list_first_entry(&__q->list,		\
+			type, member);		\
+		if (node) {					\
+			if (&node->member) \
+				list_del_init(&node->member);		\
+			kzfree(node);	\
+		}	\
+	}	\
+	spin_unlock_irqrestore(&__q->lock, flags);		\
+} while (0)
+
+typedef int (*msm_queue_func)(void *d1, void *d2);
+#define msm_queue_traverse_action(queue, type, member, func, data) do {\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL; \
+	msm_queue_func __f = (func); \
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) { \
+		list_for_each_entry(node, &__q->list, member) \
+		if (node && __f)  { \
+			__f(node, data); \
+	  } \
+	} \
+	spin_unlock_irqrestore(&__q->lock, flags);			\
+} while (0)
+
+typedef int (*msm_queue_find_func)(void *d1, void *d2);
+#define msm_queue_find(queue, type, member, func, data) ({\
+	unsigned long flags;					\
+	struct msm_queue_head *__q = (queue);			\
+	type *node = NULL; \
+	typeof(node) __ret = NULL; \
+	msm_queue_find_func __f = (func); \
+	spin_lock_irqsave(&__q->lock, flags);			\
+	if (!list_empty(&__q->list)) { \
+		list_for_each_entry(node, &__q->list, member) \
+		if ((__f) && __f(node, data)) { \
+			__ret = node; \
+			break; \
+		} \
+	} \
+	spin_unlock_irqrestore(&__q->lock, flags); \
+	__ret; \
+})
+
+static void msm_init_queue(struct msm_queue_head *qhead)
+{
+	if (WARN_ON(!qhead))
+		return;
+
+	INIT_LIST_HEAD(&qhead->list);
+	spin_lock_init(&qhead->lock);
+	qhead->len = 0;
+	qhead->max = 0;
+}
+
+static void msm_enqueue(struct msm_queue_head *qhead,
+		struct list_head *entry)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qhead->lock, flags);
+	qhead->len++;
+	if (qhead->len > qhead->max)
+		qhead->max = qhead->len;
+	list_add_tail(entry, &qhead->list);
+	spin_unlock_irqrestore(&qhead->lock, flags);
+}
+
+void msm_cam_copy_v4l2_subdev_fops(struct v4l2_file_operations *d1)
+{
+	*d1 = v4l2_subdev_fops;
+}
+EXPORT_SYMBOL(msm_cam_copy_v4l2_subdev_fops);
+
+static const struct v4l2_file_operations *msm_cam_get_v4l2_subdev_fops_ptr(
+	void)
+{
+	return &v4l2_subdev_fops;
+}
+
+/* index = session id */
+static inline int __msm_queue_find_session(void *d1, void *d2)
+{
+	struct msm_session *session = d1;
+
+	return (session->session_id == *(unsigned int *)d2) ? 1 : 0;
+}
+
+static inline int __msm_queue_find_stream(void *d1, void *d2)
+{
+	struct msm_stream *stream = d1;
+
+	return (stream->stream_id == *(unsigned int *)d2) ? 1 : 0;
+}
+
+static inline int __msm_queue_find_command_ack_q(void *d1, void *d2)
+{
+	struct msm_command_ack *ack = d1;
+
+	return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0;
+}
+
+static void msm_pm_qos_add_request(void)
+{
+	pr_info("%s: add request", __func__);
+	pm_qos_add_request(&msm_v4l2_pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
+	PM_QOS_DEFAULT_VALUE);
+}
+
+static void msm_pm_qos_remove_request(void)
+{
+	pr_info("%s: remove request", __func__);
+	pm_qos_remove_request(&msm_v4l2_pm_qos_request);
+}
+
+void msm_pm_qos_update_request(int val)
+{
+	pr_info("%s: update request %d", __func__, val);
+	pm_qos_update_request(&msm_v4l2_pm_qos_request, val);
+}
+
+struct msm_session *msm_session_find(unsigned int session_id)
+{
+	struct msm_session *session;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (WARN_ON(!session))
+		return NULL;
+	return session;
+}
+EXPORT_SYMBOL(msm_session_find);
+
+int msm_create_stream(unsigned int session_id,
+	unsigned int stream_id, struct vb2_queue *q)
+{
+	struct msm_session *session;
+	struct msm_stream  *stream;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session)
+		return -EINVAL;
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream)
+		return -ENOMEM;
+
+	stream->stream_id = stream_id;
+	stream->vb2_q = q;
+	spin_lock_init(&stream->stream_lock);
+	msm_enqueue(&session->stream_q, &stream->list);
+	session->stream_q.len++;
+
+	INIT_LIST_HEAD(&stream->queued_list);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_create_stream);
+
+void msm_delete_stream(unsigned int session_id, unsigned int stream_id)
+{
+	struct msm_session *session = NULL;
+	struct msm_stream  *stream = NULL;
+	unsigned long flags;
+	int try_count = 0;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+
+	if (!session)
+		return;
+
+	while (1) {
+		unsigned long wl_flags;
+
+		if (try_count > 5) {
+			pr_err("%s : not able to delete stream %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		write_lock_irqsave(&session->stream_rwlock, wl_flags);
+		try_count++;
+		stream = msm_queue_find(&session->stream_q, struct msm_stream,
+			list, __msm_queue_find_stream, &stream_id);
+
+		if (!stream) {
+			write_unlock_irqrestore(&session->stream_rwlock,
+				wl_flags);
+			return;
+		}
+
+		if (msm_vb2_get_stream_state(stream) != 1) {
+			write_unlock_irqrestore(&session->stream_rwlock,
+				wl_flags);
+			continue;
+		}
+
+		spin_lock_irqsave(&(session->stream_q.lock), flags);
+		list_del_init(&stream->list);
+		session->stream_q.len--;
+		kfree(stream);
+		stream = NULL;
+		spin_unlock_irqrestore(&(session->stream_q.lock), flags);
+		write_unlock_irqrestore(&session->stream_rwlock, wl_flags);
+		break;
+	}
+
+}
+EXPORT_SYMBOL(msm_delete_stream);
+
+static void msm_sd_unregister_subdev(struct video_device *vdev)
+{
+	struct v4l2_subdev *sd = video_get_drvdata(vdev);
+
+	sd->devnode = NULL;
+	kzfree(vdev);
+}
+
+static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct video_device *vdev;
+
+	if (!msm_v4l2_dev || !sd || !sd->name[0])
+		return -EINVAL;
+
+	rc = v4l2_device_register_subdev(msm_v4l2_dev, sd);
+	if (rc < 0) {
+		pr_err("v4l2_device_register_subdev: failed for %s", sd->name);
+		WARN_ON(1);
+		return rc;
+	}
+
+	/* Register a device node for every subdev marked with the
+	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+	 */
+	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+		return rc;
+
+	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+	if (!vdev) {
+		rc = -ENOMEM;
+		goto clean_up;
+	}
+
+	video_set_drvdata(vdev, sd);
+	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+	vdev->v4l2_dev = msm_v4l2_dev;
+	vdev->fops = msm_cam_get_v4l2_subdev_fops_ptr();
+	vdev->release = msm_sd_unregister_subdev;
+	rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+		  sd->owner);
+	if (rc < 0) {
+		kzfree(vdev);
+		goto clean_up;
+	}
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.info.dev.major = VIDEO_MAJOR;
+	sd->entity.info.dev.minor = vdev->minor;
+	sd->entity.name = video_device_node_name(vdev);
+#endif
+	sd->devnode = vdev;
+	return 0;
+
+clean_up:
+	if (sd->devnode)
+		video_unregister_device(sd->devnode);
+	return rc;
+}
+
+static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev,
+	struct list_head *sd_list)
+{
+	struct msm_sd_subdev *temp_sd;
+
+	list_for_each_entry(temp_sd, sd_list, list) {
+		if (temp_sd == msm_subdev) {
+			pr_err("%s :Fail to add the same sd %d\n",
+				__func__, __LINE__);
+			return;
+		}
+		if (msm_subdev->close_seq < temp_sd->close_seq) {
+			list_add_tail(&msm_subdev->list, &temp_sd->list);
+			return;
+		}
+	}
+	list_add_tail(&msm_subdev->list, sd_list);
+}
+
+int msm_sd_register(struct msm_sd_subdev *msm_subdev)
+{
+	if (WARN_ON(!msm_subdev))
+		return -EINVAL;
+
+	if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
+		return -EIO;
+
+	mutex_lock(&ordered_sd_mtx);
+	msm_add_sd_in_position(msm_subdev, &ordered_sd_list);
+	mutex_unlock(&ordered_sd_mtx);
+	return __msm_sd_register_subdev(&msm_subdev->sd);
+}
+EXPORT_SYMBOL(msm_sd_register);
+
+int msm_sd_unregister(struct msm_sd_subdev *msm_subdev)
+{
+	if (WARN_ON(!msm_subdev))
+		return -EINVAL;
+
+	v4l2_device_unregister_subdev(&msm_subdev->sd);
+	return 0;
+}
+EXPORT_SYMBOL(msm_sd_unregister);
+
+static struct v4l2_subdev *msm_sd_find(const char *name)
+{
+	unsigned long flags;
+	struct v4l2_subdev *subdev = NULL;
+	struct v4l2_subdev *subdev_out = NULL;
+
+	spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
+	if (!list_empty(&msm_v4l2_dev->subdevs)) {
+		list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list)
+			if (!strcmp(name, subdev->name)) {
+				subdev_out = subdev;
+				break;
+			}
+	}
+	spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
+
+	return subdev_out;
+}
+
+int msm_create_session(unsigned int session_id, struct video_device *vdev)
+{
+	struct msm_session *session = NULL;
+
+	if (!msm_session_q) {
+		pr_err("%s : session queue not available Line %d\n",
+				__func__, __LINE__);
+		return -ENODEV;
+	}
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (session) {
+		pr_err("%s: Session exist session_id=%d\n",
+				__func__, session_id);
+		return -EINVAL;
+	}
+
+	session = kzalloc(sizeof(*session), GFP_KERNEL);
+	if (!session)
+		return -ENOMEM;
+
+	session->session_id = session_id;
+	session->event_q.vdev = vdev;
+	msm_init_queue(&session->command_ack_q);
+	msm_init_queue(&session->stream_q);
+	msm_enqueue(msm_session_q, &session->list);
+	mutex_init(&session->lock);
+	mutex_init(&session->lock_q);
+	mutex_init(&session->close_lock);
+	rwlock_init(&session->stream_rwlock);
+
+	if (gpu_limit) {
+		session->sysfs_pwr_limit = kgsl_pwr_limits_add(KGSL_DEVICE_3D0);
+		if (session->sysfs_pwr_limit)
+			kgsl_pwr_limits_set_freq(session->sysfs_pwr_limit,
+				gpu_limit);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_create_session);
+
+int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id)
+{
+	struct msm_session *session;
+	struct msm_command_ack *cmd_ack;
+
+	if (!msm_session_q) {
+		pr_err("%s : Session queue not available Line %d\n",
+				__func__, __LINE__);
+		return -ENODEV;
+	}
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session) {
+		pr_err("%s : Session not found Line %d\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+	mutex_lock(&session->lock);
+	cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL);
+	if (!cmd_ack) {
+		mutex_unlock(&session->lock);
+		pr_err("%s : memory not available Line %d\n",
+				__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	msm_init_queue(&cmd_ack->command_q);
+	INIT_LIST_HEAD(&cmd_ack->list);
+	init_completion(&cmd_ack->wait_complete);
+	cmd_ack->stream_id = stream_id;
+
+	msm_enqueue(&session->command_ack_q, &cmd_ack->list);
+	session->command_ack_q.len++;
+	mutex_unlock(&session->lock);
+	return 0;
+}
+EXPORT_SYMBOL(msm_create_command_ack_q);
+
+void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id)
+{
+	struct msm_session *session;
+	struct msm_command_ack *cmd_ack;
+	unsigned long flags;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session)
+		return;
+	mutex_lock(&session->lock);
+
+	cmd_ack = msm_queue_find(&session->command_ack_q,
+		struct msm_command_ack,	list, __msm_queue_find_command_ack_q,
+		&stream_id);
+	if (!cmd_ack) {
+		mutex_unlock(&session->lock);
+		return;
+	}
+
+	msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
+
+	spin_lock_irqsave(&(session->command_ack_q.lock), flags);
+	list_del_init(&cmd_ack->list);
+	kzfree(cmd_ack);
+	session->command_ack_q.len--;
+	spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
+	mutex_unlock(&session->lock);
+}
+EXPORT_SYMBOL(msm_delete_command_ack_q);
+
+static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
+	struct msm_sd_close_ioctl *sd_close)
+{
+	struct v4l2_subdev *sd;
+
+	sd = &msm_sd->sd;
+	pr_debug("%s: Shutting down subdev %s", __func__, sd->name);
+
+	v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close);
+	v4l2_subdev_call(sd, core, s_power, 0);
+
+	return 0;
+}
+
+static inline int __msm_sd_notify_freeze_subdevs(struct msm_sd_subdev *msm_sd,
+	int enable)
+{
+	struct v4l2_subdev *sd;
+
+	sd = &msm_sd->sd;
+
+	if (enable)
+		v4l2_subdev_call(sd, core, ioctl, MSM_SD_NOTIFY_FREEZE, NULL);
+	else
+		v4l2_subdev_call(sd, core, ioctl, MSM_SD_UNNOTIFY_FREEZE, NULL);
+
+	return 0;
+}
+
+static inline int __msm_destroy_session_streams(void *d1, void *d2)
+{
+	struct msm_stream *stream = d1;
+	unsigned long flags;
+
+	pr_err("%s: Error: Destroyed list is not empty\n", __func__);
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	INIT_LIST_HEAD(&stream->queued_list);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	return 0;
+}
+
+static void msm_destroy_session_streams(struct msm_session *session)
+{
+
+	if (!session)
+		return;
+
+	msm_queue_traverse_action(&session->stream_q, struct msm_stream, list,
+		__msm_destroy_session_streams, NULL);
+
+	msm_queue_drain(&session->stream_q, struct msm_stream, list);
+}
+
+static inline int __msm_remove_session_cmd_ack_q(void *d1, void *d2)
+{
+	struct msm_command_ack *cmd_ack = d1;
+
+	if (!(&cmd_ack->command_q))
+		return 0;
+
+	msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
+
+	return 0;
+}
+
+static void msm_remove_session_cmd_ack_q(struct msm_session *session)
+{
+	if ((!session) || !(&session->command_ack_q))
+		return;
+
+	mutex_lock(&session->lock);
+	/* to ensure error handling purpose, it needs to detach all subdevs
+	 * which are being connected to streams
+	 */
+	msm_queue_traverse_action(&session->command_ack_q,
+		struct msm_command_ack,	list,
+		__msm_remove_session_cmd_ack_q, NULL);
+
+	msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list);
+
+	mutex_unlock(&session->lock);
+}
+
+int msm_destroy_session(unsigned int session_id)
+{
+	struct msm_session *session;
+	struct v4l2_subdev *buf_mgr_subdev;
+	struct msm_sd_close_ioctl session_info;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session)
+		return -EINVAL;
+
+	if (gpu_limit && session->sysfs_pwr_limit) {
+		kgsl_pwr_limits_set_default(session->sysfs_pwr_limit);
+		kgsl_pwr_limits_del(session->sysfs_pwr_limit);
+	}
+
+	msm_destroy_session_streams(session);
+	msm_remove_session_cmd_ack_q(session);
+	mutex_destroy(&session->lock);
+	mutex_destroy(&session->lock_q);
+	mutex_destroy(&session->close_lock);
+	msm_delete_entry(msm_session_q, struct msm_session,
+		list, session);
+	buf_mgr_subdev = msm_sd_find("msm_buf_mngr");
+	if (buf_mgr_subdev) {
+		session_info.session = session_id;
+		session_info.stream = 0;
+		v4l2_subdev_call(buf_mgr_subdev, core, ioctl,
+			MSM_SD_SHUTDOWN, &session_info);
+	} else {
+		pr_err("%s: Buff manger device node is NULL\n", __func__);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_destroy_session);
+
+static int __msm_close_destry_session_notify_apps(void *d1, void *d2)
+{
+	struct v4l2_event event;
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event.u.data[0];
+	struct msm_session *session = d1;
+
+	event.type = MSM_CAMERA_V4L2_EVENT_TYPE;
+	event.id   = MSM_CAMERA_MSM_NOTIFY;
+	event_data->command = MSM_CAMERA_PRIV_SHUTDOWN;
+
+	v4l2_event_queue(session->event_q.vdev, &event);
+
+	return 0;
+}
+
+static int __msm_wakeup_all_cmdack_session_stream(void *d1, void *d2)
+{
+	struct msm_stream *stream = d1;
+	struct msm_session *session = d2;
+	struct msm_command_ack *cmd_ack = NULL;
+	unsigned long spin_flags = 0;
+
+	cmd_ack = msm_queue_find(&session->command_ack_q,
+		struct msm_command_ack, list,
+		__msm_queue_find_command_ack_q,
+		&stream->stream_id);
+	if (cmd_ack) {
+		spin_lock_irqsave(&(session->command_ack_q.lock),
+			spin_flags);
+		complete(&cmd_ack->wait_complete);
+		spin_unlock_irqrestore(&(session->command_ack_q.lock),
+			spin_flags);
+	}
+	return 0;
+}
+
+static int __msm_close_wakeup_all_cmdack_session(void *d1, void *d2)
+{
+	struct msm_stream  *stream = NULL;
+	struct msm_session *session = d1;
+
+	stream = msm_queue_find(&session->stream_q, struct msm_stream,
+		list, __msm_wakeup_all_cmdack_session_stream, d1);
+	return 0;
+}
+
+static long msm_private_ioctl(struct file *file, void *fh,
+	bool valid_prio, unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct msm_v4l2_event_data *event_data = arg;
+	struct v4l2_event event;
+	struct msm_session *session;
+	unsigned int session_id;
+	unsigned int stream_id;
+	unsigned long spin_flags = 0;
+	struct msm_sd_subdev *msm_sd;
+
+	if (cmd == MSM_CAM_V4L2_IOCTL_DAEMON_DISABLED) {
+		is_daemon_status = false;
+		return 0;
+	}
+
+	if (!event_data)
+		return -EINVAL;
+
+	switch (cmd) {
+	case MSM_CAM_V4L2_IOCTL_NOTIFY:
+	case MSM_CAM_V4L2_IOCTL_CMD_ACK:
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG:
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR:
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	memset(&event, 0, sizeof(struct v4l2_event));
+	session_id = event_data->session_id;
+	stream_id = event_data->stream_id;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+
+	if (!session)
+		return -EINVAL;
+
+	switch (cmd) {
+	case MSM_CAM_V4L2_IOCTL_NOTIFY: {
+		if (WARN_ON(!session->event_q.vdev)) {
+			rc = -EFAULT;
+			break;
+		}
+		event.type = event_data->v4l2_event_type;
+		event.id = event_data->v4l2_event_id;
+		memcpy(&event.u.data, event_data,
+			sizeof(struct msm_v4l2_event_data));
+		v4l2_event_queue(session->event_q.vdev,
+			&event);
+	}
+		break;
+
+	case MSM_CAM_V4L2_IOCTL_CMD_ACK: {
+		struct msm_command_ack *cmd_ack;
+		struct msm_command *ret_cmd;
+
+		ret_cmd = kzalloc(sizeof(*ret_cmd), GFP_KERNEL);
+		if (!ret_cmd) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		cmd_ack = msm_queue_find(&session->command_ack_q,
+			struct msm_command_ack, list,
+			__msm_queue_find_command_ack_q,
+			&stream_id);
+		if (WARN_ON(!cmd_ack)) {
+			kzfree(ret_cmd);
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&(session->command_ack_q.lock),
+		   spin_flags);
+		event.type = event_data->v4l2_event_type;
+		event.id = event_data->v4l2_event_id;
+		memcpy(&event.u.data, event_data,
+			sizeof(struct msm_v4l2_event_data));
+		memcpy(&ret_cmd->event, &event, sizeof(struct v4l2_event));
+		msm_enqueue(&cmd_ack->command_q, &ret_cmd->list);
+		complete(&cmd_ack->wait_complete);
+		spin_unlock_irqrestore(&(session->command_ack_q.lock),
+		   spin_flags);
+	}
+		break;
+
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG: {
+		if (event_data->status) {
+			pr_err("%s:Notifying subdevs about potential sof freeze\n",
+				__func__);
+		} else {
+			pr_err("%s:Notifying subdevs about sof recover\n",
+				__func__);
+		}
+
+		mutex_lock(&ordered_sd_mtx);
+		if (!list_empty(&msm_v4l2_dev->subdevs)) {
+			list_for_each_entry(msm_sd, &ordered_sd_list, list)
+				__msm_sd_notify_freeze_subdevs(msm_sd,
+					event_data->status);
+		}
+		mutex_unlock(&ordered_sd_mtx);
+	}
+		break;
+
+	case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR:
+		/* send v4l2_event to HAL next*/
+		msm_queue_traverse_action(msm_session_q,
+			struct msm_session, list,
+			__msm_close_destry_session_notify_apps, NULL);
+		break;
+
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_unsubscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc;
+
+	mutex_lock(&v4l2_event_mtx);
+	rc = v4l2_event_unsubscribe(fh, sub);
+	mutex_unlock(&v4l2_event_mtx);
+
+	return rc;
+}
+
+static int msm_subscribe_event(struct v4l2_fh *fh,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc;
+
+	mutex_lock(&v4l2_event_mtx);
+	rc = v4l2_event_subscribe(fh, sub, 5, NULL);
+	mutex_unlock(&v4l2_event_mtx);
+
+	return rc;
+}
+
+static const struct v4l2_ioctl_ops g_msm_ioctl_ops = {
+	.vidioc_subscribe_event = msm_subscribe_event,
+	.vidioc_unsubscribe_event = msm_unsubscribe_event,
+	.vidioc_default = msm_private_ioctl,
+};
+
+static unsigned int msm_poll(struct file *f,
+	struct poll_table_struct *pll_table)
+{
+	int rc = 0;
+	struct v4l2_fh *eventq = f->private_data;
+
+	if (WARN_ON(!eventq))
+		goto err;
+
+	poll_wait(f, &eventq->wait, pll_table);
+
+	if (v4l2_event_pending(eventq))
+		rc = POLLIN | POLLRDNORM;
+
+err:
+	return rc;
+}
+
+static void msm_print_event_error(struct v4l2_event *event)
+{
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event->u.data[0];
+
+	pr_err("Evt_type=%x Evt_id=%d Evt_cmd=%x\n", event->type,
+		event->id, event_data->command);
+	pr_err("Evt_session_id=%d Evt_stream_id=%d Evt_arg=%d\n",
+		event_data->session_id, event_data->stream_id,
+		event_data->arg_value);
+}
+
+/* something seriously wrong if msm_close is triggered
+ *   !!! user space imaging server is shutdown !!!
+ */
+int msm_post_event(struct v4l2_event *event, int timeout)
+{
+	int rc = 0;
+	struct video_device *vdev;
+	struct msm_session *session;
+	struct msm_v4l2_event_data *event_data =
+		(struct msm_v4l2_event_data *)&event->u.data[0];
+	struct msm_command_ack *cmd_ack;
+	struct msm_command *cmd;
+	int session_id, stream_id;
+	unsigned long flags = 0;
+
+	session_id = event_data->session_id;
+	stream_id = event_data->stream_id;
+
+	spin_lock_irqsave(&msm_eventq_lock, flags);
+	if (!msm_eventq) {
+		spin_unlock_irqrestore(&msm_eventq_lock, flags);
+		pr_err("%s : msm event queue not available Line %d\n",
+				__func__, __LINE__);
+		return -ENODEV;
+	}
+	spin_unlock_irqrestore(&msm_eventq_lock, flags);
+
+	vdev = msm_eventq->vdev;
+
+	/* send to imaging server and wait for ACK */
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (WARN_ON(!session)) {
+		pr_err("%s : session not found Line %d\n",
+				__func__, __LINE__);
+		return -EIO;
+	}
+	mutex_lock(&session->lock);
+	cmd_ack = msm_queue_find(&session->command_ack_q,
+		struct msm_command_ack, list,
+		__msm_queue_find_command_ack_q, &stream_id);
+	if (WARN_ON(!cmd_ack)) {
+		mutex_unlock(&session->lock);
+		pr_err("%s : cmd_ack not found Line %d\n",
+				__func__, __LINE__);
+		return -EIO;
+	}
+
+	/*re-init wait_complete */
+	reinit_completion(&cmd_ack->wait_complete);
+
+	v4l2_event_queue(vdev, event);
+
+	if (timeout < 0) {
+		mutex_unlock(&session->lock);
+		pr_debug("%s : timeout cannot be negative Line %d\n",
+				__func__, __LINE__);
+		return rc;
+	}
+
+	/* should wait on session based condition */
+	rc = wait_for_completion_timeout(&cmd_ack->wait_complete,
+			msecs_to_jiffies(timeout));
+
+
+	if (list_empty_careful(&cmd_ack->command_q.list)) {
+		if (!rc) {
+			pr_err("%s: Timed out\n", __func__);
+			msm_print_event_error(event);
+			mutex_unlock(&session->lock);
+			return -ETIMEDOUT;
+		}
+		pr_err("%s: Error: No timeout but list empty!",
+				__func__);
+		msm_print_event_error(event);
+		mutex_unlock(&session->lock);
+		return -EINVAL;
+	}
+
+	cmd = msm_dequeue(&cmd_ack->command_q,
+		struct msm_command, list);
+	if (!cmd) {
+		mutex_unlock(&session->lock);
+		pr_err("%s : cmd dequeue failed Line %d\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	event_data = (struct msm_v4l2_event_data *)cmd->event.u.data;
+
+	/* compare cmd_ret and event */
+	if (WARN_ON(event->type != cmd->event.type) ||
+			WARN_ON(event->id != cmd->event.id)) {
+		pr_err("%s : Either event type or id didnot match Line %d\n",
+				__func__, __LINE__);
+		pr_err("%s : event->type %d event->id %d\n", __func__,
+				event->type, event->id);
+		pr_err("%s : cmd->event.type %d cmd->event.id %d\n", __func__,
+				cmd->event.type, cmd->event.id);
+		rc = -EINVAL;
+	}
+
+	*event = cmd->event;
+
+	kzfree(cmd);
+	mutex_unlock(&session->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_post_event);
+
+static int msm_close(struct file *filep)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct msm_sd_close_ioctl sd_close;
+	struct msm_sd_subdev *msm_sd;
+
+	/*stop all hardware blocks immediately*/
+	mutex_lock(&ordered_sd_mtx);
+	if (!list_empty(&msm_v4l2_dev->subdevs))
+		list_for_each_entry(msm_sd, &ordered_sd_list, list)
+			__msm_sd_close_subdevs(msm_sd, &sd_close);
+	mutex_unlock(&ordered_sd_mtx);
+
+	/* remove msm_v4l2_pm_qos_request */
+	msm_pm_qos_remove_request();
+
+	/* send v4l2_event to HAL next*/
+	msm_queue_traverse_action(msm_session_q, struct msm_session, list,
+		__msm_close_destry_session_notify_apps, NULL);
+
+	msm_queue_traverse_action(msm_session_q, struct msm_session, list,
+		__msm_close_wakeup_all_cmdack_session, NULL);
+
+	spin_lock_irqsave(&msm_eventq_lock, flags);
+	msm_eventq = NULL;
+	spin_unlock_irqrestore(&msm_eventq_lock, flags);
+	v4l2_fh_release(filep);
+
+	spin_lock_irqsave(&msm_pid_lock, flags);
+	put_pid(msm_pid);
+	msm_pid = NULL;
+	spin_unlock_irqrestore(&msm_pid_lock, flags);
+
+	atomic_set(&pvdev->opened, 0);
+
+	return rc;
+}
+
+static inline void msm_list_switch(struct list_head *l1,
+	struct list_head *l2)
+{
+	l1->next = l2->next;
+	l2->prev = l1->prev;
+	l1->prev->next = l2;
+	l2->next->prev = l1;
+	l1->prev = l2;
+	l2->next = l1;
+}
+
+static int msm_open(struct file *filep)
+{
+	int rc = -1;
+	unsigned long flags;
+	struct msm_video_device *pvdev = video_drvdata(filep);
+
+	if (WARN_ON(!pvdev))
+		return rc;
+
+	/* !!! only ONE open is allowed !!! */
+	if (atomic_cmpxchg(&pvdev->opened, 0, 1))
+		return -EBUSY;
+
+	spin_lock_irqsave(&msm_pid_lock, flags);
+	msm_pid = get_pid(task_pid(current));
+	spin_unlock_irqrestore(&msm_pid_lock, flags);
+
+	/* create event queue */
+	rc = v4l2_fh_open(filep);
+	if (rc  < 0)
+		return rc;
+
+	spin_lock_irqsave(&msm_eventq_lock, flags);
+	msm_eventq = filep->private_data;
+	spin_unlock_irqrestore(&msm_eventq_lock, flags);
+
+	/* register msm_v4l2_pm_qos_request */
+	msm_pm_qos_add_request();
+	return rc;
+}
+
+static struct v4l2_file_operations msm_fops = {
+	.owner  = THIS_MODULE,
+	.open   = msm_open,
+	.poll   = msm_poll,
+	.release = msm_close,
+	.unlocked_ioctl   = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = video_ioctl2,
+#endif
+};
+
+struct msm_session *msm_get_session(unsigned int session_id)
+{
+	struct msm_session *session;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session)
+		return ERR_PTR(-EINVAL);
+
+	return session;
+}
+EXPORT_SYMBOL(msm_get_session);
+
+
+struct msm_stream *msm_get_stream(struct msm_session *session,
+	unsigned int stream_id)
+{
+	struct msm_stream *stream;
+
+	stream = msm_queue_find(&session->stream_q, struct msm_stream,
+		list, __msm_queue_find_stream, &stream_id);
+
+	if (!stream)
+		return ERR_PTR(-EINVAL);
+
+	return stream;
+}
+EXPORT_SYMBOL(msm_get_stream);
+
+struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
+	unsigned int stream_id)
+{
+	struct msm_session *session;
+	struct msm_stream *stream;
+
+	session = msm_queue_find(msm_session_q, struct msm_session,
+		list, __msm_queue_find_session, &session_id);
+	if (!session)
+		return NULL;
+
+	stream = msm_queue_find(&session->stream_q, struct msm_stream,
+		list, __msm_queue_find_stream, &stream_id);
+	if (!stream)
+		return NULL;
+
+	return stream->vb2_q;
+}
+EXPORT_SYMBOL(msm_get_stream_vb2q);
+
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q)
+{
+	struct msm_session *session;
+	struct msm_stream *stream;
+	unsigned long flags1;
+	unsigned long flags2;
+
+	spin_lock_irqsave(&msm_session_q->lock, flags1);
+	list_for_each_entry(session, &(msm_session_q->list), list) {
+		spin_lock_irqsave(&(session->stream_q.lock), flags2);
+		list_for_each_entry(
+			stream, &(session->stream_q.list), list) {
+			if (stream->vb2_q == q) {
+				spin_unlock_irqrestore
+					(&(session->stream_q.lock), flags2);
+				spin_unlock_irqrestore
+					(&msm_session_q->lock, flags1);
+				return stream;
+			}
+		}
+		spin_unlock_irqrestore(&(session->stream_q.lock), flags2);
+	}
+	spin_unlock_irqrestore(&msm_session_q->lock, flags1);
+	return NULL;
+}
+EXPORT_SYMBOL(msm_get_stream_from_vb2q);
+
+struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q)
+{
+	struct msm_session *session;
+	struct msm_stream *stream;
+	unsigned long flags1;
+	unsigned long flags2;
+
+	spin_lock_irqsave(&msm_session_q->lock, flags1);
+	list_for_each_entry(session, &(msm_session_q->list), list) {
+		spin_lock_irqsave(&(session->stream_q.lock), flags2);
+		list_for_each_entry(
+			stream, &(session->stream_q.list), list) {
+			if (stream->vb2_q == q) {
+				spin_unlock_irqrestore
+					(&(session->stream_q.lock), flags2);
+				spin_unlock_irqrestore
+					(&msm_session_q->lock, flags1);
+				return session;
+			}
+		}
+		spin_unlock_irqrestore(&(session->stream_q.lock), flags2);
+	}
+	spin_unlock_irqrestore(&msm_session_q->lock, flags1);
+	return NULL;
+}
+EXPORT_SYMBOL(msm_get_session_from_vb2q);
+
+
+#ifdef CONFIG_COMPAT
+long msm_copy_camera_private_ioctl_args(unsigned long arg,
+	struct msm_camera_private_ioctl_arg *k_ioctl,
+	void __user **tmp_compat_ioctl_ptr)
+{
+	struct msm_camera_private_ioctl_arg up_ioctl;
+
+	if (WARN_ON(!arg || !k_ioctl || !tmp_compat_ioctl_ptr))
+		return -EIO;
+
+	if (copy_from_user(&up_ioctl,
+		(void __user *)arg,
+		sizeof(struct msm_camera_private_ioctl_arg)))
+		return -EFAULT;
+
+	k_ioctl->id = up_ioctl.id;
+	k_ioctl->size = up_ioctl.size;
+	k_ioctl->result = up_ioctl.result;
+	k_ioctl->reserved = up_ioctl.reserved;
+	*tmp_compat_ioctl_ptr = compat_ptr(up_ioctl.ioctl_ptr);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_copy_camera_private_ioctl_args);
+#endif
+
+static void msm_sd_notify(struct v4l2_subdev *sd,
+	unsigned int notification, void *arg)
+{
+	int rc = 0;
+	struct v4l2_subdev *subdev = NULL;
+
+	if (WARN_ON(!sd))
+		return;
+
+	if (WARN_ON(!arg))
+		return;
+
+	/* Check if subdev exists before processing*/
+	if (!msm_sd_find(sd->name))
+		return;
+
+	switch (notification) {
+	case MSM_SD_NOTIFY_GET_SD: {
+		struct msm_sd_req_sd *get_sd = arg;
+
+		get_sd->subdev = msm_sd_find(get_sd->name);
+		/* TODO: might need to add ref count on ret_sd */
+	}
+		break;
+
+	case MSM_SD_NOTIFY_PUT_SD: {
+		struct msm_sd_req_sd *put_sd = arg;
+
+		subdev = msm_sd_find(put_sd->name);
+	}
+		break;
+
+	case MSM_SD_NOTIFY_REQ_CB: {
+		struct msm_sd_req_vb2_q *req_sd = arg;
+
+		rc = msm_vb2_request_cb(req_sd);
+		if (rc < 0)
+			return;
+	}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static ssize_t write_logsync(struct file *file, const char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	char lbuf[LOGSYNC_PACKET_SIZE] = {0};
+	uint64_t seq_num = 0;
+	int ret;
+
+	if (copy_from_user(lbuf, buf, sizeof(lbuf) - 1))
+		return -EFAULT;
+
+	ret = kstrtoull(lbuf, 0, &seq_num);
+	if (ret != 1)
+		pr_err("LOGSYNC (Kernel): Bad or malformed sequence number\n");
+	else
+		pr_debug("LOGSYNC (Kernel): seq_num = %llu\n", seq_num);
+
+	return count;
+}
+
+
+static const struct file_operations logsync_fops = {
+		.write = write_logsync,
+};
+
+static int msm_probe(struct platform_device *pdev)
+{
+	struct msm_video_device *pvdev = NULL;
+	static struct dentry *cam_debugfs_root;
+	int rc = 0;
+
+	msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev),
+		GFP_KERNEL);
+	if (WARN_ON(!msm_v4l2_dev)) {
+		rc = -ENOMEM;
+		goto probe_end;
+	}
+
+	pvdev = kzalloc(sizeof(struct msm_video_device),
+		GFP_KERNEL);
+	if (WARN_ON(!pvdev)) {
+		rc = -ENOMEM;
+		goto pvdev_fail;
+	}
+
+	pvdev->vdev = video_device_alloc();
+	if (WARN_ON(!pvdev->vdev)) {
+		rc = -ENOMEM;
+		goto video_fail;
+	}
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device),
+		GFP_KERNEL);
+	if (!msm_v4l2_dev->mdev) {
+		rc = -ENOMEM;
+		goto mdev_fail;
+	}
+	media_device_init(msm_v4l2_dev->mdev);
+	strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME,
+			sizeof(msm_v4l2_dev->mdev->model));
+	msm_v4l2_dev->mdev->dev = &(pdev->dev);
+
+	rc = media_device_register(msm_v4l2_dev->mdev);
+	if (WARN_ON(rc < 0))
+		goto media_fail;
+
+	if (WARN_ON((rc == media_entity_pads_init(&pvdev->vdev->entity,
+			0, NULL)) < 0))
+		goto entity_fail;
+
+	pvdev->vdev->entity.function = QCAMERA_VNODE_GROUP_ID;
+#endif
+
+	msm_v4l2_dev->notify = msm_sd_notify;
+
+	pvdev->vdev->v4l2_dev = msm_v4l2_dev;
+
+	rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
+	if (WARN_ON(rc < 0))
+		goto register_fail;
+
+	strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name));
+	pvdev->vdev->release  = video_device_release;
+	pvdev->vdev->fops     = &msm_fops;
+	pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops;
+	pvdev->vdev->minor     = -1;
+	pvdev->vdev->vfl_type  = VFL_TYPE_GRABBER;
+	rc = video_register_device(pvdev->vdev,
+		VFL_TYPE_GRABBER, -1);
+	if (WARN_ON(rc < 0))
+		goto v4l2_fail;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	/* FIXME: How to get rid of this messy? */
+	pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev);
+#endif
+
+	atomic_set(&pvdev->opened, 0);
+	video_set_drvdata(pvdev->vdev, pvdev);
+
+	msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
+	if (WARN_ON(!msm_session_q))
+		goto v4l2_fail;
+
+	msm_init_queue(msm_session_q);
+	spin_lock_init(&msm_eventq_lock);
+	spin_lock_init(&msm_pid_lock);
+	mutex_init(&ordered_sd_mtx);
+	mutex_init(&v4l2_event_mtx);
+	INIT_LIST_HEAD(&ordered_sd_list);
+
+	cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR,
+						NULL);
+	if (!cam_debugfs_root) {
+		pr_warn("NON-FATAL: failed to create logsync base directory\n");
+	} else {
+		if (!debugfs_create_file(MSM_CAM_LOGSYNC_FILE_NAME,
+					 0660,
+					 cam_debugfs_root,
+					 NULL,
+					 &logsync_fops))
+			pr_warn("NON-FATAL: failed to create logsync debugfs file\n");
+	}
+
+	rc = cam_ahb_clk_init(pdev);
+	if (rc < 0) {
+		pr_err("%s: failed to register ahb clocks\n", __func__);
+		goto v4l2_fail;
+	}
+
+	of_property_read_u32(pdev->dev.of_node,
+		"qcom,gpu-limit", &gpu_limit);
+
+	goto probe_end;
+
+v4l2_fail:
+	v4l2_device_unregister(pvdev->vdev->v4l2_dev);
+register_fail:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&pvdev->vdev->entity);
+entity_fail:
+	media_device_unregister(msm_v4l2_dev->mdev);
+media_fail:
+	kzfree(msm_v4l2_dev->mdev);
+mdev_fail:
+#endif
+	video_device_release(pvdev->vdev);
+video_fail:
+	kzfree(pvdev);
+pvdev_fail:
+	kzfree(msm_v4l2_dev);
+probe_end:
+	return rc;
+}
+
+static const struct of_device_id msm_dt_match[] = {
+	{.compatible = "qcom,msm-cam"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_dt_match);
+
+static struct platform_driver msm_driver = {
+	.probe = msm_probe,
+	.driver = {
+		.name = "msm",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_dt_match,
+	},
+};
+
+static int __init msm_init(void)
+{
+	return platform_driver_register(&msm_driver);
+}
+
+static void __exit msm_exit(void)
+{
+	platform_driver_unregister(&msm_driver);
+}
+
+
+module_init(msm_init);
+module_exit(msm_exit);
+MODULE_DESCRIPTION("MSM V4L2 Camera");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
new file mode 100644
index 0000000..2ada45e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -0,0 +1,151 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_H
+#define _MSM_H
+
+#include <linux/version.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/pm_qos.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <linux/msm_kgsl.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/msmb_camera.h>
+
+/* Setting MAX timeout to 6.5seconds considering
+ * backend will operate @ .6fps in certain usecases
+ * like Long exposure usecase and isp needs max of 2 frames
+ * to stop the hardware which will be around 3 seconds
+ */
+#define MSM_POST_EVT_TIMEOUT 6500
+#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF
+#define MSM_CAMERA_STREAM_CNT_BITS  32
+
+#define CAMERA_DISABLE_PC_LATENCY 100
+#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE
+
+extern bool is_daemon_status;
+
+struct msm_video_device {
+	struct video_device *vdev;
+	atomic_t opened;
+	struct mutex video_drvdata_mutex;
+};
+
+struct msm_queue_head {
+	struct list_head list;
+	spinlock_t lock;
+	int len;
+	int max;
+};
+
+/** msm_event:
+ *
+ *  event sent by imaging server
+ **/
+struct msm_event {
+	struct video_device *vdev;
+	atomic_t on_heap;
+};
+
+struct msm_command {
+	struct list_head list;
+	struct v4l2_event event;
+	atomic_t on_heap;
+};
+
+/** struct msm_command_ack
+ *
+ *  Object of command_ack_q, which is
+ *  created per open operation
+ *
+ *  contains struct msm_command
+ **/
+struct msm_command_ack {
+	struct list_head list;
+	struct msm_queue_head command_q;
+	struct completion wait_complete;
+	int stream_id;
+};
+
+struct msm_v4l2_subdev {
+	/* FIXME: for session close and error handling such
+	 * as daemon shutdown
+	 */
+	int    close_sequence;
+};
+
+struct msm_session {
+	struct list_head list;
+
+	/* session index */
+	unsigned int session_id;
+
+	/* event queue sent by imaging server */
+	struct msm_event event_q;
+
+	/* ACK by imaging server. Object type of
+	 * struct msm_command_ack per open,
+	 * assumption is application can send
+	 * command on every opened video node
+	 */
+	struct msm_queue_head command_ack_q;
+
+	/* real streams(either data or metadate) owned by one
+	 * session struct msm_stream
+	 */
+	struct msm_queue_head stream_q;
+	struct mutex lock;
+	struct mutex lock_q;
+	struct mutex close_lock;
+	rwlock_t	stream_rwlock;
+	struct kgsl_pwr_limit *sysfs_pwr_limit;
+};
+
+static inline bool msm_is_daemon_present(void)
+{
+	return is_daemon_status;
+}
+
+void msm_pm_qos_update_request(int val);
+int msm_post_event(struct v4l2_event *event, int timeout);
+int  msm_create_session(unsigned int session, struct video_device *vdev);
+int msm_destroy_session(unsigned int session_id);
+
+int msm_create_stream(unsigned int session_id,
+	unsigned int stream_id, struct vb2_queue *q);
+void msm_delete_stream(unsigned int session_id, unsigned int stream_id);
+int  msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id);
+void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id);
+struct msm_session *msm_get_session(unsigned int session_id);
+struct msm_stream *msm_get_stream(struct msm_session *session,
+	unsigned int stream_id);
+struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
+	unsigned int stream_id);
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
+struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q);
+struct msm_session *msm_session_find(unsigned int session_id);
+#ifdef CONFIG_COMPAT
+long msm_copy_camera_private_ioctl_args(unsigned long arg,
+	struct msm_camera_private_ioctl_arg *k_ioctl,
+	void __user **tmp_compat_ioctl_ptr);
+#endif
+#endif /*_MSM_H */
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/Makefile b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/Makefile
new file mode 100644
index 0000000..8832457
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/Makefile
@@ -0,0 +1,2 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+obj-$(CONFIG_MSMB_CAMERA) += msm_generic_buf_mgr.o
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
new file mode 100644
index 0000000..e350096
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -0,0 +1,902 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__
+
+#include "msm_generic_buf_mgr.h"
+
+static struct msm_buf_mngr_device *msm_buf_mngr_dev;
+
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void)
+{
+	return &msm_buf_mngr_dev->subdev.sd;
+}
+
+static int32_t msm_buf_mngr_hdl_cont_get_buf(struct msm_buf_mngr_device *dev,
+	struct msm_buf_mngr_info *buf_info)
+{
+	unsigned int i;
+	struct msm_buf_mngr_user_buf_cont_info *cbuf, *cont_save;
+
+	list_for_each_entry_safe(cbuf, cont_save, &dev->cont_qhead, entry) {
+		if ((cbuf->sessid == buf_info->session_id) &&
+		(cbuf->index == buf_info->index) &&
+		(cbuf->strid == buf_info->stream_id)) {
+			buf_info->user_buf.buf_cnt = cbuf->paddr->buf_cnt;
+			if (buf_info->user_buf.buf_cnt >
+				MSM_CAMERA_MAX_USER_BUFF_CNT) {
+				pr_err("Invalid cnt%d,%d,%d\n",
+					cbuf->paddr->buf_cnt,
+					buf_info->session_id,
+					buf_info->stream_id);
+				return -EINVAL;
+			}
+			for (i = 0 ; i < buf_info->user_buf.buf_cnt; i++) {
+				buf_info->user_buf.buf_idx[i] =
+					cbuf->paddr->buf_idx[i];
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev,
+	void *argp)
+{
+	unsigned long flags;
+	int32_t rc = 0;
+	struct msm_buf_mngr_info *buf_info =
+		(struct msm_buf_mngr_info *)argp;
+	struct msm_get_bufs *new_entry =
+		kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL);
+
+	if (!new_entry) {
+		pr_err("%s:No mem\n", __func__);
+		return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&new_entry->entry);
+	new_entry->vb2_v4l2_buf = dev->vb2_ops.get_buf(buf_info->session_id,
+		buf_info->stream_id);
+	if (!new_entry->vb2_v4l2_buf) {
+		pr_debug("%s:Get buf is null\n", __func__);
+		kfree(new_entry);
+		return -EINVAL;
+	}
+	new_entry->session_id = buf_info->session_id;
+	new_entry->stream_id = buf_info->stream_id;
+	new_entry->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
+	spin_lock_irqsave(&dev->buf_q_spinlock, flags);
+	list_add_tail(&new_entry->entry, &dev->buf_qhead);
+	spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
+	buf_info->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
+	if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
+		mutex_lock(&dev->cont_mutex);
+		if (!list_empty(&dev->cont_qhead)) {
+			rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info);
+		} else {
+			pr_err("Nothing mapped in user buf for %d,%d\n",
+				buf_info->session_id, buf_info->stream_id);
+			rc = -EINVAL;
+		}
+		mutex_unlock(&dev->cont_mutex);
+	}
+	return rc;
+}
+
+static int32_t msm_buf_mngr_get_buf_by_idx(struct msm_buf_mngr_device *dev,
+	void *argp)
+{
+	unsigned long flags;
+	int32_t rc = 0;
+	struct msm_buf_mngr_info *buf_info =
+		(struct msm_buf_mngr_info *)argp;
+	struct msm_get_bufs *new_entry =
+		kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL);
+
+	if (!new_entry)
+		return -ENOMEM;
+
+	if (!buf_info) {
+		kfree(new_entry);
+		return -EIO;
+	}
+
+	INIT_LIST_HEAD(&new_entry->entry);
+	new_entry->vb2_v4l2_buf = dev->vb2_ops.get_buf_by_idx(
+		buf_info->session_id, buf_info->stream_id, buf_info->index);
+	if (!new_entry->vb2_v4l2_buf) {
+		pr_debug("%s:Get buf is null\n", __func__);
+		kfree(new_entry);
+		return -EINVAL;
+	}
+	new_entry->session_id = buf_info->session_id;
+	new_entry->stream_id = buf_info->stream_id;
+	new_entry->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
+	spin_lock_irqsave(&dev->buf_q_spinlock, flags);
+	list_add_tail(&new_entry->entry, &dev->buf_qhead);
+	spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
+	if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
+		mutex_lock(&dev->cont_mutex);
+		if (!list_empty(&dev->cont_qhead)) {
+			rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info);
+		} else {
+			pr_err("Nothing mapped in user buf for %d,%d\n",
+				buf_info->session_id, buf_info->stream_id);
+			rc = -EINVAL;
+		}
+		mutex_unlock(&dev->cont_mutex);
+	}
+	return rc;
+}
+
+static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
+	struct msm_buf_mngr_info *buf_info)
+{
+	unsigned long flags;
+	struct msm_get_bufs *bufs, *save;
+	int32_t ret = -EINVAL;
+
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
+	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
+		if ((bufs->session_id == buf_info->session_id) &&
+			(bufs->stream_id == buf_info->stream_id) &&
+			(bufs->index == buf_info->index)) {
+			ret = buf_mngr_dev->vb2_ops.buf_done
+					(bufs->vb2_v4l2_buf,
+						buf_info->session_id,
+						buf_info->stream_id,
+						buf_info->frame_id,
+						&buf_info->timestamp,
+						buf_info->reserved);
+			list_del_init(&bufs->entry);
+			kfree(bufs);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
+	return ret;
+}
+
+
+static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev,
+	struct msm_buf_mngr_info *buf_info)
+{
+	unsigned long flags;
+	struct msm_get_bufs *bufs, *save;
+	int32_t ret = -EINVAL;
+
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
+	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
+		if ((bufs->session_id == buf_info->session_id) &&
+			(bufs->stream_id == buf_info->stream_id) &&
+			(bufs->index == buf_info->index)) {
+			ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_v4l2_buf,
+				buf_info->session_id, buf_info->stream_id);
+			list_del_init(&bufs->entry);
+			kfree(bufs);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
+	return ret;
+}
+
+static int32_t msm_generic_buf_mngr_flush(
+	struct msm_buf_mngr_device *buf_mngr_dev,
+	struct msm_buf_mngr_info *buf_info)
+{
+	unsigned long flags;
+	struct msm_get_bufs *bufs, *save;
+	int32_t ret = -EINVAL;
+	struct timeval ts;
+
+	spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
+	/*
+	 * Sanity check on client buf list, remove buf mgr
+	 * queue entries in case any
+	 */
+	list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
+		if ((bufs->session_id == buf_info->session_id) &&
+			(bufs->stream_id == buf_info->stream_id)) {
+			ret = buf_mngr_dev->vb2_ops.buf_done(bufs->vb2_v4l2_buf,
+						buf_info->session_id,
+						buf_info->stream_id, 0, &ts, 0);
+			pr_err("Bufs not flushed: str_id = %d buf_index = %d ret = %d\n",
+			buf_info->stream_id, bufs->index,
+			ret);
+			list_del_init(&bufs->entry);
+			kfree(bufs);
+		}
+	}
+	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
+	/* Flush the remaining vb2 buffers in stream list */
+	ret = buf_mngr_dev->vb2_ops.flush_buf(buf_info->session_id,
+			buf_info->stream_id);
+	return ret;
+}
+
+static int32_t msm_buf_mngr_find_cont_stream(struct msm_buf_mngr_device *dev,
+					     uint32_t *cnt, uint32_t *tstream,
+					     struct msm_sd_close_ioctl *session)
+{
+	struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save;
+	int32_t ret = -1;
+
+	list_for_each_entry_safe(cont_bufs,
+		cont_save, &dev->cont_qhead, entry) {
+		if (cont_bufs->sessid == session->session) {
+			*cnt = cont_bufs->cnt;
+			*tstream = cont_bufs->strid;
+			return 0;
+		}
+	}
+	return ret;
+}
+
+static void msm_buf_mngr_contq_listdel(struct msm_buf_mngr_device *dev,
+				     uint32_t session, int32_t stream,
+				     bool unmap, uint32_t cnt)
+{
+	struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save;
+
+	list_for_each_entry_safe(cont_bufs,
+		cont_save, &dev->cont_qhead, entry) {
+		if ((cont_bufs->sessid == session) &&
+		(cont_bufs->strid == stream)) {
+			if (cnt == 1 && unmap == 1) {
+				ion_unmap_kernel(dev->ion_client,
+					cont_bufs->ion_handle);
+				ion_free(dev->ion_client,
+					cont_bufs->ion_handle);
+			}
+			list_del_init(&cont_bufs->entry);
+			kfree(cont_bufs);
+			cnt--;
+		}
+	}
+	if (cnt != 0)
+		pr_err("Buffers pending cnt = %d\n", cnt);
+}
+
+static void msm_buf_mngr_contq_cleanup(struct msm_buf_mngr_device *dev,
+				     struct msm_sd_close_ioctl *session)
+{
+	int32_t stream = -1, found = -1;
+	uint32_t cnt = 0;
+
+	do {
+		found = msm_buf_mngr_find_cont_stream(dev, &cnt,
+			&stream, session);
+		if (found == -1)
+			break;
+		msm_buf_mngr_contq_listdel(dev, session->session,
+			stream, 1, cnt);
+	} while (found == 0);
+}
+
+static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *dev,
+				     struct msm_sd_close_ioctl *session)
+{
+	unsigned long flags;
+	struct msm_get_bufs *bufs, *save;
+
+	if (WARN_ON(!dev))
+		return;
+	if (WARN_ON(!session))
+		return;
+
+	spin_lock_irqsave(&dev->buf_q_spinlock, flags);
+	if (!list_empty(&dev->buf_qhead)) {
+		list_for_each_entry_safe(bufs,
+			save, &dev->buf_qhead, entry) {
+			pr_info("%s: Delete invalid bufs =%pK, session_id=%u, bufs->ses_id=%d, str_id=%d, idx=%d\n",
+				__func__, (void *)bufs, session->session,
+				bufs->session_id, bufs->stream_id,
+				bufs->index);
+			if (session->session == bufs->session_id) {
+				list_del_init(&bufs->entry);
+				kfree(bufs);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
+	mutex_lock(&dev->cont_mutex);
+	if (!list_empty(&dev->cont_qhead))
+		msm_buf_mngr_contq_cleanup(dev, session);
+	mutex_unlock(&dev->cont_mutex);
+}
+
+static int msm_buf_mngr_handle_cont_cmd(struct msm_buf_mngr_device *dev,
+					struct msm_buf_mngr_main_cont_info
+					*cont_cmd)
+{
+	int rc = 0, i = 0;
+	struct ion_handle *ion_handle = NULL;
+	struct msm_camera_user_buf_cont_t *iaddr, *temp_addr;
+	struct msm_buf_mngr_user_buf_cont_info *new_entry, *bufs, *save;
+	size_t size;
+
+	if ((cont_cmd->cmd >= MSM_CAMERA_BUF_MNGR_CONT_MAX) ||
+		(cont_cmd->cmd < 0) ||
+		(cont_cmd->cnt > VB2_MAX_FRAME) ||
+		(cont_cmd->cont_fd < 0)) {
+		pr_debug("Invalid arg passed Cmd:%d, cnt:%d, fd:%d\n",
+			cont_cmd->cmd, cont_cmd->cnt,
+			cont_cmd->cont_fd);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->cont_mutex);
+
+	if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_MAP) {
+		if (!list_empty(&dev->cont_qhead)) {
+			list_for_each_entry_safe(bufs,
+				save, &dev->cont_qhead, entry) {
+				if ((bufs->sessid == cont_cmd->session_id) &&
+				(bufs->strid == cont_cmd->stream_id)) {
+					pr_err("Map exist %d,%d unmap first\n",
+						cont_cmd->session_id,
+						cont_cmd->stream_id);
+					rc = -EINVAL;
+					goto end;
+				}
+			}
+		}
+		ion_handle = ion_import_dma_buf_fd(dev->ion_client,
+				cont_cmd->cont_fd);
+		if (IS_ERR_OR_NULL(ion_handle)) {
+			pr_err("Failed to create ion handle for fd %d\n",
+				cont_cmd->cont_fd);
+			rc = -EINVAL;
+			goto end;
+		}
+		if (ion_handle_get_size(dev->ion_client,
+			ion_handle, &size) < 0) {
+			pr_err("Get ion size failed\n");
+			rc = -EINVAL;
+			goto free_ion_handle;
+		}
+		if ((size == 0) || (size <
+			(sizeof(struct msm_camera_user_buf_cont_t) *
+			cont_cmd->cnt))) {
+			pr_err("Invalid or zero size ION buffer %zu\n", size);
+			rc = -EINVAL;
+			goto free_ion_handle;
+		}
+		iaddr = ion_map_kernel(dev->ion_client, ion_handle);
+		if (IS_ERR_OR_NULL(iaddr)) {
+			pr_err("Mapping cont buff failed\n");
+			rc = -EINVAL;
+			goto free_ion_handle;
+		}
+		for (i = 0; i < cont_cmd->cnt; i++) {
+			temp_addr = iaddr + i;
+			if (temp_addr->buf_cnt >
+				MSM_CAMERA_MAX_USER_BUFF_CNT) {
+				pr_err("%s:Invalid buf_cnt:%d for cont:%d\n",
+					__func__, temp_addr->buf_cnt, i);
+				rc = -EINVAL;
+				goto free_list;
+			}
+			new_entry = kzalloc(sizeof(
+				struct msm_buf_mngr_user_buf_cont_info),
+				GFP_KERNEL);
+			if (!new_entry) {
+				pr_err("%s:No mem\n", __func__);
+				rc = -ENOMEM;
+				goto free_list;
+			}
+			INIT_LIST_HEAD(&new_entry->entry);
+			new_entry->sessid = cont_cmd->session_id;
+			new_entry->strid = cont_cmd->stream_id;
+			new_entry->index = i;
+			new_entry->main_fd = cont_cmd->cont_fd;
+			new_entry->ion_handle = ion_handle;
+			new_entry->cnt = cont_cmd->cnt;
+			new_entry->paddr = temp_addr;
+			list_add_tail(&new_entry->entry, &dev->cont_qhead);
+		}
+		goto end;
+	} else if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_UNMAP) {
+		if (!list_empty(&dev->cont_qhead)) {
+			msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id,
+				cont_cmd->stream_id, 1, cont_cmd->cnt);
+		} else {
+			pr_err("Nothing mapped for %d,%d\n",
+				cont_cmd->session_id, cont_cmd->stream_id);
+			rc = -EINVAL;
+		}
+		goto end;
+	}
+
+free_list:
+	if (i != 0) {
+		if (!list_empty(&dev->cont_qhead)) {
+			msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id,
+				cont_cmd->stream_id, 0, i);
+		}
+	}
+	ion_unmap_kernel(dev->ion_client, ion_handle);
+free_ion_handle:
+	ion_free(dev->ion_client, ion_handle);
+end:
+	mutex_unlock(&dev->cont_mutex);
+	return rc;
+}
+
+static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+
+	if (!buf_mngr_dev) {
+		pr_err("%s buf manager device NULL\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	return rc;
+}
+
+static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+
+	if (!buf_mngr_dev) {
+		pr_err("%s buf manager device NULL\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	return rc;
+}
+
+static int msm_cam_buf_mgr_ops(unsigned int cmd, void *argp)
+{
+	int rc = 0;
+
+	if (!msm_buf_mngr_dev)
+		return -ENODEV;
+	if (!argp)
+		return -EINVAL;
+
+	switch (cmd) {
+	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
+		rc = msm_buf_mngr_get_buf(msm_buf_mngr_dev, argp);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
+		rc = msm_buf_mngr_buf_done(msm_buf_mngr_dev, argp);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
+		rc = msm_buf_mngr_put_buf(msm_buf_mngr_dev, argp);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
+		struct msm_camera_private_ioctl_arg *k_ioctl = argp;
+
+		switch (k_ioctl->id) {
+		case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
+			struct msm_buf_mngr_info *tmp = NULL;
+
+			if (!k_ioctl->ioctl_ptr)
+				return -EINVAL;
+			if (k_ioctl->size != sizeof(struct msm_buf_mngr_info))
+				return -EINVAL;
+
+			MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
+				sizeof(tmp));
+			rc = msm_buf_mngr_get_buf_by_idx(msm_buf_mngr_dev,
+				tmp);
+			}
+			break;
+		default:
+			pr_debug("unimplemented id %d", k_ioctl->id);
+			return -EINVAL;
+		}
+	break;
+	}
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return rc;
+}
+
+int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct)
+{
+	if (!msm_buf_mngr_dev)
+		return -ENODEV;
+	if (!cb_struct)
+		return -EINVAL;
+
+	cb_struct->msm_cam_buf_mgr_ops = msm_cam_buf_mgr_ops;
+	return 0;
+}
+
+static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+	struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+	void *argp = arg;
+
+	if (!buf_mngr_dev) {
+		pr_err("%s buf manager device NULL\n", __func__);
+		rc = -ENOMEM;
+		return rc;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
+		struct msm_camera_private_ioctl_arg k_ioctl, *ptr;
+
+		if (!arg)
+			return -EINVAL;
+		ptr = arg;
+		k_ioctl = *ptr;
+		switch (k_ioctl.id) {
+		case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
+
+			if (k_ioctl.size != sizeof(struct msm_buf_mngr_info))
+				return -EINVAL;
+			if (!k_ioctl.ioctl_ptr)
+				return -EINVAL;
+#ifndef CONFIG_COMPAT
+			{
+				struct msm_buf_mngr_info buf_info, *tmp = NULL;
+
+				MSM_CAM_GET_IOCTL_ARG_PTR(&tmp,
+					&k_ioctl.ioctl_ptr, sizeof(tmp));
+				if (copy_from_user(&buf_info, tmp,
+					sizeof(struct msm_buf_mngr_info))) {
+					return -EFAULT;
+				}
+				k_ioctl.ioctl_ptr = (uintptr_t)&buf_info;
+			}
+#endif
+			argp = &k_ioctl;
+			rc = msm_cam_buf_mgr_ops(cmd, argp);
+			}
+			break;
+		default:
+			pr_debug("unimplemented id %d", k_ioctl.id);
+			return -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
+	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
+	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
+		rc = msm_cam_buf_mgr_ops(cmd, argp);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_INIT:
+		rc = msm_generic_buf_mngr_open(sd, NULL);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_DEINIT:
+		rc = msm_generic_buf_mngr_close(sd, NULL);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		break;
+	case VIDIOC_MSM_BUF_MNGR_FLUSH:
+		rc = msm_generic_buf_mngr_flush(buf_mngr_dev, argp);
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	case MSM_SD_SHUTDOWN:
+		msm_buf_mngr_sd_shutdown(buf_mngr_dev, argp);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_CONT_CMD:
+		rc = msm_buf_mngr_handle_cont_cmd(buf_mngr_dev, argp);
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_camera_buf_mgr_fetch_buf_info(
+		struct msm_buf_mngr_info32_t *buf_info32,
+		struct msm_buf_mngr_info *buf_info, unsigned long arg)
+{
+	if (!arg || !buf_info32 || !buf_info)
+		return -EINVAL;
+
+	if (copy_from_user(buf_info32, (void __user *)arg,
+				sizeof(struct msm_buf_mngr_info32_t)))
+		return -EFAULT;
+
+	buf_info->session_id = buf_info32->session_id;
+	buf_info->stream_id = buf_info32->stream_id;
+	buf_info->frame_id = buf_info32->frame_id;
+	buf_info->index = buf_info32->index;
+	buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec;
+	buf_info->timestamp.tv_usec = (long) buf_info32->
+					timestamp.tv_usec;
+	buf_info->reserved = buf_info32->reserved;
+	buf_info->type = buf_info32->type;
+	return 0;
+}
+
+static long msm_camera_buf_mgr_update_buf_info(
+		struct msm_buf_mngr_info32_t *buf_info32,
+		struct msm_buf_mngr_info *buf_info, unsigned long arg)
+{
+	if (!arg || !buf_info32 || !buf_info)
+		return -EINVAL;
+
+	buf_info32->session_id = buf_info->session_id;
+	buf_info32->stream_id = buf_info->stream_id;
+	buf_info32->index = buf_info->index;
+	buf_info32->timestamp.tv_sec = (int32_t) buf_info->
+						timestamp.tv_sec;
+	buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.
+						tv_usec;
+	buf_info32->reserved = buf_info->reserved;
+	buf_info32->type = buf_info->type;
+	buf_info32->user_buf.buf_cnt = buf_info->user_buf.buf_cnt;
+	memcpy(&buf_info32->user_buf.buf_idx,
+		&buf_info->user_buf.buf_idx,
+		sizeof(buf_info->user_buf.buf_idx));
+	if (copy_to_user((void __user *)arg, buf_info32,
+			sizeof(struct msm_buf_mngr_info32_t)))
+		return -EFAULT;
+	return 0;
+}
+static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	long rc = 0;
+	struct msm_camera_private_ioctl_arg k_ioctl;
+	void __user *tmp_compat_ioctl_ptr = NULL;
+
+	rc = msm_copy_camera_private_ioctl_args(arg,
+		&k_ioctl, &tmp_compat_ioctl_ptr);
+	if (rc < 0) {
+		pr_err("Subdev cmd %d failed\n", cmd);
+		return rc;
+	}
+
+	switch (k_ioctl.id) {
+	case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
+		struct msm_buf_mngr_info32_t buf_info32;
+		struct msm_buf_mngr_info buf_info;
+
+		if (k_ioctl.size != sizeof(struct msm_buf_mngr_info32_t)) {
+			pr_err("Invalid size for id %d with size %d",
+				k_ioctl.id, k_ioctl.size);
+			return -EINVAL;
+		}
+		if (!tmp_compat_ioctl_ptr) {
+			pr_err("Invalid ptr for id %d", k_ioctl.id);
+			return -EINVAL;
+		}
+		k_ioctl.ioctl_ptr = (__u64)&buf_info;
+		k_ioctl.size = sizeof(struct msm_buf_mngr_info);
+		rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
+			(unsigned long)tmp_compat_ioctl_ptr);
+		if (rc < 0) {
+			pr_err("Fetch buf info failed for cmd=%d", cmd);
+			return rc;
+		}
+		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &k_ioctl);
+		if (rc < 0) {
+			pr_err("Subdev cmd %d failed for id %d", cmd,
+				k_ioctl.id);
+			return rc;
+		}
+		}
+		break;
+	default:
+		pr_debug("unimplemented id %d", k_ioctl.id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	int32_t rc = 0;
+
+	/* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's
+	 * except VIDIOC_MSM_CPP_CFG32, which needs special
+	 * processing
+	 */
+	switch (cmd) {
+	case VIDIOC_MSM_BUF_MNGR_GET_BUF32:
+		cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF;
+		break;
+	case VIDIOC_MSM_BUF_MNGR_BUF_DONE32:
+		cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE;
+		break;
+	case VIDIOC_MSM_BUF_MNGR_PUT_BUF32:
+		cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF;
+		break;
+	case VIDIOC_MSM_BUF_MNGR_CONT_CMD:
+		break;
+	case VIDIOC_MSM_BUF_MNGR_FLUSH32:
+		cmd = VIDIOC_MSM_BUF_MNGR_FLUSH;
+		break;
+	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD:
+		break;
+	default:
+		pr_debug("unsupported compat type\n");
+		return -ENOIOCTLCMD;
+	}
+
+	switch (cmd) {
+	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
+	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
+	case VIDIOC_MSM_BUF_MNGR_FLUSH:
+	case VIDIOC_MSM_BUF_MNGR_PUT_BUF: {
+		struct msm_buf_mngr_info32_t buf_info32;
+		struct msm_buf_mngr_info buf_info;
+
+		rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
+			arg);
+		if (rc < 0) {
+			pr_err("Fetch buf info failed for cmd=%d\n", cmd);
+			return rc;
+		}
+		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info);
+		if (rc < 0) {
+			pr_debug("Subdev cmd %d fail\n", cmd);
+			return rc;
+		}
+		rc = msm_camera_buf_mgr_update_buf_info(&buf_info32, &buf_info,
+			arg);
+		if (rc < 0) {
+			pr_err("Update buf info failed for cmd=%d\n", cmd);
+			return rc;
+		}
+		break;
+	}
+	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
+		rc = msm_camera_buf_mgr_internal_compat_ioctl(file, cmd, arg);
+		if (rc < 0) {
+			pr_debug("Subdev cmd %d fail\n", cmd);
+			return rc;
+		}
+		}
+		break;
+	case VIDIOC_MSM_BUF_MNGR_CONT_CMD: {
+		struct msm_buf_mngr_main_cont_info cont_cmd;
+
+		if (copy_from_user(&cont_cmd, (void __user *)arg,
+			sizeof(struct msm_buf_mngr_main_cont_info)))
+			return -EFAULT;
+		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd);
+		if (rc < 0) {
+			pr_debug("Subdev cmd %d fail\n", cmd);
+			return rc;
+		}
+		}
+		break;
+	default:
+		pr_debug("unsupported compat type\n");
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+#endif
+
+static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = {
+	.ioctl = msm_buf_mngr_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_internal_ops
+	msm_generic_buf_mngr_subdev_internal_ops = {
+	.open  = msm_generic_buf_mngr_open,
+	.close = msm_generic_buf_mngr_close,
+};
+
+static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = {
+	.core = &msm_buf_mngr_subdev_core_ops,
+};
+
+static const struct of_device_id msm_buf_mngr_dt_match[] = {
+	{}
+};
+
+static struct v4l2_file_operations msm_buf_v4l2_subdev_fops;
+
+static long msm_bmgr_subdev_do_ioctl(
+		struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+}
+
+
+static long msm_buf_subdev_fops_ioctl(struct file *file,
+		unsigned int cmd,
+		unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl);
+}
+
+static int32_t __init msm_buf_mngr_init(void)
+{
+	int32_t rc = 0;
+
+	msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev),
+		GFP_KERNEL);
+	if (WARN_ON(!msm_buf_mngr_dev)) {
+		pr_err("%s: not enough memory", __func__);
+		return -ENOMEM;
+	}
+	/* Sub-dev */
+	v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd,
+		&msm_buf_mngr_subdev_ops);
+	msm_cam_copy_v4l2_subdev_fops(&msm_buf_v4l2_subdev_fops);
+	msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl;
+#ifdef CONFIG_COMPAT
+	msm_buf_v4l2_subdev_fops.compat_ioctl32 =
+			msm_bmgr_subdev_fops_compat_ioctl;
+#endif
+	snprintf(msm_buf_mngr_dev->subdev.sd.name,
+		ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr");
+	msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev);
+
+	media_entity_pads_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL);
+	msm_buf_mngr_dev->subdev.sd.entity.function =
+		MSM_CAMERA_SUBDEV_BUF_MNGR;
+	msm_buf_mngr_dev->subdev.sd.internal_ops =
+		&msm_generic_buf_mngr_subdev_internal_ops;
+	msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
+	rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
+	if (rc != 0) {
+		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
+		goto end;
+	}
+
+	msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops;
+
+	v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB,
+		&msm_buf_mngr_dev->vb2_ops);
+
+	INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
+	spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock);
+
+	mutex_init(&msm_buf_mngr_dev->cont_mutex);
+	INIT_LIST_HEAD(&msm_buf_mngr_dev->cont_qhead);
+	msm_buf_mngr_dev->ion_client =
+		msm_ion_client_create("msm_cam_generic_buf_mgr");
+	if (!msm_buf_mngr_dev->ion_client) {
+		pr_err("%s: Failed to create ion client\n", __func__);
+		rc = -EBADFD;
+	}
+
+end:
+	return rc;
+}
+
+static void __exit msm_buf_mngr_exit(void)
+{
+	msm_sd_unregister(&msm_buf_mngr_dev->subdev);
+	mutex_destroy(&msm_buf_mngr_dev->cont_mutex);
+	kfree(msm_buf_mngr_dev);
+}
+
+module_init(msm_buf_mngr_init);
+module_exit(msm_buf_mngr_exit);
+MODULE_DESCRIPTION("MSM Buffer Manager");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
new file mode 100644
index 0000000..e13deae
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_BUF_GENERIC_MNGR_H__
+#define __MSM_BUF_GENERIC_MNGR_H__
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+#include <media/msmb_generic_buf_mgr.h>
+
+#include "msm.h"
+#include "msm_sd.h"
+
+struct msm_get_bufs {
+	struct list_head entry;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf;
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t index;
+};
+
+struct msm_buf_mngr_device {
+	struct list_head buf_qhead;
+	spinlock_t buf_q_spinlock;
+	struct ion_client *ion_client;
+	struct msm_sd_subdev subdev;
+	struct msm_sd_req_vb2_q vb2_ops;
+	struct list_head cont_qhead;
+	struct mutex cont_mutex;
+};
+
+struct msm_buf_mngr_user_buf_cont_info {
+	struct list_head entry;
+	uint32_t sessid;
+	uint32_t strid;
+	uint32_t index;
+	int32_t main_fd;
+	struct msm_camera_user_buf_cont_t *paddr;
+	uint32_t cnt;
+	struct ion_handle *ion_handle;
+};
+
+/* kernel space functions*/
+struct msm_cam_buf_mgr_req_ops {
+	int (*msm_cam_buf_mgr_ops)(unsigned int cmd, void *argp);
+};
+
+/* API to register callback from client. This assumes cb_struct is allocated by
+ * client.
+ */
+int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h
new file mode 100644
index 0000000..f45c0d7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_sd.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_SD_H
+#define _MSM_SD_H
+
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+
+/* NOTE: this header file should ONLY be included by subdev drivers */
+
+struct msm_sd_close_ioctl {
+	unsigned int session;
+	unsigned int stream;
+};
+
+#define MSM_SD_CLOSE_STREAM \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl)
+
+#define MSM_SD_CLOSE_SESSION \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl)
+
+#define MSM_SD_CLOSE_SESSION_AND_STREAM \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl)
+
+#define MSM_SD_SHUTDOWN \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl)
+
+#define MSM_SD_NOTIFY_FREEZE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 30, struct msm_sd_close_ioctl)
+
+#define MSM_SD_UNNOTIFY_FREEZE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 31, struct msm_sd_close_ioctl)
+/*
+ * This is used to install Sequence in msm_sd_register.
+ * During msm_close, proper close sequence will be triggered.
+ * For example:
+ *
+ * close_sequence = 0x00100001 (ISP)
+ * close_sequence = 0x00100002 (ISP)
+ * close_sequence = 0x00100003 (ISP)
+ * close_sequence = 0x00200001 (sensor)
+ * close_sequence = 0x00200002 (sensor)
+ * close_sequence = 0x00200003 (sensor)
+ */
+#define MSM_SD_CLOSE_1ST_CATEGORY  0x00010000
+#define MSM_SD_CLOSE_2ND_CATEGORY  0x00020000
+#define MSM_SD_CLOSE_3RD_CATEGORY  0x00030000
+#define MSM_SD_CLOSE_4TH_CATEGORY  0x00040000
+
+struct msm_sd_subdev {
+	struct v4l2_subdev sd;
+	int close_seq;
+	struct list_head list;
+};
+
+struct msm_sd_req_sd {
+	char *name;
+	struct v4l2_subdev *subdev;
+};
+
+struct msm_sd_req_vb2_q {
+	struct vb2_v4l2_buffer * (*get_buf)(int session_id,
+		unsigned int stream_id);
+	struct vb2_queue * (*get_vb2_queue)(int session_id,
+		unsigned int stream_id);
+	struct vb2_v4l2_buffer * (*get_buf_by_idx)(int session_id,
+		unsigned int stream_id, uint32_t index);
+	int (*put_buf)(struct vb2_v4l2_buffer *vb2_buf, int session_id,
+		unsigned int stream_id);
+	int (*buf_done)(struct vb2_v4l2_buffer *vb2_v4l2_buf, int session_id,
+		unsigned int stream_id, uint32_t sequence, struct timeval *ts,
+		uint32_t reserved);
+	int (*flush_buf)(int session_id, unsigned int stream_id);
+};
+
+#define MSM_SD_NOTIFY_GET_SD 0x00000001
+#define MSM_SD_NOTIFY_PUT_SD 0x00000002
+#define MSM_SD_NOTIFY_REQ_CB 0x00000003
+
+#define MSM_CAM_GET_IOCTL_ARG_PTR(ptr, \
+	ioctl_ptr, len) memcpy(ptr, ioctl_ptr, len)
+
+int msm_sd_register(struct msm_sd_subdev *msm_subdev);
+int msm_sd_unregister(struct msm_sd_subdev *sd);
+struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd,
+	const char *get_name);
+void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put);
+void msm_cam_copy_v4l2_subdev_fops(struct v4l2_file_operations *d1);
+
+#endif /*_MSM_SD_H */
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/Makefile b/drivers/media/platform/msm/camera_v2/msm_vb2/Makefile
new file mode 100644
index 0000000..2673bdd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
+obj-$(CONFIG_MSMB_CAMERA) += msm_vb2.o
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
new file mode 100644
index 0000000..5c13de5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -0,0 +1,563 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-VB2 %s:%d " fmt, __func__, __LINE__
+#include "msm_vb2.h"
+
+static int msm_vb2_queue_setup(struct vb2_queue *q,
+//	const void *parg,
+	unsigned int *num_buffers, unsigned int *num_planes,
+	unsigned int sizes[], struct device *alloc_ctxs[])
+{
+	int i;
+	struct msm_v4l2_format_data *data = q->drv_priv;
+
+	if (!data) {
+		pr_err("%s: drv_priv NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES))
+			return -EINVAL;
+
+		*num_planes = data->num_planes;
+
+		for (i = 0; i < data->num_planes; i++)
+			sizes[i] = data->plane_sizes[i];
+	} else {
+		pr_err("%s: Unsupported buf type :%d\n", __func__,
+			   data->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_vb2_buf_init(struct vb2_buffer *vb)
+{
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct msm_vb2_buffer *msm_vb2_buf;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	unsigned long rl_flags;
+
+	session = msm_get_session_from_vb2q(vb->vb2_queue);
+	if (IS_ERR_OR_NULL(session))
+		return -EINVAL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
+	if (!stream) {
+		pr_err("%s: Couldn't find stream\n", __func__);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return -EINVAL;
+	}
+	msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
+	msm_vb2_buf->in_freeq = 0;
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return 0;
+}
+
+static void msm_vb2_buf_queue(struct vb2_buffer *vb)
+{
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	struct msm_session *session;
+	unsigned long flags, rl_flags;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
+	if (!msm_vb2) {
+		pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+		return;
+	}
+
+	session = msm_get_session_from_vb2q(vb->vb2_queue);
+	if (IS_ERR_OR_NULL(session))
+		return;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
+	if (!stream) {
+		pr_err("%s:%d] NULL stream", __func__, __LINE__);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_add_tail(&msm_vb2->list, &stream->queued_list);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+}
+
+static void msm_vb2_buf_finish(struct vb2_buffer *vb)
+{
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	struct msm_session *session;
+	unsigned long flags, rl_flags;
+	struct msm_vb2_buffer *msm_vb2_entry, *temp;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
+	if (!msm_vb2) {
+		pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+		return;
+	}
+
+	session = msm_get_session_from_vb2q(vb->vb2_queue);
+	if (IS_ERR_OR_NULL(session))
+		return;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
+	if (!stream) {
+		pr_err("%s:%d] NULL stream", __func__, __LINE__);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list),
+		list) {
+		if (msm_vb2_entry == msm_vb2) {
+			list_del_init(&msm_vb2_entry->list);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+}
+
+static void msm_vb2_stop_stream(struct vb2_queue *q)
+{
+	struct msm_vb2_buffer *msm_vb2, *temp;
+	struct msm_stream *stream;
+	struct msm_session *session;
+	unsigned long flags, rl_flags;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf;
+
+	session = msm_get_session_from_vb2q(q);
+	if (IS_ERR_OR_NULL(session))
+		return;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream_from_vb2q(q);
+	if (!stream) {
+		pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__);
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return;
+	}
+
+	/*
+	 * Release all the buffers enqueued to driver
+	 * when streamoff is issued
+	 */
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list),
+		list) {
+		vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+		if (vb2_v4l2_buf->vb2_buf.state == VB2_BUF_STATE_DONE)
+			continue;
+		vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
+			VB2_BUF_STATE_DONE);
+		msm_vb2->in_freeq = 0;
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+}
+
+int msm_vb2_get_stream_state(struct msm_stream *stream)
+{
+	struct msm_vb2_buffer *msm_vb2, *temp;
+	unsigned long flags;
+	int rc = 1;
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list), list) {
+		if (msm_vb2->in_freeq != 0) {
+			rc = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vb2_get_stream_state);
+
+
+static struct vb2_ops msm_vb2_get_q_op = {
+	.queue_setup	= msm_vb2_queue_setup,
+	.buf_init	= msm_vb2_buf_init,
+	.buf_queue	= msm_vb2_buf_queue,
+	.buf_finish	= msm_vb2_buf_finish,
+	.stop_streaming = msm_vb2_stop_stream,
+};
+
+
+struct vb2_ops *msm_vb2_get_q_ops(void)
+{
+	return &msm_vb2_get_q_op;
+}
+
+static void *msm_vb2_dma_contig_get_userptr(struct device *alloc_ctx,
+	unsigned long vaddr, unsigned long size,
+	enum dma_data_direction dma_dir)
+{
+	struct msm_vb2_private_data *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return ERR_PTR(-ENOMEM);
+	priv->vaddr = (void *)vaddr;
+	priv->size = size;
+	priv->alloc_ctx = alloc_ctx;
+	return priv;
+}
+
+static void msm_vb2_dma_contig_put_userptr(void *buf_priv)
+{
+	kzfree(buf_priv);
+}
+
+static struct vb2_mem_ops msm_vb2_get_q_mem_op = {
+	.get_userptr		= msm_vb2_dma_contig_get_userptr,
+	.put_userptr		= msm_vb2_dma_contig_put_userptr,
+};
+
+struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void)
+{
+	return &msm_vb2_get_q_mem_op;
+}
+
+static struct vb2_queue *msm_vb2_get_queue(int session_id,
+	unsigned int stream_id)
+{
+	return msm_get_stream_vb2q(session_id, stream_id);
+}
+
+static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id,
+	unsigned int stream_id)
+{
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+	struct msm_vb2_buffer *msm_vb2 = NULL;
+	unsigned long flags, rl_flags;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return NULL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+
+	if (!stream->vb2_q) {
+		pr_err("%s: stream q not available\n", __func__);
+		goto end;
+	}
+
+	list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+		vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+		if (vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
+			continue;
+
+		if (msm_vb2->in_freeq)
+			continue;
+
+		msm_vb2->in_freeq = 1;
+		goto end;
+	}
+	msm_vb2 = NULL;
+	vb2_v4l2_buf = NULL;
+end:
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return vb2_v4l2_buf;
+}
+
+static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id,
+	unsigned int stream_id, uint32_t index)
+{
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+	struct msm_vb2_buffer *msm_vb2 = NULL;
+	unsigned long flags, rl_flags;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return NULL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+
+	if (!stream->vb2_q) {
+		pr_err("%s: stream q not available\n", __func__);
+		goto end;
+	}
+
+	list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+		vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+		if ((vb2_v4l2_buf->vb2_buf.index != index) || msm_vb2->in_freeq
+			|| vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
+			continue;
+
+		msm_vb2->in_freeq = 1;
+		goto end;
+	}
+	msm_vb2 = NULL;
+	vb2_v4l2_buf = NULL;
+end:
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return vb2_v4l2_buf;
+}
+
+static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id,
+				unsigned int stream_id)
+{
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct msm_vb2_buffer *msm_vb2;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+	int rc = 0;
+	unsigned long flags, rl_flags;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return -EINVAL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	if (vb) {
+		list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+			vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+			if (vb2_v4l2_buf == vb)
+				break;
+		}
+		if (vb2_v4l2_buf != vb) {
+			pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n",
+					vb, session_id, stream_id);
+			spin_unlock_irqrestore(&stream->stream_lock, flags);
+			read_unlock_irqrestore(&session->stream_rwlock,
+				rl_flags);
+			return -EINVAL;
+		}
+		msm_vb2 =
+			container_of(vb2_v4l2_buf, struct msm_vb2_buffer,
+				vb2_v4l2_buf);
+		if (msm_vb2->in_freeq) {
+			msm_vb2->in_freeq = 0;
+			rc = 0;
+		} else
+			rc = -EINVAL;
+	} else {
+		pr_err(" VB buffer is null for ses_id=%d, str_id=%d\n",
+			    session_id, stream_id);
+		rc = -EINVAL;
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return rc;
+}
+
+static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id,
+				unsigned int stream_id, uint32_t sequence,
+				struct timeval *ts, uint32_t buf_type)
+{
+	unsigned long flags, rl_flags;
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+	int rc = 0;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return -EINVAL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	if (vb) {
+		list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+			vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+			if (vb2_v4l2_buf == vb)
+				break;
+		}
+		if (vb2_v4l2_buf != vb) {
+			pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n",
+				    session_id, stream_id, vb);
+			spin_unlock_irqrestore(&stream->stream_lock, flags);
+			read_unlock_irqrestore(&session->stream_rwlock,
+				rl_flags);
+			return -EINVAL;
+		}
+		msm_vb2 =
+			container_of(vb2_v4l2_buf, struct msm_vb2_buffer,
+				vb2_v4l2_buf);
+		/* put buf before buf done */
+		if (msm_vb2->in_freeq) {
+			vb2_v4l2_buf->sequence = sequence;
+			vb2_v4l2_buf->timecode.type = buf_type;
+			vb2_v4l2_buf->vb2_buf.timestamp =
+				(ts->tv_sec * 1000000 + ts->tv_usec) * 1000;
+			vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
+				VB2_BUF_STATE_DONE);
+			msm_vb2->in_freeq = 0;
+			rc = 0;
+		} else
+			rc = -EINVAL;
+	} else {
+		pr_err(" VB buffer is NULL for ses_id=%d, str_id=%d\n",
+			    session_id, stream_id);
+		rc = -EINVAL;
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return rc;
+}
+
+long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
+				uint32_t index)
+{
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+	struct msm_vb2_buffer *msm_vb2 = NULL;
+	unsigned long flags, rl_flags;
+	long rc = -EINVAL;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return rc;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+
+	if (!stream->vb2_q) {
+		pr_err("%s: stream q not available\n", __func__);
+		goto end;
+	}
+
+	list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+		vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+		if ((vb2_v4l2_buf->vb2_buf.index != index)
+			|| vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
+			continue;
+
+		if (!msm_vb2->in_freeq) {
+			vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
+				VB2_BUF_STATE_ERROR);
+			rc = 0;
+		} else {
+			rc = -EINVAL;
+		}
+		break;
+	}
+
+end:
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vb2_return_buf_by_idx);
+
+static int msm_vb2_flush_buf(int session_id, unsigned int stream_id)
+{
+	unsigned long flags, rl_flags;
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	struct msm_session *session;
+	struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
+
+	session = msm_get_session(session_id);
+	if (IS_ERR_OR_NULL(session))
+		return -EINVAL;
+
+	read_lock_irqsave(&session->stream_rwlock, rl_flags);
+
+	stream = msm_get_stream(session, stream_id);
+	if (IS_ERR_OR_NULL(stream)) {
+		read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+		vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
+		/* Do buf done for all buffers*/
+		vb2_buffer_done(&vb2_v4l2_buf->vb2_buf, VB2_BUF_STATE_DONE);
+		msm_vb2->in_freeq = 0;
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	read_unlock_irqrestore(&session->stream_rwlock, rl_flags);
+	return 0;
+}
+
+
+int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req)
+{
+	if (!req) {
+		pr_err("%s: suddev is null\n", __func__);
+		return -EINVAL;
+	}
+
+	req->get_buf = msm_vb2_get_buf;
+	req->get_buf_by_idx = msm_vb2_get_buf_by_idx;
+	req->get_vb2_queue = msm_vb2_get_queue;
+	req->put_buf = msm_vb2_put_buf;
+	req->buf_done = msm_vb2_buf_done;
+	req->flush_buf = msm_vb2_flush_buf;
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
new file mode 100644
index 0000000..1a64c54
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_VB_H
+#define _MSM_VB_H
+
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/pm_qos.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/msmb_camera.h>
+#include <media/videobuf2-core.h>
+#include "msm.h"
+#include "msm_sd.h"
+
+struct msm_vb2_buffer {
+	/*
+	 * vb2 buffer has to be first in the structure
+	 * because both v4l2 frameworks and driver directly
+	 * cast msm_vb2_buffer to a vb2_buf.
+	 */
+	struct vb2_v4l2_buffer vb2_v4l2_buf;
+	struct list_head list;
+	int in_freeq;
+};
+
+struct msm_vb2_private_data {
+	void *vaddr;
+	unsigned long size;
+	/* Offset of the plane inside the buffer */
+	struct device *alloc_ctx;
+};
+
+struct msm_stream {
+	struct list_head list;
+
+	/* stream index per session, same
+	 * as stream_id but set through s_parm
+	 */
+	unsigned int stream_id;
+	/* vb2 buffer handling */
+	struct vb2_queue *vb2_q;
+	spinlock_t stream_lock;
+	struct list_head queued_list;
+};
+
+struct vb2_ops *msm_vb2_get_q_ops(void);
+struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void);
+int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd);
+long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
+	uint32_t index);
+int msm_vb2_get_stream_state(struct msm_stream *stream);
+
+#endif /*_MSM_VB_H */
diff --git a/drivers/media/platform/msm/camera_v2/pproc/Makefile b/drivers/media/platform/msm/camera_v2/pproc/Makefile
new file mode 100644
index 0000000..854e4e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MSMB_CAMERA) += cpp/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile
new file mode 100644
index 0000000..2198352
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/Makefile
@@ -0,0 +1,6 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp/
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_buf_mgr/
+obj-$(CONFIG_MSM_CPP) += msm_cpp_soc.o msm_cpp.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
new file mode 100644
index 0000000..70bb3f2
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -0,0 +1,4802 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-CPP %s:%d " fmt, __func__, __LINE__
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/ion.h>
+#include <linux/proc_fs.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/clk/msm-clk.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msmb_camera.h>
+#include <media/msmb_generic_buf_mgr.h>
+#include <media/msmb_pproc.h>
+#include "msm_cpp.h"
+#include "msm_isp_util.h"
+#include "msm_camera_io_util.h"
+#include <linux/debugfs.h>
+#include "cam_smmu_api.h"
+
+#define MSM_CPP_DRV_NAME "msm_cpp"
+
+#define MSM_CPP_MAX_BUFF_QUEUE	16
+
+#define CONFIG_MSM_CPP_DBG	0
+
+#define ENABLE_CPP_LOW		0
+
+#define CPP_CMD_TIMEOUT_MS	300
+#define MSM_CPP_INVALID_OFFSET	0x00000000
+#define MSM_CPP_NOMINAL_CLOCK	266670000
+#define MSM_CPP_TURBO_CLOCK	320000000
+
+#define CPP_FW_VERSION_1_2_0	0x10020000
+#define CPP_FW_VERSION_1_4_0	0x10040000
+#define CPP_FW_VERSION_1_6_0	0x10060000
+#define CPP_FW_VERSION_1_8_0	0x10080000
+#define CPP_FW_VERSION_1_10_0	0x10100000
+
+/* dump the frame command before writing to the hardware */
+#define  MSM_CPP_DUMP_FRM_CMD 0
+
+#define CPP_CLK_INFO_MAX 16
+
+#define MSM_CPP_IRQ_MASK_VAL 0x7c8
+
+#define CPP_GDSCR_SW_COLLAPSE_ENABLE 0xFFFFFFFE
+#define CPP_GDSCR_SW_COLLAPSE_DISABLE 0xFFFFFFFD
+#define CPP_GDSCR_HW_CONTROL_ENABLE 0x2
+#define CPP_GDSCR_HW_CONTROL_DISABLE 0x1
+#define PAYLOAD_NUM_PLANES 3
+#define TNR_MASK 0x4
+#define UBWC_MASK 0x20
+#define CDS_MASK 0x40
+#define MMU_PF_MASK 0x80
+#define POP_FRONT 1
+#define POP_BACK 0
+#define BATCH_DUP_MASK 0x100
+
+#define IS_BATCH_BUFFER_ON_PREVIEW(new_frame) \
+	(((new_frame->batch_info.batch_mode == BATCH_MODE_PREVIEW) && \
+	new_frame->duplicate_output) ? 1 : 0)
+
+#define SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(new_frame, iden, swap_iden) { \
+	if (IS_BATCH_BUFFER_ON_PREVIEW(new_frame)) \
+		iden = swap_iden; \
+}
+
+#define SWAP_BUF_INDEX_FOR_BATCH_ON_PREVIEW(new_frame, buff_mgr_info, \
+	cur_index, swap_index) { \
+	if (IS_BATCH_BUFFER_ON_PREVIEW(new_frame)) \
+		buff_mgr_info.index = swap_index; \
+	else \
+		buff_mgr_info.index = cur_index; \
+}
+
+/*
+ * Default value for get buf to be used - 0xFFFFFFFF
+ * 0 is a valid index
+ * no valid index from userspace, use last buffer from queue.
+ */
+#define DEFAULT_OUTPUT_BUF_INDEX 0xFFFFFFFF
+#define IS_DEFAULT_OUTPUT_BUF_INDEX(index) \
+	((index == DEFAULT_OUTPUT_BUF_INDEX) ? 1 : 0)
+
+static struct msm_cpp_vbif_data cpp_vbif;
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, uint32_t ids, void *arg);
+
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
+	struct msm_queue_cmd *frame_qcmd);
+static int msm_cpp_send_command_to_hardware(struct cpp_device *cpp_dev,
+	uint32_t *cmd_msg, uint32_t payload_size);
+
+static  int msm_cpp_update_gdscr_status(struct cpp_device *cpp_dev,
+	bool status);
+static int msm_cpp_buffer_private_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, uint32_t id, void *arg);
+static void msm_cpp_set_micro_irq_mask(struct cpp_device *cpp_dev,
+	uint8_t enable, uint32_t irq_mask);
+static void msm_cpp_flush_queue_and_release_buffer(struct cpp_device *cpp_dev,
+	int queue_len);
+static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info);
+static int msm_cpp_dump_addr(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *frame_info);
+static int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev);
+
+#if CONFIG_MSM_CPP_DBG
+#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define CPP_LOW(fmt, args...) do { \
+	if (ENABLE_CPP_LOW) \
+		pr_info(fmt, ##args); \
+	} while (0)
+
+#define ERR_USER_COPY(to) pr_err("copy %s user\n", \
+			((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+
+#define msm_dequeue(queue, member, pop_dir) ({	   \
+	unsigned long flags;		  \
+	struct msm_device_queue *__q = (queue);	 \
+	struct msm_queue_cmd *qcmd = NULL;	   \
+	spin_lock_irqsave(&__q->lock, flags);	 \
+	if (!list_empty(&__q->list)) {		\
+		__q->len--;		 \
+		qcmd = pop_dir ? list_first_entry(&__q->list,   \
+			struct msm_queue_cmd, member) :    \
+			list_last_entry(&__q->list,   \
+			struct msm_queue_cmd, member);    \
+		list_del_init(&qcmd->member);	 \
+	}			 \
+	spin_unlock_irqrestore(&__q->lock, flags);  \
+	qcmd;			 \
+})
+
+#define MSM_CPP_MAX_TIMEOUT_TRIAL 1
+
+struct msm_cpp_timer_data_t {
+	struct cpp_device *cpp_dev;
+	struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
+	spinlock_t processed_frame_lock;
+};
+
+struct msm_cpp_timer_t {
+	atomic_t used;
+	struct msm_cpp_timer_data_t data;
+	struct timer_list cpp_timer;
+};
+
+static struct msm_cpp_timer_t cpp_timer;
+static void msm_cpp_set_vbif_reg_values(struct cpp_device *cpp_dev);
+
+
+void msm_cpp_vbif_register_error_handler(void *dev,
+	enum cpp_vbif_client client,
+	int (*client_vbif_error_handler)(void *, uint32_t))
+{
+	if (dev == NULL || client >= VBIF_CLIENT_MAX) {
+		pr_err("%s: Fail to register handler! dev = %pK, client %d\n",
+			__func__, dev, client);
+		return;
+	}
+
+	if (client_vbif_error_handler != NULL) {
+		cpp_vbif.dev[client] = dev;
+		cpp_vbif.err_handler[client] = client_vbif_error_handler;
+	} else {
+		/* if handler = NULL, is unregister case */
+		cpp_vbif.dev[client] = NULL;
+		cpp_vbif.err_handler[client] = NULL;
+	}
+}
+static int msm_cpp_init_bandwidth_mgr(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+
+	rc = msm_camera_register_bus_client(cpp_dev->pdev, CAM_BUS_CLIENT_CPP);
+	if (rc < 0) {
+		pr_err("Fail to register bus client\n");
+		return -ENOENT;
+	}
+
+	rc = msm_camera_update_bus_bw(CAM_BUS_CLIENT_CPP, 0, 0);
+	if (rc < 0) {
+		msm_camera_unregister_bus_client(CAM_BUS_CLIENT_CPP);
+		pr_err("Fail bus scale update %d\n", rc);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_cpp_update_bandwidth(struct cpp_device *cpp_dev,
+	uint64_t ab, uint64_t ib)
+{
+
+	int rc;
+
+	rc = msm_camera_update_bus_bw(CAM_BUS_CLIENT_CPP, ab, ib);
+	if (rc < 0) {
+		pr_err("Fail bus scale update %d\n", rc);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+
+	rc = msm_camera_unregister_bus_client(CAM_BUS_CLIENT_CPP);
+	if (rc < 0) {
+		pr_err("Failed to unregister %d\n", rc);
+		return;
+	}
+}
+
+static int  msm_cpp_update_bandwidth_setting(struct cpp_device *cpp_dev,
+	uint64_t ab, uint64_t ib) {
+	int rc;
+
+	if (cpp_dev->bus_master_flag)
+		rc = msm_cpp_update_bandwidth(cpp_dev, ab, ib);
+	else
+		rc = msm_isp_update_bandwidth(ISP_CPP, ab, ib);
+	return rc;
+}
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	CPP_DBG("E\n");
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_debug("queue %s new max is %d\n", queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	CPP_DBG("woke up %s\n", queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+#define msm_cpp_empty_list(queue, member) { \
+	unsigned long flags; \
+	struct msm_queue_cmd *qcmd = NULL; \
+	if (queue) { \
+		spin_lock_irqsave(&queue->lock, flags); \
+		while (!list_empty(&queue->list)) { \
+			queue->len--; \
+			qcmd = list_first_entry(&queue->list, \
+				struct msm_queue_cmd, member); \
+			list_del_init(&qcmd->member); \
+			kfree(qcmd); \
+		} \
+		spin_unlock_irqrestore(&queue->lock, flags); \
+	} \
+}
+
+
+
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
+	uint8_t put_buf);
+static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
+static void cpp_timer_callback(unsigned long data);
+
+static uint8_t induce_error;
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
+
+static void msm_cpp_write(u32 data, void __iomem *cpp_base)
+{
+	msm_camera_io_w((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA);
+}
+
+static void msm_cpp_clear_timer(struct cpp_device *cpp_dev)
+{
+	uint32_t i = 0;
+
+	if (atomic_read(&cpp_timer.used)) {
+		atomic_set(&cpp_timer.used, 0);
+		del_timer(&cpp_timer.cpp_timer);
+		for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
+			cpp_timer.data.processed_frame[i] = NULL;
+		cpp_dev->timeout_trial_cnt = 0;
+	}
+}
+
+static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+	unsigned long flags;
+
+	CPP_DBG("Frame done qlen %d\n", cpp_dev->processing_q.len);
+	if (cpp_dev->processing_q.len <= 1) {
+		msm_cpp_clear_timer(cpp_dev);
+	} else {
+		spin_lock_irqsave(&cpp_timer.data.processed_frame_lock, flags);
+		for (i = 0; i < cpp_dev->processing_q.len - 1; i++)
+			cpp_timer.data.processed_frame[i] =
+				cpp_timer.data.processed_frame[i + 1];
+		cpp_timer.data.processed_frame[i] = NULL;
+		cpp_dev->timeout_trial_cnt = 0;
+		spin_unlock_irqrestore(&cpp_timer.data.processed_frame_lock,
+			flags);
+
+		mod_timer(&cpp_timer.cpp_timer,
+			jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+	}
+}
+
+static uint32_t msm_cpp_read(void __iomem *cpp_base)
+{
+	uint32_t tmp, retry = 0;
+
+	do {
+		tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT);
+	} while (((tmp & 0x2) == 0x0) && (retry++ < 10));
+	if (retry < 10) {
+		tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA);
+		CPP_DBG("Read data: 0%x\n", tmp);
+	} else {
+		CPP_DBG("Read failed\n");
+		tmp = 0xDEADBEEF;
+	}
+
+	return tmp;
+}
+
+static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry(
+	struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id)
+{
+	uint32_t i = 0;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if ((cpp_dev->buff_queue[i].used == 1) &&
+			(cpp_dev->buff_queue[i].session_id == session_id) &&
+			(cpp_dev->buff_queue[i].stream_id == stream_id)) {
+			buff_queue_info = &cpp_dev->buff_queue[i];
+			break;
+		}
+	}
+
+	if (buff_queue_info == NULL) {
+		CPP_DBG("buffer queue entry for sess:%d strm:%d not found\n",
+			session_id, stream_id);
+	}
+	return buff_queue_info;
+}
+
+static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+	uint8_t native_buff, int32_t *fd)
+{
+	unsigned long phy_add = 0;
+	struct list_head *buff_head;
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+
+	if (native_buff)
+		buff_head = &buff_queue_info->native_buff_head;
+	else
+		buff_head = &buff_queue_info->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buff_index) {
+			phy_add = buff->map_info.phy_addr;
+			*fd = buff->map_info.buff_info.fd;
+			break;
+		}
+	}
+
+	return phy_add;
+}
+
+static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue,
+	struct msm_cpp_buffer_info_t *buffer_info)
+{
+	struct list_head *buff_head;
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+	int rc = 0;
+
+	if (buffer_info->native_buff)
+		buff_head = &buff_queue->native_buff_head;
+	else
+		buff_head = &buff_queue->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buffer_info->index) {
+			pr_err("error buf index already queued\n");
+			pr_err("error buf, fd %d idx %d native %d ssid %d %d\n",
+				buffer_info->fd, buffer_info->index,
+				buffer_info->native_buff,
+				buff_queue->session_id,
+				buff_queue->stream_id);
+			pr_err("existing buf,fd %d idx %d native %d id %x\n",
+				buff->map_info.buff_info.fd,
+				buff->map_info.buff_info.index,
+				buff->map_info.buff_info.native_buff,
+				buff->map_info.buff_info.identity);
+			goto error;
+		}
+	}
+
+	buff = kzalloc(
+		sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL);
+	if (!buff)
+		goto error;
+
+	buff->map_info.buff_info = *buffer_info;
+	buff->map_info.buf_fd = buffer_info->fd;
+
+	pr_debug("fd %d index %d native_buff %d ssid %d %d\n",
+		buffer_info->fd, buffer_info->index,
+		buffer_info->native_buff, buff_queue->session_id,
+		buff_queue->stream_id);
+
+	if (buff_queue->security_mode == SECURE_MODE)
+		rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl,
+			buffer_info->fd, CAM_SMMU_MAP_RW,
+			cpp_dev->ion_client, &buff->map_info.phy_addr,
+			(size_t *)&buff->map_info.len);
+	else
+		rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl,
+			buffer_info->fd, CAM_SMMU_MAP_RW,
+			&buff->map_info.phy_addr,
+			(size_t *)&buff->map_info.len);
+	if (rc < 0) {
+		pr_err("ION mmap for CPP buffer failed\n");
+		kzfree(buff);
+		goto error;
+	}
+
+	INIT_LIST_HEAD(&buff->entry);
+	list_add_tail(&buff->entry, buff_head);
+
+	return buff->map_info.phy_addr;
+error:
+	return 0;
+}
+
+static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue,
+	struct msm_cpp_buffer_map_list_t *buff)
+{
+	int ret = -1;
+
+	pr_debug("fd %d index %d native_buf %d ssid %d %d\n",
+		buff->map_info.buf_fd, buff->map_info.buff_info.index,
+		buff->map_info.buff_info.native_buff, buff_queue->session_id,
+		buff_queue->stream_id);
+
+	if (buff_queue->security_mode == SECURE_MODE)
+		ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl,
+			buff->map_info.buf_fd);
+	else
+		ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl,
+			buff->map_info.buf_fd);
+	if (ret < 0)
+		pr_err("Error: cannot put the iommu handle back to ion fd\n");
+
+	list_del_init(&buff->entry);
+	kzfree(buff);
+}
+
+static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev,
+	struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id,
+	uint32_t stream_id, int32_t *fd)
+{
+	unsigned long phy_addr = 0;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+	uint8_t native_buff = buffer_info->native_buff;
+
+	buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return phy_addr;
+	}
+
+	phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info,
+		buffer_info->index, native_buff, fd);
+	if ((phy_addr == 0) && (native_buff)) {
+		phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info,
+			buffer_info);
+		*fd = buffer_info->fd;
+	}
+
+	return phy_addr;
+}
+
+static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue_info)
+{
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+	struct list_head *buff_head;
+
+	buff_head = &buff_queue_info->native_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff);
+	}
+
+	buff_head = &buff_queue_info->vb2_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff);
+	}
+
+	return 0;
+}
+
+static int32_t msm_cpp_dequeue_buff(struct cpp_device *cpp_dev,
+	struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+	uint8_t native_buff)
+{
+	struct msm_cpp_buffer_map_list_t *buff, *save;
+	struct list_head *buff_head;
+
+	if (native_buff)
+		buff_head = &buff_queue_info->native_buff_head;
+	else
+		buff_head = &buff_queue_info->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buff_index) {
+			msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info,
+				buff);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev,
+	uint16_t session_id, uint16_t stream_id)
+{
+	uint32_t i;
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if (cpp_dev->buff_queue[i].used == 0) {
+			buff_queue_info = &cpp_dev->buff_queue[i];
+			buff_queue_info->used = 1;
+			buff_queue_info->session_id = session_id;
+			buff_queue_info->stream_id = stream_id;
+			buff_queue_info->security_mode =
+				cpp_dev->security_mode;
+			INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+			INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+			return 0;
+		}
+	}
+	pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+		session_id, stream_id);
+	return -EINVAL;
+}
+
+static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev,
+	uint32_t session_id, uint32_t stream_id)
+{
+	struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return -EINVAL;
+	}
+
+	buff_queue_info->used = 0;
+	buff_queue_info->session_id = 0;
+	buff_queue_info->stream_id = 0;
+	buff_queue_info->security_mode = NON_SECURE_MODE;
+	INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+	INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+	return 0;
+}
+
+static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev,
+	uint32_t num_buffq)
+{
+	struct msm_cpp_buff_queue_info_t *buff_queue;
+
+	buff_queue = kzalloc(
+		sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq,
+		GFP_KERNEL);
+	if (!buff_queue) {
+		pr_err("Buff queue allocation failure\n");
+		return -ENOMEM;
+	}
+
+	if (cpp_dev->buff_queue) {
+		pr_err("Buff queue not empty\n");
+		kzfree(buff_queue);
+		return -EINVAL;
+	}
+	cpp_dev->buff_queue = buff_queue;
+	cpp_dev->num_buffq = num_buffq;
+	return 0;
+}
+
+static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+
+	for (i = 0; i < cpp_dev->num_buffq; i++) {
+		if (cpp_dev->buff_queue[i].used == 1) {
+			pr_warn("Queue not free sessionid: %d, streamid: %d\n",
+				cpp_dev->buff_queue[i].session_id,
+				cpp_dev->buff_queue[i].stream_id);
+			msm_cpp_dequeue_buff_info_list
+				(cpp_dev, &cpp_dev->buff_queue[i]);
+			msm_cpp_free_buff_queue_entry(cpp_dev,
+				cpp_dev->buff_queue[i].session_id,
+				cpp_dev->buff_queue[i].stream_id);
+		}
+	}
+	kzfree(cpp_dev->buff_queue);
+	cpp_dev->buff_queue = NULL;
+	cpp_dev->num_buffq = 0;
+}
+
+static int32_t msm_cpp_poll(void __iomem *cpp_base, u32 val)
+{
+	uint32_t tmp, retry = 0;
+	int32_t rc = 0;
+
+	do {
+		tmp = msm_cpp_read(cpp_base);
+		if (tmp != 0xDEADBEEF)
+			CPP_LOW("poll: 0%x\n", tmp);
+		usleep_range(200, 250);
+	} while ((tmp != val) && (retry++ < MSM_CPP_POLL_RETRIES));
+	if (retry < MSM_CPP_POLL_RETRIES) {
+		CPP_LOW("Poll finished\n");
+	} else {
+		pr_err("Poll failed: expect: 0x%x\n", val);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int32_t msm_cpp_poll_rx_empty(void __iomem *cpp_base)
+{
+	uint32_t tmp, retry = 0;
+	int32_t rc = 0;
+
+	tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT);
+	while (((tmp & 0x2) != 0x0) && (retry++ < MSM_CPP_POLL_RETRIES)) {
+		/*
+		 * Below usleep values are chosen based on experiments
+		 * and this was the smallest number which works. This
+		 * sleep is needed to leave enough time for Microcontroller
+		 * to read rx fifo.
+		 */
+		usleep_range(200, 300);
+		tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT);
+	}
+
+	if (retry < MSM_CPP_POLL_RETRIES) {
+		CPP_LOW("Poll rx empty\n");
+	} else {
+		pr_err("Poll rx empty failed\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_cpp_dump_addr(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *frame_info)
+{
+	int32_t s_base, p_base;
+	uint32_t rd_off, wr0_off, wr1_off, wr2_off, wr3_off;
+	uint32_t wr0_mdata_off, wr1_mdata_off, wr2_mdata_off, wr3_mdata_off;
+	uint32_t rd_ref_off, wr_ref_off;
+	uint32_t s_size, p_size;
+	uint8_t tnr_enabled, ubwc_enabled, cds_en;
+	int32_t i = 0;
+	uint32_t *cpp_frame_msg;
+
+	cpp_frame_msg = frame_info->cpp_cmd_msg;
+
+	/* Update stripe/plane size and base offsets */
+	s_base = cpp_dev->payload_params.stripe_base;
+	s_size = cpp_dev->payload_params.stripe_size;
+	p_base = cpp_dev->payload_params.plane_base;
+	p_size = cpp_dev->payload_params.plane_size;
+
+	/* Fetch engine Offset */
+	rd_off = cpp_dev->payload_params.rd_pntr_off;
+	/* Write engine offsets */
+	wr0_off = cpp_dev->payload_params.wr_0_pntr_off;
+	wr1_off = wr0_off + 1;
+	wr2_off = wr1_off + 1;
+	wr3_off = wr2_off + 1;
+	/* Reference engine offsets */
+	rd_ref_off = cpp_dev->payload_params.rd_ref_pntr_off;
+	wr_ref_off = cpp_dev->payload_params.wr_ref_pntr_off;
+	/* Meta data offsets */
+	wr0_mdata_off =
+		cpp_dev->payload_params.wr_0_meta_data_wr_pntr_off;
+	wr1_mdata_off = (wr0_mdata_off + 1);
+	wr2_mdata_off = (wr1_mdata_off + 1);
+	wr3_mdata_off = (wr2_mdata_off + 1);
+
+	tnr_enabled = ((frame_info->feature_mask & TNR_MASK) >> 2);
+	ubwc_enabled = ((frame_info->feature_mask & UBWC_MASK) >> 5);
+	cds_en = ((frame_info->feature_mask & CDS_MASK) >> 6);
+
+	for (i = 0; i < frame_info->num_strips; i++) {
+		pr_err("stripe %d: in %x, out1 %x out2 %x, out3 %x, out4 %x\n",
+			i, cpp_frame_msg[s_base + rd_off + i * s_size],
+			cpp_frame_msg[s_base + wr0_off + i * s_size],
+			cpp_frame_msg[s_base + wr1_off + i * s_size],
+			cpp_frame_msg[s_base + wr2_off + i * s_size],
+			cpp_frame_msg[s_base + wr3_off + i * s_size]);
+
+		if (tnr_enabled) {
+			pr_err("stripe %d: read_ref %x, write_ref %x\n", i,
+				cpp_frame_msg[s_base + rd_ref_off + i * s_size],
+				cpp_frame_msg[s_base + wr_ref_off + i * s_size]
+				);
+		}
+
+		if (cds_en) {
+			pr_err("stripe %d:, dsdn_off %x\n", i,
+				cpp_frame_msg[s_base + rd_ref_off + i * s_size]
+				);
+		}
+
+		if (ubwc_enabled) {
+			pr_err("stripe %d: metadata %x, %x, %x, %x\n", i,
+				cpp_frame_msg[s_base + wr0_mdata_off +
+				i * s_size],
+				cpp_frame_msg[s_base + wr1_mdata_off +
+				i * s_size],
+				cpp_frame_msg[s_base + wr2_mdata_off +
+				i * s_size],
+				cpp_frame_msg[s_base + wr3_mdata_off +
+				i * s_size]
+				);
+		}
+
+	}
+	return 0;
+}
+
+static void msm_cpp_iommu_fault_reset_handler(
+	struct iommu_domain *domain, struct device *dev,
+	void *token)
+{
+	struct cpp_device *cpp_dev = NULL;
+
+	if (!token) {
+		pr_err("Invalid token\n");
+		return;
+	}
+
+	cpp_dev = token;
+
+	if (cpp_dev->fault_status != CPP_IOMMU_FAULT_NONE) {
+		pr_err("fault already detected %d\n", cpp_dev->fault_status);
+		return;
+	}
+
+	cpp_dev->fault_status = CPP_IOMMU_FAULT_DETECTED;
+
+	/* mask IRQ status */
+	msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC);
+
+	pr_err("Issue CPP HALT %d\n", cpp_dev->fault_status);
+
+	/* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
+	msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C);
+
+}
+
+static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
+	struct device *dev, unsigned long iova, int flags, void *token)
+{
+	struct cpp_device *cpp_dev = NULL;
+	struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
+	int32_t i = 0, queue_len = 0;
+	struct msm_device_queue *queue = NULL;
+	int32_t ifd, ofd, dfd, t0fd, t1fd;
+	int counter = 0;
+	u32 result;
+
+	if (token) {
+		cpp_dev = token;
+
+		if (cpp_dev->fault_status != CPP_IOMMU_FAULT_DETECTED) {
+			pr_err("fault recovery already done %d\n",
+				cpp_dev->fault_status);
+			return;
+		}
+
+		disable_irq(cpp_dev->irq->start);
+		if (atomic_read(&cpp_timer.used)) {
+			atomic_set(&cpp_timer.used, 0);
+			del_timer_sync(&cpp_timer.cpp_timer);
+		}
+		tasklet_kill(&cpp_dev->cpp_tasklet);
+
+		pr_err("in recovery, HALT status = 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+		while (counter < MSM_CPP_POLL_RETRIES) {
+			result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
+			if (result & 0x2)
+				break;
+			usleep_range(100, 200);
+			counter++;
+		}
+		/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+		pr_err("counter %d HALT status later = 0x%x\n",
+			counter,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+		/* MMSS_A_CPP_RST_CMD_0 = 0x8 firmware reset = 0x3FFFF */
+		msm_camera_io_w(0x3FFFF, cpp_dev->cpp_hw_base + 0x8);
+
+		counter = 0;
+		while (counter < MSM_CPP_POLL_RETRIES) {
+			result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
+			if (result & 0x1)
+				break;
+			usleep_range(100, 200);
+			counter++;
+		}
+
+		/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+		pr_err("counter %d after reset IRQ_STATUS_0 = 0x%x\n",
+			counter,
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+		/* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
+		msm_camera_io_w(0x0, cpp_dev->cpp_hw_base + 0x16C);
+
+		queue = &cpp_timer.data.cpp_dev->processing_q;
+		queue_len = queue->len;
+		if (!queue_len)
+			pr_err("%s:%d: Invalid queuelen\n", __func__, __LINE__);
+
+		for (i = 0; i < queue_len; i++) {
+			if (cpp_timer.data.processed_frame[i]) {
+				processed_frame[i] =
+					cpp_timer.data.processed_frame[i];
+				ifd = processed_frame[i]->input_buffer_info.fd;
+				ofd = processed_frame[i]->
+					output_buffer_info[0].fd;
+				dfd = processed_frame[i]->
+					duplicate_buffer_info.fd;
+				t0fd = processed_frame[i]->
+					tnr_scratch_buffer_info[0].fd;
+				t1fd = processed_frame[i]->
+					tnr_scratch_buffer_info[1].fd;
+				pr_err("Fault on identity=0x%x, frame_id=%03d\n",
+					processed_frame[i]->identity,
+					processed_frame[i]->frame_id);
+				pr_err("ifd %d ofd %d dfd %d t0fd %d t1fd %d\n",
+					ifd, ofd, dfd, t0fd, t1fd);
+				msm_cpp_dump_addr(cpp_dev, processed_frame[i]);
+				msm_cpp_dump_frame_cmd(processed_frame[i]);
+			}
+		}
+		msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
+		cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED;
+		pr_err("fault recovery successful\n");
+	}
+}
+
+static int cpp_init_mem(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+	int iommu_hdl;
+
+	if (cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_5_0_0 ||
+		cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_5_1_0)
+		rc = cam_smmu_get_handle("cpp_0", &iommu_hdl);
+	else
+		rc = cam_smmu_get_handle("cpp", &iommu_hdl);
+
+	if (rc < 0) {
+		pr_err("smmu get handle failed\n");
+		return -ENODEV;
+	}
+
+	cpp_dev->iommu_hdl = iommu_hdl;
+	cam_smmu_reg_client_page_fault_handler(
+			cpp_dev->iommu_hdl,
+			msm_cpp_iommu_fault_handler,
+			msm_cpp_iommu_fault_reset_handler,
+			cpp_dev);
+	return 0;
+}
+
+
+static irqreturn_t msm_cpp_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t tx_level;
+	uint32_t irq_status;
+	uint32_t i;
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+	struct cpp_device *cpp_dev = data;
+	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+
+	irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT);
+
+	if (irq_status & 0x8) {
+		tx_level = msm_camera_io_r(cpp_dev->base +
+			MSM_CPP_MICRO_FIFO_TX_STAT) >> 2;
+		for (i = 0; i < tx_level; i++) {
+			tx_fifo[i] = msm_camera_io_r(cpp_dev->base +
+				MSM_CPP_MICRO_FIFO_TX_DATA);
+		}
+		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+		queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx];
+		if (queue_cmd->cmd_used) {
+			pr_err("%s:%d] cpp tasklet queue overflow tx %d rc %x",
+				__func__, __LINE__, tx_level, irq_status);
+			list_del(&queue_cmd->list);
+		} else {
+			atomic_add(1, &cpp_dev->irq_cnt);
+		}
+		queue_cmd->irq_status = irq_status;
+		queue_cmd->tx_level = tx_level;
+		memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo));
+		for (i = 0; i < tx_level; i++)
+			queue_cmd->tx_fifo[i] = tx_fifo[i];
+
+		queue_cmd->cmd_used = 1;
+		cpp_dev->taskletq_idx =
+			(cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE;
+		list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q);
+		spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
+		tasklet_schedule(&cpp_dev->cpp_tasklet);
+	} else if (irq_status & 0x7C0) {
+		pr_debug("irq_status: 0x%x\n", irq_status);
+		pr_debug("DEBUG_SP: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x40));
+		pr_debug("DEBUG_T: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x44));
+		pr_debug("DEBUG_N: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x48));
+		pr_debug("DEBUG_R: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x4C));
+		pr_debug("DEBUG_OPPC: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x50));
+		pr_debug("DEBUG_MO: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x54));
+		pr_debug("DEBUG_TIMER0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x60));
+		pr_debug("DEBUG_TIMER1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x64));
+		pr_debug("DEBUG_GPI: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x70));
+		pr_debug("DEBUG_GPO: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x74));
+		pr_debug("DEBUG_T0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x80));
+		pr_debug("DEBUG_R0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x84));
+		pr_debug("DEBUG_T1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x88));
+		pr_debug("DEBUG_R1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->base + 0x8C));
+	}
+	msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR);
+	return IRQ_HANDLED;
+}
+
+static void msm_cpp_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	uint32_t irq_status;
+	uint32_t tx_level;
+	uint32_t msg_id, cmd_len;
+	uint32_t i;
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+	struct cpp_device *cpp_dev = (struct cpp_device *) data;
+	struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+
+	while (atomic_read(&cpp_dev->irq_cnt)) {
+		spin_lock_irqsave(&cpp_dev->tasklet_lock, flags);
+		queue_cmd = list_first_entry(&cpp_dev->tasklet_q,
+		struct msm_cpp_tasklet_queue_cmd, list);
+
+		if (!queue_cmd) {
+			atomic_set(&cpp_dev->irq_cnt, 0);
+			spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+			return;
+		}
+		atomic_sub(1, &cpp_dev->irq_cnt);
+		list_del(&queue_cmd->list);
+		queue_cmd->cmd_used = 0;
+		irq_status = queue_cmd->irq_status;
+		tx_level = queue_cmd->tx_level;
+		for (i = 0; i < tx_level; i++)
+			tx_fifo[i] = queue_cmd->tx_fifo[i];
+
+		spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags);
+
+		for (i = 0; i < tx_level; i++) {
+			if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) {
+				cmd_len = tx_fifo[i+1];
+				msg_id = tx_fifo[i+2];
+				if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
+					CPP_DBG("Frame done!!\n");
+					/* delete CPP timer */
+					CPP_DBG("delete timer.\n");
+					msm_cpp_timer_queue_update(cpp_dev);
+					msm_cpp_notify_frame_done(cpp_dev, 0);
+				} else if (msg_id ==
+					MSM_CPP_MSG_ID_FRAME_NACK) {
+					pr_err("NACK error from hw!!\n");
+					CPP_DBG("delete timer.\n");
+					msm_cpp_timer_queue_update(cpp_dev);
+					msm_cpp_notify_frame_done(cpp_dev, 0);
+				}
+				i += cmd_len + 2;
+			}
+		}
+	}
+}
+
+static int cpp_init_hardware(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+	uint32_t vbif_version;
+
+	cpp_dev->turbo_vote = 0;
+	cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE;
+
+	rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd,
+		cpp_dev->num_reg, true);
+	if (rc < 0) {
+		pr_err("%s: failed to enable regulators\n", __func__);
+		goto reg_enable_failed;
+	}
+
+	if (cpp_dev->micro_reset) {
+		rc = msm_cpp_set_micro_clk(cpp_dev);
+		if (rc < 0) {
+			pr_err("%s: reset micro clk failed\n", __func__);
+			goto clk_failed;
+		}
+	}
+
+	rc = msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info,
+			cpp_dev->cpp_clk, cpp_dev->num_clks, true);
+	if (rc < 0) {
+		pr_err("%s: clk enable failed\n", __func__);
+		goto clk_failed;
+	}
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		goto ahb_vote_fail;
+	}
+
+	if (cpp_dev->state != CPP_STATE_BOOT) {
+		rc = msm_camera_register_irq(cpp_dev->pdev, cpp_dev->irq,
+			msm_cpp_irq, IRQF_TRIGGER_RISING, "cpp", cpp_dev);
+		if (rc < 0) {
+			pr_err("%s: irq request fail\n", __func__);
+			goto req_irq_fail;
+		}
+		rc = msm_cam_buf_mgr_register_ops(&cpp_dev->buf_mgr_ops);
+		if (rc < 0) {
+			pr_err("buf mngr req ops failed\n");
+			msm_camera_unregister_irq(cpp_dev->pdev,
+				cpp_dev->irq, cpp_dev);
+			goto req_irq_fail;
+		}
+	}
+
+	cpp_dev->hw_info.cpp_hw_version =
+		msm_camera_io_r(cpp_dev->cpp_hw_base);
+	if (cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_4_1_0) {
+		vbif_version = msm_camera_io_r(cpp_dev->vbif_base);
+		if (vbif_version == VBIF_VERSION_2_3_0)
+			cpp_dev->hw_info.cpp_hw_version = CPP_HW_VERSION_4_0_0;
+	}
+	pr_info("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version);
+	cpp_dev->hw_info.cpp_hw_caps =
+		msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
+
+	rc = msm_update_freq_tbl(cpp_dev);
+	if (rc < 0)
+		goto pwr_collapse_reset;
+
+	pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
+	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
+	cpp_dev->taskletq_idx = 0;
+	atomic_set(&cpp_dev->irq_cnt, 0);
+	rc = msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
+	if (rc < 0) {
+		pr_err("%s: create buff queue failed with err %d\n",
+			__func__, rc);
+		goto pwr_collapse_reset;
+	}
+	pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt);
+	cpp_dev->stream_cnt = 0;
+	if (cpp_dev->fw_name_bin) {
+		msm_camera_enable_irq(cpp_dev->irq, false);
+		rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+		if (rc < 0) {
+			pr_err("%s: load firmware failure %d-retry\n",
+				__func__, rc);
+			rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+			if (rc < 0) {
+				msm_camera_enable_irq(cpp_dev->irq, true);
+				goto pwr_collapse_reset;
+			}
+		}
+		msm_camera_enable_irq(cpp_dev->irq, true);
+		msm_camera_io_w_mb(0x7C8, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_MASK);
+		msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+			MSM_CPP_MICRO_IRQGEN_CLR);
+	}
+
+	msm_cpp_set_vbif_reg_values(cpp_dev);
+	return rc;
+
+pwr_collapse_reset:
+	msm_cpp_update_gdscr_status(cpp_dev, false);
+	msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev);
+req_irq_fail:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+ahb_vote_fail:
+	msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info,
+		cpp_dev->cpp_clk, cpp_dev->num_clks, false);
+clk_failed:
+	msm_camera_regulator_enable(cpp_dev->cpp_vdd,
+		cpp_dev->num_reg, false);
+reg_enable_failed:
+	return rc;
+}
+
+static void cpp_release_hardware(struct cpp_device *cpp_dev)
+{
+	int32_t rc;
+
+	if (cpp_dev->state != CPP_STATE_BOOT) {
+		msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev);
+		tasklet_kill(&cpp_dev->cpp_tasklet);
+		atomic_set(&cpp_dev->irq_cnt, 0);
+	}
+	msm_cpp_delete_buff_queue(cpp_dev);
+	msm_cpp_update_gdscr_status(cpp_dev, false);
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info,
+		cpp_dev->cpp_clk, cpp_dev->num_clks, false);
+	msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, false);
+	if (cpp_dev->stream_cnt > 0) {
+		pr_warn("stream count active\n");
+		rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 0);
+	}
+	cpp_dev->stream_cnt = 0;
+	pr_info("cpp hw release done\n");
+}
+
+static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
+{
+	uint32_t i;
+	uint32_t *ptr_bin = NULL;
+	int32_t rc = 0, ret = 0;
+
+	if (!fw_name_bin) {
+		pr_err("%s:%d] invalid fw name", __func__, __LINE__);
+		rc = -EINVAL;
+		goto end;
+	}
+	pr_debug("%s:%d] FW file: %s\n", __func__, __LINE__, fw_name_bin);
+	if (cpp_dev->fw == NULL) {
+		pr_err("%s:%d] fw NULL", __func__, __LINE__);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	ptr_bin = (uint32_t *)cpp_dev->fw->data;
+	if (!ptr_bin) {
+		pr_err("%s:%d] Fw bin NULL", __func__, __LINE__);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+			CAM_AHB_NOMINAL_VOTE);
+	if (rc < 0) {
+		pr_err("%s:%d: failed to vote for AHB\n", __func__, __LINE__);
+		goto end;
+	}
+
+	msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+	msm_camera_io_w(0x1, cpp_dev->base +
+			 MSM_CPP_MICRO_BOOT_START);
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_CMD, rc);
+		goto vote;
+	}
+
+	msm_camera_io_w(0xFFFFFFFF, cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_CLR);
+
+	rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+	if (rc) {
+		pr_err("%s:%d] poll rx empty failed %d",
+			__func__, __LINE__, rc);
+		goto vote;
+	}
+	/*Start firmware loading*/
+	msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
+	msm_cpp_write(cpp_dev->fw->size, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
+	rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+	if (rc) {
+		pr_err("%s:%d] poll rx empty failed %d",
+			__func__, __LINE__, rc);
+		goto vote;
+	}
+	for (i = 0; i < cpp_dev->fw->size/4; i++) {
+		msm_cpp_write(*ptr_bin, cpp_dev->base);
+		if (i % MSM_CPP_RX_FIFO_LEVEL == 0) {
+			rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+			if (rc) {
+				pr_err("%s:%d] poll rx empty failed %d",
+					__func__, __LINE__, rc);
+				goto vote;
+			}
+		}
+		ptr_bin++;
+	}
+	msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC);
+	rc = msm_cpp_update_gdscr_status(cpp_dev, true);
+	if (rc < 0)
+		pr_err("update cpp gdscr status failed\n");
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_OK, rc);
+		goto vote;
+	}
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_CMD, rc);
+		goto vote;
+	}
+
+	rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+	if (rc) {
+		pr_err("%s:%d] poll rx empty failed %d",
+			__func__, __LINE__, rc);
+		goto vote;
+	}
+	/*Trigger MC to jump to start address*/
+	msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_CMD, rc);
+		goto vote;
+	}
+
+	rc = msm_cpp_poll(cpp_dev->base, 0x1);
+	if (rc) {
+		pr_err("%s:%d] poll command 0x1 failed %d", __func__, __LINE__,
+			rc);
+		goto vote;
+	}
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_JUMP_ACK, rc);
+		goto vote;
+	}
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_JUMP_ACK, rc);
+	}
+
+vote:
+	ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+			CAM_AHB_SVS_VOTE);
+	if (ret < 0) {
+		pr_err("%s:%d: failed to vote for AHB\n", __func__, __LINE__);
+		rc = ret;
+	}
+end:
+	return rc;
+}
+
+static int32_t msm_cpp_reset_vbif_clients(struct cpp_device *cpp_dev)
+{
+	uint32_t i;
+
+	pr_warn("%s: handle vbif hang...\n", __func__);
+	for (i = 0; i < VBIF_CLIENT_MAX; i++) {
+		if (cpp_dev->vbif_data->err_handler[i] == NULL)
+			continue;
+
+		cpp_dev->vbif_data->err_handler[i](
+			cpp_dev->vbif_data->dev[i], CPP_VBIF_ERROR_HANG);
+	}
+	return 0;
+}
+
+static int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev)
+{
+	int32_t rc = 0;
+
+	msm_cpp_reset_vbif_clients(cpp_dev);
+
+	rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+	if (rc < 0)
+		pr_err("Reset and load fw failed %d\n", rc);
+
+	return rc;
+}
+
+static int cpp_vbif_error_handler(void *dev, uint32_t vbif_error)
+{
+	struct cpp_device *cpp_dev = NULL;
+
+	if (dev == NULL || vbif_error >= CPP_VBIF_ERROR_MAX) {
+		pr_err("failed: dev %pK, vbif error %d\n", dev, vbif_error);
+		return -EINVAL;
+	}
+
+	cpp_dev = (struct cpp_device *) dev;
+
+	/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+	pr_err("%s: before reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
+		__func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+	pr_err("%s: start reset bus bridge on FD + CPP!\n", __func__);
+	/* MMSS_A_CPP_RST_CMD_0 = 0x8,  firmware reset = 0x3DF77 */
+	msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8);
+
+	/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+	pr_err("%s: after reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
+		__func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+	return 0;
+}
+
+static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc;
+	uint32_t i;
+	struct cpp_device *cpp_dev = NULL;
+
+	CPP_DBG("E");
+
+	if (!sd || !fh) {
+		pr_err("Wrong input parameters sd %pK fh %pK!",
+			sd, fh);
+		return -EINVAL;
+	}
+	cpp_dev = v4l2_get_subdevdata(sd);
+	if (!cpp_dev) {
+		pr_err("failed: cpp_dev %pK\n", cpp_dev);
+		return -EINVAL;
+	}
+	mutex_lock(&cpp_dev->mutex);
+	if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("No free CPP instance\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+		if (cpp_dev->cpp_subscribe_list[i].active == 0) {
+			cpp_dev->cpp_subscribe_list[i].active = 1;
+			cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("No free instance\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	CPP_DBG("open %d %pK\n", i, &fh->vfh);
+	cpp_dev->cpp_open_cnt++;
+
+	msm_cpp_vbif_register_error_handler(cpp_dev,
+		VBIF_CLIENT_CPP, cpp_vbif_error_handler);
+
+	if (cpp_dev->cpp_open_cnt == 1) {
+		rc = cpp_init_hardware(cpp_dev);
+		if (rc < 0) {
+			cpp_dev->cpp_open_cnt--;
+			cpp_dev->cpp_subscribe_list[i].active = 0;
+			cpp_dev->cpp_subscribe_list[i].vfh = NULL;
+			mutex_unlock(&cpp_dev->mutex);
+			return rc;
+		}
+
+		rc = cpp_init_mem(cpp_dev);
+		if (rc < 0) {
+			pr_err("Error: init memory fail\n");
+			cpp_dev->cpp_open_cnt--;
+			cpp_dev->cpp_subscribe_list[i].active = 0;
+			cpp_dev->cpp_subscribe_list[i].vfh = NULL;
+			mutex_unlock(&cpp_dev->mutex);
+			return rc;
+		}
+
+		cpp_dev->state = CPP_STATE_IDLE;
+
+		CPP_DBG("Invoking msm_ion_client_create()\n");
+		cpp_dev->ion_client = msm_ion_client_create("cpp");
+		if (cpp_dev->ion_client == NULL) {
+			pr_err("msm_ion_client_create() failed\n");
+			mutex_unlock(&cpp_dev->mutex);
+			rc = -ENOMEM;
+		}
+	}
+
+	mutex_unlock(&cpp_dev->mutex);
+	return 0;
+}
+
+static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	uint32_t i;
+	int rc = -1;
+	struct cpp_device *cpp_dev = NULL;
+	struct msm_device_queue *processing_q = NULL;
+	struct msm_device_queue *eventData_q = NULL;
+
+	if (!sd) {
+		pr_err("Wrong input sd parameter");
+		return -EINVAL;
+	}
+	cpp_dev =  v4l2_get_subdevdata(sd);
+
+	if (!cpp_dev) {
+		pr_err("failed: cpp_dev %pK\n", cpp_dev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&cpp_dev->mutex);
+
+	processing_q = &cpp_dev->processing_q;
+	eventData_q = &cpp_dev->eventData_q;
+
+	if (cpp_dev->cpp_open_cnt == 0) {
+		mutex_unlock(&cpp_dev->mutex);
+		return 0;
+	}
+
+	for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+		if (cpp_dev->cpp_subscribe_list[i].active == 1) {
+			cpp_dev->cpp_subscribe_list[i].active = 0;
+			cpp_dev->cpp_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_CPP_INSTANCE) {
+		pr_err("Invalid close\n");
+		mutex_unlock(&cpp_dev->mutex);
+		return -ENODEV;
+	}
+
+	if (cpp_dev->turbo_vote == 1) {
+		rc = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false);
+			if (rc)
+				pr_err("cx_ipeak_update failed");
+			else
+				cpp_dev->turbo_vote = 0;
+	}
+
+	cpp_dev->cpp_open_cnt--;
+	if (cpp_dev->cpp_open_cnt == 0) {
+		pr_debug("irq_status: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
+		pr_debug("DEBUG_SP: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
+		pr_debug("DEBUG_T: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
+		pr_debug("DEBUG_N: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
+		pr_debug("DEBUG_R: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
+		pr_debug("DEBUG_OPPC: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
+		pr_debug("DEBUG_MO: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
+		pr_debug("DEBUG_TIMER0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
+		pr_debug("DEBUG_TIMER1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
+		pr_debug("DEBUG_GPI: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
+		pr_debug("DEBUG_GPO: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
+		pr_debug("DEBUG_T0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
+		pr_debug("DEBUG_R0: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
+		pr_debug("DEBUG_T1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
+		pr_debug("DEBUG_R1: 0x%x\n",
+			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
+		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+		msm_cpp_clear_timer(cpp_dev);
+		cpp_release_hardware(cpp_dev);
+		if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) {
+			if (cpp_dev->security_mode == SECURE_MODE)
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_DETACH_SEC_CPP);
+			else
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_DETACH);
+
+			if (rc < 0)
+				pr_err("Error: Detach fail in release\n");
+			cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED;
+		}
+		cam_smmu_destroy_handle(cpp_dev->iommu_hdl);
+		msm_cpp_empty_list(processing_q, list_frame);
+		msm_cpp_empty_list(eventData_q, list_eventdata);
+		cpp_dev->state = CPP_STATE_OFF;
+
+		if (cpp_dev->ion_client) {
+			CPP_DBG("Invoking ion_client_destroy()\n");
+			ion_client_destroy(cpp_dev->ion_client);
+			cpp_dev->ion_client = NULL;
+		}
+	}
+
+	/* unregister vbif error handler */
+	msm_cpp_vbif_register_error_handler(cpp_dev,
+		VBIF_CLIENT_CPP, NULL);
+	mutex_unlock(&cpp_dev->mutex);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = {
+	.open = cpp_open_node,
+	.close = cpp_close_node,
+};
+
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, uint32_t ids,
+	void *arg)
+{
+	int rc = -EINVAL;
+
+	switch (buff_mgr_ops) {
+	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
+		rc = msm_cpp_buffer_private_ops(cpp_dev, buff_mgr_ops,
+			ids, arg);
+		break;
+	}
+	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
+	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
+	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
+	default: {
+		struct msm_buf_mngr_info *buff_mgr_info =
+			(struct msm_buf_mngr_info *)arg;
+		rc = cpp_dev->buf_mgr_ops.msm_cam_buf_mgr_ops(buff_mgr_ops,
+			buff_mgr_info);
+		break;
+	}
+	}
+	if (rc < 0)
+		pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
+	uint8_t put_buf)
+{
+	struct v4l2_event v4l2_evt;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_queue_cmd *event_qcmd = NULL;
+	struct msm_cpp_frame_info_t *processed_frame = NULL;
+	struct msm_device_queue *queue = &cpp_dev->processing_q;
+	struct msm_buf_mngr_info buff_mgr_info;
+	int rc = 0;
+
+	frame_qcmd = msm_dequeue(queue, list_frame, POP_FRONT);
+	if (frame_qcmd) {
+		processed_frame = frame_qcmd->command;
+		do_gettimeofday(&(processed_frame->out_time));
+		kfree(frame_qcmd);
+		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+		if (!event_qcmd) {
+			pr_err("Insufficient memory\n");
+			return -ENOMEM;
+		}
+		atomic_set(&event_qcmd->on_heap, 1);
+		event_qcmd->command = processed_frame;
+		CPP_DBG("fid %d\n", processed_frame->frame_id);
+		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
+
+		if ((processed_frame->partial_frame_indicator != 0) &&
+			(processed_frame->last_payload == 0))
+			goto NOTIFY_FRAME_DONE;
+
+		if (!processed_frame->output_buffer_info[0].processed_divert &&
+			!processed_frame->output_buffer_info[0].native_buff &&
+			!processed_frame->we_disable) {
+
+			int32_t iden = processed_frame->identity;
+
+			SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame,
+				iden, processed_frame->duplicate_identity);
+
+			memset(&buff_mgr_info, 0,
+				sizeof(struct msm_buf_mngr_info));
+
+			buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id = (iden & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			if (processed_frame->batch_info.batch_mode ==
+				BATCH_MODE_VIDEO ||
+				(IS_BATCH_BUFFER_ON_PREVIEW(
+				processed_frame))) {
+				buff_mgr_info.index =
+					processed_frame->batch_info.cont_idx;
+			} else {
+				buff_mgr_info.index = processed_frame->
+					output_buffer_info[0].index;
+			}
+			if (put_buf) {
+				rc = msm_cpp_buffer_ops(cpp_dev,
+					VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+					0x0, &buff_mgr_info);
+				if (rc < 0) {
+					pr_err("error putting buffer\n");
+					rc = -EINVAL;
+				}
+			} else {
+				rc = msm_cpp_buffer_ops(cpp_dev,
+					VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+					0x0, &buff_mgr_info);
+				if (rc < 0) {
+					pr_err("error putting buffer\n");
+					rc = -EINVAL;
+				}
+			}
+		}
+
+		if (processed_frame->duplicate_output  &&
+			!processed_frame->
+				duplicate_buffer_info.processed_divert &&
+			!processed_frame->we_disable) {
+			int32_t iden = processed_frame->duplicate_identity;
+
+			SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame,
+				iden, processed_frame->identity);
+
+			memset(&buff_mgr_info, 0,
+				sizeof(struct msm_buf_mngr_info));
+
+			buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id = (iden & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->duplicate_buffer_info.index;
+			if (put_buf) {
+				rc = msm_cpp_buffer_ops(cpp_dev,
+					VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+					0x0, &buff_mgr_info);
+				if (rc < 0) {
+					pr_err("error putting buffer\n");
+					rc = -EINVAL;
+				}
+			} else {
+				rc = msm_cpp_buffer_ops(cpp_dev,
+					VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+					0x0, &buff_mgr_info);
+				if (rc < 0) {
+					pr_err("error putting buffer\n");
+					rc = -EINVAL;
+				}
+			}
+		}
+NOTIFY_FRAME_DONE:
+		v4l2_evt.id = processed_frame->inst_id;
+		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
+		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
+	}
+	return rc;
+}
+
+#if MSM_CPP_DUMP_FRM_CMD
+static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info)
+{
+	int i, i1, i2;
+	struct cpp_device *cpp_dev = cpp_timer.data.cpp_dev;
+
+	CPP_DBG("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n",
+		frame_info->identity, frame_info->frame_id);
+
+	CPP_DBG("msg[%03d] = 0x%08x\n", 0, 0x6);
+	/* send top level and plane level */
+	for (i = 0; i < cpp_dev->payload_params.stripe_base; i++)
+		CPP_DBG("msg[%03d] = 0x%08x\n", i,
+			frame_info->cpp_cmd_msg[i]);
+	/* send stripes */
+	i1 = cpp_dev->payload_params.stripe_base +
+		cpp_dev->payload_params.stripe_size *
+		frame_info->first_stripe_index;
+	i2 = cpp_dev->payload_params.stripe_size *
+		(frame_info->last_stripe_index -
+		frame_info->first_stripe_index + 1);
+	for (i = 0; i < i2; i++)
+		CPP_DBG("msg[%03d] = 0x%08x\n", i+i1,
+			frame_info->cpp_cmd_msg[i+i1]);
+	/* send trailer */
+	CPP_DBG("msg[%03d] = 0x%08x\n", i+i1, MSM_CPP_MSG_ID_TRAILER);
+	CPP_DBG("--   end: cpp frame cmd for identity=0x%x, frame_id=%d --\n",
+		frame_info->identity, frame_info->frame_id);
+	return 0;
+}
+#else
+static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info)
+{
+	return 0;
+}
+#endif
+
+static void msm_cpp_flush_queue_and_release_buffer(struct cpp_device *cpp_dev,
+	int queue_len) {
+	uint32_t i;
+
+	while (queue_len) {
+		msm_cpp_notify_frame_done(cpp_dev, 1);
+		queue_len--;
+	}
+	atomic_set(&cpp_timer.used, 0);
+	for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
+		cpp_timer.data.processed_frame[i] = NULL;
+}
+
+static void msm_cpp_set_micro_irq_mask(struct cpp_device *cpp_dev,
+	uint8_t enable, uint32_t irq_mask)
+{
+	msm_camera_io_w_mb(irq_mask, cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_MASK);
+	msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_CLR);
+	if (enable)
+		enable_irq(cpp_dev->irq->start);
+}
+
+static void msm_cpp_do_timeout_work(struct work_struct *work)
+{
+	uint32_t j = 0, i = 0, i1 = 0, i2 = 0;
+	int32_t queue_len = 0, rc = 0, fifo_counter = 0;
+	struct msm_device_queue *queue = NULL;
+	struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
+	struct cpp_device *cpp_dev = cpp_timer.data.cpp_dev;
+
+	pr_warn("cpp_timer_callback called. (jiffies=%lu)\n",
+		jiffies);
+	mutex_lock(&cpp_dev->mutex);
+
+	if (!work || (cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE)) {
+		pr_err("Invalid work:%pK or state:%d\n", work,
+			cpp_timer.data.cpp_dev->state);
+		/* Do not flush queue here as it is not a fatal error */
+		goto end;
+	}
+	if (!atomic_read(&cpp_timer.used)) {
+		pr_warn("Delayed trigger, IRQ serviced\n");
+		/* Do not flush queue here as it is not a fatal error */
+		goto end;
+	}
+
+	msm_camera_enable_irq(cpp_timer.data.cpp_dev->irq, false);
+	/* make sure all the pending queued entries are scheduled */
+	tasklet_kill(&cpp_dev->cpp_tasklet);
+
+	queue = &cpp_timer.data.cpp_dev->processing_q;
+	queue_len = queue->len;
+	if (!queue_len) {
+		pr_err("%s:%d: irq serviced after timeout.Ignore timeout\n",
+			__func__, __LINE__);
+		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+		goto end;
+	}
+
+	pr_debug("Reloading firmware %d\n", queue_len);
+	rc = cpp_load_fw(cpp_timer.data.cpp_dev,
+		cpp_timer.data.cpp_dev->fw_name_bin);
+	if (rc) {
+		pr_warn("Firmware loading failed-retry\n");
+		rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+		if (rc < 0) {
+			pr_err("Firmware loading failed\n");
+			goto error;
+		}
+	} else {
+		pr_debug("Firmware loading done\n");
+	}
+
+	if (!atomic_read(&cpp_timer.used)) {
+		pr_warn("Delayed trigger, IRQ serviced\n");
+		/* Do not flush queue here as it is not a fatal error */
+		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+		cpp_dev->timeout_trial_cnt = 0;
+		goto end;
+	}
+
+	if (cpp_dev->timeout_trial_cnt >=
+		cpp_dev->max_timeout_trial_cnt) {
+		pr_warn("Max trial reached\n");
+		msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
+		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+		goto end;
+	}
+
+	for (i = 0; i < queue_len; i++) {
+		processed_frame[i] = cpp_timer.data.processed_frame[i];
+		if (!processed_frame[i]) {
+			pr_warn("process frame null , queue len %d", queue_len);
+			msm_cpp_flush_queue_and_release_buffer(cpp_dev,
+				queue_len);
+			msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+			goto end;
+		}
+	}
+
+	atomic_set(&cpp_timer.used, 1);
+	pr_warn("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+		CPP_CMD_TIMEOUT_MS, jiffies);
+	mod_timer(&cpp_timer.cpp_timer,
+		jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
+
+	msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+
+	for (i = 0; i < queue_len; i++) {
+		pr_warn("Rescheduling for identity=0x%x, frame_id=%03d\n",
+			processed_frame[i]->identity,
+			processed_frame[i]->frame_id);
+
+		rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+		if (rc) {
+			pr_err("%s:%d: Reschedule payload failed %d\n",
+				__func__, __LINE__, rc);
+			goto error;
+		}
+		msm_cpp_write(0x6, cpp_dev->base);
+		fifo_counter++;
+		/* send top level and plane level */
+		for (j = 0; j < cpp_dev->payload_params.stripe_base; j++,
+			fifo_counter++) {
+			if (fifo_counter % MSM_CPP_RX_FIFO_LEVEL == 0) {
+				rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+				if (rc) {
+					pr_err("%s:%d] poll failed %d rc %d",
+						__func__, __LINE__, j, rc);
+					goto error;
+				}
+				fifo_counter = 0;
+			}
+			msm_cpp_write(processed_frame[i]->cpp_cmd_msg[j],
+				cpp_dev->base);
+		}
+		if (rc) {
+			pr_err("%s:%d: Rescheduling plane info failed %d\n",
+				__func__, __LINE__, rc);
+			goto error;
+		}
+		/* send stripes */
+		i1 = cpp_dev->payload_params.stripe_base +
+			cpp_dev->payload_params.stripe_size *
+			processed_frame[i]->first_stripe_index;
+		i2 = cpp_dev->payload_params.stripe_size *
+			(processed_frame[i]->last_stripe_index -
+			processed_frame[i]->first_stripe_index + 1);
+		for (j = 0; j < i2; j++, fifo_counter++) {
+			if (fifo_counter % MSM_CPP_RX_FIFO_LEVEL == 0) {
+				rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+				if (rc) {
+					pr_err("%s:%d] poll failed %d rc %d",
+						__func__, __LINE__, j, rc);
+					break;
+				}
+				fifo_counter = 0;
+			}
+			msm_cpp_write(processed_frame[i]->cpp_cmd_msg[j+i1],
+				cpp_dev->base);
+		}
+		if (rc) {
+			pr_err("%s:%d] Rescheduling stripe info failed %d\n",
+				__func__, __LINE__, rc);
+			goto error;
+		}
+		/* send trailer */
+
+		if (fifo_counter % MSM_CPP_RX_FIFO_LEVEL == 0) {
+			rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+			if (rc) {
+				pr_err("%s:%d] Reschedule trailer failed %d\n",
+					__func__, __LINE__, rc);
+				goto error;
+			}
+			fifo_counter = 0;
+		}
+		msm_cpp_write(0xabcdefaa, cpp_dev->base);
+		pr_debug("After frame:%d write\n", i+1);
+	}
+
+	cpp_timer.data.cpp_dev->timeout_trial_cnt++;
+
+end:
+	mutex_unlock(&cpp_dev->mutex);
+	pr_debug("%s:%d] exit\n", __func__, __LINE__);
+	return;
+error:
+	cpp_dev->state = CPP_STATE_OFF;
+	/* flush the queue */
+	msm_cpp_flush_queue_and_release_buffer(cpp_dev,
+		queue_len);
+	msm_cpp_set_micro_irq_mask(cpp_dev, 0, 0x0);
+	cpp_dev->timeout_trial_cnt = 0;
+	mutex_unlock(&cpp_dev->mutex);
+	pr_debug("%s:%d] exit\n", __func__, __LINE__);
+}
+
+static void cpp_timer_callback(unsigned long data)
+{
+	struct msm_cpp_work_t *work =
+		cpp_timer.data.cpp_dev->work;
+	queue_work(cpp_timer.data.cpp_dev->timer_wq,
+		(struct work_struct *)work);
+}
+
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
+	struct msm_queue_cmd *frame_qcmd)
+{
+	unsigned long flags;
+	uint32_t i, i1, i2;
+	int32_t rc = -EAGAIN;
+	struct msm_cpp_frame_info_t *process_frame;
+	struct msm_queue_cmd *qcmd = NULL;
+	uint32_t queue_len = 0, fifo_counter = 0;
+
+	if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
+		process_frame = frame_qcmd->command;
+		msm_cpp_dump_frame_cmd(process_frame);
+		spin_lock_irqsave(&cpp_timer.data.processed_frame_lock, flags);
+		msm_enqueue(&cpp_dev->processing_q,
+			&frame_qcmd->list_frame);
+		cpp_timer.data.processed_frame[cpp_dev->processing_q.len - 1] =
+			process_frame;
+		queue_len = cpp_dev->processing_q.len;
+		spin_unlock_irqrestore(&cpp_timer.data.processed_frame_lock,
+			flags);
+		atomic_set(&cpp_timer.used, 1);
+
+		CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
+			CPP_CMD_TIMEOUT_MS, jiffies);
+		if (mod_timer(&cpp_timer.cpp_timer,
+			(jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS))) != 0)
+			CPP_DBG("Timer has not expired yet\n");
+
+		rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+		if (rc) {
+			pr_err("%s:%d: Scheduling payload failed %d",
+				__func__, __LINE__, rc);
+			goto dequeue_frame;
+		}
+		msm_cpp_write(0x6, cpp_dev->base);
+		fifo_counter++;
+		/* send top level and plane level */
+		for (i = 0; i < cpp_dev->payload_params.stripe_base; i++,
+			fifo_counter++) {
+			if ((fifo_counter % MSM_CPP_RX_FIFO_LEVEL) == 0) {
+				rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+				if (rc)
+					break;
+				fifo_counter = 0;
+			}
+			msm_cpp_write(process_frame->cpp_cmd_msg[i],
+				cpp_dev->base);
+		}
+		if (rc) {
+			pr_err("%s:%d: Scheduling plane info failed %d\n",
+				__func__, __LINE__, rc);
+			goto dequeue_frame;
+		}
+		/* send stripes */
+		i1 = cpp_dev->payload_params.stripe_base +
+			cpp_dev->payload_params.stripe_size *
+			process_frame->first_stripe_index;
+		i2 = cpp_dev->payload_params.stripe_size *
+			(process_frame->last_stripe_index -
+			process_frame->first_stripe_index + 1);
+		for (i = 0; i < i2; i++, fifo_counter++) {
+			if ((fifo_counter % MSM_CPP_RX_FIFO_LEVEL) == 0) {
+				rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+				if (rc)
+					break;
+				fifo_counter = 0;
+			}
+			msm_cpp_write(process_frame->cpp_cmd_msg[i+i1],
+				cpp_dev->base);
+		}
+		if (rc) {
+			pr_err("%s:%d: Scheduling stripe info failed %d\n",
+				__func__, __LINE__, rc);
+			goto dequeue_frame;
+		}
+		/* send trailer */
+		if ((fifo_counter % MSM_CPP_RX_FIFO_LEVEL) == 0) {
+			rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+			if (rc) {
+				pr_err("%s: Scheduling trailer failed %d\n",
+				__func__, rc);
+				goto dequeue_frame;
+			}
+			fifo_counter = 0;
+		}
+		msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+		do_gettimeofday(&(process_frame->in_time));
+		rc = 0;
+	} else {
+		pr_err("process queue full. drop frame\n");
+		goto end;
+	}
+
+dequeue_frame:
+	if (rc < 0) {
+		qcmd = msm_dequeue(&cpp_dev->processing_q, list_frame,
+			POP_BACK);
+		if (!qcmd)
+			pr_warn("%s:%d: no queue cmd\n", __func__, __LINE__);
+		spin_lock_irqsave(&cpp_timer.data.processed_frame_lock,
+			flags);
+		queue_len = cpp_dev->processing_q.len;
+		spin_unlock_irqrestore(
+			&cpp_timer.data.processed_frame_lock, flags);
+		if (queue_len == 0) {
+			atomic_set(&cpp_timer.used, 0);
+			del_timer(&cpp_timer.cpp_timer);
+		}
+	}
+end:
+	return rc;
+}
+
+static int msm_cpp_send_command_to_hardware(struct cpp_device *cpp_dev,
+	uint32_t *cmd_msg, uint32_t payload_size)
+{
+	uint32_t i;
+	int rc = 0;
+
+	rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+	if (rc) {
+		pr_err("%s:%d] poll rx empty failed %d",
+			__func__, __LINE__, rc);
+		goto end;
+	}
+
+	for (i = 0; i < payload_size; i++) {
+		msm_cpp_write(cmd_msg[i], cpp_dev->base);
+		if (i % MSM_CPP_RX_FIFO_LEVEL == 0) {
+			rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+			if (rc) {
+				pr_err("%s:%d] poll rx empty failed %d",
+					__func__, __LINE__, rc);
+				goto end;
+			}
+		}
+	}
+end:
+	return rc;
+}
+
+static int msm_cpp_flush_frames(struct cpp_device *cpp_dev)
+{
+	return 0;
+}
+
+static struct msm_cpp_frame_info_t *msm_cpp_get_frame(
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	uint32_t *cpp_frame_msg;
+	struct msm_cpp_frame_info_t *new_frame = NULL;
+	int32_t rc = 0;
+
+	new_frame = kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
+
+	if (!new_frame) {
+		rc = -ENOMEM;
+		goto no_mem_err;
+	}
+
+	rc = (copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		goto frame_err;
+	}
+
+	if ((new_frame->msg_len == 0) ||
+		(new_frame->msg_len > MSM_CPP_MAX_FRAME_LENGTH)) {
+		pr_err("%s:%d: Invalid frame len:%d\n", __func__,
+			__LINE__, new_frame->msg_len);
+		goto frame_err;
+	}
+
+	cpp_frame_msg = kcalloc(new_frame->msg_len, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!cpp_frame_msg)
+		goto frame_err;
+
+	rc = (copy_from_user(cpp_frame_msg,
+		(void __user *)new_frame->cpp_cmd_msg,
+		sizeof(uint32_t) * new_frame->msg_len) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		goto frame_msg_err;
+	}
+	new_frame->cpp_cmd_msg = cpp_frame_msg;
+	return new_frame;
+
+frame_msg_err:
+	kfree(cpp_frame_msg);
+frame_err:
+	kfree(new_frame);
+no_mem_err:
+	return NULL;
+}
+
+static int msm_cpp_check_buf_type(struct msm_buf_mngr_info *buff_mgr_info,
+	struct msm_cpp_frame_info_t *new_frame)
+{
+	int32_t num_output_bufs = 0;
+	uint32_t i = 0;
+
+	if (buff_mgr_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
+		new_frame->batch_info.cont_idx =
+			buff_mgr_info->index;
+		num_output_bufs = buff_mgr_info->user_buf.buf_cnt;
+		if (buff_mgr_info->user_buf.buf_cnt <
+			new_frame->batch_info.batch_size) {
+			/* Less bufs than Input buffer */
+			num_output_bufs = buff_mgr_info->user_buf.buf_cnt;
+		} else {
+			/* More or equal bufs as Input buffer */
+			num_output_bufs = new_frame->batch_info.batch_size;
+		}
+		if (num_output_bufs > MSM_OUTPUT_BUF_CNT)
+			return 0;
+		for (i = 0; i < num_output_bufs; i++) {
+			new_frame->output_buffer_info[i].index =
+				buff_mgr_info->user_buf.buf_idx[i];
+		}
+	} else {
+		/* For non-group case use first buf slot */
+		new_frame->output_buffer_info[0].index = buff_mgr_info->index;
+		num_output_bufs = 1;
+	}
+
+	return num_output_bufs;
+}
+
+static void msm_cpp_update_frame_msg_phy_address(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *new_frame, unsigned long in_phyaddr,
+	unsigned long out_phyaddr0, unsigned long out_phyaddr1,
+	unsigned long tnr_scratch_buffer0, unsigned long tnr_scratch_buffer1)
+{
+	int32_t stripe_base, plane_base;
+	uint32_t rd_pntr_off, wr_0_pntr_off, wr_1_pntr_off,
+		wr_2_pntr_off, wr_3_pntr_off;
+	uint32_t wr_0_meta_data_wr_pntr_off, wr_1_meta_data_wr_pntr_off,
+		wr_2_meta_data_wr_pntr_off, wr_3_meta_data_wr_pntr_off;
+	uint32_t rd_ref_pntr_off, wr_ref_pntr_off;
+	uint32_t stripe_size, plane_size;
+	uint32_t fe_mmu_pf_ptr_off, ref_fe_mmu_pf_ptr_off, we_mmu_pf_ptr_off,
+		dup_we_mmu_pf_ptr_off, ref_we_mmu_pf_ptr_off;
+	uint8_t tnr_enabled, ubwc_enabled, mmu_pf_en, cds_en;
+	int32_t i = 0;
+	uint32_t *cpp_frame_msg;
+
+	cpp_frame_msg = new_frame->cpp_cmd_msg;
+
+	/* Update stripe/plane size and base offsets */
+	stripe_base = cpp_dev->payload_params.stripe_base;
+	stripe_size = cpp_dev->payload_params.stripe_size;
+	plane_base = cpp_dev->payload_params.plane_base;
+	plane_size = cpp_dev->payload_params.plane_size;
+
+	/* Fetch engine Offset */
+	rd_pntr_off = cpp_dev->payload_params.rd_pntr_off;
+	/* Write engine offsets */
+	wr_0_pntr_off = cpp_dev->payload_params.wr_0_pntr_off;
+	wr_1_pntr_off = wr_0_pntr_off + 1;
+	wr_2_pntr_off = wr_1_pntr_off + 1;
+	wr_3_pntr_off = wr_2_pntr_off + 1;
+	/* Reference engine offsets */
+	rd_ref_pntr_off = cpp_dev->payload_params.rd_ref_pntr_off;
+	wr_ref_pntr_off = cpp_dev->payload_params.wr_ref_pntr_off;
+	/* Meta data offsets */
+	wr_0_meta_data_wr_pntr_off =
+		cpp_dev->payload_params.wr_0_meta_data_wr_pntr_off;
+	wr_1_meta_data_wr_pntr_off = (wr_0_meta_data_wr_pntr_off + 1);
+	wr_2_meta_data_wr_pntr_off = (wr_1_meta_data_wr_pntr_off + 1);
+	wr_3_meta_data_wr_pntr_off = (wr_2_meta_data_wr_pntr_off + 1);
+	/* MMU PF offsets */
+	fe_mmu_pf_ptr_off = cpp_dev->payload_params.fe_mmu_pf_ptr_off;
+	ref_fe_mmu_pf_ptr_off = cpp_dev->payload_params.ref_fe_mmu_pf_ptr_off;
+	we_mmu_pf_ptr_off = cpp_dev->payload_params.we_mmu_pf_ptr_off;
+	dup_we_mmu_pf_ptr_off = cpp_dev->payload_params.dup_we_mmu_pf_ptr_off;
+	ref_we_mmu_pf_ptr_off = cpp_dev->payload_params.ref_we_mmu_pf_ptr_off;
+
+	pr_debug("feature_mask 0x%x\n", new_frame->feature_mask);
+
+	/* Update individual module status from feature mask */
+	tnr_enabled = ((new_frame->feature_mask & TNR_MASK) >> 2);
+	ubwc_enabled = ((new_frame->feature_mask & UBWC_MASK) >> 5);
+	cds_en = ((new_frame->feature_mask & CDS_MASK) >> 6);
+	mmu_pf_en = ((new_frame->feature_mask & MMU_PF_MASK) >> 7);
+
+	/*
+	 * Update the stripe based addresses for fetch/write/reference engines.
+	 * Update meta data offset for ubwc.
+	 * Update ref engine address for cds / tnr.
+	 */
+	for (i = 0; i < new_frame->num_strips; i++) {
+		cpp_frame_msg[stripe_base + rd_pntr_off + i * stripe_size] +=
+			(uint32_t) in_phyaddr;
+		cpp_frame_msg[stripe_base + wr_0_pntr_off + i * stripe_size] +=
+			(uint32_t) out_phyaddr0;
+		cpp_frame_msg[stripe_base + wr_1_pntr_off + i * stripe_size] +=
+			(uint32_t) out_phyaddr1;
+		cpp_frame_msg[stripe_base + wr_2_pntr_off + i * stripe_size] +=
+			(uint32_t) out_phyaddr0;
+		cpp_frame_msg[stripe_base + wr_3_pntr_off + i * stripe_size] +=
+			(uint32_t) out_phyaddr1;
+		if (tnr_enabled) {
+			cpp_frame_msg[stripe_base + rd_ref_pntr_off +
+				i * stripe_size] +=
+				(uint32_t)tnr_scratch_buffer0;
+			cpp_frame_msg[stripe_base + wr_ref_pntr_off +
+				i * stripe_size] +=
+				(uint32_t)tnr_scratch_buffer1;
+		} else if (cds_en) {
+			cpp_frame_msg[stripe_base + rd_ref_pntr_off +
+				i * stripe_size] +=
+				(uint32_t)in_phyaddr;
+		}
+		if (ubwc_enabled) {
+			cpp_frame_msg[stripe_base + wr_0_meta_data_wr_pntr_off +
+				i * stripe_size] += (uint32_t) out_phyaddr0;
+			cpp_frame_msg[stripe_base + wr_1_meta_data_wr_pntr_off +
+				i * stripe_size] += (uint32_t) out_phyaddr1;
+			cpp_frame_msg[stripe_base + wr_2_meta_data_wr_pntr_off +
+				i * stripe_size] += (uint32_t) out_phyaddr0;
+			cpp_frame_msg[stripe_base + wr_3_meta_data_wr_pntr_off +
+				i * stripe_size] += (uint32_t) out_phyaddr1;
+		}
+	}
+
+	if (!mmu_pf_en)
+		goto exit;
+
+	/* Update mmu prefetch related plane specific address */
+	for (i = 0; i < PAYLOAD_NUM_PLANES; i++) {
+		cpp_frame_msg[plane_base + fe_mmu_pf_ptr_off +
+			i * plane_size] += (uint32_t)in_phyaddr;
+		cpp_frame_msg[plane_base + fe_mmu_pf_ptr_off +
+			i * plane_size + 1] += (uint32_t)in_phyaddr;
+		cpp_frame_msg[plane_base + ref_fe_mmu_pf_ptr_off +
+			i * plane_size] += (uint32_t)tnr_scratch_buffer0;
+		cpp_frame_msg[plane_base + ref_fe_mmu_pf_ptr_off +
+			i * plane_size + 1] += (uint32_t)tnr_scratch_buffer0;
+		cpp_frame_msg[plane_base + we_mmu_pf_ptr_off +
+			i * plane_size] += (uint32_t)out_phyaddr0;
+		cpp_frame_msg[plane_base + we_mmu_pf_ptr_off +
+			i * plane_size + 1] += (uint32_t)out_phyaddr0;
+		cpp_frame_msg[plane_base + dup_we_mmu_pf_ptr_off +
+			i * plane_size] += (uint32_t)out_phyaddr1;
+		cpp_frame_msg[plane_base + dup_we_mmu_pf_ptr_off +
+			i * plane_size + 1] += (uint32_t)out_phyaddr1;
+		cpp_frame_msg[plane_base + ref_we_mmu_pf_ptr_off +
+			i * plane_size] += (uint32_t)tnr_scratch_buffer1;
+		cpp_frame_msg[plane_base + ref_we_mmu_pf_ptr_off +
+			i * plane_size + 1] += (uint32_t)tnr_scratch_buffer1;
+	}
+exit:
+	return;
+}
+
+static int32_t msm_cpp_set_group_buffer_duplicate(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *new_frame, unsigned long out_phyaddr,
+	uint32_t num_output_bufs)
+{
+
+	uint32_t *set_group_buffer_w_duplication = NULL;
+	uint32_t *ptr;
+	unsigned long out_phyaddr0, out_phyaddr1, distance;
+	int32_t rc = 0;
+	uint32_t set_group_buffer_len, set_group_buffer_len_bytes,
+		dup_frame_off, ubwc_enabled, j, i = 0;
+
+	do {
+		int iden = new_frame->identity;
+
+		set_group_buffer_len =
+			cpp_dev->payload_params.set_group_buffer_len;
+		if (!set_group_buffer_len) {
+			pr_err("%s: invalid set group buffer cmd len %d\n",
+				 __func__, set_group_buffer_len);
+			rc = -EINVAL;
+			break;
+		}
+
+		/*
+		 * Length of  MSM_CPP_CMD_GROUP_BUFFER_DUP command +
+		 * 4 byte for header + 4 byte for the length field +
+		 * 4 byte for the trailer + 4 byte for
+		 * MSM_CPP_CMD_GROUP_BUFFER_DUP prefix before the payload
+		 */
+		set_group_buffer_len += 4;
+		set_group_buffer_len_bytes = set_group_buffer_len *
+			sizeof(uint32_t);
+		set_group_buffer_w_duplication =
+			kzalloc(set_group_buffer_len_bytes, GFP_KERNEL);
+		if (!set_group_buffer_w_duplication) {
+			pr_err("%s: set group buffer data alloc failed\n",
+				__func__);
+			rc = -ENOMEM;
+			break;
+		}
+
+		memset(set_group_buffer_w_duplication, 0x0,
+			set_group_buffer_len_bytes);
+		dup_frame_off =
+			cpp_dev->payload_params.dup_frame_indicator_off;
+		/* Add a factor of 1 as command is prefixed to the payload. */
+		dup_frame_off += 1;
+		ubwc_enabled = ((new_frame->feature_mask & UBWC_MASK) >> 5);
+		ptr = set_group_buffer_w_duplication;
+		/*create and send Set Group Buffer with Duplicate command*/
+		*ptr++ = MSM_CPP_CMD_GROUP_BUFFER_DUP;
+		*ptr++ = MSM_CPP_MSG_ID_CMD;
+		/*
+		 * This field is the value read from dt and stands for length of
+		 * actual data in payload
+		 */
+		*ptr++ = cpp_dev->payload_params.set_group_buffer_len;
+		*ptr++ = MSM_CPP_CMD_GROUP_BUFFER_DUP;
+		*ptr++ = 0;
+		out_phyaddr0 = out_phyaddr;
+
+		SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(new_frame,
+				iden, new_frame->duplicate_identity);
+
+		for (i = 1; i < num_output_bufs; i++) {
+			out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
+				&new_frame->output_buffer_info[i],
+				((iden >> 16) & 0xFFFF),
+				(iden & 0xFFFF),
+				&new_frame->output_buffer_info[i].fd);
+			if (!out_phyaddr1) {
+				pr_err("%s: error getting o/p phy addr\n",
+					__func__);
+				rc = -EINVAL;
+				break;
+			}
+			distance = out_phyaddr1 - out_phyaddr0;
+			out_phyaddr0 = out_phyaddr1;
+			for (j = 0; j < PAYLOAD_NUM_PLANES; j++)
+				*ptr++ = distance;
+
+			for (j = 0; j < PAYLOAD_NUM_PLANES; j++)
+				*ptr++ = ubwc_enabled ? distance : 0;
+		}
+		if (rc)
+			break;
+
+		if (new_frame->duplicate_output)
+			set_group_buffer_w_duplication[dup_frame_off] =
+				1 << new_frame->batch_info.pick_preview_idx;
+		else
+			set_group_buffer_w_duplication[dup_frame_off] = 0;
+
+		/*
+		 * Index for cpp message id trailer is length of payload for
+		 * set group buffer minus 1
+		 */
+		set_group_buffer_w_duplication[set_group_buffer_len - 1] =
+			MSM_CPP_MSG_ID_TRAILER;
+		rc = msm_cpp_send_command_to_hardware(cpp_dev,
+			set_group_buffer_w_duplication, set_group_buffer_len);
+		if (rc < 0) {
+			pr_err("%s: Send Command Error rc %d\n", __func__, rc);
+			break;
+		}
+
+	} while (0);
+
+	kfree(set_group_buffer_w_duplication);
+	return rc;
+}
+
+static int32_t msm_cpp_set_group_buffer(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *new_frame, unsigned long out_phyaddr,
+	uint32_t num_output_bufs)
+{
+	uint32_t set_group_buffer_len;
+	uint32_t *set_group_buffer = NULL;
+	uint32_t *ptr;
+	unsigned long out_phyaddr0, out_phyaddr1, distance;
+	int32_t rc = 0;
+	uint32_t set_group_buffer_len_bytes, i = 0;
+	bool batching_valid = false;
+
+	if ((IS_BATCH_BUFFER_ON_PREVIEW(new_frame)) ||
+		new_frame->batch_info.batch_mode == BATCH_MODE_VIDEO)
+		batching_valid = true;
+
+	if (!batching_valid) {
+		pr_debug("%s: batch mode %d, batching valid %d\n",
+			__func__, new_frame->batch_info.batch_mode,
+			batching_valid);
+		return rc;
+	}
+
+	if (new_frame->batch_info.batch_size <= 1) {
+		pr_debug("%s: batch size is invalid %d\n", __func__,
+			new_frame->batch_info.batch_size);
+		return rc;
+	}
+
+	if ((new_frame->feature_mask & BATCH_DUP_MASK) >> 8) {
+		return msm_cpp_set_group_buffer_duplicate(cpp_dev, new_frame,
+		out_phyaddr, num_output_bufs);
+	}
+
+	if (new_frame->duplicate_output) {
+		pr_err("cannot support duplication enable\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	set_group_buffer_len =
+		2 + 3 * (num_output_bufs - 1);
+	/*
+	 * Length of  MSM_CPP_CMD_GROUP_BUFFER command +
+	 * 4 byte for header + 4 byte for the length field +
+	 * 4 byte for the trailer + 4 byte for
+	 * MSM_CPP_CMD_GROUP_BUFFER prefix before the payload
+	 */
+	set_group_buffer_len += 4;
+	set_group_buffer_len_bytes = set_group_buffer_len *
+		sizeof(uint32_t);
+	set_group_buffer =
+		kzalloc(set_group_buffer_len_bytes, GFP_KERNEL);
+	if (!set_group_buffer) {
+		pr_err("%s: set group buffer data alloc failed\n",
+			__func__);
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	memset(set_group_buffer, 0x0,
+		set_group_buffer_len_bytes);
+	ptr = set_group_buffer;
+	/*Create and send Set Group Buffer*/
+	*ptr++ = MSM_CPP_CMD_GROUP_BUFFER;
+	*ptr++ = MSM_CPP_MSG_ID_CMD;
+	/*
+	 * This field is the value read from dt and stands
+	 * for length of actual data in payload
+	 */
+	*ptr++ = set_group_buffer_len - 4;
+	*ptr++ = MSM_CPP_CMD_GROUP_BUFFER;
+	*ptr++ = 0;
+	out_phyaddr0 = out_phyaddr;
+
+	for (i = 1; i < num_output_bufs; i++) {
+		out_phyaddr1 =
+			msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->output_buffer_info[i],
+			((new_frame->identity >> 16) & 0xFFFF),
+			(new_frame->identity & 0xFFFF),
+			&new_frame->output_buffer_info[i].fd);
+		if (!out_phyaddr1) {
+			pr_err("%s: error getting o/p phy addr\n",
+				__func__);
+			rc = -EINVAL;
+			goto free_and_exit;
+		}
+		distance = out_phyaddr1 - out_phyaddr0;
+		out_phyaddr0 = out_phyaddr1;
+		*ptr++ = distance;
+		*ptr++ = distance;
+		*ptr++ = distance;
+	}
+	if (rc)
+		goto free_and_exit;
+
+	/*
+	 * Index for cpp message id trailer is length of
+	 * payload for set group buffer minus 1
+	 */
+	set_group_buffer[set_group_buffer_len - 1] =
+		MSM_CPP_MSG_ID_TRAILER;
+	rc = msm_cpp_send_command_to_hardware(cpp_dev,
+		set_group_buffer, set_group_buffer_len);
+	if (rc < 0)
+		pr_err("Send Command Error rc %d\n", rc);
+
+free_and_exit:
+	kfree(set_group_buffer);
+exit:
+	return rc;
+}
+
+static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
+	struct msm_cpp_frame_info_t *new_frame)
+{
+	int32_t rc = 0;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	uint32_t *cpp_frame_msg;
+	unsigned long in_phyaddr, out_phyaddr0 = (unsigned long)NULL;
+	unsigned long out_phyaddr1;
+	unsigned long tnr_scratch_buffer0, tnr_scratch_buffer1;
+	uint16_t num_stripes = 0;
+	struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info;
+	int32_t in_fd;
+	int32_t num_output_bufs = 1;
+	uint32_t stripe_base = 0;
+	uint32_t stripe_size;
+	uint8_t tnr_enabled;
+	enum msm_camera_buf_mngr_buf_type buf_type =
+		MSM_CAMERA_BUF_MNGR_BUF_PLANAR;
+	uint32_t ioctl_cmd, idx;
+	uint32_t op_index, dup_index;
+
+	stripe_base = cpp_dev->payload_params.stripe_base;
+	stripe_size = cpp_dev->payload_params.stripe_size;
+
+	if (!new_frame) {
+		pr_err("%s: Frame is Null\n", __func__);
+		return -EINVAL;
+	}
+
+	if (cpp_dev->state == CPP_STATE_OFF) {
+		pr_err("%s: cpp state is off, return fatal error\n", __func__);
+		return -EINVAL;
+	}
+
+	cpp_frame_msg = new_frame->cpp_cmd_msg;
+
+	if (cpp_frame_msg == NULL ||
+		(new_frame->msg_len < MSM_CPP_MIN_FRAME_LENGTH)) {
+		pr_err("Length is not correct or frame message is missing\n");
+		return -EINVAL;
+	}
+
+	if (cpp_dev->fault_status == CPP_IOMMU_FAULT_RECOVERED) {
+		pr_err("Error, page fault occurred %d\n",
+			cpp_dev->fault_status);
+		return -EINVAL;
+	} else if (cpp_dev->fault_status == CPP_IOMMU_FAULT_DETECTED) {
+		pr_err("drop frame, page fault occurred %d\n",
+			cpp_dev->fault_status);
+		return -EFAULT;
+	}
+
+	if (cpp_frame_msg[new_frame->msg_len - 1] !=
+		MSM_CPP_MSG_ID_TRAILER) {
+		pr_err("Invalid frame message\n");
+		return -EINVAL;
+	}
+
+	/* Stripe index starts at zero */
+	if ((!new_frame->num_strips) ||
+		(new_frame->first_stripe_index >= new_frame->num_strips) ||
+		(new_frame->last_stripe_index  >= new_frame->num_strips) ||
+		(new_frame->first_stripe_index >
+			new_frame->last_stripe_index)) {
+		pr_err("Invalid frame message, #stripes=%d, stripe indices=[%d,%d]\n",
+			new_frame->num_strips,
+			new_frame->first_stripe_index,
+			new_frame->last_stripe_index);
+		return -EINVAL;
+	}
+
+	if (!stripe_size) {
+		pr_err("Invalid frame message, invalid stripe_size (%d)!\n",
+			stripe_size);
+		return -EINVAL;
+	}
+
+	if ((stripe_base == UINT_MAX) ||
+		(new_frame->num_strips >
+			(UINT_MAX - 1 - stripe_base) / stripe_size)) {
+		pr_err("Invalid frame message, num_strips %d is large\n",
+			new_frame->num_strips);
+		return -EINVAL;
+	}
+
+	if ((stripe_base + new_frame->num_strips * stripe_size + 1) !=
+		new_frame->msg_len) {
+		pr_err("Invalid frame message,len=%d,expected=%d\n",
+			new_frame->msg_len,
+			(stripe_base +
+			new_frame->num_strips * stripe_size + 1));
+		return -EINVAL;
+	}
+
+	if (cpp_dev->iommu_state != CPP_IOMMU_STATE_ATTACHED) {
+		pr_err("IOMMU is not attached\n");
+		return -EAGAIN;
+	}
+
+	in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
+		&new_frame->input_buffer_info,
+		((new_frame->input_buffer_info.identity >> 16) & 0xFFFF),
+		(new_frame->input_buffer_info.identity & 0xFFFF), &in_fd);
+	if (!in_phyaddr) {
+		pr_err("%s: error gettting input physical address\n", __func__);
+		rc = -EINVAL;
+		goto frame_msg_err;
+	}
+
+	op_index = new_frame->output_buffer_info[0].index;
+	dup_index = new_frame->duplicate_buffer_info.index;
+
+	if (new_frame->we_disable == 0) {
+		int32_t iden = new_frame->identity;
+
+		if ((new_frame->output_buffer_info[0].native_buff == 0) &&
+			(new_frame->first_payload)) {
+			memset(&buff_mgr_info, 0,
+				sizeof(struct msm_buf_mngr_info));
+			if ((new_frame->batch_info.batch_mode ==
+				BATCH_MODE_VIDEO) ||
+				(IS_BATCH_BUFFER_ON_PREVIEW(new_frame)))
+				buf_type = MSM_CAMERA_BUF_MNGR_BUF_USER;
+
+			SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(new_frame,
+				iden, new_frame->duplicate_identity);
+
+			/*
+			 * Swap the input buffer index for batch mode with
+			 * buffer on preview
+			 */
+			SWAP_BUF_INDEX_FOR_BATCH_ON_PREVIEW(new_frame,
+				buff_mgr_info, op_index, dup_index);
+
+			buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id = (iden & 0xFFFF);
+			buff_mgr_info.type = buf_type;
+
+			if (IS_DEFAULT_OUTPUT_BUF_INDEX(buff_mgr_info.index)) {
+				ioctl_cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF;
+				idx = 0x0;
+			} else {
+				ioctl_cmd = VIDIOC_MSM_BUF_MNGR_IOCTL_CMD;
+				idx =
+				MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+			}
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				ioctl_cmd, idx, &buff_mgr_info);
+			if (rc < 0) {
+				rc = -EAGAIN;
+				pr_debug("%s:get_buf err rc:%d, index %d\n",
+					__func__, rc,
+					new_frame->output_buffer_info[0].index);
+				goto frame_msg_err;
+			}
+			num_output_bufs =
+				msm_cpp_check_buf_type(&buff_mgr_info,
+					new_frame);
+			if (!num_output_bufs) {
+				pr_err("%s: error getting buffer %d\n",
+					__func__, num_output_bufs);
+				rc = -EINVAL;
+				goto phyaddr_err;
+			}
+		}
+
+		out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->output_buffer_info[0],
+			((iden >> 16) & 0xFFFF),
+			(iden & 0xFFFF),
+			&new_frame->output_buffer_info[0].fd);
+		if (!out_phyaddr0) {
+			pr_err("%s: error gettting output physical address\n",
+				__func__);
+			rc = -EINVAL;
+			goto phyaddr_err;
+		}
+	}
+	out_phyaddr1 = out_phyaddr0;
+
+	/* get buffer for duplicate output */
+	if (new_frame->duplicate_output) {
+		int32_t iden = new_frame->duplicate_identity;
+
+		CPP_DBG("duplication enabled, dup_id=0x%x",
+			new_frame->duplicate_identity);
+
+		SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(new_frame,
+			iden, new_frame->identity);
+
+		memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+
+		/*
+		 * Swap the input buffer index for batch mode with
+		 * buffer on preview
+		 */
+		SWAP_BUF_INDEX_FOR_BATCH_ON_PREVIEW(new_frame,
+			dup_buff_mgr_info, dup_index, op_index);
+
+		dup_buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
+		dup_buff_mgr_info.stream_id = (iden & 0xFFFF);
+		dup_buff_mgr_info.type =
+			MSM_CAMERA_BUF_MNGR_BUF_PLANAR;
+		if (IS_DEFAULT_OUTPUT_BUF_INDEX(dup_buff_mgr_info.index)) {
+			ioctl_cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF;
+			idx = 0x0;
+		} else {
+			ioctl_cmd = VIDIOC_MSM_BUF_MNGR_IOCTL_CMD;
+			idx = MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+		}
+		rc = msm_cpp_buffer_ops(cpp_dev, ioctl_cmd, idx,
+			&dup_buff_mgr_info);
+		if (rc < 0) {
+			rc = -EAGAIN;
+			pr_debug("%s: get_buf err rc:%d,  index %d\n",
+				__func__, rc,
+				new_frame->duplicate_buffer_info.index);
+			goto phyaddr_err;
+		}
+		new_frame->duplicate_buffer_info.index =
+			dup_buff_mgr_info.index;
+		out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->duplicate_buffer_info,
+			((iden >> 16) & 0xFFFF),
+			(iden & 0xFFFF),
+			&new_frame->duplicate_buffer_info.fd);
+		if (!out_phyaddr1) {
+			pr_err("error gettting output physical address\n");
+			rc = -EINVAL;
+			msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+				0x0, &dup_buff_mgr_info);
+			goto phyaddr_err;
+		}
+		/* set duplicate enable bit */
+		cpp_frame_msg[5] |= 0x1;
+		CPP_DBG("out_phyaddr1= %08x\n", (uint32_t)out_phyaddr1);
+	}
+
+	tnr_enabled = ((new_frame->feature_mask & TNR_MASK) >> 2);
+	if (tnr_enabled) {
+		tnr_scratch_buffer0 = msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->tnr_scratch_buffer_info[0],
+			((new_frame->identity >> 16) & 0xFFFF),
+			(new_frame->identity & 0xFFFF),
+			&new_frame->tnr_scratch_buffer_info[0].fd);
+		if (!tnr_scratch_buffer0) {
+			pr_err("error getting scratch buffer physical address\n");
+			rc = -EINVAL;
+			goto phyaddr_err;
+		}
+
+		tnr_scratch_buffer1 = msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->tnr_scratch_buffer_info[1],
+			((new_frame->identity >> 16) & 0xFFFF),
+			(new_frame->identity & 0xFFFF),
+			&new_frame->tnr_scratch_buffer_info[1].fd);
+		if (!tnr_scratch_buffer1) {
+			pr_err("error getting scratch buffer physical address\n");
+			rc = -EINVAL;
+			goto phyaddr_err;
+		}
+	} else {
+		tnr_scratch_buffer0 = 0;
+		tnr_scratch_buffer1 = 0;
+	}
+
+
+	msm_cpp_update_frame_msg_phy_address(cpp_dev, new_frame,
+		in_phyaddr, out_phyaddr0, out_phyaddr1,
+		tnr_scratch_buffer0, tnr_scratch_buffer1);
+	if (tnr_enabled) {
+		cpp_frame_msg[10] = tnr_scratch_buffer1 -
+			tnr_scratch_buffer0;
+	}
+
+	rc = msm_cpp_set_group_buffer(cpp_dev, new_frame, out_phyaddr0,
+		num_output_bufs);
+	if (rc) {
+		pr_err("%s: set group buffer failure %d\n", __func__, rc);
+		goto phyaddr_err;
+	}
+
+	num_stripes = new_frame->last_stripe_index -
+		new_frame->first_stripe_index + 1;
+	cpp_frame_msg[1] = stripe_base - 2 + num_stripes * stripe_size;
+
+	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!frame_qcmd) {
+		rc = -ENOMEM;
+		goto qcmd_err;
+	}
+
+	atomic_set(&frame_qcmd->on_heap, 1);
+	frame_qcmd->command = new_frame;
+	rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd);
+	if (rc < 0) {
+		pr_err("%s: error cannot send frame to hardware\n", __func__);
+		rc = -EINVAL;
+		goto qcmd_err;
+	}
+
+	return rc;
+qcmd_err:
+	kfree(frame_qcmd);
+phyaddr_err:
+	if (new_frame->output_buffer_info[0].native_buff == 0)
+		msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+			0x0, &buff_mgr_info);
+frame_msg_err:
+	kfree(cpp_frame_msg);
+	kfree(new_frame);
+	return rc;
+}
+
+static int msm_cpp_cfg(struct cpp_device *cpp_dev,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	struct msm_cpp_frame_info_t *frame = NULL;
+	struct msm_cpp_frame_info_t k_frame_info;
+	int32_t rc = 0;
+	uint32_t i = 0;
+	uint32_t num_buff = sizeof(k_frame_info.output_buffer_info) /
+				sizeof(struct msm_cpp_buffer_info_t);
+
+	if (copy_from_user(&k_frame_info,
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(k_frame_info)))
+		return -EFAULT;
+
+	frame = msm_cpp_get_frame(ioctl_ptr);
+	if (!frame) {
+		pr_err("%s: Error allocating frame\n", __func__);
+		rc = -EINVAL;
+	} else {
+		rc = msm_cpp_cfg_frame(cpp_dev, frame);
+		if (rc >= 0) {
+			for (i = 0; i < num_buff; i++) {
+				k_frame_info.output_buffer_info[i] =
+					frame->output_buffer_info[i];
+			}
+		}
+	}
+
+	ioctl_ptr->trans_code = rc;
+
+	if (copy_to_user((void __user *)k_frame_info.status, &rc,
+		sizeof(int32_t)))
+		pr_err("error cannot copy error\n");
+
+
+	if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+		&k_frame_info, sizeof(k_frame_info))) {
+		pr_err("Error: cannot copy k_frame_info");
+		return -EFAULT;
+	}
+
+	return rc;
+}
+
+static void msm_cpp_clean_queue(struct cpp_device *cpp_dev)
+{
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_cpp_frame_info_t *processed_frame = NULL;
+	struct msm_device_queue *queue = NULL;
+
+	while (cpp_dev->processing_q.len) {
+		pr_debug("queue len:%d\n", cpp_dev->processing_q.len);
+		queue = &cpp_dev->processing_q;
+		frame_qcmd = msm_dequeue(queue, list_frame, POP_FRONT);
+		if (frame_qcmd) {
+			processed_frame = frame_qcmd->command;
+			kfree(frame_qcmd);
+			if (processed_frame)
+				kfree(processed_frame->cpp_cmd_msg);
+			kfree(processed_frame);
+		}
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int ret;
+
+	if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
+		pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__,
+			ioctl_ptr, ioctl_ptr->len);
+		return -EINVAL;
+	}
+
+	/* For compat task, source ptr is in kernel space */
+	if (is_compat_task()) {
+		memcpy(dst_ptr, (__force void *)ioctl_ptr->ioctl_ptr,
+			ioctl_ptr->len);
+		ret = 0;
+	} else {
+		ret = copy_from_user(dst_ptr,
+			(void __user *)ioctl_ptr->ioctl_ptr, ioctl_ptr->len);
+		if (ret)
+			pr_err("Copy from user fail %d\n", ret);
+	}
+	return ret ? -EFAULT : 0;
+}
+#else
+static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int ret;
+
+	if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
+		pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__,
+			ioctl_ptr, ioctl_ptr->len);
+		return -EINVAL;
+	}
+
+	ret = copy_from_user(dst_ptr,
+		(void __user *)ioctl_ptr->ioctl_ptr, ioctl_ptr->len);
+	if (ret)
+		pr_err("Copy from user fail %d\n", ret);
+
+	return ret ? -EFAULT : 0;
+}
+#endif
+
+static int32_t msm_cpp_fw_version(struct cpp_device *cpp_dev)
+{
+	int32_t rc = 0;
+
+	rc = msm_cpp_poll_rx_empty(cpp_dev->base);
+	if (rc) {
+		pr_err("%s:%d] poll rx empty failed %d",
+			__func__, __LINE__, rc);
+		goto end;
+	}
+	/*Get Firmware Version*/
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
+	msm_cpp_write(0x1, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_CMD, rc);
+		goto end;
+	}
+	rc = msm_cpp_poll(cpp_dev->base, 0x2);
+	if (rc) {
+		pr_err("%s:%d] poll command 0x2 failed %d", __func__, __LINE__,
+			rc);
+		goto end;
+	}
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_FW_VER, rc);
+		goto end;
+	}
+
+	cpp_dev->fw_version = msm_cpp_read(cpp_dev->base);
+	pr_debug("CPP FW Version: 0x%08x\n", cpp_dev->fw_version);
+
+	rc = msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+	if (rc) {
+		pr_err("%s:%d] poll command %x failed %d", __func__, __LINE__,
+			MSM_CPP_MSG_ID_TRAILER, rc);
+	}
+
+end:
+
+	return rc;
+}
+
+static int msm_cpp_validate_input(unsigned int cmd, void *arg,
+	struct msm_camera_v4l2_ioctl_t **ioctl_ptr)
+{
+	switch (cmd) {
+	case MSM_SD_SHUTDOWN:
+	case MSM_SD_NOTIFY_FREEZE:
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	default: {
+		if (ioctl_ptr == NULL) {
+			pr_err("Wrong ioctl_ptr for cmd %u\n", cmd);
+			return -EINVAL;
+		}
+
+		*ioctl_ptr = arg;
+		if (((*ioctl_ptr) == NULL) ||
+			((*ioctl_ptr)->ioctl_ptr == NULL) ||
+			((*ioctl_ptr)->len == 0)) {
+			pr_err("Error invalid ioctl argument cmd %u", cmd);
+			return -EINVAL;
+		}
+		break;
+	}
+	}
+	return 0;
+}
+
+static unsigned long cpp_cx_ipeak_update(struct cpp_device *cpp_dev,
+	unsigned long clock, int idx)
+{
+	unsigned long clock_rate = 0;
+	int ret = 0;
+
+	if ((clock >= cpp_dev->hw_info.freq_tbl
+		[(cpp_dev->hw_info.freq_tbl_count) - 1]) &&
+		(cpp_dev->turbo_vote == 0)) {
+		ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, true);
+		if (ret) {
+			pr_err("cx_ipeak voting failed setting clock below turbo");
+			clock = cpp_dev->hw_info.freq_tbl
+				[(cpp_dev->hw_info.freq_tbl_count) - 2];
+		} else {
+			cpp_dev->turbo_vote = 1;
+		}
+		clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx);
+	} else if (clock < cpp_dev->hw_info.freq_tbl
+		[(cpp_dev->hw_info.freq_tbl_count) - 1]) {
+		clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx);
+		if (cpp_dev->turbo_vote == 1) {
+			ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false);
+			if (ret)
+				pr_err("cx_ipeak unvoting failed");
+			else
+				cpp_dev->turbo_vote = 0;
+		}
+	}
+	return clock_rate;
+}
+
+static long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct cpp_device *cpp_dev = NULL;
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = NULL;
+	int rc = 0;
+
+	if (sd == NULL) {
+		pr_err("sd %pK\n", sd);
+		return -EINVAL;
+	}
+	cpp_dev = v4l2_get_subdevdata(sd);
+	if (cpp_dev == NULL) {
+		pr_err("cpp_dev is null\n");
+		return -EINVAL;
+	}
+
+	if (_IOC_DIR(cmd) == _IOC_NONE) {
+		pr_err("Invalid ioctl/subdev cmd %u", cmd);
+		return -EINVAL;
+	}
+
+	rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr);
+	if (rc != 0) {
+		pr_err("input validation failed\n");
+		return rc;
+	}
+	mutex_lock(&cpp_dev->mutex);
+
+	CPP_DBG("E cmd: 0x%x\n", cmd);
+	switch (cmd) {
+	case VIDIOC_MSM_CPP_GET_HW_INFO: {
+		CPP_DBG("VIDIOC_MSM_CPP_GET_HW_INFO\n");
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&cpp_dev->hw_info,
+			sizeof(struct cpp_hw_info))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+		break;
+	}
+
+	case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
+		CPP_DBG("VIDIOC_MSM_CPP_LOAD_FIRMWARE\n");
+		if (cpp_dev->is_firmware_loaded == 0) {
+			if (cpp_dev->fw_name_bin != NULL) {
+				kfree(cpp_dev->fw_name_bin);
+				cpp_dev->fw_name_bin = NULL;
+			}
+			if (cpp_dev->fw) {
+				release_firmware(cpp_dev->fw);
+				cpp_dev->fw = NULL;
+			}
+			if ((ioctl_ptr->len == 0) ||
+				(ioctl_ptr->len > MSM_CPP_MAX_FW_NAME_LEN)) {
+				pr_err("ioctl_ptr->len is 0\n");
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1,
+				GFP_KERNEL);
+			if (!cpp_dev->fw_name_bin) {
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			if (ioctl_ptr->ioctl_ptr == NULL) {
+				pr_err("ioctl_ptr->ioctl_ptr=NULL\n");
+				kfree(cpp_dev->fw_name_bin);
+				cpp_dev->fw_name_bin = NULL;
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			rc = (copy_from_user(cpp_dev->fw_name_bin,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+			if (rc) {
+				ERR_COPY_FROM_USER();
+				kfree(cpp_dev->fw_name_bin);
+				cpp_dev->fw_name_bin = NULL;
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			*(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0';
+			rc = request_firmware(&cpp_dev->fw,
+				cpp_dev->fw_name_bin,
+				&cpp_dev->pdev->dev);
+			if (rc) {
+				dev_err(&cpp_dev->pdev->dev,
+					"Fail to loc blob %s dev %pK, rc:%d\n",
+					cpp_dev->fw_name_bin,
+					&cpp_dev->pdev->dev, rc);
+				kfree(cpp_dev->fw_name_bin);
+				cpp_dev->fw_name_bin = NULL;
+				cpp_dev->fw = NULL;
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			msm_camera_enable_irq(cpp_dev->irq, false);
+			rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+			if (rc < 0) {
+				pr_err("%s: load firmware failure %d-retry\n",
+					__func__, rc);
+				rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+				if (rc < 0) {
+					enable_irq(cpp_dev->irq->start);
+					mutex_unlock(&cpp_dev->mutex);
+					return rc;
+				}
+			}
+			rc = msm_cpp_fw_version(cpp_dev);
+			if (rc < 0) {
+				pr_err("%s: get firmware failure %d\n",
+					__func__, rc);
+				enable_irq(cpp_dev->irq->start);
+				mutex_unlock(&cpp_dev->mutex);
+				return rc;
+			}
+			msm_camera_enable_irq(cpp_dev->irq, true);
+			cpp_dev->is_firmware_loaded = 1;
+		}
+		break;
+	}
+	case VIDIOC_MSM_CPP_CFG:
+		CPP_DBG("VIDIOC_MSM_CPP_CFG\n");
+		rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
+		break;
+	case VIDIOC_MSM_CPP_FLUSH_QUEUE:
+		CPP_DBG("VIDIOC_MSM_CPP_FLUSH_QUEUE\n");
+		rc = msm_cpp_flush_frames(cpp_dev);
+		break;
+	case VIDIOC_MSM_CPP_DELETE_STREAM_BUFF:
+	case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO:
+	case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: {
+		uint32_t j;
+		struct msm_cpp_stream_buff_info_t *u_stream_buff_info = NULL;
+		struct msm_cpp_stream_buff_info_t k_stream_buff_info;
+		struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL;
+
+		memset(&k_stream_buff_info, 0, sizeof(k_stream_buff_info));
+		CPP_DBG("VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO\n");
+		if (sizeof(struct msm_cpp_stream_buff_info_t) !=
+			ioctl_ptr->len) {
+			pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!u_stream_buff_info) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_cpp_copy_from_ioctl_ptr(u_stream_buff_info,
+			ioctl_ptr);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			kfree(u_stream_buff_info);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+		k_stream_buff_info.identity = u_stream_buff_info->identity;
+
+		if (k_stream_buff_info.num_buffs > MSM_CAMERA_MAX_STREAM_BUF) {
+			pr_err("%s:%d: unexpected large num buff requested\n",
+				__func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (u_stream_buff_info->num_buffs != 0) {
+			k_stream_buff_info.buffer_info =
+				kzalloc(k_stream_buff_info.num_buffs *
+				sizeof(struct msm_cpp_buffer_info_t),
+				GFP_KERNEL);
+			if (ZERO_OR_NULL_PTR(k_stream_buff_info.buffer_info)) {
+				pr_err("%s:%d: malloc error\n",
+					__func__, __LINE__);
+				kfree(u_stream_buff_info);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+
+			rc = (copy_from_user(k_stream_buff_info.buffer_info,
+				(void __user *)u_stream_buff_info->buffer_info,
+				k_stream_buff_info.num_buffs *
+				sizeof(struct msm_cpp_buffer_info_t)) ?
+				-EFAULT : 0);
+			if (rc) {
+				ERR_COPY_FROM_USER();
+				kfree(k_stream_buff_info.buffer_info);
+				kfree(u_stream_buff_info);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+		}
+
+		buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+				(k_stream_buff_info.identity >> 16) & 0xFFFF,
+				k_stream_buff_info.identity & 0xFFFF);
+
+		if (buff_queue_info == NULL) {
+			if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF)
+				goto STREAM_BUFF_END;
+
+			rc = msm_cpp_add_buff_queue_entry(cpp_dev,
+				((k_stream_buff_info.identity >> 16) & 0xFFFF),
+				(k_stream_buff_info.identity & 0xFFFF));
+
+			if (rc)
+				goto STREAM_BUFF_END;
+
+			if (cpp_dev->stream_cnt == 0) {
+				cpp_dev->state = CPP_STATE_ACTIVE;
+				msm_cpp_clear_timer(cpp_dev);
+				msm_cpp_clean_queue(cpp_dev);
+			}
+			cpp_dev->stream_cnt++;
+			CPP_DBG("stream_cnt:%d\n", cpp_dev->stream_cnt);
+		}
+		buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+			((k_stream_buff_info.identity >> 16) & 0xFFFF),
+			(k_stream_buff_info.identity & 0xFFFF));
+		if (buff_queue_info == NULL) {
+			pr_err("error finding buffer queue entry identity:%d\n",
+				k_stream_buff_info.identity);
+			kfree(k_stream_buff_info.buffer_info);
+			kfree(u_stream_buff_info);
+			cpp_dev->stream_cnt--;
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF) {
+			for (j = 0; j < k_stream_buff_info.num_buffs; j++) {
+				msm_cpp_dequeue_buff(cpp_dev, buff_queue_info,
+				k_stream_buff_info.buffer_info[j].index,
+				k_stream_buff_info.buffer_info[j].native_buff);
+			}
+		} else {
+			for (j = 0; j < k_stream_buff_info.num_buffs; j++) {
+				msm_cpp_queue_buffer_info(cpp_dev,
+					buff_queue_info,
+					&k_stream_buff_info.buffer_info[j]);
+			}
+		}
+
+STREAM_BUFF_END:
+		kfree(k_stream_buff_info.buffer_info);
+		kfree(u_stream_buff_info);
+
+		break;
+	}
+	case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
+		uint32_t identity;
+		struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
+		CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n");
+		if (ioctl_ptr->len != sizeof(uint32_t)) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_cpp_copy_from_ioctl_ptr(&identity, ioctl_ptr);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev,
+			((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+		if (buff_queue_info == NULL) {
+			pr_err("error finding buffer queue entry for identity:%d\n",
+				identity);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info);
+		rc = msm_cpp_free_buff_queue_entry(cpp_dev,
+			buff_queue_info->session_id,
+			buff_queue_info->stream_id);
+		if (cpp_dev->stream_cnt > 0) {
+			cpp_dev->stream_cnt--;
+			pr_debug("stream_cnt:%d\n", cpp_dev->stream_cnt);
+			if (cpp_dev->stream_cnt == 0) {
+				rc = msm_cpp_update_bandwidth_setting(cpp_dev,
+					0, 0);
+				if (rc < 0)
+					pr_err("Bandwidth Reset Failed!\n");
+				cpp_dev->state = CPP_STATE_IDLE;
+				msm_cpp_clear_timer(cpp_dev);
+				msm_cpp_clean_queue(cpp_dev);
+			}
+		} else {
+			pr_err("error: stream count underflow %d\n",
+				cpp_dev->stream_cnt);
+		}
+		break;
+	}
+	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
+		struct msm_device_queue *queue = &cpp_dev->eventData_q;
+		struct msm_queue_cmd *event_qcmd;
+		struct msm_cpp_frame_info_t *process_frame;
+
+		CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n");
+		event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT);
+		if (!event_qcmd) {
+			pr_err("no queue cmd available");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		process_frame = event_qcmd->command;
+		CPP_DBG("fid %d\n", process_frame->frame_id);
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			process_frame,
+			sizeof(struct msm_cpp_frame_info_t))) {
+			mutex_unlock(&cpp_dev->mutex);
+			kfree(process_frame->cpp_cmd_msg);
+			kfree(process_frame);
+			kfree(event_qcmd);
+			return -EFAULT;
+		}
+
+		kfree(process_frame->cpp_cmd_msg);
+		kfree(process_frame);
+		kfree(event_qcmd);
+		break;
+	}
+	case VIDIOC_MSM_CPP_SET_CLOCK: {
+		int msm_cpp_core_clk_idx;
+		struct msm_cpp_clock_settings_t clock_settings;
+		unsigned long clock_rate = 0;
+
+		CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n");
+		if (ioctl_ptr->len == 0) {
+			pr_err("ioctl_ptr->len is 0\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (ioctl_ptr->ioctl_ptr == NULL) {
+			pr_err("ioctl_ptr->ioctl_ptr is NULL\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) {
+			pr_err("Not valid ioctl_ptr->len\n");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_cpp_copy_from_ioctl_ptr(&clock_settings, ioctl_ptr);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		if (clock_settings.clock_rate > 0) {
+			msm_cpp_core_clk_idx = msm_cpp_get_clock_index(cpp_dev,
+				"cpp_core_clk");
+			if (msm_cpp_core_clk_idx < 0) {
+				pr_err(" Fail to get clock index\n");
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			rc = msm_cpp_update_bandwidth_setting(cpp_dev,
+					clock_settings.avg,
+					clock_settings.inst);
+			if (rc < 0) {
+				pr_err("Bandwidth Set Failed!\n");
+				rc = msm_cpp_update_bandwidth_setting(cpp_dev,
+					0, 0);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			if (cpp_dev->cpp_cx_ipeak) {
+				clock_rate = cpp_cx_ipeak_update(cpp_dev,
+					clock_settings.clock_rate,
+					msm_cpp_core_clk_idx);
+			} else {
+				clock_rate = msm_cpp_set_core_clk(cpp_dev,
+					clock_settings.clock_rate,
+					msm_cpp_core_clk_idx);
+			}
+			if (rc < 0) {
+				pr_err("Fail to set core clk\n");
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			if (clock_rate != clock_settings.clock_rate)
+				pr_err("clock rate differ from settings\n");
+			msm_isp_util_update_clk_rate(clock_settings.clock_rate);
+		}
+		break;
+	}
+	case MSM_SD_NOTIFY_FREEZE:
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	case MSM_SD_SHUTDOWN:
+		CPP_DBG("MSM_SD_SHUTDOWN\n");
+		mutex_unlock(&cpp_dev->mutex);
+		pr_warn("shutdown cpp node. open cnt:%d\n",
+			cpp_dev->cpp_open_cnt);
+
+		if (atomic_read(&cpp_timer.used))
+			pr_debug("Timer state not cleared\n");
+
+		while (cpp_dev->cpp_open_cnt != 0)
+			cpp_close_node(sd, NULL);
+		mutex_lock(&cpp_dev->mutex);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_CPP_QUEUE_BUF: {
+		struct msm_pproc_queue_buf_info queue_buf_info;
+
+		CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n");
+
+		if (ioctl_ptr->len != sizeof(struct msm_pproc_queue_buf_info)) {
+			pr_err("%s: Not valid ioctl_ptr->len\n", __func__);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		rc = msm_cpp_copy_from_ioctl_ptr(&queue_buf_info, ioctl_ptr);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			break;
+		}
+
+		if (queue_buf_info.is_buf_dirty) {
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+				0x0, &queue_buf_info.buff_mgr_info);
+		} else {
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+				0x0, &queue_buf_info.buff_mgr_info);
+		}
+		if (rc < 0) {
+			pr_err("error in buf done\n");
+			rc = -EINVAL;
+		}
+
+		break;
+	}
+	case VIDIOC_MSM_CPP_POP_STREAM_BUFFER: {
+		struct msm_buf_mngr_info buff_mgr_info;
+		struct msm_cpp_frame_info_t frame_info;
+		uint32_t ioctl_cmd, idx;
+
+		if (ioctl_ptr->ioctl_ptr == NULL ||
+			(ioctl_ptr->len !=
+			sizeof(struct msm_cpp_frame_info_t))) {
+			rc = -EINVAL;
+			break;
+		}
+
+		rc = msm_cpp_copy_from_ioctl_ptr(&frame_info, ioctl_ptr);
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			break;
+		}
+
+		memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+		buff_mgr_info.session_id =
+			((frame_info.identity >> 16) & 0xFFFF);
+		buff_mgr_info.stream_id = (frame_info.identity & 0xFFFF);
+		buff_mgr_info.type =
+			MSM_CAMERA_BUF_MNGR_BUF_PLANAR;
+		if (IS_DEFAULT_OUTPUT_BUF_INDEX(
+			frame_info.output_buffer_info[0].index)) {
+			ioctl_cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF;
+			idx = 0x0;
+		} else {
+			ioctl_cmd = VIDIOC_MSM_BUF_MNGR_IOCTL_CMD;
+			idx = MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+		}
+		rc = msm_cpp_buffer_ops(cpp_dev, ioctl_cmd, idx,
+			&buff_mgr_info);
+		if (rc < 0) {
+			rc = -EAGAIN;
+			pr_err_ratelimited("POP: get_buf err rc:%d, index %d\n",
+				rc, frame_info.output_buffer_info[0].index);
+			break;
+		}
+		buff_mgr_info.frame_id = frame_info.frame_id;
+		rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+			0x0, &buff_mgr_info);
+		if (rc < 0) {
+			pr_err("error in buf done\n");
+			rc = -EAGAIN;
+		}
+		break;
+	}
+	default:
+		pr_err_ratelimited("invalid value: cmd=0x%x\n", cmd);
+		break;
+	case VIDIOC_MSM_CPP_IOMMU_ATTACH: {
+		if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
+			int32_t stall_disable;
+			struct msm_camera_smmu_attach_type cpp_attach_info;
+
+			if (ioctl_ptr->len !=
+				sizeof(struct msm_camera_smmu_attach_type)) {
+				rc = -EINVAL;
+				break;
+			}
+
+			memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
+			rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
+				ioctl_ptr);
+			if (rc < 0) {
+				pr_err("CPP_IOMMU_ATTACH copy from user fail");
+				break;
+			}
+
+			cpp_dev->security_mode = cpp_attach_info.attach;
+			stall_disable = 1;
+			/* disable smmu stall on fault */
+			cam_smmu_set_attr(cpp_dev->iommu_hdl,
+				DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
+			if (cpp_dev->security_mode == SECURE_MODE) {
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_ATTACH_SEC_CPP);
+			} else {
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_ATTACH);
+			}
+			if (rc < 0) {
+				pr_err("%s:%diommu_attach_device failed\n",
+					__func__, __LINE__);
+				rc = -EINVAL;
+				break;
+			}
+			cpp_dev->iommu_state = CPP_IOMMU_STATE_ATTACHED;
+		} else {
+			pr_err("%s:%d IOMMMU attach triggered in invalid state\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case VIDIOC_MSM_CPP_IOMMU_DETACH: {
+		if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) &&
+			(cpp_dev->stream_cnt == 0)) {
+			struct msm_camera_smmu_attach_type cpp_attach_info;
+
+			if (ioctl_ptr->len !=
+				sizeof(struct msm_camera_smmu_attach_type)) {
+				rc = -EINVAL;
+				break;
+			}
+
+			memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
+			rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
+				ioctl_ptr);
+			if (rc < 0) {
+				pr_err("CPP_IOMMU_DETTACH copy from user fail");
+				break;
+			}
+
+			cpp_dev->security_mode = cpp_attach_info.attach;
+
+			if (cpp_dev->security_mode == SECURE_MODE)
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_DETACH_SEC_CPP);
+			else
+				rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+					CAM_SMMU_DETACH);
+			if (rc < 0) {
+				pr_err("%s:%diommu detach failed\n", __func__,
+					__LINE__);
+				rc = -EINVAL;
+				break;
+			}
+			cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED;
+		} else {
+			pr_err("%s:%d IOMMMU attach triggered in invalid state\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	}
+	mutex_unlock(&cpp_dev->mutex);
+	CPP_DBG("X\n");
+	return rc;
+}
+
+static int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	CPP_DBG("Called\n");
+	return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS, NULL);
+}
+
+static int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	CPP_DBG("Called\n");
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = {
+	.ioctl = msm_cpp_subdev_ioctl,
+	.subscribe_event = msm_cpp_subscribe_event,
+	.unsubscribe_event = msm_cpp_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_cpp_subdev_ops = {
+	.core = &msm_cpp_subdev_core_ops,
+};
+
+static long msm_cpp_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev;
+	struct v4l2_subdev *sd;
+	struct v4l2_fh *vfh = NULL;
+
+	if ((arg == NULL) || (file == NULL)) {
+		pr_err("Invalid input parameters arg %pK, file %pK\n",
+			arg, file);
+		return -EINVAL;
+	}
+	vdev = video_devdata(file);
+	sd = vdev_to_v4l2_subdev(vdev);
+
+	if (sd == NULL) {
+		pr_err("Invalid input parameter sd %pK\n", sd);
+		return -EINVAL;
+	}
+	vfh = file->private_data;
+
+	switch (cmd) {
+	case VIDIOC_DQEVENT:
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+			return -ENOIOCTLCMD;
+
+		return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+	case VIDIOC_MSM_CPP_GET_INST_INFO: {
+		uint32_t i;
+		struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+		struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+		struct msm_cpp_frame_info_t inst_info;
+
+		memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));
+		for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+			if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
+				inst_info.inst_id = i;
+				break;
+			}
+		}
+		if (copy_to_user(
+				(void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+				sizeof(struct msm_cpp_frame_info_t))) {
+			return -EFAULT;
+		}
+	}
+	break;
+	default:
+		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+	}
+
+	return 0;
+}
+
+static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl);
+}
+
+
+#ifdef CONFIG_COMPAT
+static struct msm_cpp_frame_info_t *get_64bit_cpp_frame_from_compat(
+	struct msm_camera_v4l2_ioctl_t *kp_ioctl)
+{
+	struct msm_cpp_frame_info32_t *new_frame32 = NULL;
+	struct msm_cpp_frame_info_t *new_frame = NULL;
+	uint32_t *cpp_frame_msg;
+	void __user *cpp_cmd_msg_64bit;
+	int32_t rc, i;
+
+	new_frame32 = kzalloc(sizeof(struct msm_cpp_frame_info32_t),
+		GFP_KERNEL);
+	if (!new_frame32)
+		goto no_mem32;
+
+	new_frame = kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
+	if (!new_frame)
+		goto no_mem;
+
+	rc = (copy_from_user(new_frame32, (void __user *)kp_ioctl->ioctl_ptr,
+			sizeof(struct msm_cpp_frame_info32_t)) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		goto frame_err;
+	}
+
+	new_frame->frame_id = new_frame32->frame_id;
+	new_frame->inst_id = new_frame32->inst_id;
+	new_frame->client_id = new_frame32->client_id;
+	new_frame->frame_type = new_frame32->frame_type;
+	new_frame->num_strips = new_frame32->num_strips;
+
+	new_frame->src_fd =  new_frame32->src_fd;
+	new_frame->dst_fd =  new_frame32->dst_fd;
+
+	new_frame->timestamp.tv_sec =
+		(unsigned long)new_frame32->timestamp.tv_sec;
+	new_frame->timestamp.tv_usec =
+		(unsigned long)new_frame32->timestamp.tv_usec;
+
+	new_frame->in_time.tv_sec =
+		(unsigned long)new_frame32->in_time.tv_sec;
+	new_frame->in_time.tv_usec =
+		(unsigned long)new_frame32->in_time.tv_usec;
+
+	new_frame->out_time.tv_sec =
+		(unsigned long)new_frame32->out_time.tv_sec;
+	new_frame->out_time.tv_usec =
+		(unsigned long)new_frame32->out_time.tv_usec;
+
+	new_frame->msg_len = new_frame32->msg_len;
+	new_frame->identity = new_frame32->identity;
+	new_frame->input_buffer_info = new_frame32->input_buffer_info;
+	new_frame->output_buffer_info[0] =
+		new_frame32->output_buffer_info[0];
+	new_frame->output_buffer_info[1] =
+		new_frame32->output_buffer_info[1];
+	new_frame->output_buffer_info[2] =
+		new_frame32->output_buffer_info[2];
+	new_frame->output_buffer_info[3] =
+		new_frame32->output_buffer_info[3];
+	new_frame->output_buffer_info[4] =
+		new_frame32->output_buffer_info[4];
+	new_frame->output_buffer_info[5] =
+		new_frame32->output_buffer_info[5];
+	new_frame->output_buffer_info[6] =
+		new_frame32->output_buffer_info[6];
+	new_frame->output_buffer_info[7] =
+		new_frame32->output_buffer_info[7];
+	new_frame->duplicate_buffer_info =
+		new_frame32->duplicate_buffer_info;
+	new_frame->tnr_scratch_buffer_info[0] =
+		new_frame32->tnr_scratch_buffer_info[0];
+	new_frame->tnr_scratch_buffer_info[1] =
+		new_frame32->tnr_scratch_buffer_info[1];
+	new_frame->duplicate_output = new_frame32->duplicate_output;
+	new_frame->we_disable = new_frame32->we_disable;
+	new_frame->duplicate_identity = new_frame32->duplicate_identity;
+	new_frame->feature_mask = new_frame32->feature_mask;
+	new_frame->partial_frame_indicator =
+		new_frame32->partial_frame_indicator;
+	new_frame->first_payload = new_frame32->first_payload;
+	new_frame->last_payload = new_frame32->last_payload;
+	new_frame->first_stripe_index = new_frame32->first_stripe_index;
+	new_frame->last_stripe_index = new_frame32->last_stripe_index;
+	new_frame->stripe_info_offset =
+		new_frame32->stripe_info_offset;
+	new_frame->stripe_info = new_frame32->stripe_info;
+	new_frame->batch_info.batch_mode =
+		new_frame32->batch_info.batch_mode;
+	new_frame->batch_info.batch_size =
+		new_frame32->batch_info.batch_size;
+	new_frame->batch_info.cont_idx =
+		new_frame32->batch_info.cont_idx;
+	for (i = 0; i < MAX_PLANES; i++)
+		new_frame->batch_info.intra_plane_offset[i] =
+			new_frame32->batch_info.intra_plane_offset[i];
+	new_frame->batch_info.pick_preview_idx =
+		new_frame32->batch_info.pick_preview_idx;
+
+	/* Convert the 32 bit pointer to 64 bit pointer */
+	new_frame->cookie = compat_ptr(new_frame32->cookie);
+	cpp_cmd_msg_64bit = compat_ptr(new_frame32->cpp_cmd_msg);
+	if ((new_frame->msg_len == 0) ||
+		(new_frame->msg_len > MSM_CPP_MAX_FRAME_LENGTH)) {
+		pr_err("%s:%d: Invalid frame len:%d\n", __func__,
+			__LINE__, new_frame->msg_len);
+		goto frame_err;
+	}
+
+	cpp_frame_msg = kcalloc(new_frame->msg_len, sizeof(uint32_t),
+		GFP_KERNEL);
+	if (!cpp_frame_msg)
+		goto frame_err;
+
+	rc = (copy_from_user(cpp_frame_msg,
+		(void __user *)cpp_cmd_msg_64bit,
+		sizeof(uint32_t)*new_frame->msg_len) ? -EFAULT : 0);
+	if (rc) {
+		ERR_COPY_FROM_USER();
+		goto frame_msg_err;
+	}
+	new_frame->cpp_cmd_msg = cpp_frame_msg;
+
+	kfree(new_frame32);
+	return new_frame;
+
+frame_msg_err:
+	kfree(cpp_frame_msg);
+frame_err:
+	kfree(new_frame);
+no_mem:
+	kfree(new_frame32);
+no_mem32:
+	return NULL;
+}
+
+static void get_compat_frame_from_64bit(struct msm_cpp_frame_info_t *frame,
+	struct msm_cpp_frame_info32_t *k32_frame)
+{
+	int32_t i;
+
+	k32_frame->frame_id = frame->frame_id;
+	k32_frame->inst_id = frame->inst_id;
+	k32_frame->client_id = frame->client_id;
+	k32_frame->frame_type = frame->frame_type;
+	k32_frame->num_strips = frame->num_strips;
+
+	k32_frame->src_fd = frame->src_fd;
+	k32_frame->dst_fd = frame->dst_fd;
+
+	k32_frame->timestamp.tv_sec = (uint32_t)frame->timestamp.tv_sec;
+	k32_frame->timestamp.tv_usec = (uint32_t)frame->timestamp.tv_usec;
+
+	k32_frame->in_time.tv_sec = (uint32_t)frame->in_time.tv_sec;
+	k32_frame->in_time.tv_usec = (uint32_t)frame->in_time.tv_usec;
+
+	k32_frame->out_time.tv_sec = (uint32_t)frame->out_time.tv_sec;
+	k32_frame->out_time.tv_usec = (uint32_t)frame->out_time.tv_usec;
+
+	k32_frame->msg_len = frame->msg_len;
+	k32_frame->identity = frame->identity;
+	k32_frame->input_buffer_info = frame->input_buffer_info;
+	k32_frame->output_buffer_info[0] = frame->output_buffer_info[0];
+	k32_frame->output_buffer_info[1] = frame->output_buffer_info[1];
+	k32_frame->output_buffer_info[2] = frame->output_buffer_info[2];
+	k32_frame->output_buffer_info[3] = frame->output_buffer_info[3];
+	k32_frame->output_buffer_info[4] = frame->output_buffer_info[4];
+	k32_frame->output_buffer_info[5] = frame->output_buffer_info[5];
+	k32_frame->output_buffer_info[6] = frame->output_buffer_info[6];
+	k32_frame->output_buffer_info[7] = frame->output_buffer_info[7];
+	k32_frame->duplicate_buffer_info = frame->duplicate_buffer_info;
+	k32_frame->duplicate_output = frame->duplicate_output;
+	k32_frame->we_disable = frame->we_disable;
+	k32_frame->duplicate_identity = frame->duplicate_identity;
+	k32_frame->feature_mask = frame->feature_mask;
+	k32_frame->cookie = ptr_to_compat(frame->cookie);
+	k32_frame->partial_frame_indicator = frame->partial_frame_indicator;
+	k32_frame->first_payload = frame->first_payload;
+	k32_frame->last_payload = frame->last_payload;
+	k32_frame->first_stripe_index = frame->first_stripe_index;
+	k32_frame->last_stripe_index = frame->last_stripe_index;
+	k32_frame->stripe_info_offset = frame->stripe_info_offset;
+	k32_frame->stripe_info = frame->stripe_info;
+	k32_frame->batch_info.batch_mode = frame->batch_info.batch_mode;
+	k32_frame->batch_info.batch_size = frame->batch_info.batch_size;
+	k32_frame->batch_info.cont_idx = frame->batch_info.cont_idx;
+	for (i = 0; i < MAX_PLANES; i++)
+		k32_frame->batch_info.intra_plane_offset[i] =
+			frame->batch_info.intra_plane_offset[i];
+	k32_frame->batch_info.pick_preview_idx =
+		frame->batch_info.pick_preview_idx;
+}
+
+static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct cpp_device *cpp_dev = NULL;
+
+	int32_t rc = 0;
+	struct msm_camera_v4l2_ioctl_t kp_ioctl;
+	struct msm_camera_v4l2_ioctl32_t up32_ioctl;
+	struct msm_cpp_clock_settings_t clock_settings;
+	struct msm_pproc_queue_buf_info k_queue_buf;
+	struct msm_cpp_stream_buff_info_t k_cpp_buff_info;
+	struct msm_cpp_frame_info32_t k32_frame_info;
+	struct msm_cpp_frame_info_t k64_frame_info;
+	struct msm_camera_smmu_attach_type kb_cpp_smmu_attach_info;
+	uint32_t identity_k = 0;
+	bool is_copytouser_req = true;
+	void __user *up = (void __user *)arg;
+
+	if (sd == NULL) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return -EINVAL;
+	}
+	cpp_dev = v4l2_get_subdevdata(sd);
+	if (!vdev || !cpp_dev) {
+		pr_err("Invalid vdev %pK or cpp_dev %pK structures!",
+			vdev, cpp_dev);
+		return -EINVAL;
+	}
+	mutex_lock(&cpp_dev->mutex);
+	/*
+	 * copy the user space 32 bit pointer to kernel space 32 bit compat
+	 * pointer
+	 */
+	if (copy_from_user(&up32_ioctl, (void __user *)up,
+		sizeof(up32_ioctl))) {
+		mutex_unlock(&cpp_dev->mutex);
+		return -EFAULT;
+	}
+
+	/* copy the data from 32 bit compat to kernel space 64 bit pointer */
+	kp_ioctl.id = up32_ioctl.id;
+	kp_ioctl.len = up32_ioctl.len;
+	kp_ioctl.trans_code = up32_ioctl.trans_code;
+	/* Convert the 32 bit pointer to 64 bit pointer */
+	kp_ioctl.ioctl_ptr = compat_ptr(up32_ioctl.ioctl_ptr);
+	if (!kp_ioctl.ioctl_ptr) {
+		pr_err("%s: Invalid ioctl pointer\n", __func__);
+		mutex_unlock(&cpp_dev->mutex);
+		return -EINVAL;
+	}
+
+	/*
+	 * Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's
+	 * except VIDIOC_MSM_CPP_CFG32, which needs special
+	 * processing
+	 */
+	switch (cmd) {
+	case VIDIOC_MSM_CPP_CFG32:
+	{
+		struct msm_cpp_frame_info32_t k32_frame_info;
+		struct msm_cpp_frame_info_t *cpp_frame = NULL;
+		void __user *status;
+
+		if (copy_from_user(&k32_frame_info,
+			(void __user *)kp_ioctl.ioctl_ptr,
+			sizeof(k32_frame_info))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+		/* Get the cpp frame pointer */
+		cpp_frame = get_64bit_cpp_frame_from_compat(&kp_ioctl);
+
+		/* Configure the cpp frame */
+		if (cpp_frame) {
+			rc = msm_cpp_cfg_frame(cpp_dev, cpp_frame);
+			/* Cpp_frame can be free'd by cfg_frame in error */
+			if (rc >= 0) {
+				k32_frame_info.output_buffer_info[0] =
+					cpp_frame->output_buffer_info[0];
+				k32_frame_info.output_buffer_info[1] =
+					cpp_frame->output_buffer_info[1];
+			}
+		} else {
+			pr_err("%s: Error getting frame\n", __func__);
+			mutex_unlock(&cpp_dev->mutex);
+			rc = -EINVAL;
+		}
+
+		kp_ioctl.trans_code = rc;
+
+		/* Convert the 32 bit pointer to 64 bit pointer */
+		status = compat_ptr(k32_frame_info.status);
+
+		if (copy_to_user(status, &rc,
+			sizeof(void *)))
+			pr_err("error cannot copy error\n");
+
+		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
+			&k32_frame_info,
+			sizeof(k32_frame_info))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+
+		cmd = VIDIOC_MSM_CPP_CFG;
+		break;
+	}
+	case VIDIOC_MSM_CPP_GET_HW_INFO32:
+	{
+		struct cpp_hw_info_32_t u32_cpp_hw_info;
+		uint32_t i;
+
+		u32_cpp_hw_info.cpp_hw_version =
+			cpp_dev->hw_info.cpp_hw_version;
+		u32_cpp_hw_info.cpp_hw_caps = cpp_dev->hw_info.cpp_hw_caps;
+		memset(&u32_cpp_hw_info.freq_tbl, 0x00,
+				sizeof(u32_cpp_hw_info.freq_tbl));
+		for (i = 0; i < cpp_dev->hw_info.freq_tbl_count; i++)
+			u32_cpp_hw_info.freq_tbl[i] =
+				cpp_dev->hw_info.freq_tbl[i];
+
+		u32_cpp_hw_info.freq_tbl_count =
+			cpp_dev->hw_info.freq_tbl_count;
+		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
+			&u32_cpp_hw_info, sizeof(struct cpp_hw_info_32_t))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+
+		cmd = VIDIOC_MSM_CPP_GET_HW_INFO;
+		break;
+	}
+	case VIDIOC_MSM_CPP_LOAD_FIRMWARE32:
+		cmd = VIDIOC_MSM_CPP_LOAD_FIRMWARE;
+		break;
+	case VIDIOC_MSM_CPP_GET_INST_INFO32:
+	{
+		struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+		struct msm_cpp_frame_info32_t inst_info;
+		struct v4l2_fh *vfh = NULL;
+		uint32_t i;
+
+		vfh = file->private_data;
+		memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info32_t));
+		for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+			if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
+				inst_info.inst_id = i;
+				break;
+			}
+		}
+		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
+			&inst_info, sizeof(struct msm_cpp_frame_info32_t))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+		cmd = VIDIOC_MSM_CPP_GET_INST_INFO;
+		break;
+	}
+	case VIDIOC_MSM_CPP_FLUSH_QUEUE32:
+		cmd = VIDIOC_MSM_CPP_FLUSH_QUEUE;
+		break;
+	case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO32:
+	case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32:
+	case VIDIOC_MSM_CPP_DELETE_STREAM_BUFF32:
+	{
+		compat_uptr_t p;
+		struct msm_cpp_stream_buff_info32_t __user *u32_cpp_buff_info =
+			(struct msm_cpp_stream_buff_info32_t __user *)
+			kp_ioctl.ioctl_ptr;
+
+		get_user(k_cpp_buff_info.identity,
+			&u32_cpp_buff_info->identity);
+		get_user(k_cpp_buff_info.num_buffs,
+			&u32_cpp_buff_info->num_buffs);
+		get_user(p, &u32_cpp_buff_info->buffer_info);
+		k_cpp_buff_info.buffer_info =
+			(__force struct msm_cpp_buffer_info_t *)compat_ptr(p);
+
+		kp_ioctl.ioctl_ptr = (__force void __user *)&k_cpp_buff_info;
+		if (is_compat_task()) {
+			if (kp_ioctl.len != sizeof(
+				struct msm_cpp_stream_buff_info32_t)) {
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			kp_ioctl.len =
+				sizeof(struct msm_cpp_stream_buff_info_t);
+		}
+		is_copytouser_req = false;
+		if (cmd == VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32)
+			cmd = VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO;
+		else if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF32)
+			cmd = VIDIOC_MSM_CPP_DELETE_STREAM_BUFF;
+		else
+			cmd = VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO;
+		break;
+	}
+	case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO32: {
+		uint32_t __user *identity_u =
+			(uint32_t __user *)kp_ioctl.ioctl_ptr;
+
+		get_user(identity_k, identity_u);
+		kp_ioctl.ioctl_ptr = (__force void __user *)&identity_k;
+		kp_ioctl.len = sizeof(uint32_t);
+		is_copytouser_req = false;
+		cmd = VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO;
+		break;
+	}
+	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD32:
+	{
+		struct msm_device_queue *queue = &cpp_dev->eventData_q;
+		struct msm_queue_cmd *event_qcmd;
+		struct msm_cpp_frame_info_t *process_frame;
+		struct msm_cpp_frame_info32_t k32_process_frame;
+
+		CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n");
+		event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT);
+		if (!event_qcmd) {
+			pr_err("no queue cmd available");
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		process_frame = event_qcmd->command;
+
+		memset(&k32_process_frame, 0, sizeof(k32_process_frame));
+		get_compat_frame_from_64bit(process_frame, &k32_process_frame);
+
+		CPP_DBG("fid %d\n", process_frame->frame_id);
+		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
+			&k32_process_frame,
+			sizeof(struct msm_cpp_frame_info32_t))) {
+			kfree(process_frame->cpp_cmd_msg);
+			kfree(process_frame);
+			kfree(event_qcmd);
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+
+		kfree(process_frame->cpp_cmd_msg);
+		kfree(process_frame);
+		kfree(event_qcmd);
+		cmd = VIDIOC_MSM_CPP_GET_EVENTPAYLOAD;
+		break;
+	}
+	case VIDIOC_MSM_CPP_SET_CLOCK32:
+	{
+		struct msm_cpp_clock_settings32_t __user *clock_settings32 =
+			(struct msm_cpp_clock_settings32_t __user *)
+			kp_ioctl.ioctl_ptr;
+		get_user(clock_settings.clock_rate,
+			&clock_settings32->clock_rate);
+		get_user(clock_settings.avg, &clock_settings32->avg);
+		get_user(clock_settings.inst, &clock_settings32->inst);
+		kp_ioctl.ioctl_ptr = (__force void __user *)&clock_settings;
+		if (is_compat_task()) {
+			if (kp_ioctl.len != sizeof(
+				struct msm_cpp_clock_settings32_t)) {
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+			kp_ioctl.len =
+				sizeof(struct msm_cpp_clock_settings_t);
+		}
+		is_copytouser_req = false;
+		cmd = VIDIOC_MSM_CPP_SET_CLOCK;
+		break;
+	}
+	case VIDIOC_MSM_CPP_QUEUE_BUF32:
+	{
+		struct msm_pproc_queue_buf_info32_t __user *u32_queue_buf =
+			(struct msm_pproc_queue_buf_info32_t __user *)
+			kp_ioctl.ioctl_ptr;
+
+		get_user(k_queue_buf.is_buf_dirty,
+			&u32_queue_buf->is_buf_dirty);
+		get_user(k_queue_buf.buff_mgr_info.session_id,
+			&u32_queue_buf->buff_mgr_info.session_id);
+		get_user(k_queue_buf.buff_mgr_info.stream_id,
+			&u32_queue_buf->buff_mgr_info.stream_id);
+		get_user(k_queue_buf.buff_mgr_info.frame_id,
+			&u32_queue_buf->buff_mgr_info.frame_id);
+		get_user(k_queue_buf.buff_mgr_info.index,
+			&u32_queue_buf->buff_mgr_info.index);
+		get_user(k_queue_buf.buff_mgr_info.timestamp.tv_sec,
+			&u32_queue_buf->buff_mgr_info.timestamp.tv_sec);
+		get_user(k_queue_buf.buff_mgr_info.timestamp.tv_usec,
+			&u32_queue_buf->buff_mgr_info.timestamp.tv_usec);
+
+		kp_ioctl.ioctl_ptr = (__force void __user *)&k_queue_buf;
+		kp_ioctl.len = sizeof(struct msm_pproc_queue_buf_info);
+		is_copytouser_req = false;
+		cmd = VIDIOC_MSM_CPP_QUEUE_BUF;
+		break;
+	}
+	case VIDIOC_MSM_CPP_POP_STREAM_BUFFER32:
+	{
+		if (kp_ioctl.len != sizeof(struct msm_cpp_frame_info32_t)) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		kp_ioctl.len = sizeof(struct msm_cpp_frame_info_t);
+
+		if (copy_from_user(&k32_frame_info,
+			(void __user *)kp_ioctl.ioctl_ptr,
+			sizeof(k32_frame_info))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EFAULT;
+		}
+
+		memset(&k64_frame_info, 0, sizeof(k64_frame_info));
+		k64_frame_info.identity = k32_frame_info.identity;
+		k64_frame_info.frame_id = k32_frame_info.frame_id;
+
+		kp_ioctl.ioctl_ptr = (__force void __user *)&k64_frame_info;
+
+		is_copytouser_req = false;
+		cmd = VIDIOC_MSM_CPP_POP_STREAM_BUFFER;
+		break;
+	}
+	case VIDIOC_MSM_CPP_IOMMU_ATTACH32:
+	case VIDIOC_MSM_CPP_IOMMU_DETACH32:
+	{
+		if ((kp_ioctl.len != sizeof(struct msm_camera_smmu_attach_type))
+			|| (copy_from_user(&kb_cpp_smmu_attach_info,
+				(void __user *)kp_ioctl.ioctl_ptr,
+				sizeof(kb_cpp_smmu_attach_info)))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+
+		kp_ioctl.ioctl_ptr =
+			(__force void __user *)&kb_cpp_smmu_attach_info;
+		is_copytouser_req = false;
+		cmd = (cmd == VIDIOC_MSM_CPP_IOMMU_ATTACH32) ?
+			VIDIOC_MSM_CPP_IOMMU_ATTACH :
+			VIDIOC_MSM_CPP_IOMMU_DETACH;
+		break;
+	}
+	case MSM_SD_NOTIFY_FREEZE:
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	case MSM_SD_SHUTDOWN:
+		cmd = MSM_SD_SHUTDOWN;
+		break;
+	default:
+		pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n",
+				__func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE);
+		mutex_unlock(&cpp_dev->mutex);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&cpp_dev->mutex);
+	switch (cmd) {
+	case VIDIOC_MSM_CPP_LOAD_FIRMWARE:
+	case VIDIOC_MSM_CPP_FLUSH_QUEUE:
+	case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO:
+	case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO:
+	case VIDIOC_MSM_CPP_DELETE_STREAM_BUFF:
+	case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO:
+	case VIDIOC_MSM_CPP_SET_CLOCK:
+	case VIDIOC_MSM_CPP_QUEUE_BUF:
+	case VIDIOC_MSM_CPP_POP_STREAM_BUFFER:
+	case VIDIOC_MSM_CPP_IOMMU_ATTACH:
+	case VIDIOC_MSM_CPP_IOMMU_DETACH:
+	case MSM_SD_SHUTDOWN:
+		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &kp_ioctl);
+		break;
+	case VIDIOC_MSM_CPP_GET_HW_INFO:
+	case VIDIOC_MSM_CPP_CFG:
+	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD:
+	case VIDIOC_MSM_CPP_GET_INST_INFO:
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	default:
+		pr_err_ratelimited("%s: unsupported compat type :%d\n",
+				__func__, cmd);
+		return -EINVAL;
+	}
+
+	if (is_copytouser_req) {
+		up32_ioctl.id = kp_ioctl.id;
+		up32_ioctl.len = kp_ioctl.len;
+		up32_ioctl.trans_code = kp_ioctl.trans_code;
+		up32_ioctl.ioctl_ptr = ptr_to_compat(kp_ioctl.ioctl_ptr);
+
+		if (copy_to_user((void __user *)up, &up32_ioctl,
+			sizeof(up32_ioctl)))
+			return -EFAULT;
+	}
+
+	return rc;
+}
+#endif
+
+static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops = {
+	.unlocked_ioctl = msm_cpp_subdev_fops_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = msm_cpp_subdev_fops_compat_ioctl,
+#endif
+};
+static  int msm_cpp_update_gdscr_status(struct cpp_device *cpp_dev,
+	bool status)
+{
+	int rc = 0;
+	int msm_cpp_reg_idx;
+
+	if (!cpp_dev) {
+		pr_err("%s: cpp device invalid\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	msm_cpp_reg_idx = msm_cpp_get_regulator_index(cpp_dev, "vdd");
+	if (msm_cpp_reg_idx < 0) {
+		pr_err(" Fail to regulator index\n");
+		return -EINVAL;
+	}
+	rc = msm_camera_regulator_set_mode(cpp_dev->cpp_vdd +
+		msm_cpp_reg_idx, 1, status);
+	if (rc < 0)
+		pr_err("update cpp gdscr status failed\n");
+
+end:
+	return rc;
+}
+static void msm_cpp_set_vbif_reg_values(struct cpp_device *cpp_dev)
+{
+	int i, reg, val;
+	const u32 *vbif_qos_arr = NULL;
+	int vbif_qos_len = 0;
+	struct platform_device *pdev;
+
+	pr_debug("%s\n", __func__);
+	if (cpp_dev != NULL) {
+		pdev = cpp_dev->pdev;
+		vbif_qos_arr = of_get_property(pdev->dev.of_node,
+					       "qcom,vbif-qos-setting",
+						&vbif_qos_len);
+		if (!vbif_qos_arr || (vbif_qos_len & 1)) {
+			pr_debug("%s: vbif qos setting not found\n",
+				 __func__);
+			vbif_qos_len = 0;
+		}
+		vbif_qos_len /= sizeof(u32);
+		pr_debug("%s: vbif_qos_len %d\n", __func__, vbif_qos_len);
+		if (cpp_dev->vbif_base) {
+			for (i = 0; i < vbif_qos_len; i = i+2) {
+				reg = be32_to_cpu(vbif_qos_arr[i]);
+				val = be32_to_cpu(vbif_qos_arr[i+1]);
+				pr_debug("%s: DT: offset %x, val %x\n",
+					 __func__, reg, val);
+				pr_debug("%s: before write to register 0x%x\n",
+					 __func__, msm_camera_io_r(
+					 cpp_dev->vbif_base + reg));
+				msm_camera_io_w(val, cpp_dev->vbif_base + reg);
+				pr_debug("%s: after write to register 0x%x\n",
+					 __func__, msm_camera_io_r(
+					 cpp_dev->vbif_base + reg));
+			}
+		}
+	}
+}
+
+static int msm_cpp_buffer_private_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, uint32_t id, void *arg) {
+
+	int32_t rc = 0;
+
+	switch (id) {
+	case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
+		struct msm_camera_private_ioctl_arg ioctl_arg;
+		struct msm_buf_mngr_info *buff_mgr_info =
+			(struct msm_buf_mngr_info *)arg;
+
+		ioctl_arg.id = MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX;
+		ioctl_arg.size = sizeof(struct msm_buf_mngr_info);
+		ioctl_arg.result = 0;
+		ioctl_arg.reserved = 0x0;
+		ioctl_arg.ioctl_ptr = 0x0;
+		MSM_CAM_GET_IOCTL_ARG_PTR(&ioctl_arg.ioctl_ptr, &buff_mgr_info,
+			sizeof(void *));
+		rc = cpp_dev->buf_mgr_ops.msm_cam_buf_mgr_ops(buff_mgr_ops,
+			&ioctl_arg);
+		/* Use VIDIOC_MSM_BUF_MNGR_GET_BUF if getbuf with indx fails */
+		if (rc < 0) {
+			pr_err_ratelimited("get_buf_by_idx for %d err %d,use get_buf\n",
+				buff_mgr_info->index, rc);
+			rc = cpp_dev->buf_mgr_ops.msm_cam_buf_mgr_ops(
+				VIDIOC_MSM_BUF_MNGR_GET_BUF, buff_mgr_info);
+		}
+		break;
+	}
+	default: {
+		pr_err("unsupported buffer manager ioctl\n");
+		break;
+	}
+	}
+	return rc;
+}
+
+static int cpp_probe(struct platform_device *pdev)
+{
+	struct cpp_device *cpp_dev;
+	int rc = 0;
+	int i = 0;
+
+	CPP_DBG("E");
+
+	cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL);
+	if (!cpp_dev)
+		return -ENOMEM;
+
+	v4l2_subdev_init(&cpp_dev->msm_sd.sd, &msm_cpp_subdev_ops);
+	cpp_dev->msm_sd.sd.internal_ops = &msm_cpp_internal_ops;
+	snprintf(cpp_dev->msm_sd.sd.name, ARRAY_SIZE(cpp_dev->msm_sd.sd.name),
+		 "cpp");
+	cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev);
+	platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd);
+	mutex_init(&cpp_dev->mutex);
+	spin_lock_init(&cpp_dev->tasklet_lock);
+	spin_lock_init(&cpp_timer.data.processed_frame_lock);
+
+	cpp_dev->pdev = pdev;
+	memset(&cpp_vbif, 0, sizeof(struct msm_cpp_vbif_data));
+	cpp_dev->vbif_data = &cpp_vbif;
+
+	cpp_dev->base =
+		msm_camera_get_reg_base(pdev, "cpp", true);
+	if (!cpp_dev->base) {
+		rc = -ENOMEM;
+		pr_err("failed to get cpp_base\n");
+		goto cpp_base_failed;
+	}
+
+	cpp_dev->vbif_base =
+		msm_camera_get_reg_base(pdev, "cpp_vbif", false);
+	if (!cpp_dev->vbif_base) {
+		rc = -ENOMEM;
+		pr_err("failed to get vbif_base\n");
+		goto vbif_base_failed;
+	}
+
+	cpp_dev->cpp_hw_base =
+		msm_camera_get_reg_base(pdev, "cpp_hw", true);
+	if (!cpp_dev->cpp_hw_base) {
+		rc = -ENOMEM;
+		pr_err("failed to get cpp_hw_base\n");
+		goto cpp_hw_base_failed;
+	}
+
+	cpp_dev->irq = msm_camera_get_irq(pdev, "cpp");
+	if (!cpp_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto mem_err;
+	}
+
+	rc = msm_camera_get_clk_info(pdev, &cpp_dev->clk_info,
+		&cpp_dev->cpp_clk, &cpp_dev->num_clks);
+	if (rc < 0) {
+		pr_err("%s: failed to get the clocks\n", __func__);
+		goto mem_err;
+	}
+
+	/* set memcore and mem periphery logic flags to 0 */
+	for (i = 0; i < cpp_dev->num_clks; i++) {
+		if ((strcmp(cpp_dev->clk_info[i].clk_name,
+			"cpp_core_clk") == 0) ||
+			(strcmp(cpp_dev->clk_info[i].clk_name,
+			"camss_cpp_axi_clk") == 0) ||
+			(strcmp(cpp_dev->clk_info[i].clk_name,
+			"micro_iface_clk") == 0)) {
+			msm_camera_set_clk_flags(cpp_dev->cpp_clk[i],
+				CLKFLAG_NORETAIN_MEM);
+			msm_camera_set_clk_flags(cpp_dev->cpp_clk[i],
+				CLKFLAG_NORETAIN_PERIPH);
+		}
+	}
+
+	rc = msm_camera_get_reset_info(pdev,
+			&cpp_dev->micro_iface_reset);
+	if (rc < 0) {
+		cpp_dev->micro_iface_reset = NULL;
+		pr_err("%s: failed to get micro_iface_reset\n",
+				__func__);
+		goto get_reg_err;
+	}
+	rc = msm_camera_get_regulator_info(pdev, &cpp_dev->cpp_vdd,
+		&cpp_dev->num_reg);
+	if (rc < 0) {
+		pr_err("%s: failed to get the regulators\n", __func__);
+		goto get_reset_err;
+	}
+
+	msm_cpp_fetch_dt_params(cpp_dev);
+
+	rc = msm_cpp_read_payload_params_from_dt(cpp_dev);
+	if (rc)
+		goto cpp_probe_init_error;
+
+	if (cpp_dev->bus_master_flag)
+		rc = msm_cpp_init_bandwidth_mgr(cpp_dev);
+	else
+		rc = msm_isp_init_bandwidth_mgr(NULL, ISP_CPP);
+	if (rc < 0) {
+		pr_err("%s: Bandwidth registration Failed!\n", __func__);
+		goto cpp_probe_init_error;
+	}
+
+	cpp_dev->state = CPP_STATE_BOOT;
+	rc = cpp_init_hardware(cpp_dev);
+	if (rc < 0)
+		goto bus_de_init;
+
+	media_entity_pads_init(&cpp_dev->msm_sd.sd.entity, 0, NULL);
+	cpp_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CPP;
+	cpp_dev->msm_sd.sd.entity.name = pdev->name;
+	cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY;
+	msm_sd_register(&cpp_dev->msm_sd);
+	msm_cam_copy_v4l2_subdev_fops(&msm_cpp_v4l2_subdev_fops);
+	msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl;
+#ifdef CONFIG_COMPAT
+	msm_cpp_v4l2_subdev_fops.compat_ioctl32 =
+		msm_cpp_subdev_fops_compat_ioctl;
+#endif
+
+	cpp_dev->msm_sd.sd.devnode->fops = &msm_cpp_v4l2_subdev_fops;
+
+
+	msm_camera_io_w(0x0, cpp_dev->base +
+					   MSM_CPP_MICRO_IRQGEN_MASK);
+	msm_camera_io_w(0xFFFF, cpp_dev->base +
+					   MSM_CPP_MICRO_IRQGEN_CLR);
+	msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0);
+	cpp_release_hardware(cpp_dev);
+	cpp_dev->state = CPP_STATE_OFF;
+	msm_cpp_enable_debugfs(cpp_dev);
+
+	msm_queue_init(&cpp_dev->eventData_q, "eventdata");
+	msm_queue_init(&cpp_dev->processing_q, "frame");
+	INIT_LIST_HEAD(&cpp_dev->tasklet_q);
+	tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet,
+		(unsigned long)cpp_dev);
+	cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
+	cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
+		GFP_KERNEL);
+
+	if (!cpp_dev->work) {
+		pr_err("no enough memory\n");
+		rc = -ENOMEM;
+		goto bus_de_init;
+	}
+
+	INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
+	cpp_dev->cpp_open_cnt = 0;
+	cpp_dev->is_firmware_loaded = 0;
+	cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED;
+	cpp_timer.data.cpp_dev = cpp_dev;
+	atomic_set(&cpp_timer.used, 0);
+	/* install timer for cpp timeout */
+	CPP_DBG("Installing cpp_timer\n");
+	setup_timer(&cpp_timer.cpp_timer,
+		cpp_timer_callback, (unsigned long)&cpp_timer);
+	cpp_dev->fw_name_bin = NULL;
+	cpp_dev->max_timeout_trial_cnt = MSM_CPP_MAX_TIMEOUT_TRIAL;
+
+
+	if (rc == 0)
+		CPP_DBG("SUCCESS.");
+	else
+		CPP_DBG("FAILED.");
+	return rc;
+
+bus_de_init:
+	if (cpp_dev->bus_master_flag)
+		msm_cpp_deinit_bandwidth_mgr(cpp_dev);
+	else
+		msm_isp_deinit_bandwidth_mgr(ISP_CPP);
+cpp_probe_init_error:
+	media_entity_cleanup(&cpp_dev->msm_sd.sd.entity);
+	msm_sd_unregister(&cpp_dev->msm_sd);
+get_reset_err:
+	reset_control_put(cpp_dev->micro_iface_reset);
+get_reg_err:
+	msm_camera_put_clk_info(pdev, &cpp_dev->clk_info, &cpp_dev->cpp_clk,
+		cpp_dev->num_clks);
+mem_err:
+	msm_camera_put_reg_base(pdev, cpp_dev->cpp_hw_base, "cpp_hw", true);
+cpp_hw_base_failed:
+	msm_camera_put_reg_base(pdev, cpp_dev->vbif_base, "cpp_vbif", false);
+vbif_base_failed:
+	msm_camera_put_reg_base(pdev, cpp_dev->base, "cpp", true);
+cpp_base_failed:
+	msm_camera_put_reg_base(pdev, cpp_dev->camss_cpp_base,
+		"camss_cpp", true);
+
+	kfree(cpp_dev);
+	return rc;
+}
+
+static const struct of_device_id msm_cpp_dt_match[] = {
+	{.compatible = "qcom,cpp"},
+	{}
+};
+
+static int cpp_device_remove(struct platform_device *dev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(dev);
+	struct cpp_device  *cpp_dev;
+
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	cpp_dev = (struct cpp_device *)v4l2_get_subdevdata(sd);
+	if (!cpp_dev) {
+		pr_err("%s: cpp device is NULL\n", __func__);
+		return 0;
+	}
+
+	if (cpp_dev->fw) {
+		release_firmware(cpp_dev->fw);
+		cpp_dev->fw = NULL;
+	}
+	if (cpp_dev->bus_master_flag)
+		msm_cpp_deinit_bandwidth_mgr(cpp_dev);
+	else
+		msm_isp_deinit_bandwidth_mgr(ISP_CPP);
+	msm_sd_unregister(&cpp_dev->msm_sd);
+	msm_camera_put_reg_base(dev, cpp_dev->camss_cpp_base,
+		"camss_cpp", true);
+	msm_camera_put_reg_base(dev, cpp_dev->base, "cpp", true);
+	msm_camera_put_reg_base(dev, cpp_dev->vbif_base, "cpp_vbif", false);
+	msm_camera_put_reg_base(dev, cpp_dev->cpp_hw_base, "cpp_hw", true);
+	msm_camera_put_regulators(dev, &cpp_dev->cpp_vdd,
+		cpp_dev->num_reg);
+	msm_camera_put_clk_info(dev, &cpp_dev->clk_info,
+		&cpp_dev->cpp_clk, cpp_dev->num_clks);
+	msm_camera_unregister_bus_client(CAM_BUS_CLIENT_CPP);
+	mutex_destroy(&cpp_dev->mutex);
+	kfree(cpp_dev->work);
+
+	reset_control_put(cpp_dev->micro_iface_reset);
+
+	destroy_workqueue(cpp_dev->timer_wq);
+	kfree(cpp_dev->cpp_clk);
+	kfree(cpp_dev);
+	return 0;
+}
+
+static struct platform_driver cpp_driver = {
+	.probe = cpp_probe,
+	.remove = cpp_device_remove,
+	.driver = {
+		.name = MSM_CPP_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cpp_dt_match,
+	},
+};
+
+static int __init msm_cpp_init_module(void)
+{
+	return platform_driver_register(&cpp_driver);
+}
+
+static void __exit msm_cpp_exit_module(void)
+{
+	platform_driver_unregister(&cpp_driver);
+}
+
+static int msm_cpp_debugfs_error_s(void *data, u64 val)
+{
+	pr_err("setting error inducement");
+	induce_error = val;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL,
+	msm_cpp_debugfs_error_s, "%llu\n");
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
+{
+	struct dentry *debugfs_base;
+
+	debugfs_base = debugfs_create_dir("msm_cpp", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("error", 0644, debugfs_base,
+		(void *)cpp_dev, &cpp_debugfs_error))
+		return -ENOMEM;
+
+	return 0;
+}
+
+module_init(msm_cpp_init_module);
+module_exit(msm_cpp_exit_module);
+MODULE_DESCRIPTION("MSM CPP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
new file mode 100644
index 0000000..d20d217
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -0,0 +1,311 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CPP_H__
+#define __MSM_CPP_H__
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <media/v4l2-subdev.h>
+#include "msm_generic_buf_mgr.h"
+#include "msm_sd.h"
+#include "cam_soc_api.h"
+#include "cam_hw_ops.h"
+#include <media/msmb_pproc.h>
+#include <soc/qcom/cx_ipeak.h>
+
+/* hw version info:
+ * 31:28  Major version
+ * 27:16  Minor version
+ * 15:0   Revision bits
+ */
+#define CPP_HW_VERSION_1_1_0  0x10010000
+#define CPP_HW_VERSION_1_1_1  0x10010001
+#define CPP_HW_VERSION_2_0_0  0x20000000
+#define CPP_HW_VERSION_4_0_0  0x40000000
+#define CPP_HW_VERSION_4_1_0  0x40010000
+#define CPP_HW_VERSION_5_0_0  0x50000000
+#define CPP_HW_VERSION_5_1_0  0x50010000
+
+#define VBIF_VERSION_2_3_0  0x20030000
+
+#define MAX_ACTIVE_CPP_INSTANCE 8
+#define MAX_CPP_PROCESSING_FRAME 2
+#define MAX_CPP_V4l2_EVENTS 30
+
+#define MSM_CPP_MICRO_BASE          0x4000
+#define MSM_CPP_MICRO_HW_VERSION    0x0000
+#define MSM_CPP_MICRO_IRQGEN_STAT   0x0004
+#define MSM_CPP_MICRO_IRQGEN_CLR    0x0008
+#define MSM_CPP_MICRO_IRQGEN_MASK   0x000C
+#define MSM_CPP_MICRO_FIFO_TX_DATA  0x0010
+#define MSM_CPP_MICRO_FIFO_TX_STAT  0x0014
+#define MSM_CPP_MICRO_FIFO_RX_DATA  0x0018
+#define MSM_CPP_MICRO_FIFO_RX_STAT  0x001C
+#define MSM_CPP_MICRO_BOOT_START    0x0020
+#define MSM_CPP_MICRO_BOOT_LDORG    0x0024
+#define MSM_CPP_MICRO_CLKEN_CTL     0x0030
+
+#define MSM_CPP_CMD_GET_BOOTLOADER_VER	0x1
+#define MSM_CPP_CMD_FW_LOAD				0x2
+#define MSM_CPP_CMD_EXEC_JUMP			0x3
+#define MSM_CPP_CMD_RESET_HW			0x5
+#define MSM_CPP_CMD_PROCESS_FRAME		0x6
+#define MSM_CPP_CMD_FLUSH_STREAM		0x7
+#define MSM_CPP_CMD_CFG_MEM_PARAM		0x8
+#define MSM_CPP_CMD_ERROR_REQUEST		0x9
+#define MSM_CPP_CMD_GET_STATUS			0xA
+#define MSM_CPP_CMD_GET_FW_VER			0xB
+#define MSM_CPP_CMD_GROUP_BUFFER_DUP	0x12
+#define MSM_CPP_CMD_GROUP_BUFFER	0xF
+
+#define MSM_CPP_MSG_ID_CMD          0x3E646D63
+#define MSM_CPP_MSG_ID_OK           0x0A0A4B4F
+#define MSM_CPP_MSG_ID_TRAILER      0xABCDEFAA
+
+#define MSM_CPP_MSG_ID_JUMP_ACK     0x00000001
+#define MSM_CPP_MSG_ID_FRAME_ACK    0x00000002
+#define MSM_CPP_MSG_ID_FRAME_NACK   0x00000003
+#define MSM_CPP_MSG_ID_FLUSH_ACK    0x00000004
+#define MSM_CPP_MSG_ID_FLUSH_NACK   0x00000005
+#define MSM_CPP_MSG_ID_CFG_MEM_ACK  0x00000006
+#define MSM_CPP_MSG_ID_CFG_MEM_INV  0x00000007
+#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008
+#define MSM_CPP_MSG_ID_INVALID_CMD  0x00000009
+#define MSM_CPP_MSG_ID_GEN_STATUS   0x0000000A
+#define MSM_CPP_MSG_ID_FLUSHED      0x0000000B
+#define MSM_CPP_MSG_ID_FW_VER       0x0000000C
+
+#define MSM_CPP_JUMP_ADDRESS		0x20
+#define MSM_CPP_START_ADDRESS		0x0
+#define MSM_CPP_END_ADDRESS			0x3F00
+
+#define MSM_CPP_POLL_RETRIES		200
+#define MSM_CPP_TASKLETQ_SIZE		16
+#define MSM_CPP_TX_FIFO_LEVEL		16
+#define MSM_CPP_RX_FIFO_LEVEL		512
+
+enum cpp_vbif_error {
+	CPP_VBIF_ERROR_HANG,
+	CPP_VBIF_ERROR_MAX,
+};
+
+enum cpp_vbif_client {
+	VBIF_CLIENT_CPP,
+	VBIF_CLIENT_FD,
+	VBIF_CLIENT_MAX,
+};
+
+struct msm_cpp_vbif_data {
+	int (*err_handler[VBIF_CLIENT_MAX])(void *, uint32_t);
+	void *dev[VBIF_CLIENT_MAX];
+};
+
+struct cpp_subscribe_info {
+	struct v4l2_fh *vfh;
+	uint32_t active;
+};
+
+enum cpp_state {
+	CPP_STATE_BOOT,
+	CPP_STATE_IDLE,
+	CPP_STATE_ACTIVE,
+	CPP_STATE_OFF,
+};
+
+enum cpp_iommu_state {
+	CPP_IOMMU_STATE_DETACHED,
+	CPP_IOMMU_STATE_ATTACHED,
+};
+
+enum cpp_iommu_fault_state {
+	CPP_IOMMU_FAULT_NONE,
+	CPP_IOMMU_FAULT_DETECTED,
+	CPP_IOMMU_FAULT_RECOVERED,
+};
+
+enum msm_queue {
+	MSM_CAM_Q_CTRL,     /* control command or control command status */
+	MSM_CAM_Q_VFE_EVT,  /* adsp event */
+	MSM_CAM_Q_VFE_MSG,  /* adsp message */
+	MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
+	MSM_CAM_Q_VPE_MSG,  /* vpe message */
+	MSM_CAM_Q_PP_MSG,  /* pp message */
+};
+
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	struct list_head list_vpe_frame;
+	struct list_head list_eventdata;
+	enum msm_queue type;
+	void *command;
+	atomic_t on_heap;
+	struct timespec ts;
+	uint32_t error_code;
+	uint32_t trans_code;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct msm_cpp_tasklet_queue_cmd {
+	struct list_head list;
+	uint32_t irq_status;
+	uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
+	uint32_t tx_level;
+	uint8_t cmd_used;
+};
+
+struct msm_cpp_buffer_map_info_t {
+	unsigned long len;
+	dma_addr_t phy_addr;
+	int buf_fd;
+	struct msm_cpp_buffer_info_t buff_info;
+};
+
+struct msm_cpp_buffer_map_list_t {
+	struct msm_cpp_buffer_map_info_t map_info;
+	struct list_head entry;
+};
+
+struct msm_cpp_buff_queue_info_t {
+	uint32_t used;
+	uint16_t session_id;
+	uint16_t stream_id;
+	enum smmu_attach_mode security_mode;
+	struct list_head vb2_buff_head;
+	struct list_head native_buff_head;
+};
+
+struct msm_cpp_work_t {
+	struct work_struct my_work;
+	struct cpp_device *cpp_dev;
+};
+
+struct msm_cpp_payload_params {
+	uint32_t stripe_base;
+	uint32_t stripe_size;
+	uint32_t plane_base;
+	uint32_t plane_size;
+
+	/* offsets for stripe/plane pointers in payload */
+	uint32_t rd_pntr_off;
+	uint32_t wr_0_pntr_off;
+	uint32_t rd_ref_pntr_off;
+	uint32_t wr_ref_pntr_off;
+	uint32_t wr_0_meta_data_wr_pntr_off;
+	uint32_t fe_mmu_pf_ptr_off;
+	uint32_t ref_fe_mmu_pf_ptr_off;
+	uint32_t we_mmu_pf_ptr_off;
+	uint32_t dup_we_mmu_pf_ptr_off;
+	uint32_t ref_we_mmu_pf_ptr_off;
+	uint32_t set_group_buffer_len;
+	uint32_t dup_frame_indicator_off;
+};
+
+struct cpp_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *irq;
+	void __iomem *vbif_base;
+	void __iomem *base;
+	void __iomem *cpp_hw_base;
+	void __iomem *camss_cpp_base;
+	struct clk **cpp_clk;
+	struct msm_cam_clk_info *clk_info;
+	size_t num_clks;
+	struct reset_control *micro_iface_reset;
+	struct msm_cam_regulator *cpp_vdd;
+	int num_reg;
+	struct mutex mutex;
+	enum cpp_state state;
+	enum cpp_iommu_state iommu_state;
+	uint8_t is_firmware_loaded;
+	char *fw_name_bin;
+	const struct firmware *fw;
+	struct workqueue_struct *timer_wq;
+	struct msm_cpp_work_t *work;
+	uint32_t fw_version;
+	uint8_t stream_cnt;
+	uint8_t timeout_trial_cnt;
+	uint8_t max_timeout_trial_cnt;
+
+	int domain_num;
+	struct iommu_domain *domain;
+	struct device *iommu_ctx;
+	uint32_t num_clk;
+	uint32_t min_clk_rate;
+
+	int iommu_hdl;
+	struct ion_client *ion_client;
+	enum smmu_attach_mode security_mode;
+	/* Reusing proven tasklet from msm isp */
+	atomic_t irq_cnt;
+	uint8_t taskletq_idx;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	struct tasklet_struct cpp_tasklet;
+	struct msm_cpp_tasklet_queue_cmd
+		tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE];
+
+	struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
+	uint32_t cpp_open_cnt;
+	struct cpp_hw_info hw_info;
+
+	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+	/* Processing Queue
+	 * store frame info for frames sent to microcontroller
+	 */
+	struct msm_device_queue processing_q;
+
+	struct msm_cpp_buff_queue_info_t *buff_queue;
+	uint32_t num_buffq;
+	struct msm_cam_buf_mgr_req_ops buf_mgr_ops;
+
+	uint32_t bus_client;
+	uint32_t bus_idx;
+	uint32_t bus_master_flag;
+	uint32_t micro_reset;
+	struct msm_cpp_payload_params payload_params;
+	struct msm_cpp_vbif_data *vbif_data;
+	bool turbo_vote;
+	struct cx_ipeak_client *cpp_cx_ipeak;
+	enum cpp_iommu_fault_state fault_status;
+};
+
+int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
+int msm_update_freq_tbl(struct cpp_device *cpp_dev);
+int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name);
+int msm_cpp_get_regulator_index(struct cpp_device *cpp_dev,
+	const char *regulator_name);
+long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx);
+void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev);
+int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev);
+void msm_cpp_vbif_register_error_handler(void *dev,
+	enum cpp_vbif_client client,
+	int (*client_vbif_error_handler)(void *, uint32_t));
+
+#endif /* __MSM_CPP_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
new file mode 100644
index 0000000..64f3104
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp_soc.c
@@ -0,0 +1,254 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-CPP-SOC %s:%d " fmt, __func__, __LINE__
+
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/delay.h>
+#include <media/msmb_pproc.h>
+#include "msm_cpp.h"
+
+
+#define CPP_DT_READ_U32_ERR(_dev, _key, _str, _ret, _out) { \
+		_key = _str; \
+		_ret = of_property_read_u32(_dev, _key, &_out); \
+		if (_ret) \
+			break; \
+	}
+
+#define CPP_DT_READ_U32(_dev, _str, _out) { \
+		of_property_read_u32(_dev, _str, &_out); \
+	}
+
+void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev)
+{
+	int rc = 0;
+	struct device_node *of_node = cpp_dev->pdev->dev.of_node;
+
+	if (!of_node) {
+		pr_err("%s: invalid params\n", __func__);
+		return;
+	}
+
+	of_property_read_u32(of_node, "cell-index", &cpp_dev->pdev->id);
+
+	rc = of_property_read_u32(of_node, "qcom,min-clock-rate",
+			&cpp_dev->min_clk_rate);
+	if (rc < 0) {
+		pr_debug("min-clk-rate not defined, setting it to 0\n");
+		cpp_dev->min_clk_rate = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,bus-master",
+			&cpp_dev->bus_master_flag);
+	if (rc)
+		cpp_dev->bus_master_flag = 0;
+
+	if (of_property_read_bool(of_node, "qcom,micro-reset"))
+		cpp_dev->micro_reset = 1;
+	else
+		cpp_dev->micro_reset = 0;
+}
+
+int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < cpp_dev->num_clks; i++) {
+		if (!strcmp(clk_name, cpp_dev->clk_info[i].clk_name))
+			return i;
+	}
+	return -EINVAL;
+}
+
+int msm_cpp_get_regulator_index(struct cpp_device *cpp_dev,
+	const char *regulator_name)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < cpp_dev->num_reg; i++) {
+		if (!strcmp(regulator_name, cpp_dev->cpp_vdd[i].name))
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info,
+	uint32_t min_clk_rate)
+{
+	uint32_t i;
+	uint32_t idx = 0;
+	signed long freq_tbl_entry = 0;
+
+	if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
+		(clk->ops->list_rate == NULL)) {
+		pr_err("Bad parameter\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_FREQ_TBL; i++) {
+		freq_tbl_entry = clk->ops->list_rate(clk, i);
+		pr_debug("entry=%ld\n", freq_tbl_entry);
+		if (freq_tbl_entry >= 0) {
+			if (freq_tbl_entry >= min_clk_rate) {
+				hw_info->freq_tbl[idx++] = freq_tbl_entry;
+				pr_debug("tbl[%d]=%ld\n", idx-1,
+					freq_tbl_entry);
+			}
+		} else {
+			pr_debug("freq table returned invalid entry/end %ld\n",
+				freq_tbl_entry);
+			break;
+		}
+	}
+	pr_debug("%s: idx %d", __func__, idx);
+	hw_info->freq_tbl_count = idx;
+	return 0;
+}
+
+int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev)
+{
+	int rc;
+
+	rc = reset_control_assert(cpp_dev->micro_iface_reset);
+	if (rc) {
+		pr_err("%s:micro_iface_reset assert failed\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Below usleep values are chosen based on experiments
+	 * and this was the smallest number which works. This
+	 * sleep is needed to leave enough time for Microcontroller
+	 * to resets all its registers.
+	 */
+	usleep_range(1000, 1200);
+
+	rc = reset_control_deassert(cpp_dev->micro_iface_reset);
+	if (rc) {
+		pr_err("%s:micro_iface_reset de-assert failed\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Below usleep values are chosen based on experiments
+	 * and this was the smallest number which works. This
+	 * sleep is needed to leave enough time for Microcontroller
+	 * to resets all its registers.
+	 */
+	usleep_range(1000, 1200);
+	return 0;
+}
+
+int msm_update_freq_tbl(struct cpp_device *cpp_dev)
+{
+	int msm_cpp_core_clk_idx;
+	int rc = 0;
+
+	msm_cpp_core_clk_idx = msm_cpp_get_clock_index(cpp_dev, "cpp_core_clk");
+	if (msm_cpp_core_clk_idx < 0)  {
+		pr_err("%s: fail to get clock index\n", __func__);
+		rc = msm_cpp_core_clk_idx;
+		return rc;
+	}
+	rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx],
+		&cpp_dev->hw_info, cpp_dev->min_clk_rate);
+	if (rc < 0)  {
+		pr_err("%s: fail to get frequency table\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx)
+{
+	long rc = 0;
+
+	rc = msm_camera_clk_set_rate(&cpp_dev->pdev->dev,
+		cpp_dev->cpp_clk[idx], rate);
+	if (rc < 0) {
+		pr_err("%s: fail to get frequency table\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev)
+{
+	struct platform_device *pdev = cpp_dev->pdev;
+	struct device_node *fw_info_node = NULL, *dev_node = NULL;
+	char *key = "qcom,cpp-fw-payload-info";
+	struct msm_cpp_payload_params *payload_params;
+	int ret = 0;
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("%s: Invalid platform device/node\n", __func__);
+		ret = -ENODEV;
+		goto no_cpp_node;
+	}
+
+	dev_node = pdev->dev.of_node;
+	fw_info_node = of_find_node_by_name(dev_node, key);
+	if (!fw_info_node) {
+		ret = -ENODEV;
+		goto no_binding;
+	}
+	payload_params = &cpp_dev->payload_params;
+	memset(payload_params, 0x0, sizeof(struct msm_cpp_payload_params));
+
+	do {
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-base", ret,
+			payload_params->stripe_base);
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-base", ret,
+			payload_params->plane_base);
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-size", ret,
+			payload_params->stripe_size);
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-size", ret,
+			payload_params->plane_size);
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,fe-ptr-off", ret,
+			payload_params->rd_pntr_off);
+		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,we-ptr-off", ret,
+			payload_params->wr_0_pntr_off);
+
+		CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-ptr-off",
+			payload_params->rd_ref_pntr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-ptr-off",
+			payload_params->wr_ref_pntr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,we-meta-ptr-off",
+			payload_params->wr_0_meta_data_wr_pntr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,fe-mmu-pf-ptr-off",
+			payload_params->fe_mmu_pf_ptr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-mmu-pf-ptr-off",
+			payload_params->ref_fe_mmu_pf_ptr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,we-mmu-pf-ptr-off",
+			payload_params->we_mmu_pf_ptr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,dup-we-mmu-pf-ptr-off",
+			payload_params->dup_we_mmu_pf_ptr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-mmu-pf-ptr-off",
+			payload_params->ref_we_mmu_pf_ptr_off);
+		CPP_DT_READ_U32(fw_info_node, "qcom,set-group-buffer-len",
+			payload_params->set_group_buffer_len);
+		CPP_DT_READ_U32(fw_info_node, "qcom,dup-frame-indicator-off",
+			payload_params->dup_frame_indicator_off);
+	} while (0);
+
+no_binding:
+	if (ret)
+		pr_err("%s: Error reading binding %s, ret %d\n",
+			__func__, key, ret);
+no_cpp_node:
+	return ret;
+}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
new file mode 100644
index 0000000..65a7e34
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
new file mode 100644
index 0000000..404aebd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -0,0 +1,1691 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <linux/msm_iommu_domains.h>
+#include <linux/qcom_iommu.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-entity.h>
+#include <media/msmb_generic_buf_mgr.h>
+#include <media/msmb_pproc.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-attrs.h>
+#include <linux/dma-buf.h>
+#include "msm_vpe.h"
+#include "msm_camera_io_util.h"
+
+#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF)
+#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF)
+
+#define MSM_VPE_DRV_NAME "msm_vpe"
+
+#define MSM_VPE_MAX_BUFF_QUEUE 16
+
+#define CONFIG_MSM_VPE_DBG 0
+
+#if CONFIG_MSM_VPE_DBG
+#define VPE_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static void vpe_mem_dump(const char * const name, const void * const addr,
+			int size)
+{
+	char line_str[128], *p_str;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+
+	VPE_DBG("%s: (%s) %pK %d\n", __func__, name, addr, size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			snprintf(p_str, 12, "%pK: ", p);
+			p_str += 10;
+		}
+		data = *p++;
+		snprintf(p_str, 12, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			VPE_DBG("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		VPE_DBG("%s\n", line_str);
+}
+
+static inline long long vpe_do_div(long long num, long long den)
+{
+	do_div(num, den);
+	return num;
+}
+
+#define msm_dequeue(queue, member) ({					\
+			unsigned long flags;				\
+			struct msm_device_queue *__q = (queue);		\
+			struct msm_queue_cmd *qcmd = 0;			\
+			spin_lock_irqsave(&__q->lock, flags);		\
+			if (!list_empty(&__q->list)) {			\
+				__q->len--;				\
+				qcmd = list_first_entry(&__q->list,	\
+							struct msm_queue_cmd, \
+							member);	\
+				list_del_init(&qcmd->member);		\
+			}						\
+			spin_unlock_irqrestore(&__q->lock, flags);	\
+			qcmd;						\
+		})
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static struct msm_cam_clk_info vpe_clk_info[] = {
+	{"vpe_clk", 160000000},
+	{"vpe_pclk", -1},
+};
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev);
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_debug("queue %s new max is %d\n", queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	VPE_DBG("woke up %s\n", queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry(
+	struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id)
+{
+	uint32_t i = 0;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if ((vpe_dev->buff_queue[i].used == 1) &&
+			(vpe_dev->buff_queue[i].session_id == session_id) &&
+			(vpe_dev->buff_queue[i].stream_id == stream_id)) {
+			buff_queue_info = &vpe_dev->buff_queue[i];
+			break;
+		}
+	}
+
+	if (buff_queue_info == NULL) {
+		pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+			session_id, stream_id);
+	}
+	return buff_queue_info;
+}
+
+static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+	uint8_t native_buff)
+{
+	unsigned long phy_add = 0;
+	struct list_head *buff_head;
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+
+	if (native_buff)
+		buff_head = &buff_queue_info->native_buff_head;
+	else
+		buff_head = &buff_queue_info->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buff_index) {
+			phy_add = buff->map_info.phy_addr;
+			break;
+		}
+	}
+
+	return phy_add;
+}
+
+static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue,
+	struct msm_vpe_buffer_info_t *buffer_info)
+{
+	struct list_head *buff_head;
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+	int rc = 0;
+
+	if (buffer_info->native_buff)
+		buff_head = &buff_queue->native_buff_head;
+	else
+		buff_head = &buff_queue->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buffer_info->index) {
+			pr_err("error buffer index already queued\n");
+			return -EINVAL;
+		}
+	}
+
+	buff = kzalloc(
+		sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL);
+	if (!buff)
+		return -EINVAL;
+
+	buff->map_info.buff_info = *buffer_info;
+	buff->map_info.dbuf = dma_buf_get(buffer_info->fd);
+	if (IS_ERR_OR_NULL(buff->map_info.dbuf)) {
+		pr_err("Ion dma get buf failed\n");
+		rc = PTR_ERR(buff->map_info.dbuf);
+		goto err_get;
+	}
+
+	buff->map_info.attachment = dma_buf_attach(buff->map_info.dbuf,
+		&vpe_dev->pdev->dev);
+	if (IS_ERR_OR_NULL(buff->map_info.attachment)) {
+		pr_err("Ion dma buf attach failed\n");
+		rc = PTR_ERR(buff->map_info.attachment);
+		goto err_put;
+	}
+
+	buff->map_info.table =
+		dma_buf_map_attachment(buff->map_info.attachment,
+			DMA_BIDIRECTIONAL);
+	if (IS_ERR_OR_NULL(buff->map_info.table)) {
+		pr_err("DMA buf map attachment failed\n");
+		rc = PTR_ERR(buff->map_info.table);
+		goto err_detach;
+	}
+	if (msm_map_dma_buf(buff->map_info.dbuf, buff->map_info.table,
+		vpe_dev->domain_num, 0, SZ_4K, 0,
+		&buff->map_info.phy_addr,
+		&buff->map_info.len, 0, 0)) {
+		pr_err("%s: cannot map address", __func__);
+		goto err_detachment;
+	}
+
+	INIT_LIST_HEAD(&buff->entry);
+	list_add_tail(&buff->entry, buff_head);
+
+	return buff->map_info.phy_addr;
+
+err_detachment:
+	dma_buf_unmap_attachment(buff->map_info.attachment,
+		buff->map_info.table, DMA_BIDIRECTIONAL);
+err_detach:
+	dma_buf_detach(buff->map_info.dbuf, buff->map_info.attachment);
+err_put:
+	dma_buf_put(buff->map_info.dbuf);
+err_get:
+	kzfree(buff);
+	return 0;
+}
+
+static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buffer_map_list_t *buff)
+{
+	msm_unmap_dma_buf(buff->map_info.table, vpe_dev->domain_num, 0);
+	dma_buf_unmap_attachment(buff->map_info.attachment,
+		buff->map_info.table, DMA_BIDIRECTIONAL);
+	dma_buf_detach(buff->map_info.dbuf, buff->map_info.attachment);
+	dma_buf_put(buff->map_info.dbuf);
+	list_del_init(&buff->entry);
+	kzfree(buff);
+}
+
+static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id,
+	uint32_t stream_id)
+{
+	unsigned long phy_addr = 0;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+	uint8_t native_buff = buffer_info->native_buff;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return phy_addr;
+	}
+
+	phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info,
+		buffer_info->index, native_buff);
+	if ((phy_addr == 0) && (native_buff)) {
+		phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+			buffer_info);
+	}
+	return phy_addr;
+}
+
+static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev,
+	struct msm_vpe_stream_buff_info_t *stream_buff_info)
+{
+	uint32_t j;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+		return -EINVAL;
+	}
+
+	for (j = 0; j < stream_buff_info->num_buffs; j++) {
+		msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+		&stream_buff_info->buffer_info[j]);
+	}
+	return 0;
+}
+
+static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue_info)
+{
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+	struct list_head *buff_head;
+
+	buff_head = &buff_queue_info->native_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+	}
+
+	buff_head = &buff_queue_info->vb2_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+	}
+
+	return 0;
+}
+
+static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev,
+	uint16_t session_id, uint16_t stream_id)
+{
+	uint32_t i;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if (vpe_dev->buff_queue[i].used == 0) {
+			buff_queue_info = &vpe_dev->buff_queue[i];
+			buff_queue_info->used = 1;
+			buff_queue_info->session_id = session_id;
+			buff_queue_info->stream_id = stream_id;
+			INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+			INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+			return 0;
+		}
+	}
+	pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+		session_id, stream_id);
+	return -EINVAL;
+}
+
+static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev,
+					uint32_t session_id, uint32_t stream_id)
+{
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return -EINVAL;
+	}
+
+	buff_queue_info->used = 0;
+	buff_queue_info->session_id = 0;
+	buff_queue_info->stream_id = 0;
+	INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+	INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+	return 0;
+}
+
+static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev,
+					uint32_t num_buffq)
+{
+	struct msm_vpe_buff_queue_info_t *buff_queue;
+
+	buff_queue = kzalloc(
+		sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq,
+		GFP_KERNEL);
+	if (!buff_queue) {
+		pr_err("Buff queue allocation failure\n");
+		return -ENOMEM;
+	}
+
+	if (vpe_dev->buff_queue) {
+		pr_err("Buff queue not empty\n");
+		kzfree(buff_queue);
+		return -EINVAL;
+	}
+	vpe_dev->buff_queue = buff_queue;
+	vpe_dev->num_buffq = num_buffq;
+	return 0;
+}
+
+static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev)
+{
+	uint32_t i;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if (vpe_dev->buff_queue[i].used == 1) {
+			pr_err("Queue not free sessionid: %d, streamid: %d\n",
+				vpe_dev->buff_queue[i].session_id,
+				vpe_dev->buff_queue[i].stream_id);
+			msm_vpe_free_buff_queue_entry(vpe_dev,
+				vpe_dev->buff_queue[i].session_id,
+				vpe_dev->buff_queue[i].stream_id);
+		}
+	}
+	kzfree(vpe_dev->buff_queue);
+	vpe_dev->buff_queue = NULL;
+	vpe_dev->num_buffq = 0;
+}
+
+void vpe_release_ion_client(struct kref *ref)
+{
+	struct vpe_device *vpe_dev = container_of(ref,
+		struct vpe_device, refcount);
+	ion_client_destroy(vpe_dev->client);
+}
+
+static int vpe_init_mem(struct vpe_device *vpe_dev)
+{
+	kref_init(&vpe_dev->refcount);
+	kref_get(&vpe_dev->refcount);
+	vpe_dev->client = msm_ion_client_create("vpe");
+
+	if (!vpe_dev->client) {
+		pr_err("couldn't create ion client\n");
+		return  -ENODEV;
+	}
+
+	return 0;
+}
+
+static void vpe_deinit_mem(struct vpe_device *vpe_dev)
+{
+	kref_put(&vpe_dev->refcount, vpe_release_ion_client);
+}
+
+static irqreturn_t msm_vpe_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t irq_status;
+	struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+	struct vpe_device *vpe_dev = (struct vpe_device *) data;
+
+	irq_status = msm_camera_io_r_mb(vpe_dev->base +
+					VPE_INTR_STATUS_OFFSET);
+
+	spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+	queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx];
+	if (queue_cmd->cmd_used) {
+		VPE_DBG("%s: vpe tasklet queue overflow\n", __func__);
+		list_del(&queue_cmd->list);
+	} else {
+		atomic_add(1, &vpe_dev->irq_cnt);
+	}
+	queue_cmd->irq_status = irq_status;
+
+	queue_cmd->cmd_used = 1;
+	vpe_dev->taskletq_idx =
+		(vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE;
+	list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q);
+	spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+	tasklet_schedule(&vpe_dev->vpe_tasklet);
+
+	msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+	msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status);
+
+	return IRQ_HANDLED;
+}
+
+static void msm_vpe_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct vpe_device *vpe_dev = (struct vpe_device *)data;
+	struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+
+	while (atomic_read(&vpe_dev->irq_cnt)) {
+		spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+		queue_cmd = list_first_entry(&vpe_dev->tasklet_q,
+					struct msm_vpe_tasklet_queue_cmd, list);
+		if (!queue_cmd) {
+			atomic_set(&vpe_dev->irq_cnt, 0);
+			spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+			return;
+		}
+		atomic_sub(1, &vpe_dev->irq_cnt);
+		list_del(&queue_cmd->list);
+		queue_cmd->cmd_used = 0;
+
+		spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+		VPE_DBG("Frame done!!\n");
+		msm_vpe_notify_frame_done(vpe_dev);
+	}
+}
+
+static int vpe_init_hardware(struct vpe_device *vpe_dev)
+{
+	int rc = 0;
+
+	if (vpe_dev->fs_vpe == NULL) {
+		vpe_dev->fs_vpe =
+			regulator_get(&vpe_dev->pdev->dev, "vdd");
+		if (IS_ERR(vpe_dev->fs_vpe)) {
+			pr_err("Regulator vpe vdd get failed %ld\n",
+				PTR_ERR(vpe_dev->fs_vpe));
+			vpe_dev->fs_vpe = NULL;
+			rc = -ENODEV;
+			goto fail;
+		} else if (regulator_enable(vpe_dev->fs_vpe)) {
+			pr_err("Regulator vpe vdd enable failed\n");
+			regulator_put(vpe_dev->fs_vpe);
+			vpe_dev->fs_vpe = NULL;
+			rc = -ENODEV;
+			goto fail;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+				vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1);
+	if (rc < 0) {
+		pr_err("clk enable failed\n");
+		goto disable_and_put_regulator;
+	}
+
+	vpe_dev->base = ioremap(vpe_dev->mem->start,
+		resource_size(vpe_dev->mem));
+	if (!vpe_dev->base) {
+		rc = -ENOMEM;
+		pr_err("ioremap failed\n");
+		goto disable_and_put_regulator;
+	}
+
+	if (vpe_dev->state != VPE_STATE_BOOT) {
+		rc = request_irq(vpe_dev->irq->start, msm_vpe_irq,
+				IRQF_TRIGGER_RISING,
+				"vpe", vpe_dev);
+		if (rc < 0) {
+			pr_err("irq request fail! start=%u\n",
+				(uint32_t) vpe_dev->irq->start);
+			rc = -EBUSY;
+			goto unmap_base;
+		} else {
+			VPE_DBG("Got irq! %d\n", (int)vpe_dev->irq->start);
+		}
+	} else {
+		VPE_DBG("Skip requesting the irq since device is booting\n");
+	}
+	vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+	msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE);
+	return rc;
+
+unmap_base:
+	iounmap(vpe_dev->base);
+disable_and_put_regulator:
+	regulator_disable(vpe_dev->fs_vpe);
+	regulator_put(vpe_dev->fs_vpe);
+fail:
+	return rc;
+}
+
+static int vpe_release_hardware(struct vpe_device *vpe_dev)
+{
+	if (vpe_dev->state != VPE_STATE_BOOT) {
+		free_irq(vpe_dev->irq->start, vpe_dev);
+		tasklet_kill(&vpe_dev->vpe_tasklet);
+		atomic_set(&vpe_dev->irq_cnt, 0);
+	}
+
+	msm_vpe_delete_buff_queue(vpe_dev);
+	iounmap(vpe_dev->base);
+	msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+			vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
+	return 0;
+}
+
+static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	uint32_t i;
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&vpe_dev->mutex);
+	if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("No free VPE instance\n");
+		rc = -ENODEV;
+		goto err_mutex_unlock;
+	}
+
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].active == 0) {
+			vpe_dev->vpe_subscribe_list[i].active = 1;
+			vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("No free instance\n");
+		rc = -ENODEV;
+		goto err_mutex_unlock;
+	}
+
+	VPE_DBG("open %d %pK\n", i, &fh->vfh);
+	vpe_dev->vpe_open_cnt++;
+	if (vpe_dev->vpe_open_cnt == 1) {
+		rc = vpe_init_hardware(vpe_dev);
+		if (rc < 0) {
+			pr_err("%s: Couldn't init vpe hardware\n", __func__);
+			vpe_dev->vpe_open_cnt--;
+			goto err_fixup_sub_list;
+		}
+		rc = vpe_init_mem(vpe_dev);
+		if (rc < 0) {
+			pr_err("%s: Couldn't init mem\n", __func__);
+			vpe_dev->vpe_open_cnt--;
+			rc = -ENODEV;
+			goto err_release_hardware;
+		}
+		vpe_dev->state = VPE_STATE_IDLE;
+	}
+	mutex_unlock(&vpe_dev->mutex);
+
+	return rc;
+
+err_release_hardware:
+	vpe_release_hardware(vpe_dev);
+err_fixup_sub_list:
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+			vpe_dev->vpe_subscribe_list[i].active = 0;
+			vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+err_mutex_unlock:
+	mutex_unlock(&vpe_dev->mutex);
+	return rc;
+}
+
+static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	uint32_t i;
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&vpe_dev->mutex);
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+			vpe_dev->vpe_subscribe_list[i].active = 0;
+			vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("Invalid close\n");
+		mutex_unlock(&vpe_dev->mutex);
+		return -ENODEV;
+	}
+
+	VPE_DBG("close %d %pK\n", i, &fh->vfh);
+	vpe_dev->vpe_open_cnt--;
+	if (vpe_dev->vpe_open_cnt == 0) {
+		vpe_deinit_mem(vpe_dev);
+		vpe_release_hardware(vpe_dev);
+		vpe_dev->state = VPE_STATE_OFF;
+	}
+	mutex_unlock(&vpe_dev->mutex);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
+	.open = vpe_open_node,
+	.close = vpe_close_node,
+};
+
+static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev,
+	uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+	int rc = -EINVAL;
+
+	rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl,
+		buff_mgr_ops, buff_mgr_info);
+	if (rc < 0)
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev)
+{
+	struct v4l2_event v4l2_evt;
+	struct msm_queue_cmd *frame_qcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_vpe_frame_info_t *processed_frame;
+	struct msm_device_queue *queue = &vpe_dev->processing_q;
+	struct msm_buf_mngr_info buff_mgr_info;
+	int rc = 0;
+
+	if (queue->len > 0) {
+		frame_qcmd = msm_dequeue(queue, list_frame);
+		if (!frame_qcmd) {
+			pr_err("%s: %d frame_qcmd is NULL\n",
+				 __func__, __LINE__);
+			return -EINVAL;
+		}
+		processed_frame = frame_qcmd->command;
+		do_gettimeofday(&(processed_frame->out_time));
+		kfree(frame_qcmd);
+		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+		if (!event_qcmd) {
+			pr_err("%s: Insufficient memory\n", __func__);
+			return -ENOMEM;
+		}
+		atomic_set(&event_qcmd->on_heap, 1);
+		event_qcmd->command = processed_frame;
+		VPE_DBG("fid %d\n", processed_frame->frame_id);
+		msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+
+		if (!processed_frame->output_buffer_info.processed_divert) {
+			memset(&buff_mgr_info, 0,
+				sizeof(buff_mgr_info));
+			buff_mgr_info.session_id =
+				((processed_frame->identity >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id =
+				(processed_frame->identity & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->output_buffer_info.index;
+			rc = msm_vpe_buffer_ops(vpe_dev,
+						VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+						&buff_mgr_info);
+			if (rc < 0) {
+				pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+					__func__);
+				rc = -EINVAL;
+			}
+		}
+
+		v4l2_evt.id = processed_frame->inst_id;
+		v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+		v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+	}
+	return rc;
+}
+
+static void vpe_update_scaler_params(struct vpe_device *vpe_dev,
+			struct msm_vpe_frame_strip_info strip_info)
+{
+	uint32_t out_ROI_width, out_ROI_height;
+	uint32_t src_ROI_width, src_ROI_height;
+
+	/*
+	 * phase_step_x, phase_step_y, phase_init_x and phase_init_y
+	 * are represented in fixed-point, unsigned 3.29 format
+	 */
+	uint32_t phase_step_x = 0;
+	uint32_t phase_step_y = 0;
+	uint32_t phase_init_x = 0;
+	uint32_t phase_init_y = 0;
+
+	uint32_t src_roi, src_x, src_y, src_xy, temp;
+	uint32_t yscale_filter_sel, xscale_filter_sel;
+	uint32_t scale_unit_sel_x, scale_unit_sel_y;
+	uint64_t numerator, denominator;
+
+	/*
+	 * assumption is both direction need zoom. this can be
+	 * improved.
+	 */
+	temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3;
+	msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET);
+
+	src_ROI_width  = strip_info.src_w;
+	src_ROI_height = strip_info.src_h;
+	out_ROI_width  = strip_info.dst_w;
+	out_ROI_height = strip_info.dst_h;
+
+	VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n",
+		src_ROI_width, src_ROI_height, out_ROI_width,
+		out_ROI_height);
+	src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+	msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+
+	src_x = strip_info.src_x;
+	src_y = strip_info.src_y;
+
+	VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+	src_xy = src_y*(1<<16) + src_x;
+	msm_camera_io_w(src_xy, vpe_dev->base +
+			VPE_SRC_XY_OFFSET);
+	VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
+
+	/* decide whether to use FIR or M/N for scaling */
+	if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+		(src_ROI_width < 4 * out_ROI_width - 3))
+		scale_unit_sel_x = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_x = 1;/* use M/N scalar */
+
+	if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+		(src_ROI_height < 4 * out_ROI_height - 3))
+		scale_unit_sel_y = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_y = 1;/* use M/N scalar */
+
+	/* calculate phase step for the x direction */
+
+	/*
+	 * if destination is only 1 pix wide, the value of
+	 * phase_step_x is unimportant. Assigning phase_step_x to src
+	 * ROI width as an arbitrary value.
+	 */
+	if (out_ROI_width == 1)
+		phase_step_x = (uint32_t) ((src_ROI_width) <<
+						SCALER_PHASE_BITS);
+
+		/* if using FIR scalar */
+	else if (scale_unit_sel_x == 0) {
+
+		/*
+		 * Calculate the quotient ( src_ROI_width - 1 ) (
+		 * out_ROI_width - 1) with u3.29 precision. Quotient
+		 * is rounded up to the larger 29th decimal point
+		 */
+		numerator = (uint64_t)(src_ROI_width - 1) <<
+			SCALER_PHASE_BITS;
+		/*
+		 * never equals to 0 because of the "(out_ROI_width ==
+		 * 1 )"
+		 */
+		denominator = (uint64_t)(out_ROI_width - 1);
+		/*
+		 * divide and round up to the larger 29th decimal
+		 * point.
+		 */
+		phase_step_x = (uint32_t) vpe_do_div((numerator +
+					denominator - 1), denominator);
+	} else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+		/*
+		 * Calculate the quotient ( src_ROI_width ) / (
+		 * out_ROI_width) with u3.29 precision. Quotient is
+		 * rounded down to the smaller 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_width) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_width);
+		phase_step_x =
+			(uint32_t) vpe_do_div(numerator, denominator);
+	}
+	/* calculate phase step for the y direction */
+
+	/*
+	 * if destination is only 1 pix wide, the value of
+	 * phase_step_x is unimportant. Assigning phase_step_x to src
+	 * ROI width as an arbitrary value.
+	 */
+	if (out_ROI_height == 1)
+		phase_step_y =
+		(uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+	/* if FIR scalar */
+	else if (scale_unit_sel_y == 0) {
+		/*
+		 * Calculate the quotient ( src_ROI_height - 1 ) / (
+		 * out_ROI_height - 1) with u3.29 precision. Quotient
+		 * is rounded up to the larger 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_height - 1) <<
+			SCALER_PHASE_BITS;
+		/*
+		 * never equals to 0 because of the " ( out_ROI_height
+		 * == 1 )" case
+		 */
+		denominator = (uint64_t)(out_ROI_height - 1);
+		/*
+		 * Quotient is rounded up to the larger 29th decimal
+		 * point.
+		 */
+		phase_step_y =
+		(uint32_t) vpe_do_div(
+			(numerator + denominator - 1), denominator);
+	} else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+		/*
+		 * Calculate the quotient ( src_ROI_height ) (
+		 * out_ROI_height) with u3.29 precision. Quotient is
+		 * rounded down to the smaller 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_height) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_height);
+		phase_step_y = (uint32_t) vpe_do_div(
+			numerator, denominator);
+	}
+
+	/* decide which set of FIR coefficients to use */
+	if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+		xscale_filter_sel = 0;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+		xscale_filter_sel = 1;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+		xscale_filter_sel = 2;
+	else
+		xscale_filter_sel = 3;
+
+	if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+		yscale_filter_sel = 0;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+		yscale_filter_sel = 1;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+		yscale_filter_sel = 2;
+	else
+		yscale_filter_sel = 3;
+
+	/* calculate phase init for the x direction */
+
+	/* if using FIR scalar */
+	if (scale_unit_sel_x == 0) {
+		if (out_ROI_width == 1)
+			phase_init_x =
+				(uint32_t) ((src_ROI_width - 1) <<
+							SCALER_PHASE_BITS);
+		else
+			phase_init_x = 0;
+	} else if (scale_unit_sel_x == 1) /* M over N scalar  */
+		phase_init_x = 0;
+
+	/*
+	 * calculate phase init for the y direction if using FIR
+	 * scalar
+	 */
+	if (scale_unit_sel_y == 0) {
+		if (out_ROI_height == 1)
+			phase_init_y =
+			(uint32_t) ((src_ROI_height -
+						1) << SCALER_PHASE_BITS);
+		else
+			phase_init_y = 0;
+	} else if (scale_unit_sel_y == 1) /* M over N scalar   */
+		phase_init_y = 0;
+
+	strip_info.phase_step_x = phase_step_x;
+	strip_info.phase_step_y = phase_step_y;
+	strip_info.phase_init_x = phase_init_x;
+	strip_info.phase_init_y = phase_init_y;
+	VPE_DBG("phase step x = %d, step y = %d.\n",
+		 strip_info.phase_step_x, strip_info.phase_step_y);
+	VPE_DBG("phase init x = %d, init y = %d.\n",
+		 strip_info.phase_init_x, strip_info.phase_init_y);
+
+	msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base +
+			VPE_SCALE_PHASEX_STEP_OFFSET);
+	msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base +
+			VPE_SCALE_PHASEY_STEP_OFFSET);
+
+	msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base +
+			VPE_SCALE_PHASEX_INIT_OFFSET);
+	msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base +
+			VPE_SCALE_PHASEY_INIT_OFFSET);
+}
+
+static void vpe_program_buffer_addresses(
+	struct vpe_device *vpe_dev,
+	unsigned long srcP0,
+	unsigned long srcP1,
+	unsigned long outP0,
+	unsigned long outP1)
+{
+	VPE_DBG("%s VPE Configured with:\n"
+		"Src %x, %x Dest %x, %x",
+		__func__, (uint32_t)srcP0, (uint32_t)srcP1,
+		(uint32_t)outP0, (uint32_t)outP1);
+
+	msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET);
+	msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET);
+	msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET);
+	msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET);
+}
+
+static int vpe_start(struct vpe_device *vpe_dev)
+{
+	/*  enable the frame irq, bit 0 = Display list 0 ROI done */
+	msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	msm_camera_io_dump(vpe_dev->base, 0x120, CONFIG_MSM_VPE_DBG);
+	msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18, CONFIG_MSM_VPE_DBG);
+	msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250, CONFIG_MSM_VPE_DBG);
+	msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20, CONFIG_MSM_VPE_DBG);
+	msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30, CONFIG_MSM_VPE_DBG);
+	msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10, CONFIG_MSM_VPE_DBG);
+
+	/*
+	 * This triggers the operation. When the VPE is done,
+	 * msm_vpe_irq will fire.
+	 */
+	msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET);
+	return 0;
+}
+
+static void vpe_config_axi_default(struct vpe_device *vpe_dev)
+{
+	msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET);
+}
+
+static int vpe_reset(struct vpe_device *vpe_dev)
+{
+	uint32_t vpe_version;
+	uint32_t rc = 0;
+
+	vpe_version = msm_camera_io_r(
+			vpe_dev->base + VPE_HW_VERSION_OFFSET);
+	VPE_DBG("vpe_version = 0x%x\n", vpe_version);
+	/* disable all interrupts.*/
+	msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	/* clear all pending interrupts*/
+	msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+	/* write sw_reset to reset the core. */
+	msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET);
+	/* then poll the reset bit, it should be self-cleared. */
+	while (1) {
+		rc = msm_camera_io_r(
+			vpe_dev->base + VPE_SW_RESET_OFFSET) & 0x10;
+		if (rc == 0)
+			break;
+		cpu_relax();
+	}
+	/*
+	 * at this point, hardware is reset. Then pogram to default
+	 * values.
+	 */
+	msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
+			vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET);
+
+	msm_camera_io_w(VPE_CGC_ENABLE_VALUE,
+			vpe_dev->base + VPE_CGC_EN_OFFSET);
+	msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET);
+	msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE,
+			vpe_dev->base + VPE_OP_MODE_OFFSET);
+	msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG,
+			vpe_dev->base + VPE_SCALE_CONFIG_OFFSET);
+	vpe_config_axi_default(vpe_dev);
+	return rc;
+}
+
+static int vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	uint32_t i, offset;
+
+	offset = *p;
+
+	if (offset > VPE_SCALE_COEFF_MAX_N-VPE_SCALE_COEFF_NUM) {
+		pr_err("%s: invalid offset %d passed in", __func__, offset);
+		return -EINVAL;
+	}
+
+	for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) {
+		VPE_DBG("Setting scale table %d\n", i);
+		msm_camera_io_w(*(++p),
+			vpe_dev->base + VPE_SCALE_COEFF_LSBn(i));
+		msm_camera_io_w(*(++p),
+			vpe_dev->base + VPE_SCALE_COEFF_MSBn(i));
+	}
+
+	return 0;
+}
+
+static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET);
+	msm_camera_io_w(*(++p),
+		vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET);
+}
+
+static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET);
+	msm_camera_io_w(*(++p),
+		vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET);
+}
+
+static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET);
+}
+
+/**
+ * msm_vpe_transaction_setup() - send setup for one frame to VPE
+ * @vpe_dev:	vpe device
+ * @data:	packed setup commands
+ *
+ * See msm_vpe.h for the expected format of `data'
+ */
+static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data)
+{
+	int i, rc = 0;
+	void *iter = data;
+
+	vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN);
+
+	for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) {
+		rc = vpe_update_scale_coef(vpe_dev, (uint32_t *)iter);
+		if (rc != 0)
+			return;
+
+		iter += VPE_SCALER_CONFIG_LEN;
+	}
+	vpe_input_plane_config(vpe_dev, (uint32_t *)iter);
+	iter += VPE_INPUT_PLANE_CFG_LEN;
+	vpe_output_plane_config(vpe_dev, (uint32_t *)iter);
+	iter += VPE_OUTPUT_PLANE_CFG_LEN;
+	vpe_operation_config(vpe_dev, (uint32_t *)iter);
+}
+
+static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev,
+	struct msm_queue_cmd *frame_qcmd)
+{
+	struct msm_vpe_frame_info_t *process_frame;
+
+	if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) {
+		process_frame = frame_qcmd->command;
+		msm_enqueue(&vpe_dev->processing_q,
+					&frame_qcmd->list_frame);
+
+		vpe_update_scaler_params(vpe_dev, process_frame->strip_info);
+		vpe_program_buffer_addresses(
+			vpe_dev,
+			process_frame->src_phyaddr,
+			process_frame->src_phyaddr
+			+ process_frame->src_chroma_plane_offset,
+			process_frame->dest_phyaddr,
+			process_frame->dest_phyaddr
+			+ process_frame->dest_chroma_plane_offset);
+		vpe_start(vpe_dev);
+		do_gettimeofday(&(process_frame->in_time));
+	}
+	return 0;
+}
+
+static int msm_vpe_cfg(struct vpe_device *vpe_dev,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int rc = 0;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_vpe_frame_info_t *new_frame =
+		kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL);
+	unsigned long in_phyaddr, out_phyaddr;
+	struct msm_buf_mngr_info buff_mgr_info;
+
+	if (!new_frame) {
+		pr_err("Insufficient memory. return\n");
+		return -ENOMEM;
+	}
+
+	rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_vpe_frame_info_t));
+	if (rc) {
+		pr_err("%s:%d copy from user\n", __func__, __LINE__);
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+		&new_frame->input_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!in_phyaddr) {
+		pr_err("error gettting input physical address\n");
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	memset(&new_frame->output_buffer_info, 0,
+		sizeof(struct msm_vpe_buffer_info_t));
+	memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+	buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+	buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+	buff_mgr_info.type = MSM_CAMERA_BUF_MNGR_BUF_PLANAR;
+	rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+				&buff_mgr_info);
+	if (rc < 0) {
+		pr_err("error getting buffer\n");
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	new_frame->output_buffer_info.index = buff_mgr_info.index;
+	out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+		&new_frame->output_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!out_phyaddr) {
+		pr_err("error gettting output physical address\n");
+		rc = -EINVAL;
+		goto err_put_buf;
+	}
+
+	new_frame->src_phyaddr = in_phyaddr;
+	new_frame->dest_phyaddr = out_phyaddr;
+
+	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!frame_qcmd) {
+		rc = -ENOMEM;
+		goto err_put_buf;
+	}
+
+	atomic_set(&frame_qcmd->on_heap, 1);
+	frame_qcmd->command = new_frame;
+	rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd);
+	if (rc < 0) {
+		pr_err("error cannot send frame to hardware\n");
+		rc = -EINVAL;
+		goto err_free_frame_qcmd;
+	}
+
+	return rc;
+
+err_free_frame_qcmd:
+	kfree(frame_qcmd);
+err_put_buf:
+	msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+		&buff_mgr_info);
+err_free_new_frame:
+	kfree(new_frame);
+	return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	int rc = 0;
+
+	mutex_lock(&vpe_dev->mutex);
+	switch (cmd) {
+	case VIDIOC_MSM_VPE_TRANSACTION_SETUP: {
+		struct msm_vpe_transaction_setup_cfg *cfg;
+
+		VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n");
+		if (sizeof(*cfg) != ioctl_ptr->len) {
+			pr_err("%s: size mismatch cmd=%d, len=%zu, expected=%zu",
+				__func__, cmd, ioctl_ptr->len,
+				sizeof(*cfg));
+			rc = -EINVAL;
+			break;
+		}
+
+		cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!cfg) {
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(cfg);
+			break;
+		}
+
+		msm_vpe_transaction_setup(vpe_dev, (void *)cfg);
+		kfree(cfg);
+		break;
+	}
+	case VIDIOC_MSM_VPE_CFG: {
+		VPE_DBG("VIDIOC_MSM_VPE_CFG\n");
+		rc = msm_vpe_cfg(vpe_dev, ioctl_ptr);
+		break;
+	}
+	case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: {
+		struct msm_vpe_stream_buff_info_t *u_stream_buff_info;
+		struct msm_vpe_stream_buff_info_t k_stream_buff_info;
+
+		VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n");
+
+		if (sizeof(struct msm_vpe_stream_buff_info_t) !=
+			ioctl_ptr->len) {
+			pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!u_stream_buff_info) {
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(u_stream_buff_info,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		if ((u_stream_buff_info->num_buffs == 0) ||
+			(u_stream_buff_info->num_buffs >
+				MSM_CAMERA_MAX_STREAM_BUF)) {
+			pr_err("%s:%d: Invalid number of buffers\n", __func__,
+				__LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+		k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+		k_stream_buff_info.identity = u_stream_buff_info->identity;
+		k_stream_buff_info.buffer_info =
+			kzalloc(k_stream_buff_info.num_buffs *
+			sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL);
+		if (!k_stream_buff_info.buffer_info) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(k_stream_buff_info.buffer_info,
+				(void __user *)u_stream_buff_info->buffer_info,
+				k_stream_buff_info.num_buffs *
+				sizeof(struct msm_vpe_buffer_info_t)) ?
+				-EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(k_stream_buff_info.buffer_info);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_vpe_add_buff_queue_entry(vpe_dev,
+			((k_stream_buff_info.identity >> 16) & 0xFFFF),
+			(k_stream_buff_info.identity & 0xFFFF));
+		if (!rc)
+			rc = msm_vpe_enqueue_buff_info_list(vpe_dev,
+				&k_stream_buff_info);
+
+		kfree(k_stream_buff_info.buffer_info);
+		kfree(u_stream_buff_info);
+		break;
+	}
+	case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: {
+		uint32_t identity;
+		struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+		VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+		if (ioctl_ptr->len != sizeof(uint32_t)) {
+			pr_err("%s:%d Invalid len\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(&identity,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+			((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+		if (buff_queue_info == NULL) {
+			pr_err("error finding buffer queue entry for identity:%d\n",
+				identity);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info);
+		rc = msm_vpe_free_buff_queue_entry(vpe_dev,
+			buff_queue_info->session_id,
+			buff_queue_info->stream_id);
+		break;
+	}
+	case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: {
+		struct msm_device_queue *queue = &vpe_dev->eventData_q;
+		struct msm_queue_cmd *event_qcmd;
+		struct msm_vpe_frame_info_t *process_frame;
+
+		VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
+		event_qcmd = msm_dequeue(queue, list_eventdata);
+		if (!event_qcmd) {
+			pr_err("%s: %d event_qcmd is NULL\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		process_frame = event_qcmd->command;
+		VPE_DBG("fid %d\n", process_frame->frame_id);
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			process_frame,
+			sizeof(struct msm_vpe_frame_info_t))) {
+			mutex_unlock(&vpe_dev->mutex);
+			kfree(process_frame);
+			kfree(event_qcmd);
+			return -EINVAL;
+		}
+
+		kfree(process_frame);
+		kfree(event_qcmd);
+		break;
+	}
+	}
+	mutex_unlock(&vpe_dev->mutex);
+	return rc;
+}
+
+static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS, NULL);
+}
+
+static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+	.ioctl = msm_vpe_subdev_ioctl,
+	.subscribe_event = msm_vpe_subscribe_event,
+	.unsubscribe_event = msm_vpe_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+	.core = &msm_vpe_subdev_core_ops,
+};
+
+static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops;
+
+static long msm_vpe_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct v4l2_fh *vfh = file->private_data;
+
+	switch (cmd) {
+	case VIDIOC_DQEVENT:
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+			return -ENOIOCTLCMD;
+
+		return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+	case VIDIOC_MSM_VPE_GET_INST_INFO: {
+		uint32_t i;
+		struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+		struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+		struct msm_vpe_frame_info_t inst_info;
+
+		memset(&inst_info, 0, sizeof(struct msm_vpe_frame_info_t));
+		for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+			if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) {
+				inst_info.inst_id = i;
+				break;
+			}
+		}
+		if (copy_to_user(
+				(void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+				sizeof(struct msm_vpe_frame_info_t))) {
+			return -EINVAL;
+		}
+	}
+	default:
+		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+	}
+
+	return 0;
+}
+
+static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl);
+}
+
+static int vpe_register_domain(void)
+{
+	struct msm_iova_partition vpe_iommu_partition = {
+		/* TODO: verify that these are correct? */
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	};
+	struct msm_iova_layout vpe_iommu_layout = {
+		.partitions = &vpe_iommu_partition,
+		.npartitions = 1,
+		.client_name = "camera_vpe",
+		.domain_flags = 0,
+	};
+
+	return msm_register_domain(&vpe_iommu_layout);
+}
+
+static int vpe_probe(struct platform_device *pdev)
+{
+	struct vpe_device *vpe_dev;
+	int rc = 0;
+
+	vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL);
+	if (!vpe_dev)
+		return -ENOMEM;
+
+	vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) *
+				ARRAY_SIZE(vpe_clk_info), GFP_KERNEL);
+	if (!vpe_dev->vpe_clk) {
+		rc = -ENOMEM;
+		goto err_free_vpe_dev;
+	}
+
+	v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops);
+	vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops;
+	snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name),
+		"vpe");
+	vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev);
+	platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd);
+	mutex_init(&vpe_dev->mutex);
+	spin_lock_init(&vpe_dev->tasklet_lock);
+
+	vpe_dev->pdev = pdev;
+
+	vpe_dev->mem = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "vpe");
+	if (!vpe_dev->mem) {
+		pr_err("no mem resource?\n");
+		rc = -ENODEV;
+		goto err_free_vpe_clk;
+	}
+
+	vpe_dev->irq = platform_get_resource_byname(pdev,
+						IORESOURCE_IRQ, "vpe");
+	if (!vpe_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->domain_num = vpe_register_domain();
+	if (vpe_dev->domain_num < 0) {
+		pr_err("%s: could not register domain\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->domain =
+		msm_get_iommu_domain(vpe_dev->domain_num);
+	if (!vpe_dev->domain) {
+		pr_err("%s: cannot find domain\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src");
+	vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst");
+	if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) {
+		pr_err("%s: cannot get iommu_ctx\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0);
+	vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE;
+	vpe_dev->msm_sd.sd.entity.name = pdev->name;
+	msm_sd_register(&vpe_dev->msm_sd);
+	msm_cam_copy_v4l2_subdev_fops(&msm_vpe_v4l2_subdev_fops);
+	vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops;
+	vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num;
+	vpe_dev->state = VPE_STATE_BOOT;
+	rc = vpe_init_hardware(vpe_dev);
+	if (rc < 0) {
+		pr_err("%s: Couldn't init vpe hardware\n", __func__);
+		goto err_unregister_sd;
+	}
+	vpe_reset(vpe_dev);
+	vpe_release_hardware(vpe_dev);
+	vpe_dev->state = VPE_STATE_OFF;
+
+	rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+	if (rc < 0) {
+		pr_err("Couldn't attach to vpe_src context bank\n");
+		rc = -ENODEV;
+		goto err_unregister_sd;
+	}
+	rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+	if (rc < 0) {
+		pr_err("Couldn't attach to vpe_dst context bank\n");
+		rc = -ENODEV;
+		goto err_detach_src;
+	}
+
+	vpe_dev->state = VPE_STATE_OFF;
+
+	msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata");
+	msm_queue_init(&vpe_dev->processing_q, "vpe-frame");
+	INIT_LIST_HEAD(&vpe_dev->tasklet_q);
+	tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet,
+		(unsigned long)vpe_dev);
+	vpe_dev->vpe_open_cnt = 0;
+
+	return rc;
+
+err_detach_src:
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+err_unregister_sd:
+	msm_sd_unregister(&vpe_dev->msm_sd);
+err_release_mem:
+	release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+err_free_vpe_clk:
+	kfree(vpe_dev->vpe_clk);
+err_free_vpe_dev:
+	kfree(vpe_dev);
+	return rc;
+}
+
+static int vpe_device_remove(struct platform_device *dev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(dev);
+	struct vpe_device  *vpe_dev;
+
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd);
+	if (!vpe_dev) {
+		pr_err("%s: vpe device is NULL\n", __func__);
+		return 0;
+	}
+
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+	msm_sd_unregister(&vpe_dev->msm_sd);
+	release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+	mutex_destroy(&vpe_dev->mutex);
+	kfree(vpe_dev);
+	return 0;
+}
+
+static struct platform_driver vpe_driver = {
+	.probe = vpe_probe,
+	.remove = vpe_device_remove,
+	.driver = {
+		.name = MSM_VPE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_vpe_init_module(void)
+{
+	return platform_driver_register(&vpe_driver);
+}
+
+static void __exit msm_vpe_exit_module(void)
+{
+	platform_driver_unregister(&vpe_driver);
+}
+
+module_init(msm_vpe_init_module);
+module_exit(msm_vpe_exit_module);
+MODULE_DESCRIPTION("MSM VPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
new file mode 100644
index 0000000..80be8db
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
@@ -0,0 +1,259 @@
+/* Copyright (c) 2013-2014, 2016, 2018 The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_VPE_H__
+#define __MSM_VPE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-subdev.h>
+#include "msm_sd.h"
+
+/***********  start of register offset *********************/
+#define VPE_INTR_ENABLE_OFFSET                0x0020
+#define VPE_INTR_STATUS_OFFSET                0x0024
+#define VPE_INTR_CLEAR_OFFSET                 0x0028
+#define VPE_DL0_START_OFFSET                  0x0030
+#define VPE_HW_VERSION_OFFSET                 0x0070
+#define VPE_SW_RESET_OFFSET                   0x0074
+#define VPE_AXI_RD_ARB_CONFIG_OFFSET          0x0078
+#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET   0x007C
+#define VPE_CGC_EN_OFFSET                     0x0100
+#define VPE_CMD_STATUS_OFFSET                 0x10008
+#define VPE_PROFILE_EN_OFFSET                 0x10010
+#define VPE_PROFILE_COUNT_OFFSET              0x10014
+#define VPE_CMD_MODE_OFFSET                   0x10060
+#define VPE_SRC_SIZE_OFFSET                   0x10108
+#define VPE_SRCP0_ADDR_OFFSET                 0x1010C
+#define VPE_SRCP1_ADDR_OFFSET                 0x10110
+#define VPE_SRC_YSTRIDE1_OFFSET               0x1011C
+#define VPE_SRC_FORMAT_OFFSET                 0x10124
+#define VPE_SRC_UNPACK_PATTERN1_OFFSET        0x10128
+#define VPE_OP_MODE_OFFSET                    0x10138
+#define VPE_SCALE_PHASEX_INIT_OFFSET          0x1013C
+#define VPE_SCALE_PHASEY_INIT_OFFSET          0x10140
+#define VPE_SCALE_PHASEX_STEP_OFFSET          0x10144
+#define VPE_SCALE_PHASEY_STEP_OFFSET          0x10148
+#define VPE_OUT_FORMAT_OFFSET                 0x10150
+#define VPE_OUT_PACK_PATTERN1_OFFSET          0x10154
+#define VPE_OUT_SIZE_OFFSET                   0x10164
+#define VPE_OUTP0_ADDR_OFFSET                 0x10168
+#define VPE_OUTP1_ADDR_OFFSET                 0x1016C
+#define VPE_OUT_YSTRIDE1_OFFSET               0x10178
+#define VPE_OUT_XY_OFFSET                     0x1019C
+#define VPE_SRC_XY_OFFSET                     0x10200
+#define VPE_SRC_IMAGE_SIZE_OFFSET             0x10208
+#define VPE_SCALE_CONFIG_OFFSET               0x10230
+#define VPE_DEINT_STATUS_OFFSET               0x30000
+#define VPE_DEINT_DECISION_OFFSET             0x30004
+#define VPE_DEINT_COEFF0_OFFSET               0x30010
+#define VPE_SCALE_STATUS_OFFSET               0x50000
+#define VPE_SCALE_SVI_PARAM_OFFSET            0x50010
+#define VPE_SCALE_SHARPEN_CFG_OFFSET          0x50020
+#define VPE_SCALE_COEFF_LSP_0_OFFSET          0x50400
+#define VPE_SCALE_COEFF_MSP_0_OFFSET          0x50404
+
+#define VPE_AXI_ARB_1_OFFSET                  0x00408
+#define VPE_AXI_ARB_2_OFFSET                  0x0040C
+
+#define VPE_SCALE_COEFF_LSBn(n)	(0x50400 + 8 * (n))
+#define VPE_SCALE_COEFF_MSBn(n)	(0x50404 + 8 * (n))
+#define VPE_SCALE_COEFF_NUM			32
+#define VPE_SCALE_COEFF_MAX_N			127
+
+/*********** end of register offset ********************/
+
+
+#define VPE_HARDWARE_VERSION          0x00080308
+#define VPE_SW_RESET_VALUE            0x00000010  /* bit 4 for PPP*/
+#define VPE_AXI_RD_ARB_CONFIG_VALUE   0x124924
+#define VPE_CMD_MODE_VALUE            0x1
+#define VPE_DEFAULT_OP_MODE_VALUE     0x40FC0004
+#define VPE_CGC_ENABLE_VALUE          0xffff
+#define VPE_DEFAULT_SCALE_CONFIG      0x3c
+
+#define VPE_NORMAL_MODE_CLOCK_RATE   150000000
+#define VPE_TURBO_MODE_CLOCK_RATE    200000000
+#define VPE_SUBDEV_MAX_EVENTS        30
+
+/**************************************************/
+/*********** End of command id ********************/
+/**************************************************/
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50    0x50000000
+#define HAL_MDP_PHASE_STEP_1P66    0x35555555
+#define HAL_MDP_PHASE_STEP_1P25    0x28000000
+
+
+#define MAX_ACTIVE_VPE_INSTANCE 8
+#define MAX_VPE_PROCESSING_FRAME 2
+#define MAX_VPE_V4l2_EVENTS 30
+
+#define MSM_VPE_TASKLETQ_SIZE		16
+
+/**
+ * The format of the msm_vpe_transaction_setup_cfg is as follows:
+ *
+ * - vpe_update_scale_coef (65*4 uint32_t's)
+ *   - Each table is 65 uint32_t's long
+ *   - 1st uint32_t in each table indicates offset
+ *   - Following 64 uint32_t's are the data
+ *
+ * - vpe_input_plane_config (6 uint32_t's)
+ *   - VPE_SRC_FORMAT_OFFSET
+ *   - VPE_SRC_UNPACK_PATTERN1_OFFSET
+ *   - VPE_SRC_IMAGE_SIZE_OFFSET
+ *   - VPE_SRC_YSTRIDE1_OFFSET
+ *   - VPE_SRC_SIZE_OFFSET
+ *   - VPE_SRC_XY_OFFSET
+ *
+ * - vpe_output_plane_config (5 uint32_t's)
+ *   - VPE_OUT_FORMAT_OFFSET
+ *   - VPE_OUT_PACK_PATTERN1_OFFSET
+ *   - VPE_OUT_YSTRIDE1_OFFSET
+ *   - VPE_OUT_SIZE_OFFSET
+ *   - VPE_OUT_XY_OFFSET
+ *
+ * - vpe_operation_config (1 uint32_t)
+ *   - VPE_OP_MODE_OFFSET
+ *
+ */
+
+#define VPE_SCALER_CONFIG_LEN           260
+#define VPE_INPUT_PLANE_CFG_LEN         24
+#define VPE_OUTPUT_PLANE_CFG_LEN        20
+#define VPE_OPERATION_MODE_CFG_LEN      4
+#define VPE_NUM_SCALER_TABLES		4
+
+#define VPE_TRANSACTION_SETUP_CONFIG_LEN (			\
+		(VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES)	\
+		+ VPE_INPUT_PLANE_CFG_LEN			\
+		+ VPE_OUTPUT_PLANE_CFG_LEN			\
+		+ VPE_OPERATION_MODE_CFG_LEN)
+/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */
+
+struct msm_vpe_transaction_setup_cfg {
+	uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN];
+};
+
+struct vpe_subscribe_info {
+	struct v4l2_fh *vfh;
+	uint32_t active;
+};
+
+enum vpe_state {
+	VPE_STATE_BOOT,
+	VPE_STATE_IDLE,
+	VPE_STATE_ACTIVE,
+	VPE_STATE_OFF,
+};
+
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	struct list_head list_vpe_frame;
+	struct list_head list_eventdata;
+	void *command;
+	atomic_t on_heap;
+	struct timespec ts;
+	uint32_t error_code;
+	uint32_t trans_code;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct msm_vpe_tasklet_queue_cmd {
+	struct list_head list;
+	uint32_t irq_status;
+	uint8_t cmd_used;
+};
+
+struct msm_vpe_buffer_map_info_t {
+	unsigned long len;
+	dma_addr_t phy_addr;
+	struct dma_buf *dbuf;
+	struct dma_buf_attachment *attachment;
+	struct sg_table *table;
+	struct msm_vpe_buffer_info_t buff_info;
+};
+
+struct msm_vpe_buffer_map_list_t {
+	struct msm_vpe_buffer_map_info_t map_info;
+	struct list_head entry;
+};
+
+struct msm_vpe_buff_queue_info_t {
+	uint32_t used;
+	uint16_t session_id;
+	uint16_t stream_id;
+	struct list_head vb2_buff_head;
+	struct list_head native_buff_head;
+};
+
+struct vpe_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	void __iomem *base;
+	struct clk **vpe_clk;
+	struct regulator *fs_vpe;
+	struct mutex mutex;
+	enum vpe_state state;
+
+	int domain_num;
+	struct iommu_domain *domain;
+	struct device *iommu_ctx_src;
+	struct device *iommu_ctx_dst;
+	struct ion_client *client;
+	struct kref refcount;
+
+	/* Reusing proven tasklet from msm isp */
+	atomic_t irq_cnt;
+	uint8_t taskletq_idx;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	struct tasklet_struct vpe_tasklet;
+	struct msm_vpe_tasklet_queue_cmd
+	tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE];
+
+	struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE];
+	uint32_t vpe_open_cnt;
+
+	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+	/*
+	 * Processing Queue: store frame info for frames sent to
+	 * microcontroller
+	 */
+	struct msm_device_queue processing_q;
+
+	struct msm_vpe_buff_queue_info_t *buff_queue;
+	uint32_t num_buffq;
+	struct v4l2_subdev *buf_mgr_subdev;
+};
+
+#endif /* __MSM_VPE_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
new file mode 100644
index 0000000..b04560f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_vb2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/
+obj-$(CONFIG_MSMB_CAMERA) += laser_led/
+obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/Makefile b/drivers/media/platform/msm/camera_v2/sensor/actuator/Makefile
new file mode 100644
index 0000000..37dda0f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_MSMB_CAMERA) += msm_actuator.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
new file mode 100644
index 0000000..625a0db
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -0,0 +1,2149 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include "msm_sd.h"
+#include "msm_actuator.h"
+#include "msm_cci.h"
+
+DEFINE_MSM_MUTEX(msm_actuator_mutex);
+
+#undef CDBG
+#ifdef MSM_ACTUATOR_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define PARK_LENS_LONG_STEP 7
+#define PARK_LENS_MID_STEP 5
+#define PARK_LENS_SMALL_STEP 3
+#define MAX_QVALUE 4096
+
+static struct v4l2_file_operations msm_actuator_v4l2_subdev_fops;
+static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl);
+static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl);
+
+static struct msm_actuator msm_vcm_actuator_table;
+static struct msm_actuator msm_piezo_actuator_table;
+static struct msm_actuator msm_hvcm_actuator_table;
+static struct msm_actuator msm_bivcm_actuator_table;
+
+static struct i2c_driver msm_actuator_i2c_driver;
+static struct msm_actuator *actuators[] = {
+	&msm_vcm_actuator_table,
+	&msm_piezo_actuator_table,
+	&msm_hvcm_actuator_table,
+	&msm_bivcm_actuator_table,
+};
+
+static int32_t msm_actuator_piezo_set_default_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_move_params_t *move_params)
+{
+	int32_t rc = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
+
+	CDBG("Enter\n");
+
+	if (a_ctrl->i2c_reg_tbl == NULL) {
+		pr_err("failed. i2c reg table is NULL");
+		return -EFAULT;
+	}
+
+	if (a_ctrl->curr_step_pos != 0) {
+		a_ctrl->i2c_tbl_index = 0;
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			a_ctrl->initial_code, 0, 0);
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			a_ctrl->initial_code, 0, 0);
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
+		rc = a_ctrl->i2c_client.i2c_func_tbl->
+			i2c_write_table_w_microdelay(
+			&a_ctrl->i2c_client, &reg_setting);
+		if (rc < 0) {
+			pr_err("%s: i2c write error:%d\n",
+				__func__, rc);
+			return rc;
+		}
+		a_ctrl->i2c_tbl_index = 0;
+		a_ctrl->curr_step_pos = 0;
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl,
+	int16_t next_lens_position, uint32_t hw_params, uint16_t delay)
+{
+	struct msm_actuator_reg_params_t *write_arr = NULL;
+	uint32_t hw_dword = hw_params;
+	uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
+	uint16_t value = 0;
+	uint32_t size = 0, i = 0;
+	struct msm_camera_i2c_reg_array *i2c_tbl = NULL;
+
+	CDBG("Enter\n");
+
+	if (a_ctrl == NULL) {
+		pr_err("failed. actuator ctrl is NULL");
+		return;
+	}
+
+	if (a_ctrl->i2c_reg_tbl == NULL) {
+		pr_err("failed. i2c reg table is NULL");
+		return;
+	}
+
+	size = a_ctrl->reg_tbl_size;
+	write_arr = a_ctrl->reg_tbl;
+	i2c_tbl = a_ctrl->i2c_reg_tbl;
+
+	for (i = 0; i < size; i++) {
+		if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
+			value = (next_lens_position <<
+				write_arr[i].data_shift) |
+				((hw_dword & write_arr[i].hw_mask) >>
+				write_arr[i].hw_shift);
+
+			if (write_arr[i].reg_addr != 0xFFFF) {
+				i2c_byte1 = write_arr[i].reg_addr;
+				i2c_byte2 = value;
+				if (size != (i+1)) {
+					i2c_byte2 = value & 0xFF;
+					CDBG("byte1:0x%x, byte2:0x%x\n",
+						i2c_byte1, i2c_byte2);
+					if (a_ctrl->i2c_tbl_index >
+						a_ctrl->total_steps) {
+						pr_err("failed:i2c table index out of bound\n");
+						break;
+					}
+					i2c_tbl[a_ctrl->i2c_tbl_index].
+						reg_addr = i2c_byte1;
+					i2c_tbl[a_ctrl->i2c_tbl_index].
+						reg_data = i2c_byte2;
+					i2c_tbl[a_ctrl->i2c_tbl_index].
+						delay = 0;
+					a_ctrl->i2c_tbl_index++;
+					i++;
+					i2c_byte1 = write_arr[i].reg_addr;
+					i2c_byte2 = (value & 0xFF00) >> 8;
+				}
+			} else {
+				i2c_byte1 = (value & 0xFF00) >> 8;
+				i2c_byte2 = value & 0xFF;
+			}
+		} else {
+			i2c_byte1 = write_arr[i].reg_addr;
+			i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >>
+				write_arr[i].hw_shift;
+		}
+		if (a_ctrl->i2c_tbl_index > a_ctrl->total_steps) {
+			pr_err("failed: i2c table index out of bound\n");
+			break;
+		}
+		CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2);
+		i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1;
+		i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2;
+		i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay;
+		a_ctrl->i2c_tbl_index++;
+	}
+	CDBG("Exit\n");
+}
+
+static int msm_actuator_bivcm_handle_i2c_ops(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int16_t next_lens_position, uint32_t hw_params, uint16_t delay)
+{
+	struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl;
+	uint32_t hw_dword = hw_params;
+	uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
+	uint16_t value = 0, reg_data = 0;
+	uint32_t size = a_ctrl->reg_tbl_size, i = 0;
+	int32_t rc = 0;
+	struct msm_camera_i2c_reg_array i2c_tbl;
+	struct msm_camera_i2c_reg_setting reg_setting;
+	enum msm_camera_i2c_reg_addr_type save_addr_type =
+		a_ctrl->i2c_client.addr_type;
+
+	for (i = 0; i < size; i++) {
+		reg_setting.size = 1;
+		switch (write_arr[i].reg_write_type) {
+		case MSM_ACTUATOR_WRITE_DAC:
+			value = (next_lens_position <<
+			write_arr[i].data_shift) |
+			((hw_dword & write_arr[i].hw_mask) >>
+			write_arr[i].hw_shift);
+			if (write_arr[i].reg_addr != 0xFFFF) {
+				i2c_byte1 = write_arr[i].reg_addr;
+				i2c_byte2 = value;
+			} else {
+				i2c_byte1 = (value & 0xFF00) >> 8;
+				i2c_byte2 = value & 0xFF;
+			}
+			i2c_tbl.reg_addr = i2c_byte1;
+			i2c_tbl.reg_data = i2c_byte2;
+			i2c_tbl.delay = delay;
+			a_ctrl->i2c_tbl_index++;
+
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = a_ctrl->i2c_data_type;
+			rc = a_ctrl->i2c_client.
+				i2c_func_tbl->i2c_write_table_w_microdelay(
+				&a_ctrl->i2c_client, &reg_setting);
+			if (rc < 0) {
+				pr_err("i2c write error:%d\n", rc);
+				return rc;
+			}
+			break;
+		case MSM_ACTUATOR_WRITE:
+			i2c_tbl.reg_data = write_arr[i].reg_data;
+			i2c_tbl.reg_addr = write_arr[i].reg_addr;
+			i2c_tbl.delay = write_arr[i].delay;
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = write_arr[i].data_type;
+			switch (write_arr[i].addr_type) {
+			case MSM_ACTUATOR_BYTE_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_BYTE_ADDR;
+				break;
+			case MSM_ACTUATOR_WORD_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_WORD_ADDR;
+				break;
+			default:
+				pr_err("Unsupport addr type: %d\n",
+					write_arr[i].addr_type);
+				break;
+			}
+
+			rc = a_ctrl->i2c_client.
+				i2c_func_tbl->i2c_write_table_w_microdelay(
+				&a_ctrl->i2c_client, &reg_setting);
+			if (rc < 0) {
+				pr_err("i2c write error:%d\n", rc);
+				return rc;
+			}
+			break;
+		case MSM_ACTUATOR_WRITE_DIR_REG:
+			i2c_tbl.reg_data = hw_dword & 0xFFFF;
+			i2c_tbl.reg_addr = write_arr[i].reg_addr;
+			i2c_tbl.delay = write_arr[i].delay;
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = write_arr[i].data_type;
+			switch (write_arr[i].addr_type) {
+			case MSM_ACTUATOR_BYTE_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_BYTE_ADDR;
+				break;
+			case MSM_ACTUATOR_WORD_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_WORD_ADDR;
+				break;
+			default:
+				pr_err("Unsupport addr type: %d\n",
+					write_arr[i].addr_type);
+				break;
+			}
+
+			rc = a_ctrl->i2c_client.
+				i2c_func_tbl->i2c_write_table_w_microdelay(
+				&a_ctrl->i2c_client, &reg_setting);
+			if (rc < 0) {
+				pr_err("i2c write error:%d\n", rc);
+				return rc;
+			}
+			break;
+		case MSM_ACTUATOR_POLL:
+			switch (write_arr[i].addr_type) {
+			case MSM_ACTUATOR_BYTE_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_BYTE_ADDR;
+				break;
+			case MSM_ACTUATOR_WORD_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_WORD_ADDR;
+				break;
+			default:
+				pr_err("Unsupport addr type: %d\n",
+					write_arr[i].addr_type);
+				break;
+			}
+
+			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+				&a_ctrl->i2c_client,
+				write_arr[i].reg_addr,
+				write_arr[i].reg_data,
+				write_arr[i].data_type,
+				write_arr[i].delay);
+			if (rc < 0) {
+				pr_err("i2c poll error:%d\n", rc);
+				return rc;
+			}
+			break;
+		case MSM_ACTUATOR_READ_WRITE:
+			i2c_tbl.reg_addr = write_arr[i].reg_addr;
+			i2c_tbl.delay = write_arr[i].delay;
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = write_arr[i].data_type;
+
+			switch (write_arr[i].addr_type) {
+			case MSM_ACTUATOR_BYTE_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_BYTE_ADDR;
+				break;
+			case MSM_ACTUATOR_WORD_ADDR:
+				a_ctrl->i2c_client.addr_type =
+					MSM_CAMERA_I2C_WORD_ADDR;
+				break;
+			default:
+				pr_err("Unsupport addr type: %d\n",
+					write_arr[i].addr_type);
+				break;
+			}
+			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_read(
+				&a_ctrl->i2c_client,
+				write_arr[i].reg_addr,
+				&reg_data,
+				write_arr[i].data_type);
+			if (rc < 0) {
+				pr_err("i2c poll error:%d\n", rc);
+				return rc;
+			}
+
+			i2c_tbl.reg_addr = write_arr[i].reg_data;
+			i2c_tbl.reg_data = reg_data;
+			i2c_tbl.delay = write_arr[i].delay;
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = write_arr[i].data_type;
+
+			rc = a_ctrl->i2c_client.
+				i2c_func_tbl->i2c_write_table_w_microdelay(
+				&a_ctrl->i2c_client, &reg_setting);
+			if (rc < 0) {
+				pr_err("i2c write error:%d\n", rc);
+				return rc;
+			}
+			break;
+		case MSM_ACTUATOR_WRITE_HW_DAMP:
+			i2c_tbl.reg_addr = write_arr[i].reg_addr;
+			i2c_tbl.reg_data = (hw_dword & write_arr[i].hw_mask) >>
+				write_arr[i].hw_shift;
+			i2c_tbl.delay = 0;
+			reg_setting.reg_setting = &i2c_tbl;
+			reg_setting.data_type = a_ctrl->i2c_data_type;
+
+			rc = a_ctrl->i2c_client.
+				i2c_func_tbl->i2c_write_table_w_microdelay(
+				&a_ctrl->i2c_client, &reg_setting);
+			if (rc < 0) {
+				pr_err("i2c write error:%d\n", rc);
+				return rc;
+			}
+			break;
+		default:
+			pr_err("%s:%d Invalid selection\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		a_ctrl->i2c_client.addr_type = save_addr_type;
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
+	uint16_t size, struct reg_settings_t *settings)
+{
+	int32_t rc = -EFAULT;
+	int32_t i = 0;
+	enum msm_camera_i2c_reg_addr_type save_addr_type;
+
+	CDBG("Enter\n");
+
+	save_addr_type = a_ctrl->i2c_client.addr_type;
+	for (i = 0; i < size; i++) {
+
+		switch (settings[i].addr_type) {
+		case MSM_CAMERA_I2C_BYTE_ADDR:
+			a_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			break;
+		case MSM_CAMERA_I2C_WORD_ADDR:
+			a_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR;
+			break;
+		default:
+			pr_err("Unsupport addr type: %d\n",
+				settings[i].addr_type);
+			break;
+		}
+
+		switch (settings[i].i2c_operation) {
+		case MSM_ACT_WRITE:
+			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&a_ctrl->i2c_client,
+				settings[i].reg_addr,
+				settings[i].reg_data,
+				settings[i].data_type);
+			if (settings[i].delay > 20)
+				msleep(settings[i].delay);
+			else if (settings[i].delay != 0)
+				usleep_range(settings[i].delay * 1000,
+					(settings[i].delay * 1000) + 1000);
+			break;
+		case MSM_ACT_POLL:
+			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+				&a_ctrl->i2c_client,
+				settings[i].reg_addr,
+				settings[i].reg_data,
+				settings[i].data_type,
+				settings[i].delay);
+			break;
+		default:
+			pr_err("Unsupport i2c_operation: %d\n",
+				settings[i].i2c_operation);
+			break;
+		}
+
+		if (rc < 0) {
+			pr_err("%s:%d fail addr = 0X%X, data = 0X%X, dt = %d",
+				__func__, __LINE__, settings[i].reg_addr,
+				settings[i].reg_data, settings[i].data_type);
+			break;
+		}
+	}
+
+	a_ctrl->curr_step_pos = 0;
+	/*
+	 * Recover register addr_type after the init
+	 * settings are written.
+	 */
+	a_ctrl->i2c_client.addr_type = save_addr_type;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static void msm_actuator_write_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	uint16_t curr_lens_pos,
+	struct damping_params_t *damping_params,
+	int8_t sign_direction,
+	int16_t code_boundary)
+{
+	int16_t next_lens_pos = 0;
+	uint16_t damping_code_step = 0;
+	uint16_t wait_time = 0;
+
+	CDBG("Enter\n");
+
+	damping_code_step = damping_params->damping_step;
+	wait_time = damping_params->damping_delay;
+
+	/* Write code based on damping_code_step in a loop */
+	for (next_lens_pos =
+		curr_lens_pos + (sign_direction * damping_code_step);
+		(sign_direction * next_lens_pos) <=
+			(sign_direction * code_boundary);
+		next_lens_pos =
+			(next_lens_pos +
+				(sign_direction * damping_code_step))) {
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			next_lens_pos, damping_params->hw_params, wait_time);
+		curr_lens_pos = next_lens_pos;
+	}
+
+	if (curr_lens_pos != code_boundary) {
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			code_boundary, damping_params->hw_params, wait_time);
+	}
+	CDBG("Exit\n");
+}
+
+static int msm_actuator_bivcm_write_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	uint16_t curr_lens_pos,
+	struct damping_params_t *damping_params,
+	int8_t sign_direction,
+	int16_t code_boundary)
+{
+	int16_t next_lens_pos = 0;
+	uint16_t damping_code_step = 0;
+	uint16_t wait_time = 0;
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+
+	damping_code_step = damping_params->damping_step;
+	wait_time = damping_params->damping_delay;
+
+	/* Write code based on damping_code_step in a loop */
+	for (next_lens_pos =
+		curr_lens_pos + (sign_direction * damping_code_step);
+		(sign_direction * next_lens_pos) <=
+			(sign_direction * code_boundary);
+		next_lens_pos =
+			(next_lens_pos +
+				(sign_direction * damping_code_step))) {
+		rc = msm_actuator_bivcm_handle_i2c_ops(a_ctrl,
+			next_lens_pos, damping_params->hw_params, wait_time);
+		if (rc < 0) {
+			pr_err("%s:%d msm_actuator_bivcm_handle_i2c_ops failed\n",
+				__func__, __LINE__);
+				return rc;
+		}
+		curr_lens_pos = next_lens_pos;
+	}
+
+	if (curr_lens_pos != code_boundary) {
+		rc = msm_actuator_bivcm_handle_i2c_ops(a_ctrl,
+			code_boundary, damping_params->hw_params, wait_time);
+		if (rc < 0) {
+			pr_err("%s:%d msm_actuator_bivcm_handle_i2c_ops failed\n",
+				__func__, __LINE__);
+			return rc;
+		}
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_piezo_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_move_params_t *move_params)
+{
+	int32_t dest_step_position = move_params->dest_step_pos;
+	struct damping_params_t ringing_params_kernel;
+	int32_t rc = 0;
+	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
+
+	CDBG("Enter\n");
+
+	if (a_ctrl->i2c_reg_tbl == NULL) {
+		pr_err("failed. i2c reg table is NULL");
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&ringing_params_kernel,
+		&(move_params->ringing_params[0]),
+		sizeof(struct damping_params_t))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+	if (num_steps <= 0 || num_steps > MAX_NUMBER_OF_STEPS) {
+		pr_err("num_steps out of range = %d\n",
+			num_steps);
+		return -EFAULT;
+	}
+
+	if (dest_step_position > a_ctrl->total_steps) {
+		pr_err("Step pos greater than total steps = %d\n",
+			dest_step_position);
+		return -EFAULT;
+	}
+
+	a_ctrl->i2c_tbl_index = 0;
+	a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+		(num_steps *
+		a_ctrl->region_params[0].code_per_step),
+		ringing_params_kernel.hw_params, 0);
+
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
+	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
+		&a_ctrl->i2c_client, &reg_setting);
+	if (rc < 0) {
+		pr_err("i2c write error:%d\n", rc);
+		return rc;
+	}
+	a_ctrl->i2c_tbl_index = 0;
+	a_ctrl->curr_step_pos = dest_step_position;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_move_params_t *move_params)
+{
+	int32_t rc = 0;
+	struct damping_params_t *ringing_params_kernel = NULL;
+	int8_t sign_dir = move_params->sign_dir;
+	uint16_t step_boundary = 0;
+	uint16_t target_step_pos = 0;
+	uint16_t target_lens_pos = 0;
+	int16_t dest_step_pos = move_params->dest_step_pos;
+	uint16_t curr_lens_pos = 0;
+	int dir = move_params->dir;
+	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
+
+	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
+
+	if ((dest_step_pos == a_ctrl->curr_step_pos) ||
+		((dest_step_pos <= a_ctrl->total_steps) &&
+		(a_ctrl->step_position_table[dest_step_pos] ==
+		a_ctrl->step_position_table[a_ctrl->curr_step_pos])))
+		return rc;
+
+	if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) ||
+		(sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) {
+		pr_err("Invalid sign_dir = %d\n", sign_dir);
+		return -EFAULT;
+	}
+	if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) {
+		pr_err("Invalid direction = %d\n", dir);
+		return -EFAULT;
+	}
+	if (a_ctrl->i2c_reg_tbl == NULL) {
+		pr_err("failed. i2c reg table is NULL");
+		return -EFAULT;
+	}
+	if (dest_step_pos > a_ctrl->total_steps) {
+		pr_err("Step pos greater than total steps = %d\n",
+		dest_step_pos);
+		return -EFAULT;
+	}
+	if ((a_ctrl->region_size <= 0) ||
+		(a_ctrl->region_size > MAX_ACTUATOR_REGION) ||
+		(!move_params->ringing_params)) {
+		pr_err("Invalid-region size = %d, ringing_params = %pK\n",
+		a_ctrl->region_size, move_params->ringing_params);
+		return -EFAULT;
+	}
+	/*Allocate memory for damping parameters of all regions*/
+	ringing_params_kernel = kmalloc(
+		sizeof(struct damping_params_t)*(a_ctrl->region_size),
+		GFP_KERNEL);
+	if (!ringing_params_kernel) {
+		pr_err("kmalloc for damping parameters failed\n");
+		return -EFAULT;
+	}
+	if (copy_from_user(ringing_params_kernel,
+		&(move_params->ringing_params[0]),
+		(sizeof(struct damping_params_t))*(a_ctrl->region_size))) {
+		pr_err("copy_from_user failed\n");
+		/*Free the allocated memory for damping parameters*/
+		kfree(ringing_params_kernel);
+		return -EFAULT;
+	}
+	curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+	a_ctrl->i2c_tbl_index = 0;
+	CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
+		a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
+
+	while (a_ctrl->curr_step_pos != dest_step_pos) {
+		step_boundary =
+			a_ctrl->region_params[a_ctrl->curr_region_index].
+			step_bound[dir];
+		if ((dest_step_pos * sign_dir) <=
+			(step_boundary * sign_dir)) {
+
+			target_step_pos = dest_step_pos;
+			target_lens_pos =
+				a_ctrl->step_position_table[target_step_pos];
+			a_ctrl->func_tbl->actuator_write_focus(a_ctrl,
+					curr_lens_pos,
+					&ringing_params_kernel
+					[a_ctrl->curr_region_index],
+					sign_dir,
+					target_lens_pos);
+			curr_lens_pos = target_lens_pos;
+
+		} else {
+			target_step_pos = step_boundary;
+			target_lens_pos =
+				a_ctrl->step_position_table[target_step_pos];
+			a_ctrl->func_tbl->actuator_write_focus(a_ctrl,
+					curr_lens_pos,
+					&ringing_params_kernel
+					[a_ctrl->curr_region_index],
+					sign_dir,
+					target_lens_pos);
+			curr_lens_pos = target_lens_pos;
+
+			a_ctrl->curr_region_index += sign_dir;
+		}
+		a_ctrl->curr_step_pos = target_step_pos;
+	}
+	/*Free the memory allocated for damping parameters*/
+	kfree(ringing_params_kernel);
+
+	move_params->curr_lens_pos = curr_lens_pos;
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
+	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
+		&a_ctrl->i2c_client, &reg_setting);
+	if (rc < 0) {
+		pr_err("i2c write error:%d\n", rc);
+		return rc;
+	}
+	a_ctrl->i2c_tbl_index = 0;
+	CDBG("Exit\n");
+
+	return rc;
+}
+
+static int32_t msm_actuator_bivcm_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_move_params_t *move_params)
+{
+	int32_t rc = 0;
+	struct damping_params_t *ringing_params_kernel = NULL;
+	int8_t sign_dir = move_params->sign_dir;
+	uint16_t step_boundary = 0;
+	uint16_t target_step_pos = 0;
+	uint16_t target_lens_pos = 0;
+	int16_t dest_step_pos = move_params->dest_step_pos;
+	uint16_t curr_lens_pos = 0;
+	int dir = move_params->dir;
+	int32_t num_steps = move_params->num_steps;
+
+	if (a_ctrl->step_position_table == NULL) {
+		pr_err("Step Position Table is NULL");
+		return -EFAULT;
+	}
+
+	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
+
+	if (dest_step_pos == a_ctrl->curr_step_pos)
+		return rc;
+
+	if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) ||
+		(sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) {
+		pr_err("Invalid sign_dir = %d\n", sign_dir);
+		return -EFAULT;
+	}
+	if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) {
+		pr_err("Invalid direction = %d\n", dir);
+		return -EFAULT;
+	}
+	if (a_ctrl->i2c_reg_tbl == NULL) {
+		pr_err("failed. i2c reg table is NULL");
+		return -EFAULT;
+	}
+	if (dest_step_pos > a_ctrl->total_steps) {
+		pr_err("Step pos greater than total steps = %d\n",
+		dest_step_pos);
+		return -EFAULT;
+	}
+	if ((a_ctrl->region_size <= 0) ||
+		(a_ctrl->region_size > MAX_ACTUATOR_REGION) ||
+		(!move_params->ringing_params)) {
+		pr_err("Invalid-region size = %d, ringing_params = %pK\n",
+		a_ctrl->region_size, move_params->ringing_params);
+		return -EFAULT;
+	}
+	/*Allocate memory for damping parameters of all regions*/
+	ringing_params_kernel = kmalloc(
+		sizeof(struct damping_params_t)*(a_ctrl->region_size),
+		GFP_KERNEL);
+	if (!ringing_params_kernel) {
+		pr_err("kmalloc for damping parameters failed\n");
+		return -EFAULT;
+	}
+	if (copy_from_user(ringing_params_kernel,
+		&(move_params->ringing_params[0]),
+		(sizeof(struct damping_params_t))*(a_ctrl->region_size))) {
+		pr_err("copy_from_user failed\n");
+		/*Free the allocated memory for damping parameters*/
+		kfree(ringing_params_kernel);
+		return -EFAULT;
+	}
+	curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+	a_ctrl->i2c_tbl_index = 0;
+	CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
+		a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
+
+	while (a_ctrl->curr_step_pos != dest_step_pos) {
+		step_boundary =
+			a_ctrl->region_params[a_ctrl->curr_region_index].
+			step_bound[dir];
+		if ((dest_step_pos * sign_dir) <=
+			(step_boundary * sign_dir)) {
+
+			target_step_pos = dest_step_pos;
+			target_lens_pos =
+				a_ctrl->step_position_table[target_step_pos];
+			rc = msm_actuator_bivcm_write_focus(a_ctrl,
+				curr_lens_pos,
+				&ringing_params_kernel
+				[a_ctrl->curr_region_index],
+				sign_dir,
+				target_lens_pos);
+			if (rc < 0) {
+				kfree(ringing_params_kernel);
+				return rc;
+			}
+			curr_lens_pos = target_lens_pos;
+		} else {
+			target_step_pos = step_boundary;
+			target_lens_pos =
+				a_ctrl->step_position_table[target_step_pos];
+			rc = msm_actuator_bivcm_write_focus(a_ctrl,
+				curr_lens_pos,
+				&ringing_params_kernel
+				[a_ctrl->curr_region_index],
+				sign_dir,
+				target_lens_pos);
+			if (rc < 0) {
+				kfree(ringing_params_kernel);
+				return rc;
+			}
+			curr_lens_pos = target_lens_pos;
+
+			a_ctrl->curr_region_index += sign_dir;
+		}
+		a_ctrl->curr_step_pos = target_step_pos;
+	}
+	/*Free the memory allocated for damping parameters*/
+	kfree(ringing_params_kernel);
+
+	move_params->curr_lens_pos = curr_lens_pos;
+	a_ctrl->i2c_tbl_index = 0;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_park_lens(struct msm_actuator_ctrl_t *a_ctrl)
+{
+	int32_t rc = 0;
+	uint16_t next_lens_pos = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
+
+	a_ctrl->i2c_tbl_index = 0;
+	if ((a_ctrl->curr_step_pos > a_ctrl->total_steps) ||
+		(!a_ctrl->park_lens.max_step) ||
+		(!a_ctrl->step_position_table) ||
+		(!a_ctrl->i2c_reg_tbl) ||
+		(!a_ctrl->func_tbl) ||
+		(!a_ctrl->func_tbl->actuator_parse_i2c_params)) {
+		pr_err("%s:%d Failed to park lens.\n",
+			__func__, __LINE__);
+		return 0;
+	}
+
+	if (a_ctrl->park_lens.max_step > a_ctrl->max_code_size)
+		a_ctrl->park_lens.max_step = a_ctrl->max_code_size;
+
+	next_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+	while (next_lens_pos) {
+		/* conditions which help to reduce park lens time */
+		if (next_lens_pos > (a_ctrl->park_lens.max_step *
+			PARK_LENS_LONG_STEP)) {
+			next_lens_pos = next_lens_pos -
+				(a_ctrl->park_lens.max_step *
+				PARK_LENS_LONG_STEP);
+		} else if (next_lens_pos > (a_ctrl->park_lens.max_step *
+			PARK_LENS_MID_STEP)) {
+			next_lens_pos = next_lens_pos -
+				(a_ctrl->park_lens.max_step *
+				PARK_LENS_MID_STEP);
+		} else if (next_lens_pos > (a_ctrl->park_lens.max_step *
+			PARK_LENS_SMALL_STEP)) {
+			next_lens_pos = next_lens_pos -
+				(a_ctrl->park_lens.max_step *
+				PARK_LENS_SMALL_STEP);
+		} else {
+			next_lens_pos = (next_lens_pos >
+				a_ctrl->park_lens.max_step) ?
+				(next_lens_pos - a_ctrl->park_lens.
+				max_step) : 0;
+		}
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			next_lens_pos, a_ctrl->park_lens.hw_params,
+			a_ctrl->park_lens.damping_delay);
+
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+
+		rc = a_ctrl->i2c_client.i2c_func_tbl->
+			i2c_write_table_w_microdelay(
+			&a_ctrl->i2c_client, &reg_setting);
+		if (rc < 0) {
+			pr_err("%s Failed I2C write Line %d\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		a_ctrl->i2c_tbl_index = 0;
+		/* Use typical damping time delay to avoid tick sound */
+		usleep_range(10000, 12000);
+	}
+
+	return 0;
+}
+
+static int32_t msm_actuator_bivcm_init_step_table(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_info_t *set_info)
+{
+	int16_t code_per_step = 0;
+	int16_t cur_code = 0;
+	uint16_t step_index = 0, region_index = 0;
+	uint16_t step_boundary = 0;
+	uint32_t max_code_size = 1;
+	uint16_t data_size = set_info->actuator_params.data_size;
+	uint16_t mask = 0, i = 0;
+	uint32_t qvalue = 0;
+
+	CDBG("Enter\n");
+
+	for (; data_size > 0; data_size--) {
+		max_code_size *= 2;
+		mask |= (1 << i++);
+	}
+
+	a_ctrl->max_code_size = max_code_size;
+	kfree(a_ctrl->step_position_table);
+	a_ctrl->step_position_table = NULL;
+
+	if (set_info->af_tuning_params.total_steps
+		>  MAX_ACTUATOR_AF_TOTAL_STEPS) {
+		pr_err("Max actuator totalsteps exceeded = %d\n",
+		set_info->af_tuning_params.total_steps);
+		return -EFAULT;
+	}
+	/* Fill step position table */
+	a_ctrl->step_position_table =
+		kmalloc(sizeof(uint16_t) *
+		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
+
+	if (a_ctrl->step_position_table == NULL)
+		return -ENOMEM;
+
+	cur_code = set_info->af_tuning_params.initial_code;
+	a_ctrl->step_position_table[step_index++] = cur_code;
+	for (region_index = 0;
+		region_index < a_ctrl->region_size;
+		region_index++) {
+		code_per_step =
+			a_ctrl->region_params[region_index].code_per_step;
+		step_boundary =
+			a_ctrl->region_params[region_index].
+			step_bound[MOVE_NEAR];
+		if (step_boundary >
+			set_info->af_tuning_params.total_steps) {
+			pr_err("invalid step_boundary = %d, max_val = %d",
+				step_boundary,
+				set_info->af_tuning_params.total_steps);
+			kfree(a_ctrl->step_position_table);
+			a_ctrl->step_position_table = NULL;
+			return -EINVAL;
+		}
+		qvalue = a_ctrl->region_params[region_index].qvalue;
+		for (; step_index <= step_boundary;
+			step_index++) {
+			if (qvalue > 1 && qvalue <= MAX_QVALUE)
+				cur_code = step_index * code_per_step / qvalue;
+			else
+				cur_code = step_index * code_per_step;
+			cur_code = (set_info->af_tuning_params.initial_code +
+				cur_code) & mask;
+			if (cur_code < max_code_size)
+				a_ctrl->step_position_table[step_index] =
+					cur_code;
+			else {
+				for (; step_index <
+					set_info->af_tuning_params.total_steps;
+					step_index++)
+					a_ctrl->
+						step_position_table[
+						step_index] =
+						max_code_size;
+			}
+			CDBG("step_position_table[%d] = %d\n", step_index,
+				a_ctrl->step_position_table[step_index]);
+		}
+	}
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_info_t *set_info)
+{
+	int16_t code_per_step = 0;
+	uint32_t qvalue = 0;
+	int16_t cur_code = 0;
+	uint16_t step_index = 0, region_index = 0;
+	uint16_t step_boundary = 0;
+	uint32_t max_code_size = 1;
+	uint16_t data_size = set_info->actuator_params.data_size;
+
+	CDBG("Enter\n");
+
+	/* validate the actuator state */
+	if (a_ctrl->actuator_state != ACT_OPS_ACTIVE) {
+		pr_err("%s:%d invalid actuator_state %d\n"
+			, __func__, __LINE__, a_ctrl->actuator_state);
+		return -EINVAL;
+	}
+	for (; data_size > 0; data_size--)
+		max_code_size *= 2;
+
+	a_ctrl->max_code_size = max_code_size;
+
+	/* free the step_position_table to allocate a new one */
+	kfree(a_ctrl->step_position_table);
+	a_ctrl->step_position_table = NULL;
+
+	if (set_info->af_tuning_params.total_steps
+		>  MAX_ACTUATOR_AF_TOTAL_STEPS) {
+		pr_err("Max actuator totalsteps exceeded = %d\n",
+		set_info->af_tuning_params.total_steps);
+		return -EFAULT;
+	}
+	/* Fill step position table */
+	a_ctrl->step_position_table =
+		kmalloc(sizeof(uint16_t) *
+		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
+
+	if (a_ctrl->step_position_table == NULL)
+		return -ENOMEM;
+
+	cur_code = set_info->af_tuning_params.initial_code;
+	a_ctrl->step_position_table[step_index++] = cur_code;
+	for (region_index = 0;
+		region_index < a_ctrl->region_size;
+		region_index++) {
+		code_per_step =
+			a_ctrl->region_params[region_index].code_per_step;
+		qvalue =
+			a_ctrl->region_params[region_index].qvalue;
+		step_boundary =
+			a_ctrl->region_params[region_index].
+			step_bound[MOVE_NEAR];
+		if (step_boundary >
+			set_info->af_tuning_params.total_steps) {
+			pr_err("invalid step_boundary = %d, max_val = %d",
+				step_boundary,
+				set_info->af_tuning_params.total_steps);
+			kfree(a_ctrl->step_position_table);
+			a_ctrl->step_position_table = NULL;
+			return -EINVAL;
+		}
+		for (; step_index <= step_boundary;
+			step_index++) {
+			if (qvalue > 1 && qvalue <= MAX_QVALUE)
+				cur_code = step_index * code_per_step / qvalue;
+			else
+				cur_code = step_index * code_per_step;
+			cur_code += set_info->af_tuning_params.initial_code;
+			if (cur_code < max_code_size)
+				a_ctrl->step_position_table[step_index] =
+					cur_code;
+			else {
+				for (; step_index <
+					set_info->af_tuning_params.total_steps;
+					step_index++)
+					a_ctrl->
+						step_position_table[
+						step_index] =
+						max_code_size;
+			}
+			CDBG("step_position_table[%d] = %d\n", step_index,
+				a_ctrl->step_position_table[step_index]);
+		}
+	}
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_actuator_set_default_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_move_params_t *move_params)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+
+	if (a_ctrl->curr_step_pos != 0)
+		rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, move_params);
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl,
+							int config)
+{
+	int rc = 0, i, cnt;
+	struct msm_actuator_vreg *vreg_cfg;
+
+	vreg_cfg = &a_ctrl->vreg_cfg;
+	cnt = vreg_cfg->num_vreg;
+	if (!cnt)
+		return 0;
+
+	if (cnt >= MSM_ACTUATOR_MAX_VREGS) {
+		pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+			rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev),
+				&vreg_cfg->cam_vreg[i],
+				(struct regulator **)&vreg_cfg->data[i],
+				config);
+		} else if (a_ctrl->act_device_type ==
+			MSM_CAMERA_I2C_DEVICE) {
+			rc = msm_camera_config_single_vreg(
+				&(a_ctrl->i2c_client.client->dev),
+				&vreg_cfg->cam_vreg[i],
+				(struct regulator **)&vreg_cfg->data[i],
+				config);
+		}
+	}
+	return rc;
+}
+
+static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
+{
+	int32_t rc = 0;
+	enum msm_sensor_power_seq_gpio_t gpio;
+
+	CDBG("Enter\n");
+	if (a_ctrl->actuator_state != ACT_DISABLE_STATE) {
+
+		if (a_ctrl->func_tbl && a_ctrl->func_tbl->actuator_park_lens) {
+			rc = a_ctrl->func_tbl->actuator_park_lens(a_ctrl);
+			if (rc < 0)
+				pr_err("%s:%d Lens park failed.\n",
+					__func__, __LINE__);
+		}
+
+		rc = msm_actuator_vreg_control(a_ctrl, 0);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return rc;
+		}
+
+		for (gpio = SENSOR_GPIO_AF_PWDM;
+			gpio < SENSOR_GPIO_MAX; gpio++) {
+			if (a_ctrl->gconf &&
+				a_ctrl->gconf->gpio_num_info &&
+				a_ctrl->gconf->gpio_num_info->
+					valid[gpio] == 1) {
+
+				gpio_set_value_cansleep(
+					a_ctrl->gconf->gpio_num_info->
+						gpio_num[gpio],
+					GPIOF_OUT_INIT_LOW);
+
+				if (a_ctrl->cam_pinctrl_status) {
+					rc = pinctrl_select_state(
+						a_ctrl->pinctrl_info.pinctrl,
+						a_ctrl->pinctrl_info.
+							gpio_state_suspend);
+					if (rc < 0)
+						pr_err("ERR:%s:%d cannot set pin to suspend state: %d",
+							__func__, __LINE__, rc);
+
+					devm_pinctrl_put(
+						a_ctrl->pinctrl_info.pinctrl);
+				}
+				a_ctrl->cam_pinctrl_status = 0;
+				rc = msm_camera_request_gpio_table(
+					a_ctrl->gconf->cam_gpio_req_tbl,
+					a_ctrl->gconf->cam_gpio_req_tbl_size,
+					0);
+				if (rc < 0)
+					pr_err("ERR:%s:Failed in selecting state in actuator power down: %d\n",
+						__func__, rc);
+			}
+		}
+
+		kfree(a_ctrl->step_position_table);
+		a_ctrl->step_position_table = NULL;
+		kfree(a_ctrl->i2c_reg_tbl);
+		a_ctrl->i2c_reg_tbl = NULL;
+		a_ctrl->i2c_tbl_index = 0;
+		a_ctrl->actuator_state = ACT_OPS_INACTIVE;
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_set_position(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_position_t *set_pos)
+{
+	int32_t rc = 0;
+	int32_t index;
+	uint16_t next_lens_position;
+	uint16_t delay;
+	uint32_t hw_params = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
+
+	CDBG("%s Enter %d\n", __func__, __LINE__);
+	if (set_pos->number_of_steps <= 0 ||
+		set_pos->number_of_steps > MAX_NUMBER_OF_STEPS) {
+		pr_err("num_steps out of range = %d\n",
+			set_pos->number_of_steps);
+		return -EFAULT;
+	}
+
+	if (!a_ctrl || !a_ctrl->func_tbl ||
+		!a_ctrl->func_tbl->actuator_parse_i2c_params ||
+		!a_ctrl->i2c_reg_tbl) {
+		pr_err("failed. NULL actuator pointers.");
+		return -EFAULT;
+	}
+
+	if (a_ctrl->actuator_state != ACT_OPS_ACTIVE) {
+		pr_err("failed. Invalid actuator state.");
+		return -EFAULT;
+	}
+
+	a_ctrl->i2c_tbl_index = 0;
+	hw_params = set_pos->hw_params;
+	for (index = 0; index < set_pos->number_of_steps; index++) {
+		next_lens_position = set_pos->pos[index];
+		delay = set_pos->delay[index];
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+			next_lens_position, hw_params, delay);
+
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+
+		rc = a_ctrl->i2c_client.i2c_func_tbl->
+			i2c_write_table_w_microdelay(
+			&a_ctrl->i2c_client, &reg_setting);
+		if (rc < 0) {
+			pr_err("%s Failed I2C write Line %d\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		a_ctrl->i2c_tbl_index = 0;
+	}
+	CDBG("%s exit %d\n", __func__, __LINE__);
+	return rc;
+}
+
+static int32_t msm_actuator_bivcm_set_position(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_position_t *set_pos)
+{
+	int32_t rc = 0;
+	int32_t index;
+	uint16_t next_lens_position;
+	uint16_t delay;
+	uint32_t hw_params = 0;
+
+	CDBG("%s Enter %d\n", __func__, __LINE__);
+	if (set_pos->number_of_steps <= 0 ||
+		set_pos->number_of_steps > MAX_NUMBER_OF_STEPS) {
+		pr_err("num_steps out of range = %d\n",
+			set_pos->number_of_steps);
+		return -EFAULT;
+	}
+
+	if (!a_ctrl) {
+		pr_err("failed. NULL actuator pointers.");
+		return -EFAULT;
+	}
+
+	if (a_ctrl->actuator_state != ACT_OPS_ACTIVE) {
+		pr_err("failed. Invalid actuator state.");
+		return -EFAULT;
+	}
+
+	a_ctrl->i2c_tbl_index = 0;
+	hw_params = set_pos->hw_params;
+	for (index = 0; index < set_pos->number_of_steps; index++) {
+		next_lens_position = set_pos->pos[index];
+		delay = set_pos->delay[index];
+		rc = msm_actuator_bivcm_handle_i2c_ops(a_ctrl,
+		next_lens_position, hw_params, delay);
+		a_ctrl->i2c_tbl_index = 0;
+	}
+	CDBG("%s exit %d\n", __func__, __LINE__);
+	return rc;
+}
+
+static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_info_t *set_info) {
+	struct reg_settings_t *init_settings = NULL;
+	int32_t rc = -EFAULT;
+	uint16_t i = 0;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter\n");
+
+	for (i = 0; i < ARRAY_SIZE(actuators); i++) {
+		if (set_info->actuator_params.act_type ==
+			actuators[i]->act_type) {
+			a_ctrl->func_tbl = &actuators[i]->func_tbl;
+			rc = 0;
+		}
+	}
+
+	if (rc < 0) {
+		pr_err("Actuator function table not found\n");
+		return rc;
+	}
+	if (set_info->af_tuning_params.total_steps
+		>  MAX_ACTUATOR_AF_TOTAL_STEPS) {
+		pr_err("Max actuator totalsteps exceeded = %d\n",
+		set_info->af_tuning_params.total_steps);
+		return -EFAULT;
+	}
+	if (set_info->af_tuning_params.region_size
+		> MAX_ACTUATOR_REGION) {
+		pr_err("MAX_ACTUATOR_REGION is exceeded.\n");
+		return -EFAULT;
+	}
+
+	a_ctrl->region_size = set_info->af_tuning_params.region_size;
+	a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
+
+	if (copy_from_user(&a_ctrl->region_params,
+		(void __user *)set_info->af_tuning_params.region_params,
+		a_ctrl->region_size * sizeof(struct region_params_t))) {
+		pr_err("Error copying region_params\n");
+		return -EFAULT;
+	}
+	if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = a_ctrl->i2c_client.cci_client;
+		cci_client->sid =
+			set_info->actuator_params.i2c_addr >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->cci_i2c_master = a_ctrl->cci_master;
+		cci_client->i2c_freq_mode =
+			set_info->actuator_params.i2c_freq_mode;
+	} else {
+		a_ctrl->i2c_client.client->addr =
+			set_info->actuator_params.i2c_addr;
+	}
+
+	a_ctrl->i2c_data_type = set_info->actuator_params.i2c_data_type;
+	a_ctrl->i2c_client.addr_type = set_info->actuator_params.i2c_addr_type;
+	if (set_info->actuator_params.reg_tbl_size <=
+		MAX_ACTUATOR_REG_TBL_SIZE) {
+		a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size;
+	} else {
+		a_ctrl->reg_tbl_size = 0;
+		pr_err("MAX_ACTUATOR_REG_TBL_SIZE is exceeded.\n");
+		return -EFAULT;
+	}
+
+	if ((a_ctrl->actuator_state == ACT_OPS_ACTIVE) &&
+		(a_ctrl->i2c_reg_tbl != NULL)) {
+		kfree(a_ctrl->i2c_reg_tbl);
+	}
+	a_ctrl->i2c_reg_tbl = NULL;
+	a_ctrl->i2c_reg_tbl =
+		kmalloc(sizeof(struct msm_camera_i2c_reg_array) *
+		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
+	if (!a_ctrl->i2c_reg_tbl) {
+		pr_err("kmalloc fail\n");
+		return -ENOMEM;
+	}
+
+	a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
+	if (copy_from_user(&a_ctrl->reg_tbl,
+		(void __user *)set_info->actuator_params.reg_tbl_params,
+		a_ctrl->reg_tbl_size *
+		sizeof(struct msm_actuator_reg_params_t))) {
+		kfree(a_ctrl->i2c_reg_tbl);
+		a_ctrl->i2c_reg_tbl = NULL;
+		return -EFAULT;
+	}
+
+	if (set_info->actuator_params.init_setting_size &&
+		set_info->actuator_params.init_setting_size
+		<= MAX_ACTUATOR_INIT_SET) {
+		if (a_ctrl->func_tbl->actuator_init_focus) {
+			init_settings = kmalloc(sizeof(struct reg_settings_t) *
+				(set_info->actuator_params.init_setting_size),
+				GFP_KERNEL);
+			if (init_settings == NULL) {
+				kfree(a_ctrl->i2c_reg_tbl);
+				a_ctrl->i2c_reg_tbl = NULL;
+				pr_err("Error allocating memory for init_settings\n");
+				return -EFAULT;
+			}
+			if (copy_from_user(init_settings,
+				(void __user *)
+				set_info->actuator_params.init_settings,
+				set_info->actuator_params.init_setting_size *
+				sizeof(struct reg_settings_t))) {
+				kfree(init_settings);
+				kfree(a_ctrl->i2c_reg_tbl);
+				a_ctrl->i2c_reg_tbl = NULL;
+				pr_err("Error copying init_settings\n");
+				return -EFAULT;
+			}
+			rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
+				set_info->actuator_params.init_setting_size,
+				init_settings);
+			kfree(init_settings);
+			if (rc < 0) {
+				kfree(a_ctrl->i2c_reg_tbl);
+				a_ctrl->i2c_reg_tbl = NULL;
+				pr_err("Error actuator_init_focus\n");
+				return -EFAULT;
+			}
+		}
+	}
+
+	/* Park lens data */
+	a_ctrl->park_lens = set_info->actuator_params.park_lens;
+	a_ctrl->initial_code = set_info->af_tuning_params.initial_code;
+	if (a_ctrl->func_tbl->actuator_init_step_table)
+		rc = a_ctrl->func_tbl->
+			actuator_init_step_table(a_ctrl, set_info);
+
+	a_ctrl->curr_step_pos = 0;
+	a_ctrl->curr_region_index = 0;
+	CDBG("Exit\n");
+
+	return rc;
+}
+
+static int msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl)
+{
+	int rc = 0;
+
+	CDBG("Enter\n");
+	if (!a_ctrl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&a_ctrl->i2c_client, MSM_CCI_INIT);
+		if (rc < 0)
+			pr_err("cci_init failed\n");
+	}
+	a_ctrl->actuator_state = ACT_OPS_ACTIVE;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
+	void *argp)
+{
+	struct msm_actuator_cfg_data *cdata =
+		(struct msm_actuator_cfg_data *)argp;
+	int32_t rc = -EINVAL;
+
+	mutex_lock(a_ctrl->actuator_mutex);
+	CDBG("Enter\n");
+	CDBG("%s type %d\n", __func__, cdata->cfgtype);
+
+	if (cdata->cfgtype != CFG_ACTUATOR_INIT &&
+		cdata->cfgtype != CFG_ACTUATOR_POWERUP &&
+		a_ctrl->actuator_state == ACT_DISABLE_STATE) {
+		pr_err("actuator disabled %d\n", rc);
+		mutex_unlock(a_ctrl->actuator_mutex);
+		return rc;
+	}
+
+	switch (cdata->cfgtype) {
+	case CFG_ACTUATOR_INIT:
+		rc = msm_actuator_init(a_ctrl);
+		if (rc < 0)
+			pr_err("msm_actuator_init failed %d\n", rc);
+		break;
+	case CFG_GET_ACTUATOR_INFO:
+		cdata->is_af_supported = 1;
+		cdata->cfg.cam_name = a_ctrl->cam_name;
+		rc = 0;
+		break;
+
+	case CFG_SET_ACTUATOR_INFO:
+		rc = msm_actuator_set_param(a_ctrl, &cdata->cfg.set_info);
+		if (rc < 0)
+			pr_err("init table failed %d\n", rc);
+		break;
+
+	case CFG_SET_DEFAULT_FOCUS:
+		if (a_ctrl->func_tbl &&
+			a_ctrl->func_tbl->actuator_set_default_focus)
+			rc = a_ctrl->func_tbl->actuator_set_default_focus(
+				a_ctrl, &cdata->cfg.move);
+		if (rc < 0)
+			pr_err("move focus failed %d\n", rc);
+		break;
+
+	case CFG_MOVE_FOCUS:
+		if (a_ctrl->func_tbl &&
+			a_ctrl->func_tbl->actuator_move_focus)
+			rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl,
+				&cdata->cfg.move);
+		if (rc < 0)
+			pr_err("move focus failed %d\n", rc);
+		break;
+	case CFG_ACTUATOR_POWERDOWN:
+		rc = msm_actuator_power_down(a_ctrl);
+		if (rc < 0)
+			pr_err("msm_actuator_power_down failed %d\n", rc);
+		break;
+
+	case CFG_SET_POSITION:
+		if (a_ctrl->func_tbl &&
+			a_ctrl->func_tbl->actuator_set_position)
+			rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl,
+				&cdata->cfg.setpos);
+		if (rc < 0)
+			pr_err("actuator_set_position failed %d\n", rc);
+		break;
+
+	case CFG_ACTUATOR_POWERUP:
+		rc = msm_actuator_power_up(a_ctrl);
+		if (rc < 0)
+			pr_err("Failed actuator power up%d\n", rc);
+		break;
+
+	default:
+		break;
+	}
+	mutex_unlock(a_ctrl->actuator_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_actuator_get_subdev_id(struct msm_actuator_ctrl_t *a_ctrl,
+	void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		*subdev_id = a_ctrl->pdev->id;
+	else
+		*subdev_id = a_ctrl->subdev_id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_qup_i2c_write_table_w_microdelay,
+	.i2c_poll = msm_camera_qup_i2c_poll,
+};
+
+static int msm_actuator_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh) {
+	int rc = 0;
+	struct msm_actuator_ctrl_t *a_ctrl =  v4l2_get_subdevdata(sd);
+
+	CDBG("Enter\n");
+	if (!a_ctrl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	mutex_lock(a_ctrl->actuator_mutex);
+	if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE &&
+		a_ctrl->actuator_state != ACT_DISABLE_STATE) {
+		rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&a_ctrl->i2c_client, MSM_CCI_RELEASE);
+		if (rc < 0)
+			pr_err("cci_init failed\n");
+	}
+	kfree(a_ctrl->i2c_reg_tbl);
+	a_ctrl->i2c_reg_tbl = NULL;
+	a_ctrl->actuator_state = ACT_DISABLE_STATE;
+	mutex_unlock(a_ctrl->actuator_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+static const struct v4l2_subdev_internal_ops msm_actuator_internal_ops = {
+	.close = msm_actuator_close,
+};
+
+static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc;
+	struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd);
+	void *argp = (void *)arg;
+
+	CDBG("Enter\n");
+	CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, a_ctrl, argp);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_actuator_get_subdev_id(a_ctrl, argp);
+	case VIDIOC_MSM_ACTUATOR_CFG:
+		return msm_actuator_config(a_ctrl, argp);
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_SHUTDOWN:
+		if (!a_ctrl->i2c_client.i2c_func_tbl) {
+			pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n");
+			return -EINVAL;
+		}
+		mutex_lock(a_ctrl->actuator_mutex);
+		rc = msm_actuator_power_down(a_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d Actuator Power down failed\n",
+					__func__, __LINE__);
+		}
+		mutex_unlock(a_ctrl->actuator_mutex);
+		return msm_actuator_close(sd, NULL);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_actuator_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct msm_actuator_cfg_data32 *u32 =
+		(struct msm_actuator_cfg_data32 *)arg;
+	struct msm_actuator_cfg_data actuator_data;
+	void *parg = arg;
+	long rc;
+
+	switch (cmd) {
+	case VIDIOC_MSM_ACTUATOR_CFG32:
+		cmd = VIDIOC_MSM_ACTUATOR_CFG;
+		switch (u32->cfgtype) {
+		case CFG_SET_ACTUATOR_INFO:
+			actuator_data.cfgtype = u32->cfgtype;
+			actuator_data.is_af_supported = u32->is_af_supported;
+			actuator_data.cfg.set_info.actuator_params.act_type =
+				u32->cfg.set_info.actuator_params.act_type;
+
+			actuator_data.cfg.set_info.actuator_params
+				.reg_tbl_size =
+				u32->cfg.set_info.actuator_params.reg_tbl_size;
+
+			actuator_data.cfg.set_info.actuator_params.data_size =
+				u32->cfg.set_info.actuator_params.data_size;
+
+			actuator_data.cfg.set_info.actuator_params
+				.init_setting_size =
+				u32->cfg.set_info.actuator_params
+				.init_setting_size;
+
+			actuator_data.cfg.set_info.actuator_params.i2c_addr =
+				u32->cfg.set_info.actuator_params.i2c_addr;
+
+			actuator_data.cfg.set_info.actuator_params.
+				i2c_freq_mode =
+				u32->cfg.set_info.actuator_params.i2c_freq_mode;
+
+			actuator_data.cfg.set_info.actuator_params
+				.i2c_addr_type =
+				u32->cfg.set_info.actuator_params.i2c_addr_type;
+
+			actuator_data.cfg.set_info.actuator_params
+				.i2c_data_type =
+				u32->cfg.set_info.actuator_params.i2c_data_type;
+
+			actuator_data.cfg.set_info.actuator_params
+				.reg_tbl_params =
+				compat_ptr(
+				u32->cfg.set_info.actuator_params
+				.reg_tbl_params);
+
+			actuator_data.cfg.set_info.actuator_params
+				.init_settings =
+				compat_ptr(
+				u32->cfg.set_info.actuator_params
+				.init_settings);
+
+			actuator_data.cfg.set_info.af_tuning_params
+				.initial_code =
+				u32->cfg.set_info.af_tuning_params.initial_code;
+
+			actuator_data.cfg.set_info.af_tuning_params.pwd_step =
+				u32->cfg.set_info.af_tuning_params.pwd_step;
+
+			actuator_data.cfg.set_info.af_tuning_params
+				.region_size =
+				u32->cfg.set_info.af_tuning_params.region_size;
+
+			actuator_data.cfg.set_info.af_tuning_params
+				.total_steps =
+				u32->cfg.set_info.af_tuning_params.total_steps;
+
+			actuator_data.cfg.set_info.af_tuning_params
+				.region_params = compat_ptr(
+				u32->cfg.set_info.af_tuning_params
+				.region_params);
+
+			actuator_data.cfg.set_info.actuator_params.park_lens =
+				u32->cfg.set_info.actuator_params.park_lens;
+
+			parg = &actuator_data;
+			break;
+		case CFG_SET_DEFAULT_FOCUS:
+		case CFG_MOVE_FOCUS:
+			actuator_data.cfgtype = u32->cfgtype;
+			actuator_data.is_af_supported = u32->is_af_supported;
+			actuator_data.cfg.move.dir = u32->cfg.move.dir;
+
+			actuator_data.cfg.move.sign_dir =
+				u32->cfg.move.sign_dir;
+
+			actuator_data.cfg.move.dest_step_pos =
+				u32->cfg.move.dest_step_pos;
+
+			actuator_data.cfg.move.num_steps =
+				u32->cfg.move.num_steps;
+
+			actuator_data.cfg.move.curr_lens_pos =
+				u32->cfg.move.curr_lens_pos;
+
+			actuator_data.cfg.move.ringing_params =
+				compat_ptr(u32->cfg.move.ringing_params);
+			parg = &actuator_data;
+			break;
+		case CFG_SET_POSITION:
+			actuator_data.cfgtype = u32->cfgtype;
+			actuator_data.is_af_supported = u32->is_af_supported;
+			memcpy(&actuator_data.cfg.setpos, &(u32->cfg.setpos),
+				sizeof(struct msm_actuator_set_position_t));
+			break;
+		default:
+			actuator_data.cfgtype = u32->cfgtype;
+			parg = &actuator_data;
+			break;
+		}
+		break;
+	case VIDIOC_MSM_ACTUATOR_CFG:
+		pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
+		return -EINVAL;
+	}
+
+	rc = msm_actuator_subdev_ioctl(sd, cmd, parg);
+
+	switch (cmd) {
+
+	case VIDIOC_MSM_ACTUATOR_CFG:
+
+		switch (u32->cfgtype) {
+
+		case CFG_SET_DEFAULT_FOCUS:
+		case CFG_MOVE_FOCUS:
+			u32->cfg.move.curr_lens_pos =
+				actuator_data.cfg.move.curr_lens_pos;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static long msm_actuator_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_actuator_subdev_do_ioctl);
+}
+#endif
+
+static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl)
+{
+	int rc = 0;
+	enum msm_sensor_power_seq_gpio_t gpio;
+
+	CDBG("%s called\n", __func__);
+
+	rc = msm_actuator_vreg_control(a_ctrl, 1);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return rc;
+	}
+
+	for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX; gpio++) {
+		if (a_ctrl->gconf &&
+			a_ctrl->gconf->gpio_num_info &&
+			a_ctrl->gconf->gpio_num_info->valid[gpio] == 1) {
+			rc = msm_camera_request_gpio_table(
+				a_ctrl->gconf->cam_gpio_req_tbl,
+				a_ctrl->gconf->cam_gpio_req_tbl_size, 1);
+			if (rc < 0) {
+				pr_err("ERR:%s:Failed in selecting state for actuator: %d\n",
+					__func__, rc);
+				return rc;
+			}
+			if (a_ctrl->cam_pinctrl_status) {
+				rc = pinctrl_select_state(
+					a_ctrl->pinctrl_info.pinctrl,
+					a_ctrl->pinctrl_info.gpio_state_active);
+				if (rc < 0)
+					pr_err("ERR:%s:%d cannot set pin to active state: %d",
+						__func__, __LINE__, rc);
+			}
+
+			gpio_set_value_cansleep(
+				a_ctrl->gconf->gpio_num_info->gpio_num[gpio],
+				1);
+		}
+	}
+
+	/* VREG needs some delay to power up */
+	usleep_range(2000, 3000);
+	a_ctrl->actuator_state = ACT_ENABLE_STATE;
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops = {
+	.ioctl = msm_actuator_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_actuator_subdev_ops = {
+	.core = &msm_actuator_subdev_core_ops,
+};
+
+static const struct i2c_device_id msm_actuator_i2c_id[] = {
+	{"qcom,actuator", (kernel_ulong_t)NULL},
+	{ }
+};
+
+static int32_t msm_actuator_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_actuator_ctrl_t *act_ctrl_t = NULL;
+	struct msm_actuator_vreg *vreg_cfg = NULL;
+
+	CDBG("Enter\n");
+
+	if (client == NULL) {
+		pr_err("msm_actuator_i2c_probe: client is null\n");
+		return -EINVAL;
+	}
+
+	act_ctrl_t = kzalloc(sizeof(struct msm_actuator_ctrl_t),
+		GFP_KERNEL);
+	if (!act_ctrl_t)
+		return -ENOMEM;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	CDBG("client = 0x%pK\n",  client);
+
+	rc = of_property_read_u32(client->dev.of_node, "cell-index",
+		&act_ctrl_t->subdev_id);
+	CDBG("cell-index %d, rc %d\n", act_ctrl_t->subdev_id, rc);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		goto probe_failure;
+	}
+
+	if (of_find_property(client->dev.of_node,
+		"qcom,cam-vreg-name", NULL)) {
+		vreg_cfg = &act_ctrl_t->vreg_cfg;
+		rc = msm_camera_get_dt_vreg_data(client->dev.of_node,
+			&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+		if (rc < 0) {
+			pr_err("failed rc %d\n", rc);
+			goto probe_failure;
+		}
+	}
+
+	act_ctrl_t->i2c_driver = &msm_actuator_i2c_driver;
+	act_ctrl_t->i2c_client.client = client;
+	act_ctrl_t->curr_step_pos = 0,
+	act_ctrl_t->curr_region_index = 0,
+	/* Set device type as I2C */
+	act_ctrl_t->act_device_type = MSM_CAMERA_I2C_DEVICE;
+	act_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl;
+	act_ctrl_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops;
+	act_ctrl_t->actuator_mutex = &msm_actuator_mutex;
+	act_ctrl_t->cam_name = act_ctrl_t->subdev_id;
+	CDBG("act_ctrl_t->cam_name: %d", act_ctrl_t->cam_name);
+	/* Assign name for sub device */
+	snprintf(act_ctrl_t->msm_sd.sd.name, sizeof(act_ctrl_t->msm_sd.sd.name),
+		"%s", act_ctrl_t->i2c_driver->driver.name);
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&act_ctrl_t->msm_sd.sd,
+		act_ctrl_t->i2c_client.client,
+		act_ctrl_t->act_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&act_ctrl_t->msm_sd.sd, act_ctrl_t);
+	act_ctrl_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops;
+	act_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL);
+	act_ctrl_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ACTUATOR;
+	act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+	msm_sd_register(&act_ctrl_t->msm_sd);
+	msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_actuator_v4l2_subdev_fops.compat_ioctl32 =
+		msm_actuator_subdev_fops_ioctl;
+#endif
+	act_ctrl_t->msm_sd.sd.devnode->fops =
+		&msm_actuator_v4l2_subdev_fops;
+	act_ctrl_t->actuator_state = ACT_DISABLE_STATE;
+	pr_info("msm_actuator_i2c_probe: succeeded\n");
+	CDBG("Exit\n");
+
+	return 0;
+
+probe_failure:
+	kfree(act_ctrl_t);
+	return rc;
+}
+
+static int32_t msm_actuator_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_camera_cci_client *cci_client = NULL;
+	struct msm_actuator_ctrl_t *msm_actuator_t = NULL;
+	struct msm_actuator_vreg *vreg_cfg;
+
+	CDBG("Enter\n");
+
+	if (!pdev->dev.of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	msm_actuator_t = kzalloc(sizeof(struct msm_actuator_ctrl_t),
+		GFP_KERNEL);
+	if (!msm_actuator_t)
+		return -ENOMEM;
+	rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+		&pdev->id);
+	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
+	if (rc < 0) {
+		kfree(msm_actuator_t);
+		pr_err("failed rc %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master",
+		&msm_actuator_t->cci_master);
+	CDBG("qcom,cci-master %d, rc %d\n", msm_actuator_t->cci_master, rc);
+	if (rc < 0 || msm_actuator_t->cci_master >= MASTER_MAX) {
+		kfree(msm_actuator_t);
+		pr_err("failed rc %d\n", rc);
+		return rc;
+	}
+
+	if (of_find_property((&pdev->dev)->of_node,
+			"qcom,cam-vreg-name", NULL)) {
+		vreg_cfg = &msm_actuator_t->vreg_cfg;
+		rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node,
+			&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+		if (rc < 0) {
+			kfree(msm_actuator_t);
+			pr_err("failed rc %d\n", rc);
+			return rc;
+		}
+	}
+	rc = msm_sensor_driver_get_gpio_data(&(msm_actuator_t->gconf),
+		(&pdev->dev)->of_node);
+	if (rc <= 0) {
+		pr_err("%s: No/Error Actuator GPIOs\n", __func__);
+	} else {
+		msm_actuator_t->cam_pinctrl_status = 1;
+		rc = msm_camera_pinctrl_init(
+			&(msm_actuator_t->pinctrl_info), &(pdev->dev));
+		if (rc < 0) {
+			pr_err("ERR:%s: Error in reading actuator pinctrl\n",
+				__func__);
+			msm_actuator_t->cam_pinctrl_status = 0;
+		}
+	}
+
+	msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops;
+	msm_actuator_t->actuator_mutex = &msm_actuator_mutex;
+	msm_actuator_t->cam_name = pdev->id;
+
+	/* Set platform device handle */
+	msm_actuator_t->pdev = pdev;
+	/* Set device type as platform device */
+	msm_actuator_t->act_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	msm_actuator_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+	msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!msm_actuator_t->i2c_client.cci_client) {
+		kfree(msm_actuator_t->vreg_cfg.cam_vreg);
+		kfree(msm_actuator_t);
+		pr_err("failed no memory\n");
+		return -ENOMEM;
+	}
+
+	cci_client = msm_actuator_t->i2c_client.cci_client;
+	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = msm_actuator_t->cci_master;
+	v4l2_subdev_init(&msm_actuator_t->msm_sd.sd,
+		msm_actuator_t->act_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t);
+	msm_actuator_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops;
+	msm_actuator_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(msm_actuator_t->msm_sd.sd.name,
+		ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator");
+	media_entity_pads_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL);
+	msm_actuator_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ACTUATOR;
+	msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+	msm_sd_register(&msm_actuator_t->msm_sd);
+	msm_actuator_t->actuator_state = ACT_DISABLE_STATE;
+	msm_cam_copy_v4l2_subdev_fops(&msm_actuator_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_actuator_v4l2_subdev_fops.compat_ioctl32 =
+		msm_actuator_subdev_fops_ioctl;
+#endif
+	msm_actuator_t->msm_sd.sd.devnode->fops =
+		&msm_actuator_v4l2_subdev_fops;
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static const struct of_device_id msm_actuator_i2c_dt_match[] = {
+	{.compatible = "qcom,actuator"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_actuator_i2c_dt_match);
+
+static struct i2c_driver msm_actuator_i2c_driver = {
+	.id_table = msm_actuator_i2c_id,
+	.probe  = msm_actuator_i2c_probe,
+	.remove = __exit_p(msm_actuator_i2c_remove),
+	.driver = {
+		.name = "qcom,actuator",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_actuator_i2c_dt_match,
+	},
+};
+
+static const struct of_device_id msm_actuator_dt_match[] = {
+	{.compatible = "qcom,actuator", .data = NULL},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_actuator_dt_match);
+
+static struct platform_driver msm_actuator_platform_driver = {
+	.probe = msm_actuator_platform_probe,
+	.driver = {
+		.name = "qcom,actuator",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_actuator_dt_match,
+	},
+};
+
+static int __init msm_actuator_init_module(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_actuator_platform_driver);
+	if (!rc)
+		return rc;
+
+	CDBG("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&msm_actuator_i2c_driver);
+}
+
+static struct msm_actuator msm_vcm_actuator_table = {
+	.act_type = ACTUATOR_VCM,
+	.func_tbl = {
+		.actuator_init_step_table = msm_actuator_init_step_table,
+		.actuator_move_focus = msm_actuator_move_focus,
+		.actuator_write_focus = msm_actuator_write_focus,
+		.actuator_set_default_focus = msm_actuator_set_default_focus,
+		.actuator_init_focus = msm_actuator_init_focus,
+		.actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+		.actuator_set_position = msm_actuator_set_position,
+		.actuator_park_lens = msm_actuator_park_lens,
+	},
+};
+
+static struct msm_actuator msm_piezo_actuator_table = {
+	.act_type = ACTUATOR_PIEZO,
+	.func_tbl = {
+		.actuator_init_step_table = NULL,
+		.actuator_move_focus = msm_actuator_piezo_move_focus,
+		.actuator_write_focus = NULL,
+		.actuator_set_default_focus =
+			msm_actuator_piezo_set_default_focus,
+		.actuator_init_focus = msm_actuator_init_focus,
+		.actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+		.actuator_park_lens = NULL,
+	},
+};
+
+static struct msm_actuator msm_hvcm_actuator_table = {
+	.act_type = ACTUATOR_HVCM,
+	.func_tbl = {
+		.actuator_init_step_table = msm_actuator_init_step_table,
+		.actuator_move_focus = msm_actuator_move_focus,
+		.actuator_write_focus = msm_actuator_write_focus,
+		.actuator_set_default_focus = msm_actuator_set_default_focus,
+		.actuator_init_focus = msm_actuator_init_focus,
+		.actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+		.actuator_set_position = msm_actuator_set_position,
+		.actuator_park_lens = msm_actuator_park_lens,
+	},
+};
+
+static struct msm_actuator msm_bivcm_actuator_table = {
+	.act_type = ACTUATOR_BIVCM,
+	.func_tbl = {
+		.actuator_init_step_table = msm_actuator_bivcm_init_step_table,
+		.actuator_move_focus = msm_actuator_bivcm_move_focus,
+		.actuator_write_focus = NULL,
+		.actuator_set_default_focus = msm_actuator_set_default_focus,
+		.actuator_init_focus = msm_actuator_init_focus,
+		.actuator_parse_i2c_params = NULL,
+		.actuator_set_position = msm_actuator_bivcm_set_position,
+		.actuator_park_lens = NULL,
+	},
+};
+
+module_init(msm_actuator_init_module);
+MODULE_DESCRIPTION("MSM ACTUATOR");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
new file mode 100644
index 0000000..7af1d42
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2011-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_ACTUATOR_H
+#define MSM_ACTUATOR_H
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <soc/qcom/camera2.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+#define	MSM_ACTUATOR_MAX_VREGS (10)
+#define	ACTUATOR_MAX_POLL_COUNT 10
+
+struct msm_actuator_ctrl_t;
+
+enum msm_actuator_state_t {
+	ACT_ENABLE_STATE,
+	ACT_OPS_ACTIVE,
+	ACT_OPS_INACTIVE,
+	ACT_DISABLE_STATE,
+};
+
+struct msm_actuator_func_tbl {
+	int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *,
+			uint8_t,
+			uint8_t);
+	int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *,
+		struct msm_actuator_set_info_t *);
+	int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *,
+		uint16_t, struct reg_settings_t *);
+	int32_t (*actuator_set_default_focus)(struct msm_actuator_ctrl_t *,
+			struct msm_actuator_move_params_t *);
+	int32_t (*actuator_move_focus)(struct msm_actuator_ctrl_t *,
+			struct msm_actuator_move_params_t *);
+	void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *,
+			int16_t, uint32_t, uint16_t);
+	void (*actuator_write_focus)(struct msm_actuator_ctrl_t *,
+			uint16_t,
+			struct damping_params_t *,
+			int8_t,
+			int16_t);
+	int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *,
+		struct msm_actuator_set_position_t *);
+	int32_t (*actuator_park_lens)(struct msm_actuator_ctrl_t *);
+};
+
+struct msm_actuator {
+	enum actuator_type act_type;
+	struct msm_actuator_func_tbl func_tbl;
+};
+
+struct msm_actuator_vreg {
+	struct camera_vreg_t *cam_vreg;
+	void *data[MSM_ACTUATOR_MAX_VREGS];
+	int num_vreg;
+};
+
+struct msm_actuator_ctrl_t {
+	struct i2c_driver *i2c_driver;
+	struct platform_driver *pdriver;
+	struct platform_device *pdev;
+	struct msm_camera_i2c_client i2c_client;
+	enum msm_camera_device_type_t act_device_type;
+	struct msm_sd_subdev msm_sd;
+	enum af_camera_name cam_name;
+	struct mutex *actuator_mutex;
+	struct msm_actuator_func_tbl *func_tbl;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *act_v4l2_subdev_ops;
+
+	int16_t curr_step_pos;
+	uint16_t curr_region_index;
+	uint16_t *step_position_table;
+	struct region_params_t region_params[MAX_ACTUATOR_REGION];
+	uint16_t reg_tbl_size;
+	struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE];
+	uint16_t region_size;
+	void *user_data;
+	uint32_t total_steps;
+	uint16_t pwd_step;
+	uint16_t initial_code;
+	struct msm_camera_i2c_reg_array *i2c_reg_tbl;
+	uint16_t i2c_tbl_index;
+	enum cci_i2c_master_t cci_master;
+	uint32_t subdev_id;
+	enum msm_actuator_state_t actuator_state;
+	struct msm_actuator_vreg vreg_cfg;
+	struct park_lens_data_t park_lens;
+	uint32_t max_code_size;
+	struct msm_camera_gpio_conf *gconf;
+	struct msm_pinctrl_info pinctrl_info;
+	uint8_t cam_pinctrl_status;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/Makefile b/drivers/media/platform/msm/camera_v2/sensor/cci/Makefile
new file mode 100644
index 0000000..5815bbe
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSM_CCI) += msm_cci.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
new file mode 100644
index 0000000..afd5846
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CAM_CCI_HWREG__
+#define __MSM_CAM_CCI_HWREG__
+
+#define CCI_HW_VERSION_ADDR                                         0x00000000
+#define CCI_RESET_CMD_ADDR                                          0x00000004
+#define CCI_RESET_CMD_RMSK                                          0x0f73f3f7
+#define CCI_M0_RESET_RMSK                                                0x3F1
+#define CCI_M1_RESET_RMSK                                              0x3F001
+#define CCI_QUEUE_START_ADDR                                        0x00000008
+#define CCI_SET_CID_SYNC_TIMER_ADDR                                 0x00000010
+#define CCI_SET_CID_SYNC_TIMER_OFFSET                               0x00000004
+#define CCI_I2C_M0_SCL_CTL_ADDR                                     0x00000100
+#define CCI_I2C_M0_SDA_CTL_0_ADDR                                   0x00000104
+#define CCI_I2C_M0_SDA_CTL_1_ADDR                                   0x00000108
+#define CCI_I2C_M0_SDA_CTL_2_ADDR                                   0x0000010c
+#define CCI_I2C_M0_READ_DATA_ADDR                                   0x00000118
+#define CCI_I2C_M0_MISC_CTL_ADDR                                    0x00000110
+#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR                              0x0000011C
+#define CCI_HALT_REQ_ADDR                                           0x00000034
+#define CCI_M0_HALT_REQ_RMSK                                               0x1
+#define CCI_M1_HALT_REQ_RMSK                                               0x2
+#define CCI_I2C_M1_SCL_CTL_ADDR                                     0x00000200
+#define CCI_I2C_M1_SDA_CTL_0_ADDR                                   0x00000204
+#define CCI_I2C_M1_SDA_CTL_1_ADDR                                   0x00000208
+#define CCI_I2C_M1_SDA_CTL_2_ADDR                                   0x0000020c
+#define CCI_I2C_M1_MISC_CTL_ADDR                                    0x00000210
+#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR                             0x00000304
+#define CCI_I2C_M0_Q0_CUR_CMD_ADDR                                  0x00000308
+#define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR                            0x0000030c
+#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR                            0x00000300
+#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR                                0x00000310
+#define CCI_IRQ_MASK_0_ADDR                                         0x00000c04
+#define CCI_IRQ_MASK_0_RMSK                                         0x7fff7ff7
+#define CCI_IRQ_CLEAR_0_ADDR                                        0x00000c08
+#define CCI_IRQ_STATUS_0_ADDR                                       0x00000c0c
+#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK                   0x4000000
+#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK                   0x2000000
+#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK                           0x1000000
+#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK                        0x100000
+#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK                         0x10000
+#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK                            0x1000
+#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK                           0x100
+#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK                            0x10
+#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK                          0x18000EE6
+#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK                          0x60EE6000
+#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK                               0x1
+#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR                               0x00000c00
+
+#define DEBUG_TOP_REG_START                                                0x0
+#define DEBUG_TOP_REG_COUNT                                                 14
+#define DEBUG_MASTER_REG_START                                           0x100
+#define DEBUG_MASTER_REG_COUNT                                               8
+#define DEBUG_MASTER_QUEUE_REG_START                                     0x300
+#define DEBUG_MASTER_QUEUE_REG_COUNT                                         6
+#define DEBUG_INTR_REG_START                                             0xC00
+#define DEBUG_INTR_REG_COUNT                                                 7
+#endif /* __MSM_CAM_CCI_HWREG__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
new file mode 100644
index 0000000..b67af9c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -0,0 +1,2244 @@
+/* Copyright (c) 2012-2017, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include "msm_sd.h"
+#include "msm_cci.h"
+#include "msm_cam_cci_hwreg.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+#include "cam_hw_ops.h"
+
+#define V4L2_IDENT_CCI 50005
+#define CCI_I2C_QUEUE_0_SIZE 64
+#define CCI_I2C_Q0_SIZE_128W 128
+#define CCI_I2C_QUEUE_1_SIZE 16
+#define CCI_I2C_Q1_SIZE_32W 32
+#define CYCLES_PER_MICRO_SEC_DEFAULT 4915
+#define CCI_MAX_DELAY 1000000
+
+#define CCI_TIMEOUT msecs_to_jiffies(100)
+
+/* TODO move this somewhere else */
+#define MSM_CCI_DRV_NAME "msm_cci"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#undef CCI_DBG
+#ifdef MSM_CCI_DEBUG
+#define CCI_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CCI_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define CCI_DUMP_REG 0
+
+/* Max bytes that can be read per CCI read transaction */
+#define CCI_READ_MAX 12
+#define CCI_I2C_READ_MAX_RETRIES 3
+#define CCI_I2C_MAX_READ 8192
+#define CCI_I2C_MAX_WRITE 8192
+
+#define PRIORITY_QUEUE (QUEUE_0)
+#define SYNC_QUEUE (QUEUE_1)
+
+static struct v4l2_subdev *g_cci_subdev;
+
+static void msm_cci_dump_registers(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master, enum cci_i2c_queue_t queue)
+{
+	uint32_t read_val = 0;
+	uint32_t i = 0;
+	uint32_t reg_offset = 0;
+
+	/* CCI Top Registers */
+	CCI_DBG(" **** %s : %d CCI TOP Registers ****\n", __func__, __LINE__);
+	for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) {
+		reg_offset = DEBUG_TOP_REG_START + i * 4;
+		read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset);
+		CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n",
+			__func__, __LINE__, reg_offset, read_val);
+	}
+
+	/* CCI Master registers */
+	CCI_DBG(" **** %s : %d CCI MASTER%d Registers ****\n",
+		__func__, __LINE__, master);
+	for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) {
+		if (i == 6)
+			continue;
+		reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4;
+		read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset);
+		CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n",
+			__func__, __LINE__, reg_offset, read_val);
+	}
+
+	/* CCI Master Queue registers */
+	CCI_DBG(" **** %s : %d CCI MASTER%d QUEUE%d Registers ****\n",
+		__func__, __LINE__, master, queue);
+	for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) {
+		reg_offset = DEBUG_MASTER_QUEUE_REG_START +  master*0x200 +
+			queue*0x100 + i * 4;
+		read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset);
+		CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n",
+			__func__, __LINE__, reg_offset, read_val);
+	}
+
+	/* CCI Interrupt registers */
+	CCI_DBG(" **** %s : %d CCI Interrupt Registers ****\n",
+		__func__, __LINE__);
+	for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) {
+		reg_offset = DEBUG_INTR_REG_START + i * 4;
+		read_val = msm_camera_io_r_mb(cci_dev->base + reg_offset);
+		CCI_DBG("%s : %d offset = 0x%X value = 0x%X\n",
+			__func__, __LINE__, reg_offset, read_val);
+	}
+}
+
+static int32_t msm_cci_set_clk_param(struct cci_device *cci_dev,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	struct msm_cci_clk_params_t *clk_params = NULL;
+	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+	enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
+
+	if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) {
+		pr_err("%s:%d invalid i2c_freq_mode = %d",
+			__func__, __LINE__, i2c_freq_mode);
+		return -EINVAL;
+	}
+
+	if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode)
+		return 0;
+
+	clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
+	if (master == MASTER_0) {
+		msm_camera_io_w_mb(clk_params->hw_thigh << 16 |
+			clk_params->hw_tlow,
+			cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 |
+			clk_params->hw_tsu_sta,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 |
+			clk_params->hw_thd_sta,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_tbuf,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 |
+			clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+			cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR);
+	} else if (master == MASTER_1) {
+		msm_camera_io_w_mb(clk_params->hw_thigh << 16 |
+			clk_params->hw_tlow,
+			cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 |
+			clk_params->hw_tsu_sta,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 |
+			clk_params->hw_thd_sta,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_tbuf,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
+		msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 |
+			clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+			cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR);
+	}
+	cci_dev->i2c_freq_mode[master] = i2c_freq_mode;
+	return 0;
+}
+
+static void msm_cci_flush_queue(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master)
+{
+	int32_t rc = 0;
+
+	msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR);
+	rc = wait_for_completion_timeout(
+		&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
+	if (rc < 0) {
+		pr_err("%s:%d wait failed\n", __func__, __LINE__);
+	} else if (rc == 0) {
+		pr_err("%s:%d wait timeout\n", __func__, __LINE__);
+
+		/* Set reset pending flag to TRUE */
+		cci_dev->cci_master_info[master].reset_pending = TRUE;
+
+		/* Set proper mask to RESET CMD address based on MASTER */
+		if (master == MASTER_0)
+			msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+				cci_dev->base + CCI_RESET_CMD_ADDR);
+		else
+			msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+				cci_dev->base + CCI_RESET_CMD_ADDR);
+
+		/* wait for reset done irq */
+		rc = wait_for_completion_timeout(
+			&cci_dev->cci_master_info[master].reset_complete,
+			CCI_TIMEOUT);
+		if (rc <= 0)
+			pr_err("%s:%d wait failed %d\n", __func__, __LINE__,
+				rc);
+	}
+}
+
+static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
+	uint32_t len,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+	unsigned long flags;
+	uint32_t read_val = 0;
+	uint32_t reg_offset = master * 0x200 + queue * 0x100;
+
+	read_val = msm_camera_io_r_mb(cci_dev->base +
+		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+	CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n",
+		__func__, __LINE__, read_val, len,
+		cci_dev->cci_i2c_queue_info[master][queue].max_queue_size);
+	if ((read_val + len + 1) > cci_dev->
+		cci_i2c_queue_info[master][queue].max_queue_size) {
+		uint32_t reg_val = 0;
+		uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8);
+
+		CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__);
+		msm_camera_io_w_mb(report_val,
+			cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+			reg_offset);
+		read_val++;
+		CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d, queue: %d\n",
+			__func__, __LINE__, read_val, queue);
+		msm_camera_io_w_mb(read_val, cci_dev->base +
+			CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+		reg_val = 1 << ((master * 2) + queue);
+		CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
+		spin_lock_irqsave(&cci_dev->cci_master_info[master].
+						lock_q[queue], flags);
+		atomic_set(&cci_dev->cci_master_info[master].
+						done_pending[queue], 1);
+		msm_camera_io_w_mb(reg_val, cci_dev->base +
+			CCI_QUEUE_START_ADDR);
+		CDBG("%s line %d wait_for_completion_timeout\n",
+			__func__, __LINE__);
+		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+						lock_q[queue], flags);
+		rc = wait_for_completion_timeout(&cci_dev->
+			cci_master_info[master].report_q[queue], CCI_TIMEOUT);
+		if (rc <= 0) {
+			pr_err("%s: wait_for_completion_timeout %d\n",
+				 __func__, __LINE__);
+			if (rc == 0)
+				rc = -ETIMEDOUT;
+			msm_cci_flush_queue(cci_dev, master);
+			return rc;
+		}
+		rc = cci_dev->cci_master_info[master].status;
+		if (rc < 0)
+			pr_err("%s failed rc %d\n", __func__, rc);
+	}
+	return rc;
+}
+
+static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev,
+	uint32_t val,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+	uint32_t reg_offset = master * 0x200 + queue * 0x100;
+
+	if (!cci_dev) {
+		pr_err("%s: failed %d", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	rc = msm_cci_validate_queue(cci_dev, 1, master, queue);
+	if (rc < 0) {
+		pr_err("%s: failed %d", __func__, __LINE__);
+		return rc;
+	}
+	CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n",
+		__func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset, val);
+	msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+	return rc;
+}
+
+static uint32_t msm_cci_wait(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+
+	if (!cci_dev) {
+		pr_err("%s: failed %d", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	rc = wait_for_completion_timeout(&cci_dev->
+		cci_master_info[master].report_q[queue], CCI_TIMEOUT);
+	CDBG("%s line %d wait DONE_for_completion_timeout\n",
+		__func__, __LINE__);
+
+	if (rc <= 0) {
+		if (CCI_DUMP_REG)
+			msm_cci_dump_registers(cci_dev, master, queue);
+
+		pr_err("%s: %d wait for queue: %d\n",
+			 __func__, __LINE__, queue);
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		msm_cci_flush_queue(cci_dev, master);
+		return rc;
+	}
+	rc = cci_dev->cci_master_info[master].status;
+	if (rc < 0) {
+		pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int32_t msm_cci_addr_to_num_bytes(
+	enum msm_camera_i2c_reg_addr_type addr_type)
+{
+	int32_t retVal;
+
+	switch (addr_type) {
+	case MSM_CAMERA_I2C_BYTE_ADDR:
+		retVal = 1;
+		break;
+	case MSM_CAMERA_I2C_WORD_ADDR:
+		retVal = 2;
+		break;
+	case MSM_CAMERA_I2C_3B_ADDR:
+		retVal = 3;
+		break;
+	case MSM_CAMERA_I2C_DWORD_ADDR:
+		retVal = 4;
+		break;
+	default:
+		pr_err("%s: %d failed: %d\n", __func__, __LINE__, addr_type);
+		retVal = 1;
+		break;
+	}
+	return retVal;
+}
+
+static int32_t msm_cci_data_to_num_bytes(
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t retVal;
+
+	switch (data_type) {
+	case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+	case MSM_CAMERA_I2C_SET_BYTE_MASK:
+	case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+	case MSM_CAMERA_I2C_BYTE_DATA:
+		retVal = 1;
+		break;
+	case MSM_CAMERA_I2C_SET_WORD_MASK:
+	case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+	case MSM_CAMERA_I2C_WORD_DATA:
+		retVal = 2;
+		break;
+	case MSM_CAMERA_I2C_DWORD_DATA:
+		retVal = 4;
+		break;
+	default:
+		pr_err("%s: %d failed: %d\n", __func__, __LINE__, data_type);
+		retVal = 1;
+		break;
+	}
+	return retVal;
+}
+
+static int32_t msm_cci_calc_cmd_len(struct cci_device *cci_dev,
+	struct msm_camera_cci_ctrl *c_ctrl, uint32_t cmd_size,
+	 struct msm_camera_i2c_reg_array *i2c_cmd, uint32_t *pack)
+{
+	uint8_t i;
+	uint32_t len = 0;
+	uint8_t data_len = 0, addr_len = 0;
+	uint8_t pack_max_len;
+	struct msm_camera_i2c_reg_setting *msg;
+	struct msm_camera_i2c_reg_array *cmd = i2c_cmd;
+	uint32_t size = cmd_size;
+
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s: failed %d", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	msg = &c_ctrl->cfg.cci_i2c_write_cfg;
+	*pack = 0;
+
+	if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) {
+		addr_len = msm_cci_addr_to_num_bytes(msg->addr_type);
+		len = (size + addr_len) <= (cci_dev->payload_size) ?
+			(size + addr_len):cci_dev->payload_size;
+	} else {
+		addr_len = msm_cci_addr_to_num_bytes(msg->addr_type);
+		data_len = msm_cci_data_to_num_bytes(msg->data_type);
+		len = data_len + addr_len;
+		pack_max_len = size < (cci_dev->payload_size-len) ?
+			size : (cci_dev->payload_size-len);
+		for (i = 0; i < pack_max_len;) {
+			if (cmd->delay || ((cmd - i2c_cmd) >= (cmd_size - 1)))
+				break;
+			if (cmd->reg_addr + 1 ==
+				(cmd+1)->reg_addr) {
+				len += data_len;
+				if (len > cci_dev->payload_size) {
+					len = len - data_len;
+					break;
+				}
+				*pack += data_len;
+			} else
+				break;
+			i += data_len;
+			cmd++;
+		}
+	}
+
+	if (len > cci_dev->payload_size) {
+		pr_err("Len error: %d", len);
+		return -EINVAL;
+	}
+
+	len += 1; /*add i2c WR command*/
+	len = len/4 + 1;
+
+	return len;
+}
+
+static void msm_cci_load_report_cmd(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	uint32_t reg_offset = master * 0x200 + queue * 0x100;
+	uint32_t read_val = msm_camera_io_r_mb(cci_dev->base +
+		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+	uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8);
+
+	CDBG("%s:%d CCI_I2C_REPORT_CMD curr_w_cnt: %d\n",
+		__func__, __LINE__, read_val);
+	msm_camera_io_w_mb(report_val,
+		cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+	read_val++;
+
+	CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n",
+		__func__, __LINE__, read_val);
+	msm_camera_io_w_mb(read_val, cci_dev->base +
+		CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+}
+
+static int32_t msm_cci_wait_report_cmd(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	unsigned long flags;
+	uint32_t reg_val = 1 << ((master * 2) + queue);
+
+	msm_cci_load_report_cmd(cci_dev, master, queue);
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+	atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+
+	msm_camera_io_w_mb(reg_val, cci_dev->base +
+		CCI_QUEUE_START_ADDR);
+	return msm_cci_wait(cci_dev, master, queue);
+}
+
+static void msm_cci_process_half_q(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	unsigned long flags;
+	uint32_t reg_val = 1 << ((master * 2) + queue);
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
+		msm_cci_load_report_cmd(cci_dev, master, queue);
+		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+		msm_camera_io_w_mb(reg_val, cci_dev->base +
+			CCI_QUEUE_START_ADDR);
+	}
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+}
+
+static int32_t msm_cci_process_full_q(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 1) {
+		atomic_set(&cci_dev->cci_master_info[master].
+						done_pending[queue], 1);
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+		rc = msm_cci_wait(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+	} else {
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+						lock_q[queue], flags);
+		rc = msm_cci_wait_report_cmd(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int32_t msm_cci_lock_queue(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue, uint32_t en)
+{
+	uint32_t val;
+
+	if (queue != PRIORITY_QUEUE)
+		return 0;
+
+	val = en ? CCI_I2C_LOCK_CMD : CCI_I2C_UNLOCK_CMD;
+	return msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+}
+
+static int32_t msm_cci_transfer_end(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+						lock_q[queue], flags);
+		rc = msm_cci_lock_queue(cci_dev, master, queue, 0);
+		if (rc < 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return rc;
+		}
+		rc = msm_cci_wait_report_cmd(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+	} else {
+		atomic_set(&cci_dev->cci_master_info[master].
+						done_pending[queue], 1);
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+						lock_q[queue], flags);
+		rc = msm_cci_wait(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+		rc = msm_cci_lock_queue(cci_dev, master, queue, 0);
+		if (rc < 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return rc;
+		}
+		rc = msm_cci_wait_report_cmd(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int32_t msm_cci_get_queue_free_size(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	uint32_t read_val = 0;
+	uint32_t reg_offset = master * 0x200 + queue * 0x100;
+
+	read_val = msm_camera_io_r_mb(cci_dev->base +
+		CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+	CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d max %d\n",
+		__func__, __LINE__, read_val,
+		cci_dev->cci_i2c_queue_info[master][queue].max_queue_size);
+	return (cci_dev->
+		cci_i2c_queue_info[master][queue].max_queue_size) -
+		read_val;
+}
+
+static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
+	struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
+	enum cci_i2c_sync sync_en)
+{
+	uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
+	int32_t rc = 0, free_size = 0, en_seq_write = 0;
+	uint32_t cmd = 0, delay = 0;
+	uint8_t data[12];
+	uint16_t reg_addr = 0;
+	struct msm_camera_i2c_reg_setting *i2c_msg =
+		&c_ctrl->cfg.cci_i2c_write_cfg;
+	uint16_t cmd_size = i2c_msg->size;
+	struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
+	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+
+	uint32_t read_val = 0;
+	uint32_t reg_offset;
+	uint32_t val = 0;
+	uint32_t max_queue_size;
+	unsigned long flags;
+
+	if (i2c_cmd == NULL) {
+		pr_err("%s:%d Failed line\n", __func__,
+			__LINE__);
+		return -EINVAL;
+	}
+
+	if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) {
+		pr_err("%s:%d failed: invalid cmd_size %d\n",
+			__func__, __LINE__, cmd_size);
+		return -EINVAL;
+	}
+
+	CDBG("%s addr type %d data type %d cmd_size %d\n", __func__,
+		i2c_msg->addr_type, i2c_msg->data_type, cmd_size);
+
+	if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		pr_err("%s:%d failed: invalid addr_type 0x%X\n",
+			__func__, __LINE__, i2c_msg->addr_type);
+		return -EINVAL;
+	}
+	if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) {
+		pr_err("%s:%d failed: invalid data_type 0x%X\n",
+			__func__, __LINE__, i2c_msg->data_type);
+		return -EINVAL;
+	}
+	reg_offset = master * 0x200 + queue * 0x100;
+
+	msm_camera_io_w_mb(cci_dev->cci_wait_sync_cfg.cid,
+		cci_dev->base + CCI_SET_CID_SYNC_TIMER_ADDR +
+		cci_dev->cci_wait_sync_cfg.csid *
+		CCI_SET_CID_SYNC_TIMER_OFFSET);
+
+	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
+		c_ctrl->cci_info->retries << 16 |
+		c_ctrl->cci_info->id_map << 18;
+
+	CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n",
+		__func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset, val);
+	msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+
+	spin_lock_irqsave(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+					lock_q[queue], flags);
+
+	max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
+			max_queue_size;
+	reg_addr = i2c_cmd->reg_addr;
+
+	if (sync_en == MSM_SYNC_ENABLE && cci_dev->valid_sync &&
+		cmd_size < max_queue_size) {
+		val = CCI_I2C_WAIT_SYNC_CMD |
+			((cci_dev->cci_wait_sync_cfg.line) << 4);
+		msm_camera_io_w_mb(val,
+			cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+			reg_offset);
+	}
+
+	rc = msm_cci_lock_queue(cci_dev, master, queue, 1);
+	if (rc < 0) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return rc;
+	}
+
+	while (cmd_size) {
+		uint32_t pack = 0;
+
+		len = msm_cci_calc_cmd_len(cci_dev, c_ctrl, cmd_size,
+			i2c_cmd, &pack);
+		if (len <= 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		read_val = msm_camera_io_r_mb(cci_dev->base +
+			CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+		CDBG("%s line %d CUR_WORD_CNT_ADDR %d len %d max %d\n",
+			__func__, __LINE__, read_val, len, max_queue_size);
+		/* + 1 - space alocation for Report CMD*/
+		if ((read_val + len + 1) > max_queue_size/2) {
+			if ((read_val + len + 1) > max_queue_size) {
+				rc = msm_cci_process_full_q(cci_dev,
+					master, queue);
+				if (rc < 0) {
+					pr_err("%s failed line %d\n",
+						__func__, __LINE__);
+					return rc;
+				}
+				continue;
+			}
+			msm_cci_process_half_q(cci_dev,	master, queue);
+		}
+
+		CDBG("%s cmd_size %d addr 0x%x data 0x%x\n", __func__,
+			cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
+		delay = i2c_cmd->delay;
+		i = 0;
+		data[i++] = CCI_I2C_WRITE_CMD;
+
+		/* in case of multiple command
+		 * MSM_CCI_I2C_WRITE : address is not continuous, so update
+		 *			address for a new packet.
+		 * MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep
+		 *			the incremented address for a
+		 *			new packet
+		 */
+		if (c_ctrl->cmd == MSM_CCI_I2C_WRITE ||
+			c_ctrl->cmd == MSM_CCI_I2C_WRITE_ASYNC ||
+			c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC ||
+			c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC_BLOCK)
+			reg_addr = i2c_cmd->reg_addr;
+
+		if (en_seq_write == 0) {
+			/* either byte or word addr */
+			if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
+				data[i++] = reg_addr;
+			else {
+				data[i++] = (reg_addr & 0xFF00) >> 8;
+				data[i++] = reg_addr & 0x00FF;
+			}
+		}
+		/* max of 10 data bytes */
+		do {
+			if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+				data[i++] = i2c_cmd->reg_data;
+				reg_addr++;
+			} else {
+				if ((i + 1) <= cci_dev->payload_size) {
+					data[i++] = (i2c_cmd->reg_data &
+						0xFF00) >> 8; /* MSB */
+					data[i++] = i2c_cmd->reg_data &
+						0x00FF; /* LSB */
+					reg_addr++;
+				} else
+					break;
+			}
+			i2c_cmd++;
+			--cmd_size;
+		} while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) || pack--) &&
+				(cmd_size > 0) && (i <= cci_dev->payload_size));
+		free_size = msm_cci_get_queue_free_size(cci_dev, master,
+				queue);
+		if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) &&
+			((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) &&
+			cci_dev->support_seq_write && cmd_size > 0 &&
+			free_size > BURST_MIN_FREE_SIZE) {
+			data[0] |= 0xF0;
+			en_seq_write = 1;
+		} else {
+			data[0] |= ((i-1) << 4);
+			en_seq_write = 0;
+		}
+		len = ((i-1)/4) + 1;
+
+		read_val = msm_camera_io_r_mb(cci_dev->base +
+			CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+		for (h = 0, k = 0; h < len; h++) {
+			cmd = 0;
+			for (j = 0; (j < 4 && k < i); j++)
+				cmd |= (data[k++] << (j * 8));
+			CDBG("%s LOAD_DATA_ADDR 0x%x, q: %d, len:%d, cnt: %d\n",
+				__func__, cmd, queue, len, read_val);
+			msm_camera_io_w_mb(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+
+			read_val += 1;
+			msm_camera_io_w_mb(read_val, cci_dev->base +
+				CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+		}
+
+		if ((delay > 0) && (delay < CCI_MAX_DELAY) &&
+			en_seq_write == 0) {
+			cmd = (uint32_t)((delay * cci_dev->cycles_per_us) /
+				0x100);
+			cmd <<= 4;
+			cmd |= CCI_I2C_WAIT_CMD;
+			CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+				__func__, cmd);
+			msm_camera_io_w_mb(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+			read_val += 1;
+			msm_camera_io_w_mb(read_val, cci_dev->base +
+				CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+		}
+	}
+
+	rc = msm_cci_transfer_end(cci_dev, master, queue);
+	if (rc < 0) {
+		pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	return rc;
+}
+
+static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	uint32_t val = 0;
+	int32_t read_words = 0, exp_words = 0;
+	int32_t index = 0, first_byte = 0;
+	uint32_t i = 0;
+	enum cci_i2c_master_t master;
+	enum cci_i2c_queue_t queue = QUEUE_1;
+	struct cci_device *cci_dev = NULL;
+	struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL;
+
+	CDBG("%s line %d\n", __func__, __LINE__);
+	cci_dev = v4l2_get_subdevdata(sd);
+	master = c_ctrl->cci_info->cci_i2c_master;
+	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
+
+	if (master >= MASTER_MAX || master < 0) {
+		pr_err("%s:%d Invalid I2C master %d\n",
+			__func__, __LINE__, master);
+		return -EINVAL;
+	}
+
+	mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
+
+	/* Set the I2C Frequency */
+	rc = msm_cci_set_clk_param(cci_dev, c_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d msm_cci_set_clk_param failed rc = %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	/*
+	 * Call validate queue to make sure queue is empty before starting.
+	 * If this call fails, don't proceed with i2c_read call. This is to
+	 * avoid overflow / underflow of queue
+	 */
+	rc = msm_cci_validate_queue(cci_dev,
+		cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1,
+		master, queue);
+	if (rc < 0) {
+		pr_err("%s:%d Initial validataion failed rc %d\n", __func__,
+			__LINE__, rc);
+		goto ERROR;
+	}
+
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
+	if (read_cfg->data == NULL) {
+		pr_err("%s:%d Data ptr is NULL\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
+	CDBG("%s master %d, queue %d\n", __func__, master, queue);
+	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+		c_ctrl->cci_info->id_map);
+	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
+		c_ctrl->cci_info->retries << 16 |
+		c_ctrl->cci_info->id_map << 18;
+	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	val = CCI_I2C_LOCK_CMD;
+	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4);
+	for (i = 0; i < read_cfg->addr_type; i++) {
+		val |= ((read_cfg->addr >> (i << 3)) & 0xFF)  <<
+		((read_cfg->addr_type - i) << 3);
+	}
+
+	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4);
+	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	val = CCI_I2C_UNLOCK_CMD;
+	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+	val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR
+			+ master * 0x200 + queue * 0x100);
+	CDBG("%s cur word cnt 0x%x\n", __func__, val);
+	msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR
+			+ master * 0x200 + queue * 0x100);
+
+	val = 1 << ((master * 2) + queue);
+	msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR);
+	CDBG("%s:%d E wait_for_completion_timeout\n", __func__,
+		__LINE__);
+
+	rc = wait_for_completion_timeout(&cci_dev->
+		cci_master_info[master].reset_complete, CCI_TIMEOUT);
+	if (rc <= 0) {
+		if (CCI_DUMP_REG)
+			msm_cci_dump_registers(cci_dev, master, queue);
+
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		pr_err("%s: %d wait_for_completion_timeout rc = %d\n",
+			 __func__, __LINE__, rc);
+		msm_cci_flush_queue(cci_dev, master);
+		goto ERROR;
+	} else {
+		rc = 0;
+	}
+
+	read_words = msm_camera_io_r_mb(cci_dev->base +
+		CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
+	exp_words = ((read_cfg->num_byte / 4) + 1);
+	if (read_words != exp_words) {
+		pr_err("%s:%d read_words = %d, exp words = %d\n", __func__,
+			__LINE__, read_words, exp_words);
+		memset(read_cfg->data, 0, read_cfg->num_byte);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+	index = 0;
+	CDBG("%s index %d num_type %d\n", __func__, index,
+		read_cfg->num_byte);
+	first_byte = 0;
+	do {
+		val = msm_camera_io_r_mb(cci_dev->base +
+			CCI_I2C_M0_READ_DATA_ADDR + master * 0x100);
+		CDBG("%s read val 0x%x\n", __func__, val);
+		for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) {
+			CDBG("%s i %d index %d\n", __func__, i, index);
+			if (!first_byte) {
+				CDBG("%s sid 0x%x\n", __func__, val & 0xFF);
+				first_byte++;
+			} else {
+				read_cfg->data[index] =
+					(val  >> (i * 8)) & 0xFF;
+				CDBG("%s data[%d] 0x%x\n", __func__, index,
+					read_cfg->data[index]);
+				index++;
+			}
+		}
+	} while (--read_words > 0);
+ERROR:
+	mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]);
+	return rc;
+}
+
+static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev = NULL;
+	enum cci_i2c_master_t master;
+	struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL;
+	uint16_t read_bytes = 0;
+
+	if (!sd || !c_ctrl) {
+		pr_err("%s:%d sd %pK c_ctrl %pK\n", __func__,
+			__LINE__, sd, c_ctrl);
+		return -EINVAL;
+	}
+	if (!c_ctrl->cci_info) {
+		pr_err("%s:%d cci_info NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (!cci_dev) {
+		pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (cci_dev->cci_state != CCI_STATE_ENABLED) {
+		pr_err("%s invalid cci state %d\n",
+			__func__, cci_dev->cci_state);
+		return -EINVAL;
+	}
+
+	if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX
+			|| c_ctrl->cci_info->cci_i2c_master < 0) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	master = c_ctrl->cci_info->cci_i2c_master;
+	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
+	if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) {
+		pr_err("%s:%d read num bytes 0\n", __func__, __LINE__);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+
+	read_bytes = read_cfg->num_byte;
+	do {
+		if (read_bytes > CCI_READ_MAX)
+			read_cfg->num_byte = CCI_READ_MAX;
+		else
+			read_cfg->num_byte = read_bytes;
+		rc = msm_cci_i2c_read(sd, c_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		if (read_bytes > CCI_READ_MAX) {
+			read_cfg->addr += CCI_READ_MAX;
+			read_cfg->data += CCI_READ_MAX;
+			read_bytes -= CCI_READ_MAX;
+		} else {
+			read_bytes = 0;
+		}
+	} while (read_bytes);
+ERROR:
+	return rc;
+}
+
+static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
+	enum cci_i2c_sync sync_en)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (cci_dev->cci_state != CCI_STATE_ENABLED) {
+		pr_err("%s invalid cci state %d\n",
+			__func__, cci_dev->cci_state);
+		return -EINVAL;
+	}
+	master = c_ctrl->cci_info->cci_i2c_master;
+	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+		c_ctrl->cci_info->id_map);
+
+	/* Set the I2C Frequency */
+	rc = msm_cci_set_clk_param(cci_dev, c_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d msm_cci_set_clk_param failed rc = %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+	/*
+	 * Call validate queue to make sure queue is empty before starting.
+	 * If this call fails, don't proceed with i2c_write call. This is to
+	 * avoid overflow / underflow of queue
+	 */
+	rc = msm_cci_validate_queue(cci_dev,
+		cci_dev->cci_i2c_queue_info[master][queue].max_queue_size-1,
+		master, queue);
+	if (rc < 0) {
+		pr_err("%s:%d Initial validataion failed rc %d\n",
+		__func__, __LINE__, rc);
+		goto ERROR;
+	}
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+	rc = msm_cci_data_queue(cci_dev, c_ctrl, queue, sync_en);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
+ERROR:
+	return rc;
+}
+
+static void msm_cci_write_async_helper(struct work_struct *work)
+{
+	int rc;
+	struct cci_device *cci_dev;
+	struct cci_write_async *write_async =
+		container_of(work, struct cci_write_async, work);
+	struct msm_camera_i2c_reg_setting *i2c_msg;
+	enum cci_i2c_master_t master;
+	struct msm_camera_cci_master_info *cci_master_info;
+
+	cci_dev = write_async->cci_dev;
+	i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg;
+	master = write_async->c_ctrl.cci_info->cci_i2c_master;
+	cci_master_info = &cci_dev->cci_master_info[master];
+
+	mutex_lock(&cci_master_info->mutex_q[write_async->queue]);
+	rc = msm_cci_i2c_write(&cci_dev->msm_sd.sd,
+		&write_async->c_ctrl, write_async->queue, write_async->sync_en);
+	mutex_unlock(&cci_master_info->mutex_q[write_async->queue]);
+	if (rc < 0)
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+
+	kfree(write_async->c_ctrl.cfg.cci_i2c_write_cfg.reg_setting);
+	kfree(write_async);
+
+	CDBG("%s: %d Exit\n", __func__, __LINE__);
+}
+
+static int32_t msm_cci_i2c_write_async(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
+	enum cci_i2c_sync sync_en)
+{
+	struct cci_write_async *write_async;
+	struct cci_device *cci_dev;
+	struct msm_camera_i2c_reg_setting *cci_i2c_write_cfg;
+	struct msm_camera_i2c_reg_setting *cci_i2c_write_cfg_w;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+
+	CDBG("%s: %d Enter\n", __func__, __LINE__);
+
+	write_async = kzalloc(sizeof(*write_async), GFP_KERNEL);
+	if (!write_async)
+		return -ENOMEM;
+
+	INIT_WORK(&write_async->work, msm_cci_write_async_helper);
+	write_async->cci_dev = cci_dev;
+	write_async->c_ctrl = *c_ctrl;
+	write_async->queue = queue;
+	write_async->sync_en = sync_en;
+
+	cci_i2c_write_cfg = &c_ctrl->cfg.cci_i2c_write_cfg;
+	cci_i2c_write_cfg_w = &write_async->c_ctrl.cfg.cci_i2c_write_cfg;
+
+	if (cci_i2c_write_cfg->size == 0) {
+		pr_err("%s: %d Size = 0\n", __func__, __LINE__);
+		kfree(write_async);
+		return -EINVAL;
+	}
+
+	cci_i2c_write_cfg_w->reg_setting =
+		kzalloc(sizeof(struct msm_camera_i2c_reg_array)*
+		cci_i2c_write_cfg->size, GFP_KERNEL);
+	if (!cci_i2c_write_cfg_w->reg_setting) {
+		pr_err("%s: %d Couldn't allocate memory\n", __func__, __LINE__);
+		kfree(write_async);
+		return -ENOMEM;
+	}
+	memcpy(cci_i2c_write_cfg_w->reg_setting,
+		cci_i2c_write_cfg->reg_setting,
+		(sizeof(struct msm_camera_i2c_reg_array)*
+						cci_i2c_write_cfg->size));
+
+	cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type;
+	cci_i2c_write_cfg_w->data_type = cci_i2c_write_cfg->data_type;
+	cci_i2c_write_cfg_w->size = cci_i2c_write_cfg->size;
+	cci_i2c_write_cfg_w->delay = cci_i2c_write_cfg->delay;
+
+	queue_work(cci_dev->write_wq[write_async->queue], &write_async->work);
+
+	CDBG("%s: %d Exit\n", __func__, __LINE__);
+
+	return 0;
+}
+
+static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev)
+{
+	struct msm_pinctrl_info *cci_pctrl = NULL;
+
+	cci_pctrl = &cci_dev->cci_pinctrl;
+	cci_pctrl->pinctrl = devm_pinctrl_get(&cci_dev->pdev->dev);
+	if (IS_ERR_OR_NULL(cci_pctrl->pinctrl)) {
+		pr_err("%s:%d devm_pinctrl_get cci_pinctrl failed\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	cci_pctrl->gpio_state_active = pinctrl_lookup_state(
+						cci_pctrl->pinctrl,
+						CCI_PINCTRL_STATE_DEFAULT);
+	if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_active)) {
+		pr_err("%s:%d look up state  for active state failed\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	cci_pctrl->gpio_state_suspend = pinctrl_lookup_state(
+						cci_pctrl->pinctrl,
+						CCI_PINCTRL_STATE_SLEEP);
+	if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_suspend)) {
+		pr_err("%s:%d look up state for suspend state failed\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static uint32_t msm_cci_cycles_per_ms(unsigned long clk)
+{
+	uint32_t cycles_per_us;
+
+	if (clk)
+		cycles_per_us = ((clk/1000)*256)/1000;
+	else {
+		pr_err("%s:%d, failed: Can use default: %d",
+			__func__, __LINE__, CYCLES_PER_MICRO_SEC_DEFAULT);
+		cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT;
+	}
+	return cycles_per_us;
+}
+
+static uint32_t *msm_cci_get_clk_rates(struct cci_device *cci_dev,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	uint32_t j;
+	int32_t idx;
+	uint32_t cci_clk_src;
+	unsigned long clk;
+
+	struct msm_cci_clk_params_t *clk_params = NULL;
+	enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
+	struct device_node *of_node = cci_dev->pdev->dev.of_node;
+
+	if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) {
+		pr_err("%s:%d invalid i2c_freq_mode %d\n",
+			__func__, __LINE__, i2c_freq_mode);
+		return NULL;
+	}
+
+	clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
+	cci_clk_src = clk_params->cci_clk_src;
+
+	idx = of_property_match_string(of_node,
+		"clock-names", CCI_CLK_SRC_NAME);
+	if (idx < 0) {
+		cci_dev->cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT;
+		return cci_dev->cci_clk_rates[0];
+	}
+
+	if (cci_clk_src == 0) {
+		clk = cci_dev->cci_clk_rates[0][idx];
+		cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk);
+		return cci_dev->cci_clk_rates[0];
+	}
+
+	for (j = 0; j < cci_dev->num_clk_cases; j++) {
+		clk = cci_dev->cci_clk_rates[j][idx];
+		if (clk == cci_clk_src) {
+			cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk);
+			cci_dev->cci_clk_src = cci_clk_src;
+			return cci_dev->cci_clk_rates[j];
+		}
+	}
+
+	return NULL;
+}
+
+static int32_t msm_cci_i2c_set_sync_prms(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s:%d failed: invalid params %pK %pK\n", __func__,
+			__LINE__, cci_dev, c_ctrl);
+		rc = -EINVAL;
+		return rc;
+	}
+	cci_dev->cci_wait_sync_cfg = c_ctrl->cfg.cci_wait_sync_cfg;
+	cci_dev->valid_sync = cci_dev->cci_wait_sync_cfg.csid < 0 ? 0 : 1;
+
+	return rc;
+}
+
+static int32_t msm_cci_init(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	uint8_t i = 0, j = 0;
+	int32_t rc = 0, ret = 0;
+	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master = MASTER_0;
+	uint32_t *clk_rates  = NULL;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s:%d failed: invalid params %pK %pK\n", __func__,
+			__LINE__, cci_dev, c_ctrl);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+
+	if (cci_dev->ref_count++) {
+		CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+		master = c_ctrl->cci_info->cci_i2c_master;
+		CDBG("%s:%d master %d\n", __func__, __LINE__, master);
+		if (master < MASTER_MAX && master >= 0) {
+			mutex_lock(&cci_dev->cci_master_info[master].mutex);
+			mutex_lock(&cci_dev->cci_master_info[master].
+				mutex_q[PRIORITY_QUEUE]);
+			mutex_lock(&cci_dev->cci_master_info[master].
+				mutex_q[SYNC_QUEUE]);
+			flush_workqueue(cci_dev->write_wq[master]);
+			/* Re-initialize the completion */
+			reinit_completion(&cci_dev->
+				cci_master_info[master].reset_complete);
+			for (i = 0; i < NUM_QUEUES; i++)
+				reinit_completion(&cci_dev->
+					cci_master_info[master].report_q[i]);
+			/* Set reset pending flag to TRUE */
+			cci_dev->cci_master_info[master].reset_pending = TRUE;
+			/* Set proper mask to RESET CMD address */
+			if (master == MASTER_0)
+				msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			else
+				msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			/* wait for reset done irq */
+			rc = wait_for_completion_timeout(
+				&cci_dev->cci_master_info[master].
+				reset_complete,
+				CCI_TIMEOUT);
+			if (rc <= 0)
+				pr_err("%s:%d wait failed %d\n", __func__,
+					__LINE__, rc);
+			mutex_unlock(&cci_dev->cci_master_info[master].
+				mutex_q[SYNC_QUEUE]);
+			mutex_unlock(&cci_dev->cci_master_info[master].
+				mutex_q[PRIORITY_QUEUE]);
+			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+		}
+		return 0;
+	}
+	ret = msm_cci_pinctrl_init(cci_dev);
+	if (ret < 0) {
+		pr_err("%s:%d Initialization of pinctrl failed\n",
+				__func__, __LINE__);
+		cci_dev->cci_pinctrl_status = 0;
+	} else {
+		cci_dev->cci_pinctrl_status = 1;
+	}
+	rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+		cci_dev->cci_gpio_tbl_size, 1);
+	if (cci_dev->cci_pinctrl_status) {
+		ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl,
+				cci_dev->cci_pinctrl.gpio_state_active);
+		if (ret)
+			pr_err("%s:%d cannot set pin to active state\n",
+				__func__, __LINE__);
+	}
+	if (rc < 0) {
+		CDBG("%s: request gpio failed\n", __func__);
+		goto request_gpio_failed;
+	}
+
+	rc = msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg,
+		cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d cci config_vreg failed\n", __func__, __LINE__);
+		goto clk_enable_failed;
+	}
+
+	rc = msm_camera_enable_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg,
+		cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d cci enable_vreg failed\n", __func__, __LINE__);
+		goto reg_enable_failed;
+	}
+
+	clk_rates = msm_cci_get_clk_rates(cci_dev, c_ctrl);
+	if (!clk_rates) {
+		pr_err("%s: clk enable failed\n", __func__);
+		goto reg_enable_failed;
+	}
+
+	for (i = 0; i < cci_dev->num_clk; i++) {
+		cci_dev->cci_clk_info[i].clk_rate =
+			clk_rates[i];
+	}
+	rc = msm_camera_clk_enable(&cci_dev->pdev->dev,
+		cci_dev->cci_clk_info, cci_dev->cci_clk,
+		cci_dev->num_clk, true);
+	if (rc < 0) {
+		pr_err("%s: clk enable failed\n", __func__);
+		goto reg_enable_failed;
+	}
+
+	/* Re-initialize the completion */
+	reinit_completion(&cci_dev->cci_master_info[master].reset_complete);
+	for (i = 0; i < NUM_QUEUES; i++)
+		reinit_completion(&cci_dev->cci_master_info[master].
+			report_q[i]);
+	rc = msm_camera_enable_irq(cci_dev->irq, true);
+	if (rc < 0)
+		pr_err("%s: irq enable failed\n", __func__);
+	cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base +
+		CCI_HW_VERSION_ADDR);
+	pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__,
+		cci_dev->hw_version);
+	cci_dev->payload_size =
+			MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10;
+	cci_dev->support_seq_write = 0;
+	if (cci_dev->hw_version >= 0x10020000) {
+		cci_dev->payload_size =
+			MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11;
+		cci_dev->support_seq_write = 1;
+	}
+	for (i = 0; i < NUM_MASTERS; i++) {
+		for (j = 0; j < NUM_QUEUES; j++) {
+			if (j == QUEUE_0) {
+				if (cci_dev->hw_version >= 0x10060000)
+					cci_dev->cci_i2c_queue_info[i][j].
+						max_queue_size =
+							CCI_I2C_Q0_SIZE_128W;
+				else
+					cci_dev->cci_i2c_queue_info[i][j].
+						max_queue_size =
+							CCI_I2C_QUEUE_0_SIZE;
+			} else  {
+				if (cci_dev->hw_version >= 0x10060000)
+					cci_dev->cci_i2c_queue_info[i][j].
+						max_queue_size =
+							CCI_I2C_Q1_SIZE_32W;
+				else
+					cci_dev->cci_i2c_queue_info[i][j].
+						max_queue_size =
+							CCI_I2C_QUEUE_1_SIZE;
+			}
+			CDBG("CCI Master[%d] :: Q0 size: %d Q1 size: %d\n", i,
+				cci_dev->cci_i2c_queue_info[i][j].
+				max_queue_size,
+				cci_dev->cci_i2c_queue_info[i][j].
+				max_queue_size);
+		}
+	}
+
+	cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
+	msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base +
+			CCI_RESET_CMD_ADDR);
+	msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
+	rc = wait_for_completion_timeout(
+		&cci_dev->cci_master_info[MASTER_0].reset_complete,
+		CCI_TIMEOUT);
+	if (rc <= 0) {
+		pr_err("%s: wait_for_completion_timeout %d\n",
+			 __func__, __LINE__);
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		goto reset_complete_failed;
+	}
+	for (i = 0; i < MASTER_MAX; i++)
+		cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES;
+	msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+		cci_dev->base + CCI_IRQ_MASK_0_ADDR);
+	msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+		cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+	msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	for (i = 0; i < MASTER_MAX; i++) {
+		if (!cci_dev->write_wq[i]) {
+			pr_err("Failed to flush write wq\n");
+			rc = -ENOMEM;
+			goto reset_complete_failed;
+		} else {
+			flush_workqueue(cci_dev->write_wq[i]);
+		}
+	}
+	cci_dev->cci_state = CCI_STATE_ENABLED;
+
+	return 0;
+
+reset_complete_failed:
+	msm_camera_enable_irq(cci_dev->irq, false);
+	msm_camera_clk_enable(&cci_dev->pdev->dev, cci_dev->cci_clk_info,
+		cci_dev->cci_clk, cci_dev->num_clk, false);
+reg_enable_failed:
+	msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg,
+		cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0);
+clk_enable_failed:
+	if (cci_dev->cci_pinctrl_status) {
+		ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl,
+				cci_dev->cci_pinctrl.gpio_state_suspend);
+		if (ret)
+			pr_err("%s:%d cannot set pin to suspend state\n",
+				__func__, __LINE__);
+	}
+	msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+		cci_dev->cci_gpio_tbl_size, 0);
+request_gpio_failed:
+	cci_dev->ref_count--;
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return rc;
+}
+
+static int32_t msm_cci_release(struct v4l2_subdev *sd)
+{
+	int32_t rc = 0;
+	uint8_t i = 0;
+	struct cci_device *cci_dev;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) {
+		pr_err("%s invalid ref count %d / cci state %d\n",
+			__func__, cci_dev->ref_count, cci_dev->cci_state);
+		rc = -EINVAL;
+		goto ahb_vote_suspend;
+	}
+	if (--cci_dev->ref_count) {
+		CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
+		rc = 0;
+		goto ahb_vote_suspend;
+	}
+	for (i = 0; i < MASTER_MAX; i++)
+		if (cci_dev->write_wq[i])
+			flush_workqueue(cci_dev->write_wq[i]);
+
+	msm_camera_enable_irq(cci_dev->irq, false);
+	msm_camera_clk_enable(&cci_dev->pdev->dev, cci_dev->cci_clk_info,
+		cci_dev->cci_clk, cci_dev->num_clk, false);
+
+	rc = msm_camera_enable_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg,
+		cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0);
+	if (rc < 0)
+		pr_err("%s:%d cci disable_vreg failed\n", __func__, __LINE__);
+
+	rc = msm_camera_config_vreg(&cci_dev->pdev->dev, cci_dev->cci_vreg,
+		cci_dev->regulator_count, NULL, 0, &cci_dev->cci_reg_ptr[0], 0);
+	if (rc < 0)
+		pr_err("%s:%d cci unconfig_vreg failed\n", __func__, __LINE__);
+
+	if (cci_dev->cci_pinctrl_status) {
+		rc = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl,
+				cci_dev->cci_pinctrl.gpio_state_suspend);
+		if (rc)
+			pr_err("%s:%d cannot set pin to active state\n",
+				__func__, __LINE__);
+	}
+	cci_dev->cci_pinctrl_status = 0;
+	msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+		cci_dev->cci_gpio_tbl_size, 0);
+	for (i = 0; i < MASTER_MAX; i++)
+		cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES;
+	cci_dev->cci_state = CCI_STATE_DISABLED;
+	cci_dev->cycles_per_us = 0;
+	cci_dev->cci_clk_src = 0;
+
+ahb_vote_suspend:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CCI,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return rc;
+}
+
+static int32_t msm_cci_write(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master;
+	struct msm_camera_cci_master_info *cci_master_info;
+	uint32_t i;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s:%d failed: invalid params %pK %pK\n", __func__,
+			__LINE__, cci_dev, c_ctrl);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	if (cci_dev->cci_state != CCI_STATE_ENABLED) {
+		pr_err("%s invalid cci state %d\n",
+			__func__, cci_dev->cci_state);
+		return -EINVAL;
+	}
+
+	if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX
+			|| c_ctrl->cci_info->cci_i2c_master < 0) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	master = c_ctrl->cci_info->cci_i2c_master;
+	cci_master_info = &cci_dev->cci_master_info[master];
+
+	switch (c_ctrl->cmd) {
+	case MSM_CCI_I2C_WRITE_SYNC_BLOCK:
+		mutex_lock(&cci_master_info->mutex_q[SYNC_QUEUE]);
+		rc = msm_cci_i2c_write(sd, c_ctrl,
+			SYNC_QUEUE, MSM_SYNC_ENABLE);
+		mutex_unlock(&cci_master_info->mutex_q[SYNC_QUEUE]);
+		break;
+	case MSM_CCI_I2C_WRITE_SYNC:
+		rc = msm_cci_i2c_write_async(sd, c_ctrl,
+			SYNC_QUEUE, MSM_SYNC_ENABLE);
+		break;
+	case MSM_CCI_I2C_WRITE:
+	case MSM_CCI_I2C_WRITE_SEQ:
+		for (i = 0; i < NUM_QUEUES; i++) {
+			if (mutex_trylock(&cci_master_info->mutex_q[i])) {
+				rc = msm_cci_i2c_write(sd, c_ctrl, i,
+					MSM_SYNC_DISABLE);
+				mutex_unlock(&cci_master_info->mutex_q[i]);
+				return rc;
+			}
+		}
+		mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]);
+		rc = msm_cci_i2c_write(sd, c_ctrl,
+			PRIORITY_QUEUE, MSM_SYNC_DISABLE);
+		mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]);
+		break;
+	case MSM_CCI_I2C_WRITE_ASYNC:
+		rc = msm_cci_i2c_write_async(sd, c_ctrl,
+			PRIORITY_QUEUE, MSM_SYNC_DISABLE);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+	return rc;
+}
+
+static int32_t msm_cci_config(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *cci_ctrl)
+{
+	int32_t rc = 0;
+
+	CDBG("%s line %d cmd %d\n", __func__, __LINE__,
+		cci_ctrl->cmd);
+	switch (cci_ctrl->cmd) {
+	case MSM_CCI_INIT:
+		rc = msm_cci_init(sd, cci_ctrl);
+		break;
+	case MSM_CCI_RELEASE:
+		rc = msm_cci_release(sd);
+		break;
+	case MSM_CCI_I2C_READ:
+		rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
+		break;
+	case MSM_CCI_I2C_WRITE:
+	case MSM_CCI_I2C_WRITE_SEQ:
+	case MSM_CCI_I2C_WRITE_SYNC:
+	case MSM_CCI_I2C_WRITE_ASYNC:
+	case MSM_CCI_I2C_WRITE_SYNC_BLOCK:
+		rc = msm_cci_write(sd, cci_ctrl);
+		break;
+	case MSM_CCI_GPIO_WRITE:
+		break;
+	case MSM_CCI_SET_SYNC_CID:
+		rc = msm_cci_i2c_set_sync_prms(sd, cci_ctrl);
+		break;
+
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+	CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
+	cci_ctrl->status = rc;
+	return rc;
+}
+
+static irqreturn_t msm_cci_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	unsigned long flags;
+	struct cci_device *cci_dev = data;
+
+	irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
+	msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+	msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+	CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq);
+	if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) {
+		if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) {
+			cci_dev->cci_master_info[MASTER_0].reset_pending =
+				FALSE;
+			complete(&cci_dev->cci_master_info[MASTER_0].
+				reset_complete);
+		}
+		if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) {
+			cci_dev->cci_master_info[MASTER_1].reset_pending =
+				FALSE;
+			complete(&cci_dev->cci_master_info[MASTER_1].
+				reset_complete);
+		}
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) {
+		cci_dev->cci_master_info[MASTER_0].status = 0;
+		complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) {
+		struct msm_camera_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
+						lock_q[QUEUE_0], flags);
+		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
+		cci_master_info->status = 0;
+		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
+			complete(&cci_master_info->report_q[QUEUE_0]);
+			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
+		}
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
+					lock_q[QUEUE_0], flags);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) {
+		struct msm_camera_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
+						lock_q[QUEUE_1], flags);
+		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
+		cci_master_info->status = 0;
+		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
+			complete(&cci_master_info->report_q[QUEUE_1]);
+			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
+		}
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
+						lock_q[QUEUE_1], flags);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
+		cci_dev->cci_master_info[MASTER_1].status = 0;
+		complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) {
+		struct msm_camera_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
+						lock_q[QUEUE_0], flags);
+		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
+		cci_master_info->status = 0;
+		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
+			complete(&cci_master_info->report_q[QUEUE_0]);
+			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
+		}
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
+						lock_q[QUEUE_0], flags);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) {
+		struct msm_camera_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
+						lock_q[QUEUE_1], flags);
+		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
+		cci_master_info->status = 0;
+		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
+			complete(&cci_master_info->report_q[QUEUE_1]);
+			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
+		}
+		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
+						lock_q[QUEUE_1], flags);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
+		cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
+		msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+			cci_dev->base + CCI_RESET_CMD_ADDR);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) {
+		cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
+		msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+			cci_dev->base + CCI_RESET_CMD_ADDR);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
+		pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq);
+		cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
+		msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK,
+			cci_dev->base + CCI_HALT_REQ_ADDR);
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
+		pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq);
+		cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
+		msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK,
+			cci_dev->base + CCI_HALT_REQ_ADDR);
+	}
+	return IRQ_HANDLED;
+}
+
+static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status,
+	bool *handled)
+{
+	struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+
+	CDBG("%s line %d\n", __func__, __LINE__);
+	ret = msm_cci_irq(cci_dev->irq->start, cci_dev);
+	CDBG("%s: msm_cci_irq return %d\n", __func__, ret);
+	*handled = TRUE;
+	return 0;
+}
+
+static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+
+	CDBG("%s line %d\n", __func__, __LINE__);
+	switch (cmd) {
+	case VIDIOC_MSM_CCI_CFG:
+		rc = msm_cci_config(sd, arg);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		break;
+	case MSM_SD_SHUTDOWN: {
+		struct msm_camera_cci_ctrl ctrl_cmd;
+
+		ctrl_cmd.cmd = MSM_CCI_RELEASE;
+		rc = msm_cci_config(sd, &ctrl_cmd);
+		break;
+	}
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+	CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = {
+	.ioctl = &msm_cci_subdev_ioctl,
+	.interrupt_service_routine = msm_cci_irq_routine,
+};
+
+static const struct v4l2_subdev_ops msm_cci_subdev_ops = {
+	.core = &msm_cci_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_cci_internal_ops;
+
+static void msm_cci_init_cci_params(struct cci_device *new_cci_dev)
+{
+	uint8_t i = 0, j = 0;
+
+	for (i = 0; i < NUM_MASTERS; i++) {
+		new_cci_dev->cci_master_info[i].status = 0;
+		mutex_init(&new_cci_dev->cci_master_info[i].mutex);
+		init_completion(&new_cci_dev->
+			cci_master_info[i].reset_complete);
+
+		for (j = 0; j < NUM_QUEUES; j++) {
+			mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
+			init_completion(&new_cci_dev->
+				cci_master_info[i].report_q[j]);
+			spin_lock_init(&new_cci_dev->
+				cci_master_info[i].lock_q[j]);
+		}
+	}
+}
+
+static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev)
+{
+	int32_t rc = 0, i = 0;
+	uint32_t *val_array = NULL;
+	uint8_t tbl_size = 0;
+	struct device_node *of_node = cci_dev->pdev->dev.of_node;
+	struct gpio *gpio_tbl = NULL;
+
+	cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, tbl_size);
+	if (!tbl_size) {
+		pr_err("%s:%d gpio count 0\n", __func__, __LINE__);
+		return 0;
+	}
+
+	gpio_tbl = cci_dev->cci_gpio_tbl =
+		kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL);
+	if (!gpio_tbl) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return 0;
+	}
+
+	for (i = 0; i < tbl_size; i++) {
+		gpio_tbl[i].gpio = of_get_gpio(of_node, i);
+		CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i,
+			gpio_tbl[i].gpio);
+	}
+
+	val_array = kcalloc(tbl_size, sizeof(uint32_t), GFP_KERNEL);
+	if (!val_array) {
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags",
+		val_array, tbl_size);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < tbl_size; i++) {
+		gpio_tbl[i].flags = val_array[i];
+		CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i,
+			gpio_tbl[i].flags);
+	}
+
+	for (i = 0; i < tbl_size; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,gpio-tbl-label", i, &gpio_tbl[i].label);
+		CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i,
+			gpio_tbl[i].label);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		}
+	}
+
+	kfree(val_array);
+	return rc;
+
+ERROR2:
+	kfree(val_array);
+ERROR1:
+	kfree(cci_dev->cci_gpio_tbl);
+	cci_dev->cci_gpio_tbl = NULL;
+	cci_dev->cci_gpio_tbl_size = 0;
+	return rc;
+}
+
+static void msm_cci_init_default_clk_params(struct cci_device *cci_dev,
+	uint8_t index)
+{
+	/* default clock params are for 100Khz */
+	cci_dev->cci_clk_params[index].hw_thigh = 201;
+	cci_dev->cci_clk_params[index].hw_tlow = 174;
+	cci_dev->cci_clk_params[index].hw_tsu_sto = 204;
+	cci_dev->cci_clk_params[index].hw_tsu_sta = 231;
+	cci_dev->cci_clk_params[index].hw_thd_dat = 22;
+	cci_dev->cci_clk_params[index].hw_thd_sta = 162;
+	cci_dev->cci_clk_params[index].hw_tbuf = 227;
+	cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0;
+	cci_dev->cci_clk_params[index].hw_trdhld = 6;
+	cci_dev->cci_clk_params[index].hw_tsp = 3;
+	cci_dev->cci_clk_params[index].cci_clk_src = 37500000;
+}
+
+static void msm_cci_init_clk_params(struct cci_device *cci_dev)
+{
+	int32_t rc = 0;
+	uint32_t val = 0;
+	uint8_t count = 0;
+	struct device_node *of_node = cci_dev->pdev->dev.of_node;
+	struct device_node *src_node = NULL;
+
+	for (count = 0; count < I2C_MAX_MODES; count++) {
+
+		if (count == I2C_STANDARD_MODE)
+			src_node = of_find_node_by_name(of_node,
+				"qcom,i2c_standard_mode");
+		else if (count == I2C_FAST_MODE)
+			src_node = of_find_node_by_name(of_node,
+				"qcom,i2c_fast_mode");
+		else if (count == I2C_FAST_PLUS_MODE)
+			src_node = of_find_node_by_name(of_node,
+				"qcom,i2c_fast_plus_mode");
+		else
+			src_node = of_find_node_by_name(of_node,
+				"qcom,i2c_custom_mode");
+
+		rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val);
+		CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc);
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_thigh = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-tlow",
+				&val);
+			CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_tlow = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto",
+				&val);
+			CDBG("%s qcom,hw-tsu-sto %d, rc %d\n",
+				__func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_tsu_sto = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta",
+				&val);
+			CDBG("%s qcom,hw-tsu-sta %d, rc %d\n",
+				__func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_tsu_sta = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-thd-dat",
+				&val);
+			CDBG("%s qcom,hw-thd-dat %d, rc %d\n",
+				__func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_thd_dat = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-thd-sta",
+				&val);
+			CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__,
+				val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_thd_sta = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-tbuf",
+				&val);
+			CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_tbuf = val;
+			rc = of_property_read_u32(src_node,
+				"qcom,hw-scl-stretch-en", &val);
+			CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n",
+				__func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_scl_stretch_en = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-trdhld",
+				&val);
+			CDBG("%s qcom,hw-trdhld %d, rc %d\n",
+				__func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_trdhld = val;
+			rc = of_property_read_u32(src_node, "qcom,hw-tsp",
+				&val);
+			CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
+		}
+		if (!rc) {
+			cci_dev->cci_clk_params[count].hw_tsp = val;
+			val = 0;
+			rc = of_property_read_u32(src_node, "qcom,cci-clk-src",
+				&val);
+			CDBG("%s qcom,cci-clk-src %d, rc %d\n",
+				__func__, val, rc);
+			cci_dev->cci_clk_params[count].cci_clk_src = val;
+		} else {
+			msm_cci_init_default_clk_params(cci_dev, count);
+		}
+
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+}
+
+struct v4l2_subdev *msm_cci_get_subdev(void)
+{
+	return g_cci_subdev;
+}
+
+static int msm_cci_probe(struct platform_device *pdev)
+{
+	struct cci_device *new_cci_dev;
+	int rc = 0, i = 0;
+
+	CDBG("%s: pdev %pK device id = %d\n", __func__, pdev, pdev->id);
+	new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL);
+	if (!new_cci_dev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+	v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops);
+	snprintf(new_cci_dev->msm_sd.sd.name,
+			ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci");
+	v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev);
+	platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd);
+
+	CDBG("%s sd %pK\n", __func__, &new_cci_dev->msm_sd.sd);
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node,
+			"cell-index", &pdev->id);
+
+	rc = msm_camera_get_clk_info_and_rates(pdev,
+		&new_cci_dev->cci_clk_info, &new_cci_dev->cci_clk,
+		&new_cci_dev->cci_clk_rates, &new_cci_dev->num_clk_cases,
+		&new_cci_dev->num_clk);
+	if (rc < 0) {
+		pr_err("%s: msm_cci_get_clk_info() failed", __func__);
+		kfree(new_cci_dev);
+		return -EFAULT;
+	}
+
+	new_cci_dev->ref_count = 0;
+	new_cci_dev->base = msm_camera_get_reg_base(pdev, "cci", true);
+	if (!new_cci_dev->base) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto cci_no_resource;
+	}
+	new_cci_dev->irq = msm_camera_get_irq(pdev, "cci");
+	if (!new_cci_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto cci_no_resource;
+	}
+	CDBG("%s line %d cci irq start %d end %d\n", __func__,
+		__LINE__,
+		(int) new_cci_dev->irq->start,
+		(int) new_cci_dev->irq->end);
+	rc = msm_camera_register_irq(pdev, new_cci_dev->irq,
+		msm_cci_irq, IRQF_TRIGGER_RISING, "cci", new_cci_dev);
+	if (rc < 0) {
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto cci_release_mem;
+	}
+
+	msm_camera_enable_irq(new_cci_dev->irq, false);
+
+	new_cci_dev->pdev = pdev;
+	new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops;
+	new_cci_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&new_cci_dev->msm_sd.sd.entity, 0, NULL);
+	new_cci_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CCI;
+	new_cci_dev->msm_sd.sd.entity.name = new_cci_dev->msm_sd.sd.name;
+	new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
+	msm_sd_register(&new_cci_dev->msm_sd);
+	new_cci_dev->pdev = pdev;
+	msm_cci_init_cci_params(new_cci_dev);
+	msm_cci_init_clk_params(new_cci_dev);
+	msm_cci_init_gpio_params(new_cci_dev);
+
+	rc = msm_camera_get_dt_vreg_data(new_cci_dev->pdev->dev.of_node,
+		&(new_cci_dev->cci_vreg), &(new_cci_dev->regulator_count));
+	if (rc < 0) {
+		pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__);
+		rc = -EFAULT;
+		goto cci_release_mem;
+	}
+
+	if ((new_cci_dev->regulator_count < 0) ||
+		(new_cci_dev->regulator_count > MAX_REGULATOR)) {
+		pr_err("%s: invalid reg count = %d, max is %d\n", __func__,
+			new_cci_dev->regulator_count, MAX_REGULATOR);
+		rc = -EFAULT;
+		goto cci_invalid_vreg_data;
+	}
+
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (rc)
+		pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc);
+	new_cci_dev->cci_state = CCI_STATE_DISABLED;
+	g_cci_subdev = &new_cci_dev->msm_sd.sd;
+	for (i = 0; i < MASTER_MAX; i++) {
+		new_cci_dev->write_wq[i] = create_singlethread_workqueue(
+								"msm_cci_wq");
+		if (!new_cci_dev->write_wq[i])
+			pr_err("Failed to create write wq\n");
+	}
+	CDBG("%s cci subdev %pK\n", __func__, &new_cci_dev->msm_sd.sd);
+	CDBG("%s line %d\n", __func__, __LINE__);
+	return 0;
+
+cci_invalid_vreg_data:
+	kfree(new_cci_dev->cci_vreg);
+cci_release_mem:
+	msm_camera_put_reg_base(pdev, new_cci_dev->base, "cci", true);
+cci_no_resource:
+	kfree(new_cci_dev);
+	return rc;
+}
+
+static int msm_cci_exit(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct cci_device *cci_dev =
+		v4l2_get_subdevdata(subdev);
+
+	msm_camera_put_clk_info_and_rates(pdev,
+		&cci_dev->cci_clk_info, &cci_dev->cci_clk,
+		&cci_dev->cci_clk_rates, cci_dev->num_clk_cases,
+		cci_dev->num_clk);
+
+	msm_camera_put_reg_base(pdev, cci_dev->base, "cci", true);
+	kfree(cci_dev);
+	return 0;
+}
+
+static const struct of_device_id msm_cci_dt_match[] = {
+	{.compatible = "qcom,cci"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_cci_dt_match);
+
+static struct platform_driver cci_driver = {
+	.probe = msm_cci_probe,
+	.remove = msm_cci_exit,
+	.driver = {
+		.name = MSM_CCI_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cci_dt_match,
+	},
+};
+
+static int __init msm_cci_init_module(void)
+{
+	return platform_driver_register(&cci_driver);
+}
+
+static void __exit msm_cci_exit_module(void)
+{
+	platform_driver_unregister(&cci_driver);
+}
+
+module_init(msm_cci_init_module);
+module_exit(msm_cci_exit_module);
+MODULE_DESCRIPTION("MSM CCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
new file mode 100644
index 0000000..c997ca9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -0,0 +1,239 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CCI_H
+#define MSM_CCI_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/workqueue.h>
+#include <media/msm_cam_sensor.h>
+#include <soc/qcom/camera2.h>
+#include "msm_sd.h"
+#include "cam_soc_api.h"
+
+#define NUM_MASTERS 2
+#define NUM_QUEUES 2
+
+#define TRUE  1
+#define FALSE 0
+
+#define CCI_PINCTRL_STATE_DEFAULT "cci_default"
+#define CCI_PINCTRL_STATE_SLEEP "cci_suspend"
+
+#define CCI_NUM_CLK_MAX	16
+#define CCI_NUM_CLK_CASES 5
+#define CCI_CLK_SRC_NAME "cci_src_clk"
+#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10 10
+#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11
+#define BURST_MIN_FREE_SIZE 8
+
+enum cci_i2c_sync {
+	MSM_SYNC_DISABLE,
+	MSM_SYNC_ENABLE,
+};
+
+enum cci_i2c_queue_t {
+	QUEUE_0,
+	QUEUE_1,
+	QUEUE_INVALID,
+};
+
+struct msm_camera_cci_client {
+	struct v4l2_subdev *cci_subdev;
+	uint32_t freq;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum cci_i2c_master_t cci_i2c_master;
+	uint16_t sid;
+	uint16_t cid;
+	uint32_t timeout;
+	uint16_t retries;
+	uint16_t id_map;
+};
+
+enum msm_cci_cmd_type {
+	MSM_CCI_INIT,
+	MSM_CCI_RELEASE,
+	MSM_CCI_SET_SID,
+	MSM_CCI_SET_FREQ,
+	MSM_CCI_SET_SYNC_CID,
+	MSM_CCI_I2C_READ,
+	MSM_CCI_I2C_WRITE,
+	MSM_CCI_I2C_WRITE_SEQ,
+	MSM_CCI_I2C_WRITE_ASYNC,
+	MSM_CCI_GPIO_WRITE,
+	MSM_CCI_I2C_WRITE_SYNC,
+	MSM_CCI_I2C_WRITE_SYNC_BLOCK,
+};
+
+struct msm_camera_cci_wait_sync_cfg {
+	uint16_t cid;
+	int16_t csid;
+	uint16_t line;
+	uint16_t delay;
+};
+
+struct msm_camera_cci_gpio_cfg {
+	uint16_t gpio_queue;
+	uint16_t i2c_queue;
+};
+
+struct msm_camera_cci_i2c_read_cfg {
+	uint32_t addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	uint8_t *data;
+	uint16_t num_byte;
+};
+
+struct msm_camera_cci_i2c_queue_info {
+	uint32_t max_queue_size;
+	uint32_t report_id;
+	uint32_t irq_en;
+	uint32_t capture_rep_data;
+};
+
+struct msm_camera_cci_ctrl {
+	int32_t status;
+	struct msm_camera_cci_client *cci_info;
+	enum msm_cci_cmd_type cmd;
+	union {
+		struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
+		struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
+		struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
+		struct msm_camera_cci_gpio_cfg gpio_cfg;
+	} cfg;
+};
+
+struct msm_camera_cci_master_info {
+	uint32_t status;
+	atomic_t q_free[NUM_QUEUES];
+	uint8_t q_lock[NUM_QUEUES];
+	uint8_t reset_pending;
+	struct mutex mutex;
+	struct completion reset_complete;
+	struct mutex mutex_q[NUM_QUEUES];
+	struct completion report_q[NUM_QUEUES];
+	atomic_t done_pending[NUM_QUEUES];
+	spinlock_t lock_q[NUM_QUEUES];
+};
+
+struct msm_cci_clk_params_t {
+	uint16_t hw_thigh;
+	uint16_t hw_tlow;
+	uint16_t hw_tsu_sto;
+	uint16_t hw_tsu_sta;
+	uint16_t hw_thd_dat;
+	uint16_t hw_thd_sta;
+	uint16_t hw_tbuf;
+	uint8_t hw_scl_stretch_en;
+	uint8_t hw_trdhld;
+	uint8_t hw_tsp;
+	uint32_t cci_clk_src;
+};
+
+enum msm_cci_state_t {
+	CCI_STATE_ENABLED,
+	CCI_STATE_DISABLED,
+};
+
+struct cci_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *irq;
+	void __iomem *base;
+
+	uint32_t hw_version;
+	uint8_t ref_count;
+	enum msm_cci_state_t cci_state;
+	size_t num_clk;
+	size_t num_clk_cases;
+	struct clk **cci_clk;
+	uint32_t **cci_clk_rates;
+	struct msm_cam_clk_info *cci_clk_info;
+	struct msm_camera_cci_i2c_queue_info
+		cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
+	struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS];
+	enum i2c_freq_mode_t i2c_freq_mode[NUM_MASTERS];
+	struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES];
+	struct gpio *cci_gpio_tbl;
+	uint8_t cci_gpio_tbl_size;
+	struct msm_pinctrl_info cci_pinctrl;
+	uint8_t cci_pinctrl_status;
+	uint32_t cycles_per_us;
+	uint32_t cci_clk_src;
+	struct camera_vreg_t *cci_vreg;
+	struct regulator *cci_reg_ptr[MAX_REGULATOR];
+	int32_t regulator_count;
+	uint8_t payload_size;
+	uint8_t support_seq_write;
+	struct workqueue_struct *write_wq[MASTER_MAX];
+	struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
+	uint8_t valid_sync;
+};
+
+enum msm_cci_i2c_cmd_type {
+	CCI_I2C_SET_PARAM_CMD = 1,
+	CCI_I2C_WAIT_CMD,
+	CCI_I2C_WAIT_SYNC_CMD,
+	CCI_I2C_WAIT_GPIO_EVENT_CMD,
+	CCI_I2C_TRIG_I2C_EVENT_CMD,
+	CCI_I2C_LOCK_CMD,
+	CCI_I2C_UNLOCK_CMD,
+	CCI_I2C_REPORT_CMD,
+	CCI_I2C_WRITE_CMD,
+	CCI_I2C_READ_CMD,
+	CCI_I2C_WRITE_DISABLE_P_CMD,
+	CCI_I2C_READ_DISABLE_P_CMD,
+	CCI_I2C_WRITE_CMD2,
+	CCI_I2C_WRITE_CMD3,
+	CCI_I2C_REPEAT_CMD,
+	CCI_I2C_INVALID_CMD,
+};
+
+enum msm_cci_gpio_cmd_type {
+	CCI_GPIO_SET_PARAM_CMD = 1,
+	CCI_GPIO_WAIT_CMD,
+	CCI_GPIO_WAIT_SYNC_CMD,
+	CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
+	CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
+	CCI_GPIO_OUT_CMD,
+	CCI_GPIO_TRIG_EVENT_CMD,
+	CCI_GPIO_REPORT_CMD,
+	CCI_GPIO_REPEAT_CMD,
+	CCI_GPIO_CONTINUE_CMD,
+	CCI_GPIO_INVALID_CMD,
+};
+
+struct cci_write_async {
+	struct cci_device *cci_dev;
+	struct msm_camera_cci_ctrl c_ctrl;
+	enum cci_i2c_queue_t queue;
+	struct work_struct work;
+	enum cci_i2c_sync sync_en;
+};
+
+#ifdef CONFIG_MSM_CCI
+struct v4l2_subdev *msm_cci_get_subdev(void);
+#else
+static inline struct v4l2_subdev *msm_cci_get_subdev(void)
+{
+	return NULL;
+}
+#endif
+
+#define VIDIOC_MSM_CCI_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *)
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
new file mode 100644
index 0000000..c51555d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSM_CSID) += msm_csid.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_0_hwreg.h
new file mode 100644
index 0000000..3bd444c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_0_hwreg.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_2_0_HWREG_H
+#define MSM_CSID_2_0_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v2_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v2_0 = {
+
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x4,
+	0x8,
+	0xc,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x5c,
+	0x60,
+	0x64,
+	0x68,
+	0x6c,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x9C,
+	0xA0,
+	0xA8,
+	0xAC,
+	0xB0,
+	11,
+	0x7FFF,
+	0x2,
+	17,
+	0x02000011,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_2_hwreg.h
new file mode 100644
index 0000000..697ae4c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_2_2_hwreg.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_2_2_HWREG_H
+#define MSM_CSID_2_2_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v2_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v2_2 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x4,
+	0x8,
+	0xc,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x5c,
+	0x60,
+	0x64,
+	0x68,
+	0x6c,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x9C,
+	0xA0,
+	0xA8,
+	0xAC,
+	0xB0,
+	11,
+	0x7FFF,
+	0x2,
+	17,
+	0x02001000,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_0_hwreg.h
new file mode 100644
index 0000000..4d5378d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_0_hwreg.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_0_HWREG_H
+#define MSM_CSID_3_0_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v3_0 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30000000,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_1_hwreg.h
new file mode 100644
index 0000000..952434e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_1_hwreg.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_1_HWREG_H
+#define MSM_CSID_3_1_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v3_1 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30010000,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_2_hwreg.h
new file mode 100644
index 0000000..f6bf2f0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_2_hwreg.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_2_HWREG_H
+#define MSM_CSID_3_2_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v3_2 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30020000,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_1_hwreg.h
new file mode 100644
index 0000000..bddcc74
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_1_hwreg.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_4_1_HWREG_H
+#define MSM_CSID_3_4_1_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+static uint8_t csid_lane_assign_v3_4_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+
+static struct csid_reg_parms_t csid_v3_4_1 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30040001,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_2_hwreg.h
new file mode 100644
index 0000000..b829db6
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_2_hwreg.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_4_2_HWREG_H
+#define MSM_CSID_3_4_2_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_4_2[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
+static struct csid_reg_parms_t csid_v3_4_2 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30040002,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h
new file mode 100644
index 0000000..8c48c6d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_1_hwreg.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_5_1_HWREG_H
+#define MSM_CSID_3_5_1_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_5_1[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
+
+static struct csid_reg_parms_t csid_v3_5_1 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x24,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0x9C,
+	0xA0,
+	0xA8,
+	0xAC,
+	0xB4,
+	0xB8,
+	0xBC,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30050001,
+	0xC,
+	0x84,
+	0xA4,
+	0x7f010800,
+	20,
+	17,
+	16,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h
new file mode 100644
index 0000000..d5463443
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_5_HWREG_H
+#define MSM_CSID_3_5_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_5[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
+
+static struct csid_reg_parms_t csid_v3_5 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x24,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0x9C,
+	0xA0,
+	0xA8,
+	0xAC,
+	0xB4,
+	0xB8,
+	0xBC,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30050000,
+	0xC,
+	0x84,
+	0xA4,
+	0x7f010800,
+	20,
+	17,
+	16,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_6_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_6_0_hwreg.h
new file mode 100644
index 0000000..b568a91
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_6_0_hwreg.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_3_6_0_HWREG_H
+#define MSM_CSID_3_6_0_HWREG_H
+
+#include <sensor/csid/msm_csid.h>
+
+static uint8_t csid_lane_assign_v3_6_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
+static struct csid_reg_parms_t csid_v3_6_0 = {
+	/* MIPI	CSID registers */
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x14,
+	0x18,
+	0x1C,
+	0x20,
+	0x60,
+	0x64,
+	0x68,
+	0x6C,
+	0x70,
+	0x74,
+	0x78,
+	0x7C,
+	0x80,
+	0x84,
+	0x88,
+	0x8C,
+	0x90,
+	0x94,
+	0x98,
+	0xA0,
+	0xA4,
+	0xAC,
+	0xB0,
+	0xB4,
+	11,
+	0x7FFF,
+	0x4,
+	17,
+	0x30060000,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+	0x7f010800,
+	20,
+	0xFFFFFFFF,
+	0xFFFFFFFF,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
new file mode 100644
index 0000000..ba32526
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -0,0 +1,1253 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/irqreturn.h>
+#include "msm_csid.h"
+#include "msm_sd.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+#include "include/msm_csid_2_0_hwreg.h"
+#include "include/msm_csid_2_2_hwreg.h"
+#include "include/msm_csid_3_0_hwreg.h"
+#include "include/msm_csid_3_1_hwreg.h"
+#include "include/msm_csid_3_2_hwreg.h"
+#include "include/msm_csid_3_5_hwreg.h"
+#include "include/msm_csid_3_4_1_hwreg.h"
+#include "include/msm_csid_3_4_2_hwreg.h"
+#include "include/msm_csid_3_6_0_hwreg.h"
+#include "include/msm_csid_3_5_1_hwreg.h"
+#include "cam_hw_ops.h"
+
+#define V4L2_IDENT_CSID                            50002
+#define CSID_VERSION_V20                      0x02000011
+#define CSID_VERSION_V22                      0x02001000
+#define CSID_VERSION_V30                      0x30000000
+#define CSID_VERSION_V31                      0x30010000
+#define CSID_VERSION_V31_1                    0x30010001
+#define CSID_VERSION_V31_3                    0x30010003
+#define CSID_VERSION_V32                      0x30020000
+#define CSID_VERSION_V33                      0x30030000
+#define CSID_VERSION_V34                      0x30040000
+#define CSID_VERSION_V34_1                    0x30040001
+#define CSID_VERSION_V34_2                    0x30040002
+#define CSID_VERSION_V36                      0x30060000
+#define CSID_VERSION_V37                      0x30070000
+#define CSID_VERSION_V35                      0x30050000
+#define CSID_VERSION_V35_1                    0x30050001
+#define CSID_VERSION_V40                      0x40000000
+#define CSID_VERSION_V50                      0x50000000
+#define MSM_CSID_DRV_NAME                    "msm_csid"
+
+#define DBG_CSID                             0
+#define SHORT_PKT_CAPTURE                    0
+#define SHORT_PKT_OFFSET                     0x200
+#define ENABLE_3P_BIT                        1
+#define SOF_DEBUG_ENABLE                     1
+#define SOF_DEBUG_DISABLE                    0
+
+#define TRUE   1
+#define FALSE  0
+
+#define MAX_LANE_COUNT 4
+#define CSID_TIMEOUT msecs_to_jiffies(100)
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static struct camera_vreg_t csid_vreg_info[] = {
+	{"qcom,mipi-csi-vdd", 0, 0, 12000},
+};
+
+#ifdef CONFIG_COMPAT
+static struct v4l2_file_operations msm_csid_v4l2_subdev_fops;
+#endif
+
+static int msm_csid_cid_lut(
+	struct msm_camera_csid_lut_params *csid_lut_params,
+	struct csid_device *csid_dev)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0;
+
+	if (!csid_lut_params) {
+		pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (csid_lut_params->num_cid > MAX_CID) {
+		pr_err("%s:%d num_cid exceeded limit num_cid = %d max = %d\n",
+			__func__, __LINE__, csid_lut_params->num_cid, MAX_CID);
+		return -EINVAL;
+	}
+	for (i = 0; i < csid_lut_params->num_cid; i++) {
+		if (csid_lut_params->vc_cfg[i]->cid >= MAX_CID) {
+			pr_err("%s: cid outside range %d\n",
+				 __func__, csid_lut_params->vc_cfg[i]->cid);
+			return -EINVAL;
+		}
+		CDBG("%s lut params num_cid = %d, cid = %d\n",
+			__func__,
+			csid_lut_params->num_cid,
+			csid_lut_params->vc_cfg[i]->cid);
+		CDBG("%s lut params dt = 0x%x, df = %d\n", __func__,
+			csid_lut_params->vc_cfg[i]->dt,
+			csid_lut_params->vc_cfg[i]->decode_format);
+		if (csid_lut_params->vc_cfg[i]->dt < 0x12 ||
+			csid_lut_params->vc_cfg[i]->dt > 0x37) {
+			pr_err("%s: unsupported data type 0x%x\n",
+				 __func__, csid_lut_params->vc_cfg[i]->dt);
+			return rc;
+		}
+		val = msm_camera_io_r(csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr +
+			(csid_lut_params->vc_cfg[i]->cid >> 2) * 4)
+			& ~(0xFF << ((csid_lut_params->vc_cfg[i]->cid % 4) *
+			8));
+		val |= (csid_lut_params->vc_cfg[i]->dt <<
+			((csid_lut_params->vc_cfg[i]->cid % 4) * 8));
+		msm_camera_io_w(val, csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr +
+			(csid_lut_params->vc_cfg[i]->cid >> 2) * 4);
+
+		val = (csid_lut_params->vc_cfg[i]->decode_format << 4) | 0x3;
+		msm_camera_io_w(val, csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr +
+			(csid_lut_params->vc_cfg[i]->cid * 4));
+	}
+	return rc;
+}
+
+#if (DBG_CSID)
+static void msm_csid_set_debug_reg(struct csid_device *csid_dev,
+	struct msm_camera_csid_params *csid_params)
+{
+	uint32_t val = 0;
+
+	if ((csid_dev->hw_dts_version == CSID_VERSION_V34_1) ||
+		(csid_dev->hw_dts_version == CSID_VERSION_V36)) {
+		val = ((1 << csid_params->lane_cnt) - 1) << 20;
+		msm_camera_io_w(0x7f010800 | val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+		msm_camera_io_w(0x7f010800 | val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	} else {
+		if (csid_dev->csid_3p_enabled == 1) {
+			val = ((1 << csid_params->lane_cnt) - 1) <<
+				csid_dev->ctrl_reg->
+				csid_reg.csid_err_lane_overflow_offset_3p;
+		} else {
+			val = ((1 << csid_params->lane_cnt) - 1) <<
+				csid_dev->ctrl_reg->
+				csid_reg.csid_err_lane_overflow_offset_2p;
+		}
+		val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val;
+		msm_camera_io_w(val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+		msm_camera_io_w(val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	}
+}
+#elif(SHORT_PKT_CAPTURE)
+static void msm_csid_set_debug_reg(struct csid_device *csid_dev,
+	struct msm_camera_csid_params *csid_params)
+{
+	uint32_t val = 0;
+
+	if ((csid_dev->hw_dts_version == CSID_VERSION_V34_1) ||
+		(csid_dev->hw_dts_version == CSID_VERSION_V36)) {
+		val = ((1 << csid_params->lane_cnt) - 1) << 20;
+		msm_camera_io_w(0x7f010a00 | val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+		msm_camera_io_w(0x7f010a00 | val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	} else {
+		if (csid_dev->csid_3p_enabled == 1) {
+			val = ((1 << csid_params->lane_cnt) - 1) <<
+				csid_dev->ctrl_reg->
+				csid_reg.csid_err_lane_overflow_offset_3p;
+		} else {
+			val = ((1 << csid_params->lane_cnt) - 1) <<
+				csid_dev->ctrl_reg->
+				csid_reg.csid_err_lane_overflow_offset_2p;
+		}
+		val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val;
+		val |= SHORT_PKT_OFFSET;
+		msm_camera_io_w(val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+		msm_camera_io_w(val, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	}
+}
+#else
+static void msm_csid_set_debug_reg(struct csid_device *csid_dev,
+	struct msm_camera_csid_params *csid_params) {}
+#endif
+
+static void msm_csid_set_sof_freeze_debug_reg(
+	struct csid_device *csid_dev, uint8_t irq_enable)
+{
+	uint32_t val = 0;
+
+	if (!irq_enable) {
+		val = msm_camera_io_r(csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+		msm_camera_io_w(val, csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+		msm_camera_io_w(0, csid_dev->base +
+			csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+		return;
+	}
+
+	if (csid_dev->csid_3p_enabled == 1) {
+		val = ((1 << csid_dev->current_csid_params.lane_cnt) - 1) <<
+			csid_dev->ctrl_reg->
+			csid_reg.csid_err_lane_overflow_offset_3p;
+	} else {
+		val = ((1 << csid_dev->current_csid_params.lane_cnt) - 1) <<
+			csid_dev->ctrl_reg->
+			csid_reg.csid_err_lane_overflow_offset_2p;
+	}
+	val |= csid_dev->ctrl_reg->csid_reg.csid_irq_mask_val;
+	val |= SHORT_PKT_OFFSET;
+	msm_camera_io_w(val, csid_dev->base +
+	csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+	msm_camera_io_w(val, csid_dev->base +
+	csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+}
+
+static int msm_csid_reset(struct csid_device *csid_dev)
+{
+	int32_t rc = 0;
+
+	msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all,
+		csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr);
+	rc = wait_for_completion_timeout(&csid_dev->reset_complete,
+		CSID_TIMEOUT);
+	if (rc < 0) {
+		pr_err("wait_for_completion in msm_csid_reset fail rc = %d\n",
+			rc);
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+	}
+	return rc;
+}
+
+static bool msm_csid_find_max_clk_rate(struct csid_device *csid_dev)
+{
+	int i;
+	bool ret = FALSE;
+
+	for (i = 0; i < csid_dev->num_clk; i++) {
+		if (!strcmp(csid_dev->csid_clk_info[i].clk_name,
+			 "csi_src_clk")) {
+			CDBG("%s:%d, copy csi_src_clk, clk_rate[%d] = %ld",
+				__func__, __LINE__, i,
+				csid_dev->csid_clk_info[i].clk_rate);
+			csid_dev->csid_max_clk =
+				 csid_dev->csid_clk_info[i].clk_rate;
+			csid_dev->csid_clk_index = i;
+			ret = TRUE;
+			break;
+		}
+	}
+	return ret;
+}
+static int msm_csid_config(struct csid_device *csid_dev,
+	struct msm_camera_csid_params *csid_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	long clk_rate = 0;
+	uint32_t input_sel;
+	uint32_t lane_assign = 0;
+	uint8_t  lane_num = 0;
+	uint8_t  i, j;
+	void __iomem *csidbase;
+
+	csidbase = csid_dev->base;
+	if (!csidbase || !csid_params) {
+		pr_err("%s:%d csidbase %pK, csid params %pK\n", __func__,
+			__LINE__, csidbase, csid_params);
+		return -EINVAL;
+	}
+
+	CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n",
+		__func__,
+		csid_params->lane_cnt,
+		csid_params->lane_assign);
+	CDBG("%s csid_params phy_sel = %d\n", __func__,
+		csid_params->phy_sel);
+	if ((csid_params->lane_cnt == 0) ||
+		(csid_params->lane_cnt > MAX_LANE_COUNT)) {
+		pr_err("%s:%d invalid lane count = %d\n",
+			__func__, __LINE__, csid_params->lane_cnt);
+		return -EINVAL;
+	}
+
+	csid_dev->csid_lane_cnt = csid_params->lane_cnt;
+	rc = msm_csid_reset(csid_dev);
+	if (rc < 0) {
+		pr_err("%s:%d msm_csid_reset failed\n", __func__, __LINE__);
+		return rc;
+	}
+
+	if (!msm_csid_find_max_clk_rate(csid_dev))
+		pr_err("msm_csid_find_max_clk_rate failed\n");
+
+	clk_rate = (csid_params->csi_clk > 0) ?
+				(csid_params->csi_clk) : csid_dev->csid_max_clk;
+
+	clk_rate = msm_camera_clk_set_rate(&csid_dev->pdev->dev,
+		csid_dev->csid_clk[csid_dev->csid_clk_index], clk_rate);
+	if (clk_rate < 0) {
+		pr_err("csi_src_clk set failed\n");
+		return -EINVAL;
+	}
+
+	if (csid_dev->is_testmode == 1) {
+		struct msm_camera_csid_testmode_parms *tm;
+
+		tm = &csid_dev->testmode_params;
+
+		/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT, 1:0 VC */
+		val = ((tm->v_blanking_count & 0xFF) << 24) |
+			((tm->h_blanking_count & 0x7FF) << 13);
+		msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_tg_vc_cfg_addr);
+		CDBG("[TG] CSID_TG_VC_CFG_ADDR 0x%08x\n", val);
+
+		/* 28:16 bytes per lines, 12:0 num of lines */
+		val = ((tm->num_bytes_per_line & 0x1FFF) << 16) |
+			(tm->num_lines & 0x1FFF);
+		msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_0_addr);
+		CDBG("[TG] CSID_TG_DT_n_CFG_0_ADDR 0x%08x\n", val);
+
+		/* 5:0 data type */
+		val = csid_params->lut_params.vc_cfg[0]->dt;
+		msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_1_addr);
+		CDBG("[TG] CSID_TG_DT_n_CFG_1_ADDR 0x%08x\n", val);
+
+		/* 2:0 output random */
+		msm_camera_io_w(csid_dev->testmode_params.payload_mode,
+			csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_tg_dt_n_cfg_2_addr);
+	} else {
+		val = csid_params->lane_cnt - 1;
+
+		for (i = 0, j = 0; i < PHY_LANE_MAX; i++) {
+			if (i == PHY_LANE_CLK)
+				continue;
+			lane_num = (csid_params->lane_assign >> j) & 0xF;
+			if (lane_num >= PHY_LANE_MAX) {
+				pr_err("%s:%d invalid lane number %d\n",
+					__func__, __LINE__, lane_num);
+				return -EINVAL;
+			}
+			if (csid_dev->ctrl_reg->csid_lane_assign[lane_num] >=
+				PHY_LANE_MAX){
+				pr_err("%s:%d invalid lane map %d\n",
+					__func__, __LINE__,
+					csid_dev->ctrl_reg->
+					csid_lane_assign[lane_num]);
+				return -EINVAL;
+			}
+			lane_assign |=
+				csid_dev->ctrl_reg->csid_lane_assign[lane_num]
+				<< j;
+			j += 4;
+		}
+
+		CDBG("%s csid_params calculated lane_assign = 0x%X\n",
+			__func__, lane_assign);
+
+		val |= lane_assign <<
+			csid_dev->ctrl_reg->csid_reg.csid_dl_input_sel_shift;
+		if (csid_dev->hw_version < CSID_VERSION_V30) {
+			val |= (0xF << 10);
+			msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr);
+		} else {
+			msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr);
+			val = csid_params->phy_sel <<
+			    csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift;
+			val |= 0xF;
+			msm_camera_io_w(val, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_1_addr);
+		}
+		if (csid_dev->hw_version >= CSID_VERSION_V35 &&
+			csid_params->csi_3p_sel == 1) {
+			csid_dev->csid_3p_enabled = 1;
+			val = (csid_params->lane_cnt - 1) << ENABLE_3P_BIT;
+
+			for (i = 0; i < csid_params->lane_cnt; i++) {
+				input_sel =
+					(csid_params->lane_assign >> (4*i))
+					& 0xF;
+				val |= input_sel << (4*(i+1));
+			}
+			val |= csid_params->phy_sel <<
+			    csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift_3p;
+			val |= ENABLE_3P_BIT;
+			msm_camera_io_w(val, csidbase + csid_dev->ctrl_reg
+				->csid_reg.csid_3p_ctrl_0_addr);
+		}
+	}
+
+	rc = msm_csid_cid_lut(&csid_params->lut_params, csid_dev);
+	if (rc < 0) {
+		pr_err("%s:%d config cid lut failed\n", __func__, __LINE__);
+		return rc;
+	}
+	msm_csid_set_debug_reg(csid_dev, csid_params);
+
+	if (csid_dev->is_testmode == 1)
+		msm_camera_io_w(0x00A06437, csidbase +
+			csid_dev->ctrl_reg->csid_reg.csid_tg_ctrl_addr);
+
+	return rc;
+}
+
+#if SHORT_PKT_CAPTURE
+static irqreturn_t msm_csid_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	uint32_t short_dt = 0;
+	uint32_t count = 0, dt = 0;
+	struct csid_device *csid_dev = data;
+
+	if (!csid_dev) {
+		pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+		return IRQ_HANDLED;
+	}
+	irq = msm_camera_io_r(csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+	CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+		 __func__, csid_dev->pdev->id, irq);
+	if (irq & (0x1 <<
+		csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift))
+		complete(&csid_dev->reset_complete);
+	if (irq & SHORT_PKT_OFFSET) {
+		short_dt = msm_camera_io_r(csid_dev->base +
+			csid_dev->ctrl_reg->
+			csid_reg.csid_captured_short_pkt_addr);
+		count = (short_dt >> 8) & 0xffff;
+		dt =  short_dt >> 24;
+		CDBG("CSID:: %s:%d core %d dt: 0x%x, count: %d\n",
+			__func__, __LINE__, csid_dev->pdev->id, dt, count);
+		msm_camera_io_w(0x101, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr);
+	}
+	msm_camera_io_w(irq, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	return IRQ_HANDLED;
+}
+#else
+static irqreturn_t msm_csid_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	struct csid_device *csid_dev = data;
+
+	if (!csid_dev) {
+		pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+		return IRQ_HANDLED;
+	}
+
+	if (csid_dev->csid_sof_debug == SOF_DEBUG_ENABLE) {
+		if (csid_dev->csid_sof_debug_count < CSID_SOF_DEBUG_COUNT)
+			csid_dev->csid_sof_debug_count++;
+		else {
+			msm_csid_set_sof_freeze_debug_reg(csid_dev, false);
+			return IRQ_HANDLED;
+		}
+	}
+
+	irq = msm_camera_io_r(csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+	pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+		 __func__, csid_dev->pdev->id, irq);
+	if (irq & (0x1 <<
+		csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift))
+		complete(&csid_dev->reset_complete);
+	msm_camera_io_w(irq, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	return IRQ_HANDLED;
+}
+#endif
+
+static int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status,
+	bool *handled)
+{
+	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+
+	CDBG("%s E\n", __func__);
+	ret = msm_csid_irq(csid_dev->irq->start, csid_dev);
+	*handled = TRUE;
+	return 0;
+}
+
+static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
+{
+	int rc = 0;
+
+	if (!csid_version) {
+		pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	csid_dev->csid_sof_debug_count = 0;
+	csid_dev->reg_ptr = NULL;
+
+	if (csid_dev->csid_state == CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		return -EINVAL;
+	}
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+
+	pr_info("%s: CSID_VERSION = 0x%x\n", __func__,
+		csid_dev->ctrl_reg->csid_reg.csid_version);
+	/* power up */
+	rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+		csid_dev->regulator_count, NULL, 0,
+		&csid_dev->csid_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csid config_vreg failed\n", __func__, __LINE__);
+		goto top_vreg_config_failed;
+	}
+
+	rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator on failed\n", __func__);
+		goto csid_vreg_config_failed;
+	}
+
+	rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+		csid_dev->regulator_count, NULL, 0,
+		&csid_dev->csid_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csid enable_vreg failed\n", __func__, __LINE__);
+		goto top_vreg_enable_failed;
+	}
+
+	rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator enable failed\n", __func__);
+		goto csid_vreg_enable_failed;
+	}
+	rc = msm_camera_clk_enable(&csid_dev->pdev->dev,
+		csid_dev->csid_clk_info, csid_dev->csid_clk,
+		csid_dev->num_clk, true);
+	if (rc < 0) {
+		pr_err("%s:%d clock enable failed\n",
+			 __func__, __LINE__);
+		goto clk_enable_failed;
+	}
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	csid_dev->hw_version =
+		msm_camera_io_r(csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_hw_version_addr);
+	CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__,
+		csid_dev->hw_version);
+	*csid_version = csid_dev->hw_version;
+	csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE;
+
+	csid_dev->is_testmode = 0;
+
+	init_completion(&csid_dev->reset_complete);
+
+	rc = msm_camera_enable_irq(csid_dev->irq, true);
+	if (rc < 0)
+		pr_err("%s: irq enable failed\n", __func__);
+	rc = msm_csid_reset(csid_dev);
+	if (rc < 0) {
+		pr_err("%s:%d msm_csid_reset failed\n", __func__, __LINE__);
+		goto msm_csid_reset_fail;
+	}
+
+	csid_dev->csid_state = CSID_POWER_UP;
+	return rc;
+
+msm_csid_reset_fail:
+	msm_camera_enable_irq(csid_dev->irq, false);
+	msm_camera_clk_enable(&csid_dev->pdev->dev, csid_dev->csid_clk_info,
+		csid_dev->csid_clk, csid_dev->num_clk, false);
+clk_enable_failed:
+	msm_camera_enable_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 0);
+csid_vreg_enable_failed:
+	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+		csid_dev->regulator_count, NULL, 0,
+		&csid_dev->csid_reg_ptr[0], 0);
+top_vreg_enable_failed:
+	msm_camera_config_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 0);
+csid_vreg_config_failed:
+	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+		csid_dev->regulator_count, NULL, 0,
+		&csid_dev->csid_reg_ptr[0], 0);
+top_vreg_config_failed:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote from AHB\n", __func__);
+	return rc;
+}
+
+static int msm_csid_release(struct csid_device *csid_dev)
+{
+	uint32_t irq;
+
+	if (csid_dev->csid_state != CSID_POWER_UP) {
+		pr_err("%s: csid invalid state %d\n", __func__,
+			csid_dev->csid_state);
+		return -EINVAL;
+	}
+
+	CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__,
+		csid_dev->hw_version);
+
+	irq = msm_camera_io_r(csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+	msm_camera_io_w(irq, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
+	msm_camera_io_w(0, csid_dev->base +
+		csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
+
+	msm_camera_enable_irq(csid_dev->irq, false);
+
+	msm_camera_clk_enable(&csid_dev->pdev->dev,
+		csid_dev->csid_clk_info,
+		csid_dev->csid_clk,
+		csid_dev->num_clk, false);
+
+	msm_camera_enable_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 0);
+
+	msm_camera_enable_vreg(&csid_dev->pdev->dev,
+		csid_dev->csid_vreg, csid_dev->regulator_count, NULL,
+		0, &csid_dev->csid_reg_ptr[0], 0);
+
+	msm_camera_config_vreg(&csid_dev->pdev->dev,
+		csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+		NULL, 0, &csid_dev->csi_vdd, 0);
+
+	msm_camera_config_vreg(&csid_dev->pdev->dev,
+		csid_dev->csid_vreg, csid_dev->regulator_count, NULL,
+		0, &csid_dev->csid_reg_ptr[0], 0);
+
+	if (!IS_ERR_OR_NULL(csid_dev->reg_ptr)) {
+		regulator_disable(csid_dev->reg_ptr);
+		regulator_put(csid_dev->reg_ptr);
+	}
+
+	csid_dev->csid_state = CSID_POWER_DOWN;
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote from AHB\n", __func__);
+	return 0;
+}
+
+static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg)
+{
+	int rc = 0;
+	struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg;
+
+	if (!csid_dev || !cdata) {
+		pr_err("%s:%d csid_dev %pK, cdata %pK\n", __func__, __LINE__,
+			csid_dev, cdata);
+		return -EINVAL;
+	}
+	CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CSID_INIT:
+		rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version);
+		CDBG("%s csid version 0x%x\n", __func__,
+			cdata->cfg.csid_version);
+		break;
+	case CSID_TESTMODE_CFG: {
+		csid_dev->is_testmode = 1;
+		if (copy_from_user(&csid_dev->testmode_params,
+			(void __user *)cdata->cfg.csid_testmode_params,
+			sizeof(struct msm_camera_csid_testmode_parms))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case CSID_CFG: {
+		struct msm_camera_csid_params csid_params;
+		struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
+		int i = 0;
+
+		if (copy_from_user(&csid_params,
+			(void __user *)cdata->cfg.csid_params,
+			sizeof(struct msm_camera_csid_params))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		if (csid_params.lut_params.num_cid < 1 ||
+			csid_params.lut_params.num_cid > MAX_CID) {
+			pr_err("%s: %d num_cid outside range\n",
+				 __func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
+		for (i = 0; i < csid_params.lut_params.num_cid; i++) {
+			vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+				GFP_KERNEL);
+			if (!vc_cfg) {
+				rc = -ENOMEM;
+				goto MEM_CLEAN;
+			}
+			if (copy_from_user(vc_cfg,
+				(void __user *)csid_params.lut_params.vc_cfg[i],
+				sizeof(struct msm_camera_csid_vc_cfg))) {
+				pr_err("%s: %d failed\n", __func__, __LINE__);
+				kfree(vc_cfg);
+				rc = -EFAULT;
+				goto MEM_CLEAN;
+			}
+			csid_params.lut_params.vc_cfg[i] = vc_cfg;
+		}
+		csid_dev->current_csid_params = csid_params;
+		csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE;
+		rc = msm_csid_config(csid_dev, &csid_params);
+MEM_CLEAN:
+		for (i--; i >= 0; i--)
+			kfree(csid_params.lut_params.vc_cfg[i]);
+		break;
+	}
+	case CSID_RELEASE:
+		rc = msm_csid_release(csid_dev);
+		break;
+	default:
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	return rc;
+}
+
+static int32_t msm_csid_get_subdev_id(struct csid_device *csid_dev, void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	if (!subdev_id) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	*subdev_id = csid_dev->pdev->id;
+	pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id);
+	return 0;
+}
+
+static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = -ENOIOCTLCMD;
+	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&csid_dev->mutex);
+	CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		rc = msm_csid_get_subdev_id(csid_dev, arg);
+		break;
+	case VIDIOC_MSM_CSID_IO_CFG:
+		rc = msm_csid_cmd(csid_dev, arg);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		if (csid_dev->csid_state != CSID_POWER_UP)
+			break;
+		if (csid_dev->csid_sof_debug == SOF_DEBUG_DISABLE) {
+			csid_dev->csid_sof_debug = SOF_DEBUG_ENABLE;
+			msm_csid_set_sof_freeze_debug_reg(csid_dev, true);
+		}
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		if (csid_dev->csid_state != CSID_POWER_UP)
+			break;
+		csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE;
+		msm_csid_set_sof_freeze_debug_reg(csid_dev, false);
+		break;
+	case VIDIOC_MSM_CSID_RELEASE:
+	case MSM_SD_SHUTDOWN:
+		rc = msm_csid_release(csid_dev);
+		break;
+	default:
+		pr_err_ratelimited("%s: command not found\n", __func__);
+	}
+	CDBG("%s:%d\n", __func__, __LINE__);
+	mutex_unlock(&csid_dev->mutex);
+	return rc;
+}
+
+
+#ifdef CONFIG_COMPAT
+static int32_t msm_csid_cmd32(struct csid_device *csid_dev, void *arg)
+{
+	int rc = 0;
+	struct csid_cfg_data *cdata;
+	struct csid_cfg_data32 *arg32 =  (struct csid_cfg_data32 *) (arg);
+	struct csid_cfg_data local_arg;
+
+	local_arg.cfgtype = arg32->cfgtype;
+	cdata = &local_arg;
+
+	if (!csid_dev || !cdata) {
+		pr_err("%s:%d csid_dev %pK, cdata %pK\n", __func__, __LINE__,
+			csid_dev, cdata);
+		return -EINVAL;
+	}
+
+	CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CSID_INIT:
+		rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version);
+		arg32->cfg.csid_version = local_arg.cfg.csid_version;
+		CDBG("%s csid version 0x%x\n", __func__,
+			cdata->cfg.csid_version);
+		break;
+	case CSID_TESTMODE_CFG: {
+		csid_dev->is_testmode = 1;
+		if (copy_from_user(&csid_dev->testmode_params,
+			(void __user *)
+			compat_ptr(arg32->cfg.csid_testmode_params),
+			sizeof(struct msm_camera_csid_testmode_parms))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case CSID_CFG: {
+
+		struct msm_camera_csid_params csid_params;
+		struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
+		int i = 0;
+		struct msm_camera_csid_lut_params32 lut_par32;
+		struct msm_camera_csid_params32 csid_params32;
+		struct msm_camera_csid_vc_cfg vc_cfg32;
+
+		if (copy_from_user(&csid_params32,
+			(void __user *)compat_ptr(arg32->cfg.csid_params),
+			sizeof(struct msm_camera_csid_params32))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		csid_params.lane_cnt = csid_params32.lane_cnt;
+		csid_params.lane_assign = csid_params32.lane_assign;
+		csid_params.phy_sel = csid_params32.phy_sel;
+		csid_params.csi_clk = csid_params32.csi_clk;
+		csid_params.csi_3p_sel = csid_params32.csi_3p_sel;
+
+		lut_par32 = csid_params32.lut_params;
+		csid_params.lut_params.num_cid = lut_par32.num_cid;
+
+		if (csid_params.lut_params.num_cid < 1 ||
+			csid_params.lut_params.num_cid > MAX_CID) {
+			pr_err("%s: %d num_cid outside range %d\n", __func__,
+				__LINE__, csid_params.lut_params.num_cid);
+			rc = -EINVAL;
+			break;
+		}
+
+		for (i = 0; i < lut_par32.num_cid; i++) {
+			vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+				GFP_KERNEL);
+			if (!vc_cfg) {
+				rc = -ENOMEM;
+				goto MEM_CLEAN32;
+			}
+			/* msm_camera_csid_vc_cfg size
+			 * does not change in COMPAT MODE
+			 */
+			if (copy_from_user(&vc_cfg32,
+				(void __user *)compat_ptr(lut_par32.vc_cfg[i]),
+				sizeof(vc_cfg32))) {
+				pr_err("%s: %d failed\n", __func__, __LINE__);
+				kfree(vc_cfg);
+				vc_cfg = NULL;
+				rc = -EFAULT;
+				goto MEM_CLEAN32;
+			}
+			vc_cfg->cid = vc_cfg32.cid;
+			vc_cfg->dt = vc_cfg32.dt;
+			vc_cfg->decode_format = vc_cfg32.decode_format;
+			csid_params.lut_params.vc_cfg[i] = vc_cfg;
+		}
+		rc = msm_csid_config(csid_dev, &csid_params);
+		csid_dev->current_csid_params = csid_params;
+
+MEM_CLEAN32:
+		for (i--; i >= 0; i--) {
+			kfree(csid_params.lut_params.vc_cfg[i]);
+			csid_params.lut_params.vc_cfg[i] = NULL;
+		}
+		break;
+	}
+	case CSID_RELEASE:
+		rc = msm_csid_release(csid_dev);
+		break;
+	default:
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	return rc;
+}
+
+static long msm_csid_subdev_ioctl32(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = -ENOIOCTLCMD;
+	struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&csid_dev->mutex);
+	CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		rc = msm_csid_get_subdev_id(csid_dev, arg);
+		break;
+	case VIDIOC_MSM_CSID_IO_CFG32:
+		rc = msm_csid_cmd32(csid_dev, arg);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		if (csid_dev->csid_state != CSID_POWER_UP)
+			break;
+		if (csid_dev->csid_sof_debug == SOF_DEBUG_DISABLE) {
+			csid_dev->csid_sof_debug = SOF_DEBUG_ENABLE;
+			msm_csid_set_sof_freeze_debug_reg(csid_dev, true);
+		}
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		if (csid_dev->csid_state != CSID_POWER_UP)
+			break;
+		csid_dev->csid_sof_debug = SOF_DEBUG_DISABLE;
+		msm_csid_set_sof_freeze_debug_reg(csid_dev, false);
+		break;
+	case VIDIOC_MSM_CSID_RELEASE:
+	case MSM_SD_SHUTDOWN:
+		rc = msm_csid_release(csid_dev);
+		break;
+	default:
+		pr_err_ratelimited("%s: command not found\n", __func__);
+	}
+	CDBG("%s:%d\n", __func__, __LINE__);
+	mutex_unlock(&csid_dev->mutex);
+	return rc;
+}
+
+static long msm_csid_subdev_do_ioctl32(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	return msm_csid_subdev_ioctl32(sd, cmd, arg);
+}
+
+static long msm_csid_subdev_fops_ioctl32(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_csid_subdev_do_ioctl32);
+}
+#endif
+static const struct v4l2_subdev_internal_ops msm_csid_internal_ops;
+
+static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
+	.ioctl = &msm_csid_subdev_ioctl,
+	.interrupt_service_routine = msm_csid_irq_routine,
+};
+
+static const struct v4l2_subdev_ops msm_csid_subdev_ops = {
+	.core = &msm_csid_subdev_core_ops,
+};
+
+static int csid_probe(struct platform_device *pdev)
+{
+	struct csid_device *new_csid_dev;
+	uint32_t csi_vdd_voltage = 0;
+	int rc = 0;
+
+	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
+	if (!new_csid_dev)
+		return -ENOMEM;
+
+	CDBG("%s: csid_probe entry\n", __func__);
+
+	new_csid_dev->csid_3p_enabled = 0;
+	new_csid_dev->ctrl_reg = NULL;
+	new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t),
+		GFP_KERNEL);
+	if (!new_csid_dev->ctrl_reg) {
+		kfree(new_csid_dev);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&new_csid_dev->msm_sd.sd, &msm_csid_subdev_ops);
+	v4l2_set_subdevdata(&new_csid_dev->msm_sd.sd, new_csid_dev);
+	platform_set_drvdata(pdev, &new_csid_dev->msm_sd.sd);
+	mutex_init(&new_csid_dev->mutex);
+
+	if (pdev->dev.of_node) {
+		rc = of_property_read_u32((&pdev->dev)->of_node,
+			"cell-index", &pdev->id);
+		if (rc < 0) {
+			pr_err("%s:%d failed to read cell-index\n", __func__,
+				__LINE__);
+			goto csid_no_resource;
+		}
+		CDBG("%s device id %d\n", __func__, pdev->id);
+
+		rc = of_property_read_u32((&pdev->dev)->of_node,
+			"qcom,csi-vdd-voltage", &csi_vdd_voltage);
+		if (rc < 0) {
+			pr_err("%s:%d failed to read qcom,csi-vdd-voltage\n",
+				__func__, __LINE__);
+			goto csid_no_resource;
+		}
+		CDBG("%s:%d reading mipi_csi_vdd is %d\n", __func__, __LINE__,
+			csi_vdd_voltage);
+
+		csid_vreg_info[0].min_voltage = csi_vdd_voltage;
+		csid_vreg_info[0].max_voltage = csi_vdd_voltage;
+	}
+
+	rc = msm_camera_get_clk_info(pdev, &new_csid_dev->csid_clk_info,
+		&new_csid_dev->csid_clk, &new_csid_dev->num_clk);
+	if (rc < 0) {
+		pr_err("%s: msm_camera_get_clk_info failed", __func__);
+		rc = -EFAULT;
+		goto csid_no_resource;
+	}
+
+	rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+		&(new_csid_dev->csid_vreg), &(new_csid_dev->regulator_count));
+	if (rc < 0) {
+		pr_err("%s: get vreg data from dtsi fail\n", __func__);
+		rc = -EFAULT;
+		goto csid_no_resource;
+	}
+
+	if ((new_csid_dev->regulator_count < 0) ||
+		(new_csid_dev->regulator_count > MAX_REGULATOR)) {
+		pr_err("%s: invalid reg count = %d, max is %d\n", __func__,
+			new_csid_dev->regulator_count, MAX_REGULATOR);
+		rc = -EFAULT;
+		goto csid_no_resource;
+	}
+
+	new_csid_dev->base = msm_camera_get_reg_base(pdev, "csid", true);
+	if (!new_csid_dev->base) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csid_invalid_vreg_data;
+	}
+	new_csid_dev->irq = msm_camera_get_irq(pdev, "csid");
+	if (!new_csid_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csid_invalid_irq;
+	}
+	new_csid_dev->pdev = pdev;
+	new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops;
+	new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(new_csid_dev->msm_sd.sd.name,
+			ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid");
+	media_entity_pads_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL);
+	new_csid_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CSID;
+	new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
+	msm_sd_register(&new_csid_dev->msm_sd);
+
+#ifdef CONFIG_COMPAT
+	msm_cam_copy_v4l2_subdev_fops(&msm_csid_v4l2_subdev_fops);
+	msm_csid_v4l2_subdev_fops.compat_ioctl32 = msm_csid_subdev_fops_ioctl32;
+	new_csid_dev->msm_sd.sd.devnode->fops = &msm_csid_v4l2_subdev_fops;
+#endif
+
+	rc = msm_camera_register_irq(pdev, new_csid_dev->irq,
+		msm_csid_irq, IRQF_TRIGGER_RISING, "csid", new_csid_dev);
+	if (rc < 0) {
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csid_invalid_irq;
+	}
+	rc = msm_camera_enable_irq(new_csid_dev->irq, false);
+	if (rc < 0) {
+		pr_err("%s Error registering irq ", __func__);
+		rc = -EBUSY;
+		goto csid_invalid_irq;
+	}
+
+	if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v2.0")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v2_0;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v2_0;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V20;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v2.2")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v2_2;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v2_2;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V22;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.0")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_0;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_0;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V30;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v4.0")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_0;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_0;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V40;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.1")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_1;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_1;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V31;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.2")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_2;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_2;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V32;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.4.1")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_1;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V34_1;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_4_1;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.4.2")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_2;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V34_2;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_4_2;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.6.0")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_6_0;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V36;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_6_0;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.5")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_5;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_5;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V35;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v5.0")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_5;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_5;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V50;
+	} else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node,
+		"qcom,csid-v3.5.1")) {
+		new_csid_dev->ctrl_reg->csid_reg = csid_v3_5_1;
+		new_csid_dev->ctrl_reg->csid_lane_assign =
+			csid_lane_assign_v3_5_1;
+		new_csid_dev->hw_dts_version = CSID_VERSION_V35_1;
+	} else {
+		pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__,
+			new_csid_dev->hw_dts_version);
+		rc = -EINVAL;
+		goto csid_invalid_irq;
+	}
+
+	new_csid_dev->csid_state = CSID_POWER_DOWN;
+	return 0;
+
+csid_invalid_irq:
+	msm_camera_put_reg_base(pdev, new_csid_dev->base, "csid", true);
+csid_invalid_vreg_data:
+	kfree(new_csid_dev->csid_vreg);
+csid_no_resource:
+	mutex_destroy(&new_csid_dev->mutex);
+	kfree(new_csid_dev->ctrl_reg);
+	kfree(new_csid_dev);
+	return rc;
+}
+
+static int msm_csid_exit(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct csid_device *csid_dev =
+		v4l2_get_subdevdata(subdev);
+
+	msm_camera_put_clk_info(pdev, &csid_dev->csid_clk_info,
+		&csid_dev->csid_clk, csid_dev->num_clk);
+	msm_camera_put_reg_base(pdev, csid_dev->base, "csid", true);
+	kfree(csid_dev);
+	return 0;
+}
+
+static const struct of_device_id msm_csid_dt_match[] = {
+	{.compatible = "qcom,csid"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_csid_dt_match);
+
+static struct platform_driver csid_driver = {
+	.probe = csid_probe,
+	.remove = msm_csid_exit,
+	.driver = {
+		.name = MSM_CSID_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_csid_dt_match,
+	},
+};
+
+static int __init msm_csid_init_module(void)
+{
+	return platform_driver_register(&csid_driver);
+}
+
+static void __exit msm_csid_exit_module(void)
+{
+	platform_driver_unregister(&csid_driver);
+}
+
+module_init(msm_csid_init_module);
+module_exit(msm_csid_exit_module);
+MODULE_DESCRIPTION("MSM CSID driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h
new file mode 100644
index 0000000..79eaf59
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2011-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_H
+#define MSM_CSID_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_cam_sensor.h>
+#include "msm_sd.h"
+#include "cam_soc_api.h"
+
+#define CSID_SOF_DEBUG_COUNT                      3
+
+enum csiphy_lane_assign {
+	PHY_LANE_D0,
+	PHY_LANE_CLK,
+	PHY_LANE_D1,
+	PHY_LANE_D2,
+	PHY_LANE_D3,
+	PHY_LANE_MAX,
+};
+
+struct csid_reg_parms_t {
+/* MIPI	CSID registers */
+	uint32_t csid_hw_version_addr;
+	uint32_t csid_core_ctrl_0_addr;
+	uint32_t csid_core_ctrl_1_addr;
+	uint32_t csid_rst_cmd_addr;
+	uint32_t csid_cid_lut_vc_0_addr;
+	uint32_t csid_cid_lut_vc_1_addr;
+	uint32_t csid_cid_lut_vc_2_addr;
+	uint32_t csid_cid_lut_vc_3_addr;
+	uint32_t csid_cid_n_cfg_addr;
+	uint32_t csid_irq_clear_cmd_addr;
+	uint32_t csid_irq_mask_addr;
+	uint32_t csid_irq_status_addr;
+	uint32_t csid_captured_unmapped_long_pkt_hdr_addr;
+	uint32_t csid_captured_mmaped_long_pkt_hdr_addr;
+	uint32_t csid_captured_short_pkt_addr;
+	uint32_t csid_captured_long_pkt_hdr_addr;
+	uint32_t csid_captured_long_pkt_ftr_addr;
+	uint32_t csid_pif_misr_dl0_addr;
+	uint32_t csid_pif_misr_dl1_addr;
+	uint32_t csid_pif_misr_dl2_addr;
+	uint32_t csid_pif_misr_dl3_addr;
+	uint32_t csid_stats_total_pkts_rcvd_addr;
+	uint32_t csid_stats_ecc_addr;
+	uint32_t csid_stats_crc_addr;
+	uint32_t csid_tg_ctrl_addr;
+	uint32_t csid_tg_vc_cfg_addr;
+	uint32_t csid_tg_dt_n_cfg_0_addr;
+	uint32_t csid_tg_dt_n_cfg_1_addr;
+	uint32_t csid_tg_dt_n_cfg_2_addr;
+	uint32_t csid_rst_done_irq_bitshift;
+	uint32_t csid_rst_stb_all;
+	uint32_t csid_dl_input_sel_shift;
+	uint32_t csid_phy_sel_shift;
+	uint32_t csid_version;
+	uint32_t csid_3p_ctrl_0_addr;
+	uint32_t csid_3p_pkt_hdr_addr;
+	uint32_t csid_test_bus_ctrl;
+	uint32_t csid_irq_mask_val;
+	uint32_t csid_err_lane_overflow_offset_2p;
+	uint32_t csid_err_lane_overflow_offset_3p;
+	uint32_t csid_phy_sel_shift_3p;
+};
+
+struct csid_ctrl_t {
+	struct csid_reg_parms_t csid_reg;
+	uint8_t *csid_lane_assign;
+};
+
+enum msm_csid_state_t {
+	CSID_POWER_UP,
+	CSID_POWER_DOWN,
+};
+
+struct csid_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct resource *irq;
+	struct regulator *csi_vdd;
+	void __iomem *base;
+	struct mutex mutex;
+	struct completion reset_complete;
+	uint32_t hw_version;
+	uint32_t hw_dts_version;
+	enum msm_csid_state_t csid_state;
+	struct csid_ctrl_t *ctrl_reg;
+	struct regulator *reg_ptr;
+	size_t num_clk;
+	struct clk **csid_clk;
+	struct msm_cam_clk_info *csid_clk_info;
+	uint32_t csid_clk_index;
+	uint32_t csid_max_clk;
+	uint32_t csid_3p_enabled;
+	struct camera_vreg_t *csid_vreg;
+	struct regulator *csid_reg_ptr[MAX_REGULATOR];
+	int32_t regulator_count;
+	uint8_t is_testmode;
+	struct msm_camera_csid_testmode_parms testmode_params;
+	struct msm_camera_csid_params  current_csid_params;
+	uint32_t csid_sof_debug;
+	uint32_t csid_lane_cnt;
+	uint32_t csid_sof_debug_count;
+};
+
+#define VIDIOC_MSM_CSID_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct v4l2_subdev*)
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
new file mode 100644
index 0000000..e0cbdb8
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h
new file mode 100644
index 0000000..f7da4a7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_2_0_HWREG_H
+#define MSM_CSIPHY_2_0_HWREG_H
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v2_0 = {
+	/*MIPI CSI PHY registers*/
+	0x17C,
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x100,
+	0x104,
+	0x108,
+	0x10C,
+	0x110,
+	0x128,
+	0x140,
+	0x144,
+	0x164,
+	0x180,
+	0x1A0,
+	0x6F,
+	0x1A4,
+	0x1C0,
+	0x1C4,
+	0x4,
+	0x1E0,
+	0x1E8,
+	0x0,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h
new file mode 100644
index 0000000..d8a0e99
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_2_2_HWREG_H
+#define MSM_CSIPHY_2_2_HWREG_H
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v2_2 = {
+	/*MIPI CSI PHY registers*/
+	0x17C,
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x100,
+	0x104,
+	0x108,
+	0x10C,
+	0x110,
+	0x128,
+	0x140,
+	0x144,
+	0x164,
+	0x180,
+	0x1A0,
+	0x6F,
+	0x1A4,
+	0x1C0,
+	0x1C4,
+	0x4,
+	0x1E0,
+	0x1E8,
+	0x1,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h
new file mode 100644
index 0000000..9b2b00f8
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_3_0_HWREG_H
+#define MSM_CSIPHY_3_0_HWREG_H
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v3_0 = {
+	/*MIPI CSI PHY registers*/
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x100,
+	0x104,
+	0x108,
+	0x10C,
+	0x110,
+	0x128,
+	0x140,
+	0x144,
+	0x164,
+	0x188,
+	0x18C,
+	0x1AC,
+	0x3F,
+	0x1AC,
+	0x1CC,
+	0x1CC,
+	0x4,
+	0x1EC,
+	0x1F4,
+	0x10,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h
new file mode 100644
index 0000000..2b924b9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_3_1_HWREG_H
+#define MSM_CSIPHY_3_1_HWREG_H
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v3_1 = {
+	/*MIPI CSI PHY registers*/
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x100,
+	0x104,
+	0x108,
+	0x10C,
+	0x1C,
+	0x28,
+	0x140,
+	0x144,
+	0x164,
+	0x188,
+	0x18C,
+	0x1AC,
+	0x3F,
+	0x1AC,
+	0x1CC,
+	0x1CC,
+	0x4,
+	0x1EC,
+	0x1F4,
+	0x31,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h
new file mode 100644
index 0000000..5445f2f
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_3_2_HWREG_H
+#define MSM_CSIPHY_3_2_HWREG_H
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v3_2 = {
+	/*MIPI CSI PHY registers*/
+	0x0,
+	0x4,
+	0x8,
+	0xC,
+	0x10,
+	0x100,
+	0x104,
+	0x108,
+	0x10C,
+	0x110,
+	0x128,
+	0x140,
+	0x144,
+	0x164,
+	0x188,
+	0x18C,
+	0x1AC,
+	0x3F,
+	0x1AC,
+	0x1CC,
+	0x1CC,
+	0x4,
+	0x1EC,
+	0x1F4,
+	0x32,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h
new file mode 100644
index 0000000..04b7376
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_4_2_hwreg.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_3_4_2_HWREG_H
+#define MSM_CSIPHY_3_4_2_HWREG_H
+
+#define ULPM_WAKE_UP_TIMER_MODE                   2
+#define GLITCH_ELIMINATION_NUM                    0x12 /* bit [6:4] */
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v3_4_2 = {
+	.mipi_csiphy_interrupt_status0_addr = 0x8B0,
+	.mipi_csiphy_interrupt_clear0_addr = 0x858,
+	.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
+	.combo_clk_mask = 0x10,
+};
+
+static struct csiphy_reg_3ph_parms_t csiphy_v3_4_2_3ph = {
+	/*MIPI CSI PHY registers*/
+	{0x814, 0x0},
+	{0x818, 0x1},
+	{0x188, 0x7F},
+	{0x18C, 0x7F},
+	{0x190, 0x0},
+	{0x104, 0x6},
+	{0x108, 0x0},
+	{0x10c, 0x0},
+	{0x114, 0x20},
+	{0x118, 0x3E},
+	{0x11c, 0x41},
+	{0x120, 0x41},
+	{0x124, 0x7F},
+	{0x128, 0x0},
+	{0x12c, 0x0},
+	{0x130, 0x1},
+	{0x134, 0x0},
+	{0x138, 0x0},
+	{0x13C, 0x10},
+	{0x140, 0x1},
+	{0x144, GLITCH_ELIMINATION_NUM},
+	{0x148, 0xFE},
+	{0x14C, 0x1},
+	{0x154, 0x0},
+	{0x15C, 0x33},
+	{0x160, ULPM_WAKE_UP_TIMER_MODE},
+	{0x164, 0x48},
+	{0x168, 0xA0},
+	{0x16C, 0x17},
+	{0x170, 0x41},
+	{0x174, 0x41},
+	{0x178, 0x3E},
+	{0x17C, 0x0},
+	{0x180, 0x0},
+	{0x184, 0x7F},
+	{0x1cc, 0x10},
+	{0x81c, 0x6},
+	{0x82c, 0xFF},
+	{0x830, 0xFF},
+	{0x834, 0xFB},
+	{0x838, 0xFF},
+	{0x83c, 0x7F},
+	{0x840, 0xFF},
+	{0x844, 0xFF},
+	{0x848, 0xEF},
+	{0x84c, 0xFF},
+	{0x850, 0xFF},
+	{0x854, 0xFF},
+	{0x28, 0x0},
+	{0x800, 0x2},
+	{0x0, 0x8E},
+	{0x4, 0x8},
+	{0x8, 0x0},
+	{0xC, 0xFF},
+	{0x10, 0x56},
+	{0x2C, 0x1},
+	{0x30, 0x0},
+	{0x34, 0x3},
+	{0x38, 0xfe},
+	{0x3C, 0xB8},
+	{0x1C, 0xE7},
+	{0x14, 0x0},
+	{0x14, 0x60},
+	{0x700, 0x80}
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h
new file mode 100644
index 0000000..90b8e1c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_3_5_HWREG_H
+#define MSM_CSIPHY_3_5_HWREG_H
+
+#define ULPM_WAKE_UP_TIMER_MODE                   2
+#define GLITCH_ELIMINATION_NUM                    0x12 /* bit [6:4] */
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v3_5 = {
+	.mipi_csiphy_interrupt_status0_addr = 0x8B0,
+	.mipi_csiphy_interrupt_clear0_addr = 0x858,
+	.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
+	.combo_clk_mask = 0x10,
+};
+
+static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = {
+	/*MIPI CSI PHY registers*/
+	{0x814, 0x0},
+	{0x818, 0x1},
+	{0x188, 0x7F},
+	{0x18C, 0x7F},
+	{0x190, 0x0},
+	{0x104, 0x6},
+	{0x108, 0x0},
+	{0x10c, 0x0},
+	{0x114, 0x20},
+	{0x118, 0x3E},
+	{0x11c, 0x41},
+	{0x120, 0x41},
+	{0x124, 0x7F},
+	{0x128, 0x0},
+	{0x12c, 0x0},
+	{0x130, 0x1},
+	{0x134, 0x0},
+	{0x138, 0x0},
+	{0x13C, 0x10},
+	{0x140, 0x1},
+	{0x144, GLITCH_ELIMINATION_NUM},
+	{0x148, 0xFE},
+	{0x14C, 0x1},
+	{0x154, 0x0},
+	{0x15C, 0x33},
+	{0x160, ULPM_WAKE_UP_TIMER_MODE},
+	{0x164, 0x48},
+	{0x168, 0xA0},
+	{0x16C, 0x17},
+	{0x170, 0x41},
+	{0x174, 0x41},
+	{0x178, 0x3E},
+	{0x17C, 0x0},
+	{0x180, 0x0},
+	{0x184, 0x7F},
+	{0x1cc, 0x10},
+	{0x81c, 0x6},
+	{0x82c, 0xFF},
+	{0x830, 0xFF},
+	{0x834, 0xFB},
+	{0x838, 0xFF},
+	{0x83c, 0x7F},
+	{0x840, 0xFF},
+	{0x844, 0xFF},
+	{0x848, 0xEF},
+	{0x84c, 0xFF},
+	{0x850, 0xFF},
+	{0x854, 0xFF},
+	{0x28, 0x0},
+	{0x800, 0x0},
+	{0x0, 0xD7},
+	{0x4, 0x8},
+	{0x8, 0x0},
+	{0xC, 0xA5},
+	{0x10, 0x52},
+	{0x2C, 0x1},
+	{0x30, 0x2},
+	{0x34, 0x3},
+	{0x38, 0x1},
+	{0x3C, 0xB8},
+	{0x1C, 0xA},
+	{0x14, 0x0},
+	{0x0, 0x0},
+	{0x700, 0xC0},
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
new file mode 100644
index 0000000..d92614d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
@@ -0,0 +1,163 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_5_0_1_HWREG_H
+#define MSM_CSIPHY_5_0_1_HWREG_H
+
+#define ULPM_WAKE_UP_TIMER_MODE                   2
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v5_0_1 = {
+	.mipi_csiphy_interrupt_status0_addr = 0x8B0,
+	.mipi_csiphy_interrupt_clear0_addr = 0x858,
+	.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
+	.combo_clk_mask = 0x10,
+};
+
+static struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = {
+	/*MIPI CSI PHY registers*/
+	{0x814, 0xD5},
+	{0x818, 0x1},
+	{0x188, 0x7F},
+	{0x18C, 0x7F},
+	{0x190, 0x0},
+	{0x104, 0x6},
+	{0x108, 0x1},
+	{0x10c, 0x12},
+	{0x114, 0x20},
+	{0x118, 0x3E},
+	{0x11c, 0x41},
+	{0x120, 0x41},
+	{0x124, 0x7F},
+	{0x128, 0x0},
+	{0x12c, 0x0},
+	{0x130, 0x1},
+	{0x134, 0x0},
+	{0x138, 0x0},
+	{0x13C, 0x10},
+	{0x140, 0x1},
+	{0x144, 0x12},
+	{0x148, 0xFE},
+	{0x14C, 0x1},
+	{0x154, 0x0},
+	{0x15C, 0x63},
+	{0x160, ULPM_WAKE_UP_TIMER_MODE},
+	{0x164, 0x00},
+	{0x168, 0xAC},
+	{0x16C, 0xA5},
+	{0x170, 0x41},
+	{0x174, 0x41},
+	{0x178, 0x3E},
+	{0x17C, 0x0},
+	{0x180, 0x0},
+	{0x184, 0x7F},
+	{0x1cc, 0x41},
+	{0x81c, 0x2},
+	{0x82c, 0xFF},
+	{0x830, 0xFF},
+	{0x834, 0xFB},
+	{0x838, 0xFF},
+	{0x83c, 0x7F},
+	{0x840, 0xFF},
+	{0x844, 0xFF},
+	{0x848, 0xEF},
+	{0x84c, 0xFF},
+	{0x850, 0xFF},
+	{0x854, 0xFF},
+	{0x28, 0x0},
+	{0x800, 0x0},
+	{0x4, 0xC},
+	{0x8, 0x14},
+	{0x8, 0x14},
+	{0x10, 0x52},
+	{0x14, 0x60},
+	{0x14, 0x60},
+	{0x1C, 0xa},
+	{0x1c, 0xa},
+	{0x38, 0x1},
+	{0x3C, 0xB8},
+	{0x3C, 0xB8},
+	{0x14, 0x0},
+	{0x14, 0x0},
+	{0x700, 0xC0},
+	{0x150, 0},
+	{0x1dc, 0x51},
+	{0x2C, 0x1},
+	{0x34, 0xf},
+	{0x728, 0x4},
+	{0x0, 0x91},
+	{0x70C, 0xA5},
+	{0x38, 0xFE},
+	{0x81c, 0x2},
+	{0x700, 0x80},
+	{0x724, 0x04},
+	{0x024, 0x04},
+};
+
+static struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = {
+	{
+		{0x818, 0x1},
+		{0x81c, 0x2},
+		{0x004, 0x0C},
+		{0x704, 0x0C},
+		{0x204, 0x0C},
+		{0x404, 0x0C},
+		{0x604, 0x0C},
+		{0x02c, 0x1},
+		{0x22c, 0x1},
+		{0x42c, 0x1},
+		{0x62c, 0x1},
+		{0x72c, 0x1},
+		{0x034, 0x0f},
+		{0x234, 0x0f},
+		{0x434, 0x0f},
+		{0x634, 0x0f},
+		{0x734, 0x0f},
+		{0x01c, 0x0a},
+		{0x21c, 0x0a},
+		{0x41c, 0x0a},
+		{0x61c, 0x0a},
+		{0x71c, 0x0a},
+		{0x014, 0x60},
+		{0x214, 0x60},
+		{0x414, 0x60},
+		{0x614, 0x60},
+		{0x714, 0x60},
+		{0x728, 0x4},
+		{0x428, 0x0a},
+		{0x628, 0x0e},
+		{0x03c, 0xb8},
+		{0x73c, 0xb8},
+		{0x23c, 0xb8},
+		{0x43c, 0xb8},
+		{0x63c, 0xb8},
+		{0x000, 0x91},
+		{0x700, 0x80},
+		{0x200, 0x91},
+		{0x400, 0x91},
+		{0x600, 0x80},
+		{0x70c, 0xA5},
+		{0x60c, 0xA5},
+		{0x010, 0x52},
+		{0x710, 0x52},
+		{0x210, 0x52},
+		{0x410, 0x52},
+		{0x610, 0x52},
+		{0x038, 0xfe},
+		{0x738, 0x1f},
+		{0x238, 0xfe},
+		{0x438, 0xfe},
+		{0x638, 0x1f},
+	}
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
new file mode 100644
index 0000000..f247958
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
@@ -0,0 +1,164 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_5_0_HWREG_H
+#define MSM_CSIPHY_5_0_HWREG_H
+
+#define ULPM_WAKE_UP_TIMER_MODE                   2
+#define GLITCH_ELIMINATE_NUM                      0x32
+
+#include <sensor/csiphy/msm_csiphy.h>
+
+static struct csiphy_reg_parms_t csiphy_v5_0 = {
+	.mipi_csiphy_interrupt_status0_addr = 0x8B0,
+	.mipi_csiphy_interrupt_clear0_addr = 0x858,
+	.mipi_csiphy_glbl_irq_cmd_addr = 0x828,
+	.combo_clk_mask = 0x10,
+};
+
+static struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = {
+	/*MIPI CSI PHY registers*/
+	{0x814, 0x2A},
+	{0x818, 0x1},
+	{0x188, 0x7F},
+	{0x18C, 0x7F},
+	{0x190, 0x0},
+	{0x104, 0x6},
+	{0x108, 0x1},
+	{0x10c, 0x12},
+	{0x114, 0x20},
+	{0x118, 0x3E},
+	{0x11c, 0x41},
+	{0x120, 0x41},
+	{0x124, 0x7F},
+	{0x128, 0x0},
+	{0x12c, 0x0},
+	{0x130, 0x1},
+	{0x134, 0x0},
+	{0x138, 0x0},
+	{0x13C, 0x10},
+	{0x140, 0x1},
+	{0x144, GLITCH_ELIMINATE_NUM},
+	{0x148, 0xFE},
+	{0x14C, 0x1},
+	{0x154, 0x0},
+	{0x15C, 0x23},
+	{0x160, ULPM_WAKE_UP_TIMER_MODE},
+	{0x164, 0x00},
+	{0x168, 0xA0},
+	{0x16C, 0x25},
+	{0x170, 0x41},
+	{0x174, 0x41},
+	{0x178, 0x3E},
+	{0x17C, 0x0},
+	{0x180, 0x0},
+	{0x184, 0x7F},
+	{0x1cc, 0x41},
+	{0x81c, 0x2},
+	{0x82c, 0xFF},
+	{0x830, 0xFF},
+	{0x834, 0xFB},
+	{0x838, 0xFF},
+	{0x83c, 0x7F},
+	{0x840, 0xFF},
+	{0x844, 0xFF},
+	{0x848, 0xEF},
+	{0x84c, 0xFF},
+	{0x850, 0xFF},
+	{0x854, 0xFF},
+	{0x28, 0x0},
+	{0x800, 0x0},
+	{0x4, 0x8},
+	{0x8, 0x4},
+	{0x8, 0x4},
+	{0x10, 0x52},
+	{0x14, 0x60},
+	{0x14, 0x60},
+	{0x1C, 0xa},
+	{0x1c, 0xa},
+	{0x38, 0x1},
+	{0x3C, 0xB8},
+	{0x3C, 0xB8},
+	{0x14, 0x0},
+	{0x0, 0x0},
+	{0x700, 0xC0},
+	{0x150, 0},
+	{0x1dc, 0x51},
+	{0x2C, 0x1},
+	{0x34, 0xf},
+	{0x728, 0x4},
+	{0x0, 0x91},
+	{0x70C, 0x16},
+	{0x38, 0xFE},
+	{0x81c, 0x6},
+	{0x700, 0x80},
+	{0x724, 0x04},
+	{0x024, 0x04},
+};
+
+static struct csiphy_settings_t csiphy_combo_mode_v5_0 = {
+	{
+		{0x818, 0x1},
+		{0x81c, 0x2},
+		{0x004, 0x08},
+		{0x704, 0x08},
+		{0x204, 0x08},
+		{0x404, 0x08},
+		{0x604, 0x08},
+		{0x02c, 0x1},
+		{0x22c, 0x1},
+		{0x42c, 0x1},
+		{0x62c, 0x1},
+		{0x72c, 0x1},
+		{0x034, 0x0f},
+		{0x234, 0x0f},
+		{0x434, 0x0f},
+		{0x634, 0x0f},
+		{0x734, 0x0f},
+		{0x01c, 0x0a},
+		{0x21c, 0x0a},
+		{0x41c, 0x0a},
+		{0x61c, 0x0a},
+		{0x71c, 0x0a},
+		{0x014, 0x60},
+		{0x214, 0x60},
+		{0x414, 0x60},
+		{0x614, 0x60},
+		{0x714, 0x60},
+		{0x728, 0x4},
+		{0x428, 0x0a},
+		{0x628, 0x0e},
+		{0x03c, 0xb8},
+		{0x73c, 0xb8},
+		{0x23c, 0xb8},
+		{0x43c, 0xb8},
+		{0x63c, 0xb8},
+		{0x000, 0x91},
+		{0x700, 0x80},
+		{0x200, 0x91},
+		{0x400, 0x91},
+		{0x600, 0x80},
+		{0x70c, 0xA5},
+		{0x60c, 0xA5},
+		{0x010, 0x52},
+		{0x710, 0x52},
+		{0x210, 0x52},
+		{0x410, 0x52},
+		{0x610, 0x52},
+		{0x038, 0xfe},
+		{0x738, 0x1f},
+		{0x238, 0xfe},
+		{0x438, 0xfe},
+		{0x638, 0x1f},
+	}
+};
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
new file mode 100644
index 0000000..edf022e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -0,0 +1,1930 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/irqreturn.h>
+#include "msm_csiphy.h"
+#include "msm_sd.h"
+#include "include/msm_csiphy_2_0_hwreg.h"
+#include "include/msm_csiphy_2_2_hwreg.h"
+#include "include/msm_csiphy_3_0_hwreg.h"
+#include "include/msm_csiphy_3_1_hwreg.h"
+#include "include/msm_csiphy_3_2_hwreg.h"
+#include "include/msm_csiphy_3_4_2_hwreg.h"
+#include "include/msm_csiphy_3_5_hwreg.h"
+#include "include/msm_csiphy_5_0_hwreg.h"
+#include "include/msm_csiphy_5_0_1_hwreg.h"
+#include "cam_hw_ops.h"
+
+#define DBG_CSIPHY 0
+#define SOF_DEBUG_ENABLE 1
+#define SOF_DEBUG_DISABLE 0
+
+#define V4L2_IDENT_CSIPHY                        50003
+#define CSIPHY_VERSION_V22                        0x01
+#define CSIPHY_VERSION_V20                        0x00
+#define CSIPHY_VERSION_V30                        0x10
+#define CSIPHY_VERSION_V31                        0x31
+#define CSIPHY_VERSION_V32                        0x32
+#define CSIPHY_VERSION_V342                       0x342
+#define CSIPHY_VERSION_V35                        0x35
+#define CSIPHY_VERSION_V50                        0x500
+#define CSIPHY_VERSION_V501                       0x501
+#define MSM_CSIPHY_DRV_NAME                      "msm_csiphy"
+#define CLK_LANE_OFFSET                             1
+#define NUM_LANES_OFFSET                            4
+#define CLOCK_LANE                                  0x02
+
+#define CSI_3PHASE_HW                               1
+#define MAX_DPHY_DATA_LN                            4
+#define CLOCK_OFFSET                              0x700
+#define CSIPHY_SOF_DEBUG_COUNT                      2
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static struct v4l2_file_operations msm_csiphy_v4l2_subdev_fops;
+
+static void msm_csiphy_write_settings(
+	struct csiphy_device *csiphy_dev,
+	struct csiphy_settings_t csiphy_settings)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_CSIPHY_SETTINGS; i++) {
+		if (csiphy_settings.settings[i].addr == 0 &&
+			csiphy_settings.settings[i].data == 0)
+			break;
+
+		msm_camera_io_w(csiphy_settings.settings[i].data,
+			csiphy_dev->base + csiphy_settings.settings[i].addr);
+	}
+}
+
+static void msm_csiphy_cphy_irq_config(
+	struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl11.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl11.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl12.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl12.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl13.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl13.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl14.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl14.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl15.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl15.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl16.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl16.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl17.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl17.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl18.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl18.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl19.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl19.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl20.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl20.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl21.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl21.addr);
+}
+
+static int msm_csiphy_3phase_lane_config(
+	struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	uint8_t i = 0;
+	uint16_t lane_mask = 0, lane_enable = 0, temp;
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	lane_mask = csiphy_params->lane_mask & 0x7;
+	while (lane_mask != 0) {
+		temp = (i << 1)+1;
+		lane_enable |= ((lane_mask & 0x1) << temp);
+		lane_mask >>= 1;
+		i++;
+	}
+	msm_camera_io_w(lane_enable,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl5.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.addr);
+	lane_mask = csiphy_params->lane_mask & 0x7;
+	i = 0;
+	while (lane_mask & 0x7) {
+		if (!(lane_mask & 0x1)) {
+			i++;
+			lane_mask >>= 1;
+			continue;
+		}
+
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl21.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl21.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl26.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl26.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl27.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl27.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl1.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl1.addr + 0x200*i);
+		msm_camera_io_w(0,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl2.addr + 0x200*i);
+		msm_camera_io_w((csiphy_params->settle_cnt & 0xff),
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl3.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl5.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl5.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl6.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl6.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl7.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl7.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl8.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl8.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl9.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl9.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl10.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl10.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl11.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl11.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl12.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl12.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl15.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl15.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl16.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl16.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl17.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl17.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl18.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl18.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl19.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl19.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl24.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl24.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl28.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl28.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl29.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl29.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl30.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl30.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl33.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl33.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl34.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl34.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl35.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl35.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl36.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl36.addr + 0x200*i);
+
+		if (ULPM_WAKE_UP_TIMER_MODE == 0x22) {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_lnn_ctrl51.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.mipi_csiphy_3ph_lnn_ctrl51.addr +
+				0x200*i);
+		}
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl25.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl25.addr + 0x200*i);
+
+		lane_mask >>= 1;
+		i++;
+	}
+	if (csiphy_params->combo_mode == 1) {
+		msm_camera_io_w(0x2,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl7.addr);
+	} else {
+		msm_camera_io_w(0x6,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl7.addr);
+	}
+	/* Delay for stabilizing the regulator*/
+	usleep_range(10, 15);
+	msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params);
+	return 0;
+}
+
+static int msm_csiphy_3phase_lane_config_v50(
+	struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	uint8_t i = 0;
+	uint16_t lane_mask = 0, lane_enable = 0, temp;
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	lane_mask = csiphy_params->lane_mask & 0x7;
+	while (lane_mask != 0) {
+		temp = (i << 1)+1;
+		lane_enable |= ((lane_mask & 0x1) << temp);
+		lane_mask >>= 1;
+		i++;
+	}
+	msm_camera_io_w(lane_enable,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl5.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl7_cphy.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl7_cphy.addr);
+
+	lane_mask = csiphy_params->lane_mask & 0x7;
+	i = 0;
+	while (lane_mask & 0x7) {
+		if (!(lane_mask & 0x1)) {
+			i++;
+			lane_mask >>= 1;
+			continue;
+		}
+
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl23.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl26.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl26.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl27.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl27.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl1.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl1.addr + 0x200*i);
+		msm_camera_io_w((csiphy_params->settle_cnt & 0xff),
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl3.addr + 0x200*i);
+		msm_camera_io_w(0,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl2.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl5.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl5.addr + 0x200*i);
+		msm_camera_io_w(0,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl20.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl6.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl6.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl7.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl7.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl8.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl8.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl9.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl9.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl10.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl10.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl11.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl11.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl17.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl17.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl24.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl24.addr + 0x200*i);
+		if (ULPM_WAKE_UP_TIMER_MODE == 0x22) {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_lnn_ctrl51.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.mipi_csiphy_3ph_lnn_ctrl51.addr +
+				0x200*i);
+		}
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl25.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl25.addr + 0x200*i);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl55.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_lnn_ctrl55.addr + 0x200*i);
+
+		lane_mask >>= 1;
+		i++;
+	}
+	/* Delay for stabilizing the regulator*/
+	usleep_range(10, 15);
+	msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params);
+	return 0;
+}
+
+static int msm_csiphy_2phase_lane_config(
+	struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	uint32_t val = 0, lane_enable = 0, clk_lane, mask = 1;
+	uint16_t lane_mask = 0, i = 0, offset;
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	lane_mask = csiphy_params->lane_mask & 0x1f;
+	for (i = 0; i < MAX_DPHY_DATA_LN; i++) {
+		if (mask == 0x2) {
+			if (lane_mask & mask)
+				lane_enable |= 0x80;
+			i--;
+		} else if (lane_mask & mask)
+			lane_enable |= 0x1 << (i<<1);
+		mask <<= 1;
+	}
+	CDBG("%s:%d lane_enable: %d\n", __func__, __LINE__, lane_enable);
+
+	msm_camera_io_w(lane_enable,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl5.addr);
+	msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.data,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl6.addr);
+
+	for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) {
+		if (!(lane_mask & mask)) {
+			if (mask == 0x2)
+				i--;
+			mask <<= 0x1;
+			continue;
+		}
+		if (mask == 0x2) {
+			val = 4;
+			offset = CLOCK_OFFSET;
+			clk_lane = 1;
+			i--;
+		} else {
+			offset = 0x200*i;
+			val = 0;
+			clk_lane = 0;
+		}
+
+		if (csiphy_params->combo_mode == 1) {
+			val |= 0xA;
+			if (mask == csiphy_dev->ctrl_reg->
+				csiphy_reg.combo_clk_mask) {
+				val |= 0x4;
+				clk_lane = 1;
+			}
+		}
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg7.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg7.addr + offset);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg6.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg6.addr + offset);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg8.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg8.addr + offset);
+		msm_camera_io_w(val, csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_misc1.addr + offset);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_ctrl15.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_ctrl15.addr + offset);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg2.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg2.addr + offset);
+
+		msm_camera_io_w((csiphy_params->settle_cnt & 0xFF),
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_cfg3.addr + offset);
+
+		if (clk_lane == 1) {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_lnck_cfg1.data, csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_lnck_cfg1.addr);
+
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg4.data, csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg4.addr + offset);
+		} else {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg1.data,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg1.addr + offset);
+		}
+		if (csiphy_dev->hw_version == CSIPHY_VERSION_V342 &&
+			csiphy_params->combo_mode == 1) {
+			msm_camera_io_w(0x52,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg5.addr + offset);
+		} else {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg5.data,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg5.addr + offset);
+		}
+		if (clk_lane == 1 &&
+			csiphy_dev->hw_version == CSIPHY_VERSION_V342) {
+			msm_camera_io_w(0x1f,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg9.addr + offset);
+		} else {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg9.data,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg9.addr + offset);
+		}
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_test_imp.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnn_test_imp.addr + offset);
+		if (csiphy_dev->hw_version == CSIPHY_VERSION_V342) {
+			msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl5.data,
+				csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl5.addr + offset);
+		}
+		mask <<= 1;
+	}
+	if (csiphy_dev->hw_version == CSIPHY_VERSION_V342 &&
+		csiphy_params->combo_mode != 1) {
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl0.data,
+			csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl0.addr);
+	}
+	msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params);
+	return 0;
+}
+
+static int msm_csiphy_2phase_lane_config_v50(
+	struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	uint32_t lane_enable = 0, mask = 1;
+	uint16_t lane_mask = 0, i = 0, offset;
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	lane_mask = csiphy_params->lane_mask & 0x1f;
+
+	lane_enable = msm_camera_io_r(csiphybase +
+		csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl5.addr);
+
+    /* write settle count and lane_enable */
+	for (i = 0; i < MAX_DPHY_DATA_LN; i++) {
+		if (mask == 0x2) {
+			if (lane_mask & mask)
+				lane_enable |= 0x80;
+			i--;
+			offset = CLOCK_OFFSET;
+		} else if (lane_mask & mask) {
+			lane_enable |= 0x1 << (i<<1);
+			offset = 0x200*i;
+		}
+
+		if (lane_mask & mask)
+			msm_camera_io_w((csiphy_params->settle_cnt & 0xFF),
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg2.addr + offset);
+		mask <<= 1;
+	}
+	CDBG("%s:%d lane_enable: 0x%x\n", __func__, __LINE__, lane_enable);
+
+	msm_camera_io_w(lane_enable,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl5.addr);
+
+    /* write mode specific settings */
+	if (csiphy_params->combo_mode == 1)
+		msm_csiphy_write_settings(csiphy_dev,
+			csiphy_dev->ctrl_reg->csiphy_combo_mode_settings);
+	else {
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl6.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl6.addr);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl7.data,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl7.addr);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnck_ctrl10.data,
+			csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnck_ctrl10.addr);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnck_ctrl3.data, csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_2ph_lnck_ctrl3.addr);
+
+		for (i = 0, mask = 0x1; i < MAX_DPHY_DATA_LN; i++) {
+			if (!(lane_mask & mask)) {
+				if (mask == 0x2)
+					i--;
+				mask <<= 0x1;
+				continue;
+			}
+			if (mask == 0x2) {
+				offset = CLOCK_OFFSET;
+				i--;
+			} else {
+				offset = 0x200*i;
+			}
+
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl11.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl11.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl13.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl13.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg7.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg7.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg5.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg5.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl15.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl15.addr + offset);
+			if (mask == CLOCK_LANE) {
+				msm_camera_io_w(csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnck_ctrl0.data,
+					csiphybase + csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnck_ctrl0.addr);
+				msm_camera_io_w(csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnck_ctrl9.data,
+					csiphybase + csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnck_ctrl9.addr);
+			} else {
+				msm_camera_io_w(csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnn_ctrl0.data,
+					csiphybase + csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnn_ctrl0.addr +
+					offset);
+				msm_camera_io_w(csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnn_ctrl9.data,
+					csiphybase + csiphy_dev->ctrl_reg->
+					csiphy_3ph_reg.
+					mipi_csiphy_2ph_lnn_ctrl9.addr +
+					offset);
+			}
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg1.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg1.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg4.data, csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_cfg4.addr + offset);
+			msm_camera_io_w(csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl14.data,
+				csiphybase + csiphy_dev->ctrl_reg->
+				csiphy_3ph_reg.
+				mipi_csiphy_2ph_lnn_ctrl14.addr + offset);
+			mask <<= 1;
+		}
+	}
+	msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params);
+	return 0;
+}
+
+static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev,
+	struct msm_camera_csiphy_params *csiphy_params)
+{
+	int rc = 0;
+	int j = 0, curr_lane = 0;
+	uint32_t val = 0;
+	long clk_rate = 0;
+	uint8_t lane_cnt = 0;
+	uint16_t lane_mask = 0;
+	void __iomem *csiphybase;
+	uint8_t csiphy_id = csiphy_dev->pdev->id;
+	int32_t lane_val = 0, lane_right = 0, num_lanes = 0;
+	int ratio = 1;
+
+	csiphybase = csiphy_dev->base;
+	if (!csiphybase) {
+		pr_err("%s: csiphybase NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask;
+	lane_mask = csiphy_dev->lane_mask[csiphy_id];
+	lane_cnt = csiphy_params->lane_cnt;
+	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
+		pr_err("%s: unsupported lane cnt %d\n",
+			__func__, csiphy_params->lane_cnt);
+		return rc;
+	}
+
+	clk_rate = (csiphy_params->csiphy_clk > 0)
+			? csiphy_params->csiphy_clk :
+			csiphy_dev->csiphy_max_clk;
+	clk_rate = msm_camera_clk_set_rate(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_clk[csiphy_dev->csiphy_clk_index],
+		clk_rate);
+	if (clk_rate < 0) {
+		pr_err("csiphy_clk_set_rate failed\n");
+		return -EINVAL;
+	}
+
+	if (clk_rate < csiphy_dev->csiphy_max_clk &&
+		clk_rate > 0) {
+		ratio = csiphy_dev->csiphy_max_clk/clk_rate;
+		csiphy_params->settle_cnt = csiphy_params->settle_cnt/ratio;
+	}
+	CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n",
+		__func__,
+		csiphy_params->lane_mask,
+		csiphy_params->lane_cnt);
+	CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n",
+		__func__, csiphy_params->settle_cnt,
+		csiphy_params->csid_core);
+
+	if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30 &&
+		csiphy_dev->clk_mux_base != NULL &&
+		csiphy_dev->hw_version < CSIPHY_VERSION_V50) {
+		val = msm_camera_io_r(csiphy_dev->clk_mux_base);
+		if (csiphy_params->combo_mode &&
+			(csiphy_params->lane_mask & 0x18) == 0x18) {
+			val &= ~0xf0;
+			val |= csiphy_params->csid_core << 4;
+		} else {
+			val &= ~0xf;
+			val |= (uint32_t)csiphy_params->csid_core;
+		}
+		msm_camera_io_w(val, csiphy_dev->clk_mux_base);
+		CDBG("%s clk mux addr %pK val 0x%x\n", __func__,
+			csiphy_dev->clk_mux_base, val);
+		/* ensure write is done */
+		mb();
+	}
+
+	csiphy_dev->csi_3phase = csiphy_params->csi_3phase;
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) {
+		if (csiphy_dev->csi_3phase == 1) {
+			rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+				csiphy_dev->csiphy_3p_clk_info,
+				csiphy_dev->csiphy_3p_clk, 2, true);
+			if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V50)
+				rc = msm_csiphy_3phase_lane_config_v50(
+					csiphy_dev, csiphy_params);
+			else
+				rc = msm_csiphy_3phase_lane_config(csiphy_dev,
+					csiphy_params);
+			csiphy_dev->num_irq_registers = 20;
+		} else {
+			if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V50)
+				rc = msm_csiphy_2phase_lane_config_v50(
+					csiphy_dev, csiphy_params);
+			else
+				rc = msm_csiphy_2phase_lane_config(csiphy_dev,
+					csiphy_params);
+			csiphy_dev->num_irq_registers = 11;
+		}
+		if (rc < 0) {
+			pr_err("%s:%d: Error in setting lane configuration\n",
+				__func__, __LINE__);
+		}
+		return rc;
+	}
+
+	msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_glbl_t_init_cfg0_addr);
+	msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_t_wakeup_cfg0_addr);
+
+	if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
+		val = 0x3;
+		msm_camera_io_w((lane_mask << 2) | val,
+				csiphybase +
+				csiphy_dev->ctrl_reg->
+				csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr);
+		msm_camera_io_w(0x10, csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg2_addr);
+		msm_camera_io_w(csiphy_params->settle_cnt,
+			csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg3_addr);
+		msm_camera_io_w(0x24,
+			csiphybase + csiphy_dev->ctrl_reg->
+			csiphy_reg.mipi_csiphy_interrupt_mask0_addr);
+		msm_camera_io_w(0x24,
+			csiphybase + csiphy_dev->ctrl_reg->
+			csiphy_reg.mipi_csiphy_interrupt_clear0_addr);
+	} else {
+		val = 0x1;
+		msm_camera_io_w((lane_mask << 1) | val,
+				csiphybase +
+				csiphy_dev->ctrl_reg->
+				csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr);
+		msm_camera_io_w(csiphy_params->combo_mode <<
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_mode_config_shift,
+			csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_glbl_reset_addr);
+	}
+
+	lane_mask &= 0x1f;
+	while (lane_mask & 0x1f) {
+		if (!(lane_mask & 0x1)) {
+			j++;
+			lane_mask >>= 1;
+			continue;
+		}
+		msm_camera_io_w(0x10,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnn_cfg2_addr + 0x40*j);
+		msm_camera_io_w(csiphy_params->settle_cnt,
+			csiphybase + csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnn_cfg3_addr + 0x40*j);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_mask_val, csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_mask_addr + 0x4*j);
+		msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_mask_val, csiphybase +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_clear_addr + 0x4*j);
+		if (csiphy_dev->is_3_1_20nm_hw == 1) {
+			if (j > CLK_LANE_OFFSET) {
+				lane_right = 0x8;
+				num_lanes = (lane_cnt - curr_lane)
+					<< NUM_LANES_OFFSET;
+				if (lane_cnt < curr_lane) {
+					pr_err("%s: Lane_cnt is less than curr_lane number\n",
+						__func__);
+					return -EINVAL;
+				}
+				lane_val = lane_right|num_lanes;
+			} else if (j == 1) {
+				lane_val = 0x4;
+			}
+			if (csiphy_params->combo_mode == 1) {
+				/*
+				 * In the case of combo mode, the clock is
+				 * always 4th lane for the second sensor.
+				 * So check whether the sensor is of one lane
+				 * sensor and curr_lane for 0.
+				 */
+				if (curr_lane == 0 &&
+					((csiphy_params->lane_mask &
+						0x18) == 0x18))
+					lane_val = 0x4;
+			}
+			msm_camera_io_w(lane_val, csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_reg.
+				mipi_csiphy_lnn_misc1_addr + 0x40*j);
+			msm_camera_io_w(0x17, csiphybase +
+				csiphy_dev->ctrl_reg->csiphy_reg.
+				mipi_csiphy_lnn_test_imp + 0x40*j);
+			curr_lane++;
+		}
+		j++;
+		lane_mask >>= 1;
+	}
+	return rc;
+}
+
+static void msm_csiphy_disable_irq(
+	struct csiphy_device *csiphy_dev)
+{
+	void __iomem *csiphybase;
+
+	csiphybase = csiphy_dev->base;
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl11.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl12.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl13.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl14.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl15.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl16.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl17.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl18.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl19.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl20.addr);
+	msm_camera_io_w(0,
+		csiphybase + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl21.addr);
+}
+
+static irqreturn_t msm_csiphy_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	int i;
+	struct csiphy_device *csiphy_dev = data;
+
+	if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_ENABLE) {
+		if (csiphy_dev->csiphy_sof_debug_count < CSIPHY_SOF_DEBUG_COUNT)
+			csiphy_dev->csiphy_sof_debug_count++;
+		else {
+			msm_csiphy_disable_irq(csiphy_dev);
+			return IRQ_HANDLED;
+		}
+	}
+
+	for (i = 0; i < csiphy_dev->num_irq_registers; i++) {
+		irq = msm_camera_io_r(
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_status0_addr + 0x4*i);
+		msm_camera_io_w(irq,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_clear0_addr + 0x4*i);
+		pr_err_ratelimited(
+			"%s CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x\n",
+			__func__, csiphy_dev->pdev->id, i, irq);
+		msm_camera_io_w(0x0,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_clear0_addr + 0x4*i);
+	}
+	msm_camera_io_w(0x1, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
+	msm_camera_io_w(0x0, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
+	return IRQ_HANDLED;
+}
+
+static void msm_csiphy_reset(struct csiphy_device *csiphy_dev)
+{
+	msm_camera_io_w(0x1, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr);
+	usleep_range(5000, 8000);
+	msm_camera_io_w(0x0, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr);
+}
+
+static void msm_csiphy_3ph_reset(struct csiphy_device *csiphy_dev)
+{
+	msm_camera_io_w(0x1, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl0.addr);
+	usleep_range(5000, 8000);
+	msm_camera_io_w(0x0, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+		mipi_csiphy_3ph_cmn_ctrl0.addr);
+}
+
+#if DBG_CSIPHY
+static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
+{
+	int rc = 0;
+
+	if (csiphy_dev == NULL) {
+		pr_err("%s: csiphy_dev NULL\n", __func__);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (csiphy_dev->ref_count++) {
+		CDBG("%s csiphy refcount = %d\n", __func__,
+			csiphy_dev->ref_count);
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		csiphy_dev->ref_count--;
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csiphy config_vreg failed\n",
+			__func__, __LINE__);
+		goto csiphy_vreg_config_fail;
+	}
+	rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csiphy enable_vreg failed\n",
+			__func__, __LINE__);
+		goto top_vreg_enable_failed;
+	}
+
+	rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, true);
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (rc < 0) {
+		pr_err("%s: csiphy clk enable failed\n", __func__);
+		csiphy_dev->ref_count--;
+		goto csiphy_enable_clk_fail;
+	}
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	rc = msm_camera_enable_irq(csiphy_dev->irq, true);
+	if (rc < 0)
+		pr_err("%s: irq enable failed\n", __func__);
+
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW)
+		msm_csiphy_3ph_reset(csiphy_dev);
+	else
+		msm_csiphy_reset(csiphy_dev);
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30)
+		csiphy_dev->hw_version =
+			msm_camera_io_r(csiphy_dev->base +
+				 csiphy_dev->ctrl_reg->
+				 csiphy_reg.mipi_csiphy_hw_version_addr);
+	else
+		csiphy_dev->hw_version = csiphy_dev->hw_dts_version;
+
+	CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__,
+		csiphy_dev->hw_version);
+	csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
+	return 0;
+
+csiphy_enable_clk_fail:
+	msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+top_vreg_enable_failed:
+	msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+csiphy_vreg_config_fail:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to vote for AHB\n", __func__);
+	return rc;
+}
+#else
+static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
+{
+	int rc = 0;
+
+	if (csiphy_dev == NULL) {
+		pr_err("%s: csiphy_dev NULL\n", __func__);
+		rc = -ENOMEM;
+		return rc;
+	}
+	csiphy_dev->csiphy_sof_debug_count = 0;
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (csiphy_dev->ref_count++) {
+		CDBG("%s csiphy refcount = %d\n", __func__,
+			csiphy_dev->ref_count);
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		rc = -EINVAL;
+		return rc;
+	}
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+			CAM_AHB_SVS_VOTE);
+	if (rc < 0) {
+		csiphy_dev->ref_count--;
+		pr_err("%s: failed to vote for AHB\n", __func__);
+		return rc;
+	}
+	rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csiphy config_vreg failed\n",
+			__func__, __LINE__);
+		goto csiphy_vreg_config_fail;
+	}
+	rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d csiphy enable_vreg failed\n",
+			__func__, __LINE__);
+		goto top_vreg_enable_failed;
+	}
+
+	rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, true);
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (rc < 0) {
+		pr_err("%s: csiphy clk enable failed\n", __func__);
+		csiphy_dev->ref_count--;
+		goto csiphy_enable_clk_fail;
+	}
+	CDBG("%s:%d clk enable success\n", __func__, __LINE__);
+
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW)
+		msm_csiphy_3ph_reset(csiphy_dev);
+	else
+		msm_csiphy_reset(csiphy_dev);
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30)
+		csiphy_dev->hw_version =
+			msm_camera_io_r(csiphy_dev->base +
+				 csiphy_dev->ctrl_reg->
+				 csiphy_reg.mipi_csiphy_hw_version_addr);
+	else
+		csiphy_dev->hw_version = csiphy_dev->hw_dts_version;
+
+	csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE;
+	CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__,
+		csiphy_dev->hw_version);
+	csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
+	return 0;
+
+csiphy_enable_clk_fail:
+	msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+top_vreg_enable_failed:
+	msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+csiphy_vreg_config_fail:
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+		CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to vote for AHB\n", __func__);
+	return rc;
+}
+#endif
+
+#if DBG_CSIPHY
+static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
+{
+	int i = 0;
+	int rc = 0;
+	struct msm_camera_csi_lane_params *csi_lane_params;
+	uint16_t csi_lane_mask;
+
+	csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
+
+	if (!csiphy_dev || !csiphy_dev->ref_count) {
+		pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
+		return 0;
+	}
+
+	if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		return -EINVAL;
+	}
+
+	if (--csiphy_dev->ref_count) {
+		CDBG("%s csiphy refcount = %d\n", __func__,
+			csiphy_dev->ref_count);
+		return 0;
+	}
+
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) {
+		msm_camera_io_w(0x0,
+			csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl5.addr);
+		msm_camera_io_w(0x0,
+			csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl6.addr);
+		if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V50)
+			msm_camera_io_w(0x0,
+				csiphy_dev->base +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_cmn_ctrl7.addr);
+	} else if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
+		csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
+		for (i = 0; i < 4; i++)
+			msm_camera_io_w(0x0, csiphy_dev->base +
+				csiphy_dev->ctrl_reg->csiphy_reg.
+				mipi_csiphy_lnn_cfg2_addr + 0x40*i);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg2_addr);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_glbl_pwr_cfg_addr);
+	} else {
+		if (!csi_lane_params) {
+			pr_err("%s:%d failed: csi_lane_params %pK\n", __func__,
+				__LINE__, csi_lane_params);
+			return -EINVAL;
+		}
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
+
+		CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n",
+			__func__,
+			csi_lane_params->csi_lane_assign,
+			csi_lane_params->csi_lane_mask);
+
+		if (!csi_lane_mask)
+			csi_lane_mask = 0x1f;
+
+		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
+			~(csi_lane_mask);
+		i = 0;
+		while (csi_lane_mask) {
+			if (csi_lane_mask & 0x1) {
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_cfg2_addr + 0x40*i);
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_misc1_addr + 0x40*i);
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_test_imp + 0x40*i);
+			}
+			csi_lane_mask >>= 1;
+			i++;
+		}
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg2_addr);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_glbl_pwr_cfg_addr);
+	}
+
+	rc = msm_camera_enable_irq(csiphy_dev->irq, false);
+
+	msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, false);
+
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW &&
+		csiphy_dev->csi_3phase == 1) {
+		msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_dev->csiphy_3p_clk_info,
+			csiphy_dev->csiphy_3p_clk, 2, false);
+	}
+
+	msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->regulator_count, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+	msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+		NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
+	csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+		 CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return 0;
+}
+#else
+static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
+{
+	int i = 0, rc = 0;
+	struct msm_camera_csi_lane_params *csi_lane_params;
+	uint16_t csi_lane_mask;
+
+	csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
+
+	if (!csiphy_dev || !csiphy_dev->ref_count) {
+		pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
+		return 0;
+	}
+
+	if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) {
+		pr_err("%s: csiphy invalid state %d\n", __func__,
+			csiphy_dev->csiphy_state);
+		return -EINVAL;
+	}
+
+	if (--csiphy_dev->ref_count) {
+		CDBG("%s csiphy refcount = %d\n", __func__,
+			csiphy_dev->ref_count);
+		return 0;
+	}
+
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW) {
+		msm_camera_io_w(0x0,
+			csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl5.addr);
+		msm_camera_io_w(0x0,
+			csiphy_dev->base + csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+			mipi_csiphy_3ph_cmn_ctrl6.addr);
+		if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V50)
+			msm_camera_io_w(0x0,
+				csiphy_dev->base +
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg.
+				mipi_csiphy_3ph_cmn_ctrl7.addr);
+	} else	if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
+		csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
+		for (i = 0; i < 4; i++)
+			msm_camera_io_w(0x0, csiphy_dev->base +
+				csiphy_dev->ctrl_reg->csiphy_reg.
+				mipi_csiphy_lnn_cfg2_addr + 0x40*i);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg2_addr);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_glbl_pwr_cfg_addr);
+	} else {
+		if (!csi_lane_params) {
+			pr_err("%s:%d failed: csi_lane_params %pK\n", __func__,
+				__LINE__, csi_lane_params);
+			return -EINVAL;
+		}
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
+
+		CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n",
+			__func__,
+			csi_lane_params->csi_lane_assign,
+			csi_lane_params->csi_lane_mask);
+
+		if (!csi_lane_mask)
+			csi_lane_mask = 0x1f;
+
+		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
+			~(csi_lane_mask);
+		i = 0;
+		while (csi_lane_mask) {
+			if (csi_lane_mask & 0x1) {
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_cfg2_addr + 0x40*i);
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_misc1_addr + 0x40*i);
+				msm_camera_io_w(0x0, csiphy_dev->base +
+					csiphy_dev->ctrl_reg->csiphy_reg.
+					mipi_csiphy_lnn_test_imp + 0x40*i);
+			}
+			csi_lane_mask >>= 1;
+			i++;
+		}
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_lnck_cfg2_addr);
+		msm_camera_io_w(0x0, csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_glbl_pwr_cfg_addr);
+	}
+	if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_ENABLE)
+		rc = msm_camera_enable_irq(csiphy_dev->irq, false);
+
+	msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, false);
+	if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW &&
+		csiphy_dev->csi_3phase == 1) {
+		msm_camera_clk_enable(&csiphy_dev->pdev->dev,
+			csiphy_dev->csiphy_3p_clk_info,
+			csiphy_dev->csiphy_3p_clk, 2, false);
+	}
+
+	msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+		NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+	msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+		csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+		NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
+	csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
+
+	if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
+		 CAM_AHB_SUSPEND_VOTE) < 0)
+		pr_err("%s: failed to remove vote for AHB\n", __func__);
+	return 0;
+}
+
+#endif
+static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg)
+{
+	int rc = 0;
+	struct csiphy_cfg_data *cdata = (struct csiphy_cfg_data *)arg;
+	struct msm_camera_csiphy_params csiphy_params;
+	struct msm_camera_csi_lane_params csi_lane_params;
+
+	if (!csiphy_dev || !cdata) {
+		pr_err("%s: csiphy_dev NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (cdata->cfgtype) {
+	case CSIPHY_INIT:
+		rc = msm_csiphy_init(csiphy_dev);
+		break;
+	case CSIPHY_CFG:
+		if (copy_from_user(&csiphy_params,
+			(void __user *)cdata->cfg.csiphy_params,
+			sizeof(struct msm_camera_csiphy_params))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE;
+		rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params);
+		break;
+	case CSIPHY_RELEASE:
+		if (copy_from_user(&csi_lane_params,
+			(void __user *)cdata->cfg.csi_lane_params,
+			sizeof(struct msm_camera_csi_lane_params))) {
+			pr_err("%s: %d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		rc = msm_csiphy_release(csiphy_dev, &csi_lane_params);
+		break;
+	default:
+		pr_err("%s: %d failed\n", __func__, __LINE__);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	return rc;
+}
+
+static int32_t msm_csiphy_get_subdev_id(struct csiphy_device *csiphy_dev,
+	void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	if (!subdev_id) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	*subdev_id = csiphy_dev->pdev->id;
+	pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id);
+	return 0;
+}
+
+static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = -ENOIOCTLCMD;
+	struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd);
+
+	if (!csiphy_dev) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return  -EINVAL;
+	}
+	mutex_lock(&csiphy_dev->mutex);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		rc = msm_csiphy_get_subdev_id(csiphy_dev, arg);
+		break;
+	case VIDIOC_MSM_CSIPHY_IO_CFG:
+		rc = msm_csiphy_cmd(csiphy_dev, arg);
+		break;
+	case VIDIOC_MSM_CSIPHY_RELEASE:
+	case MSM_SD_SHUTDOWN:
+		rc = msm_csiphy_release(csiphy_dev, arg);
+		break;
+	case MSM_SD_NOTIFY_FREEZE:
+		if (!csiphy_dev || !csiphy_dev->ctrl_reg ||
+				!csiphy_dev->ref_count)
+			break;
+		if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_DISABLE) {
+			csiphy_dev->csiphy_sof_debug = SOF_DEBUG_ENABLE;
+			rc = msm_camera_enable_irq(csiphy_dev->irq, true);
+		}
+		break;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		if (!csiphy_dev || !csiphy_dev->ctrl_reg ||
+				!csiphy_dev->ref_count)
+			break;
+		csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE;
+		rc = msm_camera_enable_irq(csiphy_dev->irq, false);
+		break;
+	default:
+		pr_err_ratelimited("%s: command not found\n", __func__);
+	}
+	mutex_unlock(&csiphy_dev->mutex);
+	CDBG("%s:%d\n", __func__, __LINE__);
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_csiphy_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct csiphy_cfg_data32 *u32 =
+		(struct csiphy_cfg_data32 *)arg;
+	struct csiphy_cfg_data csiphy_data;
+
+	switch (cmd) {
+	case VIDIOC_MSM_CSIPHY_IO_CFG32:
+		cmd = VIDIOC_MSM_CSIPHY_IO_CFG;
+		csiphy_data.cfgtype = u32->cfgtype;
+		csiphy_data.cfg.csiphy_params =
+			compat_ptr(u32->cfg.csiphy_params);
+		return msm_csiphy_subdev_ioctl(sd, cmd, &csiphy_data);
+	default:
+		return msm_csiphy_subdev_ioctl(sd, cmd, arg);
+	}
+}
+
+static long msm_csiphy_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_csiphy_subdev_do_ioctl);
+}
+#endif
+
+static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops;
+
+static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = {
+	.ioctl = &msm_csiphy_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = {
+	.core = &msm_csiphy_subdev_core_ops,
+};
+
+static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev,
+	struct platform_device *pdev)
+{
+	int i, rc = 0;
+	char *csi_3p_clk_name = "csi_phy_3p_clk";
+	char *csi_3p_clk_src_name = "csiphy_3p_clk_src";
+	uint32_t clk_cnt = 0;
+
+	rc = msm_camera_get_clk_info(csiphy_dev->pdev,
+		&csiphy_dev->csiphy_all_clk_info,
+		&csiphy_dev->csiphy_all_clk,
+		&csiphy_dev->num_all_clk);
+	if (rc < 0) {
+		pr_err("%s:%d, failed\n", __func__, __LINE__);
+		return rc;
+	}
+	if (csiphy_dev->num_all_clk > CSIPHY_NUM_CLK_MAX) {
+		pr_err("%s: invalid count=%zu, max is %d\n", __func__,
+			csiphy_dev->num_all_clk, CSIPHY_NUM_CLK_MAX);
+		rc = -EINVAL;
+		goto MAX_CLK_ERROR;
+	}
+
+	for (i = 0; i < csiphy_dev->num_all_clk; i++) {
+		if (!strcmp(csiphy_dev->csiphy_all_clk_info[i].clk_name,
+			csi_3p_clk_src_name)) {
+			csiphy_dev->csiphy_3p_clk_info[0].clk_name =
+				csiphy_dev->csiphy_all_clk_info[i].clk_name;
+			csiphy_dev->csiphy_3p_clk_info[0].clk_rate =
+				csiphy_dev->csiphy_all_clk_info[i].clk_rate;
+			csiphy_dev->csiphy_3p_clk[0] =
+				csiphy_dev->csiphy_all_clk[i];
+			continue;
+		} else if (!strcmp(csiphy_dev->csiphy_all_clk_info[i].clk_name,
+					csi_3p_clk_name)) {
+			csiphy_dev->csiphy_3p_clk_info[1].clk_name =
+				csiphy_dev->csiphy_all_clk_info[i].clk_name;
+			csiphy_dev->csiphy_3p_clk_info[1].clk_rate =
+				csiphy_dev->csiphy_all_clk_info[i].clk_rate;
+			csiphy_dev->csiphy_3p_clk[1] =
+				csiphy_dev->csiphy_all_clk[i];
+			continue;
+		}
+		csiphy_dev->csiphy_clk_info[clk_cnt].clk_name =
+			csiphy_dev->csiphy_all_clk_info[i].clk_name;
+		csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate =
+			csiphy_dev->csiphy_all_clk_info[i].clk_rate;
+		csiphy_dev->csiphy_clk[clk_cnt] =
+			csiphy_dev->csiphy_all_clk[clk_cnt];
+		if (!strcmp(csiphy_dev->csiphy_clk_info[clk_cnt].clk_name,
+				"csiphy_timer_src_clk")) {
+			CDBG("%s:%d, copy csiphy_timer_src_clk",
+				__func__, __LINE__);
+			csiphy_dev->csiphy_max_clk =
+				csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate;
+			csiphy_dev->csiphy_clk_index = clk_cnt;
+		}
+		CDBG("%s: clk_rate[%d] = %ld\n", __func__, clk_cnt,
+			csiphy_dev->csiphy_clk_info[clk_cnt].clk_rate);
+		clk_cnt++;
+	}
+
+	csiphy_dev->num_clk = clk_cnt;
+	return rc;
+MAX_CLK_ERROR:
+	msm_camera_put_clk_info(csiphy_dev->pdev,
+		&csiphy_dev->csiphy_all_clk_info,
+		&csiphy_dev->csiphy_all_clk,
+		csiphy_dev->num_all_clk);
+
+	return rc;
+}
+
+static int csiphy_probe(struct platform_device *pdev)
+{
+	struct csiphy_device *new_csiphy_dev;
+	int rc = 0;
+
+	new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
+	if (!new_csiphy_dev)
+		return -ENOMEM;
+	new_csiphy_dev->is_3_1_20nm_hw = 0;
+	new_csiphy_dev->ctrl_reg = NULL;
+	new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t),
+		GFP_KERNEL);
+	if (!new_csiphy_dev->ctrl_reg)
+		return -ENOMEM;
+	v4l2_subdev_init(&new_csiphy_dev->msm_sd.sd, &msm_csiphy_subdev_ops);
+	v4l2_set_subdevdata(&new_csiphy_dev->msm_sd.sd, new_csiphy_dev);
+	platform_set_drvdata(pdev, &new_csiphy_dev->msm_sd.sd);
+
+	mutex_init(&new_csiphy_dev->mutex);
+
+	if (pdev->dev.of_node) {
+		of_property_read_u32((&pdev->dev)->of_node,
+			"cell-index", &pdev->id);
+		CDBG("%s: device id = %d\n", __func__, pdev->id);
+	}
+
+	new_csiphy_dev->pdev = pdev;
+	new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops;
+	new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(new_csiphy_dev->msm_sd.sd.name,
+		ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy");
+	media_entity_pads_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL);
+	new_csiphy_dev->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_CSIPHY;
+	new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4;
+	msm_sd_register(&new_csiphy_dev->msm_sd);
+
+	new_csiphy_dev->csiphy_3phase = 0;
+	new_csiphy_dev->num_irq_registers = 0x8;
+
+	if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v2.0")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V20;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v2.2")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_2;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V22;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.0")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_0;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V30;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.1")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.1.1")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31;
+		new_csiphy_dev->is_3_1_20nm_hw = 1;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.2")) {
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_2;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V32;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.4.2")) {
+		new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v3_4_2_3ph;
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_4_2;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V342;
+		new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v3.5")) {
+		new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v3_5_3ph;
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_5;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V35;
+		new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v5.0")) {
+		new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v5_0_3ph;
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v5_0;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V50;
+		new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW;
+		new_csiphy_dev->ctrl_reg->csiphy_combo_mode_settings =
+			csiphy_combo_mode_v5_0;
+	} else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node,
+		"qcom,csiphy-v5.01")) {
+		new_csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_v5_0_1_3ph;
+		new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v5_0_1;
+		new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V501;
+		new_csiphy_dev->csiphy_3phase = CSI_3PHASE_HW;
+		new_csiphy_dev->ctrl_reg->csiphy_combo_mode_settings =
+			csiphy_combo_mode_v5_0_1;
+	} else {
+		pr_err("%s:%d, invalid hw version : 0x%x\n", __func__, __LINE__,
+		new_csiphy_dev->hw_dts_version);
+		rc =  -EINVAL;
+		goto csiphy_no_resource;
+	}
+
+	rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+		&(new_csiphy_dev->csiphy_vreg),
+		&(new_csiphy_dev->regulator_count));
+	if (rc < 0) {
+		pr_err("%s: get vreg data from dtsi fail\n", __func__);
+		rc = -EFAULT;
+		goto csiphy_no_resource;
+	}
+	/* ToDo: Enable 3phase clock for dynamic clock enable/disable */
+	rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev);
+	if (rc < 0) {
+		pr_err("%s: msm_csiphy_get_clk_info() failed", __func__);
+		rc =  -EFAULT;
+		goto csiphy_no_resource;
+	}
+
+	new_csiphy_dev->base = msm_camera_get_reg_base(pdev, "csiphy", true);
+	if (!new_csiphy_dev->base) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_resource;
+	}
+
+	if (new_csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) {
+		new_csiphy_dev->clk_mux_base = msm_camera_get_reg_base(pdev,
+					"csiphy_clk_mux", true);
+		if (!new_csiphy_dev->clk_mux_base)
+			pr_err("%s: no mem resource?\n", __func__);
+	}
+	new_csiphy_dev->irq = msm_camera_get_irq(pdev, "csiphy");
+	if (!new_csiphy_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_irq_resource;
+	}
+	rc = msm_camera_register_irq(pdev, new_csiphy_dev->irq,
+		msm_csiphy_irq, IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev);
+	if (rc < 0) {
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csiphy_no_irq_resource;
+	}
+	msm_camera_enable_irq(new_csiphy_dev->irq, false);
+
+	msm_cam_copy_v4l2_subdev_fops(&msm_csiphy_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_csiphy_v4l2_subdev_fops.compat_ioctl32 =
+		msm_csiphy_subdev_fops_ioctl;
+#endif
+	new_csiphy_dev->msm_sd.sd.devnode->fops =
+		&msm_csiphy_v4l2_subdev_fops;
+	new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
+	return 0;
+
+csiphy_no_irq_resource:
+	if (new_csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) {
+		msm_camera_put_reg_base(pdev, new_csiphy_dev->clk_mux_base,
+			"csiphy_clk_mux", true);
+	}
+	msm_camera_put_reg_base(pdev, new_csiphy_dev->base, "csiphy", true);
+csiphy_no_resource:
+	mutex_destroy(&new_csiphy_dev->mutex);
+	kfree(new_csiphy_dev->ctrl_reg);
+	kfree(new_csiphy_dev);
+	return rc;
+}
+
+static int msm_csiphy_exit(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct csiphy_device *csiphy_dev =
+		v4l2_get_subdevdata(subdev);
+
+	msm_camera_put_clk_info(pdev,
+		&csiphy_dev->csiphy_all_clk_info,
+		&csiphy_dev->csiphy_all_clk,
+		csiphy_dev->num_all_clk);
+
+	msm_camera_put_reg_base(pdev, csiphy_dev->base, "csiphy", true);
+	if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) {
+		msm_camera_put_reg_base(pdev, csiphy_dev->clk_mux_base,
+			"csiphy_clk_mux", true);
+	}
+	kfree(csiphy_dev);
+	return 0;
+}
+
+static const struct of_device_id msm_csiphy_dt_match[] = {
+	{.compatible = "qcom,csiphy"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match);
+
+static struct platform_driver csiphy_driver = {
+	.probe = csiphy_probe,
+	.remove = msm_csiphy_exit,
+	.driver = {
+		.name = MSM_CSIPHY_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_csiphy_dt_match,
+	},
+};
+
+static int __init msm_csiphy_init_module(void)
+{
+	return platform_driver_register(&csiphy_driver);
+}
+
+static void __exit msm_csiphy_exit_module(void)
+{
+	platform_driver_unregister(&csiphy_driver);
+}
+
+module_init(msm_csiphy_init_module);
+module_exit(msm_csiphy_exit_module);
+MODULE_DESCRIPTION("MSM CSIPHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
new file mode 100644
index 0000000..bc8f2d9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
@@ -0,0 +1,197 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_H
+#define MSM_CSIPHY_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_cam_sensor.h>
+#include "msm_sd.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+#include "cam_soc_api.h"
+
+#define MAX_CSIPHY 3
+#define CSIPHY_NUM_CLK_MAX  16
+#define MAX_CSIPHY_SETTINGS 120
+
+struct csiphy_reg_t {
+	uint32_t addr;
+	uint32_t data;
+};
+
+struct csiphy_settings_t {
+	struct csiphy_reg_t settings[MAX_CSIPHY_SETTINGS];
+};
+
+struct csiphy_reg_parms_t {
+/*MIPI CSI PHY registers*/
+	uint32_t mipi_csiphy_lnn_cfg1_addr;
+	uint32_t mipi_csiphy_lnn_cfg2_addr;
+	uint32_t mipi_csiphy_lnn_cfg3_addr;
+	uint32_t mipi_csiphy_lnn_cfg4_addr;
+	uint32_t mipi_csiphy_lnn_cfg5_addr;
+	uint32_t mipi_csiphy_lnck_cfg1_addr;
+	uint32_t mipi_csiphy_lnck_cfg2_addr;
+	uint32_t mipi_csiphy_lnck_cfg3_addr;
+	uint32_t mipi_csiphy_lnck_cfg4_addr;
+	uint32_t mipi_csiphy_lnn_test_imp;
+	uint32_t mipi_csiphy_lnn_misc1_addr;
+	uint32_t mipi_csiphy_glbl_reset_addr;
+	uint32_t mipi_csiphy_glbl_pwr_cfg_addr;
+	uint32_t mipi_csiphy_glbl_irq_cmd_addr;
+	uint32_t mipi_csiphy_hw_version_addr;
+	uint32_t mipi_csiphy_interrupt_status0_addr;
+	uint32_t mipi_csiphy_interrupt_mask0_addr;
+	uint32_t mipi_csiphy_interrupt_mask_val;
+	uint32_t mipi_csiphy_interrupt_mask_addr;
+	uint32_t mipi_csiphy_interrupt_clear0_addr;
+	uint32_t mipi_csiphy_interrupt_clear_addr;
+	uint32_t mipi_csiphy_mode_config_shift;
+	uint32_t mipi_csiphy_glbl_t_init_cfg0_addr;
+	uint32_t mipi_csiphy_t_wakeup_cfg0_addr;
+	uint32_t csiphy_version;
+	uint32_t combo_clk_mask;
+};
+
+struct csiphy_reg_3ph_parms_t {
+/*MIPI CSI PHY registers*/
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl5;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl6;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl34;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl35;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl36;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl1;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl2;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl3;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl5;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl6;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl7;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl8;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl9;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl10;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl11;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl12;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl13;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl14;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl15;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl16;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl17;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl18;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl19;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl21;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl23;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl24;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl25;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl26;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl27;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl28;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl29;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl30;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl31;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl32;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl33;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl51;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl11;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl12;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl13;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl14;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl15;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl16;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl17;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl18;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl19;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl20;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl21;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_misc1;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl0;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg1;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg2;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg3;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg4;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg5;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg6;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg7;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg8;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_cfg9;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl15;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_test_imp;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_test_force;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl5;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnck_cfg1;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl20;
+	struct csiphy_reg_t mipi_csiphy_3ph_lnn_ctrl55;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl11;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl13;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl10;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl0;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl3;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl14;
+	struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7_cphy;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl0;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl9;
+	struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl9;
+};
+
+struct csiphy_ctrl_t {
+	struct csiphy_reg_parms_t csiphy_reg;
+	struct csiphy_reg_3ph_parms_t csiphy_3ph_reg;
+	struct csiphy_settings_t csiphy_combo_mode_settings;
+};
+
+enum msm_csiphy_state_t {
+	CSIPHY_POWER_UP,
+	CSIPHY_POWER_DOWN,
+};
+
+struct csiphy_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *irq;
+	void __iomem *base;
+	void __iomem *clk_mux_base;
+	struct mutex mutex;
+	uint32_t hw_version;
+	uint32_t hw_dts_version;
+	enum msm_csiphy_state_t csiphy_state;
+	struct csiphy_ctrl_t *ctrl_reg;
+	size_t num_all_clk;
+	struct clk **csiphy_all_clk;
+	struct msm_cam_clk_info *csiphy_all_clk_info;
+	uint32_t num_clk;
+	struct clk *csiphy_clk[CSIPHY_NUM_CLK_MAX];
+	struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX];
+	struct clk *csiphy_3p_clk[2];
+	struct msm_cam_clk_info csiphy_3p_clk_info[2];
+	unsigned char csi_3phase;
+	int32_t ref_count;
+	uint16_t lane_mask[MAX_CSIPHY];
+	uint32_t is_3_1_20nm_hw;
+	uint32_t csiphy_clk_index;
+	uint32_t csiphy_max_clk;
+	uint8_t csiphy_3phase;
+	uint8_t num_irq_registers;
+	uint32_t csiphy_sof_debug;
+	uint32_t csiphy_sof_debug_count;
+	struct camera_vreg_t *csiphy_vreg;
+	struct regulator *csiphy_reg_ptr[MAX_REGULATOR];
+	int32_t regulator_count;
+};
+
+#define VIDIOC_MSM_CSIPHY_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *)
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/Makefile b/drivers/media/platform/msm/camera_v2/sensor/eeprom/Makefile
new file mode 100644
index 0000000..ba78a65
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_MSM_EEPROM) += msm_eeprom.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
new file mode 100644
index 0000000..cd16236
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -0,0 +1,1887 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include "msm_sd.h"
+#include "msm_cci.h"
+#include "msm_eeprom.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+DEFINE_MSM_MUTEX(msm_eeprom_mutex);
+#ifdef CONFIG_COMPAT
+static struct v4l2_file_operations msm_eeprom_v4l2_subdev_fops;
+#endif
+
+/*
+ * msm_get_read_mem_size - Get the total size for allocation
+ * @eeprom_map_array:	mem map
+ *
+ * Returns size after computation size, returns error in case of error
+ */
+static int msm_get_read_mem_size
+	(struct msm_eeprom_memory_map_array *eeprom_map_array) {
+	int size = 0, i, j;
+	struct msm_eeprom_mem_map_t *eeprom_map;
+
+	if (eeprom_map_array->msm_size_of_max_mappings >
+		MSM_EEPROM_MAX_MEM_MAP_CNT) {
+		pr_err("%s:%d Memory map cnt greter then expected: %d",
+			__func__, __LINE__,
+			eeprom_map_array->msm_size_of_max_mappings);
+		return -EINVAL;
+	}
+	for (j = 0; j < eeprom_map_array->msm_size_of_max_mappings; j++) {
+		eeprom_map = &(eeprom_map_array->memory_map[j]);
+		if (eeprom_map->memory_map_size >
+			MSM_EEPROM_MEMORY_MAP_MAX_SIZE) {
+			pr_err("%s:%d Memory map size greter then expected: %d",
+				__func__, __LINE__,
+				eeprom_map->memory_map_size);
+			return -EINVAL;
+		}
+		for (i = 0; i < eeprom_map->memory_map_size; i++) {
+			if (eeprom_map->mem_settings[i].i2c_operation ==
+				MSM_CAM_READ) {
+				size += eeprom_map->mem_settings[i].reg_data;
+			}
+		}
+	}
+	CDBG("Total Data Size: %d\n", size);
+	return size;
+}
+
+/*
+ * msm_eeprom_verify_sum - verify crc32 checksum
+ * @mem:	data buffer
+ * @size:	size of data buffer
+ * @sum:	expected checksum
+ *
+ * Returns 0 if checksum match, -EINVAL otherwise.
+ */
+static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum)
+{
+	uint32_t crc = ~0;
+
+	/* check overflow */
+	if (size > crc - sizeof(uint32_t))
+		return -EINVAL;
+
+	crc = crc32_le(crc, mem, size);
+	if (~crc != sum) {
+		CDBG("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc);
+		return -EINVAL;
+	}
+	CDBG("%s: checksum pass 0x%x\n", __func__, sum);
+	return 0;
+}
+
+/*
+ * msm_eeprom_match_crc - verify multiple regions using crc
+ * @data:	data block to be verified
+ *
+ * Iterates through all regions stored in @data.  Regions with odd index
+ * are treated as data, and its next region is treated as checksum.  Thus
+ * regions of even index must have valid_size of 4 or 0 (skip verification).
+ * Returns a bitmask of verified regions, starting from LSB.  1 indicates
+ * a checksum match, while 0 indicates checksum mismatch or not verified.
+ */
+static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data)
+{
+	int j, rc;
+	uint32_t *sum;
+	uint32_t ret = 0;
+	uint8_t *memptr;
+	struct msm_eeprom_memory_map_t *map;
+
+	if (!data) {
+		pr_err("%s data is NULL", __func__);
+		return -EINVAL;
+	}
+	map = data->map;
+	memptr = data->mapdata;
+
+	for (j = 0; j + 1 < data->num_map; j += 2) {
+		/* empty table or no checksum */
+		if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) {
+			memptr += map[j].mem.valid_size
+				+ map[j+1].mem.valid_size;
+			continue;
+		}
+		if (map[j+1].mem.valid_size != sizeof(uint32_t)) {
+			CDBG("%s: malformatted data mapping\n", __func__);
+			return -EINVAL;
+		}
+		sum = (uint32_t *) (memptr + map[j].mem.valid_size);
+		rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size,
+					   *sum);
+		if (!rc)
+			ret |= 1 << (j/2);
+		memptr += map[j].mem.valid_size + map[j+1].mem.valid_size;
+	}
+	return ret;
+}
+
+/*
+ * read_eeprom_memory() - read map data into buffer
+ * @e_ctrl:	eeprom control struct
+ * @block:	block to be read
+ *
+ * This function iterates through blocks stored in block->map, reads each
+ * region and concatenate them into the pre-allocated block->mapdata
+ */
+static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl,
+	struct msm_eeprom_memory_block_t *block)
+{
+	int rc = 0;
+	int j;
+	struct msm_eeprom_memory_map_t *emap = block->map;
+	struct msm_eeprom_board_info *eb_info;
+	uint8_t *memptr = block->mapdata;
+
+	if (!e_ctrl) {
+		pr_err("%s e_ctrl is NULL", __func__);
+		return -EINVAL;
+	}
+
+	eb_info = e_ctrl->eboard_info;
+
+	for (j = 0; j < block->num_map; j++) {
+		if (emap[j].saddr.addr) {
+			eb_info->i2c_slaveaddr = emap[j].saddr.addr;
+			e_ctrl->i2c_client.cci_client->sid =
+					eb_info->i2c_slaveaddr >> 1;
+			pr_err("qcom,slave-addr = 0x%X\n",
+				eb_info->i2c_slaveaddr);
+		}
+
+		if (emap[j].page.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].page.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].page.addr,
+				emap[j].page.data, emap[j].page.data_t);
+				msleep(emap[j].page.delay);
+			if (rc < 0) {
+				pr_err("%s: page write failed\n", __func__);
+				return rc;
+			}
+		}
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				emap[j].pageen.data, emap[j].pageen.data_t);
+				msleep(emap[j].pageen.delay);
+			if (rc < 0) {
+				pr_err("%s: page enable failed\n", __func__);
+				return rc;
+			}
+		}
+		if (emap[j].poll.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+				&(e_ctrl->i2c_client), emap[j].poll.addr,
+				emap[j].poll.data, emap[j].poll.data_t,
+				emap[j].poll.delay);
+			if (rc < 0) {
+				pr_err("%s: poll failed\n", __func__);
+				return rc;
+			}
+		}
+
+		if (emap[j].mem.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq(
+				&(e_ctrl->i2c_client), emap[j].mem.addr,
+				memptr, emap[j].mem.valid_size);
+			if (rc < 0) {
+				pr_err("%s: read failed\n", __func__);
+				return rc;
+			}
+			memptr += emap[j].mem.valid_size;
+		}
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				0, emap[j].pageen.data_t);
+			if (rc < 0) {
+				pr_err("%s: page disable failed\n", __func__);
+				return rc;
+			}
+		}
+	}
+	return rc;
+}
+/*
+ * msm_eeprom_parse_memory_map() - parse memory map in device node
+ * @of:	device node
+ * @data:	memory block for output
+ *
+ * This functions parses @of to fill @data.  It allocates map itself, parses
+ * the @of node, calculate total data length, and allocates required buffer.
+ * It only fills the map, but does not perform actual reading.
+ */
+static int msm_eeprom_parse_memory_map(struct device_node *of,
+	struct msm_eeprom_memory_block_t *data)
+{
+	int i, rc = 0;
+	char property[PROPERTY_MAXSIZE];
+	uint32_t count = 6;
+	struct msm_eeprom_memory_map_t *map;
+
+	snprintf(property, PROPERTY_MAXSIZE, "qcom,num-blocks");
+	rc = of_property_read_u32(of, property, &data->num_map);
+	CDBG("%s: %s %d\n", __func__, property, data->num_map);
+	if (rc < 0) {
+		pr_err("%s failed rc %d\n", __func__, rc);
+		return rc;
+	}
+
+	map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL);
+	if (!map) {
+		rc = -ENOMEM;
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return rc;
+	}
+	data->map = map;
+
+	for (i = 0; i < data->num_map; i++) {
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &map[i].page, count);
+		if (rc < 0) {
+			pr_err("%s: failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+
+		snprintf(property, PROPERTY_MAXSIZE,
+			"qcom,pageen%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &map[i].pageen, count);
+		if (rc < 0)
+			CDBG("%s: pageen not needed\n", __func__);
+
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &map[i].saddr.addr, 1);
+		if (rc < 0)
+			CDBG("%s: saddr not needed - block %d\n", __func__, i);
+
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &map[i].poll, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &map[i].mem, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		data->num_data += map[i].mem.valid_size;
+	}
+
+	CDBG("%s num_bytes %d\n", __func__, data->num_data);
+
+	data->mapdata = kzalloc(data->num_data, GFP_KERNEL);
+	if (!data->mapdata) {
+		rc = -ENOMEM;
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+	return rc;
+
+ERROR:
+	kfree(data->map);
+	memset(data, 0, sizeof(*data));
+	return rc;
+}
+
+/*
+ * eeprom_parse_memory_map - Parse mem map
+ * @e_ctrl:	ctrl structure
+ * @eeprom_map_array: eeprom map
+ *
+ * Returns success or failure
+ */
+static int eeprom_parse_memory_map(struct msm_eeprom_ctrl_t *e_ctrl,
+	struct msm_eeprom_memory_map_array *eeprom_map_array)
+{
+	int rc =  0, i, j;
+	uint8_t *memptr;
+	struct msm_eeprom_mem_map_t *eeprom_map;
+
+	e_ctrl->cal_data.mapdata = NULL;
+	e_ctrl->cal_data.num_data = msm_get_read_mem_size(eeprom_map_array);
+	if (e_ctrl->cal_data.num_data <= 0) {
+		pr_err("%s:%d Error in reading mem size\n",
+			__func__, __LINE__);
+		e_ctrl->cal_data.num_data = 0;
+		return -EINVAL;
+	}
+	e_ctrl->cal_data.mapdata =
+		kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL);
+	if (!e_ctrl->cal_data.mapdata)
+		return -ENOMEM;
+
+	memptr = e_ctrl->cal_data.mapdata;
+	for (j = 0; j < eeprom_map_array->msm_size_of_max_mappings; j++) {
+		eeprom_map = &(eeprom_map_array->memory_map[j]);
+		if (e_ctrl->i2c_client.cci_client) {
+			e_ctrl->i2c_client.cci_client->sid =
+				eeprom_map->slave_addr >> 1;
+		} else if (e_ctrl->i2c_client.client) {
+			e_ctrl->i2c_client.client->addr =
+				eeprom_map->slave_addr >> 1;
+		}
+		CDBG("Slave Addr: 0x%X\n", eeprom_map->slave_addr);
+		CDBG("Memory map Size: %d",
+			eeprom_map->memory_map_size);
+		for (i = 0; i < eeprom_map->memory_map_size; i++) {
+			switch (eeprom_map->mem_settings[i].i2c_operation) {
+			case MSM_CAM_WRITE: {
+				e_ctrl->i2c_client.addr_type =
+					eeprom_map->mem_settings[i].addr_type;
+				rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+					&(e_ctrl->i2c_client),
+					eeprom_map->mem_settings[i].reg_addr,
+					eeprom_map->mem_settings[i].reg_data,
+					eeprom_map->mem_settings[i].data_type);
+				msleep(eeprom_map->mem_settings[i].delay);
+				if (rc < 0) {
+					pr_err("%s: page write failed\n",
+						__func__);
+					goto clean_up;
+				}
+			}
+			break;
+			case MSM_CAM_POLL: {
+				e_ctrl->i2c_client.addr_type =
+					eeprom_map->mem_settings[i].addr_type;
+				rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+					&(e_ctrl->i2c_client),
+					eeprom_map->mem_settings[i].reg_addr,
+					eeprom_map->mem_settings[i].reg_data,
+					eeprom_map->mem_settings[i].data_type,
+					eeprom_map->mem_settings[i].delay);
+				if (rc < 0) {
+					pr_err("%s: poll failed\n",
+						__func__);
+					goto clean_up;
+				}
+			}
+			break;
+			case MSM_CAM_READ: {
+				e_ctrl->i2c_client.addr_type =
+					eeprom_map->mem_settings[i].addr_type;
+				rc = e_ctrl->i2c_client.i2c_func_tbl->
+					i2c_read_seq(&(e_ctrl->i2c_client),
+					eeprom_map->mem_settings[i].reg_addr,
+					memptr,
+					eeprom_map->mem_settings[i].reg_data);
+				msleep(eeprom_map->mem_settings[i].delay);
+				if (rc < 0) {
+					pr_err("%s: read failed\n",
+						__func__);
+					goto clean_up;
+				}
+				memptr += eeprom_map->mem_settings[i].reg_data;
+			}
+			break;
+			default:
+				pr_err("%s: %d Invalid i2c operation LC:%d\n",
+					__func__, __LINE__, i);
+				return -EINVAL;
+			}
+		}
+	}
+	memptr = e_ctrl->cal_data.mapdata;
+	for (i = 0; i < e_ctrl->cal_data.num_data; i++)
+		CDBG("memory_data[%d] = 0x%X\n", i, memptr[i]);
+	return rc;
+
+clean_up:
+	kfree(e_ctrl->cal_data.mapdata);
+	e_ctrl->cal_data.num_data = 0;
+	e_ctrl->cal_data.mapdata = NULL;
+	return rc;
+}
+
+/*
+ * msm_eeprom_power_up - Do eeprom power up here
+ * @e_ctrl:	ctrl structure
+ * @power_info: power up info for eeprom
+ *
+ * Returns success or failure
+ */
+static int msm_eeprom_power_up(struct msm_eeprom_ctrl_t *e_ctrl,
+	struct msm_camera_power_ctrl_t *power_info) {
+	int32_t rc = 0;
+
+	rc = msm_camera_fill_vreg_params(
+		power_info->cam_vreg, power_info->num_vreg,
+		power_info->power_setting, power_info->power_setting_size);
+	if (rc < 0) {
+		pr_err("%s:%d failed in camera_fill_vreg_params  rc %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	/* Parse and fill vreg params for powerdown settings*/
+	rc = msm_camera_fill_vreg_params(
+		power_info->cam_vreg, power_info->num_vreg,
+		power_info->power_down_setting,
+		power_info->power_down_setting_size);
+	if (rc < 0) {
+		pr_err("%s:%d failed msm_camera_fill_vreg_params for PDOWN rc %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+			&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("%s:%d failed in eeprom Power up rc %d\n",
+		__func__, __LINE__, rc);
+		return rc;
+	}
+	return rc;
+}
+
+/*
+ * msm_eeprom_power_up - Do power up, parse and power down
+ * @e_ctrl: ctrl structure
+ * Returns success or failure
+ */
+static int eeprom_init_config(struct msm_eeprom_ctrl_t *e_ctrl,
+	void *argp)
+{
+	int rc =  0;
+	struct msm_eeprom_cfg_data *cdata = argp;
+	struct msm_sensor_power_setting_array *power_setting_array = NULL;
+	struct msm_camera_power_ctrl_t *power_info;
+	struct msm_eeprom_memory_map_array *memory_map_arr = NULL;
+
+	power_setting_array =
+		kzalloc(sizeof(struct msm_sensor_power_setting_array),
+			GFP_KERNEL);
+	if (!power_setting_array) {
+		pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		return rc;
+	}
+	memory_map_arr = kzalloc(sizeof(struct msm_eeprom_memory_map_array),
+		GFP_KERNEL);
+	if (!memory_map_arr) {
+		rc = -ENOMEM;
+		pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__);
+		goto free_mem;
+	}
+
+	if (copy_from_user(power_setting_array,
+		(void __user *)cdata->cfg.eeprom_info.power_setting_array,
+		sizeof(struct msm_sensor_power_setting_array))) {
+		pr_err("%s copy_from_user failed %d\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+	CDBG("%s:%d Size of power setting array: %d\n",
+		__func__, __LINE__, power_setting_array->size);
+	if (copy_from_user(memory_map_arr,
+		(void __user *)cdata->cfg.eeprom_info.mem_map_array,
+		sizeof(struct msm_eeprom_memory_map_array))) {
+		rc = -EINVAL;
+		pr_err("%s copy_from_user failed for memory map%d\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+
+	power_info = &(e_ctrl->eboard_info->power_info);
+
+	power_info->power_setting =
+		power_setting_array->power_setting_a;
+	power_info->power_down_setting =
+		power_setting_array->power_down_setting_a;
+
+	power_info->power_setting_size =
+		power_setting_array->size;
+	power_info->power_down_setting_size =
+		power_setting_array->size_down;
+
+	if ((power_info->power_setting_size >
+		MAX_POWER_CONFIG) ||
+		(power_info->power_down_setting_size >
+		MAX_POWER_CONFIG) ||
+		(!power_info->power_down_setting_size) ||
+		(!power_info->power_setting_size)) {
+		rc = -EINVAL;
+		pr_err("%s:%d Invalid power setting size :%d, %d\n",
+			__func__, __LINE__,
+			power_info->power_setting_size,
+			power_info->power_down_setting_size);
+		goto free_mem;
+	}
+
+	if (e_ctrl->i2c_client.cci_client) {
+		e_ctrl->i2c_client.cci_client->i2c_freq_mode =
+			cdata->cfg.eeprom_info.i2c_freq_mode;
+		if (e_ctrl->i2c_client.cci_client->i2c_freq_mode >
+			I2C_MAX_MODES) {
+			pr_err("%s::%d Improper I2C freq mode\n",
+				__func__, __LINE__);
+			e_ctrl->i2c_client.cci_client->i2c_freq_mode =
+				I2C_STANDARD_MODE;
+		}
+	}
+
+	/* Fill vreg power info and power up here */
+	rc = msm_eeprom_power_up(e_ctrl, power_info);
+	if (rc < 0) {
+		pr_err("Power Up failed for eeprom\n");
+		goto free_mem;
+	}
+
+	rc = eeprom_parse_memory_map(e_ctrl, memory_map_arr);
+	if (rc < 0) {
+		pr_err("%s::%d memory map parse failed\n", __func__, __LINE__);
+		goto free_mem;
+	}
+
+	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc < 0) {
+		pr_err("%s:%d Power down failed rc %d\n",
+			__func__, __LINE__, rc);
+		goto free_mem;
+	}
+
+free_mem:
+	kfree(power_setting_array);
+	kfree(memory_map_arr);
+	power_setting_array = NULL;
+	memory_map_arr = NULL;
+	return rc;
+}
+
+static int msm_eeprom_get_cmm_data(struct msm_eeprom_ctrl_t *e_ctrl,
+				       struct msm_eeprom_cfg_data *cdata)
+{
+	int rc = 0;
+	struct msm_eeprom_cmm_t *cmm_data = &e_ctrl->eboard_info->cmm_data;
+
+	cdata->cfg.get_cmm_data.cmm_support = cmm_data->cmm_support;
+	cdata->cfg.get_cmm_data.cmm_compression = cmm_data->cmm_compression;
+	cdata->cfg.get_cmm_data.cmm_size = cmm_data->cmm_size;
+	return rc;
+}
+
+static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl,
+	struct msm_eeprom_cfg_data *cdata)
+{
+	int rc;
+
+	/* check range */
+	if (cdata->cfg.read_data.num_bytes >
+		e_ctrl->cal_data.num_data) {
+		CDBG("%s: Invalid size. exp %u, req %u\n", __func__,
+			e_ctrl->cal_data.num_data,
+			cdata->cfg.read_data.num_bytes);
+		return -EINVAL;
+	}
+
+	rc = copy_to_user((void __user *)cdata->cfg.read_data.dbuffer,
+		e_ctrl->cal_data.mapdata,
+		cdata->cfg.read_data.num_bytes);
+
+	return rc;
+}
+
+static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
+	void *argp)
+{
+	struct msm_eeprom_cfg_data *cdata =
+		(struct msm_eeprom_cfg_data *)argp;
+	int rc = 0;
+	size_t length = 0;
+
+	CDBG("%s E\n", __func__);
+	switch (cdata->cfgtype) {
+	case CFG_EEPROM_GET_INFO:
+		if (e_ctrl->userspace_probe == 1) {
+			pr_err("%s:%d Eeprom name should be module driver",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
+		CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__);
+		cdata->is_supported = e_ctrl->is_supported;
+		length = strlen(e_ctrl->eboard_info->eeprom_name) + 1;
+		if (length > MAX_EEPROM_NAME) {
+			pr_err("%s:%d invalid eeprom_name length %d\n",
+				__func__, __LINE__, (int)length);
+			rc = -EINVAL;
+			break;
+		}
+		memcpy(cdata->cfg.eeprom_name,
+			e_ctrl->eboard_info->eeprom_name, length);
+		break;
+	case CFG_EEPROM_GET_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
+		cdata->cfg.get_data.num_bytes =
+			e_ctrl->cal_data.num_data;
+		break;
+	case CFG_EEPROM_READ_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
+		rc = eeprom_config_read_cal_data(e_ctrl, cdata);
+		break;
+	case CFG_EEPROM_GET_MM_INFO:
+		CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__);
+		rc = msm_eeprom_get_cmm_data(e_ctrl, cdata);
+		break;
+	case CFG_EEPROM_INIT:
+		if (e_ctrl->userspace_probe == 0) {
+			pr_err("%s:%d Eeprom already probed at kernel boot",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
+		if (e_ctrl->cal_data.num_data == 0) {
+			rc = eeprom_init_config(e_ctrl, argp);
+			if (rc < 0) {
+				pr_err("%s:%d Eeprom init failed\n",
+					__func__, __LINE__);
+				return rc;
+			}
+		} else {
+			CDBG("%s:%d Already read eeprom\n",
+				__func__, __LINE__);
+		}
+		break;
+	default:
+		break;
+	}
+
+	CDBG("%s X rc: %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl,
+				    void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("%s E\n", __func__);
+	if (!subdev_id) {
+		pr_err("%s failed\n", __func__);
+		return -EINVAL;
+	}
+	*subdev_id = e_ctrl->subdev_id;
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("%s X\n", __func__);
+	return 0;
+}
+
+static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+		unsigned int cmd, void *arg)
+{
+	struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd);
+	void *argp = (void *)arg;
+
+	CDBG("%s E\n", __func__);
+	CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_eeprom_get_subdev_id(e_ctrl, argp);
+	case VIDIOC_MSM_EEPROM_CFG:
+		return msm_eeprom_config(e_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	CDBG("%s X\n", __func__);
+}
+
+static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_seq = msm_camera_cci_i2c_write_seq,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+	msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll = msm_camera_cci_i2c_poll,
+};
+
+static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+	msm_camera_qup_i2c_write_table_w_microdelay,
+};
+
+static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = {
+	.i2c_read = msm_camera_spi_read,
+	.i2c_read_seq = msm_camera_spi_read_seq,
+};
+
+static int msm_eeprom_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh) {
+	int rc = 0;
+	struct msm_eeprom_ctrl_t *e_ctrl =  v4l2_get_subdevdata(sd);
+
+	CDBG("%s E\n", __func__);
+	if (!e_ctrl) {
+		pr_err("%s failed e_ctrl is NULL\n", __func__);
+		return -EINVAL;
+	}
+	CDBG("%s X\n", __func__);
+	return rc;
+}
+
+static int msm_eeprom_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh) {
+	int rc = 0;
+	struct msm_eeprom_ctrl_t *e_ctrl =  v4l2_get_subdevdata(sd);
+
+	CDBG("%s E\n", __func__);
+	if (!e_ctrl) {
+		pr_err("%s failed e_ctrl is NULL\n", __func__);
+		return -EINVAL;
+	}
+	CDBG("%s X\n", __func__);
+	return rc;
+}
+
+static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = {
+	.open = msm_eeprom_open,
+	.close = msm_eeprom_close,
+};
+
+static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = {
+	.ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_eeprom_subdev_ops = {
+	.core = &msm_eeprom_subdev_core_ops,
+};
+
+static int msm_eeprom_i2c_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
+
+	CDBG("%s E\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s i2c_check_functionality failed\n", __func__);
+		goto probe_failure;
+	}
+
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
+	if (!e_ctrl)
+		return -ENOMEM;
+	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
+	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
+	CDBG("%s client = 0x%pK\n", __func__, client);
+	e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data);
+	if (!e_ctrl->eboard_info) {
+		pr_err("%s:%d board info NULL\n", __func__, __LINE__);
+		rc = -EINVAL;
+		goto ectrl_free;
+	}
+	e_ctrl->i2c_client.client = client;
+	e_ctrl->cal_data.mapdata = NULL;
+	e_ctrl->cal_data.map = NULL;
+	e_ctrl->userspace_probe = 0;
+	e_ctrl->is_supported = 1;
+
+	/* Set device type as I2C */
+	e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE;
+	e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl;
+
+	if (e_ctrl->eboard_info->i2c_slaveaddr != 0)
+		e_ctrl->i2c_client.client->addr =
+			e_ctrl->eboard_info->i2c_slaveaddr;
+
+	/*Get clocks information*/
+	rc = msm_camera_i2c_dev_get_clk_info(
+		&e_ctrl->i2c_client.client->dev,
+		&e_ctrl->eboard_info->power_info.clk_info,
+		&e_ctrl->eboard_info->power_info.clk_ptr,
+		&e_ctrl->eboard_info->power_info.clk_info_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_clk_info rc %d", rc);
+		goto ectrl_free;
+	}
+
+	/*IMPLEMENT READING PART*/
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd,
+		e_ctrl->i2c_client.client,
+		e_ctrl->eeprom_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl);
+	e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops;
+	e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
+	e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
+	msm_sd_register(&e_ctrl->msm_sd);
+	CDBG("%s success result=%d X\n", __func__, rc);
+	return rc;
+
+ectrl_free:
+	kfree(e_ctrl);
+probe_failure:
+	pr_err("%s failed! rc = %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_eeprom_i2c_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct msm_eeprom_ctrl_t  *e_ctrl;
+
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd);
+	if (!e_ctrl) {
+		pr_err("%s: eeprom device is NULL\n", __func__);
+		return 0;
+	}
+
+	if (!e_ctrl->eboard_info) {
+		pr_err("%s: eboard_info is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_camera_i2c_dev_put_clk_info(&e_ctrl->i2c_client.client->dev,
+		&e_ctrl->eboard_info->power_info.clk_info,
+		&e_ctrl->eboard_info->power_info.clk_ptr,
+		e_ctrl->eboard_info->power_info.clk_info_size);
+
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
+	if (e_ctrl->eboard_info) {
+		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
+		kfree(e_ctrl->eboard_info);
+	}
+	e_ctrl->cal_data.mapdata = NULL;
+	kfree(e_ctrl);
+	e_ctrl = NULL;
+
+	return 0;
+}
+
+static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic)
+{
+	int rc = -EFAULT;
+	uint32_t tmp[3];
+
+	if (of_property_read_u32_array(
+		spic->spi_master->dev.of_node,
+		"qcom,spiop,read", tmp, 3)) {
+		return -EFAULT;
+	}
+	spic->cmd_tbl.read.opcode = tmp[0];
+	spic->cmd_tbl.read.addr_len = tmp[1];
+	spic->cmd_tbl.read.dummy_len = tmp[2];
+
+	if (of_property_read_u32_array(
+		spic->spi_master->dev.of_node,
+		"qcom,spiop,readseq", tmp, 3)) {
+		return -EFAULT;
+	}
+	spic->cmd_tbl.read_seq.opcode = tmp[0];
+	spic->cmd_tbl.read_seq.addr_len = tmp[1];
+	spic->cmd_tbl.read_seq.dummy_len = tmp[2];
+
+	if (of_property_read_u32_array(
+		spic->spi_master->dev.of_node,
+		"qcom,spiop,queryid", tmp, 3)) {
+		return -EFAULT;
+	}
+	spic->cmd_tbl.query_id.opcode = tmp[0];
+	spic->cmd_tbl.query_id.addr_len = tmp[1];
+	spic->cmd_tbl.query_id.dummy_len = tmp[2];
+
+	rc = of_property_read_u32_array(spic->spi_master->dev.of_node,
+					"qcom,eeprom-id", tmp, 2);
+	if (rc) {
+		pr_err("%s: Failed to get eeprom id\n", __func__);
+		return rc;
+	}
+	spic->mfr_id0 = tmp[0];
+	spic->device_id0 = tmp[1];
+
+	return 0;
+}
+
+static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+	int rc;
+	struct msm_camera_i2c_client *client = &e_ctrl->i2c_client;
+	uint8_t id[2];
+
+	rc = msm_camera_spi_query_id(client, 0, &id[0], 2);
+	if (rc < 0)
+		return rc;
+	CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0],
+		id[1], client->spi_client->mfr_id0,
+		client->spi_client->device_id0);
+	if (id[0] != client->spi_client->mfr_id0
+		|| id[1] != client->spi_client->device_id0)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+	int rc = 0, i = 0;
+	struct msm_eeprom_board_info *eb_info;
+	struct msm_camera_power_ctrl_t *power_info =
+		&e_ctrl->eboard_info->power_info;
+	struct device_node *of_node = NULL;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	int8_t gpio_array_size = 0;
+	uint16_t *gpio_array = NULL;
+
+	eb_info = e_ctrl->eboard_info;
+	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+		of_node = e_ctrl->i2c_client.
+			spi_client->spi_master->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		of_node = e_ctrl->pdev->dev.of_node;
+
+	if (!of_node) {
+		pr_err("%s: %d of_node is NULL\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
+					     &power_info->num_vreg);
+	if (rc < 0)
+		return rc;
+
+	if (e_ctrl->userspace_probe == 0) {
+		rc = msm_camera_get_dt_power_setting_data(of_node,
+			power_info->cam_vreg, power_info->num_vreg,
+			power_info);
+		if (rc < 0)
+			goto ERROR1;
+	}
+
+	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+					GFP_KERNEL);
+	if (!power_info->gpio_conf) {
+		rc = -ENOMEM;
+		goto ERROR2;
+	}
+	gconf = power_info->gpio_conf;
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+	if (gpio_array_size > 0) {
+		gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t),
+			GFP_KERNEL);
+		if (!gpio_array)
+			goto ERROR3;
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
+
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR4;
+		}
+
+		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR4;
+		}
+		kfree(gpio_array);
+	}
+
+	return rc;
+ERROR4:
+	kfree(gpio_array);
+ERROR3:
+	kfree(power_info->gpio_conf);
+ERROR2:
+	kfree(power_info->cam_vreg);
+ERROR1:
+	kfree(power_info->power_setting);
+	return rc;
+}
+
+
+static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info,
+	struct device_node *of_node)
+{
+	int rc = 0;
+	struct msm_eeprom_cmm_t *cmm_data = &eb_info->cmm_data;
+
+	cmm_data->cmm_support =
+		of_property_read_bool(of_node, "qcom,cmm-data-support");
+	if (!cmm_data->cmm_support)
+		return -EINVAL;
+	cmm_data->cmm_compression =
+		of_property_read_bool(of_node, "qcom,cmm-data-compressed");
+	if (!cmm_data->cmm_compression)
+		CDBG("No MM compression data\n");
+
+	rc = of_property_read_u32(of_node, "qcom,cmm-data-offset",
+		&cmm_data->cmm_offset);
+	if (rc < 0)
+		CDBG("No MM offset data\n");
+
+	rc = of_property_read_u32(of_node, "qcom,cmm-data-size",
+		&cmm_data->cmm_size);
+	if (rc < 0)
+		CDBG("No MM size data\n");
+
+	CDBG("cmm_support: cmm_compr %d, cmm_offset %d, cmm_size %d\n",
+		cmm_data->cmm_compression,
+		cmm_data->cmm_offset,
+		cmm_data->cmm_size);
+	return 0;
+}
+
+static int msm_eeprom_spi_setup(struct spi_device *spi)
+{
+	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
+	struct msm_camera_i2c_client *client = NULL;
+	struct msm_camera_spi_client *spi_client;
+	struct msm_eeprom_board_info *eb_info;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
+	int rc = 0;
+
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
+	if (!e_ctrl)
+		return -ENOMEM;
+	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
+	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
+	client = &e_ctrl->i2c_client;
+	e_ctrl->is_supported = 0;
+	e_ctrl->userspace_probe = 0;
+	e_ctrl->cal_data.mapdata = NULL;
+	e_ctrl->cal_data.map = NULL;
+
+	spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL);
+	if (!spi_client) {
+		kfree(e_ctrl);
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32(spi->dev.of_node, "cell-index",
+				  &e_ctrl->subdev_id);
+	CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		return rc;
+	}
+
+	eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL);
+	if (!eb_info)
+		goto spi_free;
+	e_ctrl->eboard_info = eb_info;
+
+	rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name",
+		&eb_info->eeprom_name);
+	CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
+		eb_info->eeprom_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		e_ctrl->userspace_probe = 1;
+		goto board_free;
+	}
+
+	e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE;
+	client->spi_client = spi_client;
+	spi_client->spi_master = spi;
+	client->i2c_func_tbl = &msm_eeprom_spi_func_tbl;
+	client->addr_type = MSM_CAMERA_I2C_3B_ADDR;
+
+	rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, spi->dev.of_node);
+	if (rc < 0)
+		CDBG("%s MM data miss:%d\n", __func__, __LINE__);
+
+	power_info = &eb_info->power_info;
+	power_info->dev = &spi->dev;
+
+	/*Get clocks information*/
+	rc = msm_camera_i2c_dev_get_clk_info(
+		&spi->dev,
+		&power_info->clk_info,
+		&power_info->clk_ptr,
+		&power_info->clk_info_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_clk_info rc %d", rc);
+		goto board_free;
+	}
+
+	rc = msm_eeprom_get_dt_data(e_ctrl);
+	if (rc < 0)
+		goto board_free;
+
+	/* set spi instruction info */
+	spi_client->retry_delay = 1;
+	spi_client->retries = 0;
+
+	rc = msm_eeprom_spi_parse_of(spi_client);
+	if (rc < 0) {
+		dev_err(&spi->dev,
+			"%s: Error parsing device properties\n", __func__);
+		goto board_free;
+	}
+
+	if (e_ctrl->userspace_probe == 0) {
+		/* prepare memory buffer */
+		rc = msm_eeprom_parse_memory_map(spi->dev.of_node,
+			&e_ctrl->cal_data);
+		if (rc < 0)
+			CDBG("%s: no cal memory map\n", __func__);
+
+		/* power up eeprom for reading */
+		rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+			&e_ctrl->i2c_client);
+		if (rc < 0) {
+			pr_err("failed rc %d\n", rc);
+			goto caldata_free;
+		}
+
+		/* check eeprom id */
+		rc = msm_eeprom_match_id(e_ctrl);
+		if (rc < 0) {
+			CDBG("%s: eeprom not matching %d\n", __func__, rc);
+			goto power_down;
+		}
+		/* read eeprom */
+		if (e_ctrl->cal_data.map) {
+			rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data);
+			if (rc < 0) {
+				pr_err("%s: read cal data failed\n", __func__);
+				goto power_down;
+			}
+			e_ctrl->is_supported |= msm_eeprom_match_crc(
+				&e_ctrl->cal_data);
+		}
+
+		rc = msm_camera_power_down(power_info,
+			e_ctrl->eeprom_device_type, &e_ctrl->i2c_client);
+		if (rc < 0) {
+			pr_err("failed rc %d\n", rc);
+			goto caldata_free;
+		}
+	} else
+		e_ctrl->is_supported = 1;
+
+	/* initiazlie subdev */
+	v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd,
+		e_ctrl->i2c_client.spi_client->spi_master,
+		e_ctrl->eeprom_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl);
+	e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops;
+	e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
+	e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
+	msm_sd_register(&e_ctrl->msm_sd);
+	e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1;
+	CDBG("%s success result=%d supported=%x X\n", __func__, rc,
+	     e_ctrl->is_supported);
+
+	return 0;
+
+power_down:
+	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+caldata_free:
+	msm_camera_i2c_dev_put_clk_info(
+		&e_ctrl->i2c_client.spi_client->spi_master->dev,
+		&e_ctrl->eboard_info->power_info.clk_info,
+		&e_ctrl->eboard_info->power_info.clk_ptr,
+		e_ctrl->eboard_info->power_info.clk_info_size);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
+board_free:
+	kfree(e_ctrl->eboard_info);
+spi_free:
+	kfree(spi_client);
+	kfree(e_ctrl);
+	return rc;
+}
+
+static int msm_eeprom_spi_probe(struct spi_device *spi)
+{
+	int irq, cs, cpha, cpol, cs_high;
+
+	CDBG("%s\n", __func__);
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	spi_setup(spi);
+
+	irq = spi->irq;
+	cs = spi->chip_select;
+	cpha = (spi->mode & SPI_CPHA) ? 1 : 0;
+	cpol = (spi->mode & SPI_CPOL) ? 1 : 0;
+	cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0;
+	CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n",
+			__func__, irq, cs, cpha, cpol, cs_high);
+	CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz);
+
+	return msm_eeprom_spi_setup(spi);
+}
+
+static int msm_eeprom_spi_remove(struct spi_device *sdev)
+{
+	struct v4l2_subdev *sd = spi_get_drvdata(sdev);
+	struct msm_eeprom_ctrl_t  *e_ctrl;
+
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd);
+	if (!e_ctrl) {
+		pr_err("%s: eeprom device is NULL\n", __func__);
+		return 0;
+	}
+
+	if (!e_ctrl->eboard_info) {
+		pr_err("%s: board info is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_camera_i2c_dev_put_clk_info(
+		&e_ctrl->i2c_client.spi_client->spi_master->dev,
+		&e_ctrl->eboard_info->power_info.clk_info,
+		&e_ctrl->eboard_info->power_info.clk_ptr,
+		e_ctrl->eboard_info->power_info.clk_info_size);
+
+	kfree(e_ctrl->i2c_client.spi_client);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
+	if (e_ctrl->eboard_info) {
+		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
+		kfree(e_ctrl->eboard_info);
+	}
+	e_ctrl->cal_data.mapdata = NULL;
+	kfree(e_ctrl);
+	e_ctrl = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static void msm_eeprom_copy_power_settings_compat(
+	struct msm_sensor_power_setting_array *ps,
+	struct msm_sensor_power_setting_array32 *ps32)
+{
+	uint16_t i = 0;
+
+	ps->size = ps32->size;
+	for (i = 0; i < ps32->size; i++) {
+		ps->power_setting_a[i].config_val =
+			ps32->power_setting_a[i].config_val;
+		ps->power_setting_a[i].delay =
+			ps32->power_setting_a[i].delay;
+		ps->power_setting_a[i].seq_type =
+			ps32->power_setting_a[i].seq_type;
+		ps->power_setting_a[i].seq_val =
+			ps32->power_setting_a[i].seq_val;
+	}
+
+	ps->size_down = ps32->size_down;
+	for (i = 0; i < ps32->size_down; i++) {
+		ps->power_down_setting_a[i].config_val =
+			ps32->power_down_setting_a[i].config_val;
+		ps->power_down_setting_a[i].delay =
+			ps32->power_down_setting_a[i].delay;
+		ps->power_down_setting_a[i].seq_type =
+			ps32->power_down_setting_a[i].seq_type;
+		ps->power_down_setting_a[i].seq_val =
+			ps32->power_down_setting_a[i].seq_val;
+	}
+}
+
+static int eeprom_config_read_cal_data32(struct msm_eeprom_ctrl_t *e_ctrl,
+	void *arg)
+{
+	int rc;
+	uint8_t __user *ptr_dest = NULL;
+	struct msm_eeprom_cfg_data32 *cdata32 =
+		(struct msm_eeprom_cfg_data32 *) arg;
+	struct msm_eeprom_cfg_data cdata;
+
+	cdata.cfgtype = cdata32->cfgtype;
+	cdata.is_supported = cdata32->is_supported;
+	cdata.cfg.read_data.num_bytes = cdata32->cfg.read_data.num_bytes;
+	/* check range */
+	if (cdata.cfg.read_data.num_bytes >
+	    e_ctrl->cal_data.num_data) {
+		CDBG("%s: Invalid size. exp %u, req %u\n", __func__,
+			e_ctrl->cal_data.num_data,
+			cdata.cfg.read_data.num_bytes);
+		return -EINVAL;
+	}
+	if (!e_ctrl->cal_data.mapdata)
+		return -EFAULT;
+
+	ptr_dest = (uint8_t __user *)compat_ptr(cdata32->cfg.read_data.dbuffer);
+
+	rc = copy_to_user(ptr_dest, e_ctrl->cal_data.mapdata,
+		cdata.cfg.read_data.num_bytes);
+
+	return rc;
+}
+
+static int eeprom_init_config32(struct msm_eeprom_ctrl_t *e_ctrl,
+	void *argp)
+{
+	int rc =  0;
+	struct msm_eeprom_cfg_data32 *cdata32 = argp;
+	struct msm_sensor_power_setting_array *power_setting_array = NULL;
+	struct msm_sensor_power_setting_array32 *power_setting_array32 = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
+	struct msm_eeprom_memory_map_array *mem_map_array = NULL;
+
+	power_setting_array32 =
+		kzalloc(sizeof(struct msm_sensor_power_setting_array32),
+			GFP_KERNEL);
+	if (!power_setting_array32) {
+		pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		return rc;
+	}
+	power_setting_array =
+		kzalloc(sizeof(struct msm_sensor_power_setting_array),
+			GFP_KERNEL);
+	if (power_setting_array ==  NULL) {
+		pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto free_mem;
+	}
+	mem_map_array =
+		kzalloc(sizeof(struct msm_eeprom_memory_map_array),
+			GFP_KERNEL);
+	if (mem_map_array == NULL) {
+		pr_err("%s:%d Mem Alloc Fail\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto free_mem;
+	}
+
+	if (copy_from_user(power_setting_array32,
+		(void __user *)compat_ptr(cdata32->cfg.eeprom_info.
+		power_setting_array),
+		sizeof(struct msm_sensor_power_setting_array32))) {
+		pr_err("%s:%d copy_from_user failed\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+	CDBG("%s:%d Size of power setting array: %d",
+		__func__, __LINE__, power_setting_array32->size);
+	if (copy_from_user(mem_map_array,
+		(void __user *)
+		compat_ptr(cdata32->cfg.eeprom_info.mem_map_array),
+		sizeof(struct msm_eeprom_memory_map_array))) {
+		pr_err("%s:%d copy_from_user failed for memory map\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+
+	power_info = &(e_ctrl->eboard_info->power_info);
+
+	if ((power_setting_array32->size > MAX_POWER_CONFIG) ||
+		(power_setting_array32->size_down > MAX_POWER_CONFIG) ||
+		(!power_setting_array32->size) ||
+		(!power_setting_array32->size_down)) {
+		pr_err("%s:%d invalid power setting size=%d size_down=%d\n",
+			__func__, __LINE__, power_setting_array32->size,
+			power_setting_array32->size_down);
+		rc = -EINVAL;
+		goto free_mem;
+	}
+	msm_eeprom_copy_power_settings_compat(
+		power_setting_array,
+		power_setting_array32);
+
+	power_info->power_setting =
+		power_setting_array->power_setting_a;
+	power_info->power_down_setting =
+		power_setting_array->power_down_setting_a;
+
+	power_info->power_setting_size =
+		power_setting_array->size;
+	power_info->power_down_setting_size =
+		power_setting_array->size_down;
+
+	if (e_ctrl->i2c_client.cci_client) {
+		e_ctrl->i2c_client.cci_client->i2c_freq_mode =
+			cdata32->cfg.eeprom_info.i2c_freq_mode;
+		if (e_ctrl->i2c_client.cci_client->i2c_freq_mode >
+			I2C_MAX_MODES) {
+			pr_err("%s::%d Improper I2C Freq Mode\n",
+				__func__, __LINE__);
+			e_ctrl->i2c_client.cci_client->i2c_freq_mode =
+				I2C_STANDARD_MODE;
+		}
+		CDBG("%s:%d Not CCI probe", __func__, __LINE__);
+	}
+	/* Fill vreg power info and power up here */
+	rc = msm_eeprom_power_up(e_ctrl, power_info);
+	if (rc < 0) {
+		pr_err("%s:%d Power Up failed for eeprom\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+
+	rc = eeprom_parse_memory_map(e_ctrl, mem_map_array);
+	if (rc < 0) {
+		pr_err("%s:%d memory map parse failed\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+
+	rc = msm_camera_power_down(power_info,
+		e_ctrl->eeprom_device_type, &e_ctrl->i2c_client);
+	if (rc < 0)
+		pr_err("%s:%d Power down failed rc %d\n",
+			__func__, __LINE__, rc);
+
+free_mem:
+	kfree(power_setting_array32);
+	kfree(power_setting_array);
+	kfree(mem_map_array);
+	power_setting_array32 = NULL;
+	power_setting_array = NULL;
+	mem_map_array = NULL;
+	return rc;
+}
+
+static int msm_eeprom_config32(struct msm_eeprom_ctrl_t *e_ctrl,
+	void *argp)
+{
+	struct msm_eeprom_cfg_data32 *cdata =
+		(struct msm_eeprom_cfg_data32 *)argp;
+	int rc = 0;
+	size_t length = 0;
+
+	CDBG("%s E\n", __func__);
+	switch (cdata->cfgtype) {
+	case CFG_EEPROM_GET_INFO:
+		if (e_ctrl->userspace_probe == 1) {
+			pr_err("%s:%d Eeprom name should be module driver",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
+		CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__);
+		cdata->is_supported = e_ctrl->is_supported;
+		length = strlen(e_ctrl->eboard_info->eeprom_name) + 1;
+		if (length > MAX_EEPROM_NAME) {
+			pr_err("%s:%d invalid eeprom_name length %d\n",
+				__func__, __LINE__, (int)length);
+			rc = -EINVAL;
+			break;
+		}
+		memcpy(cdata->cfg.eeprom_name,
+			e_ctrl->eboard_info->eeprom_name, length);
+		break;
+	case CFG_EEPROM_GET_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
+		cdata->cfg.get_data.num_bytes =
+			e_ctrl->cal_data.num_data;
+		break;
+	case CFG_EEPROM_READ_CAL_DATA:
+		CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
+		rc = eeprom_config_read_cal_data32(e_ctrl, argp);
+		break;
+	case CFG_EEPROM_INIT:
+		if (e_ctrl->userspace_probe == 0) {
+			pr_err("%s:%d Eeprom already probed at kernel boot",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
+		if (e_ctrl->cal_data.num_data == 0) {
+			rc = eeprom_init_config32(e_ctrl, argp);
+			if (rc < 0)
+				pr_err("%s:%d Eeprom init failed\n",
+					__func__, __LINE__);
+		} else {
+			CDBG("%s:%d Already read eeprom\n",
+				__func__, __LINE__);
+		}
+		break;
+	default:
+		break;
+	}
+
+	CDBG("%s X rc: %d\n", __func__, rc);
+	return rc;
+}
+
+static long msm_eeprom_subdev_ioctl32(struct v4l2_subdev *sd,
+		unsigned int cmd, void *arg)
+{
+	struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd);
+	void *argp = (void *)arg;
+
+	CDBG("%s E\n", __func__);
+	CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_eeprom_get_subdev_id(e_ctrl, argp);
+	case VIDIOC_MSM_EEPROM_CFG32:
+		return msm_eeprom_config32(e_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	CDBG("%s X\n", __func__);
+}
+
+static long msm_eeprom_subdev_do_ioctl32(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	return msm_eeprom_subdev_ioctl32(sd, cmd, arg);
+}
+
+static long msm_eeprom_subdev_fops_ioctl32(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_eeprom_subdev_do_ioctl32);
+}
+
+#endif
+
+static int msm_eeprom_platform_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	int j = 0;
+	uint32_t temp;
+
+	struct msm_camera_cci_client *cci_client = NULL;
+	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
+	struct msm_eeprom_board_info *eb_info = NULL;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
+
+	CDBG("%s E\n", __func__);
+
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
+	if (!e_ctrl)
+		return -ENOMEM;
+	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
+	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
+
+	e_ctrl->cal_data.mapdata = NULL;
+	e_ctrl->cal_data.map = NULL;
+	e_ctrl->userspace_probe = 0;
+	e_ctrl->is_supported = 0;
+	if (!of_node) {
+		pr_err("%s dev.of_node NULL\n", __func__);
+		rc = -EINVAL;
+		goto ectrl_free;
+	}
+
+	/* Set platform device handle */
+	e_ctrl->pdev = pdev;
+	/* Set device type as platform device */
+	e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl;
+	e_ctrl->i2c_client.cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!e_ctrl->i2c_client.cci_client) {
+		rc = -ENOMEM;
+		goto ectrl_free;
+	}
+
+	e_ctrl->eboard_info = kzalloc(sizeof(
+		struct msm_eeprom_board_info), GFP_KERNEL);
+	if (!e_ctrl->eboard_info) {
+		rc = -ENOMEM;
+		goto cciclient_free;
+	}
+
+	eb_info = e_ctrl->eboard_info;
+	power_info = &eb_info->power_info;
+	cci_client = e_ctrl->i2c_client.cci_client;
+	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->retries = 3;
+	cci_client->id_map = 0;
+	power_info->dev = &pdev->dev;
+
+	/*Get clocks information*/
+	rc = msm_camera_get_clk_info(e_ctrl->pdev,
+		&power_info->clk_info,
+		&power_info->clk_ptr,
+		&power_info->clk_info_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_clk_info rc %d", rc);
+		goto board_free;
+	}
+
+	rc = of_property_read_u32(of_node, "cell-index",
+		&pdev->id);
+	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		goto board_free;
+	}
+	e_ctrl->subdev_id = pdev->id;
+
+	rc = of_property_read_u32(of_node, "qcom,cci-master",
+		&e_ctrl->cci_master);
+	CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
+	if (rc < 0) {
+		pr_err("%s failed rc %d\n", __func__, rc);
+		goto board_free;
+	}
+	cci_client->cci_i2c_master = e_ctrl->cci_master;
+
+	rc = of_property_read_string(of_node, "qcom,eeprom-name",
+		&eb_info->eeprom_name);
+	CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
+		eb_info->eeprom_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		e_ctrl->userspace_probe = 1;
+	}
+
+	rc = msm_eeprom_get_dt_data(e_ctrl);
+	if (rc < 0)
+		goto board_free;
+
+	if (e_ctrl->userspace_probe == 0) {
+		rc = of_property_read_u32(of_node, "qcom,slave-addr",
+			&temp);
+		if (rc < 0) {
+			pr_err("%s failed rc %d\n", __func__, rc);
+			goto board_free;
+		}
+
+		rc = of_property_read_u32(of_node, "qcom,i2c-freq-mode",
+			&e_ctrl->i2c_freq_mode);
+		CDBG("qcom,i2c_freq_mode %d, rc %d\n",
+			e_ctrl->i2c_freq_mode, rc);
+		if (rc < 0) {
+			pr_err("%s qcom,i2c-freq-mode read fail. Setting to 0 %d\n",
+				__func__, rc);
+			e_ctrl->i2c_freq_mode = 0;
+		}
+		if (e_ctrl->i2c_freq_mode >= I2C_MAX_MODES) {
+			pr_err("%s:%d invalid i2c_freq_mode = %d\n",
+				__func__, __LINE__, e_ctrl->i2c_freq_mode);
+			e_ctrl->i2c_freq_mode = 0;
+		}
+		eb_info->i2c_slaveaddr = temp;
+		CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr);
+		eb_info->i2c_freq_mode = e_ctrl->i2c_freq_mode;
+		cci_client->i2c_freq_mode = e_ctrl->i2c_freq_mode;
+		cci_client->sid = eb_info->i2c_slaveaddr >> 1;
+
+		rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data);
+		if (rc < 0)
+			goto board_free;
+
+		rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+			&e_ctrl->i2c_client);
+		if (rc) {
+			pr_err("failed rc %d\n", rc);
+			goto memdata_free;
+		}
+		rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data);
+		if (rc < 0) {
+			pr_err("%s read_eeprom_memory failed\n", __func__);
+			goto power_down;
+		}
+		for (j = 0; j < e_ctrl->cal_data.num_data; j++)
+			CDBG("memory_data[%d] = 0x%X\n", j,
+				e_ctrl->cal_data.mapdata[j]);
+
+		e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data);
+
+		rc = msm_camera_power_down(power_info,
+			e_ctrl->eeprom_device_type, &e_ctrl->i2c_client);
+		if (rc) {
+			pr_err("failed rc %d\n", rc);
+			goto memdata_free;
+		}
+	} else
+		e_ctrl->is_supported = 1;
+
+	v4l2_subdev_init(&e_ctrl->msm_sd.sd,
+		e_ctrl->eeprom_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl);
+	platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd);
+	e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops;
+	e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(e_ctrl->msm_sd.sd.name,
+		ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom");
+	media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL);
+	e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM;
+	msm_sd_register(&e_ctrl->msm_sd);
+
+#ifdef CONFIG_COMPAT
+	msm_cam_copy_v4l2_subdev_fops(&msm_eeprom_v4l2_subdev_fops);
+	msm_eeprom_v4l2_subdev_fops.compat_ioctl32 =
+		msm_eeprom_subdev_fops_ioctl32;
+	e_ctrl->msm_sd.sd.devnode->fops = &msm_eeprom_v4l2_subdev_fops;
+#endif
+
+	e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1;
+	CDBG("%s X\n", __func__);
+	return rc;
+
+power_down:
+	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+memdata_free:
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
+board_free:
+	kfree(e_ctrl->eboard_info);
+cciclient_free:
+	kfree(e_ctrl->i2c_client.cci_client);
+ectrl_free:
+	kfree(e_ctrl);
+	return rc;
+}
+
+static int msm_eeprom_platform_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct msm_eeprom_ctrl_t  *e_ctrl;
+
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd);
+	if (!e_ctrl) {
+		pr_err("%s: eeprom device is NULL\n", __func__);
+		return 0;
+	}
+
+	if (!e_ctrl->eboard_info) {
+		pr_err("%s: board info is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_camera_put_clk_info(e_ctrl->pdev,
+		&e_ctrl->eboard_info->power_info.clk_info,
+		&e_ctrl->eboard_info->power_info.clk_ptr,
+		e_ctrl->eboard_info->power_info.clk_info_size);
+
+	kfree(e_ctrl->i2c_client.cci_client);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
+	if (e_ctrl->eboard_info) {
+		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
+		kfree(e_ctrl->eboard_info);
+	}
+	kfree(e_ctrl);
+	return 0;
+}
+
+static const struct of_device_id msm_eeprom_dt_match[] = {
+	{ .compatible = "qcom,eeprom" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match);
+
+static struct platform_driver msm_eeprom_platform_driver = {
+	.driver = {
+		.name = "qcom,eeprom",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_eeprom_dt_match,
+	},
+	.probe = msm_eeprom_platform_probe,
+	.remove = msm_eeprom_platform_remove,
+};
+
+static const struct i2c_device_id msm_eeprom_i2c_id[] = {
+	{ "msm_eeprom", (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver msm_eeprom_i2c_driver = {
+	.id_table = msm_eeprom_i2c_id,
+	.probe  = msm_eeprom_i2c_probe,
+	.remove = msm_eeprom_i2c_remove,
+	.driver = {
+		.name = "msm_eeprom",
+	},
+};
+
+static struct spi_driver msm_eeprom_spi_driver = {
+	.driver = {
+		.name = "qcom_eeprom",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_eeprom_dt_match,
+	},
+	.probe = msm_eeprom_spi_probe,
+	.remove = msm_eeprom_spi_remove,
+};
+
+static int __init msm_eeprom_init_module(void)
+{
+	int rc = 0;
+
+	CDBG("%s E\n", __func__);
+	rc = platform_driver_register(&msm_eeprom_platform_driver);
+	CDBG("%s:%d platform rc %d\n", __func__, __LINE__, rc);
+	rc = spi_register_driver(&msm_eeprom_spi_driver);
+	CDBG("%s:%d spi rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&msm_eeprom_i2c_driver);
+}
+
+static void __exit msm_eeprom_exit_module(void)
+{
+	platform_driver_unregister(&msm_eeprom_platform_driver);
+	spi_unregister_driver(&msm_eeprom_spi_driver);
+	i2c_del_driver(&msm_eeprom_i2c_driver);
+}
+
+module_init(msm_eeprom_init_module);
+module_exit(msm_eeprom_exit_module);
+MODULE_DESCRIPTION("MSM EEPROM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h
new file mode 100644
index 0000000..5596846
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2011-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_EEPROM_H
+#define MSM_EEPROM_H
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <soc/qcom/camera2.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_spi.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+
+struct msm_eeprom_ctrl_t;
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+#define PROPERTY_MAXSIZE 32
+
+struct msm_eeprom_ctrl_t {
+	struct platform_device *pdev;
+	struct mutex *eeprom_mutex;
+
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops;
+	enum msm_camera_device_type_t eeprom_device_type;
+	struct msm_sd_subdev msm_sd;
+	enum cci_i2c_master_t cci_master;
+	enum i2c_freq_mode_t i2c_freq_mode;
+
+	struct msm_camera_i2c_client i2c_client;
+	struct msm_eeprom_board_info *eboard_info;
+	uint32_t subdev_id;
+	int32_t userspace_probe;
+	struct msm_eeprom_memory_block_t cal_data;
+	uint8_t is_supported;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
new file mode 100644
index 0000000..6a28da5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_flash.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
new file mode 100644
index 0000000..656b1ca
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -0,0 +1,1404 @@
+/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/leds-qpnp-flash.h>
+#include "msm_flash.h"
+#include "msm_camera_dt_util.h"
+#include "msm_cci.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+DEFINE_MSM_MUTEX(msm_flash_mutex);
+
+static struct v4l2_file_operations msm_flash_v4l2_subdev_fops;
+static struct led_trigger *torch_trigger;
+
+static const struct of_device_id msm_flash_dt_match[] = {
+	{.compatible = "qcom,camera-flash", .data = NULL},
+	{}
+};
+
+static struct msm_flash_table msm_i2c_flash_table;
+static struct msm_flash_table msm_gpio_flash_table;
+static struct msm_flash_table msm_pmic_flash_table;
+
+static struct msm_flash_table *flash_table[] = {
+	&msm_i2c_flash_table,
+	&msm_gpio_flash_table,
+	&msm_pmic_flash_table
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
+};
+
+static void msm_torch_brightness_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (!torch_trigger) {
+		pr_err("No torch trigger found, can't set brightness\n");
+		return;
+	}
+
+	led_trigger_event(torch_trigger, value);
+};
+
+static struct led_classdev msm_torch_led[MAX_LED_TRIGGERS] = {
+	{
+		.name		= "torch-light0",
+		.brightness_set	= msm_torch_brightness_set,
+		.brightness	= LED_OFF,
+	},
+	{
+		.name		= "torch-light1",
+		.brightness_set	= msm_torch_brightness_set,
+		.brightness	= LED_OFF,
+	},
+	{
+		.name		= "torch-light2",
+		.brightness_set	= msm_torch_brightness_set,
+		.brightness	= LED_OFF,
+	},
+};
+
+static int32_t msm_torch_create_classdev(struct platform_device *pdev,
+				void *data)
+{
+	int32_t rc = 0;
+	int32_t i = 0;
+	struct msm_flash_ctrl_t *fctrl =
+		(struct msm_flash_ctrl_t *)data;
+
+	if (!fctrl) {
+		pr_err("Invalid fctrl\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < fctrl->torch_num_sources; i++) {
+		if (fctrl->torch_trigger[i]) {
+			torch_trigger = fctrl->torch_trigger[i];
+			CDBG("%s:%d msm_torch_brightness_set for torch %d",
+				__func__, __LINE__, i);
+			msm_torch_brightness_set(&msm_torch_led[i],
+				LED_OFF);
+
+			rc = led_classdev_register(&pdev->dev,
+				&msm_torch_led[i]);
+			if (rc) {
+				pr_err("Failed to register %d led dev. rc = %d\n",
+						i, rc);
+				return rc;
+			}
+		} else {
+			pr_err("Invalid fctrl->torch_trigger[%d]\n", i);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+};
+
+static int32_t msm_flash_get_subdev_id(
+	struct msm_flash_ctrl_t *flash_ctrl, void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	if (flash_ctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		*subdev_id = flash_ctrl->pdev->id;
+	else
+		*subdev_id = flash_ctrl->subdev_id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_flash_i2c_write_table(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_camera_i2c_reg_setting_array *settings)
+{
+	struct msm_camera_i2c_reg_setting conf_array;
+
+	conf_array.addr_type = settings->addr_type;
+	conf_array.data_type = settings->data_type;
+	conf_array.delay = settings->delay;
+	conf_array.reg_setting = settings->reg_setting_a;
+	conf_array.size = settings->size;
+
+	/* Validate the settings size */
+	if ((!conf_array.size) || (conf_array.size > MAX_I2C_REG_SET)) {
+		pr_err("failed: invalid size %d", conf_array.size);
+		return -EINVAL;
+	}
+
+	return flash_ctrl->flash_i2c_client.i2c_func_tbl->i2c_write_table(
+		&flash_ctrl->flash_i2c_client, &conf_array);
+}
+
+#ifdef CONFIG_COMPAT
+static void msm_flash_copy_power_settings_compat(
+	struct msm_sensor_power_setting *ps,
+	struct msm_sensor_power_setting32 *ps32, uint32_t size)
+{
+	uint16_t i = 0;
+
+	for (i = 0; i < size; i++) {
+		ps[i].config_val = ps32[i].config_val;
+		ps[i].delay = ps32[i].delay;
+		ps[i].seq_type = ps32[i].seq_type;
+		ps[i].seq_val = ps32[i].seq_val;
+	}
+}
+#endif
+
+static int32_t msm_flash_i2c_init(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	int32_t rc = 0;
+	struct msm_flash_init_info_t *flash_init_info =
+		flash_data->cfg.flash_init_info;
+	struct msm_camera_i2c_reg_setting_array *settings = NULL;
+	struct msm_camera_cci_client *cci_client = NULL;
+#ifdef CONFIG_COMPAT
+	struct msm_sensor_power_setting_array32 *power_setting_array32 = NULL;
+#endif
+	if (!flash_init_info || !flash_init_info->power_setting_array) {
+		pr_err("%s:%d failed: Null pointer\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		power_setting_array32 = kzalloc(
+			sizeof(struct msm_sensor_power_setting_array32),
+			GFP_KERNEL);
+		if (!power_setting_array32) {
+			pr_err("%s mem allocation failed %d\n",
+				__func__, __LINE__);
+			return -ENOMEM;
+		}
+
+		if (copy_from_user(power_setting_array32,
+			(void __user *)flash_init_info->power_setting_array,
+			sizeof(struct msm_sensor_power_setting_array32))) {
+			pr_err("%s copy_from_user failed %d\n",
+				__func__, __LINE__);
+			kfree(power_setting_array32);
+			return -EFAULT;
+		}
+
+		flash_ctrl->power_setting_array.size =
+			power_setting_array32->size;
+		flash_ctrl->power_setting_array.size_down =
+			power_setting_array32->size_down;
+
+		flash_ctrl->power_setting_array.power_down_setting =
+			kzalloc(sizeof(struct msm_sensor_power_setting)*
+			flash_ctrl->power_setting_array.size_down, GFP_KERNEL);
+		if (!flash_ctrl->power_setting_array.power_down_setting)
+			return -ENOMEM;
+		if (copy_from_user(
+			flash_ctrl->power_setting_array.power_down_setting,
+			(void __user *)
+			compat_ptr(power_setting_array32->power_down_setting),
+			sizeof(struct msm_sensor_power_setting)*
+			flash_ctrl->power_setting_array.size_down)) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+
+		flash_ctrl->power_setting_array.power_setting =
+			kzalloc(sizeof(struct msm_sensor_power_setting)*
+			flash_ctrl->power_setting_array.size, GFP_KERNEL);
+		if (!flash_ctrl->power_setting_array.power_setting)
+			return -ENOMEM;
+		if (copy_from_user(
+			flash_ctrl->power_setting_array.power_setting,
+			(void __user *)
+			compat_ptr(power_setting_array32->power_setting),
+			sizeof(struct msm_sensor_power_setting)*
+			flash_ctrl->power_setting_array.size)) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+
+		/* Validate power_up array size and power_down array size */
+		if ((!flash_ctrl->power_setting_array.size) ||
+			(flash_ctrl->power_setting_array.size >
+			MAX_POWER_CONFIG) ||
+			(!flash_ctrl->power_setting_array.size_down) ||
+			(flash_ctrl->power_setting_array.size_down >
+			MAX_POWER_CONFIG)) {
+
+			pr_err("failed: invalid size %d, size_down %d",
+				flash_ctrl->power_setting_array.size,
+				flash_ctrl->power_setting_array.size_down);
+			kfree(power_setting_array32);
+			power_setting_array32 = NULL;
+			return -EINVAL;
+		}
+		/* Copy the settings from compat struct to regular struct */
+		msm_flash_copy_power_settings_compat(
+			flash_ctrl->power_setting_array.power_setting_a,
+			power_setting_array32->power_setting_a,
+			flash_ctrl->power_setting_array.size);
+
+		msm_flash_copy_power_settings_compat(
+			flash_ctrl->power_setting_array.power_down_setting_a,
+			power_setting_array32->power_down_setting_a,
+			flash_ctrl->power_setting_array.size_down);
+	} else
+#endif
+	if (copy_from_user(&flash_ctrl->power_setting_array,
+		(void __user *)flash_init_info->power_setting_array,
+		sizeof(struct msm_sensor_power_setting_array))) {
+		pr_err("%s copy_from_user failed %d\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if (flash_ctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = flash_ctrl->flash_i2c_client.cci_client;
+		cci_client->sid = flash_init_info->slave_addr >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->i2c_freq_mode = flash_init_info->i2c_freq_mode;
+	}
+
+	flash_ctrl->power_info.power_setting =
+		flash_ctrl->power_setting_array.power_setting_a;
+	flash_ctrl->power_info.power_down_setting =
+		flash_ctrl->power_setting_array.power_down_setting_a;
+	flash_ctrl->power_info.power_setting_size =
+		flash_ctrl->power_setting_array.size;
+	flash_ctrl->power_info.power_down_setting_size =
+		flash_ctrl->power_setting_array.size_down;
+
+	if ((flash_ctrl->power_info.power_setting_size > MAX_POWER_CONFIG) ||
+	(flash_ctrl->power_info.power_down_setting_size > MAX_POWER_CONFIG)) {
+		pr_err("%s:%d invalid power setting size=%d size_down=%d\n",
+			__func__, __LINE__,
+			flash_ctrl->power_info.power_setting_size,
+			flash_ctrl->power_info.power_down_setting_size);
+		rc = -EINVAL;
+		goto msm_flash_i2c_init_fail;
+	}
+
+	rc = msm_camera_power_up(&flash_ctrl->power_info,
+		flash_ctrl->flash_device_type,
+		&flash_ctrl->flash_i2c_client);
+	if (rc < 0) {
+		pr_err("%s msm_camera_power_up failed %d\n",
+			__func__, __LINE__);
+		goto msm_flash_i2c_init_fail;
+	}
+
+	if (flash_data->cfg.flash_init_info->settings) {
+		settings = kzalloc(sizeof(
+			struct msm_camera_i2c_reg_setting_array), GFP_KERNEL);
+		if (!settings)
+			return -ENOMEM;
+
+		if (copy_from_user(settings, (void __user *)
+			flash_init_info->settings,
+			sizeof(struct msm_camera_i2c_reg_setting_array))) {
+			kfree(settings);
+			pr_err("%s copy_from_user failed %d\n",
+				__func__, __LINE__);
+			return -EFAULT;
+		}
+
+		rc = msm_flash_i2c_write_table(flash_ctrl, settings);
+		kfree(settings);
+
+		if (rc < 0) {
+			pr_err("%s:%d msm_flash_i2c_write_table rc %d failed\n",
+				__func__, __LINE__, rc);
+		}
+	}
+
+	return 0;
+
+msm_flash_i2c_init_fail:
+	return rc;
+}
+
+static int32_t msm_flash_gpio_init(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	int32_t i = 0;
+	int32_t rc = 0;
+
+	CDBG("Enter");
+	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
+		flash_ctrl->flash_op_current[i] = LED_FULL;
+
+	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
+		flash_ctrl->torch_op_current[i] = LED_HALF;
+
+	for (i = 0; i < flash_ctrl->torch_num_sources; i++) {
+		if (!flash_ctrl->torch_trigger[i]) {
+			if (i < flash_ctrl->flash_num_sources)
+				flash_ctrl->torch_trigger[i] =
+					flash_ctrl->flash_trigger[i];
+			else
+				flash_ctrl->torch_trigger[i] =
+					flash_ctrl->flash_trigger[
+					flash_ctrl->flash_num_sources - 1];
+		}
+	}
+
+	rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, flash_data);
+
+	CDBG("Exit");
+	return rc;
+}
+
+static int32_t msm_flash_i2c_release(
+	struct msm_flash_ctrl_t *flash_ctrl)
+{
+	int32_t rc = 0;
+
+	if (!(&flash_ctrl->power_info) || !(&flash_ctrl->flash_i2c_client)) {
+		pr_err("%s:%d failed: %pK %pK\n",
+			__func__, __LINE__, &flash_ctrl->power_info,
+			&flash_ctrl->flash_i2c_client);
+		return -EINVAL;
+	}
+
+	rc = msm_camera_power_down(&flash_ctrl->power_info,
+		flash_ctrl->flash_device_type,
+		&flash_ctrl->flash_i2c_client);
+	if (rc < 0) {
+		pr_err("%s msm_camera_power_down failed %d\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int32_t msm_flash_off(struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	int32_t i = 0;
+
+	CDBG("Enter\n");
+
+	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
+		if (flash_ctrl->flash_trigger[i])
+			led_trigger_event(flash_ctrl->flash_trigger[i], 0);
+
+	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
+		if (flash_ctrl->torch_trigger[i])
+			led_trigger_event(flash_ctrl->torch_trigger[i], 0);
+	if (flash_ctrl->switch_trigger)
+		led_trigger_event(flash_ctrl->switch_trigger, 0);
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_flash_i2c_write_setting_array(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	int32_t rc = 0;
+	struct msm_camera_i2c_reg_setting_array *settings = NULL;
+
+	if (!flash_data->cfg.settings) {
+		pr_err("%s:%d failed: Null pointer\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	settings = kzalloc(sizeof(struct msm_camera_i2c_reg_setting_array),
+		GFP_KERNEL);
+	if (!settings)
+		return -ENOMEM;
+
+	if (copy_from_user(settings, (void __user *)flash_data->cfg.settings,
+		sizeof(struct msm_camera_i2c_reg_setting_array))) {
+		kfree(settings);
+		pr_err("%s copy_from_user failed %d\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	rc = msm_flash_i2c_write_table(flash_ctrl, settings);
+	kfree(settings);
+
+	if (rc < 0) {
+		pr_err("%s:%d msm_flash_i2c_write_table rc = %d failed\n",
+			__func__, __LINE__, rc);
+	}
+	return rc;
+}
+
+static int32_t msm_flash_init(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	uint32_t i = 0;
+	int32_t rc = -EFAULT;
+	enum msm_flash_driver_type flash_driver_type = FLASH_DRIVER_DEFAULT;
+
+	CDBG("Enter");
+
+	if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT) {
+		pr_err("%s:%d Invalid flash state = %d",
+			__func__, __LINE__, flash_ctrl->flash_state);
+		return 0;
+	}
+
+	if (flash_data->cfg.flash_init_info->flash_driver_type ==
+		FLASH_DRIVER_DEFAULT) {
+		flash_driver_type = flash_ctrl->flash_driver_type;
+		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+			flash_data->flash_current[i] =
+				flash_ctrl->flash_max_current[i];
+			flash_data->flash_duration[i] =
+				flash_ctrl->flash_max_duration[i];
+		}
+	} else if (flash_data->cfg.flash_init_info->flash_driver_type ==
+		flash_ctrl->flash_driver_type) {
+		flash_driver_type = flash_ctrl->flash_driver_type;
+		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+			flash_ctrl->flash_max_current[i] =
+				flash_data->flash_current[i];
+			flash_ctrl->flash_max_duration[i] =
+					flash_data->flash_duration[i];
+		}
+	}
+
+	if (flash_driver_type == FLASH_DRIVER_DEFAULT) {
+		pr_err("%s:%d invalid flash_driver_type", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(flash_table); i++) {
+		if (flash_driver_type == flash_table[i]->flash_driver_type) {
+			flash_ctrl->func_tbl = &flash_table[i]->func_tbl;
+			rc = 0;
+		}
+	}
+
+	if (rc < 0) {
+		pr_err("%s:%d failed invalid flash_driver_type %d\n",
+			__func__, __LINE__,
+			flash_data->cfg.flash_init_info->flash_driver_type);
+	}
+
+	if (flash_ctrl->func_tbl->camera_flash_init) {
+		rc = flash_ctrl->func_tbl->camera_flash_init(
+				flash_ctrl, flash_data);
+		if (rc < 0) {
+			pr_err("%s:%d camera_flash_init failed rc = %d",
+				__func__, __LINE__, rc);
+			return rc;
+		}
+	}
+
+	flash_ctrl->flash_state = MSM_CAMERA_FLASH_INIT;
+
+	CDBG("Exit");
+	return 0;
+}
+
+static int32_t msm_flash_init_prepare(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+#ifdef CONFIG_COMPAT
+	struct msm_flash_cfg_data_t flash_data_k;
+	struct msm_flash_init_info_t flash_init_info;
+	int32_t i = 0;
+
+	if (!is_compat_task()) {
+		/*for 64-bit usecase,it need copy the data to local memory*/
+		flash_data_k.cfg_type = flash_data->cfg_type;
+		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+			flash_data_k.flash_current[i] =
+				flash_data->flash_current[i];
+			flash_data_k.flash_duration[i] =
+				flash_data->flash_duration[i];
+		}
+
+		flash_data_k.cfg.flash_init_info = &flash_init_info;
+		if (copy_from_user(&flash_init_info,
+			(void __user *)(flash_data->cfg.flash_init_info),
+			sizeof(struct msm_flash_init_info_t))) {
+			pr_err("%s copy_from_user failed %d\n",
+				__func__, __LINE__);
+			return -EFAULT;
+		}
+		return msm_flash_init(flash_ctrl, &flash_data_k);
+	}
+	/*
+	 * for 32-bit usecase,it already copy the userspace
+	 * data to local memory in msm_flash_subdev_do_ioctl()
+	 * so here do not need copy from user
+	 */
+	return msm_flash_init(flash_ctrl, flash_data);
+#else
+	struct msm_flash_cfg_data_t flash_data_k;
+	struct msm_flash_init_info_t flash_init_info;
+	int32_t i = 0;
+
+	flash_data_k.cfg_type = flash_data->cfg_type;
+	for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+		flash_data_k.flash_current[i] =
+			flash_data->flash_current[i];
+		flash_data_k.flash_duration[i] =
+			flash_data->flash_duration[i];
+	}
+
+	flash_data_k.cfg.flash_init_info = &flash_init_info;
+	if (copy_from_user(&flash_init_info,
+		(void __user *)(flash_data->cfg.flash_init_info),
+		sizeof(struct msm_flash_init_info_t))) {
+		pr_err("%s copy_from_user failed %d\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+	return msm_flash_init(flash_ctrl, &flash_data_k);
+#endif
+}
+
+static int32_t msm_flash_prepare(
+	struct msm_flash_ctrl_t *flash_ctrl)
+{
+	int32_t ret = 0;
+
+	CDBG("%s:%d: State : %d\n",
+		__func__, __LINE__, flash_ctrl->flash_state);
+
+	if (flash_ctrl->switch_trigger == NULL) {
+		pr_err("%s:%d Invalid argument\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT &&
+		flash_ctrl->is_regulator_enabled == 0) {
+		ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
+				ENABLE_REGULATOR, NULL);
+		if (ret < 0) {
+			pr_err("%s:%d regulator enable failed ret = %d\n",
+				__func__, __LINE__, ret);
+			return ret;
+		}
+		flash_ctrl->is_regulator_enabled = 1;
+	} else if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE &&
+		flash_ctrl->is_regulator_enabled) {
+		ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
+				DISABLE_REGULATOR, NULL);
+		if (ret < 0) {
+			pr_err("%s:%d regulator disable failed ret = %d\n",
+				__func__, __LINE__, ret);
+			return ret;
+		}
+		flash_ctrl->is_regulator_enabled = 0;
+	}
+	CDBG("%s:%d:Exit\n", __func__, __LINE__);
+	return ret;
+}
+
+static int32_t msm_flash_low(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	uint32_t curr = 0, max_current = 0;
+	int32_t i = 0;
+
+	CDBG("Enter\n");
+	/* Turn off flash triggers */
+	for (i = 0; i < flash_ctrl->flash_num_sources; i++)
+		if (flash_ctrl->flash_trigger[i])
+			led_trigger_event(flash_ctrl->flash_trigger[i], 0);
+
+	/* Turn on flash triggers */
+	for (i = 0; i < flash_ctrl->torch_num_sources; i++) {
+		if (flash_ctrl->torch_trigger[i]) {
+			max_current = flash_ctrl->torch_max_current[i];
+			if (flash_data->flash_current[i] >= 0 &&
+				flash_data->flash_current[i] <
+				max_current) {
+				curr = flash_data->flash_current[i];
+			} else {
+				curr = flash_ctrl->torch_op_current[i];
+				pr_debug("LED current clamped to %d\n",
+					curr);
+			}
+			CDBG("low_flash_current[%d] = %d", i, curr);
+			led_trigger_event(flash_ctrl->torch_trigger[i],
+				curr);
+		}
+	}
+	if (flash_ctrl->switch_trigger)
+		led_trigger_event(flash_ctrl->switch_trigger, 1);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_flash_high(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_cfg_data_t *flash_data)
+{
+	int32_t curr = 0;
+	int32_t max_current = 0;
+	int32_t i = 0;
+
+	/* Turn off torch triggers */
+	for (i = 0; i < flash_ctrl->torch_num_sources; i++)
+		if (flash_ctrl->torch_trigger[i])
+			led_trigger_event(flash_ctrl->torch_trigger[i], 0);
+
+	/* Turn on flash triggers */
+	for (i = 0; i < flash_ctrl->flash_num_sources; i++) {
+		if (flash_ctrl->flash_trigger[i]) {
+			max_current = flash_ctrl->flash_max_current[i];
+			if (flash_data->flash_current[i] >= 0 &&
+				flash_data->flash_current[i] <
+				max_current) {
+				curr = flash_data->flash_current[i];
+			} else {
+				curr = flash_ctrl->flash_op_current[i];
+				pr_debug("LED flash_current[%d] clamped %d\n",
+					i, curr);
+			}
+			CDBG("high_flash_current[%d] = %d", i, curr);
+			led_trigger_event(flash_ctrl->flash_trigger[i],
+				curr);
+		}
+	}
+	if (flash_ctrl->switch_trigger)
+		led_trigger_event(flash_ctrl->switch_trigger, 1);
+	return 0;
+}
+
+static int32_t msm_flash_query_current(
+	struct msm_flash_ctrl_t *flash_ctrl,
+	struct msm_flash_query_data_t *flash_query_data)
+{
+	int32_t ret = -EINVAL;
+	int32_t max_current = -EINVAL;
+
+	if (flash_ctrl->switch_trigger) {
+		ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
+					QUERY_MAX_CURRENT, &max_current);
+		if (ret < 0) {
+			pr_err("%s:%d Query max_avail_curr failed ret = %d\n",
+				__func__, __LINE__, ret);
+			return ret;
+		}
+	}
+
+	flash_query_data->max_avail_curr = max_current;
+	CDBG("%s: %d: max_avail_curr : %d\n", __func__, __LINE__,
+			flash_query_data->max_avail_curr);
+	return 0;
+}
+
+static int32_t msm_flash_release(
+	struct msm_flash_ctrl_t *flash_ctrl)
+{
+	int32_t rc = 0;
+
+	rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, NULL);
+	if (rc < 0) {
+		pr_err("%s:%d camera_flash_init failed rc = %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+	flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE;
+	return 0;
+}
+
+static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl,
+	void *argp)
+{
+	int32_t rc = 0;
+	struct msm_flash_cfg_data_t *flash_data =
+		(struct msm_flash_cfg_data_t *) argp;
+
+	mutex_lock(flash_ctrl->flash_mutex);
+
+	CDBG("Enter %s type %d\n", __func__, flash_data->cfg_type);
+
+	switch (flash_data->cfg_type) {
+	case CFG_FLASH_INIT:
+		rc = msm_flash_init_prepare(flash_ctrl, flash_data);
+		break;
+	case CFG_FLASH_RELEASE:
+		if (flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) {
+			rc = flash_ctrl->func_tbl->camera_flash_release(
+				flash_ctrl);
+		} else {
+			CDBG(pr_fmt("Invalid state : %d\n"),
+				flash_ctrl->flash_state);
+		}
+		break;
+	case CFG_FLASH_OFF:
+		if ((flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) &&
+			(flash_ctrl->flash_state != MSM_CAMERA_FLASH_OFF)) {
+			rc = flash_ctrl->func_tbl->camera_flash_off(
+				flash_ctrl, flash_data);
+			if (!rc)
+				flash_ctrl->flash_state = MSM_CAMERA_FLASH_OFF;
+		} else {
+			CDBG(pr_fmt("Invalid state : %d\n"),
+				flash_ctrl->flash_state);
+		}
+		break;
+	case CFG_FLASH_LOW:
+		if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) ||
+			(flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) {
+			rc = flash_ctrl->func_tbl->camera_flash_low(
+				flash_ctrl, flash_data);
+			if (!rc)
+				flash_ctrl->flash_state = MSM_CAMERA_FLASH_LOW;
+		} else {
+			CDBG(pr_fmt("Invalid state : %d\n"),
+				flash_ctrl->flash_state);
+		}
+		break;
+	case CFG_FLASH_HIGH:
+		if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) ||
+			(flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) {
+			rc = flash_ctrl->func_tbl->camera_flash_high(
+				flash_ctrl, flash_data);
+			if (!rc)
+				flash_ctrl->flash_state = MSM_CAMERA_FLASH_HIGH;
+		} else {
+			CDBG(pr_fmt("Invalid state : %d\n"),
+				flash_ctrl->flash_state);
+		}
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(flash_ctrl->flash_mutex);
+
+	rc = msm_flash_prepare(flash_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d Enable/Disable Regulator failed ret = %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	CDBG("Exit %s type %d\n", __func__, flash_data->cfg_type);
+
+	return rc;
+}
+
+static int32_t msm_flash_query_data(struct msm_flash_ctrl_t *flash_ctrl,
+	void *argp)
+{
+	int32_t rc = -EINVAL, i = 0;
+	struct msm_flash_query_data_t *flash_query =
+		(struct msm_flash_query_data_t *) argp;
+
+	CDBG("Enter %s type %d\n", __func__, flash_query->query_type);
+
+	switch (flash_query->query_type) {
+	case FLASH_QUERY_CURRENT:
+		if (flash_ctrl->func_tbl && flash_ctrl->func_tbl->
+				camera_flash_query_current != NULL)
+			rc = flash_ctrl->func_tbl->
+				camera_flash_query_current(
+				flash_ctrl, flash_query);
+		else {
+			flash_query->max_avail_curr = 0;
+			for (i = 0; i < flash_ctrl->flash_num_sources; i++) {
+				flash_query->max_avail_curr +=
+					flash_ctrl->flash_op_current[i];
+			}
+			rc = 0;
+			CDBG("%s: max_avail_curr: %d\n", __func__,
+				flash_query->max_avail_curr);
+		}
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	CDBG("Exit %s type %d\n", __func__, flash_query->query_type);
+
+	return rc;
+}
+
+static long msm_flash_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_flash_ctrl_t *fctrl = NULL;
+	void *argp = (void *)arg;
+
+	CDBG("Enter\n");
+
+	if (!sd) {
+		pr_err("sd NULL\n");
+		return -EINVAL;
+	}
+	fctrl = v4l2_get_subdevdata(sd);
+	if (!fctrl) {
+		pr_err("fctrl NULL\n");
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_flash_get_subdev_id(fctrl, argp);
+	case VIDIOC_MSM_FLASH_CFG:
+		return msm_flash_config(fctrl, argp);
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_SHUTDOWN:
+		if (!fctrl->func_tbl) {
+			pr_err("fctrl->func_tbl NULL\n");
+		} else {
+			fctrl->func_tbl->camera_flash_release(fctrl);
+			return msm_flash_prepare(fctrl);
+		}
+		return -EINVAL;
+	case VIDIOC_MSM_FLASH_QUERY_DATA:
+		return msm_flash_query_data(fctrl, argp);
+	default:
+		pr_err_ratelimited("invalid cmd %d\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+	CDBG("Exit\n");
+}
+
+static struct v4l2_subdev_core_ops msm_flash_subdev_core_ops = {
+	.ioctl = msm_flash_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_flash_subdev_ops = {
+	.core = &msm_flash_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_flash_internal_ops;
+
+static int32_t msm_flash_get_pmic_source_info(
+	struct device_node *of_node,
+	struct msm_flash_ctrl_t *fctrl)
+{
+	int32_t rc = 0;
+	uint32_t count = 0, i = 0;
+	struct device_node *flash_src_node = NULL;
+	struct device_node *torch_src_node = NULL;
+	struct device_node *switch_src_node = NULL;
+
+	switch_src_node = of_parse_phandle(of_node, "qcom,switch-source", 0);
+	if (!switch_src_node) {
+		CDBG("%s:%d switch_src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_string(switch_src_node,
+			"qcom,default-led-trigger",
+			&fctrl->switch_trigger_name);
+		if (rc < 0) {
+			rc = of_property_read_string(switch_src_node,
+				"linux,default-trigger",
+				&fctrl->switch_trigger_name);
+			if (rc < 0)
+				pr_err("default-trigger read failed\n");
+		}
+		of_node_put(switch_src_node);
+		switch_src_node = NULL;
+		if (!rc) {
+			CDBG("switch trigger %s\n",
+				fctrl->switch_trigger_name);
+			led_trigger_register_simple(
+				fctrl->switch_trigger_name,
+				&fctrl->switch_trigger);
+		}
+	}
+
+	if (of_get_property(of_node, "qcom,flash-source", &count)) {
+		count /= sizeof(uint32_t);
+		CDBG("count %d\n", count);
+		if (count > MAX_LED_TRIGGERS) {
+			pr_err("invalid count\n");
+			return -EINVAL;
+		}
+		fctrl->flash_num_sources = count;
+		CDBG("%s:%d flash_num_sources = %d",
+			__func__, __LINE__, fctrl->flash_num_sources);
+		for (i = 0; i < count; i++) {
+			flash_src_node = of_parse_phandle(of_node,
+				"qcom,flash-source", i);
+			if (!flash_src_node) {
+				pr_err("flash_src_node NULL\n");
+				continue;
+			}
+
+			rc = of_property_read_string(flash_src_node,
+				"qcom,default-led-trigger",
+				&fctrl->flash_trigger_name[i]);
+			if (rc < 0) {
+				rc = of_property_read_string(flash_src_node,
+					"linux,default-trigger",
+					&fctrl->flash_trigger_name[i]);
+				if (rc < 0) {
+					pr_err("default-trigger read failed\n");
+					of_node_put(flash_src_node);
+					continue;
+				}
+			}
+
+			CDBG("default trigger %s\n",
+				fctrl->flash_trigger_name[i]);
+
+			/* Read operational-current */
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,current",
+				&fctrl->flash_op_current[i]);
+			if (rc < 0) {
+				rc = of_property_read_u32(flash_src_node,
+					"qcom,current-ma",
+					&fctrl->flash_op_current[i]);
+				if (rc < 0) {
+					pr_err("current: read failed\n");
+					of_node_put(flash_src_node);
+					continue;
+				}
+			}
+
+			/* Read max-current */
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,max-current",
+				&fctrl->flash_max_current[i]);
+			if (rc < 0) {
+				pr_err("current: read failed\n");
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			/* Read max-duration */
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,duration",
+				&fctrl->flash_max_duration[i]);
+			if (rc < 0) {
+				rc = of_property_read_u32(flash_src_node,
+					"qcom,duration-ms",
+					&fctrl->flash_max_duration[i]);
+				if (rc < 0) {
+					pr_err("duration: read failed\n");
+					of_node_put(flash_src_node);
+				}
+				/* Non-fatal; this property is optional */
+			}
+
+			of_node_put(flash_src_node);
+
+			CDBG("max_current[%d] %d\n",
+				i, fctrl->flash_op_current[i]);
+
+			led_trigger_register_simple(
+				fctrl->flash_trigger_name[i],
+				&fctrl->flash_trigger[i]);
+		}
+		if (fctrl->flash_driver_type == FLASH_DRIVER_DEFAULT)
+			fctrl->flash_driver_type = FLASH_DRIVER_PMIC;
+		CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__,
+			fctrl->flash_driver_type);
+	}
+
+	if (of_get_property(of_node, "qcom,torch-source", &count)) {
+		count /= sizeof(uint32_t);
+		CDBG("count %d\n", count);
+		if (count > MAX_LED_TRIGGERS) {
+			pr_err("invalid count\n");
+			return -EINVAL;
+		}
+		fctrl->torch_num_sources = count;
+		CDBG("%s:%d torch_num_sources = %d",
+			__func__, __LINE__, fctrl->torch_num_sources);
+		for (i = 0; i < count; i++) {
+			torch_src_node = of_parse_phandle(of_node,
+				"qcom,torch-source", i);
+			if (!torch_src_node) {
+				pr_err("torch_src_node NULL\n");
+				continue;
+			}
+
+			rc = of_property_read_string(torch_src_node,
+				"qcom,default-led-trigger",
+				&fctrl->torch_trigger_name[i]);
+			if (rc < 0) {
+				rc = of_property_read_string(torch_src_node,
+					"linux,default-trigger",
+					&fctrl->torch_trigger_name[i]);
+				if (rc < 0) {
+					pr_err("default-trigger read failed\n");
+					of_node_put(torch_src_node);
+					continue;
+				}
+			}
+
+			CDBG("default trigger %s\n",
+				fctrl->torch_trigger_name[i]);
+
+			/* Read operational-current */
+			rc = of_property_read_u32(torch_src_node,
+				"qcom,current",
+				&fctrl->torch_op_current[i]);
+			if (rc < 0) {
+				rc = of_property_read_u32(torch_src_node,
+					"qcom,current-ma",
+					&fctrl->torch_op_current[i]);
+				if (rc < 0) {
+					pr_err("current: read failed\n");
+					of_node_put(torch_src_node);
+					continue;
+				}
+			}
+
+			/* Read max-current */
+			rc = of_property_read_u32(torch_src_node,
+				"qcom,max-current",
+				&fctrl->torch_max_current[i]);
+			if (rc < 0) {
+				pr_err("current: read failed\n");
+				of_node_put(torch_src_node);
+				continue;
+			}
+
+			of_node_put(torch_src_node);
+
+			CDBG("max_current[%d] %d\n",
+				i, fctrl->torch_op_current[i]);
+
+			led_trigger_register_simple(
+				fctrl->torch_trigger_name[i],
+				&fctrl->torch_trigger[i]);
+		}
+		if (fctrl->flash_driver_type == FLASH_DRIVER_DEFAULT)
+			fctrl->flash_driver_type = FLASH_DRIVER_PMIC;
+		CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__,
+			fctrl->flash_driver_type);
+	}
+
+	return 0;
+}
+
+static int32_t msm_flash_get_dt_data(struct device_node *of_node,
+	struct msm_flash_ctrl_t *fctrl)
+{
+	int32_t rc = 0;
+
+	CDBG("called\n");
+
+	if (!of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	/* Read the sub device */
+	rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		return rc;
+	}
+
+	CDBG("subdev id %d\n", fctrl->subdev_id);
+
+	fctrl->flash_driver_type = FLASH_DRIVER_DEFAULT;
+
+	/* Read the CCI master. Use M0 if not available in the node */
+	rc = of_property_read_u32(of_node, "qcom,cci-master",
+		&fctrl->cci_i2c_master);
+	CDBG("%s qcom,cci-master %d, rc %d\n", __func__, fctrl->cci_i2c_master,
+		rc);
+	if (rc < 0) {
+		/* Set default master 0 */
+		fctrl->cci_i2c_master = MASTER_0;
+		rc = 0;
+	} else {
+		fctrl->flash_driver_type = FLASH_DRIVER_I2C;
+	}
+
+	/* Read the flash and torch source info from device tree node */
+	rc = msm_flash_get_pmic_source_info(of_node, fctrl);
+	if (rc < 0) {
+		pr_err("%s:%d msm_flash_get_pmic_source_info failed rc %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	/* Read the gpio information from device tree */
+	rc = msm_sensor_driver_get_gpio_data(
+		&(fctrl->power_info.gpio_conf), of_node);
+	if (rc < 0) {
+		pr_err("%s:%d msm_sensor_driver_get_gpio_data failed rc %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	if (fctrl->flash_driver_type == FLASH_DRIVER_DEFAULT)
+		fctrl->flash_driver_type = FLASH_DRIVER_GPIO;
+	CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__,
+		fctrl->flash_driver_type);
+
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_flash_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	int32_t i = 0;
+	int32_t rc = 0;
+	struct video_device *vdev;
+	struct v4l2_subdev *sd;
+	struct msm_flash_cfg_data_t32 *u32;
+	struct msm_flash_cfg_data_t flash_data;
+	struct msm_flash_init_info_t32 flash_init_info32;
+	struct msm_flash_init_info_t flash_init_info;
+
+	CDBG("Enter");
+
+	if (!file || !arg) {
+		pr_err("%s:failed NULL parameter\n", __func__);
+		return -EINVAL;
+	}
+	vdev = video_devdata(file);
+	sd = vdev_to_v4l2_subdev(vdev);
+	u32 = (struct msm_flash_cfg_data_t32 *)arg;
+
+	switch (cmd) {
+	case VIDIOC_MSM_FLASH_CFG32:
+		flash_data.cfg_type = u32->cfg_type;
+		for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+			flash_data.flash_current[i] = u32->flash_current[i];
+			flash_data.flash_duration[i] = u32->flash_duration[i];
+		}
+		cmd = VIDIOC_MSM_FLASH_CFG;
+		switch (flash_data.cfg_type) {
+		case CFG_FLASH_OFF:
+		case CFG_FLASH_LOW:
+		case CFG_FLASH_HIGH:
+			flash_data.cfg.settings = compat_ptr(u32->cfg.settings);
+			break;
+		case CFG_FLASH_INIT:
+			flash_data.cfg.flash_init_info = &flash_init_info;
+			if (copy_from_user(&flash_init_info32,
+				(void __user *)
+				compat_ptr(u32->cfg.flash_init_info),
+				sizeof(struct msm_flash_init_info_t32))) {
+				pr_err("%s copy_from_user failed %d\n",
+					__func__, __LINE__);
+				return -EFAULT;
+			}
+			flash_init_info.flash_driver_type =
+				flash_init_info32.flash_driver_type;
+			flash_init_info.slave_addr =
+				flash_init_info32.slave_addr;
+			flash_init_info.i2c_freq_mode =
+				flash_init_info32.i2c_freq_mode;
+			flash_init_info.settings =
+				compat_ptr(flash_init_info32.settings);
+			flash_init_info.power_setting_array =
+				compat_ptr(
+				flash_init_info32.power_setting_array);
+			break;
+		default:
+			break;
+		}
+		break;
+	case VIDIOC_MSM_FLASH_CFG:
+		pr_err("invalid cmd 0x%x received\n", cmd);
+		return -EINVAL;
+	default:
+		return msm_flash_subdev_ioctl(sd, cmd, arg);
+	}
+
+	rc =  msm_flash_subdev_ioctl(sd, cmd, &flash_data);
+	for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+		u32->flash_current[i] = flash_data.flash_current[i];
+		u32->flash_duration[i] = flash_data.flash_duration[i];
+	}
+	CDBG("Exit");
+	return rc;
+}
+
+static long msm_flash_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_flash_subdev_do_ioctl);
+}
+#endif
+static int32_t msm_flash_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_flash_ctrl_t *flash_ctrl = NULL;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter");
+	if (!pdev->dev.of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	flash_ctrl = kzalloc(sizeof(struct msm_flash_ctrl_t), GFP_KERNEL);
+	if (!flash_ctrl)
+		return -ENOMEM;
+
+	memset(flash_ctrl, 0, sizeof(struct msm_flash_ctrl_t));
+
+	flash_ctrl->pdev = pdev;
+
+	rc = msm_flash_get_dt_data(pdev->dev.of_node, flash_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d msm_flash_get_dt_data failed\n",
+			__func__, __LINE__);
+		kfree(flash_ctrl);
+		return -EINVAL;
+	}
+
+	flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE;
+	flash_ctrl->power_info.dev = &flash_ctrl->pdev->dev;
+	flash_ctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	flash_ctrl->flash_mutex = &msm_flash_mutex;
+	flash_ctrl->flash_i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+	flash_ctrl->flash_i2c_client.cci_client = kzalloc(
+		sizeof(struct msm_camera_cci_client), GFP_KERNEL);
+	if (!flash_ctrl->flash_i2c_client.cci_client) {
+		kfree(flash_ctrl);
+		pr_err("failed no memory\n");
+		return -ENOMEM;
+	}
+
+	cci_client = flash_ctrl->flash_i2c_client.cci_client;
+	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = flash_ctrl->cci_i2c_master;
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&flash_ctrl->msm_sd.sd, &msm_flash_subdev_ops);
+	v4l2_set_subdevdata(&flash_ctrl->msm_sd.sd, flash_ctrl);
+
+	flash_ctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops;
+	flash_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(flash_ctrl->msm_sd.sd.name,
+		ARRAY_SIZE(flash_ctrl->msm_sd.sd.name),
+		"msm_camera_flash");
+	media_entity_pads_init(&flash_ctrl->msm_sd.sd.entity, 0, NULL);
+	flash_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_FLASH;
+	flash_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
+	msm_sd_register(&flash_ctrl->msm_sd);
+
+	CDBG("%s:%d flash sd name = %s", __func__, __LINE__,
+		flash_ctrl->msm_sd.sd.entity.name);
+	msm_cam_copy_v4l2_subdev_fops(&msm_flash_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_flash_v4l2_subdev_fops.compat_ioctl32 =
+		msm_flash_subdev_fops_ioctl;
+#endif
+	flash_ctrl->msm_sd.sd.devnode->fops = &msm_flash_v4l2_subdev_fops;
+
+	if (flash_ctrl->flash_driver_type == FLASH_DRIVER_PMIC)
+		rc = msm_torch_create_classdev(pdev, flash_ctrl);
+
+	CDBG("probe success\n");
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, msm_flash_dt_match);
+
+static struct platform_driver msm_flash_platform_driver = {
+	.probe = msm_flash_platform_probe,
+	.driver = {
+		.name = "qcom,camera-flash",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_flash_dt_match,
+	},
+};
+
+static int __init msm_flash_init_module(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_flash_platform_driver);
+	if (rc)
+		pr_err("platform probe for flash failed");
+
+	return rc;
+}
+
+static void __exit msm_flash_exit_module(void)
+{
+	platform_driver_unregister(&msm_flash_platform_driver);
+}
+
+static struct msm_flash_table msm_pmic_flash_table = {
+	.flash_driver_type = FLASH_DRIVER_PMIC,
+	.func_tbl = {
+		.camera_flash_init = NULL,
+		.camera_flash_release = msm_flash_release,
+		.camera_flash_off = msm_flash_off,
+		.camera_flash_low = msm_flash_low,
+		.camera_flash_high = msm_flash_high,
+		.camera_flash_query_current = msm_flash_query_current,
+	},
+};
+
+static struct msm_flash_table msm_gpio_flash_table = {
+	.flash_driver_type = FLASH_DRIVER_GPIO,
+	.func_tbl = {
+		.camera_flash_init = msm_flash_gpio_init,
+		.camera_flash_release = msm_flash_release,
+		.camera_flash_off = msm_flash_off,
+		.camera_flash_low = msm_flash_low,
+		.camera_flash_high = msm_flash_high,
+		.camera_flash_query_current = NULL,
+	},
+};
+
+static struct msm_flash_table msm_i2c_flash_table = {
+	.flash_driver_type = FLASH_DRIVER_I2C,
+	.func_tbl = {
+		.camera_flash_init = msm_flash_i2c_init,
+		.camera_flash_release = msm_flash_i2c_release,
+		.camera_flash_off = msm_flash_i2c_write_setting_array,
+		.camera_flash_low = msm_flash_i2c_write_setting_array,
+		.camera_flash_high = msm_flash_i2c_write_setting_array,
+		.camera_flash_query_current = NULL,
+	},
+};
+
+module_init(msm_flash_init_module);
+module_exit(msm_flash_exit_module);
+MODULE_DESCRIPTION("MSM FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h
new file mode 100644
index 0000000..eda6ce4
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2009-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef MSM_FLASH_H
+#define MSM_FLASH_H
+
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msm_cam_sensor.h>
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+#include "msm_sd.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+enum msm_camera_flash_state_t {
+	MSM_CAMERA_FLASH_INIT,
+	MSM_CAMERA_FLASH_OFF,
+	MSM_CAMERA_FLASH_LOW,
+	MSM_CAMERA_FLASH_HIGH,
+	MSM_CAMERA_FLASH_RELEASE,
+};
+
+struct msm_flash_ctrl_t;
+
+struct msm_flash_func_t {
+	int32_t (*camera_flash_init)(struct msm_flash_ctrl_t *,
+		struct msm_flash_cfg_data_t *);
+	int32_t (*camera_flash_release)(struct msm_flash_ctrl_t *);
+	int32_t (*camera_flash_off)(struct msm_flash_ctrl_t *,
+		struct msm_flash_cfg_data_t *);
+	int32_t (*camera_flash_low)(struct msm_flash_ctrl_t *,
+		struct msm_flash_cfg_data_t *);
+	int32_t (*camera_flash_high)(struct msm_flash_ctrl_t *,
+		struct msm_flash_cfg_data_t *);
+	int32_t (*camera_flash_query_current)(struct msm_flash_ctrl_t *,
+		struct msm_flash_query_data_t *);
+
+};
+
+struct msm_flash_table {
+	enum msm_flash_driver_type flash_driver_type;
+	struct msm_flash_func_t func_tbl;
+};
+
+struct msm_flash_reg_t {
+	struct msm_camera_i2c_reg_setting *init_setting;
+	struct msm_camera_i2c_reg_setting *off_setting;
+	struct msm_camera_i2c_reg_setting *release_setting;
+	struct msm_camera_i2c_reg_setting *low_setting;
+	struct msm_camera_i2c_reg_setting *high_setting;
+};
+
+struct msm_flash_ctrl_t {
+	struct msm_camera_i2c_client flash_i2c_client;
+	struct msm_sd_subdev msm_sd;
+	struct platform_device *pdev;
+	struct msm_flash_func_t *func_tbl;
+	struct msm_camera_power_ctrl_t power_info;
+
+	/* Switch node to trigger led */
+	const char *switch_trigger_name;
+	struct led_trigger *switch_trigger;
+	uint32_t is_regulator_enabled;
+
+	/* Flash */
+	uint32_t flash_num_sources;
+	const char *flash_trigger_name[MAX_LED_TRIGGERS];
+	struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
+	uint32_t flash_op_current[MAX_LED_TRIGGERS];
+	uint32_t flash_max_current[MAX_LED_TRIGGERS];
+	uint32_t flash_max_duration[MAX_LED_TRIGGERS];
+
+	/* Torch */
+	uint32_t torch_num_sources;
+	const char *torch_trigger_name[MAX_LED_TRIGGERS];
+	struct led_trigger *torch_trigger[MAX_LED_TRIGGERS];
+	uint32_t torch_op_current[MAX_LED_TRIGGERS];
+	uint32_t torch_max_current[MAX_LED_TRIGGERS];
+
+	void *data;
+	enum msm_camera_device_type_t flash_device_type;
+	enum cci_i2c_master_t cci_i2c_master;
+	uint32_t subdev_id;
+	struct mutex *flash_mutex;
+	struct msm_sensor_power_setting_array power_setting_array;
+
+	/* flash driver type */
+	enum msm_flash_driver_type flash_driver_type;
+
+	/* flash state */
+	enum msm_camera_flash_state_t flash_state;
+};
+
+int msm_flash_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+
+int msm_flash_probe(struct platform_device *pdev, const void *data);
+
+int32_t msm_flash_create_v4lsubdev(struct platform_device *pdev,
+	void *data);
+int32_t msm_led_i2c_flash_create_v4lsubdev(void *data);
+
+int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_flash_ctrl_t *fctrl,
+	void *arg);
+
+int32_t msm_led_i2c_trigger_config(struct msm_flash_ctrl_t *fctrl,
+	void *data);
+
+int msm_flash_led_init(struct msm_flash_ctrl_t *fctrl);
+int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl);
+int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl);
+int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl);
+int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/Makefile b/drivers/media/platform/msm/camera_v2/sensor/io/Makefile
new file mode 100644
index 0000000..549c35a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/Makefile
@@ -0,0 +1,6 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+ccflags-y += -Idrivers/misc/
+obj-$(CONFIG_MSMB_CAMERA)   += msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_spi.o msm_camera_dt_util.o msm_camera_tz_i2c.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
new file mode 100644
index 0000000..ae75ca9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -0,0 +1,579 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+#include "msm_cci.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args)
+#define MAX_I2C_ADDR_TYPE_SIZE (MSM_CAMERA_I2C_3B_ADDR + 1)
+#define MAX_I2C_DATA_TYPE_SIZE (MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA + 1)
+
+int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[MAX_I2C_ADDR_TYPE_SIZE + MAX_I2C_DATA_TYPE_SIZE];
+	struct msm_camera_cci_ctrl cci_ctrl;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_3B_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	cci_ctrl.cmd = MSM_CCI_I2C_READ;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_read_cfg.data = buf;
+	cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	rc = cci_ctrl.status;
+	if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
+		*data = buf[0];
+	else
+		*data = buf[0] << 8 | buf[1];
+
+	S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	unsigned char *buf = NULL;
+	int i;
+	struct msm_camera_cci_ctrl cci_ctrl;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_3B_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_DWORD_ADDR)
+		|| num_byte == 0)
+		return rc;
+
+	if (num_byte > I2C_REG_DATA_MAX) {
+		S_I2C_DBG("%s: Error num_byte:0x%x exceeds max:0x%x\n",
+		__func__, num_byte, I2C_REG_DATA_MAX);
+		return rc;
+	}
+
+	buf = kzalloc(num_byte, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	cci_ctrl.cmd = MSM_CCI_I2C_READ;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_read_cfg.data = buf;
+	cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte;
+	cci_ctrl.status = -EFAULT;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
+	rc = cci_ctrl.status;
+
+	S_I2C_DBG("%s addr = 0x%x", __func__, addr);
+	for (i = 0; i < num_byte; i++) {
+		data[i] = buf[i];
+		S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]);
+		S_I2C_DBG("Data: 0x%x\n", data[i]);
+	}
+	kfree(buf);
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
+	struct msm_camera_i2c_reg_array reg_conf_tbl;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	CDBG("%s:%d reg addr = 0x%x data type: %d\n",
+		__func__, __LINE__, addr, data_type);
+	reg_conf_tbl.reg_addr = addr;
+	reg_conf_tbl.reg_data = data;
+	reg_conf_tbl.delay = 0;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = &reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	rc = cci_ctrl.status;
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	uint32_t i = 0;
+	struct msm_camera_cci_ctrl cci_ctrl;
+	struct msm_camera_i2c_reg_array *reg_conf_tbl = NULL;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| num_byte == 0)
+		return rc;
+
+	if (num_byte > I2C_SEQ_REG_DATA_MAX) {
+		pr_err("%s: num_byte=%d clamped to max supported %d\n",
+			__func__, num_byte, I2C_SEQ_REG_DATA_MAX);
+		return rc;
+	}
+
+	S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
+		__func__, addr, num_byte);
+
+	reg_conf_tbl = kzalloc(num_byte *
+		(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+	if (!reg_conf_tbl)
+		return -ENOMEM;
+
+	reg_conf_tbl[0].reg_addr = addr;
+	for (i = 0; i < num_byte; i++) {
+		reg_conf_tbl[i].reg_data = data[i];
+		reg_conf_tbl[i].delay = 0;
+	}
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE_SEQ;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte;
+	cci_ctrl.status = -EFAULT;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
+	rc = cci_ctrl.status;
+	kfree(reg_conf_tbl);
+	reg_conf_tbl = NULL;
+	return rc;
+}
+
+static int32_t msm_camera_cci_i2c_write_table_cmd(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting,
+	enum msm_cci_cmd_type cmd)
+{
+	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	cci_ctrl.cmd = cmd;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	rc = cci_ctrl.status;
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_write_table_async(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	return msm_camera_cci_i2c_write_table_cmd(client, write_setting,
+		MSM_CCI_I2C_WRITE_ASYNC);
+}
+
+int32_t msm_camera_cci_i2c_write_table_sync(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	return msm_camera_cci_i2c_write_table_cmd(client, write_setting,
+		MSM_CCI_I2C_WRITE_SYNC);
+}
+
+int32_t msm_camera_cci_i2c_write_table_sync_block(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	return msm_camera_cci_i2c_write_table_cmd(client, write_setting,
+		MSM_CCI_I2C_WRITE_SYNC_BLOCK);
+}
+
+int32_t msm_camera_cci_i2c_write_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	return msm_camera_cci_i2c_write_table_cmd(client, write_setting,
+		MSM_CCI_I2C_WRITE);
+}
+
+int32_t msm_camera_cci_i2c_write_seq_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_seq_reg_array *reg_setting;
+	uint16_t client_addr_type;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) {
+		pr_err("%s Invalid addr type %d\n", __func__,
+			write_setting->addr_type);
+		return rc;
+	}
+
+	reg_setting = write_setting->reg_setting;
+	client_addr_type = client->addr_type;
+	client->addr_type = write_setting->addr_type;
+
+	if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) {
+		pr_err("%s: number of bytes %u exceeding the max supported %d\n",
+		__func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX);
+		return rc;
+	}
+
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr,
+			reg_setting->reg_data, reg_setting->reg_data_size);
+		if (rc < 0)
+			return rc;
+		reg_setting++;
+	}
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+
+	client->addr_type = client_addr_type;
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	rc = cci_ctrl.status;
+	return rc;
+}
+
+static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc;
+	uint16_t reg_data = 0;
+	int data_len = 0;
+
+	switch (data_type) {
+	case MSM_CAMERA_I2C_BYTE_DATA:
+	case MSM_CAMERA_I2C_WORD_DATA:
+		data_len = data_type;
+		break;
+	case MSM_CAMERA_I2C_SET_BYTE_MASK:
+	case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+		data_len = MSM_CAMERA_I2C_BYTE_DATA;
+		break;
+	case MSM_CAMERA_I2C_SET_WORD_MASK:
+	case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+		data_len = MSM_CAMERA_I2C_WORD_DATA;
+		break;
+	default:
+		pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+		break;
+	}
+
+	rc = msm_camera_cci_i2c_read(client, addr, &reg_data, data_len);
+	if (rc < 0)
+		return rc;
+
+	rc = I2C_COMPARE_MISMATCH;
+	switch (data_type) {
+	case MSM_CAMERA_I2C_BYTE_DATA:
+	case MSM_CAMERA_I2C_WORD_DATA:
+		if (data == reg_data)
+			rc = I2C_COMPARE_MATCH;
+		break;
+	case MSM_CAMERA_I2C_SET_BYTE_MASK:
+	case MSM_CAMERA_I2C_SET_WORD_MASK:
+		if ((reg_data & data) == data)
+			rc = I2C_COMPARE_MATCH;
+		break;
+	case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+	case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+		if (!(reg_data & data))
+			rc = I2C_COMPARE_MATCH;
+		break;
+	default:
+		pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+		break;
+	}
+
+	S_I2C_DBG("%s: Register and data match result %d\n", __func__,
+		rc);
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type, uint32_t delay_ms)
+{
+	int32_t rc = -EFAULT;
+	int32_t i = 0;
+
+	S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n",
+		__func__, addr, data, data_type);
+
+	if (delay_ms > MAX_POLL_DELAY_MS) {
+		pr_err("%s:%d invalid delay = %d max_delay = %d\n",
+			__func__, __LINE__, delay_ms, MAX_POLL_DELAY_MS);
+		return -EINVAL;
+	}
+	for (i = 0; i < delay_ms; i++) {
+		rc = msm_camera_cci_i2c_compare(client,
+			addr, data, data_type);
+		if (!rc)
+			return rc;
+		usleep_range(1000, 1010);
+	}
+
+	/* If rc is 1 then read is successful but poll is failure */
+	if (rc == 1)
+		pr_err("%s:%d poll failed rc=%d(non-fatal)\n",
+			__func__, __LINE__, rc);
+
+	if (rc < 0)
+		pr_err("%s:%d poll failed rc=%d\n", __func__, __LINE__, rc);
+
+	return rc;
+}
+
+static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t mask,
+	enum msm_camera_i2c_data_type data_type, uint16_t set_mask)
+{
+	int32_t rc = -EFAULT;
+	uint16_t reg_data;
+
+	rc = msm_camera_cci_i2c_read(client, addr, &reg_data, data_type);
+	if (rc < 0) {
+		S_I2C_DBG("%s read fail\n", __func__);
+		return rc;
+	}
+	S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n",
+			__func__, addr, reg_data, mask);
+
+	if (set_mask)
+		reg_data |= mask;
+	else
+		reg_data &= ~mask;
+	S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data);
+
+	rc = msm_camera_cci_i2c_write(client, addr, reg_data, data_type);
+	if (rc < 0)
+		S_I2C_DBG("%s write fail\n", __func__);
+
+	return rc;
+}
+
+static int32_t msm_camera_cci_i2c_set_write_mask_data(
+	struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data, int16_t mask,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc;
+	uint16_t reg_data;
+
+	CDBG("%s\n", __func__);
+	if (mask == -1)
+		return 0;
+	if (mask == 0) {
+		rc = msm_camera_cci_i2c_write(client, addr, data, data_type);
+	} else {
+		rc = msm_camera_cci_i2c_read(client, addr, &reg_data,
+			data_type);
+		if (rc < 0) {
+			CDBG("%s read fail\n", __func__);
+			return rc;
+		}
+		reg_data &= ~mask;
+		reg_data |= (data & mask);
+		rc = msm_camera_cci_i2c_write(client, addr, reg_data,
+			data_type);
+		if (rc < 0)
+			CDBG("%s write fail\n", __func__);
+	}
+	return rc;
+}
+
+int32_t msm_camera_cci_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int i;
+	int32_t rc = -EFAULT;
+
+	for (i = 0; i < size; i++) {
+		enum msm_camera_i2c_data_type dt;
+
+		if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
+			rc = msm_camera_cci_i2c_poll(client,
+				reg_conf_tbl->reg_addr,
+				reg_conf_tbl->reg_data,
+				reg_conf_tbl->dt, I2C_POLL_TIME_MS);
+		} else {
+			if (reg_conf_tbl->dt == 0)
+				dt = data_type;
+			else
+				dt = reg_conf_tbl->dt;
+			switch (dt) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+				rc = msm_camera_cci_i2c_write(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data, dt);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_MASK:
+				rc = msm_camera_cci_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+				rc = msm_camera_cci_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_WORD_MASK:
+				rc = msm_camera_cci_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+				rc = msm_camera_cci_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+				rc = msm_camera_cci_i2c_set_write_mask_data(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					reg_conf_tbl->mask,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			default:
+				pr_err("%s: Unsupport data type: %d\n",
+					__func__, dt);
+				break;
+			}
+		}
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
+int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client,
+	uint16_t cci_cmd)
+{
+	int32_t rc = 0;
+	struct msm_camera_cci_ctrl cci_ctrl;
+
+	CDBG("%s line %d\n", __func__, __LINE__);
+	cci_ctrl.cmd = cci_cmd;
+	cci_ctrl.cci_info = client->cci_client;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
+	}
+	return cci_ctrl.status;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
new file mode 100644
index 0000000..d044a50
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -0,0 +1,1740 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_i2c_mux.h"
+#include "msm_cci.h"
+
+#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend"
+#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default"
+/*#define CONFIG_MSM_CAMERA_DT_DEBUG*/
+
+#define VALIDATE_VOLTAGE(min, max, config_val) ((config_val) && \
+	(config_val >= min) && (config_val <= max))
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct msm_sensor_power_setting *power_setting,
+	uint16_t power_setting_size)
+{
+	uint16_t i = 0;
+	int      j = 0;
+
+	/* Validate input parameters */
+	if (!cam_vreg || !power_setting) {
+		pr_err("%s:%d failed: cam_vreg %pK power_setting %pK", __func__,
+			__LINE__,  cam_vreg, power_setting);
+		return -EINVAL;
+	}
+
+	/* Validate size of num_vreg */
+	if (num_vreg <= 0) {
+		pr_err("failed: num_vreg %d", num_vreg);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < power_setting_size; i++) {
+		if (power_setting[i].seq_type != SENSOR_VREG)
+			continue;
+
+		switch (power_setting[i].seq_val) {
+		case CAM_VDIG:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) {
+					CDBG("%s:%d i %d j %d cam_vdig\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+			break;
+
+		case CAM_VIO:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) {
+					CDBG("%s:%d i %d j %d cam_vio\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+			break;
+
+		case CAM_VANA:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) {
+					CDBG("%s:%d i %d j %d cam_vana\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+			break;
+
+		case CAM_VAF:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) {
+					CDBG("%s:%d i %d j %d cam_vaf\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+			break;
+
+		case CAM_V_CUSTOM1:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name,
+					"cam_v_custom1")) {
+					CDBG("%s:%d i %d j %d cam_vcustom1\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+
+		case CAM_V_CUSTOM2:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name,
+					"cam_v_custom2")) {
+					CDBG("%s:%d i %d j %d cam_vcustom2\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					if (VALIDATE_VOLTAGE(
+						cam_vreg[j].min_voltage,
+						cam_vreg[j].max_voltage,
+						power_setting[i].config_val)) {
+						cam_vreg[j].min_voltage =
+						cam_vreg[j].max_voltage =
+						power_setting[i].config_val;
+					}
+					break;
+				}
+			}
+			break;
+
+		default:
+			pr_err("%s:%d invalid seq_val %d\n", __func__,
+				__LINE__, power_setting[i].seq_val);
+			break;
+		}
+	}
+	return 0;
+}
+
+int msm_sensor_get_sub_module_index(struct device_node *of_node,
+				    struct  msm_sensor_info_t **s_info)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0, count = 0;
+	uint32_t *val_array = NULL;
+	struct device_node *src_node = NULL;
+	struct msm_sensor_info_t *sensor_info;
+
+	sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL);
+	if (!sensor_info)
+		return -ENOMEM;
+	for (i = 0; i < SUB_MODULE_MAX; i++) {
+		sensor_info->subdev_id[i] = -1;
+		/* Subdev expose additional interface for same sub module*/
+		sensor_info->subdev_intf[i] = -1;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,ois-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,ois cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_OIS] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index", &val);
+	if (rc != -EINVAL) {
+		CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
+	} else {
+		rc = 0;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,ir-led-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,ir led cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_IR_LED] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,ir-cut-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,ir cut cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_IR_CUT] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index", &val);
+	if (rc != -EINVAL) {
+		CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val;
+	} else {
+		rc = 0;
+	}
+
+	if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) {
+		count /= sizeof(uint32_t);
+		if (count > 2) {
+			pr_err("%s qcom,csiphy-sd-index count %d > 2\n",
+				__func__, count);
+			goto ERROR;
+		}
+		val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+		if (!val_array) {
+			rc = -ENOMEM;
+			goto ERROR;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index",
+			val_array, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			kfree(val_array);
+			goto ERROR;
+		}
+		for (i = 0; i < count; i++) {
+			sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] =
+								val_array[i];
+			CDBG("%s csiphy_core[%d] = %d\n",
+				__func__, i, val_array[i]);
+		}
+		kfree(val_array);
+	} else {
+		pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__,
+			__LINE__);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+
+	if (of_get_property(of_node, "qcom,csid-sd-index", &count)) {
+		count /= sizeof(uint32_t);
+		if (count > 2) {
+			pr_err("%s qcom,csid-sd-index count %d > 2\n",
+				__func__, count);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+		if (!val_array) {
+			rc = -ENOMEM;
+			goto ERROR;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index",
+			val_array, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			kfree(val_array);
+			goto ERROR;
+		}
+		for (i = 0; i < count; i++) {
+			sensor_info->subdev_id
+				[SUB_MODULE_CSID + i] = val_array[i];
+			CDBG("%s csid_core[%d] = %d\n",
+				__func__, i, val_array[i]);
+		}
+		kfree(val_array);
+	} else {
+		pr_err("%s:%d qcom,csid-sd-index not present\n", __func__,
+			__LINE__);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+
+	*s_info = sensor_info;
+	return rc;
+ERROR:
+	kfree(sensor_info);
+	return rc;
+}
+
+int msm_sensor_get_dt_actuator_data(struct device_node *of_node,
+				    struct msm_actuator_info **act_info)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct msm_actuator_info *actuator_info;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val);
+	CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc);
+	if (rc < 0)
+		return 0;
+
+	actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL);
+	if (!actuator_info) {
+		rc = -ENOMEM;
+		goto ERROR;
+	}
+
+	actuator_info->cam_name = val;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val);
+	CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc);
+	if (!rc)
+		actuator_info->vcm_pwd = val;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val);
+	CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc);
+	if (!rc)
+		actuator_info->vcm_enable = val;
+
+	*act_info = actuator_info;
+	return 0;
+ERROR:
+	kfree(actuator_info);
+	return rc;
+}
+
+int msm_sensor_get_dt_csi_data(struct device_node *of_node,
+	struct msm_camera_csi_lane_params **csi_lane_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct msm_camera_csi_lane_params *clp;
+
+	clp = kzalloc(sizeof(*clp), GFP_KERNEL);
+	if (!clp)
+		return -ENOMEM;
+	*csi_lane_params = clp;
+
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val);
+	CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+	clp->csi_lane_assign = val;
+
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val);
+	CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+	clp->csi_lane_mask = val;
+
+	return rc;
+ERROR:
+	kfree(clp);
+	return rc;
+}
+
+int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+	struct camera_vreg_t *cam_vreg, int num_vreg,
+	struct msm_camera_power_ctrl_t *power_info)
+{
+	int rc = 0, i, j;
+	int count = 0;
+	const char *seq_name = NULL;
+	uint32_t *array = NULL;
+	struct msm_sensor_power_setting *ps;
+
+	struct msm_sensor_power_setting *power_setting;
+	uint16_t *power_setting_size, size = 0;
+	bool need_reverse = 0;
+
+	if (!power_info)
+		return -EINVAL;
+
+	power_setting = power_info->power_setting;
+	power_setting_size = &power_info->power_setting_size;
+
+	count = of_property_count_strings(of_node, "qcom,cam-power-seq-type");
+	*power_setting_size = count;
+
+	CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count);
+
+	if (count <= 0)
+		return 0;
+
+	ps = kcalloc(count, sizeof(*ps), GFP_KERNEL);
+	if (!ps)
+		return -ENOMEM;
+	power_setting = ps;
+	power_info->power_setting = ps;
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,cam-power-seq-type", i,
+			&seq_name);
+		CDBG("%s seq_name[%d] = %s\n", __func__, i,
+			seq_name);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR1;
+		}
+		if (!strcmp(seq_name, "sensor_vreg")) {
+			ps[i].seq_type = SENSOR_VREG;
+			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
+				i, ps[i].seq_type);
+		} else if (!strcmp(seq_name, "sensor_gpio")) {
+			ps[i].seq_type = SENSOR_GPIO;
+			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
+				i, ps[i].seq_type);
+		} else if (!strcmp(seq_name, "sensor_clk")) {
+			ps[i].seq_type = SENSOR_CLK;
+			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
+				i, ps[i].seq_type);
+		} else if (!strcmp(seq_name, "sensor_i2c_mux")) {
+			ps[i].seq_type = SENSOR_I2C_MUX;
+			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
+				i, ps[i].seq_type);
+		} else {
+			CDBG("%s: unrecognized seq-type\n", __func__);
+			rc = -EILSEQ;
+			goto ERROR1;
+		}
+	}
+
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,cam-power-seq-val", i,
+			&seq_name);
+		CDBG("%s seq_name[%d] = %s\n", __func__, i,
+			seq_name);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR1;
+		}
+		switch (ps[i].seq_type) {
+		case SENSOR_VREG:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(seq_name, cam_vreg[j].reg_name))
+					break;
+			}
+			if (j < num_vreg)
+				ps[i].seq_val = j;
+			else
+				rc = -EILSEQ;
+			break;
+		case SENSOR_GPIO:
+			if (!strcmp(seq_name, "sensor_gpio_reset"))
+				ps[i].seq_val = SENSOR_GPIO_RESET;
+			else if (!strcmp(seq_name, "sensor_gpio_standby"))
+				ps[i].seq_val = SENSOR_GPIO_STANDBY;
+			else if (!strcmp(seq_name, "sensor_gpio_vdig"))
+				ps[i].seq_val = SENSOR_GPIO_VDIG;
+			else if (!strcmp(seq_name, "sensor_gpio_vana"))
+				ps[i].seq_val = SENSOR_GPIO_VANA;
+			else if (!strcmp(seq_name, "sensor_gpio_vaf"))
+				ps[i].seq_val = SENSOR_GPIO_VAF;
+			else if (!strcmp(seq_name, "sensor_gpio_vio"))
+				ps[i].seq_val = SENSOR_GPIO_VIO;
+			else if (!strcmp(seq_name, "sensor_gpio_custom1"))
+				ps[i].seq_val = SENSOR_GPIO_CUSTOM1;
+			else if (!strcmp(seq_name, "sensor_gpio_custom2"))
+				ps[i].seq_val = SENSOR_GPIO_CUSTOM2;
+			else if (!strcmp(seq_name, "sensor_gpio_custom3"))
+				ps[i].seq_val = SENSOR_GPIO_CUSTOM3;
+			else
+				rc = -EILSEQ;
+			break;
+		case SENSOR_CLK:
+			if (!strcmp(seq_name, "sensor_cam_mclk"))
+				ps[i].seq_val = SENSOR_CAM_MCLK;
+			else if (!strcmp(seq_name, "sensor_cam_clk"))
+				ps[i].seq_val = SENSOR_CAM_CLK;
+			else
+				rc = -EILSEQ;
+			break;
+		case SENSOR_I2C_MUX:
+			if (!strcmp(seq_name, "none"))
+				ps[i].seq_val = 0;
+			else
+				rc = -EILSEQ;
+			break;
+		default:
+			rc = -EILSEQ;
+			break;
+		}
+		if (rc < 0) {
+			CDBG("%s: unrecognized seq-val\n", __func__);
+			goto ERROR1;
+		}
+	}
+
+	array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+	if (!array) {
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val",
+		array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		if (ps[i].seq_type == SENSOR_GPIO) {
+			if (array[i] == 0)
+				ps[i].config_val = GPIO_OUT_LOW;
+			else if (array[i] == 1)
+				ps[i].config_val = GPIO_OUT_HIGH;
+		} else {
+			ps[i].config_val = array[i];
+		}
+		CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i,
+			ps[i].config_val);
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay",
+		array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		ps[i].delay = array[i];
+		CDBG("%s power_setting[%d].delay = %d\n", __func__,
+			i, ps[i].delay);
+	}
+	kfree(array);
+
+	size = *power_setting_size;
+
+	if (NULL != ps && 0 != size)
+		need_reverse = 1;
+
+	power_info->power_down_setting =
+		kzalloc(sizeof(*ps) * size, GFP_KERNEL);
+
+	if (!power_info->power_down_setting) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	memcpy(power_info->power_down_setting,
+		ps, sizeof(*ps) * size);
+
+	power_info->power_down_setting_size = size;
+
+	if (need_reverse) {
+		int c, end = size - 1;
+		struct msm_sensor_power_setting power_down_setting_t;
+
+		for (c = 0; c < size/2; c++) {
+			power_down_setting_t =
+				power_info->power_down_setting[c];
+			power_info->power_down_setting[c] =
+				power_info->power_down_setting[end];
+			power_info->power_down_setting[end] =
+				power_down_setting_t;
+			end--;
+		}
+	}
+	return rc;
+ERROR2:
+	kfree(array);
+ERROR1:
+	kfree(ps);
+	power_setting_size = NULL;
+	return rc;
+}
+
+int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
+{
+	int rc = 0, i = 0;
+	uint32_t count = 0;
+	uint32_t *val_array = NULL;
+
+	if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count))
+		return 0;
+
+	count /= sizeof(uint32_t);
+	if (!count) {
+		pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__);
+		return 0;
+	}
+
+	val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+	if (!val_array)
+		return -ENOMEM;
+
+	gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio),
+		GFP_KERNEL);
+	if (!gconf->cam_gpio_req_tbl) {
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+	gconf->cam_gpio_req_tbl_size = count;
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num",
+		val_array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio req tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
+		CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i,
+			gconf->cam_gpio_req_tbl[i].gpio);
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags",
+		val_array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		gconf->cam_gpio_req_tbl[i].flags = val_array[i];
+		CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i,
+			gconf->cam_gpio_req_tbl[i].flags);
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,gpio-req-tbl-label", i,
+			&gconf->cam_gpio_req_tbl[i].label);
+		CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i,
+			gconf->cam_gpio_req_tbl[i].label);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		}
+	}
+
+	kfree(val_array);
+	return rc;
+
+ERROR2:
+	kfree(gconf->cam_gpio_req_tbl);
+ERROR1:
+	kfree(val_array);
+	gconf->cam_gpio_req_tbl_size = 0;
+	return rc;
+}
+
+int msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
+{
+	int rc = 0, val = 0;
+
+	gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
+		GFP_KERNEL);
+	if (!gconf->gpio_num_info) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-ir-p", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-ir-p failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-ir-p invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+
+		gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_P] = 1;
+
+		CDBG("%s qcom,gpio-ir-p %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_P]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-ir-m", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-ir-m failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-ir-m invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+
+		gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M] =
+			gpio_array[val];
+
+		gconf->gpio_num_info->valid[IR_CUT_FILTER_GPIO_M] = 1;
+
+		CDBG("%s qcom,gpio-ir-m %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-vana failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vana invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_VANA] = 1;
+		CDBG("%s qcom,gpio-vana %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-vio", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-vio failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vio invalid %d\n",
+				__func__, __LINE__, val);
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_VIO] = 1;
+		CDBG("%s qcom,gpio-vio %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-vaf", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-vaf failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vaf invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_VAF] = 1;
+		CDBG("%s qcom,gpio-vaf %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vdig invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1;
+		CDBG("%s qcom,gpio-vdig %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-reset failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-reset invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1;
+		CDBG("%s qcom,gpio-reset %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-standby failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-standby invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1;
+		CDBG("%s qcom,gpio-standby %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_AF_PWDM] = 1;
+		CDBG("%s qcom,gpio-af-pwdm %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-flash-en invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1;
+		CDBG("%s qcom,gpio-flash-en %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-flash-now invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1;
+		CDBG("%s qcom,gpio-flash-now %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-reset", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%dread qcom,gpio-flash-reset failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-flash-reset invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_FL_RESET] = 1;
+		CDBG("%s qcom,gpio-flash-reset %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET]);
+	} else
+		rc = 0;
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-custom1", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-custom1 failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-custom1 invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM1] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM1] = 1;
+		CDBG("%s qcom,gpio-custom1 %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM1]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-custom2", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-custom2 failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-custom2 invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM2] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM2] = 1;
+		CDBG("%s qcom,gpio-custom2 %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM2]);
+	} else {
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-custom3", &val);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-custom3 failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-custom3 invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM3] = 1;
+		CDBG("%s qcom,gpio-custom3 %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3]);
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+
+ERROR:
+	kfree(gconf->gpio_num_info);
+	gconf->gpio_num_info = NULL;
+	return rc;
+}
+
+int msm_camera_get_dt_vreg_data(struct device_node *of_node,
+	struct camera_vreg_t **cam_vreg, int *num_vreg)
+{
+	int rc = 0, i = 0;
+	int32_t count = 0;
+	uint32_t *vreg_array = NULL;
+	struct camera_vreg_t *vreg = NULL;
+	bool custom_vreg_name =  false;
+
+	count = of_property_count_strings(of_node, "qcom,cam-vreg-name");
+	CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count);
+
+	if (!count || (count == -EINVAL)) {
+		pr_err("%s:%d number of entries is 0 or not present in dts\n",
+			__func__, __LINE__);
+		*num_vreg = 0;
+		return 0;
+	}
+
+	vreg = kcalloc(count, sizeof(*vreg), GFP_KERNEL);
+	if (!vreg)
+		return -ENOMEM;
+	*cam_vreg = vreg;
+	*num_vreg = count;
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node,
+			"qcom,cam-vreg-name", i,
+			&vreg[i].reg_name);
+		CDBG("%s reg_name[%d] = %s\n", __func__, i,
+			vreg[i].reg_name);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR1;
+		}
+	}
+
+	custom_vreg_name = of_property_read_bool(of_node,
+		"qcom,cam-custom-vreg-name");
+	if (custom_vreg_name) {
+		for (i = 0; i < count; i++) {
+			rc = of_property_read_string_index(of_node,
+				"qcom,cam-custom-vreg-name", i,
+				&vreg[i].custom_vreg_name);
+			CDBG("%s sub reg_name[%d] = %s\n", __func__, i,
+				vreg[i].custom_vreg_name);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR1;
+			}
+		}
+	}
+
+	vreg_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+	if (!vreg_array) {
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	for (i = 0; i < count; i++)
+		vreg[i].type = VREG_TYPE_DEFAULT;
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type",
+		vreg_array, count);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		} else {
+			for (i = 0; i < count; i++) {
+				vreg[i].type = vreg_array[i];
+				CDBG("%s cam_vreg[%d].type = %d\n",
+					__func__, i, vreg[i].type);
+			}
+		}
+	} else {
+		CDBG("%s:%d no qcom,cam-vreg-type entries in dts\n",
+			__func__, __LINE__);
+		rc = 0;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage",
+		vreg_array, count);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		} else {
+			for (i = 0; i < count; i++) {
+				vreg[i].min_voltage = vreg_array[i];
+				CDBG("%s cam_vreg[%d].min_voltage = %d\n",
+					__func__, i, vreg[i].min_voltage);
+			}
+		}
+	} else {
+		CDBG("%s:%d no qcom,cam-vreg-min-voltage entries in dts\n",
+			__func__, __LINE__);
+		rc = 0;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage",
+		vreg_array, count);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		} else {
+			for (i = 0; i < count; i++) {
+				vreg[i].max_voltage = vreg_array[i];
+				CDBG("%s cam_vreg[%d].max_voltage = %d\n",
+					__func__, i, vreg[i].max_voltage);
+			}
+		}
+	} else {
+		CDBG("%s:%d no qcom,cam-vreg-max-voltage entries in dts\n",
+			__func__, __LINE__);
+		rc = 0;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode",
+		vreg_array, count);
+	if (rc != -EINVAL) {
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR2;
+		} else {
+			for (i = 0; i < count; i++) {
+				vreg[i].op_mode = vreg_array[i];
+				CDBG("%s cam_vreg[%d].op_mode = %d\n",
+					__func__, i, vreg[i].op_mode);
+			}
+		}
+	} else {
+		CDBG("%s:%d no qcom,cam-vreg-op-mode entries in dts\n",
+			__func__, __LINE__);
+		rc = 0;
+	}
+
+	kfree(vreg_array);
+	return rc;
+ERROR2:
+	kfree(vreg_array);
+ERROR1:
+	kfree(vreg);
+	*num_vreg = 0;
+	return rc;
+}
+
+static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+	struct v4l2_subdev *i2c_mux_sd =
+		dev_get_drvdata(&i2c_conf->mux_dev->dev);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+		VIDIOC_MSM_I2C_MUX_INIT, NULL);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+		VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode);
+	return 0;
+}
+
+static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+	struct v4l2_subdev *i2c_mux_sd =
+		dev_get_drvdata(&i2c_conf->mux_dev->dev);
+	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+		VIDIOC_MSM_I2C_MUX_RELEASE, NULL);
+	return 0;
+}
+
+int msm_camera_pinctrl_init(
+	struct msm_pinctrl_info *sensor_pctrl, struct device *dev) {
+
+	sensor_pctrl->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) {
+		pr_err("%s:%d Getting pinctrl handle failed\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	sensor_pctrl->gpio_state_active =
+		pinctrl_lookup_state(sensor_pctrl->pinctrl,
+				CAM_SENSOR_PINCTRL_STATE_DEFAULT);
+	if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) {
+		pr_err("%s:%d Failed to get the active state pinctrl handle\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	sensor_pctrl->gpio_state_suspend
+		= pinctrl_lookup_state(sensor_pctrl->pinctrl,
+				CAM_SENSOR_PINCTRL_STATE_SLEEP);
+	if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) {
+		pr_err("%s:%d Failed to get the suspend state pinctrl handle\n",
+				__func__, __LINE__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_cam_sensor_handle_reg_gpio(int seq_val,
+	struct msm_camera_gpio_conf *gconf, int val) {
+
+	int gpio_offset = -1;
+
+	if (!gconf) {
+		pr_err("ERR:%s: Input Parameters are not proper\n", __func__);
+		return -EINVAL;
+	}
+	CDBG("%s: %d Seq val: %d, config: %d", __func__, __LINE__,
+		seq_val, val);
+
+	switch (seq_val) {
+	case CAM_VDIG:
+		gpio_offset = SENSOR_GPIO_VDIG;
+		break;
+
+	case CAM_VIO:
+		gpio_offset = SENSOR_GPIO_VIO;
+		break;
+
+	case CAM_VANA:
+		gpio_offset = SENSOR_GPIO_VANA;
+		break;
+
+	case CAM_VAF:
+		gpio_offset = SENSOR_GPIO_VAF;
+		break;
+
+	case CAM_V_CUSTOM1:
+		gpio_offset = SENSOR_GPIO_CUSTOM1;
+		break;
+
+	case CAM_V_CUSTOM2:
+		gpio_offset = SENSOR_GPIO_CUSTOM2;
+		break;
+
+	default:
+		pr_err("%s:%d Invalid VREG seq val %d\n", __func__,
+			__LINE__, seq_val);
+		return -EINVAL;
+	}
+
+	CDBG("%s: %d GPIO offset: %d, seq_val: %d\n", __func__, __LINE__,
+		gpio_offset, seq_val);
+
+	if ((gconf->gpio_num_info->valid[gpio_offset] == 1)) {
+		gpio_set_value_cansleep(
+			gconf->gpio_num_info->gpio_num
+			[gpio_offset], val);
+	}
+	return 0;
+}
+
+int32_t msm_sensor_driver_get_gpio_data(
+	struct msm_camera_gpio_conf **gpio_conf,
+	struct device_node *of_node)
+{
+	int32_t                      rc = 0, i = 0;
+	uint16_t                    *gpio_array = NULL;
+	int16_t                     gpio_array_size = 0;
+	struct msm_camera_gpio_conf *gconf = NULL;
+
+	/* Validate input parameters */
+	if (!of_node) {
+		pr_err("failed: invalid param of_node %pK", of_node);
+		return -EINVAL;
+	}
+
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("gpio count %d\n", gpio_array_size);
+	if (gpio_array_size <= 0)
+		return 0;
+
+	gconf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+		GFP_KERNEL);
+	if (!gconf)
+		return -ENOMEM;
+
+	*gpio_conf = gconf;
+
+	gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL);
+	if (!gpio_array)
+		goto FREE_GPIO_CONF;
+
+	for (i = 0; i < gpio_array_size; i++) {
+		gpio_array[i] = of_get_gpio(of_node, i);
+		CDBG("gpio_array[%d] = %d", i, gpio_array[i]);
+	}
+	rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array,
+		gpio_array_size);
+	if (rc < 0) {
+		pr_err("failed in msm_camera_get_dt_gpio_req_tbl\n");
+		goto FREE_GPIO_CONF;
+	}
+
+	rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array,
+		gpio_array_size);
+	if (rc < 0) {
+		pr_err("failed in msm_camera_init_gpio_pin_tbl\n");
+		goto FREE_GPIO_REQ_TBL;
+	}
+	kfree(gpio_array);
+	return rc;
+
+FREE_GPIO_REQ_TBL:
+	kfree(gconf->cam_gpio_req_tbl);
+FREE_GPIO_CONF:
+	kfree(gconf);
+	kfree(gpio_array);
+	*gpio_conf = NULL;
+	return rc;
+}
+
+int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
+	enum msm_camera_device_type_t device_type,
+	struct msm_camera_i2c_client *sensor_i2c_client)
+{
+	int rc = 0, index = 0, no_gpio = 0, ret = 0;
+	struct msm_sensor_power_setting *power_setting = NULL;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	if (!ctrl || !sensor_i2c_client) {
+		pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl,
+			sensor_i2c_client);
+		return -EINVAL;
+	}
+	if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL)
+		pr_err("%s:%d mux install\n", __func__, __LINE__);
+
+	ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev);
+	if (ret < 0) {
+		pr_err("%s:%d Initialization of pinctrl failed\n",
+				__func__, __LINE__);
+		ctrl->cam_pinctrl_status = 0;
+	} else {
+		ctrl->cam_pinctrl_status = 1;
+	}
+	rc = msm_camera_request_gpio_table(
+		ctrl->gpio_conf->cam_gpio_req_tbl,
+		ctrl->gpio_conf->cam_gpio_req_tbl_size, 1);
+	if (rc < 0)
+		no_gpio = rc;
+	if (ctrl->cam_pinctrl_status) {
+		ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl,
+			ctrl->pinctrl_info.gpio_state_active);
+		if (ret)
+			pr_err("%s:%d cannot set pin to active state",
+				__func__, __LINE__);
+	}
+	for (index = 0; index < ctrl->power_setting_size; index++) {
+		CDBG("%s index %d\n", __func__, index);
+		power_setting = &ctrl->power_setting[index];
+		CDBG("%s type %d\n", __func__, power_setting->seq_type);
+		switch (power_setting->seq_type) {
+		case SENSOR_CLK:
+			if (power_setting->seq_val >= ctrl->clk_info_size) {
+				pr_err_ratelimited("%s clk index %d >= max %zu\n",
+				  __func__, power_setting->seq_val,
+				ctrl->clk_info_size);
+				goto power_up_failed;
+			}
+			if (power_setting->config_val)
+				ctrl->clk_info[power_setting->seq_val].
+					clk_rate = power_setting->config_val;
+			rc = msm_camera_clk_enable(ctrl->dev,
+				ctrl->clk_info, ctrl->clk_ptr,
+				ctrl->clk_info_size, true);
+			if (rc < 0) {
+				pr_err_ratelimited("%s: clk enable failed\n",
+				 __func__);
+				goto power_up_failed;
+			}
+			break;
+		case SENSOR_GPIO:
+			if (no_gpio) {
+				pr_err("%s: request gpio failed\n", __func__);
+				return no_gpio;
+			}
+			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
+				!ctrl->gpio_conf->gpio_num_info) {
+				pr_err("%s gpio index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				goto power_up_failed;
+			}
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[power_setting->seq_val])
+				continue;
+			CDBG("%s:%d gpio set val %d\n", __func__, __LINE__,
+				ctrl->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val]);
+			gpio_set_value_cansleep(
+				ctrl->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val],
+				(int) power_setting->config_val);
+			break;
+		case SENSOR_VREG:
+			if (power_setting->seq_val >= CAM_VREG_MAX) {
+				pr_err("%s vreg index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					SENSOR_GPIO_MAX);
+				goto power_up_failed;
+			}
+			if (power_setting->seq_val < ctrl->num_vreg)
+				msm_camera_config_single_vreg(ctrl->dev,
+					&ctrl->cam_vreg
+					[power_setting->seq_val],
+					(struct regulator **)
+					&power_setting->data[0],
+					1);
+			else
+				pr_err("%s: %d usr_idx:%d dts_idx:%d\n",
+					__func__, __LINE__,
+					power_setting->seq_val, ctrl->num_vreg);
+
+			rc = msm_cam_sensor_handle_reg_gpio(
+				power_setting->seq_val,
+				ctrl->gpio_conf, 1);
+			if (rc < 0) {
+				pr_err("ERR:%s Error in handling VREG GPIO\n",
+					__func__);
+				goto power_up_failed;
+			}
+			break;
+		case SENSOR_I2C_MUX:
+			if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux)
+				msm_camera_enable_i2c_mux(ctrl->i2c_conf);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				power_setting->seq_type);
+			break;
+		}
+		if (power_setting->delay > 20) {
+			msleep(power_setting->delay);
+		} else if (power_setting->delay) {
+			usleep_range(power_setting->delay * 1000,
+				(power_setting->delay * 1000) + 1000);
+		}
+	}
+
+	if (device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		rc = sensor_i2c_client->i2c_func_tbl->i2c_util(
+			sensor_i2c_client, MSM_CCI_INIT);
+		if (rc < 0) {
+			pr_err("%s cci_init failed\n", __func__);
+			goto power_up_failed;
+		}
+	}
+	CDBG("%s exit\n", __func__);
+	return 0;
+power_up_failed:
+	pr_err_ratelimited("%s:%d failed\n", __func__, __LINE__);
+	for (index--; index >= 0; index--) {
+		CDBG("%s index %d\n", __func__, index);
+		power_setting = &ctrl->power_setting[index];
+		CDBG("%s type %d\n", __func__, power_setting->seq_type);
+		switch (power_setting->seq_type) {
+		case SENSOR_GPIO:
+			if (!ctrl->gpio_conf->gpio_num_info)
+				continue;
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[power_setting->seq_val])
+				continue;
+			gpio_set_value_cansleep(
+				ctrl->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			break;
+		case SENSOR_VREG:
+			if (power_setting->seq_val < ctrl->num_vreg)
+				msm_camera_config_single_vreg(ctrl->dev,
+					&ctrl->cam_vreg
+					[power_setting->seq_val],
+					(struct regulator **)
+					&power_setting->data[0],
+					0);
+			else
+				pr_err("%s:%d:seq_val: %d > num_vreg: %d\n",
+					__func__, __LINE__,
+					power_setting->seq_val, ctrl->num_vreg);
+
+			msm_cam_sensor_handle_reg_gpio(power_setting->seq_val,
+				ctrl->gpio_conf, GPIOF_OUT_INIT_LOW);
+			break;
+		case SENSOR_I2C_MUX:
+			if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux)
+				msm_camera_disable_i2c_mux(ctrl->i2c_conf);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				power_setting->seq_type);
+			break;
+		}
+		if (power_setting->delay > 20) {
+			msleep(power_setting->delay);
+		} else if (power_setting->delay) {
+			usleep_range(power_setting->delay * 1000,
+				(power_setting->delay * 1000) + 1000);
+		}
+	}
+	if (ctrl->cam_pinctrl_status) {
+		ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl,
+				ctrl->pinctrl_info.gpio_state_suspend);
+		if (ret)
+			pr_err("%s:%d cannot set pin to suspend state\n",
+				__func__, __LINE__);
+		devm_pinctrl_put(ctrl->pinctrl_info.pinctrl);
+	}
+	ctrl->cam_pinctrl_status = 0;
+	msm_camera_request_gpio_table(
+		ctrl->gpio_conf->cam_gpio_req_tbl,
+		ctrl->gpio_conf->cam_gpio_req_tbl_size, 0);
+	return rc;
+}
+
+static struct msm_sensor_power_setting*
+msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl,
+				enum msm_sensor_power_seq_type_t seq_type,
+				uint16_t seq_val)
+{
+	struct msm_sensor_power_setting *power_setting, *ps = NULL;
+	int idx;
+
+	for (idx = 0; idx < ctrl->power_setting_size; idx++) {
+		power_setting = &ctrl->power_setting[idx];
+		if (power_setting->seq_type == seq_type &&
+			power_setting->seq_val ==  seq_val) {
+			ps = power_setting;
+			return ps;
+		}
+
+	}
+	return ps;
+}
+
+int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
+	enum msm_camera_device_type_t device_type,
+	struct msm_camera_i2c_client *sensor_i2c_client)
+{
+	int index = 0, ret = 0;
+	struct msm_sensor_power_setting *pd = NULL;
+	struct msm_sensor_power_setting *ps;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	if (!ctrl || !sensor_i2c_client) {
+		pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl,
+			sensor_i2c_client);
+		return -EINVAL;
+	}
+	if (device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		sensor_i2c_client->i2c_func_tbl->i2c_util(
+			sensor_i2c_client, MSM_CCI_RELEASE);
+
+	for (index = 0; index < ctrl->power_down_setting_size; index++) {
+		CDBG("%s index %d\n", __func__, index);
+		pd = &ctrl->power_down_setting[index];
+		ps = NULL;
+		CDBG("%s type %d\n", __func__, pd->seq_type);
+		switch (pd->seq_type) {
+		case SENSOR_CLK:
+			msm_camera_clk_enable(ctrl->dev,
+				ctrl->clk_info, ctrl->clk_ptr,
+				ctrl->clk_info_size, false);
+				break;
+		case SENSOR_GPIO:
+			if (pd->seq_val >= SENSOR_GPIO_MAX ||
+				!ctrl->gpio_conf->gpio_num_info) {
+				pr_err("%s gpio index %d >= max %d\n", __func__,
+					pd->seq_val,
+					SENSOR_GPIO_MAX);
+				continue;
+			}
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[pd->seq_val])
+				continue;
+			gpio_set_value_cansleep(
+				ctrl->gpio_conf->gpio_num_info->gpio_num
+				[pd->seq_val],
+				(int) pd->config_val);
+			break;
+		case SENSOR_VREG:
+			if (pd->seq_val == INVALID_VREG)
+				break;
+			if (pd->seq_val >= CAM_VREG_MAX) {
+				pr_err("%s vreg index %d >= max %d\n", __func__,
+					pd->seq_val,
+					SENSOR_GPIO_MAX);
+				continue;
+			}
+
+			ps = msm_camera_get_power_settings(ctrl,
+						pd->seq_type,
+						pd->seq_val);
+			if (ps) {
+				if (pd->seq_val < ctrl->num_vreg)
+					msm_camera_config_single_vreg(ctrl->dev,
+						&ctrl->cam_vreg
+						[pd->seq_val],
+						(struct regulator **)
+						&ps->data[0],
+						0);
+				else
+					pr_err("%s:%d:seq_val:%d > num_vreg: %d\n",
+						__func__, __LINE__, pd->seq_val,
+						ctrl->num_vreg);
+			} else
+				pr_err("%s error in power up/down seq data\n",
+								__func__);
+			ret = msm_cam_sensor_handle_reg_gpio(pd->seq_val,
+				ctrl->gpio_conf, GPIOF_OUT_INIT_LOW);
+			if (ret < 0)
+				pr_err("ERR:%s Error while disabling VREG GPIO\n",
+					__func__);
+			break;
+		case SENSOR_I2C_MUX:
+			if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux)
+				msm_camera_disable_i2c_mux(ctrl->i2c_conf);
+			break;
+		default:
+			pr_err("%s error power seq type %d\n", __func__,
+				pd->seq_type);
+			break;
+		}
+		if (pd->delay > 20) {
+			msleep(pd->delay);
+		} else if (pd->delay) {
+			usleep_range(pd->delay * 1000,
+				(pd->delay * 1000) + 1000);
+		}
+	}
+	if (ctrl->cam_pinctrl_status) {
+		ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl,
+				ctrl->pinctrl_info.gpio_state_suspend);
+		if (ret)
+			pr_err("%s:%d cannot set pin to suspend state",
+				__func__, __LINE__);
+		devm_pinctrl_put(ctrl->pinctrl_info.pinctrl);
+	}
+	ctrl->cam_pinctrl_status = 0;
+	msm_camera_request_gpio_table(
+		ctrl->gpio_conf->cam_gpio_req_tbl,
+		ctrl->gpio_conf->cam_gpio_req_tbl_size, 0);
+	CDBG("%s exit\n", __func__);
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
new file mode 100644
index 0000000..545ebdc
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CAMERA_DT_UTIL_H__
+#define MSM_CAMERA_DT_UTIL_H__
+
+#include <soc/qcom/camera2.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include "msm_camera_i2c.h"
+#include "cam_soc_api.h"
+
+
+#define INVALID_VREG 100
+
+int msm_sensor_get_sub_module_index(struct device_node *of_node,
+	struct  msm_sensor_info_t **s_info);
+
+int msm_sensor_get_dt_actuator_data(struct device_node *of_node,
+	struct msm_actuator_info **act_info);
+
+int msm_sensor_get_dt_csi_data(struct device_node *of_node,
+	struct msm_camera_csi_lane_params **csi_lane_params);
+
+int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+	struct camera_vreg_t *cam_vreg, int num_vreg,
+	struct msm_camera_power_ctrl_t *power_info);
+
+int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int msm_camera_get_dt_vreg_data(struct device_node *of_node,
+	struct camera_vreg_t **cam_vreg, int *num_vreg);
+
+int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
+	enum msm_camera_device_type_t device_type,
+	struct msm_camera_i2c_client *sensor_i2c_client);
+
+int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
+	enum msm_camera_device_type_t device_type,
+	struct msm_camera_i2c_client *sensor_i2c_client);
+
+int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct msm_sensor_power_setting *power_setting,
+	uint16_t power_setting_size);
+
+int msm_camera_pinctrl_init
+	(struct msm_pinctrl_info *sensor_pctrl, struct device *dev);
+
+int32_t msm_sensor_driver_get_gpio_data(
+	struct msm_camera_gpio_conf **gpio_conf,
+	struct device_node *of_node);
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
new file mode 100644
index 0000000..c8e8a42
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -0,0 +1,211 @@
+/* Copyright (c) 2011-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CAMERA_CCI_I2C_H
+#define MSM_CAMERA_CCI_I2C_H
+
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_cam_sensor.h>
+
+#define I2C_POLL_TIME_MS 5
+#define MAX_POLL_DELAY_MS 100
+
+#define I2C_COMPARE_MATCH 0
+#define I2C_COMPARE_MISMATCH 1
+
+struct msm_camera_i2c_client {
+	struct msm_camera_i2c_fn_t *i2c_func_tbl;
+	struct i2c_client *client;
+	struct msm_camera_cci_client *cci_client;
+	struct msm_camera_spi_client *spi_client;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+};
+
+struct msm_camera_i2c_fn_t {
+	int (*i2c_read)(struct msm_camera_i2c_client *, uint32_t, uint16_t *,
+		enum msm_camera_i2c_data_type);
+	int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t,
+		uint8_t *, uint32_t);
+	int (*i2c_write)(struct msm_camera_i2c_client *, uint32_t, uint16_t,
+		enum msm_camera_i2c_data_type);
+	int (*i2c_write_seq)(struct msm_camera_i2c_client *, uint32_t,
+		uint8_t *, uint32_t);
+	int32_t (*i2c_write_table)(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_reg_setting *);
+	int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_seq_reg_setting *);
+	int32_t (*i2c_write_table_w_microdelay)
+		(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_reg_setting *);
+	int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t);
+	int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client,
+		struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+		enum msm_camera_i2c_data_type data_type);
+	int32_t (*i2c_poll)(struct msm_camera_i2c_client *client,
+		uint32_t addr, uint16_t data,
+		enum msm_camera_i2c_data_type data_type, uint32_t delay_ms);
+	int32_t (*i2c_read_burst)(struct msm_camera_i2c_client *client,
+		uint32_t read_byte, uint8_t *buffer, uint32_t addr,
+		enum msm_camera_i2c_data_type data_type);
+	int32_t (*i2c_write_burst)(struct msm_camera_i2c_client *client,
+		struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size,
+		uint32_t buf_len, uint32_t addr,
+		enum msm_camera_i2c_data_type data_type);
+	int32_t (*i2c_write_table_async)(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_reg_setting *);
+	int32_t (*i2c_write_table_sync)(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_reg_setting *);
+	int32_t (*i2c_write_table_sync_block)(struct msm_camera_i2c_client *,
+		struct msm_camera_i2c_reg_setting *);
+};
+
+int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_cci_i2c_write_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_table_async(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_table_sync(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_table_sync_block(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_seq_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_cci_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client,
+	uint16_t cci_cmd);
+
+int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type, uint32_t delay_ms);
+
+int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting);
+
+int32_t msm_camera_qup_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_qup_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type, uint32_t delay_ms);
+
+int32_t msm_camera_tz_i2c_register_sensor(void *s_ctrl_p);
+
+int32_t msm_camera_tz_i2c_power_up(struct msm_camera_i2c_client *client);
+
+int32_t msm_camera_tz_i2c_power_down(struct msm_camera_i2c_client *client);
+
+int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_tz_i2c_write_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_table_async(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_table_sync(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_table_sync_block(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_seq_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_tz_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client,
+	uint16_t cci_cmd);
+
+int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type);
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.c
new file mode 100644
index 0000000..af794bb
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2011-2014, 2016, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include "msm_camera_i2c_mux.h"
+
+/* TODO move this somewhere else */
+#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
+static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode)
+{
+	uint32_t val;
+
+	val = msm_camera_io_r(mux_device->ctl_base);
+	if (*mode == MODE_DUAL) {
+		msm_camera_io_w(val | 0x3, mux_device->ctl_base);
+	} else if (*mode == MODE_L) {
+		msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base);
+		val = msm_camera_io_r(mux_device->ctl_base);
+		CDBG("the camio mode config left value is %d\n", val);
+	} else {
+		msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base);
+		val = msm_camera_io_r(mux_device->ctl_base);
+		CDBG("the camio mode config right value is %d\n", val);
+	}
+	return 0;
+}
+
+static int msm_i2c_mux_init(struct i2c_mux_device *mux_device)
+{
+	int rc = 0, val = 0;
+
+	if (mux_device->use_count == 0) {
+		val = msm_camera_io_r(mux_device->rw_base);
+		msm_camera_io_w((val | 0x200), mux_device->rw_base);
+	}
+	mux_device->use_count++;
+	return 0;
+};
+
+static int msm_i2c_mux_release(struct i2c_mux_device *mux_device)
+{
+	int val = 0;
+
+	mux_device->use_count--;
+	if (mux_device->use_count == 0) {
+		val = msm_camera_io_r(mux_device->rw_base);
+		msm_camera_io_w((val & ~0x200), mux_device->rw_base);
+	}
+	return 0;
+}
+
+static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct i2c_mux_device *mux_device;
+	int rc = 0;
+
+	mux_device = v4l2_get_subdevdata(sd);
+	if (mux_device == NULL) {
+		rc = -ENOMEM;
+		return rc;
+	}
+	mutex_lock(&mux_device->mutex);
+	switch (cmd) {
+	case VIDIOC_MSM_I2C_MUX_CFG:
+		rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg);
+		break;
+	case VIDIOC_MSM_I2C_MUX_INIT:
+		rc = msm_i2c_mux_init(mux_device);
+		break;
+	case VIDIOC_MSM_I2C_MUX_RELEASE:
+		rc = msm_i2c_mux_release(mux_device);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+	mutex_unlock(&mux_device->mutex);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = {
+	.ioctl = &msm_i2c_mux_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = {
+	.core = &msm_i2c_mux_subdev_core_ops,
+};
+
+static int i2c_mux_probe(struct platform_device *pdev)
+{
+	struct i2c_mux_device *mux_device;
+	int rc = 0;
+
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL);
+	if (!mux_device) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops);
+	v4l2_set_subdevdata(&mux_device->subdev, mux_device);
+	platform_set_drvdata(pdev, &mux_device->subdev);
+	mutex_init(&mux_device->mutex);
+
+	mux_device->ctl_base = msm_camera_get_reg_base(pdev,
+		"i2c_mux_ctl", true);
+	if (!mux_device->ctl_base) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto ctl_base_failed;
+	}
+	mux_device->rw_base = msm_camera_get_reg_base(pdev, "i2c_mux_rw", true);
+	if (!mux_device->rw_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto rw_base_failed;
+	}
+	mux_device->pdev = pdev;
+	return 0;
+
+rw_base_failed:
+	msm_camera_put_reg_base(pdev, mux_device->ctl_base,
+		"i2c_mux_ctl", true);
+ctl_base_failed:
+	mutex_destroy(&mux_device->mutex);
+	kfree(mux_device);
+	return 0;
+}
+
+static int i2c_mux_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sub_dev = platform_get_drvdata(pdev);
+	struct i2c_mux_device *mux_device;
+
+	if (!sub_dev) {
+		pr_err("%s: sub device is NULL\n", __func__);
+		return 0;
+	}
+
+	mux_device = (struct mux_device *)v4l2_get_subdevdata(sub_dev);
+	if (!mux_device) {
+		pr_err("%s: sub device is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_camera_put_reg_base(pdev, mux_device->rw_base, "i2c_mux_ctl", true);
+	msm_camera_put_reg_base(pdev, mux_device->ctl_base, "i2c_mux_rw", true);
+}
+
+static struct platform_driver i2c_mux_driver = {
+	.probe = i2c_mux_probe,
+	.remove = i2c_mux_remove,
+	.driver = {
+		.name = MSM_I2C_MUX_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_camera_i2c_mux_init_module(void)
+{
+	return platform_driver_register(&i2c_mux_driver);
+}
+
+static void __exit msm_camera_i2c_mux_exit_module(void)
+{
+	platform_driver_unregister(&i2c_mux_driver);
+}
+
+module_init(msm_camera_i2c_mux_init_module);
+module_exit(msm_camera_i2c_mux_exit_module);
+MODULE_DESCRIPTION("MSM Camera I2C mux driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.h
new file mode 100644
index 0000000..6c1a4212a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c_mux.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2011-2014, 2016, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_I2C_MUX_H
+#define MSM_I2C_MUX_H
+
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct i2c_mux_device {
+	struct platform_device *pdev;
+	struct v4l2_subdev subdev;
+	void __iomem *ctl_base;
+	void __iomem *rw_base;
+	struct mutex mutex;
+	unsigned int use_count;
+};
+
+struct i2c_mux_cfg_params {
+	struct v4l2_subdev *subdev;
+	void *parms;
+};
+
+#define VIDIOC_MSM_I2C_MUX_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params)
+
+#define VIDIOC_MSM_I2C_MUX_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_I2C_MUX_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*)
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
new file mode 100644
index 0000000..e16629c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -0,0 +1,616 @@
+/* Copyright (c) 2011, 2013-2016, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#define S_I2C_DBG(fmt, args...) do { } while (0)
+#endif
+
+static int32_t msm_camera_qup_i2c_rxdata(
+	struct msm_camera_i2c_client *dev_client, unsigned char *rxdata,
+	int data_length)
+{
+	int32_t rc = 0;
+	uint16_t saddr = dev_client->client->addr >> 1;
+	struct i2c_msg msgs[] = {
+		{
+			.addr  = saddr,
+			.flags = 0,
+			.len   = dev_client->addr_type,
+			.buf   = rxdata,
+		},
+		{
+			.addr  = saddr,
+			.flags = I2C_M_RD,
+			.len   = data_length,
+			.buf   = rxdata,
+		},
+	};
+	rc = i2c_transfer(dev_client->client->adapter, msgs, 2);
+	if (rc < 0)
+		S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr);
+	return rc;
+}
+
+static int32_t msm_camera_qup_i2c_txdata(
+	struct msm_camera_i2c_client *dev_client, unsigned char *txdata,
+	int length)
+{
+	int32_t rc = 0;
+	uint16_t saddr = dev_client->client->addr >> 1;
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		 },
+	};
+	rc = i2c_transfer(dev_client->client->adapter, msg, 1);
+	if (rc < 0)
+		S_I2C_DBG("msm_camera_qup_i2c_txdata failed 0x%x\n", saddr);
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	unsigned char *buf = NULL;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	if (client->addr_type > UINT_MAX - data_type) {
+		S_I2C_DBG("%s: integer overflow prevented\n", __func__);
+		return rc;
+	}
+
+	buf = kzalloc((uint32_t)client->addr_type + (uint32_t)data_type,
+					GFP_KERNEL);
+	if (!buf) {
+		S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
+		buf[0] = addr;
+	} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
+		buf[0] = addr >> BITS_PER_BYTE;
+		buf[1] = addr;
+	}
+	rc = msm_camera_qup_i2c_rxdata(client, buf, data_type);
+	if (rc < 0) {
+		S_I2C_DBG("%s fail\n", __func__);
+		kfree(buf);
+		buf = NULL;
+		return rc;
+	}
+
+	if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
+		*data = buf[0];
+	else
+		*data = buf[0] << 8 | buf[1];
+
+	S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
+	kfree(buf);
+	buf = NULL;
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	unsigned char *buf = NULL;
+	int i;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| num_byte == 0)
+		return rc;
+
+	if (num_byte > I2C_REG_DATA_MAX) {
+		S_I2C_DBG("%s: Error num_byte:0x%x exceeds max:0x%x\n",
+				__func__, num_byte, I2C_REG_DATA_MAX);
+		return rc;
+	}
+	if (client->addr_type > UINT_MAX - num_byte) {
+		S_I2C_DBG("%s: integer overflow prevented\n", __func__);
+		return rc;
+	}
+
+	buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL);
+	if (!buf) {
+		S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
+		buf[0] = addr;
+	} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
+		buf[0] = addr >> BITS_PER_BYTE;
+		buf[1] = addr;
+	}
+	rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte);
+	if (rc < 0) {
+		S_I2C_DBG("%s fail\n", __func__);
+		kfree(buf);
+		buf = NULL;
+		return rc;
+	}
+
+	S_I2C_DBG("%s addr = 0x%x", __func__, addr);
+	for (i = 0; i < num_byte; i++) {
+		data[i] = buf[i];
+		S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]);
+		S_I2C_DBG("Data: 0x%x\n", data[i]);
+	}
+	kfree(buf);
+	buf = NULL;
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	unsigned char *buf = NULL;
+	uint8_t len = 0;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	buf = kzalloc((uint32_t)client->addr_type + (uint32_t)data_type,
+					GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	S_I2C_DBG("%s reg addr = 0x%x data type: %d\n",
+			  __func__, addr, data_type);
+	if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
+		buf[0] = addr;
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len, buf[len]);
+		len = 1;
+	} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
+		buf[0] = addr >> BITS_PER_BYTE;
+		buf[1] = addr;
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len, buf[len]);
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len+1, buf[len+1]);
+		len = 2;
+	}
+	S_I2C_DBG("Data: 0x%x\n", data);
+	if (data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+		buf[len] = data;
+		S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]);
+		len += 1;
+	} else if (data_type == MSM_CAMERA_I2C_WORD_DATA) {
+		buf[len] = data >> BITS_PER_BYTE;
+		buf[len+1] = data;
+		S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]);
+		S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]);
+		len += 2;
+	}
+	rc = msm_camera_qup_i2c_txdata(client, buf, len);
+	if (rc < 0)
+		S_I2C_DBG("%s fail\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	unsigned char *buf;
+	uint8_t len = 0, i = 0;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| num_byte == 0)
+		return rc;
+
+	buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
+			  __func__, addr, num_byte);
+	if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
+		buf[0] = addr;
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len, buf[len]);
+		len = 1;
+	} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
+		buf[0] = addr >> BITS_PER_BYTE;
+		buf[1] = addr;
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len, buf[len]);
+		S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
+			len+1, buf[len+1]);
+		len = 2;
+	}
+	if (num_byte > I2C_SEQ_REG_DATA_MAX) {
+		pr_err("%s: num_byte=%d clamped to max supported %d\n",
+			__func__, num_byte, I2C_SEQ_REG_DATA_MAX);
+		num_byte = I2C_SEQ_REG_DATA_MAX;
+	}
+	for (i = 0; i < num_byte; i++) {
+		buf[i+len] = data[i];
+		S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]);
+		S_I2C_DBG("Data: 0x%x\n", data[i]);
+	}
+	rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte);
+	if (rc < 0)
+		S_I2C_DBG("%s fail\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting;
+	uint16_t client_addr_type;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	reg_setting = write_setting->reg_setting;
+	client_addr_type = client->addr_type;
+	client->addr_type = write_setting->addr_type;
+
+	for (i = 0; i < write_setting->size; i++) {
+		CDBG("%s addr 0x%x data 0x%x\n", __func__,
+			reg_setting->reg_addr, reg_setting->reg_data);
+
+		rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
+		if (rc < 0)
+			break;
+		reg_setting++;
+	}
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+
+	client->addr_type = client_addr_type;
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_seq_reg_array *reg_setting;
+	uint16_t client_addr_type;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) {
+		pr_err("%s Invalid addr type %d\n", __func__,
+			write_setting->addr_type);
+		return rc;
+	}
+
+	reg_setting = write_setting->reg_setting;
+	client_addr_type = client->addr_type;
+	client->addr_type = write_setting->addr_type;
+
+	if (reg_setting->reg_data_size > I2C_SEQ_REG_DATA_MAX) {
+		pr_err("%s: number of bytes %u exceeding the max supported %d\n",
+		__func__, reg_setting->reg_data_size, I2C_SEQ_REG_DATA_MAX);
+		return rc;
+	}
+
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr,
+			reg_setting->reg_data, reg_setting->reg_data_size);
+		if (rc < 0)
+			break;
+		reg_setting++;
+	}
+	if (write_setting->delay > 20)
+		msleep(write_setting->delay);
+	else if (write_setting->delay)
+		usleep_range(write_setting->delay * 1000, (write_setting->delay
+			* 1000) + 1000);
+
+	client->addr_type = client_addr_type;
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	reg_setting = write_setting->reg_setting;
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
+		if (rc < 0)
+			break;
+		if (reg_setting->delay)
+			usleep_range(reg_setting->delay,
+				reg_setting->delay + 1000);
+		reg_setting++;
+	}
+	return rc;
+}
+
+static int32_t msm_camera_qup_i2c_compare(
+	struct msm_camera_i2c_client *client, uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc;
+	uint16_t reg_data = 0;
+	int data_len = 0;
+
+	switch (data_type) {
+	case MSM_CAMERA_I2C_BYTE_DATA:
+	case MSM_CAMERA_I2C_WORD_DATA:
+		data_len = data_type;
+		break;
+	case MSM_CAMERA_I2C_SET_BYTE_MASK:
+	case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+		data_len = MSM_CAMERA_I2C_BYTE_DATA;
+		break;
+	case MSM_CAMERA_I2C_SET_WORD_MASK:
+	case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+		data_len = MSM_CAMERA_I2C_WORD_DATA;
+		break;
+	default:
+		pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+		break;
+	}
+
+	rc = msm_camera_qup_i2c_read(client, addr, &reg_data, data_len);
+	if (rc < 0)
+		return rc;
+
+	rc = I2C_COMPARE_MISMATCH;
+	switch (data_type) {
+	case MSM_CAMERA_I2C_BYTE_DATA:
+	case MSM_CAMERA_I2C_WORD_DATA:
+		if (data == reg_data)
+			rc = I2C_COMPARE_MATCH;
+		break;
+	case MSM_CAMERA_I2C_SET_BYTE_MASK:
+	case MSM_CAMERA_I2C_SET_WORD_MASK:
+		if ((reg_data & data) == data)
+			rc = I2C_COMPARE_MATCH;
+		break;
+	case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+	case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+		if (!(reg_data & data))
+			rc = I2C_COMPARE_MATCH;
+		break;
+	default:
+		pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
+		break;
+	}
+
+	S_I2C_DBG("%s: Register and data match result %d\n", __func__,
+		rc);
+	return rc;
+}
+
+int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type, uint32_t delay_ms)
+{
+	int32_t rc = 0;
+	int i;
+
+	S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n",
+		__func__, addr, data, data_type);
+
+	if (delay_ms > MAX_POLL_DELAY_MS) {
+		pr_err("%s:%d invalid delay = %d max_delay = %d\n",
+			__func__, __LINE__, delay_ms, MAX_POLL_DELAY_MS);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < delay_ms; i++) {
+		rc = msm_camera_qup_i2c_compare(client,
+			addr, data, data_type);
+		if (rc < 0) {
+			pr_err("%s:%d qup_i2c_compare failed rc = %d", __func__,
+				__LINE__, rc);
+			break;
+		}
+		if (rc == I2C_COMPARE_MISMATCH)
+			break;
+		usleep_range(1000, 1010);
+	}
+	return rc;
+}
+
+static int32_t msm_camera_qup_i2c_set_mask(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t mask,
+	enum msm_camera_i2c_data_type data_type, uint16_t set_mask)
+{
+	int32_t rc;
+	uint16_t reg_data;
+
+	rc = msm_camera_qup_i2c_read(client, addr, &reg_data, data_type);
+	if (rc < 0) {
+		S_I2C_DBG("%s read fail\n", __func__);
+		return rc;
+	}
+	S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n",
+			__func__, addr, reg_data, mask);
+
+	if (set_mask)
+		reg_data |= mask;
+	else
+		reg_data &= ~mask;
+	S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data);
+
+	rc = msm_camera_qup_i2c_write(client, addr, reg_data, data_type);
+	if (rc < 0)
+		S_I2C_DBG("%s write fail\n", __func__);
+
+	return rc;
+}
+
+static int32_t msm_camera_qup_i2c_set_write_mask_data(
+	struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data, int16_t mask,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc;
+	uint16_t reg_data;
+
+	CDBG("%s\n", __func__);
+	if (mask == -1)
+		return 0;
+	if (mask == 0) {
+		rc = msm_camera_qup_i2c_write(client, addr, data, data_type);
+	} else {
+		rc = msm_camera_qup_i2c_read(client, addr, &reg_data,
+			data_type);
+		if (rc < 0) {
+			CDBG("%s read fail\n", __func__);
+			return rc;
+		}
+		reg_data &= ~mask;
+		reg_data |= (data & mask);
+		rc = msm_camera_qup_i2c_write(client, addr, reg_data,
+			data_type);
+		if (rc < 0)
+			CDBG("%s write fail\n", __func__);
+	}
+	return rc;
+}
+
+
+int32_t msm_camera_qup_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int i;
+	int32_t rc = -EFAULT;
+
+	pr_err("%s, E. ", __func__);
+	for (i = 0; i < size; i++) {
+		enum msm_camera_i2c_data_type dt;
+
+		if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
+			rc = msm_camera_qup_i2c_poll(client,
+				reg_conf_tbl->reg_addr,
+				reg_conf_tbl->reg_data,
+				reg_conf_tbl->dt, I2C_POLL_TIME_MS);
+		} else {
+			if (reg_conf_tbl->dt == 0)
+				dt = data_type;
+			else
+				dt = reg_conf_tbl->dt;
+			switch (dt) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+				rc = msm_camera_qup_i2c_write(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data, dt);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_MASK:
+				rc = msm_camera_qup_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+				rc = msm_camera_qup_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_WORD_MASK:
+				rc = msm_camera_qup_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 1);
+				break;
+			case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+				rc = msm_camera_qup_i2c_set_mask(client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					MSM_CAMERA_I2C_WORD_DATA, 0);
+				break;
+			case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+				rc = msm_camera_qup_i2c_set_write_mask_data(
+					client,
+					reg_conf_tbl->reg_addr,
+					reg_conf_tbl->reg_data,
+					reg_conf_tbl->mask,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			default:
+				pr_err("%s: Unsupport data type: %d\n",
+					__func__, dt);
+				break;
+			}
+		}
+		if (rc < 0)
+			break;
+		reg_conf_tbl++;
+	}
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c
new file mode 100644
index 0000000..713ca06
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.c
@@ -0,0 +1,854 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <soc/qcom/camera2.h>
+#include "msm_camera_spi.h"
+
+#undef SPIDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define SPIDBG(fmt, args...) pr_debug(fmt, ##args)
+#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define SPIDBG(fmt, args...) do { } while (0)
+#define S_I2C_DBG(fmt, args...) do { } while (0)
+#endif
+
+static int msm_camera_spi_txfr(struct spi_device *spi, char *txbuf,
+	char *rxbuf, int num_byte)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+
+	memset(&t, 0, sizeof(t));
+	t.tx_buf = txbuf;
+	t.rx_buf = rxbuf;
+	t.len = num_byte;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	return spi_sync(spi, &m);
+}
+
+static int msm_camera_spi_txfr_read(struct spi_device *spi, char *txbuf,
+	char *rxbuf, int txlen, int rxlen)
+{
+	struct spi_transfer tx;
+	struct spi_transfer rx;
+	struct spi_message m;
+
+	memset(&tx, 0, sizeof(tx));
+	memset(&rx, 0, sizeof(rx));
+	tx.tx_buf = txbuf;
+	rx.rx_buf = rxbuf;
+	tx.len = txlen;
+	rx.len = rxlen;
+	spi_message_init(&m);
+	spi_message_add_tail(&tx, &m);
+	spi_message_add_tail(&rx, &m);
+	return spi_sync(spi, &m);
+}
+
+
+/*
+ * msm_camera_set_addr() - helper function to set transfer address
+ * @addr:	device address
+ * @addr_len:	the addr field length of an instruction
+ * @type:	type (i.e. byte-length) of @addr
+ * @str:	shifted address output, must be zeroed when passed in
+ *
+ * This helper function sets @str based on the addr field length of an
+ * instruction and the data length.
+ */
+static void msm_camera_set_addr(uint32_t addr, uint8_t addr_len,
+				enum msm_camera_i2c_reg_addr_type type,
+				char *str)
+{
+	int i, len;
+
+	if (!addr_len)
+		return;
+
+	if (addr_len < type)
+		SPIDBG("%s: omitting higher bits in address\n", __func__);
+
+	/* only support transfer MSB first for now */
+	len = addr_len - type;
+	for (i = len; i < addr_len; i++) {
+		if (i >= 0)
+			str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1)))
+				& 0xFF;
+	}
+
+}
+
+/*
+ * msm_camera_spi_tx_helper() - wrapper for SPI transaction
+ * @client:	io client
+ * @inst:	inst of this transaction
+ * @addr:	device addr following the inst
+ * @data:	output byte array (could be NULL)
+ * @num_byte:	size of @data
+ * @tx, rx:	optional transfer buffer.  It must be at least header
+ *		+ @num_byte long.
+ *
+ * This is the core function for SPI transaction, except for writes.  It first
+ * checks address type, then allocates required memory for tx/rx buffers.
+ * It sends out <opcode><addr>, and optionally receives @num_byte of response,
+ * if @data is not NULL.  This function does not check for wait conditions,
+ * and will return immediately once bus transaction finishes.
+ *
+ * This function will allocate buffers of header + @num_byte long.  For
+ * large transfers, the allocation could fail.  External buffer @tx, @rx
+ * should be passed in to bypass allocation.  The size of buffer should be
+ * at least header + num_byte long.  Since buffer is managed externally,
+ * @data will be ignored, and read results will be in @rx.
+ * @tx, @rx also can be used for repeated transfers to improve performance.
+ */
+static int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client,
+	struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
+	uint32_t num_byte, char *tx, char *rx)
+{
+	int32_t rc = -EINVAL;
+	struct spi_device *spi = client->spi_client->spi_master;
+	char *ctx = NULL, *crx = NULL;
+	uint32_t len, hlen;
+	uint8_t retries = client->spi_client->retries;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_3B_ADDR))
+		return rc;
+
+	hlen = msm_camera_spi_get_hlen(inst);
+	len = hlen + num_byte;
+
+	if (tx)
+		ctx = tx;
+	else
+		ctx = kzalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (num_byte) {
+		if (rx)
+			crx = rx;
+		else
+			crx = kzalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!crx) {
+			if (!tx)
+				kfree(ctx);
+			return -ENOMEM;
+		}
+	} else {
+		crx = NULL;
+	}
+
+	ctx[0] = inst->opcode;
+	msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1);
+	while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) {
+		retries--;
+		msleep(client->spi_client->retry_delay);
+	}
+	if (rc < 0) {
+		SPIDBG("%s: failed %d\n", __func__, rc);
+		goto out;
+	}
+	if (data && num_byte && !rx)
+		memcpy(data, crx + hlen, num_byte);
+
+out:
+	if (!tx)
+		kfree(ctx);
+	if (!rx)
+		kfree(crx);
+	return rc;
+}
+
+static int32_t msm_camera_spi_tx_read(struct msm_camera_i2c_client *client,
+	struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
+	uint32_t num_byte, char *tx, char *rx)
+{
+	int32_t rc = -EINVAL;
+	struct spi_device *spi = client->spi_client->spi_master;
+	char *ctx = NULL, *crx = NULL;
+	uint32_t hlen;
+	uint8_t retries = client->spi_client->retries;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_3B_ADDR))
+		return rc;
+
+	hlen = msm_camera_spi_get_hlen(inst);
+	if (tx)
+		ctx = tx;
+	else
+		ctx = kzalloc(hlen, GFP_KERNEL | GFP_DMA);
+	if (!ctx)
+		return -ENOMEM;
+	if (num_byte) {
+		if (rx)
+			crx = rx;
+		else
+			crx = kzalloc(num_byte, GFP_KERNEL | GFP_DMA);
+		if (!crx) {
+			if (!tx)
+				kfree(ctx);
+			return -ENOMEM;
+		}
+	} else {
+		crx = NULL;
+	}
+
+	ctx[0] = inst->opcode;
+	if (client->addr_type == MSM_CAMERA_I2C_3B_ADDR) {
+		msm_camera_set_addr(addr, inst->addr_len, client->addr_type,
+			ctx + 1);
+	} else {
+		ctx[1] = (addr >> BITS_PER_BYTE) & 0xFF;
+		ctx[2] = (addr & 0xFF);
+		ctx[3] = 0;
+	}
+	SPIDBG("%s: tx(%u): %02x %02x %02x %02x\n", __func__,
+		hlen, ctx[0], ctx[1], ctx[2], ctx[3]);
+	while ((rc = msm_camera_spi_txfr_read(spi, ctx, crx, hlen, num_byte))
+			&& retries) {
+		retries--;
+		msleep(client->spi_client->retry_delay);
+	}
+	if (rc < 0) {
+		pr_err("%s: failed %d\n", __func__, rc);
+		goto out;
+	}
+	if (data && num_byte && !rx)
+		memcpy(data, crx, num_byte);
+out:
+	if (!tx)
+		kfree(ctx);
+	if (!rx)
+		kfree(crx);
+	return rc;
+}
+
+int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EINVAL;
+	uint8_t temp[2];
+
+	if ((data_type != MSM_CAMERA_I2C_BYTE_DATA)
+	    && (data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	rc = msm_camera_spi_tx_read(client,
+			&client->spi_client->cmd_tbl.read, addr, &temp[0],
+			data_type, NULL, NULL);
+	if (rc < 0) {
+		pr_err("%s: failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
+		*data = temp[0];
+	else
+		*data = (temp[0] << BITS_PER_BYTE) | temp[1];
+
+	SPIDBG("%s: addr 0x%x, data %u\n", __func__, addr, *data);
+	return rc;
+}
+
+int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	return msm_camera_spi_tx_helper(client,
+		&client->spi_client->cmd_tbl.read_seq, addr, data, num_byte,
+		NULL, NULL);
+}
+
+/*
+ * msm_camera_spi_read_seq_l()- function for large SPI reads
+ * @client:	io client
+ * @addr:	device address to read
+ * @num_byte:	read length
+ * @tx,rx:	pre-allocated SPI buffer.  Its size must be at least
+ *		header + num_byte
+ *
+ * This function is used for large transactions.  Instead of allocating SPI
+ * buffer each time, caller is responsible for pre-allocating memory buffers.
+ * Memory buffer must be at least header + num_byte.  Header length can be
+ * obtained by msm_camera_spi_get_hlen().
+ */
+int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint32_t num_byte, char *tx, char *rx)
+{
+	return msm_camera_spi_tx_helper(client,
+		&client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte,
+		tx, rx);
+}
+
+int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	return msm_camera_spi_tx_helper(client,
+		&client->spi_client->cmd_tbl.query_id, addr, data, num_byte,
+		NULL, NULL);
+}
+
+static int32_t msm_camera_spi_read_status_reg(
+	struct msm_camera_i2c_client *client, uint8_t *status)
+{
+	struct msm_camera_spi_inst *rs =
+		&client->spi_client->cmd_tbl.read_status;
+	if (rs->addr_len != 0) {
+		pr_err("%s: not implemented yet\n", __func__);
+		return -EINVAL;
+	}
+	return msm_camera_spi_tx_helper(client, rs, 0, status, 1, NULL, NULL);
+}
+
+static int32_t msm_camera_spi_device_busy(struct msm_camera_i2c_client *client,
+	uint8_t *busy)
+{
+	int rc;
+	uint8_t st = 0;
+
+	rc = msm_camera_spi_read_status_reg(client,  &st);
+	if (rc < 0) {
+		pr_err("%s: failed to read status reg\n", __func__);
+		return rc;
+	}
+	*busy = st & client->spi_client->busy_mask;
+	return 0;
+}
+
+static int32_t msm_camera_spi_wait(struct msm_camera_i2c_client *client,
+	struct msm_camera_spi_inst *inst)
+{
+	uint8_t busy;
+	int i, rc;
+
+	SPIDBG("%s: op 0x%x wait start\n", __func__, inst->opcode);
+	for (i = 0; i < inst->delay_count; i++) {
+		rc = msm_camera_spi_device_busy(client, &busy);
+		if (rc < 0)
+			return rc;
+		if (!busy)
+			break;
+
+		msleep(inst->delay_intv);
+		SPIDBG("%s: op 0x%x wait\n", __func__, inst->opcode);
+	}
+	if (i > inst->delay_count) {
+		pr_err("%s: op %x timed out\n", __func__, inst->opcode);
+		return -ETIMEDOUT;
+	}
+	SPIDBG("%s: op %x finished\n", __func__, inst->opcode);
+	return 0;
+}
+
+static int32_t msm_camera_spi_write_enable(
+	struct msm_camera_i2c_client *client)
+{
+	struct msm_camera_spi_inst *we =
+		&client->spi_client->cmd_tbl.write_enable;
+	int rc;
+
+	if (we->opcode == 0)
+		return 0;
+	if (we->addr_len != 0) {
+		pr_err("%s: not implemented yet\n", __func__);
+		return -EINVAL;
+	}
+	rc = msm_camera_spi_tx_helper(client, we, 0, NULL, 0, NULL, NULL);
+	if (rc < 0)
+		pr_err("%s: write enable failed\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint32_t size)
+{
+	struct msm_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase;
+	int rc = 0;
+	uint32_t cur;
+	uint32_t end = addr + size;
+	uint32_t erase_size = client->spi_client->erase_size;
+
+	end = addr + size;
+	for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) {
+		SPIDBG("%s: erasing 0x%x\n", __func__, cur);
+		rc = msm_camera_spi_write_enable(client);
+		if (rc < 0)
+			return rc;
+		rc = msm_camera_spi_tx_helper(client, se, cur, NULL, 0,
+			NULL, NULL);
+		if (rc < 0) {
+			pr_err("%s: erase failed\n", __func__);
+			return rc;
+		}
+		rc = msm_camera_spi_wait(client, se);
+		if (rc < 0) {
+			pr_err("%s: erase timedout\n", __func__);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+/*
+ * msm_camera_spi_page_program() - core function to perform write
+ * @client: need for obtaining SPI device
+ * @addr: address to program on device
+ * @data: data to write
+ * @len: size of data
+ * @tx: tx buffer, size >= header + len
+ *
+ * This function performs SPI write, and has no boundary check.  Writing range
+ * should not cross page boundary, or data will be corrupted.  Transaction is
+ * guaranteed to be finished when it returns.  This function should never be
+ * used outside msm_camera_spi_write_seq().
+ */
+static int32_t msm_camera_spi_page_program(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint16_t len, uint8_t *tx)
+{
+	int rc;
+	struct msm_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	struct spi_device *spi = client->spi_client->spi_master;
+	uint8_t retries = client->spi_client->retries;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+
+	SPIDBG("%s: addr 0x%x, size 0x%x\n", __func__, addr, len);
+	rc = msm_camera_spi_write_enable(client);
+	if (rc < 0)
+		return rc;
+	memset(tx, 0, header_len);
+	tx[0] = pg->opcode;
+	msm_camera_set_addr(addr, pg->addr_len, client->addr_type, tx + 1);
+	memcpy(tx + header_len, data, len);
+	SPIDBG("%s: tx(%u): %02x %02x %02x %02x\n", __func__,
+		len, tx[0], tx[1], tx[2], tx[3]);
+	while ((rc = spi_write(spi, tx, len + header_len)) && retries) {
+		rc = msm_camera_spi_wait(client, pg);
+		msleep(client->spi_client->retry_delay);
+		retries--;
+	}
+	if (rc < 0) {
+		pr_err("%s: failed %d\n", __func__, rc);
+		return rc;
+	}
+	rc = msm_camera_spi_wait(client, pg);
+		return rc;
+}
+
+int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	struct msm_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	const uint32_t page_size = client->spi_client->page_size;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	uint16_t len;
+	uint32_t cur_len, end;
+	char *tx, *pdata = data;
+	int rc = -EINVAL;
+
+	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_3B_ADDR))
+		return rc;
+    /* single page write */
+	if ((addr % page_size) + num_byte <= page_size) {
+		len = header_len + num_byte;
+		tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!tx)
+			goto NOMEM;
+		rc = msm_camera_spi_page_program(client, addr, data,
+			num_byte, tx);
+		if (rc < 0)
+			goto ERROR;
+		goto OUT;
+	}
+	/* multi page write */
+	len = header_len + page_size;
+	tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!tx)
+		goto NOMEM;
+	while (num_byte) {
+		end = min(page_size, (addr % page_size) + num_byte);
+		cur_len = end - (addr % page_size);
+		rc = msm_camera_spi_page_program(client, addr, pdata,
+			cur_len, tx);
+		if (rc < 0)
+			goto ERROR;
+		addr += cur_len;
+		pdata += cur_len;
+		num_byte -= cur_len;
+	}
+	goto OUT;
+NOMEM:
+	pr_err("%s: memory allocation failed\n", __func__);
+	return -ENOMEM;
+ERROR:
+	pr_err("%s: error write\n", __func__);
+OUT:
+	kfree(tx);
+	return rc;
+}
+
+int32_t msm_camera_spi_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type)
+{
+	struct msm_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	uint16_t len = 0;
+	char *buf = NULL;
+	char *tx;
+	int rc = -EINVAL;
+
+	if (((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		&& (client->addr_type != MSM_CAMERA_I2C_3B_ADDR))
+		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+	buf = kzalloc(data_type, GFP_KERNEL);
+	if (!buf)
+		goto NOMEM;
+	S_I2C_DBG("Data: 0x%x\n", data);
+	len = header_len + (uint8_t)data_type;
+	tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!tx)
+		goto NOMEM;
+	if (data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+		buf[0] = data;
+		SPIDBG("Byte %d: 0x%x\n", len, buf[0]);
+	} else if (data_type == MSM_CAMERA_I2C_WORD_DATA) {
+		buf[0] = (data >> BITS_PER_BYTE) & 0x00FF;
+		buf[1] = (data & 0x00FF);
+	}
+	rc = msm_camera_spi_page_program(client, addr, buf,
+		(uint16_t)data_type, tx);
+	if (rc < 0)
+		goto ERROR;
+	goto OUT;
+NOMEM:
+	pr_err("%s: memory allocation failed\n", __func__);
+	return -ENOMEM;
+ERROR:
+	pr_err("%s: error write\n", __func__);
+OUT:
+	kfree(tx);
+	return rc;
+}
+int32_t msm_camera_spi_write_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int i;
+	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting;
+	uint16_t client_addr_type;
+
+	if (!client || !write_setting)
+		return rc;
+	if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+		&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+	reg_setting = write_setting->reg_setting;
+	client_addr_type = client->addr_type;
+	client->addr_type = write_setting->addr_type;
+	for (i = 0; i < write_setting->size; i++) {
+		SPIDBG("%s addr %x data %x\n", __func__,
+		reg_setting->reg_addr, reg_setting->reg_data);
+		rc = msm_camera_spi_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
+		if (rc < 0)
+			break;
+		reg_setting++;
+	}
+		if (write_setting->delay > 20)
+			msleep(write_setting->delay);
+		else if (write_setting->delay)
+			usleep_range(write_setting->delay * 1000,
+				(write_setting->delay
+				* 1000) + 1000);
+	client->addr_type = client_addr_type;
+	return rc;
+}
+static uint32_t msm_get_burst_size(struct msm_camera_i2c_reg_array *reg_setting,
+	uint32_t reg_size, uint32_t index, uint16_t burst_addr)
+{
+	uint32_t i;
+	uint32_t cnt = 0;
+
+	for (i = index; i < reg_size; i++) {
+		if (reg_setting[i].reg_addr == burst_addr)
+			cnt++;
+		else
+			break;
+	}
+	return cnt;
+}
+
+#ifdef SPI_DYNAMIC_ALLOC
+static int32_t msm_camera_spi_send_burst(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size,
+	struct msm_camera_burst_info *info,
+	enum msm_camera_i2c_data_type data_type)
+{
+	uint32_t i, j, k;
+	int32_t rc = 0;
+	uint32_t chunk_num, residue;
+	struct msm_camera_spi_inst *pg =
+	&client->spi_client->cmd_tbl.page_program;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	uint8_t *ctx, *data;
+	uint32_t len;
+
+	if (info->burst_len == 0 || info->chunk_size == 0) {
+		pr_err("%s:%d Invalid argument\n", __func__, __LINE__);
+		return rc;
+	}
+	if (info->burst_start + info->burst_len > reg_size) {
+		pr_err("%s too big burst size, index=%d, size=%d\n", __func__,
+			info->burst_start, info->burst_len);
+		return rc;
+	}
+	chunk_num = info->burst_len / info->chunk_size;
+	residue = info->burst_len % info->chunk_size;
+	SPIDBG("%s header_len=%d, chunk nb=%d, residue=%d\n",
+		__func__, header_len, chunk_num, residue);
+	len = info->chunk_size * data_type + header_len;
+	SPIDBG("buffer allocation size = %d\n", len);
+	ctx = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!ctx) {
+		pr_err("%s %d memory alloc fail!\n", __func__, __LINE__);
+		return rc;
+	}
+	ctx[0] = pg->opcode;
+	ctx[1] = (info->burst_addr >> 8) & 0xff;
+	ctx[2] = info->burst_addr & 0xff;
+	k = info->burst_start;
+	for (i = 0; i < chunk_num; i++) {
+		data = ctx + header_len;
+		for (j = 0; j < info->chunk_size; j++) {
+			*data++ = (reg_setting[k+j].reg_data >> 8) & 0xff;
+			*data++ = reg_setting[k+j].reg_data & 0xff;
+		}
+		rc = msm_camera_spi_txfr(client->spi_client->spi_master,
+				(void *) ctx, NULL,
+				info->chunk_size * data_type + header_len);
+		if (rc < 0) {
+			pr_err("%s %d spi sending error = %d!!\n",
+				__func__, __LINE__, rc);
+			goto fail;
+		}
+		k += info->chunk_size;
+	}
+	SPIDBG("%s burst chunk start=%d, residue=%d\n",
+		__func__, k, residue);
+	if (residue) {
+		data = ctx + header_len;
+		for (j = 0; j < residue; j++) {
+			*data++ = (reg_setting[k+j].reg_data >> 8) & 0xff;
+			*data++ = reg_setting[k+j].reg_data & 0xff;
+		}
+		rc = msm_camera_spi_txfr(client->spi_client->spi_master,
+					(void *)ctx, NULL,
+					residue*data_type+header_len);
+		if (rc < 0) {
+			pr_err("%s %d spi sending error = %d!!\n", __func__,
+				__LINE__, rc);
+			goto fail;
+		}
+	}
+fail:
+	kfree(ctx);
+	return rc;
+}
+#else /* SPI_DYNAMIC_ALLOC */
+int32_t msm_camera_spi_send_burst(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size,
+	struct msm_camera_burst_info *info,
+	enum msm_camera_i2c_data_type data_type)
+{
+	uint32_t i, j, k;
+	int32_t rc = 0;
+	uint32_t chunk_num, residue;
+	struct msm_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.page_program;
+	uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
+	struct msm_spi_write_burst_packet tx_buf;
+
+	if (info->burst_len == 0 || info->burst_len == 0
+		|| info->chunk_size == 0) {
+		pr_err("%s %d Invalid argument\n", __func__, __LINE__);
+		return rc;
+	}
+	if (info->burst_start + info->burst_len > reg_size) {
+		pr_err("%s too big burst size, index=%d, size=%d\n", __func__,
+		info->burst_start, info->burst_len);
+		return rc;
+	}
+	chunk_num = info->burst_len / info->chunk_size;
+	residue = info->burst_len % info->chunk_size;
+	SPIDBG("%s header_len=%d, chunk nb=%d, residue=%d\n",
+		__func__, header_len, chunk_num, residue);
+	tx_buf.cmd = pg->opcode;
+	tx_buf.addr_msb = (info->burst_addr >> 8) & 0xff;
+	tx_buf.addr_lsb = info->burst_addr & 0xff;
+	SPIDBG("%s cmd=%d, addr_msb=0x%x, addr_lsb=0x%x\n", __func__,
+		tx_buf.cmd, tx_buf.addr_msb, tx_buf.addr_lsb);
+	k = info->burst_start;
+	for (i = 0; i < chunk_num; i++) {
+		SPIDBG("%s burst chunk start=%d, chunk_size=%d, chunk_num=%d\n",
+			__func__,
+			k, info->chunk_size, i);
+		for (j = 0; j < info->chunk_size; j++) {
+			tx_buf.data_arr[j].data_msb =
+				(reg_setting[k+j].reg_data >> 8) & 0xff;
+			tx_buf.data_arr[j].data_lsb =
+				reg_setting[k+j].reg_data & 0xff;
+		}
+		rc = msm_camera_spi_txfr(client->spi_client->spi_master,
+			(void *)&tx_buf, NULL,
+			info->chunk_size * data_type+header_len);
+		if (rc < 0) {
+			pr_err("%s %d spi sending error = %d!!\n", __func__,
+				__LINE__, rc);
+			goto fail;
+		}
+		k += info->chunk_size;
+	}
+	SPIDBG("%s burst chunk start=%d, residue=%d\n", __func__, k, residue);
+	if (residue) {
+		for (j = 0; j < residue; j++) {
+			tx_buf.data_arr[j].data_msb = (reg_setting[k+j].reg_data
+				>> 8) & 0xff;
+			tx_buf.data_arr[j].data_lsb = reg_setting[k+j].reg_data
+				& 0xff;
+		}
+		rc = msm_camera_spi_txfr(client->spi_client->spi_master,
+					(void *)&tx_buf, NULL,
+					residue * data_type+header_len);
+		if (rc < 0) {
+			pr_err("%s %d spi sending error = %d!!\n", __func__,
+				__LINE__, rc);
+			goto fail;
+		}
+	}
+fail:
+	return rc;
+}
+#endif /* SPI_DYNAMIC_ALLOC */
+
+int32_t msm_camera_spi_write_burst(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size,
+	uint32_t buf_len, uint32_t burst_addr,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int k = 0;
+	int32_t rc = -EFAULT;
+	struct msm_camera_burst_info burst_info;
+
+	SPIDBG(" %s: start\n", __func__);
+	if (buf_len <= 0) {
+		pr_err("%s Invalid parameter, buf_len = %d\n",
+			__func__, buf_len);
+		return rc;
+	}
+	if (reg_size <= 0 || reg_setting == NULL) {
+		pr_err("%s Invalid parameter, array_size = %d\n",
+			__func__, reg_size);
+		return rc;
+	}
+
+	if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+
+	SPIDBG(" %s: buf_len=%d, reg_size=%d\n", __func__, buf_len, reg_size);
+	while (k < reg_size) {
+		if (reg_setting[k].reg_addr == burst_addr) {
+			memset(&burst_info, 0x00,
+				sizeof(struct msm_camera_burst_info));
+			burst_info.burst_addr = burst_addr;
+			burst_info.burst_start = k;
+			burst_info.chunk_size = buf_len;
+			burst_info.burst_len =
+				msm_get_burst_size(reg_setting, reg_size, k,
+					burst_addr);
+			SPIDBG("%s burst start = %d, length = %d\n", __func__,
+				k, burst_info.burst_len);
+			rc = msm_camera_spi_send_burst(client, reg_setting,
+				reg_size, &burst_info, data_type);
+			if (rc < 0) {
+				pr_err("[%s::%d][spi_sync Error::%d]\n",
+					__func__, __LINE__, rc);
+				return rc;
+			}
+			k += burst_info.burst_len;
+		} else {
+			SPIDBG("%s word write, start = %d\n", __func__, k);
+			msm_camera_spi_write(client, reg_setting[k].reg_addr,
+				reg_setting[k].reg_data, data_type);
+			k++;
+		}
+	}
+	SPIDBG("%s: end\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_spi_read_burst(struct msm_camera_i2c_client *client,
+	uint32_t read_byte, uint8_t *buffer, uint32_t burst_addr,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	struct msm_camera_spi_inst *pg =
+		&client->spi_client->cmd_tbl.read;
+	uint32_t len = msm_camera_spi_get_hlen(pg);
+	uint8_t *tx_buf = NULL;
+	uint8_t *r = buffer;
+
+	SPIDBG("%s: start\n", __func__);
+
+	if (buffer == NULL || read_byte == 0 || len == 0) {
+		pr_err("%s %d Invalid parameters!!\n", __func__, __LINE__);
+		return rc;
+	}
+
+	if ((client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+		|| (data_type != MSM_CAMERA_I2C_WORD_DATA))
+		return rc;
+	tx_buf = kzalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!tx_buf)
+		return -ENOMEM;
+
+	tx_buf[0] = pg->opcode;
+	tx_buf[1] = (burst_addr >> 8) & 0xff;
+	tx_buf[2] = burst_addr & 0xff;
+	tx_buf[3] = 0; /* dummy */
+	rc = msm_camera_spi_txfr_read(client->spi_client->spi_master,
+		&tx_buf[0], r, len, read_byte);
+	if (rc < 0)
+		pr_err("[%s::%d][spi_sync Error::%d]\n", __func__,
+			__LINE__, rc);
+
+	kfree(tx_buf);
+
+	SPIDBG("%s: end\n", __func__);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h
new file mode 100644
index 0000000..4a122cf
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_spi.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CAMERA_SPI_H
+#define __MSM_CAMERA_SPI_H
+
+#include <linux/spi/spi.h>
+#include <media/msm_cam_sensor.h>
+#include "msm_camera_i2c.h"
+
+#define MAX_SPI_SIZE 110
+#define SPI_DYNAMIC_ALLOC
+
+/*
+ * Common SPI communication scheme
+ * tx: <opcode>[addr][wait][write buffer]
+ * rx: [read buffer]
+ * Some inst require polling busy reg until it's done
+ */
+struct msm_camera_spi_inst {
+	uint8_t opcode;		/* one-byte opcode */
+	uint8_t addr_len;	/* addr len in bytes */
+	uint8_t dummy_len;	/* setup cycles */
+	uint8_t delay_intv;	/* delay intv for this inst (ms) */
+	uint8_t delay_count;	/* total delay count for this inst */
+};
+
+struct msm_spi_write_burst_data {
+	u8 data_msb;
+	u8 data_lsb;
+};
+
+struct msm_spi_write_burst_packet {
+	u8 cmd;
+	u8 addr_msb;
+	u8 addr_lsb;
+	struct msm_spi_write_burst_data data_arr[MAX_SPI_SIZE];
+};
+
+struct msm_camera_burst_info {
+	uint32_t burst_addr;
+	uint32_t burst_start;
+	uint32_t burst_len;
+	uint32_t chunk_size;
+};
+
+struct msm_camera_spi_inst_tbl {
+	struct msm_camera_spi_inst read;
+	struct msm_camera_spi_inst read_seq;
+	struct msm_camera_spi_inst query_id;
+	struct msm_camera_spi_inst page_program;
+	struct msm_camera_spi_inst write_enable;
+	struct msm_camera_spi_inst read_status;
+	struct msm_camera_spi_inst erase;
+};
+
+struct msm_camera_spi_client {
+	struct spi_device *spi_master;
+	struct msm_camera_spi_inst_tbl cmd_tbl;
+	uint8_t device_id0;
+	uint8_t device_id1;
+	uint8_t mfr_id0;
+	uint8_t mfr_id1;
+	uint8_t retry_delay;	/* ms */
+	uint8_t retries;	/* retry times upon failure */
+	uint8_t busy_mask;	/* busy bit in status reg */
+	uint16_t page_size;	/* page size for page program */
+	uint32_t erase_size;	/* minimal erase size */
+};
+
+static __always_inline
+uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst)
+{
+	return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len;
+}
+
+int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint32_t num_byte, char *tx, char *rx);
+
+int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte);
+
+int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint32_t size);
+
+int32_t msm_camera_spi_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data, enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_spi_write_table(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting);
+
+int32_t msm_camera_spi_write_burst(struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_array *reg_setting, uint32_t reg_size,
+	uint32_t buf_len, uint32_t addr,
+	enum msm_camera_i2c_data_type data_type);
+
+int32_t msm_camera_spi_read_burst(struct msm_camera_i2c_client *client,
+	uint32_t read_byte, uint8_t *buffer, uint32_t addr,
+	enum msm_camera_i2c_data_type data_type);
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c
new file mode 100644
index 0000000..df22d84
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c
@@ -0,0 +1,882 @@
+/* Copyright (c) 2016, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <soc/qcom/camera2.h>
+#include "qseecom_kernel.h"
+#include "msm_camera_i2c.h"
+#include "msm_camera_tz_util.h"
+#include "msm_cci.h"
+#include "msm_sensor.h"
+
+#undef CDBG
+#define MSM_CAMERA_TZ_I2C_VERBOSE
+
+#ifdef CONFIG_MSM_SEC_CCI_DEBUG
+	#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \
+		((ret < 0) ? i2c_fn(__VA_ARGS__):ret)
+#else /* CONFIG_MSM_SEC_CCI_DEBUG */
+	#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \
+			((ret < 0) ? -EFAULT:ret)
+#endif /* CONFIG_MSM_SEC_CCI_DEBUG */
+
+#ifdef MSM_CAMERA_TZ_I2C_VERBOSE
+	#define CDBG(fmt, args...) \
+		pr_info(CONFIG_MSM_SEC_CCI_TA_NAME "::%s:%d - " fmt, \
+		__func__, __LINE__, ##args)
+#else /* MSM_CAMERA_TZ_I2C_VERBOSE */
+	#define CDBG(fmt, args...) \
+		pr_debug("%s:%d - " fmt,  __func__, __LINE__, ##args)
+#endif /* MSM_CAMERA_TZ_I2C_VERBOSE */
+
+#pragma pack(push, msm_camera_tz_i2c, 1)
+
+struct msm_camera_tz_i2c_cci_generic_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+	enum msm_camera_tz_cmd_id_t cci_cmd_id;
+	uint32_t                    cci_i2c_master;
+	uint16_t                    sid;
+	uint16_t                    cid;
+};
+
+#define msm_camera_tz_i2c_cci_generic_rsp_t msm_camera_tz_generic_rsp_t
+
+/* MSM_CAMERA_TZ_CMD_POWER_UP */
+struct msm_camera_tz_i2c_power_up_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+};
+
+#define msm_camera_tz_i2c_power_up_rsp_t msm_camera_tz_generic_rsp_t
+
+/* MSM_CAMERA_TZ_CMD_POWER_DOWN */
+struct msm_camera_tz_i2c_power_down_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+};
+
+#define msm_camera_tz_i2c_power_down_rsp_t msm_camera_tz_generic_rsp_t
+
+/* MSM_CAMERA_TZ_CMD_CCI_READ */
+struct msm_camera_tz_i2c_cci_read_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+	uint32_t                    cci_i2c_master;
+	uint16_t                    sid;
+	uint16_t                    cid;
+	uint32_t                    addr;
+	uint32_t                    data_type;
+};
+
+struct msm_camera_tz_i2c_cci_read_rsp_t {
+	enum msm_camera_tz_status_t rc;
+	uint16_t                    data;
+};
+
+/* MSM_CAMERA_TZ_CMD_CCI_WRITE */
+struct msm_camera_tz_i2c_cci_write_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+	uint32_t                    cci_i2c_master;
+	uint16_t                    sid;
+	uint16_t                    cid;
+	uint32_t                    addr;
+	uint16_t                    data;
+	uint32_t                    data_type;
+};
+
+#define msm_camera_tz_i2c_cci_write_rsp_t msm_camera_tz_generic_rsp_t
+
+/* MSM_CAMERA_TZ_CMD_CCI_UTIL */
+struct msm_camera_tz_i2c_cci_util_req_t {
+	enum msm_camera_tz_cmd_id_t cmd_id;
+	int32_t                     sensor_id;
+	uint32_t                    cci_i2c_master;
+	uint16_t                    sid;
+	uint16_t                    cid;
+	uint16_t                    cci_cmd;
+};
+
+#define msm_camera_tz_i2c_cci_util_rsp_t msm_camera_tz_generic_rsp_t
+
+#pragma pack(pop, msm_camera_tz_i2c)
+
+/* Camera control structure */
+struct msm_camera_tz_i2c_sensor_info_t {
+	struct msm_sensor_ctrl_t    *s_ctrl;
+	struct msm_camera_i2c_fn_t  *saved_sensor_i2c_fn;
+	uint32_t                    secure;
+	uint32_t                    ready;
+};
+
+static struct msm_camera_tz_i2c_sensor_info_t sensor_info[MAX_CAMERAS];
+
+static int32_t msm_camera_tz_i2c_is_sensor_secure(
+	struct msm_camera_i2c_client *client)
+{
+	uint32_t index;
+
+	if (client == NULL) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	for (index = 0; index < MAX_CAMERAS; index++) {
+		if ((sensor_info[index].s_ctrl != NULL) &&
+			sensor_info[index].secure &&
+			(sensor_info[index].s_ctrl->sensor_i2c_client ==
+				client)) {
+			CDBG("Found secure sensor ID = %d\n",
+				sensor_info[index].s_ctrl->id);
+			return sensor_info[index].s_ctrl->id;
+		}
+	}
+	return -EINVAL;
+}
+
+static int32_t msm_camera_tz_i2c_ta_power_up(
+	struct qseecom_handle *ta_qseecom_handle,
+	int32_t sensor_id,
+	uint32_t *sensor_secure)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_power_up_req_t *cmd;
+	struct msm_camera_tz_i2c_power_up_rsp_t *rsp;
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+
+	if (sensor_secure == NULL) {
+		pr_err("%s:%d - Bad parameter\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	*sensor_secure = 0;
+
+	if ((ta_qseecom_handle == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	cmd_len = sizeof(struct msm_camera_tz_i2c_power_up_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_power_up_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_POWER_UP;
+		cmd->sensor_id = sensor_id;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Unable to get sensor secure status, rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+
+		if (rsp->rc == MSM_CAMERA_TZ_STATUS_SUCCESS)
+			*sensor_secure = 1;
+		CDBG("Sensor %d is %s\n", sensor_id,
+			(*sensor_secure)?"SECURE":"NON-SECURE");
+	}
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_power_down(
+	struct qseecom_handle *ta_qseecom_handle,
+	int32_t sensor_id)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_power_down_req_t *cmd;
+	struct msm_camera_tz_i2c_power_down_rsp_t *rsp;
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+
+	if ((ta_qseecom_handle == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	cmd_len = sizeof(struct msm_camera_tz_i2c_power_down_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_power_down_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_POWER_DOWN;
+		cmd->sensor_id = sensor_id;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed: rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_cci_generic(
+	struct msm_camera_i2c_client *client,
+	enum msm_camera_tz_cmd_id_t cci_cmd_id)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_cci_generic_req_t *cmd;
+	struct msm_camera_tz_i2c_cci_generic_rsp_t *rsp;
+	int32_t rc = 0;
+	struct qseecom_handle *ta_qseecom_handle;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	if ((client == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	ta_qseecom_handle = msm_camera_tz_get_ta_handle();
+	cmd_len = sizeof(struct msm_camera_tz_i2c_cci_generic_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_cci_generic_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_CCI_GENERIC;
+		cmd->sensor_id = sensor_id;
+		cmd->cci_cmd_id = cci_cmd_id;
+		cmd->cci_i2c_master = client->cci_client->cci_i2c_master;
+		cmd->sid = client->cci_client->sid;
+		cmd->cid = client->cci_client->cid;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed: rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+		rc = rsp->rc;
+	}
+	CDBG("Done: rc=%d, SN=%d, MS=%d, SID=%d, CID=%d, CMD=%d - %lluus\n",
+		rc,	sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		cci_cmd_id,
+		ktime_us_delta(ktime_get(), startTime));
+
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_cci_read(
+	struct msm_camera_i2c_client *client,
+	uint32_t addr,
+	uint16_t *data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_cci_read_req_t *cmd;
+	struct msm_camera_tz_i2c_cci_read_rsp_t *rsp;
+	int32_t rc = 0;
+	struct qseecom_handle *ta_qseecom_handle;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	if ((client == NULL) ||
+		(data == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	ta_qseecom_handle = msm_camera_tz_get_ta_handle();
+	cmd_len = sizeof(struct msm_camera_tz_i2c_cci_read_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_cci_read_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_CCI_READ;
+		cmd->sensor_id = sensor_id;
+		cmd->cci_i2c_master = client->cci_client->cci_i2c_master;
+		cmd->sid = client->cci_client->sid;
+		cmd->cid = client->cci_client->cid;
+		cmd->addr = addr;
+		cmd->data_type = data_type;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed: rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+		rc = rsp->rc;
+		*data = rsp->data;
+	}
+	CDBG("Done: rc=%d, SN=%d, MS=%d, SID=%d, CID=%d, ", rc,
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	CDBG("Addr=0x%X, Type=%d, Data=0x%X - %lluus\n",
+		addr, data_type, *data,
+		ktime_us_delta(ktime_get(), startTime));
+
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_cci_write(
+	struct msm_camera_i2c_client *client,
+	uint32_t addr,
+	uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_cci_write_req_t *cmd;
+	struct msm_camera_tz_i2c_cci_write_rsp_t *rsp;
+	int32_t rc = 0;
+	struct qseecom_handle *ta_qseecom_handle;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	if ((client == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	ta_qseecom_handle = msm_camera_tz_get_ta_handle();
+	cmd_len = sizeof(struct msm_camera_tz_i2c_cci_write_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_cci_write_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_CCI_WRITE;
+		cmd->sensor_id = sensor_id;
+		cmd->cci_i2c_master = client->cci_client->cci_i2c_master;
+		cmd->sid = client->cci_client->sid;
+		cmd->cid = client->cci_client->cid;
+		cmd->addr = addr;
+		cmd->data = data;
+		cmd->data_type = data_type;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed:, rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+		rc = rsp->rc;
+	}
+	CDBG("Done: rc=%d, SN=%d, MS=%d, SID=%d, CID=%d, ", rc,
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	CDBG("Addr=0x%X, Data=0x%X Type=%d - %lluus\n",
+		addr, data,	data_type,
+		ktime_us_delta(ktime_get(), startTime));
+
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_cci_util(
+	struct msm_camera_i2c_client *client,
+	uint16_t cci_cmd)
+{
+	int32_t cmd_len, rsp_len;
+	struct msm_camera_tz_i2c_cci_util_req_t *cmd;
+	struct msm_camera_tz_i2c_cci_util_rsp_t *rsp;
+	int32_t rc = 0;
+	struct qseecom_handle *ta_qseecom_handle;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	if ((client == NULL) ||
+		(sensor_id < 0) ||
+		(sensor_id >= MAX_CAMERAS)) {
+		pr_err("%s:%d - Bad parameters\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	ta_qseecom_handle = msm_camera_tz_get_ta_handle();
+	cmd_len = sizeof(struct msm_camera_tz_i2c_cci_util_req_t);
+	rsp_len = sizeof(struct msm_camera_tz_i2c_cci_util_rsp_t);
+
+	rc = get_cmd_rsp_buffers(ta_qseecom_handle,
+		(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
+	if (!rc)  {
+		cmd->cmd_id = MSM_CAMERA_TZ_CMD_CCI_UTIL;
+		cmd->sensor_id = sensor_id;
+		cmd->cci_i2c_master = client->cci_client->cci_i2c_master;
+		cmd->sid = client->cci_client->sid;
+		cmd->cid = client->cci_client->cid;
+		cmd->cci_cmd = cci_cmd;
+
+		rc = qseecom_send_command(ta_qseecom_handle,
+			(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+		if (rc < 0) {
+			pr_err("%s:%d - Failed: rc=%d\n",
+				__func__, __LINE__,
+				rc);
+			return rc;
+		}
+		rc = rsp->rc;
+	}
+	CDBG("Done: rc=%d, SN=%d, MS=%d, SID=%d, CID=%d, CMD=%d - %lluus\n",
+		rc,	sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		cci_cmd,
+		ktime_us_delta(ktime_get(), startTime));
+
+	return rc;
+}
+
+static int32_t msm_camera_tz_i2c_ta_probe(
+	struct msm_camera_i2c_client *client)
+{
+	int32_t sensor_id = -1;
+
+	CDBG("Enter\n");
+	sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	if ((sensor_id >= 0) &&
+		(sensor_id < MAX_CAMERAS) &&
+		(sensor_info[sensor_id].ready != 0)) {
+		msm_camera_tz_lock();
+		return sensor_id;
+	}
+	return -EINVAL;
+}
+
+static int32_t msm_camera_tz_i2c_ta_done(void)
+{
+	CDBG("Enter\n");
+	msm_camera_tz_unlock();
+	return 0;
+}
+
+int32_t msm_camera_tz_i2c_power_up(
+	struct msm_camera_i2c_client *client)
+{
+	int32_t rc = 0;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	CDBG("Enter (sensor_id=%d)\n", sensor_id);
+	if ((sensor_id >= 0) && (sensor_id < MAX_CAMERAS)) {
+		rc = msm_camera_tz_load_ta();
+		if (!rc) {
+			uint32_t sensor_secure = 0;
+
+			msm_camera_tz_lock();
+			/* Notify TA & get sensor secure status */
+			rc = msm_camera_tz_i2c_ta_power_up(
+				msm_camera_tz_get_ta_handle(),
+				sensor_id,
+				&sensor_secure);
+			if (!rc && sensor_secure)
+				/* Sensor validated by TA*/
+				sensor_info[sensor_id].ready++;
+			else {
+				msm_camera_tz_unload_ta();
+				rc = -EFAULT;
+			}
+			msm_camera_tz_unlock();
+		}
+	} else
+		rc = -EFAULT;
+	CDBG("Power UP sensor = %d, %s(%d) - %lluus\n",
+		sensor_id,
+		(!rc)?"Ok":"Failed", rc,
+		ktime_us_delta(ktime_get(), startTime));
+	return rc;
+}
+
+int32_t msm_camera_tz_i2c_power_down(
+	struct msm_camera_i2c_client *client)
+{
+	int32_t rc = 0;
+	int32_t sensor_id = msm_camera_tz_i2c_is_sensor_secure(client);
+	ktime_t startTime = ktime_get();
+
+	CDBG("Enter (sensor_id=%d)\n", sensor_id);
+	if ((sensor_id >= 0) &&
+		(sensor_id < MAX_CAMERAS) &&
+		(sensor_info[sensor_id].ready != 0)) {
+
+		msm_camera_tz_lock();
+		rc = msm_camera_tz_i2c_ta_power_down(
+			msm_camera_tz_get_ta_handle(),
+			sensor_id);
+		sensor_info[sensor_id].ready--;
+		msm_camera_tz_unlock();
+		if (!sensor_info[sensor_id].ready)
+			rc = msm_camera_tz_unload_ta();
+	} else
+		rc = -EFAULT;
+	CDBG("Power DOWN sensor = %d, %s(%d) - %lluus\n",
+		sensor_id,
+		(!rc)?"Ok":"Failed", rc,
+		ktime_us_delta(ktime_get(), startTime));
+	return rc;
+}
+
+int32_t msm_camera_tz_i2c_register_sensor(
+	void *s_ctrl_p)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *)s_ctrl_p;
+
+	if (s_ctrl == NULL) {
+		pr_err("%s:%d - invalid parameter)\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	if (s_ctrl->id >= MAX_CAMERAS) {
+		pr_err("%s:%d - invalid ID: %d\n",
+			__func__, __LINE__, s_ctrl->id);
+		return -EINVAL;
+	}
+
+	CDBG("id=%d, client=%pK\n", s_ctrl->id, s_ctrl);
+	sensor_info[s_ctrl->id].s_ctrl = s_ctrl;
+	sensor_info[s_ctrl->id].secure = s_ctrl->is_secure;
+	return 0;
+}
+
+int32_t msm_camera_tz_i2c_read(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t *data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		addr);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_read(
+			client, addr, data, data_type);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_read, client, addr, data, data_type);
+}
+
+int32_t msm_camera_tz_i2c_read_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		addr,
+		num_byte);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_READ_SEQ);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_read_seq, client, addr, data, num_byte);
+}
+
+int32_t msm_camera_tz_i2c_write(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		addr);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_write(
+			client, addr, data, data_type);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write, client, addr, data, data_type);
+}
+
+int32_t msm_camera_tz_i2c_write_seq(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint8_t *data, uint32_t num_byte)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, addr=0x%08X, num=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid,
+		addr,
+		num_byte);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_SEQ);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_seq, client, addr, data, num_byte);
+}
+
+int32_t msm_camera_tz_i2c_write_table_async(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_ASYNC);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_table_async, client, write_setting);
+}
+
+int32_t msm_camera_tz_i2c_write_table_sync(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_SYNC);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_table_sync, client, write_setting);
+}
+
+int32_t msm_camera_tz_i2c_write_table_sync_block(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_SYNC_BLOCK);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_table_sync_block, client,
+			write_setting);
+}
+
+int32_t msm_camera_tz_i2c_write_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_table, client, write_setting);
+}
+
+int32_t msm_camera_tz_i2c_write_seq_table(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_seq_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_SEQ_TABLE);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_seq_table, client, write_setting);
+}
+
+int32_t msm_camera_tz_i2c_write_table_w_microdelay(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_setting *write_setting)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_TABLE_W_MICRODELAY);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_table_w_microdelay, client,
+			write_setting);
+}
+
+int32_t msm_camera_tz_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_POLL);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_poll, client, addr, data, data_type);
+}
+
+int32_t msm_camera_tz_i2c_write_conf_tbl(
+	struct msm_camera_i2c_client *client,
+	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_generic(
+			client, MSM_CAMERA_TZ_CMD_CCI_WRITE_CONF_TBL);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_camera_cci_i2c_write_conf_tbl, client, reg_conf_tbl, size,
+			data_type);
+}
+
+int32_t msm_sensor_tz_i2c_util(struct msm_camera_i2c_client *client,
+	uint16_t cci_cmd)
+{
+	int32_t rc = -EFAULT;
+	int32_t sensor_id = msm_camera_tz_i2c_ta_probe(client);
+
+	CDBG("Sensor=%d, MS=%d, SID=%d, CID=%d, cci_cmd=%d\n",
+		sensor_id,
+		client->cci_client->cci_i2c_master,
+		client->cci_client->sid,
+		client->cci_client->cid, cci_cmd);
+
+	if (sensor_id >= 0) {
+		rc = msm_camera_tz_i2c_ta_cci_util(client, cci_cmd);
+		msm_camera_tz_i2c_ta_done();
+	}
+	return TZ_I2C_FN_RETURN(rc,
+		msm_sensor_cci_i2c_util, client, cci_cmd);
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_cut/Makefile b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/Makefile
new file mode 100644
index 0000000..8950c1c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_ir_cut.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c
new file mode 100644
index 0000000..002a9b9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.c
@@ -0,0 +1,664 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include "msm_ir_cut.h"
+#include "msm_camera_dt_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+DEFINE_MSM_MUTEX(msm_ir_cut_mutex);
+
+static struct v4l2_file_operations msm_ir_cut_v4l2_subdev_fops;
+
+static const struct of_device_id msm_ir_cut_dt_match[] = {
+	{.compatible = "qcom,ir-cut", .data = NULL},
+	{}
+};
+
+static struct msm_ir_cut_table msm_gpio_ir_cut_table;
+
+static struct msm_ir_cut_table *ir_cut_table[] = {
+	&msm_gpio_ir_cut_table,
+};
+
+static int32_t msm_ir_cut_get_subdev_id(
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl, void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	if (ir_cut_ctrl->ir_cut_device_type != MSM_CAMERA_PLATFORM_DEVICE) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+
+	*subdev_id = ir_cut_ctrl->pdev->id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_cut_init(
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
+	struct msm_ir_cut_cfg_data_t *ir_cut_data)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter");
+
+	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(ir_cut_ctrl, ir_cut_data);
+
+	CDBG("Exit");
+	return rc;
+}
+
+static int32_t msm_ir_cut_release(
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl)
+{
+	int32_t rc = 0;
+
+	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_RELEASE) {
+		pr_err("%s:%d Invalid ir_cut state = %d",
+			__func__, __LINE__, ir_cut_ctrl->ir_cut_state);
+		return 0;
+	}
+
+	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(ir_cut_ctrl, NULL);
+	if (rc < 0) {
+		pr_err("%s:%d camera_ir_cut_on failed rc = %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE;
+	return 0;
+}
+
+static int32_t msm_ir_cut_off(struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
+	struct msm_ir_cut_cfg_data_t *ir_cut_data)
+{
+	int rc = 0;
+
+	CDBG("Enter cut off\n");
+
+	if (ir_cut_ctrl->gconf) {
+		rc = msm_camera_request_gpio_table(
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1);
+
+		if (rc < 0) {
+			pr_err("ERR:%s:Failed in selecting state: %d\n",
+				__func__, rc);
+
+			return rc;
+		}
+	} else {
+		pr_err("%s: No IR CUT GPIOs\n", __func__);
+		return 0;
+	}
+
+	if (ir_cut_ctrl->cam_pinctrl_status) {
+		rc = pinctrl_select_state(
+			ir_cut_ctrl->pinctrl_info.pinctrl,
+			ir_cut_ctrl->pinctrl_info.gpio_state_active);
+
+		if (rc < 0)
+			pr_err("ERR:%s:%d cannot set pin to active state: %d",
+				__func__, __LINE__, rc);
+	}
+
+	CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[0] = %d",
+		__func__,
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_P]);
+
+	CDBG("ERR:%s:gpio_conf->gpio_num_info->gpio_num[1] = %d",
+		__func__,
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_M]);
+
+	gpio_set_value_cansleep(
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_P],
+		0);
+
+	gpio_set_value_cansleep(
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_M],
+		1);
+
+	if (ir_cut_ctrl->gconf) {
+		rc = msm_camera_request_gpio_table(
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0);
+
+		if (rc < 0) {
+			pr_err("ERR:%s:Failed in selecting state: %d\n",
+				__func__, rc);
+
+			return rc;
+		}
+	} else {
+		pr_err("%s: No IR CUT GPIOs\n", __func__);
+		return 0;
+	}
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_cut_on(
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
+	struct msm_ir_cut_cfg_data_t *ir_cut_data)
+{
+	int rc = 0;
+
+	CDBG("Enter ir cut on\n");
+
+	if (ir_cut_ctrl->gconf) {
+		rc = msm_camera_request_gpio_table(
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 1);
+
+		if (rc < 0) {
+			pr_err("ERR:%s:Failed in selecting state: %d\n",
+				__func__, rc);
+
+			return rc;
+		}
+	} else {
+		pr_err("%s: No IR CUT GPIOs\n", __func__);
+		return 0;
+	}
+
+	if (ir_cut_ctrl->cam_pinctrl_status) {
+		rc = pinctrl_select_state(
+			ir_cut_ctrl->pinctrl_info.pinctrl,
+			ir_cut_ctrl->pinctrl_info.gpio_state_active);
+
+		if (rc < 0)
+			pr_err("ERR:%s:%d cannot set pin to active state: %d",
+				__func__, __LINE__, rc);
+	}
+
+	CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[0] = %d",
+		__func__,
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_P]);
+
+	CDBG("ERR:%s: gpio_conf->gpio_num_info->gpio_num[1] = %d",
+		__func__,
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_M]);
+
+	gpio_set_value_cansleep(
+		ir_cut_ctrl->gconf->gpio_num_info->
+			gpio_num[IR_CUT_FILTER_GPIO_P],
+		1);
+
+	gpio_set_value_cansleep(
+		ir_cut_ctrl->gconf->
+			gpio_num_info->gpio_num[IR_CUT_FILTER_GPIO_M],
+		1);
+
+	if (ir_cut_ctrl->gconf) {
+		rc = msm_camera_request_gpio_table(
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl_size, 0);
+
+		if (rc < 0) {
+			pr_err("ERR:%s:Failed in selecting state: %d\n",
+				__func__, rc);
+
+			return rc;
+		}
+	} else {
+		pr_err("%s: No IR CUT GPIOs\n", __func__);
+		return 0;
+	}
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_cut_handle_init(
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
+	struct msm_ir_cut_cfg_data_t *ir_cut_data)
+{
+	uint32_t i = 0;
+	int32_t rc = -EFAULT;
+	enum msm_ir_cut_driver_type ir_cut_driver_type =
+		ir_cut_ctrl->ir_cut_driver_type;
+
+	CDBG("Enter");
+
+	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT) {
+		pr_err("%s:%d Invalid ir_cut state = %d",
+			__func__, __LINE__, ir_cut_ctrl->ir_cut_state);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ir_cut_table); i++) {
+		if (ir_cut_driver_type == ir_cut_table[i]->ir_cut_driver_type) {
+			ir_cut_ctrl->func_tbl = &ir_cut_table[i]->func_tbl;
+			rc = 0;
+			break;
+		}
+	}
+
+	if (rc < 0) {
+		pr_err("%s:%d failed invalid ir_cut_driver_type %d\n",
+			__func__, __LINE__, ir_cut_driver_type);
+		return -EINVAL;
+	}
+
+	rc = ir_cut_ctrl->func_tbl->camera_ir_cut_init(
+			ir_cut_ctrl, ir_cut_data);
+	if (rc < 0) {
+		pr_err("%s:%d camera_ir_cut_init failed rc = %d",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_INIT;
+
+	CDBG("Exit");
+	return 0;
+}
+
+static int32_t msm_ir_cut_config(struct msm_ir_cut_ctrl_t *ir_cut_ctrl,
+	void *argp)
+{
+	int32_t rc = -EINVAL;
+	struct msm_ir_cut_cfg_data_t *ir_cut_data =
+		(struct msm_ir_cut_cfg_data_t *) argp;
+
+	mutex_lock(ir_cut_ctrl->ir_cut_mutex);
+
+	CDBG("Enter %s type %d\n", __func__, ir_cut_data->cfg_type);
+
+	switch (ir_cut_data->cfg_type) {
+	case CFG_IR_CUT_INIT:
+		rc = msm_ir_cut_handle_init(ir_cut_ctrl, ir_cut_data);
+		break;
+	case CFG_IR_CUT_RELEASE:
+		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
+			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release(
+				ir_cut_ctrl);
+		break;
+	case CFG_IR_CUT_OFF:
+		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
+			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_off(
+				ir_cut_ctrl, ir_cut_data);
+		break;
+	case CFG_IR_CUT_ON:
+		if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
+			rc = ir_cut_ctrl->func_tbl->camera_ir_cut_on(
+				ir_cut_ctrl, ir_cut_data);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(ir_cut_ctrl->ir_cut_mutex);
+
+	CDBG("Exit %s type %d\n", __func__, ir_cut_data->cfg_type);
+
+	return rc;
+}
+
+static long msm_ir_cut_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_ir_cut_ctrl_t *fctrl = NULL;
+	void *argp = (void *)arg;
+
+	CDBG("Enter\n");
+
+	if (!sd) {
+		pr_err("sd NULL\n");
+		return -EINVAL;
+	}
+	fctrl = v4l2_get_subdevdata(sd);
+	if (!fctrl) {
+		pr_err("fctrl NULL\n");
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_ir_cut_get_subdev_id(fctrl, argp);
+	case VIDIOC_MSM_IR_CUT_CFG:
+		return msm_ir_cut_config(fctrl, argp);
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_SHUTDOWN:
+		if (!fctrl->func_tbl) {
+			pr_err("fctrl->func_tbl NULL\n");
+			return -EINVAL;
+		} else {
+			return fctrl->func_tbl->camera_ir_cut_release(fctrl);
+		}
+	default:
+		pr_err_ratelimited("invalid cmd %d\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+	CDBG("Exit\n");
+}
+
+static struct v4l2_subdev_core_ops msm_ir_cut_subdev_core_ops = {
+	.ioctl = msm_ir_cut_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_ir_cut_subdev_ops = {
+	.core = &msm_ir_cut_subdev_core_ops,
+};
+static int msm_ir_cut_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh) {
+
+	int rc = 0;
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl = v4l2_get_subdevdata(sd);
+
+	CDBG("Enter\n");
+
+	if (!ir_cut_ctrl) {
+		pr_err("%s: failed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (ir_cut_ctrl->ir_cut_state == MSM_CAMERA_IR_CUT_INIT)
+		rc = ir_cut_ctrl->func_tbl->camera_ir_cut_release(
+			ir_cut_ctrl);
+
+	CDBG("Exit\n");
+
+	return rc;
+};
+
+static const struct v4l2_subdev_internal_ops msm_ir_cut_internal_ops = {
+	.close = msm_ir_cut_close,
+};
+
+static int32_t msm_ir_cut_get_gpio_dt_data(struct device_node *of_node,
+		struct msm_ir_cut_ctrl_t *fctrl)
+{
+	int32_t rc = 0, i = 0;
+	uint16_t *gpio_array = NULL;
+	int16_t gpio_array_size = 0;
+	struct msm_camera_gpio_conf *gconf = NULL;
+
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+	if (gpio_array_size > 0) {
+		fctrl->power_info.gpio_conf =
+			 kzalloc(sizeof(struct msm_camera_gpio_conf),
+				 GFP_KERNEL);
+		if (!fctrl->power_info.gpio_conf) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			return rc;
+		}
+		gconf = fctrl->power_info.gpio_conf;
+
+		gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t),
+			GFP_KERNEL);
+		if (!gpio_array)
+			return -ENOMEM;
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			if (((int16_t)gpio_array[i]) < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				rc = -EINVAL;
+				goto free_gpio_array;
+			}
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
+
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto free_gpio_array;
+		}
+		kfree(gpio_array);
+
+		if (fctrl->ir_cut_driver_type == IR_CUT_DRIVER_DEFAULT)
+			fctrl->ir_cut_driver_type = IR_CUT_DRIVER_GPIO;
+		CDBG("%s:%d fctrl->ir_cut_driver_type = %d", __func__, __LINE__,
+			fctrl->ir_cut_driver_type);
+	}
+
+	return rc;
+
+free_gpio_array:
+	kfree(gpio_array);
+	return rc;
+}
+
+static int32_t msm_ir_cut_get_dt_data(struct device_node *of_node,
+	struct msm_ir_cut_ctrl_t *fctrl)
+{
+	int32_t rc = 0;
+
+	CDBG("called\n");
+
+	if (!of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	/* Read the sub device */
+	rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		return rc;
+	}
+
+	fctrl->ir_cut_driver_type = IR_CUT_DRIVER_DEFAULT;
+
+	/* Read the gpio information from device tree */
+	rc = msm_ir_cut_get_gpio_dt_data(of_node, fctrl);
+	if (rc < 0) {
+		pr_err("%s:%d msm_ir_cut_get_gpio_dt_data failed rc %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_ir_cut_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct msm_ir_cut_cfg_data_t32 *u32 =
+		(struct msm_ir_cut_cfg_data_t32 *)arg;
+	struct msm_ir_cut_cfg_data_t ir_cut_data;
+
+	CDBG("Enter");
+	ir_cut_data.cfg_type = u32->cfg_type;
+
+	switch (cmd) {
+	case VIDIOC_MSM_IR_CUT_CFG32:
+		cmd = VIDIOC_MSM_IR_CUT_CFG;
+		break;
+	default:
+		return msm_ir_cut_subdev_ioctl(sd, cmd, arg);
+	}
+
+	rc = msm_ir_cut_subdev_ioctl(sd, cmd, &ir_cut_data);
+
+	CDBG("Exit");
+	return rc;
+}
+
+static long msm_ir_cut_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_ir_cut_subdev_do_ioctl);
+}
+#endif
+
+static int32_t msm_ir_cut_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0, i = 0;
+	struct msm_ir_cut_ctrl_t *ir_cut_ctrl = NULL;
+
+	CDBG("Enter");
+	if (!pdev->dev.of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	ir_cut_ctrl = kzalloc(sizeof(struct msm_ir_cut_ctrl_t), GFP_KERNEL);
+	if (!ir_cut_ctrl)
+		return -ENOMEM;
+
+	memset(ir_cut_ctrl, 0, sizeof(struct msm_ir_cut_ctrl_t));
+
+	ir_cut_ctrl->pdev = pdev;
+
+	rc = msm_ir_cut_get_dt_data(pdev->dev.of_node, ir_cut_ctrl);
+
+	if (rc < 0) {
+		pr_err("%s:%d msm_ir_cut_get_dt_data failed\n",
+			__func__, __LINE__);
+		kfree(ir_cut_ctrl);
+		return -EINVAL;
+	}
+
+	rc = msm_sensor_driver_get_gpio_data(&(ir_cut_ctrl->gconf),
+		(&pdev->dev)->of_node);
+
+	if ((rc < 0) || (ir_cut_ctrl->gconf == NULL)) {
+		pr_err("%s: No IR CUT GPIOs\n", __func__);
+
+		kfree(ir_cut_ctrl);
+		return -EINVAL;
+	}
+
+	CDBG("%s: gpio_request_table_size = %d\n",
+		__func__,
+		ir_cut_ctrl->gconf->cam_gpio_req_tbl_size);
+
+	for (i = 0;
+		i < ir_cut_ctrl->gconf->cam_gpio_req_tbl_size; i++) {
+		CDBG("%s: gpio = %d\n", __func__,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].gpio);
+		CDBG("%s: gpio-flags = %lu\n", __func__,
+			ir_cut_ctrl->gconf->cam_gpio_req_tbl[i].flags);
+		CDBG("%s: gconf->gpio_num_info->gpio_num[%d] = %d\n",
+			__func__, i,
+			ir_cut_ctrl->gconf->gpio_num_info->gpio_num[i]);
+	}
+
+	ir_cut_ctrl->cam_pinctrl_status = 1;
+
+	rc = msm_camera_pinctrl_init(
+		&(ir_cut_ctrl->pinctrl_info), &(pdev->dev));
+
+	if (rc < 0) {
+		pr_err("ERR:%s: Error in reading IR CUT pinctrl\n",
+			__func__);
+		ir_cut_ctrl->cam_pinctrl_status = 0;
+	}
+
+	ir_cut_ctrl->ir_cut_state = MSM_CAMERA_IR_CUT_RELEASE;
+	ir_cut_ctrl->power_info.dev = &ir_cut_ctrl->pdev->dev;
+	ir_cut_ctrl->ir_cut_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	ir_cut_ctrl->ir_cut_mutex = &msm_ir_cut_mutex;
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&ir_cut_ctrl->msm_sd.sd, &msm_ir_cut_subdev_ops);
+	v4l2_set_subdevdata(&ir_cut_ctrl->msm_sd.sd, ir_cut_ctrl);
+
+	ir_cut_ctrl->msm_sd.sd.internal_ops = &msm_ir_cut_internal_ops;
+	ir_cut_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(ir_cut_ctrl->msm_sd.sd.name,
+		ARRAY_SIZE(ir_cut_ctrl->msm_sd.sd.name),
+		"msm_camera_ir_cut");
+	media_entity_pads_init(&ir_cut_ctrl->msm_sd.sd.entity, 0, NULL);
+	ir_cut_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_IR_CUT;
+	ir_cut_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
+	msm_sd_register(&ir_cut_ctrl->msm_sd);
+
+	CDBG("%s:%d ir_cut sd name = %s", __func__, __LINE__,
+		ir_cut_ctrl->msm_sd.sd.entity.name);
+	msm_ir_cut_v4l2_subdev_fops = v4l2_subdev_fops;
+#ifdef CONFIG_COMPAT
+	msm_ir_cut_v4l2_subdev_fops.compat_ioctl32 =
+		msm_ir_cut_subdev_fops_ioctl;
+#endif
+	ir_cut_ctrl->msm_sd.sd.devnode->fops = &msm_ir_cut_v4l2_subdev_fops;
+
+	CDBG("probe success\n");
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, msm_ir_cut_dt_match);
+
+static struct platform_driver msm_ir_cut_platform_driver = {
+	.probe = msm_ir_cut_platform_probe,
+	.driver = {
+		.name = "qcom,ir-cut",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ir_cut_dt_match,
+	},
+};
+
+static int __init msm_ir_cut_init_module(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_ir_cut_platform_driver);
+	if (!rc)
+		return rc;
+
+	pr_err("platform probe for ir_cut failed");
+
+	return rc;
+}
+
+static void __exit msm_ir_cut_exit_module(void)
+{
+	platform_driver_unregister(&msm_ir_cut_platform_driver);
+}
+
+static struct msm_ir_cut_table msm_gpio_ir_cut_table = {
+	.ir_cut_driver_type = IR_CUT_DRIVER_GPIO,
+	.func_tbl = {
+		.camera_ir_cut_init = msm_ir_cut_init,
+		.camera_ir_cut_release = msm_ir_cut_release,
+		.camera_ir_cut_off = msm_ir_cut_off,
+		.camera_ir_cut_on = msm_ir_cut_on,
+	},
+};
+
+module_init(msm_ir_cut_init_module);
+module_exit(msm_ir_cut_exit_module);
+MODULE_DESCRIPTION("MSM IR CUT");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.h b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.h
new file mode 100644
index 0000000..91401f4
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_cut/msm_ir_cut.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MSM_IR_CUT_H
+#define MSM_IR_CUT_H
+
+#include <soc/qcom/camera2.h>
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_sd.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+enum msm_camera_ir_cut_state_t {
+	MSM_CAMERA_IR_CUT_INIT,
+	MSM_CAMERA_IR_CUT_RELEASE,
+};
+
+enum msm_ir_cut_driver_type {
+	IR_CUT_DRIVER_GPIO,
+	IR_CUT_DRIVER_DEFAULT,
+};
+
+struct msm_ir_cut_ctrl_t;
+
+struct msm_ir_cut_func_t {
+	int32_t (*camera_ir_cut_init)(struct msm_ir_cut_ctrl_t *,
+		struct msm_ir_cut_cfg_data_t *);
+	int32_t (*camera_ir_cut_release)(struct msm_ir_cut_ctrl_t *);
+	int32_t (*camera_ir_cut_off)(struct msm_ir_cut_ctrl_t *,
+		struct msm_ir_cut_cfg_data_t *);
+	int32_t (*camera_ir_cut_on)(struct msm_ir_cut_ctrl_t *,
+		struct msm_ir_cut_cfg_data_t *);
+};
+
+struct msm_ir_cut_table {
+	enum msm_ir_cut_driver_type ir_cut_driver_type;
+	struct msm_ir_cut_func_t func_tbl;
+};
+
+struct msm_ir_cut_ctrl_t {
+	struct msm_sd_subdev msm_sd;
+	struct platform_device *pdev;
+	struct msm_ir_cut_func_t *func_tbl;
+	struct msm_camera_power_ctrl_t power_info;
+
+	enum msm_camera_device_type_t ir_cut_device_type;
+	struct mutex *ir_cut_mutex;
+
+	/* ir_cut driver type */
+	enum msm_ir_cut_driver_type ir_cut_driver_type;
+
+	/* ir_cut state */
+	enum msm_camera_ir_cut_state_t ir_cut_state;
+
+	struct msm_camera_gpio_conf *gconf;
+	struct msm_pinctrl_info pinctrl_info;
+	uint8_t cam_pinctrl_status;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_led/Makefile b/drivers/media/platform/msm/camera_v2/sensor/ir_led/Makefile
new file mode 100644
index 0000000..6e99ecc
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_led/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_ir_led.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c
new file mode 100644
index 0000000..2beca58
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.c
@@ -0,0 +1,461 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include "msm_ir_led.h"
+#include "msm_camera_dt_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+DEFINE_MSM_MUTEX(msm_ir_led_mutex);
+
+static struct v4l2_file_operations msm_ir_led_v4l2_subdev_fops;
+
+static const struct of_device_id msm_ir_led_dt_match[] = {
+	{.compatible = "qcom,ir-led", .data = NULL},
+	{}
+};
+
+static struct msm_ir_led_table msm_default_ir_led_table;
+
+static struct msm_ir_led_table *ir_led_table[] = {
+	&msm_default_ir_led_table,
+};
+
+static int32_t msm_ir_led_get_subdev_id(
+	struct msm_ir_led_ctrl_t *ir_led_ctrl, void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("subdevice ID is not valid\n");
+		return -EINVAL;
+	}
+	if (ir_led_ctrl->ir_led_device_type != MSM_CAMERA_PLATFORM_DEVICE) {
+		pr_err("device type is not matching\n");
+		return -EINVAL;
+	}
+
+	*subdev_id = ir_led_ctrl->pdev->id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_led_init(
+	struct msm_ir_led_ctrl_t *ir_led_ctrl,
+	struct msm_ir_led_cfg_data_t *ir_led_data)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+
+	rc = ir_led_ctrl->func_tbl->camera_ir_led_off(ir_led_ctrl, ir_led_data);
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_ir_led_release(
+	struct msm_ir_led_ctrl_t *ir_led_ctrl)
+{
+	int32_t rc = 0;
+
+	if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_RELEASE) {
+		pr_err("Invalid ir_led state = %d\n",
+			ir_led_ctrl->ir_led_state);
+		return 0;
+	}
+
+	rc = ir_led_ctrl->func_tbl->camera_ir_led_off(ir_led_ctrl, NULL);
+	if (rc < 0) {
+		pr_err("camera_ir_led_off failed (%d)\n", rc);
+		return rc;
+	}
+	ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_RELEASE;
+	return 0;
+}
+
+static int32_t msm_ir_led_off(struct msm_ir_led_ctrl_t *ir_led_ctrl,
+	struct msm_ir_led_cfg_data_t *ir_led_data)
+{
+	CDBG("Enter\n");
+
+	if (ir_led_ctrl->pwm_dev)
+		pwm_disable(ir_led_ctrl->pwm_dev);
+	else
+		pr_err("pwm device is null\n");
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_led_on(
+	struct msm_ir_led_ctrl_t *ir_led_ctrl,
+	struct msm_ir_led_cfg_data_t *ir_led_data)
+{
+	int rc;
+
+	CDBG("pwm duty on(ns) %d, pwm period(ns) %d\n",
+		ir_led_data->pwm_duty_on_ns, ir_led_data->pwm_period_ns);
+
+	if (ir_led_ctrl->pwm_dev) {
+		rc = pwm_config(ir_led_ctrl->pwm_dev,
+			ir_led_data->pwm_duty_on_ns,
+			ir_led_data->pwm_period_ns);
+		if (rc) {
+			pr_err("PWM config failed (%d)\n", rc);
+			return rc;
+		}
+
+		rc = pwm_enable(ir_led_ctrl->pwm_dev);
+		if (rc) {
+			pr_err("PWM enable failed(%d)\n", rc);
+			return rc;
+		}
+	} else
+		pr_err("pwm device is null\n");
+
+	return 0;
+}
+
+static int32_t msm_ir_led_handle_init(
+	struct msm_ir_led_ctrl_t *ir_led_ctrl,
+	struct msm_ir_led_cfg_data_t *ir_led_data)
+{
+	uint32_t i = 0;
+	int32_t rc = -EFAULT;
+	enum msm_ir_led_driver_type ir_led_driver_type =
+		ir_led_ctrl->ir_led_driver_type;
+
+	CDBG("Enter\n");
+
+	if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT) {
+		pr_err("Invalid ir_led state = %d\n",
+				ir_led_ctrl->ir_led_state);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ir_led_table); i++) {
+		if (ir_led_driver_type == ir_led_table[i]->ir_led_driver_type) {
+			ir_led_ctrl->func_tbl = &ir_led_table[i]->func_tbl;
+			rc = 0;
+			break;
+		}
+	}
+
+	if (rc < 0) {
+		pr_err("failed invalid ir_led_driver_type %d\n",
+				ir_led_driver_type);
+		return -EINVAL;
+	}
+
+	rc = ir_led_ctrl->func_tbl->camera_ir_led_init(
+			ir_led_ctrl, ir_led_data);
+	if (rc < 0) {
+		pr_err("camera_ir_led_init failed (%d)\n", rc);
+		return rc;
+	}
+
+	ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_INIT;
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int32_t msm_ir_led_config(struct msm_ir_led_ctrl_t *ir_led_ctrl,
+	void *argp)
+{
+	int32_t rc = -EINVAL;
+	struct msm_ir_led_cfg_data_t *ir_led_data =
+		(struct msm_ir_led_cfg_data_t *) argp;
+
+	mutex_lock(ir_led_ctrl->ir_led_mutex);
+
+	CDBG("type %d\n", ir_led_data->cfg_type);
+
+	switch (ir_led_data->cfg_type) {
+	case CFG_IR_LED_INIT:
+		rc = msm_ir_led_handle_init(ir_led_ctrl, ir_led_data);
+		break;
+	case CFG_IR_LED_RELEASE:
+		if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT)
+			rc = ir_led_ctrl->func_tbl->camera_ir_led_release(
+				ir_led_ctrl);
+		break;
+	case CFG_IR_LED_OFF:
+		if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT)
+			rc = ir_led_ctrl->func_tbl->camera_ir_led_off(
+				ir_led_ctrl, ir_led_data);
+		break;
+	case CFG_IR_LED_ON:
+		if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT)
+			rc = ir_led_ctrl->func_tbl->camera_ir_led_on(
+				ir_led_ctrl, ir_led_data);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(ir_led_ctrl->ir_led_mutex);
+
+	CDBG("Exit: type %d\n", ir_led_data->cfg_type);
+
+	return rc;
+}
+
+static long msm_ir_led_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_ir_led_ctrl_t *fctrl = NULL;
+	void *argp = (void *)arg;
+
+	CDBG("Enter\n");
+
+	if (!sd) {
+		pr_err(" v4l2 ir led subdevice is NULL\n");
+		return -EINVAL;
+	}
+	fctrl = v4l2_get_subdevdata(sd);
+	if (!fctrl) {
+		pr_err("fctrl NULL\n");
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_ir_led_get_subdev_id(fctrl, argp);
+	case VIDIOC_MSM_IR_LED_CFG:
+		return msm_ir_led_config(fctrl, argp);
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_SHUTDOWN:
+		if (!fctrl->func_tbl) {
+			pr_err("No call back funcions\n");
+			return -EINVAL;
+		} else {
+			return fctrl->func_tbl->camera_ir_led_release(fctrl);
+		}
+	default:
+		pr_err_ratelimited("invalid cmd %d\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+	CDBG("Exit\n");
+}
+
+static struct v4l2_subdev_core_ops msm_ir_led_subdev_core_ops = {
+	.ioctl = msm_ir_led_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_ir_led_subdev_ops = {
+	.core = &msm_ir_led_subdev_core_ops,
+};
+
+static int msm_ir_led_close(struct v4l2_subdev *sd,
+			struct v4l2_subdev_fh *fh) {
+
+	int rc = 0;
+	struct msm_ir_led_ctrl_t *ir_led_ctrl = v4l2_get_subdevdata(sd);
+
+	if (!ir_led_ctrl) {
+		pr_err("v4l2 subdevice data read failed\n");
+		return -EINVAL;
+	}
+
+	CDBG("Enter\n");
+
+	if (ir_led_ctrl->ir_led_state == MSM_CAMERA_IR_LED_INIT)
+		rc = ir_led_ctrl->func_tbl->camera_ir_led_release(
+			ir_led_ctrl);
+
+	CDBG("Exit (%d)\n", rc);
+
+	return rc;
+}
+
+static const struct v4l2_subdev_internal_ops msm_ir_led_internal_ops = {
+	.close = msm_ir_led_close,
+};
+
+static int32_t msm_ir_led_get_dt_data(struct device_node *of_node,
+	struct msm_ir_led_ctrl_t *fctrl)
+{
+	int32_t rc = 0;
+
+	CDBG("called\n");
+
+	/* Read the sub device */
+	rc = of_property_read_u32(of_node, "cell-index", &fctrl->pdev->id);
+	if (rc < 0) {
+		pr_err("reading cell-index for ir-led node is failed(rc) %d\n",
+				rc);
+		return rc;
+	}
+
+	fctrl->ir_led_driver_type = IR_LED_DRIVER_DEFAULT;
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_ir_led_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct msm_ir_led_cfg_data_t32 *u32 =
+		(struct msm_ir_led_cfg_data_t32 *)arg;
+	struct msm_ir_led_cfg_data_t ir_led_data;
+
+	CDBG("Enter\n");
+	ir_led_data.cfg_type = u32->cfg_type;
+	ir_led_data.pwm_duty_on_ns = u32->pwm_duty_on_ns;
+	ir_led_data.pwm_period_ns = u32->pwm_period_ns;
+
+	switch (cmd) {
+	case VIDIOC_MSM_IR_LED_CFG32:
+		cmd = VIDIOC_MSM_IR_LED_CFG;
+		break;
+	default:
+		return msm_ir_led_subdev_ioctl(sd, cmd, arg);
+	}
+
+	rc = msm_ir_led_subdev_ioctl(sd, cmd, &ir_led_data);
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static long msm_ir_led_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_ir_led_subdev_do_ioctl);
+}
+#endif
+
+static int32_t msm_ir_led_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_ir_led_ctrl_t *ir_led_ctrl = NULL;
+
+	CDBG("Enter\n");
+	if (!pdev->dev.of_node) {
+		pr_err("IR LED device node is not present in device tree\n");
+		return -EINVAL;
+	}
+
+	ir_led_ctrl = devm_kzalloc(&pdev->dev, sizeof(struct msm_ir_led_ctrl_t),
+				GFP_KERNEL);
+	if (!ir_led_ctrl)
+		return -ENOMEM;
+
+	ir_led_ctrl->pdev = pdev;
+
+	/* Reading PWM device node */
+	ir_led_ctrl->pwm_dev = of_pwm_get(pdev->dev.of_node, NULL);
+
+	if (IS_ERR(ir_led_ctrl->pwm_dev)) {
+		rc = PTR_ERR(ir_led_ctrl->pwm_dev);
+		pr_err("Cannot get PWM device (%d)\n", rc);
+		ir_led_ctrl->pwm_dev = NULL;
+	}
+
+	rc = msm_ir_led_get_dt_data(pdev->dev.of_node, ir_led_ctrl);
+	if (rc < 0) {
+		pr_err("msm_ir_led_get_dt_data failed\n");
+		devm_kfree(&pdev->dev, ir_led_ctrl);
+		return -EINVAL;
+	}
+
+	ir_led_ctrl->ir_led_state = MSM_CAMERA_IR_LED_RELEASE;
+	ir_led_ctrl->power_info.dev = &ir_led_ctrl->pdev->dev;
+	ir_led_ctrl->ir_led_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	ir_led_ctrl->ir_led_mutex = &msm_ir_led_mutex;
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&ir_led_ctrl->msm_sd.sd, &msm_ir_led_subdev_ops);
+	v4l2_set_subdevdata(&ir_led_ctrl->msm_sd.sd, ir_led_ctrl);
+
+	ir_led_ctrl->msm_sd.sd.internal_ops = &msm_ir_led_internal_ops;
+	ir_led_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(ir_led_ctrl->msm_sd.sd.name,
+		ARRAY_SIZE(ir_led_ctrl->msm_sd.sd.name),
+		"msm_camera_ir_led");
+	media_entity_pads_init(&ir_led_ctrl->msm_sd.sd.entity, 0, NULL);
+	ir_led_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_IR_LED;
+	ir_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
+	msm_sd_register(&ir_led_ctrl->msm_sd);
+
+	CDBG("ir_led sd name = %s\n",
+		ir_led_ctrl->msm_sd.sd.entity.name);
+	msm_ir_led_v4l2_subdev_fops = v4l2_subdev_fops;
+#ifdef CONFIG_COMPAT
+	msm_ir_led_v4l2_subdev_fops.compat_ioctl32 =
+		msm_ir_led_subdev_fops_ioctl;
+#endif
+	ir_led_ctrl->msm_sd.sd.devnode->fops = &msm_ir_led_v4l2_subdev_fops;
+
+	CDBG("probe success\n");
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, msm_ir_led_dt_match);
+
+static struct platform_driver msm_ir_led_platform_driver = {
+	.probe = msm_ir_led_platform_probe,
+	.driver = {
+		.name = "qcom,ir-led",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ir_led_dt_match,
+	},
+};
+
+static int __init msm_ir_led_init_module(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_ir_led_platform_driver);
+	if (!rc)
+		return rc;
+
+	pr_err("ir-led driver register failed (%d)\n", rc);
+
+	return rc;
+}
+
+static void __exit msm_ir_led_exit_module(void)
+{
+	platform_driver_unregister(&msm_ir_led_platform_driver);
+}
+
+static struct msm_ir_led_table msm_default_ir_led_table = {
+	.ir_led_driver_type = IR_LED_DRIVER_DEFAULT,
+	.func_tbl = {
+		.camera_ir_led_init = msm_ir_led_init,
+		.camera_ir_led_release = msm_ir_led_release,
+		.camera_ir_led_off = msm_ir_led_off,
+		.camera_ir_led_on = msm_ir_led_on,
+	},
+};
+
+module_init(msm_ir_led_init_module);
+module_exit(msm_ir_led_exit_module);
+MODULE_DESCRIPTION("MSM IR LED");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.h b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.h
new file mode 100644
index 0000000..8330c97
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ir_led/msm_ir_led.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MSM_IR_LED_H
+#define MSM_IR_LED_H
+
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msm_cam_sensor.h>
+#include <soc/qcom/camera2.h>
+#include "msm_sd.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+enum msm_camera_ir_led_state_t {
+	MSM_CAMERA_IR_LED_INIT,
+	MSM_CAMERA_IR_LED_RELEASE,
+};
+
+enum msm_ir_led_driver_type {
+	IR_LED_DRIVER_GPIO,
+	IR_LED_DRIVER_DEFAULT,
+};
+
+struct msm_ir_led_ctrl_t;
+
+struct msm_ir_led_func_t {
+	int32_t (*camera_ir_led_init)(struct msm_ir_led_ctrl_t *,
+		struct msm_ir_led_cfg_data_t *);
+	int32_t (*camera_ir_led_release)(struct msm_ir_led_ctrl_t *);
+	int32_t (*camera_ir_led_off)(struct msm_ir_led_ctrl_t *,
+		struct msm_ir_led_cfg_data_t *);
+	int32_t (*camera_ir_led_on)(struct msm_ir_led_ctrl_t *,
+		struct msm_ir_led_cfg_data_t *);
+};
+
+struct msm_ir_led_table {
+	enum msm_ir_led_driver_type ir_led_driver_type;
+	struct msm_ir_led_func_t func_tbl;
+};
+
+struct msm_ir_led_ctrl_t {
+	struct msm_sd_subdev msm_sd;
+	struct platform_device *pdev;
+	struct pwm_device       *pwm_dev;
+	struct msm_ir_led_func_t *func_tbl;
+	struct msm_camera_power_ctrl_t power_info;
+
+	enum msm_camera_device_type_t ir_led_device_type;
+	struct mutex *ir_led_mutex;
+
+	/* ir_led driver type */
+	enum msm_ir_led_driver_type ir_led_driver_type;
+
+	/* ir_led state */
+	enum msm_camera_ir_led_state_t ir_led_state;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile b/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile
new file mode 100644
index 0000000..e981fc2
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_MSMB_CAMERA) += msm_laser_led.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c
new file mode 100644
index 0000000..ee695d8
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.c
@@ -0,0 +1,572 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include "msm_laser_led.h"
+#include "msm_camera_dt_util.h"
+#include "msm_sd.h"
+#include "msm_cci.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+DEFINE_MSM_MUTEX(msm_laser_led_mutex);
+
+static struct v4l2_file_operations msm_laser_led_v4l2_subdev_fops;
+
+static const struct of_device_id msm_laser_led_dt_match[] = {
+	{.compatible = "qcom,laser-led", .data = NULL},
+	{}
+};
+
+static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+
+static int32_t msm_laser_led_get_subdev_id(
+	struct msm_laser_led_ctrl_t *laser_led_ctrl, void __user *arg)
+{
+	int32_t __user *subdev_id = (int32_t __user *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("subdevice ID is not valid\n");
+		return -EINVAL;
+	}
+
+	if (laser_led_ctrl->laser_led_device_type !=
+		MSM_CAMERA_PLATFORM_DEVICE) {
+		pr_err("device type is not matching\n");
+		return -EINVAL;
+	}
+
+	if (copy_to_user(arg, &laser_led_ctrl->pdev->id,
+		sizeof(int32_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	CDBG("Exit: subdev_id %d\n", laser_led_ctrl->pdev->id);
+	return 0;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
+};
+#ifdef CONFIG_COMPAT
+static int32_t msm_laser_led_init(
+	struct msm_laser_led_ctrl_t *laser_led_ctrl,
+	struct msm_laser_led_cfg_data_t32 __user *laser_led_data)
+#else
+static int32_t msm_laser_led_init(
+	struct msm_laser_led_ctrl_t *laser_led_ctrl,
+	struct msm_laser_led_cfg_data_t __user *laser_led_data)
+#endif
+{
+	int32_t rc = -EFAULT;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter\n");
+
+	if (laser_led_ctrl->laser_led_state == MSM_CAMERA_LASER_LED_INIT) {
+		pr_err("Invalid laser_led state = %d\n",
+				laser_led_ctrl->laser_led_state);
+		return 0;
+	}
+
+	rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&laser_led_ctrl->i2c_client, MSM_CCI_INIT);
+	if (rc < 0)
+		pr_err("cci_init failed\n");
+
+	cci_client = laser_led_ctrl->i2c_client.cci_client;
+
+	if (copy_from_user(&(cci_client->sid),
+		&(laser_led_data->i2c_addr),
+		sizeof(uint16_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	cci_client->sid = cci_client->sid >> 1;
+	cci_client->retries = 3;
+	cci_client->id_map = 0;
+
+	if (copy_from_user(&(cci_client->i2c_freq_mode),
+		&(laser_led_data->i2c_freq_mode),
+		sizeof(enum i2c_freq_mode_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_INIT;
+
+	CDBG("Exit\n");
+	return 0;
+}
+
+static int msm_laser_led_close(struct v4l2_subdev *sd,
+			struct v4l2_subdev_fh *fh) {
+	int rc = 0;
+	struct msm_laser_led_ctrl_t *l_ctrl =  v4l2_get_subdevdata(sd);
+
+	CDBG("Enter\n");
+	if (!l_ctrl) {
+		pr_err("failed: subdev data is null\n");
+		return -EINVAL;
+	}
+	mutex_lock(l_ctrl->laser_led_mutex);
+	if (l_ctrl->laser_led_device_type == MSM_CAMERA_PLATFORM_DEVICE &&
+		l_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_RELEASE) {
+		rc = l_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&l_ctrl->i2c_client, MSM_CCI_RELEASE);
+		if (rc < 0)
+			pr_err("cci_init failed: %d\n", rc);
+	}
+	l_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
+	mutex_unlock(l_ctrl->laser_led_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_laser_led_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	CDBG("Enter\n");
+	switch (cmd) {
+	case VIDIOC_MSM_LASER_LED_CFG32:
+		cmd = VIDIOC_MSM_LASER_LED_CFG;
+	default:
+		rc =  msm_laser_led_subdev_ioctl(sd, cmd, arg);
+	}
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static long msm_laser_led_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return msm_laser_led_subdev_do_ioctl(file, cmd, (void *)arg);
+}
+
+static int32_t msm_laser_led_control32(
+	struct msm_laser_led_ctrl_t *laser_led_ctrl,
+	void __user *argp)
+{
+	struct msm_camera_i2c_reg_setting32 conf_array32;
+	struct msm_camera_i2c_reg_setting conf_array;
+	int32_t rc = 0;
+	struct msm_laser_led_cfg_data_t32 laser_led_data;
+	uint32_t *debug_reg;
+	int i;
+	uint16_t local_data;
+
+	if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) {
+		pr_err("%s:%d failed: invalid state %d\n", __func__,
+			__LINE__, laser_led_ctrl->laser_led_state);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&laser_led_data,
+		argp,
+		sizeof(struct msm_laser_led_cfg_data_t32))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&conf_array32,
+		(compat_ptr)(laser_led_data.setting),
+		sizeof(struct msm_camera_i2c_reg_setting32))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	conf_array.addr_type = conf_array32.addr_type;
+	conf_array.data_type = conf_array32.data_type;
+	conf_array.delay = conf_array32.delay;
+	conf_array.size = conf_array32.size;
+
+	if (!conf_array.size ||
+		conf_array.size > I2C_REG_DATA_MAX) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	conf_array.reg_setting = kzalloc(conf_array.size *
+		(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+	if (!conf_array.reg_setting)
+		return -ENOMEM;
+
+	if (copy_from_user(conf_array.reg_setting,
+		(compat_ptr)(conf_array32.reg_setting),
+		conf_array.size *
+		sizeof(struct msm_camera_i2c_reg_array))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		kfree(conf_array.reg_setting);
+		return -EFAULT;
+	}
+
+	debug_reg = kzalloc(laser_led_data.debug_reg_size *
+		(sizeof(uint32_t)), GFP_KERNEL);
+	if (!debug_reg) {
+		kfree(conf_array.reg_setting);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(debug_reg,
+		(void __user *)compat_ptr(laser_led_data.debug_reg),
+		laser_led_data.debug_reg_size *
+		sizeof(uint32_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		kfree(conf_array.reg_setting);
+		kfree(debug_reg);
+		return -EFAULT;
+	}
+
+	laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type;
+
+	rc = laser_led_ctrl->i2c_client.i2c_func_tbl->
+		i2c_write_table(&(laser_led_ctrl->i2c_client),
+		&conf_array);
+
+	for (i = 0; i < laser_led_data.debug_reg_size; i++) {
+		rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read(
+			&(laser_led_ctrl->i2c_client),
+			debug_reg[i],
+			&local_data, conf_array.data_type);
+	}
+
+	kfree(conf_array.reg_setting);
+	kfree(debug_reg);
+
+	return rc;
+}
+#endif
+
+static int32_t msm_laser_led_control(
+	struct msm_laser_led_ctrl_t *laser_led_ctrl,
+	void __user *argp)
+{
+	struct msm_camera_i2c_reg_setting conf_array;
+	struct msm_laser_led_cfg_data_t laser_led_data;
+
+	uint32_t *debug_reg;
+	int i;
+	uint16_t local_data;
+	int32_t rc = 0;
+
+	if (laser_led_ctrl->laser_led_state != MSM_CAMERA_LASER_LED_INIT) {
+		pr_err("%s:%d failed: invalid state %d\n", __func__,
+			__LINE__, laser_led_ctrl->laser_led_state);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&laser_led_data,
+		argp,
+		sizeof(struct msm_laser_led_cfg_data_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&conf_array,
+		(laser_led_data.setting),
+		sizeof(struct msm_camera_i2c_reg_setting))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	if (!conf_array.size ||
+		conf_array.size > I2C_REG_DATA_MAX) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	conf_array.reg_setting = kzalloc(conf_array.size *
+		(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+	if (!conf_array.reg_setting)
+		return -ENOMEM;
+
+	if (copy_from_user(conf_array.reg_setting, (void __user *)(
+		conf_array.reg_setting),
+		conf_array.size *
+		sizeof(struct msm_camera_i2c_reg_array))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		kfree(conf_array.reg_setting);
+		return -EFAULT;
+	}
+
+	debug_reg = kzalloc(laser_led_data.debug_reg_size *
+		(sizeof(uint32_t)), GFP_KERNEL);
+	if (!debug_reg) {
+		kfree(conf_array.reg_setting);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(debug_reg,
+		(laser_led_data.debug_reg),
+		laser_led_data.debug_reg_size *
+		sizeof(uint32_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		kfree(debug_reg);
+		kfree(conf_array.reg_setting);
+		return -EFAULT;
+	}
+
+	laser_led_ctrl->i2c_client.addr_type = conf_array.addr_type;
+
+	rc = laser_led_ctrl->i2c_client.i2c_func_tbl->
+		i2c_write_table(&(laser_led_ctrl->i2c_client),
+		&conf_array);
+
+	for (i = 0; i < laser_led_data.debug_reg_size; i++) {
+		rc = laser_led_ctrl->i2c_client.i2c_func_tbl->i2c_read(
+			&(laser_led_ctrl->i2c_client),
+			debug_reg[i],
+			&local_data, conf_array.data_type);
+	}
+
+	kfree(conf_array.reg_setting);
+	kfree(debug_reg);
+
+	return rc;
+}
+
+static int32_t msm_laser_led_config(struct msm_laser_led_ctrl_t *laser_led_ctrl,
+	void __user *argp)
+{
+	int32_t rc = -EINVAL;
+	enum msm_laser_led_cfg_type_t cfg_type;
+
+#ifdef CONFIG_COMPAT
+	struct msm_laser_led_cfg_data_t32 __user *laser_led_data =
+		(struct msm_laser_led_cfg_data_t32 __user *) argp;
+#else
+	struct msm_laser_led_cfg_data_t __user *laser_led_data =
+		(struct msm_laser_led_cfg_data_t __user *) argp;
+#endif
+
+	mutex_lock(laser_led_ctrl->laser_led_mutex);
+
+	if (copy_from_user(&(cfg_type),
+		&(laser_led_data->cfg_type),
+		sizeof(enum msm_laser_led_cfg_type_t))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		mutex_unlock(laser_led_ctrl->laser_led_mutex);
+		return -EFAULT;
+	}
+
+	CDBG("type %d\n", cfg_type);
+
+	switch (cfg_type) {
+	case CFG_LASER_LED_INIT:
+		rc = msm_laser_led_init(laser_led_ctrl, laser_led_data);
+		break;
+	case CFG_LASER_LED_CONTROL:
+#ifdef CONFIG_COMPAT
+		if (is_compat_task())
+			rc = msm_laser_led_control32(laser_led_ctrl, argp);
+		else
+#endif
+			rc = msm_laser_led_control(laser_led_ctrl, argp);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	mutex_unlock(laser_led_ctrl->laser_led_mutex);
+
+	CDBG("Exit: type %d\n", cfg_type);
+
+	return rc;
+}
+
+static long msm_laser_led_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_laser_led_ctrl_t *lctrl = NULL;
+	void __user *argp = (void __user *)arg;
+
+	CDBG("Enter\n");
+
+	if (!sd) {
+		pr_err(" v4l2 ir led subdevice is NULL\n");
+		return -EINVAL;
+	}
+	lctrl = v4l2_get_subdevdata(sd);
+	if (!lctrl) {
+		pr_err("lctrl NULL\n");
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_laser_led_get_subdev_id(lctrl, argp);
+	case VIDIOC_MSM_LASER_LED_CFG:
+		return msm_laser_led_config(lctrl, argp);
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_SHUTDOWN:
+		if (!lctrl->i2c_client.i2c_func_tbl) {
+			pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n");
+			return -EINVAL;
+		}
+		return msm_laser_led_close(sd, NULL);
+
+	default:
+		pr_err("invalid cmd %d\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+	CDBG("Exit\n");
+}
+
+static struct v4l2_subdev_core_ops msm_laser_led_subdev_core_ops = {
+	.ioctl = msm_laser_led_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_laser_led_subdev_ops = {
+	.core = &msm_laser_led_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_laser_led_internal_ops = {
+	.close = msm_laser_led_close,
+};
+
+static int32_t msm_laser_led_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_laser_led_ctrl_t *laser_led_ctrl = NULL;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter\n");
+	if (!pdev->dev.of_node) {
+		pr_err("IR LED device node is not present in device tree\n");
+		return -EINVAL;
+	}
+
+	laser_led_ctrl = devm_kzalloc(&pdev->dev,
+		sizeof(struct msm_laser_led_ctrl_t), GFP_KERNEL);
+	if (!laser_led_ctrl)
+		return -ENOMEM;
+
+	laser_led_ctrl->pdev = pdev;
+
+	rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+		&pdev->id);
+	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
+	if (rc < 0) {
+		kfree(laser_led_ctrl);
+		pr_err("reading cell index failed: rc %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master",
+		&laser_led_ctrl->cci_master);
+	CDBG("qcom,cci-master %d, rc %d\n", laser_led_ctrl->cci_master, rc);
+	if (rc < 0 || laser_led_ctrl->cci_master >= MASTER_MAX) {
+		kfree(laser_led_ctrl);
+		pr_err("invalid cci master info: rc %d\n", rc);
+		return rc;
+	}
+
+	laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
+	laser_led_ctrl->power_info.dev = &laser_led_ctrl->pdev->dev;
+	laser_led_ctrl->laser_led_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	laser_led_ctrl->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+	laser_led_ctrl->laser_led_mutex = &msm_laser_led_mutex;
+
+	laser_led_ctrl->i2c_client.cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!laser_led_ctrl->i2c_client.cci_client)
+		return -ENOMEM;
+
+	cci_client = laser_led_ctrl->i2c_client.cci_client;
+	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = laser_led_ctrl->cci_master;
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&laser_led_ctrl->msm_sd.sd, &msm_laser_led_subdev_ops);
+	v4l2_set_subdevdata(&laser_led_ctrl->msm_sd.sd, laser_led_ctrl);
+
+	laser_led_ctrl->msm_sd.sd.internal_ops = &msm_laser_led_internal_ops;
+	laser_led_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(laser_led_ctrl->msm_sd.sd.name,
+		ARRAY_SIZE(laser_led_ctrl->msm_sd.sd.name),
+		"msm_camera_laser_led");
+	media_entity_pads_init(&laser_led_ctrl->msm_sd.sd.entity, 0, NULL);
+	laser_led_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_LASER_LED;
+	laser_led_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
+	msm_sd_register(&laser_led_ctrl->msm_sd);
+
+	laser_led_ctrl->laser_led_state = MSM_CAMERA_LASER_LED_RELEASE;
+
+	CDBG("laser_led sd name = %s\n",
+		laser_led_ctrl->msm_sd.sd.entity.name);
+	msm_laser_led_v4l2_subdev_fops = v4l2_subdev_fops;
+#ifdef CONFIG_COMPAT
+	msm_laser_led_v4l2_subdev_fops.compat_ioctl32 =
+		msm_laser_led_subdev_fops_ioctl;
+#endif
+	laser_led_ctrl->msm_sd.sd.devnode->fops =
+		&msm_laser_led_v4l2_subdev_fops;
+
+	CDBG("probe success\n");
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, msm_laser_led_dt_match);
+
+static struct platform_driver msm_laser_led_platform_driver = {
+	.probe = msm_laser_led_platform_probe,
+	.driver = {
+		.name = "qcom,laser-led",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_laser_led_dt_match,
+	},
+};
+
+static int __init msm_laser_led_init_module(void)
+{
+	int32_t rc;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_laser_led_platform_driver);
+	if (!rc) {
+		CDBG("Exit\n");
+		return rc;
+	}
+	pr_err("laser-led driver register failed: %d\n", rc);
+
+	return rc;
+}
+
+static void __exit msm_laser_led_exit_module(void)
+{
+	platform_driver_unregister(&msm_laser_led_platform_driver);
+}
+
+module_init(msm_laser_led_init_module);
+module_exit(msm_laser_led_exit_module);
+MODULE_DESCRIPTION("MSM IR LED");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h
new file mode 100644
index 0000000..7874aa3
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/laser_led/msm_laser_led.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MSM_LASER_LED_H
+#define MSM_LASER_LED_H
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <soc/qcom/camera2.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/msm_cam_sensor.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_sd.h"
+
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+enum msm_camera_laser_led_state_t {
+	MSM_CAMERA_LASER_LED_INIT,
+	MSM_CAMERA_LASER_LED_RELEASE,
+};
+
+struct msm_laser_led_ctrl_t;
+
+struct msm_laser_led_ctrl_t {
+	struct msm_sd_subdev msm_sd;
+	struct platform_device *pdev;
+	struct msm_laser_led_func_t *func_tbl;
+	struct msm_camera_power_ctrl_t power_info;
+	struct i2c_driver *i2c_driver;
+	struct platform_driver *pdriver;
+	struct msm_camera_i2c_client i2c_client;
+	enum msm_camera_device_type_t laser_led_device_type;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *laser_led_v4l2_subdev_ops;
+	struct mutex *laser_led_mutex;
+	enum msm_camera_laser_led_state_t laser_led_state;
+	enum cci_i2c_master_t cci_master;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
new file mode 100644
index 0000000..c0c83e5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -0,0 +1,1554 @@
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include "msm_sensor.h"
+#include "msm_sd.h"
+#include "camera.h"
+#include "msm_cci.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_i2c_mux.h"
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <linux/regulator/consumer.h>
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl;
+static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl;
+
+static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl)
+{
+	int idx;
+	struct msm_sensor_power_setting *power_setting;
+
+	for (idx = 0; idx < ctrl->power_setting_size; idx++) {
+		power_setting = &ctrl->power_setting[idx];
+		if (power_setting->seq_type == SENSOR_CLK &&
+			power_setting->seq_val ==  SENSOR_CAM_MCLK) {
+			if (power_setting->config_val == 24000000) {
+				power_setting->config_val = 23880000;
+				CDBG("%s MCLK request adjusted to 23.88MHz\n"
+							, __func__);
+			}
+			break;
+		}
+	}
+
+}
+
+static void msm_sensor_misc_regulator(
+	struct msm_sensor_ctrl_t *sctrl, uint32_t enable)
+{
+	int32_t rc = 0;
+
+	if (enable) {
+		sctrl->misc_regulator = (void *)rpm_regulator_get(
+			&sctrl->pdev->dev, sctrl->sensordata->misc_regulator);
+		if (sctrl->misc_regulator) {
+			rc = rpm_regulator_set_mode(sctrl->misc_regulator,
+				RPM_REGULATOR_MODE_HPM);
+			if (rc < 0) {
+				pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+					__func__,
+					sctrl->sensordata->misc_regulator, rc);
+				rpm_regulator_put(sctrl->misc_regulator);
+			}
+		} else {
+			pr_err("%s: Failed to vote for rpm regulator on %s: %d\n",
+				__func__,
+				sctrl->sensordata->misc_regulator, rc);
+		}
+	} else {
+		if (sctrl->misc_regulator) {
+			rc = rpm_regulator_set_mode(
+				(struct rpm_regulator *)sctrl->misc_regulator,
+				RPM_REGULATOR_MODE_AUTO);
+			if (rc < 0)
+				pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+					__func__,
+					sctrl->sensordata->misc_regulator, rc);
+			rpm_regulator_put(sctrl->misc_regulator);
+		}
+	}
+}
+
+int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client)
+		return 0;
+	kfree(s_ctrl->sensordata->slave_info);
+	kfree(s_ctrl->sensordata->cam_slave_info);
+	kfree(s_ctrl->sensordata->actuator_info);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf);
+	kfree(s_ctrl->sensordata->power_info.cam_vreg);
+	kfree(s_ctrl->sensordata->power_info.power_setting);
+	kfree(s_ctrl->sensordata->power_info.power_down_setting);
+	kfree(s_ctrl->sensordata->csi_lane_params);
+	kfree(s_ctrl->sensordata->sensor_info);
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_I2C_DEVICE) {
+		msm_camera_i2c_dev_put_clk_info(
+			&s_ctrl->sensor_i2c_client->client->dev,
+			&s_ctrl->sensordata->power_info.clk_info,
+			&s_ctrl->sensordata->power_info.clk_ptr,
+			s_ctrl->sensordata->power_info.clk_info_size);
+	} else {
+		msm_camera_put_clk_info(s_ctrl->pdev,
+			&s_ctrl->sensordata->power_info.clk_info,
+			&s_ctrl->sensordata->power_info.clk_ptr,
+			s_ctrl->sensordata->power_info.clk_info_size);
+	}
+
+	kfree(s_ctrl->sensordata);
+	return 0;
+}
+
+int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	struct msm_camera_power_ctrl_t *power_info;
+	enum msm_camera_device_type_t sensor_device_type;
+	struct msm_camera_i2c_client *sensor_i2c_client;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: s_ctrl %pK\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	if (s_ctrl->is_csid_tg_mode)
+		return 0;
+
+	power_info = &s_ctrl->sensordata->power_info;
+	sensor_device_type = s_ctrl->sensor_device_type;
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+
+	if (!power_info || !sensor_i2c_client) {
+		pr_err("%s:%d failed: power_info %pK sensor_i2c_client %pK\n",
+			__func__, __LINE__, power_info, sensor_i2c_client);
+		return -EINVAL;
+	}
+
+	/* Power down secure session if it exist*/
+	if (s_ctrl->is_secure)
+		msm_camera_tz_i2c_power_down(sensor_i2c_client);
+
+	return msm_camera_power_down(power_info, sensor_device_type,
+		sensor_i2c_client);
+}
+
+int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc;
+	struct msm_camera_power_ctrl_t *power_info;
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	struct msm_camera_slave_info *slave_info;
+	const char *sensor_name;
+	uint32_t retry = 0;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: %pK\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	if (s_ctrl->is_csid_tg_mode)
+		return 0;
+
+	power_info = &s_ctrl->sensordata->power_info;
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+	slave_info = s_ctrl->sensordata->slave_info;
+	sensor_name = s_ctrl->sensordata->sensor_name;
+
+	if (!power_info || !sensor_i2c_client || !slave_info ||
+		!sensor_name) {
+		pr_err("%s:%d failed: %pK %pK %pK %pK\n",
+			__func__, __LINE__, power_info,
+			sensor_i2c_client, slave_info, sensor_name);
+		return -EINVAL;
+	}
+
+	if (s_ctrl->set_mclk_23880000)
+		msm_sensor_adjust_mclk(power_info);
+
+	CDBG("Sensor %d tagged as %s\n", s_ctrl->id,
+		(s_ctrl->is_secure)?"SECURE":"NON-SECURE");
+
+	for (retry = 0; retry < 3; retry++) {
+		if (s_ctrl->is_secure) {
+			rc = msm_camera_tz_i2c_power_up(sensor_i2c_client);
+			if (rc < 0) {
+#ifdef CONFIG_MSM_SEC_CCI_DEBUG
+				CDBG("Secure Sensor %d use cci\n", s_ctrl->id);
+				/* session is not secure */
+				s_ctrl->sensor_i2c_client->i2c_func_tbl =
+					&msm_sensor_cci_func_tbl;
+#else  /* CONFIG_MSM_SEC_CCI_DEBUG */
+				return rc;
+#endif /* CONFIG_MSM_SEC_CCI_DEBUG */
+			} else {
+				/* session is secure */
+				s_ctrl->sensor_i2c_client->i2c_func_tbl =
+					&msm_sensor_secure_func_tbl;
+			}
+		}
+		rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type,
+			sensor_i2c_client);
+		if (rc < 0)
+			return rc;
+		rc = msm_sensor_check_id(s_ctrl);
+		if (rc < 0) {
+			msm_camera_power_down(power_info,
+				s_ctrl->sensor_device_type, sensor_i2c_client);
+			msleep(20);
+			continue;
+		} else {
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static uint16_t msm_sensor_id_by_mask(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t chipid)
+{
+	uint16_t sensor_id = chipid;
+	int16_t sensor_id_mask = s_ctrl->sensordata->slave_info->sensor_id_mask;
+
+	if (!sensor_id_mask)
+		sensor_id_mask = ~sensor_id_mask;
+
+	sensor_id &= sensor_id_mask;
+	sensor_id_mask &= -sensor_id_mask;
+	sensor_id_mask -= 1;
+	while (sensor_id_mask) {
+		sensor_id_mask >>= 1;
+		sensor_id >>= 1;
+	}
+	return sensor_id;
+}
+
+int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0;
+	uint16_t chipid = 0;
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	struct msm_camera_slave_info *slave_info;
+	const char *sensor_name;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: %pK\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+	slave_info = s_ctrl->sensordata->slave_info;
+	sensor_name = s_ctrl->sensordata->sensor_name;
+
+	if (!sensor_i2c_client || !slave_info || !sensor_name) {
+		pr_err("%s:%d failed: %pK %pK %pK\n",
+			__func__, __LINE__, sensor_i2c_client, slave_info,
+			sensor_name);
+		return -EINVAL;
+	}
+
+	rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
+		sensor_i2c_client, slave_info->sensor_id_reg_addr,
+		&chipid, MSM_CAMERA_I2C_WORD_DATA);
+	if (rc < 0) {
+		pr_err("%s: %s: read id failed\n", __func__, sensor_name);
+		return rc;
+	}
+
+	pr_debug("%s: read id: 0x%x expected id 0x%x:\n",
+			__func__, chipid, slave_info->sensor_id);
+	if (msm_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) {
+		pr_err("%s chip id %x does not match %x\n",
+				__func__, chipid, slave_info->sensor_id);
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
+{
+	return container_of(container_of(sd, struct msm_sd_subdev, sd),
+		struct msm_sensor_ctrl_t, msm_sd);
+}
+
+static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
+		kfree(s_ctrl->stop_setting.reg_setting);
+		s_ctrl->stop_setting.reg_setting = NULL;
+
+		if (s_ctrl->func_tbl->sensor_power_down) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 0);
+
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+			CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			pr_err("s_ctrl->func_tbl NULL\n");
+		}
+	}
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+}
+
+static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl,
+			void *argp)
+{
+	/* TO-DO: Need to set AF status register address and expected value
+	 * We need to check the AF status in the sensor register and
+	 * set the status in the *status variable accordingly
+	 */
+	return 0;
+}
+
+static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	void *argp = (void *)arg;
+
+	if (!s_ctrl) {
+		pr_err("%s s_ctrl NULL\n", __func__);
+		return -EBADF;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_CFG:
+#ifdef CONFIG_COMPAT
+		if (is_compat_task())
+			rc = s_ctrl->func_tbl->sensor_config32(s_ctrl, argp);
+		else
+#endif
+			rc = s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+		return rc;
+	case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
+		return msm_sensor_get_af_status(s_ctrl, argp);
+	case VIDIOC_MSM_SENSOR_RELEASE:
+	case MSM_SD_SHUTDOWN:
+		msm_sensor_stop_stream(s_ctrl);
+		return 0;
+	case MSM_SD_NOTIFY_FREEZE:
+		return 0;
+	case MSM_SD_UNNOTIFY_FREEZE:
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_sensor_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_CFG32:
+		cmd = VIDIOC_MSM_SENSOR_CFG;
+	default:
+		return msm_sensor_subdev_ioctl(sd, cmd, arg);
+	}
+}
+
+long msm_sensor_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_sensor_subdev_do_ioctl);
+}
+
+static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl,
+	void *argp)
+{
+	struct sensorb_cfg_data32 *cdata = (struct sensorb_cfg_data32 *)argp;
+	int32_t rc = 0;
+	int32_t i = 0;
+
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+		s_ctrl->sensordata->sensor_name, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CFG_GET_SENSOR_INFO:
+		memcpy(cdata->cfg.sensor_info.sensor_name,
+			s_ctrl->sensordata->sensor_name,
+			sizeof(cdata->cfg.sensor_info.sensor_name));
+		cdata->cfg.sensor_info.session_id =
+			s_ctrl->sensordata->sensor_info->session_id;
+		for (i = 0; i < SUB_MODULE_MAX; i++) {
+			cdata->cfg.sensor_info.subdev_id[i] =
+				s_ctrl->sensordata->sensor_info->subdev_id[i];
+			cdata->cfg.sensor_info.subdev_intf[i] =
+				s_ctrl->sensordata->sensor_info->subdev_intf[i];
+		}
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+		cdata->cfg.sensor_info.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_info.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.sensor_name);
+		CDBG("%s:%d session id %d\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.session_id);
+		for (i = 0; i < SUB_MODULE_MAX; i++) {
+			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
+				cdata->cfg.sensor_info.subdev_id[i]);
+			CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__,
+				i, cdata->cfg.sensor_info.subdev_intf[i]);
+		}
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
+
+		break;
+	case CFG_GET_SENSOR_INIT_PARAMS:
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
+			__LINE__,
+			cdata->cfg.sensor_init_params.modes_supported,
+			cdata->cfg.sensor_init_params.position,
+			cdata->cfg.sensor_init_params.sensor_mount_angle);
+		break;
+	case CFG_WRITE_I2C_ARRAY:
+	case CFG_WRITE_I2C_ARRAY_SYNC:
+	case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK:
+	case CFG_WRITE_I2C_ARRAY_ASYNC: {
+		struct msm_camera_i2c_reg_setting32 conf_array32;
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(&conf_array32,
+			(void __user *)compat_ptr(cdata->cfg.setting),
+			sizeof(struct msm_camera_i2c_reg_setting32))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.addr_type = conf_array32.addr_type;
+		conf_array.data_type = conf_array32.data_type;
+		conf_array.delay = conf_array32.delay;
+		conf_array.size = conf_array32.size;
+
+		if (!conf_array.size ||
+			conf_array.size > I2C_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+			(void __user *)
+			compat_ptr(conf_array32.reg_setting),
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+
+		if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table(s_ctrl->sensor_i2c_client,
+				&conf_array);
+		else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_ASYNC)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_async(s_ctrl->sensor_i2c_client,
+				&conf_array);
+		else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_SYNC_BLOCK)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_sync_block(
+				s_ctrl->sensor_i2c_client,
+				&conf_array);
+		else
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_sync(s_ctrl->sensor_i2c_client,
+				&conf_array);
+
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_SLAVE_READ_I2C: {
+		struct msm_camera_i2c_read_config read_config;
+		struct msm_camera_i2c_read_config *read_config_ptr = NULL;
+		uint16_t local_data = 0;
+		uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+		uint16_t orig_addr_type = 0, read_addr_type = 0;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		read_config_ptr =
+			(__force struct msm_camera_i2c_read_config *)
+			compat_ptr(cdata->cfg.setting);
+
+		if (copy_from_user(&read_config,
+			(void __user *) read_config_ptr,
+			sizeof(struct msm_camera_i2c_read_config))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		read_slave_addr = read_config.slave_addr;
+		read_addr_type = read_config.addr_type;
+
+		CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+		CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+			__func__, read_config.slave_addr,
+			read_config.reg_addr, read_config.data_type);
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				read_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				read_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+				__func__, orig_slave_addr,
+				read_slave_addr >> 1);
+
+		orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
+		s_ctrl->sensor_i2c_client->addr_type = read_addr_type;
+
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+				s_ctrl->sensor_i2c_client,
+				read_config.reg_addr,
+				&local_data, read_config.data_type);
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				orig_slave_addr;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			s_ctrl->sensor_i2c_client->client->addr =
+				orig_slave_addr;
+		}
+		s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
+
+		pr_debug("slave_read %x %x %x\n", read_slave_addr,
+			read_config.reg_addr, local_data);
+
+		if (rc < 0) {
+			pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+			break;
+		}
+		if (copy_to_user((void __user *)(&read_config_ptr->data),
+				&local_data, sizeof(local_data))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case CFG_SLAVE_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_array_write_config32 write_config32;
+		struct msm_camera_i2c_array_write_config write_config;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+		uint16_t orig_slave_addr = 0, write_slave_addr = 0;
+		uint16_t orig_addr_type = 0, write_addr_type = 0;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (copy_from_user(&write_config32,
+				(void __user *)compat_ptr(cdata->cfg.setting),
+				sizeof(
+				struct msm_camera_i2c_array_write_config32))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		write_config.slave_addr = write_config32.slave_addr;
+		write_config.conf_array.addr_type =
+			write_config32.conf_array.addr_type;
+		write_config.conf_array.data_type =
+			write_config32.conf_array.data_type;
+		write_config.conf_array.delay =
+			write_config32.conf_array.delay;
+		write_config.conf_array.size =
+			write_config32.conf_array.size;
+
+		pr_debug("%s:CFG_SLAVE_WRITE_I2C_ARRAY:\n", __func__);
+		pr_debug("%s:slave_addr=0x%x, array_size=%d addr_type=%d data_type=%d\n",
+			__func__,
+			write_config.slave_addr,
+			write_config.conf_array.size,
+			write_config.conf_array.addr_type,
+			write_config.conf_array.data_type);
+
+		if (!write_config.conf_array.size ||
+			write_config.conf_array.size > I2C_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(write_config.conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+				(void __user *)
+				compat_ptr(
+				write_config32.conf_array.reg_setting),
+				write_config.conf_array.size *
+				sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		write_config.conf_array.reg_setting = reg_setting;
+		write_slave_addr = write_config.slave_addr;
+		write_addr_type = write_config.conf_array.addr_type;
+
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				write_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				write_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.",
+				__func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		pr_debug("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x\n",
+				__func__, orig_slave_addr,
+				write_slave_addr >> 1);
+		orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
+		s_ctrl->sensor_i2c_client->addr_type = write_addr_type;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+
+		s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				orig_slave_addr;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			s_ctrl->sensor_i2c_client->client->addr =
+				orig_slave_addr;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.\n",
+				__func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_WRITE_I2C_SEQ_ARRAY: {
+		struct msm_camera_i2c_seq_reg_setting32 conf_array32;
+		struct msm_camera_i2c_seq_reg_setting conf_array;
+		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(&conf_array32,
+			(void __user *)compat_ptr(cdata->cfg.setting),
+			sizeof(struct msm_camera_i2c_seq_reg_setting32))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.addr_type = conf_array32.addr_type;
+		conf_array.delay = conf_array32.delay;
+		conf_array.size = conf_array32.size;
+
+		if (!conf_array.size ||
+			conf_array.size > I2C_SEQ_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_seq_reg_array)),
+			GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+			(void __user *)
+			compat_ptr(conf_array32.reg_setting),
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_seq_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write_seq_table(s_ctrl->sensor_i2c_client,
+			&conf_array);
+		kfree(reg_setting);
+		break;
+	}
+
+	case CFG_POWER_UP:
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_up) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 1);
+
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
+			CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			rc = -EFAULT;
+		}
+		break;
+	case CFG_POWER_DOWN:
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		kfree(s_ctrl->stop_setting.reg_setting);
+		s_ctrl->stop_setting.reg_setting = NULL;
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_down) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 0);
+
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+			CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			rc = -EFAULT;
+		}
+		break;
+	case CFG_SET_STOP_STREAM_SETTING: {
+		struct msm_camera_i2c_reg_setting32 stop_setting32;
+		struct msm_camera_i2c_reg_setting *stop_setting =
+			&s_ctrl->stop_setting;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (copy_from_user(&stop_setting32,
+				(void __user *)compat_ptr((cdata->cfg.setting)),
+			sizeof(struct msm_camera_i2c_reg_setting32))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		stop_setting->addr_type = stop_setting32.addr_type;
+		stop_setting->data_type = stop_setting32.data_type;
+		stop_setting->delay = stop_setting32.delay;
+		stop_setting->size = stop_setting32.size;
+
+		if (!stop_setting->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		stop_setting->reg_setting = kzalloc(stop_setting->size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!stop_setting->reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(stop_setting->reg_setting,
+			(void __user *)
+			compat_ptr(stop_setting32.reg_setting),
+			stop_setting->size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(stop_setting->reg_setting);
+			stop_setting->reg_setting = NULL;
+			stop_setting->size = 0;
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+
+	case CFG_SET_I2C_SYNC_PARAM: {
+		struct msm_camera_cci_ctrl cci_ctrl;
+
+		s_ctrl->sensor_i2c_client->cci_client->cid =
+			cdata->cfg.sensor_i2c_sync_params.cid;
+		s_ctrl->sensor_i2c_client->cci_client->id_map =
+			cdata->cfg.sensor_i2c_sync_params.csid;
+
+		CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n",
+			s_ctrl->sensor_i2c_client->cci_client->cid,
+			cdata->cfg.sensor_i2c_sync_params.line,
+			cdata->cfg.sensor_i2c_sync_params.delay,
+			cdata->cfg.sensor_i2c_sync_params.csid);
+
+		cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID;
+		cci_ctrl.cfg.cci_wait_sync_cfg.line =
+			cdata->cfg.sensor_i2c_sync_params.line;
+		cci_ctrl.cfg.cci_wait_sync_cfg.delay =
+			cdata->cfg.sensor_i2c_sync_params.delay;
+		cci_ctrl.cfg.cci_wait_sync_cfg.cid =
+			cdata->cfg.sensor_i2c_sync_params.cid;
+		cci_ctrl.cfg.cci_wait_sync_cfg.csid =
+			cdata->cfg.sensor_i2c_sync_params.csid;
+		rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client->
+				cci_client->cci_subdev,
+				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+		if (rc < 0) {
+			pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+DONE:
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+	return rc;
+}
+#endif
+
+int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp)
+{
+	struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
+	int32_t rc = 0;
+	int32_t i = 0;
+
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+		s_ctrl->sensordata->sensor_name, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CFG_GET_SENSOR_INFO:
+		memcpy(cdata->cfg.sensor_info.sensor_name,
+			s_ctrl->sensordata->sensor_name,
+			sizeof(cdata->cfg.sensor_info.sensor_name));
+		cdata->cfg.sensor_info.session_id =
+			s_ctrl->sensordata->sensor_info->session_id;
+		for (i = 0; i < SUB_MODULE_MAX; i++) {
+			cdata->cfg.sensor_info.subdev_id[i] =
+				s_ctrl->sensordata->sensor_info->subdev_id[i];
+			cdata->cfg.sensor_info.subdev_intf[i] =
+				s_ctrl->sensordata->sensor_info->subdev_intf[i];
+		}
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+		cdata->cfg.sensor_info.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_info.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.sensor_name);
+		CDBG("%s:%d session id %d\n", __func__, __LINE__,
+			cdata->cfg.sensor_info.session_id);
+		for (i = 0; i < SUB_MODULE_MAX; i++) {
+			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
+				cdata->cfg.sensor_info.subdev_id[i]);
+			CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__,
+				i, cdata->cfg.sensor_info.subdev_intf[i]);
+		}
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
+
+		break;
+	case CFG_GET_SENSOR_INIT_PARAMS:
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
+			__LINE__,
+			cdata->cfg.sensor_init_params.modes_supported,
+			cdata->cfg.sensor_init_params.position,
+			cdata->cfg.sensor_init_params.sensor_mount_angle);
+		break;
+
+	case CFG_WRITE_I2C_ARRAY:
+	case CFG_WRITE_I2C_ARRAY_SYNC:
+	case CFG_WRITE_I2C_ARRAY_SYNC_BLOCK:
+	case CFG_WRITE_I2C_ARRAY_ASYNC: {
+		struct msm_camera_i2c_reg_setting conf_array;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(&conf_array,
+			(void __user *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (!conf_array.size ||
+			conf_array.size > I2C_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+			(void __user *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table(s_ctrl->sensor_i2c_client,
+					&conf_array);
+		else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_ASYNC)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_async(s_ctrl->sensor_i2c_client,
+					&conf_array);
+		else if (cdata->cfgtype == CFG_WRITE_I2C_ARRAY_SYNC_BLOCK)
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_sync_block(
+					s_ctrl->sensor_i2c_client,
+					&conf_array);
+		else
+			rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+				i2c_write_table_sync(s_ctrl->sensor_i2c_client,
+					&conf_array);
+
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_SLAVE_READ_I2C: {
+		struct msm_camera_i2c_read_config read_config;
+		struct msm_camera_i2c_read_config *read_config_ptr = NULL;
+		uint16_t local_data = 0;
+		uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+		uint16_t orig_addr_type = 0, read_addr_type = 0;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		read_config_ptr =
+			(struct msm_camera_i2c_read_config *)cdata->cfg.setting;
+		if (copy_from_user(&read_config,
+			(void __user *)read_config_ptr,
+			sizeof(struct msm_camera_i2c_read_config))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		read_slave_addr = read_config.slave_addr;
+		read_addr_type = read_config.addr_type;
+		CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+		CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+			__func__, read_config.slave_addr,
+			read_config.reg_addr, read_config.data_type);
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				read_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				read_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+				__func__, orig_slave_addr,
+				read_slave_addr >> 1);
+
+		orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
+		s_ctrl->sensor_i2c_client->addr_type = read_addr_type;
+
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+				s_ctrl->sensor_i2c_client,
+				read_config.reg_addr,
+				&local_data, read_config.data_type);
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				orig_slave_addr;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			s_ctrl->sensor_i2c_client->client->addr =
+				orig_slave_addr;
+		}
+		s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
+
+		if (rc < 0) {
+			pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+			break;
+		}
+		if (copy_to_user((void __user *)(&read_config_ptr->data),
+				&local_data, sizeof(local_data))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case CFG_SLAVE_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_array_write_config write_config;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+		uint16_t orig_slave_addr = 0,  write_slave_addr = 0;
+		uint16_t orig_addr_type = 0, write_addr_type = 0;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (copy_from_user(&write_config,
+			(void __user *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_array_write_config))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
+		CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
+			write_config.slave_addr,
+			write_config.conf_array.size);
+
+		if (!write_config.conf_array.size ||
+			write_config.conf_array.size > I2C_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(write_config.conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+				(void __user *)
+				(write_config.conf_array.reg_setting),
+				write_config.conf_array.size *
+				sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		write_config.conf_array.reg_setting = reg_setting;
+		write_slave_addr = write_config.slave_addr;
+		write_addr_type = write_config.conf_array.addr_type;
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				write_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				write_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+				__func__, orig_slave_addr,
+				write_slave_addr >> 1);
+		orig_addr_type = s_ctrl->sensor_i2c_client->addr_type;
+		s_ctrl->sensor_i2c_client->addr_type = write_addr_type;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+		s_ctrl->sensor_i2c_client->addr_type = orig_addr_type;
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				orig_slave_addr;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			s_ctrl->sensor_i2c_client->client->addr =
+				orig_slave_addr;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		kfree(reg_setting);
+		break;
+	}
+	case CFG_WRITE_I2C_SEQ_ARRAY: {
+		struct msm_camera_i2c_seq_reg_setting conf_array;
+		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(&conf_array,
+			(void __user *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_seq_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (!conf_array.size ||
+			conf_array.size > I2C_SEQ_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_seq_reg_array)),
+			GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+			(void __user *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_seq_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->
+			i2c_write_seq_table(s_ctrl->sensor_i2c_client,
+			&conf_array);
+		kfree(reg_setting);
+		break;
+	}
+
+	case CFG_POWER_UP:
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_up) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 1);
+
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
+			CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			rc = -EFAULT;
+		}
+		break;
+
+	case CFG_POWER_DOWN:
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		kfree(s_ctrl->stop_setting.reg_setting);
+		s_ctrl->stop_setting.reg_setting = NULL;
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_down) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 0);
+
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+			CDBG("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			rc = -EFAULT;
+		}
+		break;
+
+	case CFG_SET_STOP_STREAM_SETTING: {
+		struct msm_camera_i2c_reg_setting *stop_setting =
+			&s_ctrl->stop_setting;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+
+		if (s_ctrl->is_csid_tg_mode)
+			goto DONE;
+
+		if (copy_from_user(stop_setting,
+			(void __user *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		reg_setting = stop_setting->reg_setting;
+
+		if (!stop_setting->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		stop_setting->reg_setting = kzalloc(stop_setting->size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!stop_setting->reg_setting) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(stop_setting->reg_setting,
+			(void __user *)reg_setting,
+			stop_setting->size *
+			sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(stop_setting->reg_setting);
+			stop_setting->reg_setting = NULL;
+			stop_setting->size = 0;
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+
+	case CFG_SET_I2C_SYNC_PARAM: {
+		struct msm_camera_cci_ctrl cci_ctrl;
+
+		s_ctrl->sensor_i2c_client->cci_client->cid =
+			cdata->cfg.sensor_i2c_sync_params.cid;
+		s_ctrl->sensor_i2c_client->cci_client->id_map =
+			cdata->cfg.sensor_i2c_sync_params.csid;
+
+		CDBG("I2C_SYNC_PARAM CID:%d, line:%d delay:%d, cdid:%d\n",
+			s_ctrl->sensor_i2c_client->cci_client->cid,
+			cdata->cfg.sensor_i2c_sync_params.line,
+			cdata->cfg.sensor_i2c_sync_params.delay,
+			cdata->cfg.sensor_i2c_sync_params.csid);
+
+		cci_ctrl.cmd = MSM_CCI_SET_SYNC_CID;
+		cci_ctrl.cfg.cci_wait_sync_cfg.line =
+			cdata->cfg.sensor_i2c_sync_params.line;
+		cci_ctrl.cfg.cci_wait_sync_cfg.delay =
+			cdata->cfg.sensor_i2c_sync_params.delay;
+		cci_ctrl.cfg.cci_wait_sync_cfg.cid =
+			cdata->cfg.sensor_i2c_sync_params.cid;
+		cci_ctrl.cfg.cci_wait_sync_cfg.csid =
+			cdata->cfg.sensor_i2c_sync_params.csid;
+		rc = v4l2_subdev_call(s_ctrl->sensor_i2c_client->
+				cci_client->cci_subdev,
+				core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+		if (rc < 0) {
+			pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+DONE:
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+	return rc;
+}
+
+int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc;
+
+	if (s_ctrl->func_tbl->sensor_match_id)
+		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+	else
+		rc = msm_sensor_match_id(s_ctrl);
+	if (rc < 0)
+		pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static int msm_sensor_power(struct v4l2_subdev *sd, int on)
+{
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+		s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+		s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+	}
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
+	return rc;
+}
+static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+static struct v4l2_subdev_ops msm_sensor_subdev_ops = {
+	.core = &msm_sensor_subdev_core_ops,
+};
+
+static struct msm_sensor_fn_t msm_sensor_func_tbl = {
+	.sensor_config = msm_sensor_config,
+#ifdef CONFIG_COMPAT
+	.sensor_config32 = msm_sensor_config32,
+#endif
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+	.sensor_match_id = msm_sensor_match_id,
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl,
+	.i2c_write_table_async = msm_camera_cci_i2c_write_table_async,
+	.i2c_write_table_sync = msm_camera_cci_i2c_write_table_sync,
+	.i2c_write_table_sync_block = msm_camera_cci_i2c_write_table_sync_block,
+
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_qup_i2c_write_table_w_microdelay,
+	.i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl,
+	.i2c_write_table_async = msm_camera_qup_i2c_write_table,
+	.i2c_write_table_sync = msm_camera_qup_i2c_write_table,
+	.i2c_write_table_sync_block = msm_camera_qup_i2c_write_table,
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl = {
+	.i2c_read = msm_camera_tz_i2c_read,
+	.i2c_read_seq = msm_camera_tz_i2c_read_seq,
+	.i2c_write = msm_camera_tz_i2c_write,
+	.i2c_write_table = msm_camera_tz_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_tz_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_tz_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_tz_i2c_util,
+	.i2c_write_conf_tbl = msm_camera_tz_i2c_write_conf_tbl,
+	.i2c_write_table_async = msm_camera_tz_i2c_write_table_async,
+	.i2c_write_table_sync = msm_camera_tz_i2c_write_table_sync,
+	.i2c_write_table_sync_block = msm_camera_tz_i2c_write_table_sync_block,
+};
+
+int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	struct msm_camera_cci_client *cci_client = NULL;
+	unsigned long mount_pos = 0;
+
+	/* Validate input parameters */
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: invalid params s_ctrl %pK\n", __func__,
+			__LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	if (!s_ctrl->sensor_i2c_client) {
+		pr_err("%s:%d failed: invalid params sensor_i2c_client %pK\n",
+			__func__, __LINE__, s_ctrl->sensor_i2c_client);
+		return -EINVAL;
+	}
+
+	/* Initialize cci_client */
+	s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!s_ctrl->sensor_i2c_client->cci_client)
+		return -ENOMEM;
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = s_ctrl->sensor_i2c_client->cci_client;
+
+		/* Get CCI subdev */
+		cci_client->cci_subdev = msm_cci_get_subdev();
+
+		if (s_ctrl->is_secure)
+			msm_camera_tz_i2c_register_sensor((void *)s_ctrl);
+
+		/* Update CCI / I2C function table */
+		if (!s_ctrl->sensor_i2c_client->i2c_func_tbl)
+			s_ctrl->sensor_i2c_client->i2c_func_tbl =
+				&msm_sensor_cci_func_tbl;
+	} else {
+		if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) {
+			CDBG("%s:%d\n", __func__, __LINE__);
+			s_ctrl->sensor_i2c_client->i2c_func_tbl =
+				&msm_sensor_qup_func_tbl;
+		}
+	}
+
+	/* Update function table driven by ioctl */
+	if (!s_ctrl->func_tbl)
+		s_ctrl->func_tbl = &msm_sensor_func_tbl;
+
+	/* Update v4l2 subdev ops table */
+	if (!s_ctrl->sensor_v4l2_subdev_ops)
+		s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
+
+	/* Update sensor mount angle and position in media entity flag */
+	mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
+	mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info->
+					sensor_mount_angle / 90) << 8);
+	s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
new file mode 100644
index 0000000..753e85a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2011-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_SENSOR_H
+#define MSM_SENSOR_H
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <soc/qcom/camera2.h>
+#include <media/msm_cam_sensor.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_sd.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+enum msm_sensor_sensor_slave_info_type {
+	MSM_SENSOR_SLAVEADDR_DATA,
+	MSM_SENSOR_IDREGADDR_DATA,
+	MSM_SENSOR_SENSOR_ID_DATA,
+	MSM_SENSOR_SENIDMASK_DATA,
+	MSM_SENSOR_NUM_ID_INFO_DATA,
+};
+
+struct msm_sensor_ctrl_t;
+
+enum msm_sensor_state_t {
+	MSM_SENSOR_POWER_DOWN,
+	MSM_SENSOR_POWER_UP,
+};
+
+struct msm_sensor_fn_t {
+	int (*sensor_config)(struct msm_sensor_ctrl_t *, void *);
+#ifdef CONFIG_COMPAT
+	int (*sensor_config32)(struct msm_sensor_ctrl_t *, void *);
+#endif
+	int (*sensor_power_down)(struct msm_sensor_ctrl_t *);
+	int (*sensor_power_up)(struct msm_sensor_ctrl_t *);
+	int (*sensor_match_id)(struct msm_sensor_ctrl_t *);
+};
+
+struct msm_sensor_ctrl_t {
+	struct platform_device *pdev;
+	struct mutex *msm_sensor_mutex;
+
+	enum msm_camera_device_type_t sensor_device_type;
+	struct msm_camera_sensor_board_info *sensordata;
+	struct msm_sensor_power_setting_array power_setting_array;
+	struct msm_sensor_packed_cfg_t *cfg_override;
+	struct msm_sd_subdev msm_sd;
+	enum cci_i2c_master_t cci_i2c_master;
+
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
+	uint8_t sensor_v4l2_subdev_info_size;
+	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
+	struct msm_sensor_fn_t *func_tbl;
+	struct msm_camera_i2c_reg_setting stop_setting;
+	void *misc_regulator;
+	enum msm_sensor_state_t sensor_state;
+	uint8_t is_probe_succeed;
+	uint32_t id;
+	struct device_node *of_node;
+	enum msm_camera_stream_type_t camera_stream_type;
+	uint32_t set_mclk_23880000;
+	uint8_t is_csid_tg_mode;
+	uint32_t is_secure;
+	uint8_t bypass_video_node_creation;
+};
+
+int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp);
+
+int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
+
+int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl);
+
+int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+#ifdef CONFIG_COMPAT
+long msm_sensor_subdev_fops_ioctl(struct file *file,
+	unsigned int cmd,
+	unsigned long arg);
+#endif
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
new file mode 100644
index 0000000..0b0f98a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -0,0 +1,1501 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define SENSOR_DRIVER_I2C "i2c_camera"
+/* Header file declaration */
+#include "msm_sensor.h"
+#include "msm_sd.h"
+#include "camera.h"
+#include "msm_cci.h"
+#include "msm_camera_dt_util.h"
+#include "msm_sensor_driver.h"
+
+/* Logging macro */
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define SENSOR_MAX_MOUNTANGLE (360)
+
+static struct v4l2_file_operations msm_sensor_v4l2_subdev_fops;
+static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev);
+
+/* Static declaration */
+static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS];
+
+static int msm_sensor_platform_remove(struct platform_device *pdev)
+{
+	struct msm_sensor_ctrl_t  *s_ctrl;
+
+	pr_err("%s: sensor FREE\n", __func__);
+
+	s_ctrl = g_sctrl[pdev->id];
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_sensor_free_sensor_data(s_ctrl);
+	kfree(s_ctrl->msm_sensor_mutex);
+	kfree(s_ctrl->sensor_i2c_client);
+	kfree(s_ctrl);
+	g_sctrl[pdev->id] = NULL;
+
+	return 0;
+}
+
+
+static const struct of_device_id msm_sensor_driver_dt_match[] = {
+	{.compatible = "qcom,camera"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match);
+
+static struct platform_driver msm_sensor_platform_driver = {
+	.probe = msm_sensor_driver_platform_probe,
+	.driver = {
+		.name = "qcom,camera",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_sensor_driver_dt_match,
+	},
+	.remove = msm_sensor_platform_remove,
+};
+
+static struct v4l2_subdev_info msm_sensor_driver_subdev_info[] = {
+	{
+		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt = 1,
+		.order = 0,
+	},
+};
+
+static int32_t msm_sensor_driver_create_i2c_v4l_subdev
+			(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint32_t session_id = 0;
+	struct i2c_client *client = s_ctrl->sensor_i2c_client->client;
+
+	CDBG("%s %s I2c probe succeeded\n", __func__, client->name);
+	if (s_ctrl->bypass_video_node_creation == 0) {
+		rc = camera_init_v4l2(&client->dev, &session_id);
+		if (rc < 0) {
+			pr_err("failed: camera_init_i2c_v4l2 rc %d", rc);
+			return rc;
+		}
+	}
+
+	CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
+	snprintf(s_ctrl->msm_sd.sd.name,
+		sizeof(s_ctrl->msm_sd.sd.name), "%s",
+		s_ctrl->sensordata->sensor_name);
+	v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client,
+		s_ctrl->sensor_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client);
+	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&s_ctrl->msm_sd.sd.entity, 0, NULL);
+	s_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR;
+	s_ctrl->msm_sd.sd.entity.name =	s_ctrl->msm_sd.sd.name;
+	s_ctrl->sensordata->sensor_info->session_id = session_id;
+	s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
+	rc = msm_sd_register(&s_ctrl->msm_sd);
+	if (rc < 0) {
+		pr_err("failed: msm_sd_register rc %d", rc);
+		return rc;
+	}
+	msm_sensor_v4l2_subdev_fops = v4l2_subdev_fops;
+#ifdef CONFIG_COMPAT
+	msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
+		msm_sensor_subdev_fops_ioctl;
+#endif
+	s_ctrl->msm_sd.sd.devnode->fops =
+		&msm_sensor_v4l2_subdev_fops;
+	CDBG("%s:%d\n", __func__, __LINE__);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_create_v4l_subdev
+			(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint32_t session_id = 0;
+
+	if (s_ctrl->bypass_video_node_creation == 0) {
+		rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
+		if (rc < 0) {
+			pr_err("failed: camera_init_v4l2 rc %d", rc);
+			return rc;
+		}
+	}
+
+	CDBG("rc %d session_id %d", rc, session_id);
+	s_ctrl->sensordata->sensor_info->session_id = session_id;
+
+	/* Create /dev/v4l-subdevX device */
+	v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops);
+	snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s",
+		s_ctrl->sensordata->sensor_name);
+	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
+	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&s_ctrl->msm_sd.sd.entity, 0, NULL);
+	s_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR;
+	s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
+	s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
+	rc = msm_sd_register(&s_ctrl->msm_sd);
+	if (rc < 0) {
+		pr_err("failed: msm_sd_register rc %d", rc);
+		return rc;
+	}
+	msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
+		msm_sensor_subdev_fops_ioctl;
+#endif
+	s_ctrl->msm_sd.sd.devnode->fops =
+		&msm_sensor_v4l2_subdev_fops;
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_eeprom_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	const char *eeprom_name;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, eeprom_name_len;
+	int32_t *eeprom_subdev_id, i, userspace_probe = 0;
+	int32_t count = 0;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+	const void *p;
+
+	if (!s_ctrl->sensordata->eeprom_name || !of_node)
+		return -EINVAL;
+
+	eeprom_name_len = strlen(s_ctrl->sensordata->eeprom_name);
+	if (eeprom_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	eeprom_subdev_id = &sensor_info->subdev_id[SUB_MODULE_EEPROM];
+	/*
+	 * string for eeprom name is valid, set sudev id to -1
+	 *  and try to found new id
+	 */
+	*eeprom_subdev_id = -1;
+
+	if (eeprom_name_len == 0)
+		return 0;
+
+	p = of_get_property(of_node, "qcom,eeprom-src", &count);
+	if (!p || !count)
+		return 0;
+
+	count /= sizeof(uint32_t);
+	for (i = 0; i < count; i++) {
+		userspace_probe = 0;
+		eeprom_name = NULL;
+		src_node = of_parse_phandle(of_node, "qcom,eeprom-src", i);
+		if (!src_node) {
+			pr_err("eeprom src node NULL\n");
+			continue;
+		}
+		/* In the case of eeprom probe from kernel eeprom name
+		 * should be present, Otherwise it will throw as errors
+		 */
+		rc = of_property_read_string(src_node, "qcom,eeprom-name",
+			&eeprom_name);
+		if (rc < 0) {
+			pr_err("%s:%d Eeprom userspace probe for %s\n",
+				__func__, __LINE__,
+				s_ctrl->sensordata->eeprom_name);
+			of_node_put(src_node);
+			userspace_probe = 1;
+			if (count > 1)
+				return -EINVAL;
+		}
+		if (!userspace_probe &&
+			strcmp(eeprom_name, s_ctrl->sensordata->eeprom_name))
+			continue;
+
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		if (rc < 0) {
+			pr_err("%s qcom,eeprom cell index %d, rc %d\n",
+				__func__, val, rc);
+			of_node_put(src_node);
+			if (userspace_probe)
+				return -EINVAL;
+			continue;
+		}
+
+		*eeprom_subdev_id = val;
+		CDBG("%s:%d Eeprom subdevice id is %d\n",
+			__func__, __LINE__, val);
+		of_node_put(src_node);
+		src_node = NULL;
+		break;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_actuator_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, actuator_name_len;
+	int32_t *actuator_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+
+	if (!s_ctrl->sensordata->actuator_name || !of_node)
+		return -EINVAL;
+
+	actuator_name_len = strlen(s_ctrl->sensordata->actuator_name);
+	if (actuator_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	actuator_subdev_id = &sensor_info->subdev_id[SUB_MODULE_ACTUATOR];
+	/*
+	 * string for actuator name is valid, set sudev id to -1
+	 * and try to found new id
+	 */
+	*actuator_subdev_id = -1;
+
+	if (actuator_name_len == 0)
+		return 0;
+
+	src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		*actuator_subdev_id = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_laser_led_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0;
+	int32_t *laser_led_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+
+	if (!of_node)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	laser_led_subdev_id = &sensor_info->subdev_id[SUB_MODULE_LASER_LED];
+	/* set sudev id to -1 and try to found new id */
+	*laser_led_subdev_id = -1;
+
+
+	src_node = of_parse_phandle(of_node, "qcom,laserled-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,laser led cell index %d, rc %d\n", __func__,
+			val, rc);
+		of_node_put(src_node);
+		src_node = NULL;
+		if (rc < 0) {
+			pr_err("%s cell index not found %d\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		*laser_led_subdev_id = val;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_flash_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, flash_name_len;
+	int32_t *flash_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+
+	if (!of_node || !s_ctrl->sensordata->flash_name)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	flash_subdev_id = &sensor_info->subdev_id[SUB_MODULE_LED_FLASH];
+
+	*flash_subdev_id = -1;
+
+	flash_name_len = strlen(s_ctrl->sensordata->flash_name);
+	if (flash_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	if (flash_name_len == 0)
+		return 0;
+
+	src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,flash cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		*flash_subdev_id = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+	return rc;
+}
+
+static int32_t msm_sensor_fill_ois_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, ois_name_len;
+	int32_t *ois_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+
+	if (!s_ctrl->sensordata->ois_name || !of_node)
+		return -EINVAL;
+
+	ois_name_len = strlen(s_ctrl->sensordata->ois_name);
+	if (ois_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	ois_subdev_id = &sensor_info->subdev_id[SUB_MODULE_OIS];
+	/*
+	 * string for ois name is valid, set sudev id to -1
+	 * and try to found new id
+	 */
+	*ois_subdev_id = -1;
+
+	if (ois_name_len == 0)
+		return 0;
+
+	src_node = of_parse_phandle(of_node, "qcom,ois-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,ois cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		*ois_subdev_id = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_slave_info_init_params(
+	struct msm_camera_sensor_slave_info *slave_info,
+	struct msm_sensor_info_t *sensor_info)
+{
+	struct msm_sensor_init_params *sensor_init_params;
+
+	if (!slave_info ||  !sensor_info)
+		return -EINVAL;
+
+	sensor_init_params = &slave_info->sensor_init_params;
+	if (sensor_init_params->position != INVALID_CAMERA_B)
+		sensor_info->position =
+			sensor_init_params->position;
+
+	if (sensor_init_params->sensor_mount_angle < SENSOR_MAX_MOUNTANGLE) {
+		sensor_info->sensor_mount_angle =
+			sensor_init_params->sensor_mount_angle;
+		sensor_info->is_mount_angle_valid = 1;
+	}
+
+	if (sensor_init_params->modes_supported != CAMERA_MODE_INVALID)
+		sensor_info->modes_supported =
+			sensor_init_params->modes_supported;
+
+	return 0;
+}
+
+
+static int32_t msm_sensor_validate_slave_info(
+	struct msm_sensor_info_t *sensor_info)
+{
+	if (sensor_info->position == INVALID_CAMERA_B) {
+		sensor_info->position = BACK_CAMERA_B;
+		CDBG("%s:%d Set default sensor position\n",
+			__func__, __LINE__);
+	}
+	if (sensor_info->modes_supported == CAMERA_MODE_INVALID) {
+		sensor_info->modes_supported = CAMERA_MODE_2D_B;
+		CDBG("%s:%d Set default sensor modes_supported\n",
+			__func__, __LINE__);
+	}
+	if (sensor_info->sensor_mount_angle >= SENSOR_MAX_MOUNTANGLE) {
+		sensor_info->sensor_mount_angle = 0;
+		CDBG("%s:%d Set default sensor mount angle\n",
+			__func__, __LINE__);
+		sensor_info->is_mount_angle_valid = 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static int32_t msm_sensor_get_pw_settings_compat(
+	struct msm_sensor_power_setting *ps,
+	struct msm_sensor_power_setting *us_ps, uint32_t size)
+{
+	int32_t rc = 0, i = 0;
+	struct msm_sensor_power_setting32 *ps32 =
+		kzalloc(sizeof(*ps32) * size, GFP_KERNEL);
+
+	if (!ps32) {
+		pr_err("failed: no memory ps32");
+		return -ENOMEM;
+	}
+	if (copy_from_user(ps32, (void __user *)us_ps, sizeof(*ps32) * size)) {
+		pr_err("failed: copy_from_user");
+		kfree(ps32);
+		return -EFAULT;
+	}
+	for (i = 0; i < size; i++) {
+		ps[i].config_val = ps32[i].config_val;
+		ps[i].delay = ps32[i].delay;
+		ps[i].seq_type = ps32[i].seq_type;
+		ps[i].seq_val = ps32[i].seq_val;
+	}
+	kfree(ps32);
+	return rc;
+}
+#endif
+
+static int32_t msm_sensor_create_pd_settings(void *setting,
+	struct msm_sensor_power_setting *pd, uint32_t size_down,
+	struct msm_sensor_power_setting *pu)
+{
+	int32_t rc = 0;
+	int c, end;
+	struct msm_sensor_power_setting pd_tmp;
+
+	pr_err("Generating power_down_setting");
+
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		rc = msm_sensor_get_pw_settings_compat(
+			pd, pu, size_down);
+		if (rc < 0) {
+			pr_err("failed");
+			return -EFAULT;
+		}
+	} else
+#endif
+	{
+		if (copy_from_user(
+			pd, (void __user *)pu, sizeof(*pd) * size_down)) {
+			pr_err("failed: copy_from_user");
+			return -EFAULT;
+		}
+	}
+	/* reverse */
+	end = size_down - 1;
+	for (c = 0; c < size_down/2; c++) {
+		pd_tmp = pd[c];
+		pd[c] = pd[end];
+		pd[end] = pd_tmp;
+		end--;
+	}
+	return rc;
+}
+
+static int32_t msm_sensor_get_power_down_settings(void *setting,
+	struct msm_camera_sensor_slave_info *slave_info,
+	struct msm_camera_power_ctrl_t *power_info)
+{
+	int32_t rc = 0;
+	uint16_t size_down = 0;
+	uint16_t i = 0;
+	struct msm_sensor_power_setting *pd = NULL;
+
+	/* DOWN */
+	size_down = slave_info->power_setting_array.size_down;
+	if (!size_down || size_down > MAX_POWER_CONFIG)
+		size_down = slave_info->power_setting_array.size;
+	/* Validate size_down */
+	if (size_down > MAX_POWER_CONFIG) {
+		pr_err("failed: invalid size_down %d", size_down);
+		return -EINVAL;
+	}
+	/* Allocate memory for power down setting */
+	pd = kcalloc(size_down, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return -EFAULT;
+
+	if (slave_info->power_setting_array.power_down_setting) {
+#ifdef CONFIG_COMPAT
+		if (is_compat_task()) {
+			rc = msm_sensor_get_pw_settings_compat(
+				pd, slave_info->power_setting_array.
+				power_down_setting, size_down);
+			if (rc < 0) {
+				pr_err("failed");
+				kfree(pd);
+				return -EFAULT;
+			}
+		} else
+#endif
+		if (copy_from_user(
+			pd, (void __user *)slave_info->power_setting_array.
+			power_down_setting, sizeof(*pd) * size_down)) {
+			pr_err("failed: copy_from_user");
+			kfree(pd);
+			return -EFAULT;
+		}
+	} else {
+
+		rc = msm_sensor_create_pd_settings(setting, pd, size_down,
+			slave_info->power_setting_array.power_setting);
+		if (rc < 0) {
+			pr_err("failed");
+			kfree(pd);
+			return -EFAULT;
+		}
+	}
+
+	/* Fill power down setting and power down setting size */
+	power_info->power_down_setting = pd;
+	power_info->power_down_setting_size = size_down;
+
+	/* Print power setting */
+	for (i = 0; i < size_down; i++) {
+		CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d",
+			pd[i].seq_type, pd[i].seq_val,
+			pd[i].config_val, pd[i].delay);
+	}
+	return rc;
+}
+
+static int32_t msm_sensor_get_power_up_settings(void *setting,
+	struct msm_camera_sensor_slave_info *slave_info,
+	struct msm_camera_power_ctrl_t *power_info)
+{
+	int32_t rc = 0;
+	uint16_t size = 0;
+	uint16_t i = 0;
+	struct msm_sensor_power_setting *pu = NULL;
+
+	size = slave_info->power_setting_array.size;
+
+	/* Validate size */
+	if ((size == 0) || (size > MAX_POWER_CONFIG)) {
+		pr_err("failed: invalid power_setting size_up = %d\n", size);
+		return -EINVAL;
+	}
+
+	/* Allocate memory for power up setting */
+	pu = kcalloc(size, sizeof(*pu), GFP_KERNEL);
+	if (!pu)
+		return -ENOMEM;
+
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		rc = msm_sensor_get_pw_settings_compat(pu,
+			slave_info->power_setting_array.
+				power_setting, size);
+		if (rc < 0) {
+			pr_err("failed");
+			kfree(pu);
+			return -EFAULT;
+		}
+	} else
+#endif
+	{
+		if (copy_from_user(pu,
+			(void __user *)
+			slave_info->power_setting_array.power_setting,
+			sizeof(*pu) * size)) {
+			pr_err("failed: copy_from_user");
+			kfree(pu);
+			return -EFAULT;
+		}
+	}
+
+	/* Print power setting */
+	for (i = 0; i < size; i++) {
+		CDBG("UP seq_type %d seq_val %d config_val %ld delay %d",
+			pu[i].seq_type, pu[i].seq_val,
+			pu[i].config_val, pu[i].delay);
+	}
+
+
+	/* Fill power up setting and power up setting size */
+	power_info->power_setting = pu;
+	power_info->power_setting_size = size;
+
+	return rc;
+}
+
+static int32_t msm_sensor_get_power_settings(void *setting,
+	struct msm_camera_sensor_slave_info *slave_info,
+	struct msm_camera_power_ctrl_t *power_info)
+{
+	int32_t rc = 0;
+
+	rc = msm_sensor_get_power_up_settings(setting, slave_info, power_info);
+	if (rc < 0) {
+		pr_err("failed");
+		return -EINVAL;
+	}
+
+	rc = msm_sensor_get_power_down_settings(setting, slave_info,
+		power_info);
+	if (rc < 0) {
+		pr_err("failed");
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static void msm_sensor_fill_sensor_info(struct msm_sensor_ctrl_t *s_ctrl,
+	struct msm_sensor_info_t *sensor_info, char *entity_name)
+{
+	uint32_t i;
+
+	if (!s_ctrl || !sensor_info) {
+		pr_err("%s:failed\n", __func__);
+		return;
+	}
+
+	strlcpy(sensor_info->sensor_name, s_ctrl->sensordata->sensor_name,
+		MAX_SENSOR_NAME);
+
+	sensor_info->session_id = s_ctrl->sensordata->sensor_info->session_id;
+
+	s_ctrl->sensordata->sensor_info->subdev_id[SUB_MODULE_SENSOR] =
+		s_ctrl->sensordata->sensor_info->session_id;
+	for (i = 0; i < SUB_MODULE_MAX; i++) {
+		sensor_info->subdev_id[i] =
+			s_ctrl->sensordata->sensor_info->subdev_id[i];
+		sensor_info->subdev_intf[i] =
+			s_ctrl->sensordata->sensor_info->subdev_intf[i];
+	}
+
+	sensor_info->is_mount_angle_valid =
+		s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+	sensor_info->sensor_mount_angle =
+		s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+	sensor_info->modes_supported =
+		s_ctrl->sensordata->sensor_info->modes_supported;
+	sensor_info->position =
+		s_ctrl->sensordata->sensor_info->position;
+
+	strlcpy(entity_name, s_ctrl->msm_sd.sd.entity.name, MAX_SENSOR_NAME);
+}
+
+/* static function definition */
+static int32_t msm_sensor_driver_is_special_support(
+	struct msm_sensor_ctrl_t *s_ctrl,
+	char *sensor_name)
+{
+	int32_t rc = 0, i = 0;
+	struct msm_camera_sensor_board_info *sensordata = s_ctrl->sensordata;
+
+	for (i = 0; i < sensordata->special_support_size; i++) {
+		if (!strcmp(sensordata->special_support_sensors[i],
+						 sensor_name)) {
+			rc = TRUE;
+			break;
+		}
+	}
+	return rc;
+}
+
+/* static function definition */
+int32_t msm_sensor_driver_probe(void *setting,
+	struct msm_sensor_info_t *probed_info, char *entity_name)
+{
+	int32_t                              rc = 0;
+	struct msm_sensor_ctrl_t            *s_ctrl = NULL;
+	struct msm_camera_cci_client        *cci_client = NULL;
+	struct msm_camera_sensor_slave_info *slave_info = NULL;
+	struct msm_camera_slave_info        *camera_info = NULL;
+
+	unsigned long                        mount_pos = 0;
+	uint32_t                             is_yuv;
+
+	/* Validate input parameters */
+	if (!setting) {
+		pr_err("failed: slave_info %pK", setting);
+		return -EINVAL;
+	}
+
+	/* Allocate memory for slave info */
+	slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL);
+	if (!slave_info)
+		return -ENOMEM;
+#ifdef CONFIG_COMPAT
+	if (is_compat_task()) {
+		struct msm_camera_sensor_slave_info32 *slave_info32 =
+			kzalloc(sizeof(*slave_info32), GFP_KERNEL);
+		if (!slave_info32) {
+			pr_err("failed: no memory for slave_info32 %pK\n",
+				slave_info32);
+			rc = -ENOMEM;
+			goto free_slave_info;
+		}
+		if (copy_from_user(slave_info32, (void __user *)setting,
+			sizeof(*slave_info32))) {
+			pr_err("failed: copy_from_user");
+			rc = -EFAULT;
+			kfree(slave_info32);
+			goto free_slave_info;
+		}
+
+		strlcpy(slave_info->actuator_name, slave_info32->actuator_name,
+			sizeof(slave_info->actuator_name));
+
+		strlcpy(slave_info->eeprom_name, slave_info32->eeprom_name,
+			sizeof(slave_info->eeprom_name));
+
+		strlcpy(slave_info->sensor_name, slave_info32->sensor_name,
+			sizeof(slave_info->sensor_name));
+
+		strlcpy(slave_info->ois_name, slave_info32->ois_name,
+			sizeof(slave_info->ois_name));
+
+		strlcpy(slave_info->flash_name, slave_info32->flash_name,
+			sizeof(slave_info->flash_name));
+
+		slave_info->addr_type = slave_info32->addr_type;
+		slave_info->camera_id = slave_info32->camera_id;
+
+		slave_info->i2c_freq_mode = slave_info32->i2c_freq_mode;
+		slave_info->sensor_id_info = slave_info32->sensor_id_info;
+
+		slave_info->slave_addr = slave_info32->slave_addr;
+		slave_info->power_setting_array.size =
+			slave_info32->power_setting_array.size;
+		slave_info->power_setting_array.size_down =
+			slave_info32->power_setting_array.size_down;
+		slave_info->power_setting_array.size_down =
+			slave_info32->power_setting_array.size_down;
+
+		slave_info->power_setting_array.power_down_setting =
+			(__force struct msm_sensor_power_setting *)
+			(compat_ptr(slave_info32->
+			power_setting_array.power_down_setting));
+
+		slave_info->power_setting_array.power_setting =
+			(__force struct msm_sensor_power_setting *)
+			(compat_ptr(slave_info32->
+			power_setting_array.power_setting));
+
+		slave_info->sensor_init_params =
+			slave_info32->sensor_init_params;
+		slave_info->output_format =
+			slave_info32->output_format;
+		slave_info->bypass_video_node_creation =
+			!!slave_info32->bypass_video_node_creation;
+		kfree(slave_info32);
+	} else
+#endif
+	{
+		if (copy_from_user(slave_info,
+			(void __user *)setting, sizeof(*slave_info))) {
+			pr_err("failed: copy_from_user");
+			rc = -EFAULT;
+			goto free_slave_info;
+		}
+	}
+
+	if (strlen(slave_info->sensor_name) >= MAX_SENSOR_NAME ||
+		strlen(slave_info->eeprom_name) >= MAX_SENSOR_NAME ||
+		strlen(slave_info->actuator_name) >= MAX_SENSOR_NAME ||
+		strlen(slave_info->ois_name) >= MAX_SENSOR_NAME) {
+		pr_err("failed: name len greater than 32.\n");
+		pr_err("sensor name len:%zu, eeprom name len: %zu.\n",
+			strlen(slave_info->sensor_name),
+			strlen(slave_info->eeprom_name));
+		pr_err("actuator name len: %zu, ois name len:%zu.\n",
+			strlen(slave_info->actuator_name),
+			strlen(slave_info->ois_name));
+		rc = -EINVAL;
+		goto free_slave_info;
+	}
+
+	/* Print slave info */
+	CDBG("camera id %d Slave addr 0x%X addr_type %d\n",
+		slave_info->camera_id, slave_info->slave_addr,
+		slave_info->addr_type);
+	CDBG("sensor_id_reg_addr 0x%X sensor_id 0x%X sensor id mask %d",
+		slave_info->sensor_id_info.sensor_id_reg_addr,
+		slave_info->sensor_id_info.sensor_id,
+		slave_info->sensor_id_info.sensor_id_mask);
+	CDBG("power up size %d power down size %d\n",
+		slave_info->power_setting_array.size,
+		slave_info->power_setting_array.size_down);
+	CDBG("position %d",
+		slave_info->sensor_init_params.position);
+	CDBG("mount %d",
+		slave_info->sensor_init_params.sensor_mount_angle);
+	CDBG("bypass video node creation %d",
+		slave_info->bypass_video_node_creation);
+	/* Validate camera id */
+	if (slave_info->camera_id >= MAX_CAMERAS) {
+		pr_err("failed: invalid camera id %d max %d",
+			slave_info->camera_id, MAX_CAMERAS);
+		rc = -EINVAL;
+		goto free_slave_info;
+	}
+
+	/* Extract s_ctrl from camera id */
+	s_ctrl = g_sctrl[slave_info->camera_id];
+	if (!s_ctrl) {
+		pr_err("failed: s_ctrl %pK for camera_id %d", s_ctrl,
+			slave_info->camera_id);
+		rc = -EINVAL;
+		goto free_slave_info;
+	}
+
+	CDBG("s_ctrl[%d] %pK", slave_info->camera_id, s_ctrl);
+
+	if (s_ctrl->sensordata->special_support_size > 0) {
+		if (!msm_sensor_driver_is_special_support(s_ctrl,
+			slave_info->sensor_name)) {
+			pr_err("%s:%s is not support on this board\n",
+				__func__, slave_info->sensor_name);
+			rc = 0;
+			goto free_slave_info;
+		}
+	}
+
+	if (s_ctrl->is_probe_succeed == 1) {
+		/*
+		 * Different sensor on this camera slot has been connected
+		 * and probe already succeeded for that sensor. Ignore this
+		 * probe
+		 */
+		if (slave_info->sensor_id_info.sensor_id ==
+			s_ctrl->sensordata->cam_slave_info->
+				sensor_id_info.sensor_id &&
+			!(strcmp(slave_info->sensor_name,
+			s_ctrl->sensordata->cam_slave_info->sensor_name))) {
+			pr_err("slot%d: sensor name: %s sensor id%d already probed\n",
+				slave_info->camera_id,
+				slave_info->sensor_name,
+				s_ctrl->sensordata->cam_slave_info->
+					sensor_id_info.sensor_id);
+			msm_sensor_fill_sensor_info(s_ctrl,
+				probed_info, entity_name);
+		} else
+			pr_err("slot %d has some other sensor\n",
+				slave_info->camera_id);
+
+		rc = 0;
+		goto free_slave_info;
+	}
+
+	if (slave_info->power_setting_array.size == 0 &&
+		slave_info->slave_addr == 0) {
+		s_ctrl->is_csid_tg_mode = 1;
+		goto CSID_TG;
+	}
+
+	rc = msm_sensor_get_power_settings(setting, slave_info,
+		&s_ctrl->sensordata->power_info);
+	if (rc < 0) {
+		pr_err("failed");
+		goto free_slave_info;
+	}
+
+
+	camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL);
+	if (!camera_info)
+		goto free_slave_info;
+
+	s_ctrl->sensordata->slave_info = camera_info;
+
+	/* Fill sensor slave info */
+	camera_info->sensor_slave_addr = slave_info->slave_addr;
+	camera_info->sensor_id_reg_addr =
+		slave_info->sensor_id_info.sensor_id_reg_addr;
+	camera_info->sensor_id = slave_info->sensor_id_info.sensor_id;
+	camera_info->sensor_id_mask = slave_info->sensor_id_info.sensor_id_mask;
+
+	/* Fill CCI master, slave address and CCI default params */
+	if (!s_ctrl->sensor_i2c_client) {
+		pr_err("failed: sensor_i2c_client %pK",
+			s_ctrl->sensor_i2c_client);
+		rc = -EINVAL;
+		goto free_camera_info;
+	}
+	/* Fill sensor address type */
+	s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type;
+	if (s_ctrl->sensor_i2c_client->client)
+		s_ctrl->sensor_i2c_client->client->addr =
+			camera_info->sensor_slave_addr;
+
+	cci_client = s_ctrl->sensor_i2c_client->cci_client;
+	if (!cci_client) {
+		pr_err("failed: cci_client %pK", cci_client);
+		goto free_camera_info;
+	}
+	cci_client->cci_i2c_master = s_ctrl->cci_i2c_master;
+	cci_client->sid = slave_info->slave_addr >> 1;
+	cci_client->retries = 3;
+	cci_client->id_map = 0;
+	cci_client->i2c_freq_mode = slave_info->i2c_freq_mode;
+
+	/* Parse and fill vreg params for powerup settings */
+	rc = msm_camera_fill_vreg_params(
+		s_ctrl->sensordata->power_info.cam_vreg,
+		s_ctrl->sensordata->power_info.num_vreg,
+		s_ctrl->sensordata->power_info.power_setting,
+		s_ctrl->sensordata->power_info.power_setting_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_dt_power_setting_data rc %d",
+			rc);
+		goto free_camera_info;
+	}
+
+	/* Parse and fill vreg params for powerdown settings*/
+	rc = msm_camera_fill_vreg_params(
+		s_ctrl->sensordata->power_info.cam_vreg,
+		s_ctrl->sensordata->power_info.num_vreg,
+		s_ctrl->sensordata->power_info.power_down_setting,
+		s_ctrl->sensordata->power_info.power_down_setting_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d",
+			rc);
+		goto free_camera_info;
+	}
+
+CSID_TG:
+	/* Update sensor, actuator and eeprom name in
+	 * sensor control structure
+	 */
+	s_ctrl->sensordata->sensor_name = slave_info->sensor_name;
+	s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name;
+	s_ctrl->sensordata->actuator_name = slave_info->actuator_name;
+	s_ctrl->sensordata->ois_name = slave_info->ois_name;
+	s_ctrl->sensordata->flash_name = slave_info->flash_name;
+	/*
+	 * Update eeporm subdevice Id by input eeprom name
+	 */
+	rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto free_camera_info;
+	}
+	/*
+	 * Update actuator subdevice Id by input actuator name
+	 */
+	rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto free_camera_info;
+	}
+	rc = msm_sensor_fill_laser_led_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto free_camera_info;
+	}
+
+	rc = msm_sensor_fill_ois_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto free_camera_info;
+	}
+
+	rc = msm_sensor_fill_flash_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto free_camera_info;
+	}
+
+	/* Power up and probe sensor */
+	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s power up failed", slave_info->sensor_name);
+		goto free_camera_info;
+	}
+
+	pr_err("%s probe succeeded", slave_info->sensor_name);
+
+	s_ctrl->bypass_video_node_creation =
+		slave_info->bypass_video_node_creation;
+
+	/*
+	 * Create /dev/videoX node, comment for now until dummy /dev/videoX
+	 * node is created and used by HAL
+	 */
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		rc = msm_sensor_driver_create_v4l_subdev(s_ctrl);
+	else
+		rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: camera creat v4l2 rc %d", rc);
+		goto camera_power_down;
+	}
+
+	/* Power down */
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+
+	rc = msm_sensor_fill_slave_info_init_params(
+		slave_info,
+		s_ctrl->sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("%s Fill slave info failed", slave_info->sensor_name);
+		goto free_camera_info;
+	}
+	rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("%s Validate slave info failed",
+			slave_info->sensor_name);
+		goto free_camera_info;
+	}
+	/* Update sensor mount angle and position in media entity flag */
+	is_yuv = (slave_info->output_format == MSM_SENSOR_YCBCR) ? 1 : 0;
+	mount_pos = ((s_ctrl->is_secure & 0x1) << 26) | is_yuv << 25 |
+		(s_ctrl->sensordata->sensor_info->position << 16) |
+		((s_ctrl->sensordata->
+		sensor_info->sensor_mount_angle / 90) << 8);
+
+	s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
+
+	/*Save sensor info*/
+	s_ctrl->sensordata->cam_slave_info = slave_info;
+
+	msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name);
+
+	/*
+	 * Set probe succeeded flag to 1 so that no other camera shall
+	 * probed on this slot
+	 */
+	s_ctrl->is_probe_succeed = 1;
+	return rc;
+
+camera_power_down:
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+free_camera_info:
+	kfree(camera_info);
+free_slave_info:
+	kfree(slave_info);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t                              rc = 0, i = 0;
+	struct msm_camera_sensor_board_info *sensordata = NULL;
+	struct device_node                  *of_node = s_ctrl->of_node;
+	uint32_t	cell_id;
+
+	s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL);
+	if (!s_ctrl->sensordata)
+		return -ENOMEM;
+
+	sensordata = s_ctrl->sensordata;
+
+	/*
+	 * Read cell index - this cell index will be the camera slot where
+	 * this camera will be mounted
+	 */
+	rc = of_property_read_u32(of_node, "cell-index", &cell_id);
+	if (rc < 0) {
+		pr_err("failed: cell-index rc %d", rc);
+		goto FREE_SENSOR_DATA;
+	}
+	s_ctrl->id = cell_id;
+
+	/* Validate cell_id */
+	if (cell_id >= MAX_CAMERAS) {
+		pr_err("failed: invalid cell_id %d", cell_id);
+		rc = -EINVAL;
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Check whether g_sctrl is already filled for this cell_id */
+	if (g_sctrl[cell_id]) {
+		pr_err("failed: sctrl already filled for cell_id %d", cell_id);
+		rc = -EINVAL;
+		goto FREE_SENSOR_DATA;
+	}
+
+	sensordata->special_support_size =
+		of_property_count_strings(of_node,
+				 "qcom,special-support-sensors");
+
+	if (sensordata->special_support_size < 0)
+		sensordata->special_support_size = 0;
+
+	if (sensordata->special_support_size > MAX_SPECIAL_SUPPORT_SIZE) {
+		pr_debug("%s:support_size exceed max support size\n", __func__);
+		sensordata->special_support_size = MAX_SPECIAL_SUPPORT_SIZE;
+	}
+
+	if (sensordata->special_support_size) {
+		for (i = 0; i < sensordata->special_support_size; i++) {
+			rc = of_property_read_string_index(of_node,
+				"qcom,special-support-sensors", i,
+				&(sensordata->special_support_sensors[i]));
+			if (rc < 0) {
+				/* if read sensor support names failed,
+				 *   set support all sensors, break;
+				 */
+				sensordata->special_support_size = 0;
+				break;
+			}
+			CDBG("%s special_support_sensors[%d] = %s\n", __func__,
+				i, sensordata->special_support_sensors[i]);
+		}
+	}
+
+	/* Read subdev info */
+	rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("failed");
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Read vreg information */
+	rc = msm_camera_get_dt_vreg_data(of_node,
+		&sensordata->power_info.cam_vreg,
+		&sensordata->power_info.num_vreg);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_dt_vreg_data rc %d", rc);
+		goto FREE_SUB_MODULE_DATA;
+	}
+
+	/* Read gpio information */
+	rc = msm_sensor_driver_get_gpio_data
+		(&(sensordata->power_info.gpio_conf), of_node);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc);
+		goto FREE_VREG_DATA;
+	}
+
+	/* Get custom mode */
+	rc = of_property_read_u32(of_node, "qcom,secure",
+		&s_ctrl->is_secure);
+	CDBG("qcom,secure = %d, rc %d", s_ctrl->is_secure, rc);
+	if (rc < 0) {
+		/* Set default to non-secure mode */
+		s_ctrl->is_secure = 0;
+		rc = 0;
+	}
+
+	/* Get CCI master */
+	rc = of_property_read_u32(of_node, "qcom,cci-master",
+		&s_ctrl->cci_i2c_master);
+	CDBG("qcom,cci-master %d, rc %d", s_ctrl->cci_i2c_master, rc);
+	if (rc < 0) {
+		/* Set default master 0 */
+		s_ctrl->cci_i2c_master = MASTER_0;
+		rc = 0;
+	}
+
+	/* Get mount angle */
+	if (of_property_read_u32(of_node, "qcom,mount-angle",
+		&sensordata->sensor_info->sensor_mount_angle) < 0) {
+		/* Invalidate mount angle flag */
+		sensordata->sensor_info->is_mount_angle_valid = 0;
+		sensordata->sensor_info->sensor_mount_angle = 0;
+	} else {
+		sensordata->sensor_info->is_mount_angle_valid = 1;
+	}
+	CDBG("%s qcom,mount-angle %d\n", __func__,
+		sensordata->sensor_info->sensor_mount_angle);
+	if (of_property_read_u32(of_node, "qcom,sensor-position",
+		&sensordata->sensor_info->position) < 0) {
+		CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__);
+		sensordata->sensor_info->position = INVALID_CAMERA_B;
+	}
+	if (of_property_read_u32(of_node, "qcom,sensor-mode",
+		&sensordata->sensor_info->modes_supported) < 0) {
+		CDBG("%s:%d Invalid sensor mode supported\n",
+			__func__, __LINE__);
+		sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID;
+	}
+	/* Get vdd-cx regulator */
+	/*Optional property, don't return error if absent */
+	of_property_read_string(of_node, "qcom,vdd-cx-name",
+		&sensordata->misc_regulator);
+	CDBG("qcom,misc_regulator %s", sensordata->misc_regulator);
+
+	s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node,
+						"qcom,mclk-23880000");
+
+	CDBG("%s qcom,mclk-23880000 = %d\n", __func__,
+		s_ctrl->set_mclk_23880000);
+
+	return rc;
+
+FREE_VREG_DATA:
+	kfree(sensordata->power_info.cam_vreg);
+FREE_SUB_MODULE_DATA:
+	kfree(sensordata->sensor_info);
+FREE_SENSOR_DATA:
+	kfree(sensordata);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t                   rc = 0;
+
+	CDBG("Enter");
+	/* Validate input parameters */
+
+
+	/* Allocate memory for sensor_i2c_client */
+	s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client),
+		GFP_KERNEL);
+	if (!s_ctrl->sensor_i2c_client)
+		return -ENOMEM;
+
+	/* Allocate memory for mutex */
+	s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex),
+		GFP_KERNEL);
+	if (!s_ctrl->msm_sensor_mutex) {
+		rc = -ENOMEM;
+		goto FREE_SENSOR_I2C_CLIENT;
+	}
+
+	/* Parse dt information and store in sensor control structure */
+	rc = msm_sensor_driver_get_dt_data(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: rc %d", rc);
+		goto FREE_MUTEX;
+	}
+
+	/* Initialize mutex */
+	mutex_init(s_ctrl->msm_sensor_mutex);
+
+	/* Initialize v4l2 subdev info */
+	s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info;
+	s_ctrl->sensor_v4l2_subdev_info_size =
+		ARRAY_SIZE(msm_sensor_driver_subdev_info);
+
+	/* Initialize default parameters */
+	rc = msm_sensor_init_default_params(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_init_default_params rc %d", rc);
+		goto FREE_DT_DATA;
+	}
+
+	/* Store sensor control structure in static database */
+	g_sctrl[s_ctrl->id] = s_ctrl;
+	CDBG("g_sctrl[%d] %pK", s_ctrl->id, g_sctrl[s_ctrl->id]);
+
+	return rc;
+
+FREE_DT_DATA:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf);
+	kfree(s_ctrl->sensordata->power_info.cam_vreg);
+	kfree(s_ctrl->sensordata);
+FREE_MUTEX:
+	kfree(s_ctrl->msm_sensor_mutex);
+FREE_SENSOR_I2C_CLIENT:
+	kfree(s_ctrl->sensor_i2c_client);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = NULL;
+
+	/* Create sensor control structure */
+	s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL);
+	if (!s_ctrl)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, s_ctrl);
+
+	/* Initialize sensor device type */
+	s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	s_ctrl->of_node = pdev->dev.of_node;
+
+	/*fill in platform device*/
+	s_ctrl->pdev = pdev;
+
+	rc = msm_sensor_driver_parse(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_parse rc %d", rc);
+		goto FREE_S_CTRL;
+	}
+
+	/* Get clocks information */
+	rc = msm_camera_get_clk_info(s_ctrl->pdev,
+		&s_ctrl->sensordata->power_info.clk_info,
+		&s_ctrl->sensordata->power_info.clk_ptr,
+		&s_ctrl->sensordata->power_info.clk_info_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_clk_info rc %d", rc);
+		goto FREE_S_CTRL;
+	}
+
+	/* Fill platform device id*/
+	pdev->id = s_ctrl->id;
+
+	/* Fill device in power info */
+	s_ctrl->sensordata->power_info.dev = &pdev->dev;
+	return rc;
+FREE_S_CTRL:
+	kfree(s_ctrl);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+
+	CDBG("\n\nEnter: msm_sensor_driver_i2c_probe");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s i2c_check_functionality failed\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	/* Create sensor control structure */
+	s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL);
+	if (!s_ctrl)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, s_ctrl);
+
+	/* Initialize sensor device type */
+	s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE;
+	s_ctrl->of_node = client->dev.of_node;
+
+	rc = msm_sensor_driver_parse(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_parse rc %d", rc);
+		goto FREE_S_CTRL;
+	}
+
+	if (s_ctrl->sensor_i2c_client != NULL) {
+		s_ctrl->sensor_i2c_client->client = client;
+		s_ctrl->sensordata->power_info.dev = &client->dev;
+
+		/* Get clocks information */
+		rc = msm_camera_i2c_dev_get_clk_info(
+			&s_ctrl->sensor_i2c_client->client->dev,
+			&s_ctrl->sensordata->power_info.clk_info,
+			&s_ctrl->sensordata->power_info.clk_ptr,
+			&s_ctrl->sensordata->power_info.clk_info_size);
+		if (rc < 0) {
+			pr_err("failed: msm_camera_i2c_dev_get_clk_info rc %d",
+				rc);
+			goto FREE_S_CTRL;
+		}
+		return rc;
+	}
+FREE_S_CTRL:
+	kfree(s_ctrl);
+	return rc;
+}
+
+static int msm_sensor_driver_i2c_remove(struct i2c_client *client)
+{
+	struct msm_sensor_ctrl_t  *s_ctrl = i2c_get_clientdata(client);
+
+	pr_err("%s: sensor FREE\n", __func__);
+
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	g_sctrl[s_ctrl->id] = NULL;
+	msm_sensor_free_sensor_data(s_ctrl);
+	kfree(s_ctrl->msm_sensor_mutex);
+	kfree(s_ctrl->sensor_i2c_client);
+	kfree(s_ctrl);
+
+	return 0;
+}
+
+static const struct i2c_device_id i2c_id[] = {
+	{SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver msm_sensor_driver_i2c = {
+	.id_table = i2c_id,
+	.probe  = msm_sensor_driver_i2c_probe,
+	.remove = msm_sensor_driver_i2c_remove,
+	.driver = {
+		.name = SENSOR_DRIVER_I2C,
+	},
+};
+
+static int __init msm_sensor_driver_init(void)
+{
+	int32_t rc = 0;
+
+	CDBG("%s Enter\n", __func__);
+	rc = platform_driver_register(&msm_sensor_platform_driver);
+	if (rc)
+		pr_err("%s platform_driver_register failed rc = %d",
+			__func__, rc);
+	rc = i2c_add_driver(&msm_sensor_driver_i2c);
+	if (rc)
+		pr_err("%s i2c_add_driver failed rc = %d",  __func__, rc);
+
+	return rc;
+}
+
+static void __exit msm_sensor_driver_exit(void)
+{
+	CDBG("Enter");
+	platform_driver_unregister(&msm_sensor_platform_driver);
+	i2c_del_driver(&msm_sensor_driver_i2c);
+}
+
+module_init(msm_sensor_driver_init);
+module_exit(msm_sensor_driver_exit);
+MODULE_DESCRIPTION("msm_sensor_driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h
new file mode 100644
index 0000000..28e4336
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_SENSOR_DRIVER_H
+#define MSM_SENSOR_DRIVER_H
+
+#include "msm_sensor.h"
+
+int32_t msm_sensor_driver_probe(void *setting,
+	struct msm_sensor_info_t *probed_info, char *entity_name);
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
new file mode 100644
index 0000000..acab45e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
@@ -0,0 +1,225 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__
+
+/* Header files */
+#include "msm_sensor_init.h"
+#include "msm_sensor_driver.h"
+#include "msm_sensor.h"
+#include "msm_sd.h"
+
+/* Logging macro */
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static struct msm_sensor_init_t *s_init;
+static struct v4l2_file_operations msm_sensor_init_v4l2_subdev_fops;
+/* Static function declaration */
+static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+
+/* Static structure declaration */
+static struct v4l2_subdev_core_ops msm_sensor_init_subdev_core_ops = {
+	.ioctl = msm_sensor_init_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_sensor_init_subdev_ops = {
+	.core = &msm_sensor_init_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_sensor_init_internal_ops;
+
+static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init)
+{
+	int rc;
+	int tm = 20000;
+
+	if (s_init->module_init_status == 1) {
+		CDBG("msm_cam_get_module_init_status -2\n");
+		return 0;
+	}
+	rc = wait_event_timeout(s_init->state_wait,
+		(s_init->module_init_status == 1), msecs_to_jiffies(tm));
+	if (rc == 0)
+		pr_err("%s:%d wait timeout\n", __func__, __LINE__);
+
+	return rc;
+}
+
+/* Static function definition */
+static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init,
+	void *arg)
+{
+	int32_t                      rc = 0;
+	struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg;
+
+	/* Validate input parameters */
+	if (!s_init || !cfg) {
+		pr_err("failed: s_init %pK cfg %pK", s_init, cfg);
+		return -EINVAL;
+	}
+
+	switch (cfg->cfgtype) {
+	case CFG_SINIT_PROBE:
+		mutex_lock(&s_init->imutex);
+		s_init->module_init_status = 0;
+		rc = msm_sensor_driver_probe(cfg->cfg.setting,
+			&cfg->probed_info,
+			cfg->entity_name);
+		mutex_unlock(&s_init->imutex);
+		if (rc < 0)
+			pr_err_ratelimited("%s failed (non-fatal) rc %d",
+				__func__, rc);
+		break;
+
+	case CFG_SINIT_PROBE_DONE:
+		s_init->module_init_status = 1;
+		wake_up(&s_init->state_wait);
+		break;
+
+	case CFG_SINIT_PROBE_WAIT_DONE:
+		msm_sensor_wait_for_probe_done(s_init);
+		break;
+
+	default:
+		pr_err("default");
+		break;
+	}
+
+	return rc;
+}
+
+static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc = 0;
+	struct msm_sensor_init_t *s_init = v4l2_get_subdevdata(sd);
+
+	CDBG("Enter");
+
+	/* Validate input parameters */
+	if (!s_init) {
+		pr_err("failed: s_init %pK", s_init);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_INIT_CFG:
+		rc = msm_sensor_driver_cmd(s_init, arg);
+		break;
+
+	default:
+		pr_err_ratelimited("default\n");
+		break;
+	}
+
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_sensor_init_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	int32_t             rc = 0;
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct sensor_init_cfg_data32 *u32 =
+		(struct sensor_init_cfg_data32 *)arg;
+	struct sensor_init_cfg_data sensor_init_data;
+
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_INIT_CFG32:
+		memset(&sensor_init_data, 0, sizeof(sensor_init_data));
+		sensor_init_data.cfgtype = u32->cfgtype;
+		sensor_init_data.cfg.setting =
+			(__force void *)compat_ptr(u32->cfg.setting);
+		cmd = VIDIOC_MSM_SENSOR_INIT_CFG;
+		rc = msm_sensor_init_subdev_ioctl(sd, cmd, &sensor_init_data);
+		if (rc < 0) {
+			pr_err_ratelimited("%s:%d VIDIOC_MSM_SENSOR_INIT_CFG failed (non-fatal)",
+				__func__, __LINE__);
+			return rc;
+		}
+		u32->probed_info = sensor_init_data.probed_info;
+		strlcpy(u32->entity_name, sensor_init_data.entity_name,
+			sizeof(sensor_init_data.entity_name));
+		return 0;
+	default:
+		return msm_sensor_init_subdev_ioctl(sd, cmd, arg);
+	}
+}
+
+static long msm_sensor_init_subdev_fops_ioctl(
+	struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_sensor_init_subdev_do_ioctl);
+}
+#endif
+
+static int __init msm_sensor_init_module(void)
+{
+	int ret = 0;
+	/* Allocate memory for msm_sensor_init control structure */
+	s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL);
+	if (!s_init)
+		return -ENOMEM;
+
+	CDBG("MSM_SENSOR_INIT_MODULE %pK", NULL);
+
+	/* Initialize mutex */
+	mutex_init(&s_init->imutex);
+
+	/* Create /dev/v4l-subdevX for msm_sensor_init */
+	v4l2_subdev_init(&s_init->msm_sd.sd, &msm_sensor_init_subdev_ops);
+	snprintf(s_init->msm_sd.sd.name, sizeof(s_init->msm_sd.sd.name), "%s",
+		"msm_sensor_init");
+	v4l2_set_subdevdata(&s_init->msm_sd.sd, s_init);
+	s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops;
+	s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&s_init->msm_sd.sd.entity, 0, NULL);
+	s_init->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_SENSOR_INIT;
+	s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name;
+	s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
+	ret = msm_sd_register(&s_init->msm_sd);
+	if (ret) {
+		CDBG("%s: msm_sd_register error = %d\n", __func__, ret);
+		goto error;
+	}
+	msm_cam_copy_v4l2_subdev_fops(&msm_sensor_init_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_sensor_init_v4l2_subdev_fops.compat_ioctl32 =
+		msm_sensor_init_subdev_fops_ioctl;
+#endif
+	s_init->msm_sd.sd.devnode->fops =
+		&msm_sensor_init_v4l2_subdev_fops;
+
+	init_waitqueue_head(&s_init->state_wait);
+
+	return 0;
+error:
+	mutex_destroy(&s_init->imutex);
+	kfree(s_init);
+	return ret;
+}
+
+static void __exit msm_sensor_exit_module(void)
+{
+	msm_sd_unregister(&s_init->msm_sd);
+	mutex_destroy(&s_init->imutex);
+	kfree(s_init);
+}
+
+module_init(msm_sensor_init_module);
+module_exit(msm_sensor_exit_module);
+MODULE_DESCRIPTION("msm_sensor_init");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h
new file mode 100644
index 0000000..4048eb0
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_SENSOR_INIT_H
+#define MSM_SENSOR_INIT_H
+
+#include "msm_sensor.h"
+
+struct msm_sensor_init_t {
+	struct mutex imutex;
+	struct msm_sd_subdev msm_sd;
+	int module_init_status;
+	wait_queue_head_t state_wait;
+};
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/Makefile b/drivers/media/platform/msm/camera_v2/sensor/ois/Makefile
new file mode 100644
index 0000000..f09c92a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ois/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_MSMB_CAMERA) += msm_ois.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
new file mode 100644
index 0000000..0e17b7d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c
@@ -0,0 +1,1110 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "msm_sd.h"
+#include "msm_ois.h"
+#include "msm_cci.h"
+
+DEFINE_MSM_MUTEX(msm_ois_mutex);
+/*#define MSM_OIS_DEBUG*/
+#undef CDBG
+#ifdef MSM_OIS_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static struct v4l2_file_operations msm_ois_v4l2_subdev_fops;
+static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl);
+static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl);
+
+static struct i2c_driver msm_ois_i2c_driver;
+
+static int32_t data_type_to_num_bytes(
+	enum msm_camera_i2c_data_type data_type)
+{
+	int32_t ret_val;
+
+	switch (data_type) {
+	case MSM_CAMERA_I2C_BYTE_DATA:
+		ret_val = 1;
+		break;
+	case MSM_CAMERA_I2C_WORD_DATA:
+		ret_val = 2;
+		break;
+	case MSM_CAMERA_I2C_DWORD_DATA:
+		ret_val = 4;
+		break;
+	default:
+		pr_err("unsupported data type: %d\n",
+			data_type);
+		ret_val = 1;
+		break;
+	}
+	return ret_val;
+}
+
+static int32_t msm_ois_download(struct msm_ois_ctrl_t *o_ctrl)
+{
+	uint16_t bytes_in_tx = 0;
+	uint16_t total_bytes = 0;
+	uint8_t *ptr = NULL;
+	int32_t rc = 0;
+	const struct firmware *fw = NULL;
+	const char *fw_name_prog = NULL;
+	const char *fw_name_coeff = NULL;
+	char name_prog[MAX_SENSOR_NAME] = {0};
+	char name_coeff[MAX_SENSOR_NAME] = {0};
+	struct device *dev = &(o_ctrl->pdev->dev);
+	enum msm_camera_i2c_reg_addr_type save_addr_type;
+
+	CDBG("Enter\n");
+	save_addr_type = o_ctrl->i2c_client.addr_type;
+	o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+
+	snprintf(name_coeff, MAX_SENSOR_NAME, "%s.coeff",
+		o_ctrl->oboard_info->ois_name);
+
+	snprintf(name_prog, MAX_SENSOR_NAME, "%s.prog",
+		o_ctrl->oboard_info->ois_name);
+
+	/* cast pointer as const pointer*/
+	fw_name_prog = name_prog;
+	fw_name_coeff = name_coeff;
+
+	/* Load FW */
+	rc = request_firmware(&fw, fw_name_prog, dev);
+	if (rc) {
+		dev_err(dev, "Failed to locate %s\n", fw_name_prog);
+		o_ctrl->i2c_client.addr_type = save_addr_type;
+		return rc;
+	}
+
+	total_bytes = fw->size;
+	for (ptr = (uint8_t *)fw->data; total_bytes;
+		total_bytes -= bytes_in_tx, ptr += bytes_in_tx) {
+		bytes_in_tx = (total_bytes > 10) ? 10 : total_bytes;
+		rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq(
+			&o_ctrl->i2c_client, o_ctrl->oboard_info->opcode.prog,
+			 ptr, bytes_in_tx);
+		if (rc < 0) {
+			pr_err("Failed:remaining bytes to be downloaded:%d\n",
+				bytes_in_tx);
+			/* abort download fw and return error*/
+			goto release_firmware;
+		}
+	}
+	release_firmware(fw);
+
+	rc = request_firmware(&fw, fw_name_coeff, dev);
+	if (rc) {
+		dev_err(dev, "Failed to locate %s\n", fw_name_coeff);
+		o_ctrl->i2c_client.addr_type = save_addr_type;
+		return rc;
+	}
+	total_bytes = fw->size;
+	for (ptr = (uint8_t *)fw->data; total_bytes;
+		total_bytes -= bytes_in_tx, ptr += bytes_in_tx) {
+		bytes_in_tx = (total_bytes > 10) ? 10 : total_bytes;
+		rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq(
+			&o_ctrl->i2c_client, o_ctrl->oboard_info->opcode.coeff,
+			ptr, bytes_in_tx);
+		if (rc < 0) {
+			pr_err("Failed:remaining bytes to be downloaded:%d\n",
+				total_bytes);
+			/* abort download fw*/
+			break;
+		}
+	}
+release_firmware:
+	release_firmware(fw);
+	o_ctrl->i2c_client.addr_type = save_addr_type;
+
+	return rc;
+}
+
+static int32_t msm_ois_data_config(struct msm_ois_ctrl_t *o_ctrl,
+	struct msm_ois_slave_info *slave_info)
+{
+	int rc = 0;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter\n");
+	if (!slave_info) {
+		pr_err("failed : invalid slave_info\n");
+		return -EINVAL;
+	}
+	/* fill ois slave info*/
+	if (strlcpy(o_ctrl->oboard_info->ois_name, slave_info->ois_name,
+		sizeof(o_ctrl->oboard_info->ois_name)) == 0) {
+		pr_err("failed: invalid ois_name\n");
+		return -EFAULT;
+	}
+	memcpy(&(o_ctrl->oboard_info->opcode), &(slave_info->opcode),
+		sizeof(struct msm_ois_opcode));
+	o_ctrl->oboard_info->i2c_slaveaddr = slave_info->i2c_addr;
+
+	/* config cci_client*/
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = o_ctrl->i2c_client.cci_client;
+		cci_client->sid =
+			o_ctrl->oboard_info->i2c_slaveaddr >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->cci_i2c_master = o_ctrl->cci_master;
+	} else {
+		o_ctrl->i2c_client.client->addr =
+			o_ctrl->oboard_info->i2c_slaveaddr;
+	}
+	o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR;
+
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl,
+	uint16_t size, struct reg_settings_ois_t *settings)
+{
+	int32_t rc = -EFAULT;
+	int32_t i = 0, num_byte_seq = 0;
+	uint8_t *reg_data_seq;
+
+	struct msm_camera_i2c_seq_reg_array *reg_setting;
+
+	CDBG("Enter\n");
+
+	for (i = 0; i < size; i++) {
+		switch (settings[i].i2c_operation) {
+		case MSM_OIS_WRITE: {
+			switch (settings[i].data_type) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+				rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+					&o_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					settings[i].data_type);
+				break;
+			case MSM_CAMERA_I2C_DWORD_DATA:
+			reg_setting =
+			kzalloc(sizeof(struct msm_camera_i2c_seq_reg_array),
+				GFP_KERNEL);
+				if (!reg_setting)
+					return -ENOMEM;
+
+				reg_setting->reg_addr = settings[i].reg_addr;
+				reg_setting->reg_data[0] = (uint8_t)
+					((settings[i].reg_data &
+					0xFF000000) >> 24);
+				reg_setting->reg_data[1] = (uint8_t)
+					((settings[i].reg_data &
+					0x00FF0000) >> 16);
+				reg_setting->reg_data[2] = (uint8_t)
+					((settings[i].reg_data &
+					0x0000FF00) >> 8);
+				reg_setting->reg_data[3] = (uint8_t)
+					(settings[i].reg_data & 0x000000FF);
+				reg_setting->reg_data_size = 4;
+				rc = o_ctrl->i2c_client.i2c_func_tbl->
+					i2c_write_seq(&o_ctrl->i2c_client,
+					reg_setting->reg_addr,
+					reg_setting->reg_data,
+					reg_setting->reg_data_size);
+				kfree(reg_setting);
+				reg_setting = NULL;
+				if (rc < 0)
+					return rc;
+				break;
+
+			default:
+				pr_err("Unsupport data type: %d\n",
+					settings[i].data_type);
+				break;
+			}
+			if (settings[i].delay > 20)
+				msleep(settings[i].delay);
+			else if (settings[i].delay != 0)
+				usleep_range(settings[i].delay * 1000,
+					(settings[i].delay * 1000) + 1000);
+		}
+			break;
+
+		case MSM_OIS_POLL: {
+			switch (settings[i].data_type) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+
+				rc = o_ctrl->i2c_client.i2c_func_tbl
+					->i2c_poll(&o_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					settings[i].data_type,
+					settings[i].delay);
+				break;
+
+			default:
+				pr_err("Unsupport data type: %d\n",
+					settings[i].data_type);
+				break;
+			}
+			break;
+		}
+		case MSM_OIS_READ: {
+			switch (settings[i].data_type) {
+			case MSM_CAMERA_I2C_BYTE_DATA:
+			case MSM_CAMERA_I2C_WORD_DATA:
+			case MSM_CAMERA_I2C_DWORD_DATA:
+
+				num_byte_seq =
+					data_type_to_num_bytes
+					(settings[i].data_type);
+				reg_data_seq = kzalloc(sizeof(uint32_t),
+						GFP_KERNEL);
+				if (!reg_data_seq)
+					return -ENOMEM;
+
+				rc = msm_camera_cci_i2c_read_seq
+					(&o_ctrl->i2c_client,
+					settings[i].reg_addr,
+					reg_data_seq,
+					num_byte_seq);
+
+				memcpy(&settings[i].reg_data,
+					reg_data_seq, sizeof(uint32_t));
+
+				CDBG("ois data read 0x%x from address 0x%x",
+					settings[i].reg_addr,
+					settings[i].reg_data);
+
+				kfree(reg_data_seq);
+				reg_data_seq = NULL;
+
+				break;
+			default:
+				pr_err("Unsupport data type for MSM_OIS_READ: %d\n",
+					settings[i].data_type);
+				break;
+			}
+			break;
+		}
+
+		if (rc < 0)
+			break;
+		}
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_ois_vreg_control(struct msm_ois_ctrl_t *o_ctrl,
+							int config)
+{
+	int rc = 0, i, cnt;
+	struct msm_ois_vreg *vreg_cfg;
+
+	vreg_cfg = &o_ctrl->vreg_cfg;
+	cnt = vreg_cfg->num_vreg;
+	if (!cnt)
+		return 0;
+
+	if (cnt >= MSM_OIS_MAX_VREGS) {
+		pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		rc = msm_camera_config_single_vreg(&(o_ctrl->pdev->dev),
+			&vreg_cfg->cam_vreg[i],
+			(struct regulator **)&vreg_cfg->data[i],
+			config);
+	}
+	return rc;
+}
+
+static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl)
+{
+	int32_t rc = 0;
+	enum msm_sensor_power_seq_gpio_t gpio;
+
+	CDBG("Enter\n");
+	if (o_ctrl->ois_state != OIS_DISABLE_STATE) {
+
+		rc = msm_ois_vreg_control(o_ctrl, 0);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return rc;
+		}
+
+		for (gpio = SENSOR_GPIO_AF_PWDM; gpio < SENSOR_GPIO_MAX;
+			gpio++) {
+			if (o_ctrl->gconf &&
+				o_ctrl->gconf->gpio_num_info &&
+				o_ctrl->gconf->
+					gpio_num_info->valid[gpio] == 1) {
+				gpio_set_value_cansleep(
+					o_ctrl->gconf->gpio_num_info
+						->gpio_num[gpio],
+					GPIOF_OUT_INIT_LOW);
+
+				if (o_ctrl->cam_pinctrl_status) {
+					rc = pinctrl_select_state(
+						o_ctrl->pinctrl_info.pinctrl,
+						o_ctrl->pinctrl_info.
+							gpio_state_suspend);
+					if (rc < 0)
+						pr_err("ERR:%s:%d cannot set pin to suspend state: %d",
+							__func__, __LINE__, rc);
+					devm_pinctrl_put(
+						o_ctrl->pinctrl_info.pinctrl);
+				}
+				o_ctrl->cam_pinctrl_status = 0;
+				rc = msm_camera_request_gpio_table(
+					o_ctrl->gconf->cam_gpio_req_tbl,
+					o_ctrl->gconf->cam_gpio_req_tbl_size,
+					0);
+				if (rc < 0)
+					pr_err("ERR:%s:Failed in selecting state in ois power down: %d\n",
+						__func__, rc);
+			}
+		}
+
+		o_ctrl->i2c_tbl_index = 0;
+		o_ctrl->ois_state = OIS_OPS_INACTIVE;
+	}
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int msm_ois_init(struct msm_ois_ctrl_t *o_ctrl)
+{
+	int rc = 0;
+
+	CDBG("Enter\n");
+
+	if (!o_ctrl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&o_ctrl->i2c_client, MSM_CCI_INIT);
+		if (rc < 0)
+			pr_err("cci_init failed\n");
+	}
+	o_ctrl->ois_state = OIS_OPS_ACTIVE;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl,
+	struct msm_ois_set_info_t *set_info)
+{
+	struct reg_settings_ois_t *settings = NULL;
+	int32_t rc = 0, i = 0;
+	struct msm_camera_cci_client *cci_client = NULL;
+
+	CDBG("Enter\n");
+
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = o_ctrl->i2c_client.cci_client;
+		cci_client->sid =
+			set_info->ois_params.i2c_addr >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->cci_i2c_master = o_ctrl->cci_master;
+		cci_client->i2c_freq_mode = set_info->ois_params.i2c_freq_mode;
+	} else {
+		o_ctrl->i2c_client.client->addr =
+			set_info->ois_params.i2c_addr;
+	}
+	o_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR;
+
+
+	if (set_info->ois_params.setting_size > 0 &&
+		set_info->ois_params.setting_size
+		< MAX_OIS_REG_SETTINGS) {
+		settings = kmalloc(
+			sizeof(struct reg_settings_ois_t) *
+			(set_info->ois_params.setting_size),
+			GFP_KERNEL);
+		if (settings == NULL) {
+			pr_err("Error allocating memory\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(settings,
+			(void __user *)set_info->ois_params.settings,
+			set_info->ois_params.setting_size *
+			sizeof(struct reg_settings_ois_t))) {
+			kfree(settings);
+			pr_err("Error copying\n");
+			return -EFAULT;
+		}
+
+		rc = msm_ois_write_settings(o_ctrl,
+			set_info->ois_params.setting_size,
+			settings);
+
+		for (i = 0; i < set_info->ois_params.setting_size; i++) {
+			if (settings[i].i2c_operation
+				== MSM_OIS_READ) {
+				if (copy_to_user(
+					(void __user *)
+					(&set_info->ois_params.settings[i]),
+					&settings[i],
+					sizeof(struct reg_settings_ois_t))) {
+					kfree(settings);
+					pr_err("Error copying\n");
+					return -EFAULT;
+				}
+				CDBG("ois_data at addr 0x%x is 0x%x",
+				settings[i].reg_addr,
+				settings[i].reg_data);
+			}
+		}
+
+		kfree(settings);
+		if (rc < 0) {
+			pr_err("Error\n");
+			return -EFAULT;
+		}
+	}
+
+	CDBG("Exit\n");
+
+	return rc;
+}
+
+static int32_t msm_ois_config(struct msm_ois_ctrl_t *o_ctrl,
+	void *argp)
+{
+	struct msm_ois_cfg_data *cdata =
+		(struct msm_ois_cfg_data *)argp;
+	int32_t rc = 0;
+
+	mutex_lock(o_ctrl->ois_mutex);
+	CDBG("Enter\n");
+	CDBG("%s type %d\n", __func__, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CFG_OIS_INIT:
+		rc = msm_ois_init(o_ctrl);
+		if (rc < 0)
+			pr_err("msm_ois_init failed %d\n", rc);
+		break;
+	case CFG_OIS_POWERDOWN:
+		rc = msm_ois_power_down(o_ctrl);
+		if (rc < 0)
+			pr_err("msm_ois_power_down failed %d\n", rc);
+		break;
+	case CFG_OIS_POWERUP:
+		rc = msm_ois_power_up(o_ctrl);
+		if (rc < 0)
+			pr_err("Failed ois power up%d\n", rc);
+		break;
+	case CFG_OIS_CONTROL:
+		rc = msm_ois_control(o_ctrl, &cdata->cfg.set_info);
+		if (rc < 0)
+			pr_err("Failed ois control%d\n", rc);
+		break;
+	case CFG_OIS_I2C_WRITE_SEQ_TABLE: {
+		struct msm_camera_i2c_seq_reg_setting conf_array;
+		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+
+#ifdef CONFIG_COMPAT
+		if (is_compat_task()) {
+			memcpy(&conf_array,
+				(void *)cdata->cfg.settings,
+				sizeof(struct msm_camera_i2c_seq_reg_setting));
+		} else
+#endif
+		if (copy_from_user(&conf_array,
+			(void __user *)cdata->cfg.settings,
+			sizeof(struct msm_camera_i2c_seq_reg_setting))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
+		if (!conf_array.size ||
+			conf_array.size > I2C_SEQ_REG_DATA_MAX) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		reg_setting = kzalloc(conf_array.size *
+			(sizeof(struct msm_camera_i2c_seq_reg_array)),
+			GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+			(void __user *)conf_array.reg_setting,
+			conf_array.size *
+			sizeof(struct msm_camera_i2c_seq_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+
+		conf_array.reg_setting = reg_setting;
+		rc = o_ctrl->i2c_client.i2c_func_tbl->
+			i2c_write_seq_table(&o_ctrl->i2c_client,
+			&conf_array);
+		kfree(reg_setting);
+		break;
+	}
+	default:
+		break;
+	}
+	mutex_unlock(o_ctrl->ois_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+static int32_t msm_ois_config_download(struct msm_ois_ctrl_t *o_ctrl,
+	void *argp)
+{
+	struct msm_ois_cfg_download_data *cdata =
+		(struct msm_ois_cfg_download_data *)argp;
+	int32_t rc = 0;
+
+	if (!o_ctrl || !cdata) {
+		pr_err("failed: Invalid data\n");
+		return -EINVAL;
+	}
+	mutex_lock(o_ctrl->ois_mutex);
+	CDBG("Enter\n");
+	CDBG("%s type %d\n", __func__, cdata->cfgtype);
+	switch (cdata->cfgtype) {
+	case CFG_OIS_DATA_CONFIG:
+		rc = msm_ois_data_config(o_ctrl, &cdata->slave_info);
+		if (rc < 0)
+			pr_err("Failed ois data config %d\n", rc);
+		break;
+	case CFG_OIS_DOWNLOAD:
+		rc = msm_ois_download(o_ctrl);
+		if (rc < 0)
+			pr_err("Failed ois download %d\n", rc);
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(o_ctrl->ois_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+
+static int32_t msm_ois_get_subdev_id(struct msm_ois_ctrl_t *o_ctrl,
+	void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+
+	CDBG("Enter\n");
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		*subdev_id = o_ctrl->pdev->id;
+	else
+		*subdev_id = o_ctrl->subdev_id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	CDBG("Exit\n");
+	return 0;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq = msm_camera_cci_i2c_write_seq,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
+};
+
+static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq = msm_camera_qup_i2c_write_seq,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_qup_i2c_write_table_w_microdelay,
+	.i2c_poll = msm_camera_qup_i2c_poll,
+};
+
+static int msm_ois_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh) {
+	int rc = 0;
+	struct msm_ois_ctrl_t *o_ctrl =  v4l2_get_subdevdata(sd);
+
+	CDBG("Enter\n");
+	if (!o_ctrl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	mutex_lock(o_ctrl->ois_mutex);
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE &&
+		o_ctrl->ois_state != OIS_DISABLE_STATE) {
+		rc = o_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+			&o_ctrl->i2c_client, MSM_CCI_RELEASE);
+		if (rc < 0)
+			pr_err("cci_init failed\n");
+	}
+	o_ctrl->ois_state = OIS_DISABLE_STATE;
+	mutex_unlock(o_ctrl->ois_mutex);
+	CDBG("Exit\n");
+	return rc;
+}
+
+static const struct v4l2_subdev_internal_ops msm_ois_internal_ops = {
+	.close = msm_ois_close,
+};
+
+static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc;
+	struct msm_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd);
+	void *argp = (void *)arg;
+
+	CDBG("Enter\n");
+	CDBG("%s:%d o_ctrl %pK argp %pK\n", __func__, __LINE__, o_ctrl, argp);
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+		return msm_ois_get_subdev_id(o_ctrl, argp);
+	case VIDIOC_MSM_OIS_CFG:
+		return msm_ois_config(o_ctrl, argp);
+	case VIDIOC_MSM_OIS_CFG_DOWNLOAD:
+		return msm_ois_config_download(o_ctrl, argp);
+	case MSM_SD_SHUTDOWN:
+		if (!o_ctrl->i2c_client.i2c_func_tbl) {
+			pr_err("o_ctrl->i2c_client.i2c_func_tbl NULL\n");
+			return -EINVAL;
+		}
+		mutex_lock(o_ctrl->ois_mutex);
+		rc = msm_ois_power_down(o_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d OIS Power down failed\n",
+				__func__, __LINE__);
+		}
+		mutex_unlock(o_ctrl->ois_mutex);
+		return msm_ois_close(sd, NULL);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int32_t msm_ois_power_up(struct msm_ois_ctrl_t *o_ctrl)
+{
+	int rc = 0;
+	enum msm_sensor_power_seq_gpio_t gpio;
+
+	CDBG("%s called\n", __func__);
+
+	rc = msm_ois_vreg_control(o_ctrl, 1);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return rc;
+	}
+
+	for (gpio = SENSOR_GPIO_AF_PWDM;
+		gpio < SENSOR_GPIO_MAX; gpio++) {
+		if (o_ctrl->gconf && o_ctrl->gconf->gpio_num_info &&
+			o_ctrl->gconf->gpio_num_info->valid[gpio] == 1) {
+			rc = msm_camera_request_gpio_table(
+				o_ctrl->gconf->cam_gpio_req_tbl,
+				o_ctrl->gconf->cam_gpio_req_tbl_size, 1);
+			if (rc < 0) {
+				pr_err("ERR:%s:Failed in selecting state for ois: %d\n",
+					__func__, rc);
+				return rc;
+			}
+			if (o_ctrl->cam_pinctrl_status) {
+				rc = pinctrl_select_state(
+					o_ctrl->pinctrl_info.pinctrl,
+					o_ctrl->pinctrl_info.gpio_state_active);
+				if (rc < 0)
+					pr_err("ERR:%s:%d cannot set pin to active state: %d",
+						__func__, __LINE__, rc);
+			}
+
+			gpio_set_value_cansleep(
+				o_ctrl->gconf->gpio_num_info->gpio_num[gpio],
+				1);
+		}
+	}
+
+	o_ctrl->ois_state = OIS_ENABLE_STATE;
+	CDBG("Exit\n");
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_ois_subdev_core_ops = {
+	.ioctl = msm_ois_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_ois_subdev_ops = {
+	.core = &msm_ois_subdev_core_ops,
+};
+
+static const struct i2c_device_id msm_ois_i2c_id[] = {
+	{"qcom,ois", (kernel_ulong_t)NULL},
+	{ }
+};
+
+static int32_t msm_ois_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_ois_ctrl_t *ois_ctrl_t = NULL;
+
+	CDBG("Enter\n");
+
+	if (client == NULL) {
+		pr_err("msm_ois_i2c_probe: client is null\n");
+		return -EINVAL;
+	}
+
+	ois_ctrl_t = kzalloc(sizeof(struct msm_ois_ctrl_t),
+		GFP_KERNEL);
+	if (!ois_ctrl_t)
+		return -ENOMEM;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		rc = -EINVAL;
+		goto probe_failure;
+	}
+
+	CDBG("client = 0x%pK\n",  client);
+
+	rc = of_property_read_u32(client->dev.of_node, "cell-index",
+		&ois_ctrl_t->subdev_id);
+	CDBG("cell-index %d, rc %d\n", ois_ctrl_t->subdev_id, rc);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		goto probe_failure;
+	}
+
+	ois_ctrl_t->i2c_driver = &msm_ois_i2c_driver;
+	ois_ctrl_t->i2c_client.client = client;
+	/* Set device type as I2C */
+	ois_ctrl_t->ois_device_type = MSM_CAMERA_I2C_DEVICE;
+	ois_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl;
+	ois_ctrl_t->ois_v4l2_subdev_ops = &msm_ois_subdev_ops;
+	ois_ctrl_t->ois_mutex = &msm_ois_mutex;
+
+	/* Assign name for sub device */
+	snprintf(ois_ctrl_t->msm_sd.sd.name, sizeof(ois_ctrl_t->msm_sd.sd.name),
+		"%s", ois_ctrl_t->i2c_driver->driver.name);
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&ois_ctrl_t->msm_sd.sd,
+		ois_ctrl_t->i2c_client.client,
+		ois_ctrl_t->ois_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&ois_ctrl_t->msm_sd.sd, ois_ctrl_t);
+	ois_ctrl_t->msm_sd.sd.internal_ops = &msm_ois_internal_ops;
+	ois_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_pads_init(&ois_ctrl_t->msm_sd.sd.entity, 0, NULL);
+	ois_ctrl_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_OIS;
+	ois_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+	msm_sd_register(&ois_ctrl_t->msm_sd);
+	ois_ctrl_t->ois_state = OIS_DISABLE_STATE;
+	pr_info("msm_ois_i2c_probe: succeeded\n");
+	CDBG("Exit\n");
+
+probe_failure:
+	kfree(ois_ctrl_t);
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long msm_ois_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	long rc = 0;
+	struct video_device *vdev;
+	struct v4l2_subdev *sd;
+	struct msm_ois_cfg_data32 *u32;
+	struct msm_ois_cfg_data ois_data;
+	void *parg;
+	struct msm_camera_i2c_seq_reg_setting settings;
+	struct msm_camera_i2c_seq_reg_setting32 settings32;
+
+	if (!file || !arg) {
+		pr_err("%s:failed NULL parameter\n", __func__);
+		return -EINVAL;
+	}
+	vdev = video_devdata(file);
+	sd = vdev_to_v4l2_subdev(vdev);
+	u32 = (struct msm_ois_cfg_data32 *)arg;
+	parg = arg;
+
+	switch (cmd) {
+	case VIDIOC_MSM_OIS_CFG32:
+		cmd = VIDIOC_MSM_OIS_CFG;
+		ois_data.cfgtype = u32->cfgtype;
+
+		switch (u32->cfgtype) {
+		case CFG_OIS_CONTROL:
+			ois_data.cfg.set_info.ois_params.setting_size =
+				u32->cfg.set_info.ois_params.setting_size;
+			ois_data.cfg.set_info.ois_params.i2c_addr =
+				u32->cfg.set_info.ois_params.i2c_addr;
+			ois_data.cfg.set_info.ois_params.i2c_freq_mode =
+				u32->cfg.set_info.ois_params.i2c_freq_mode;
+			ois_data.cfg.set_info.ois_params.i2c_addr_type =
+				u32->cfg.set_info.ois_params.i2c_addr_type;
+			ois_data.cfg.set_info.ois_params.i2c_data_type =
+				u32->cfg.set_info.ois_params.i2c_data_type;
+			ois_data.cfg.set_info.ois_params.settings =
+				compat_ptr(u32->cfg.set_info.ois_params.
+				settings);
+			parg = &ois_data;
+			break;
+		case CFG_OIS_I2C_WRITE_SEQ_TABLE:
+			if (copy_from_user(&settings32,
+				(void __user *)compat_ptr(u32->cfg.settings),
+				sizeof(
+				struct msm_camera_i2c_seq_reg_setting32))) {
+				pr_err("copy_from_user failed\n");
+				return -EFAULT;
+			}
+
+			settings.addr_type = settings32.addr_type;
+			settings.delay = settings32.delay;
+			settings.size = settings32.size;
+
+			settings.reg_setting =
+				kzalloc(
+				sizeof(struct msm_camera_i2c_seq_reg_array),
+				GFP_KERNEL);
+			if (!settings.reg_setting)
+				return -ENOMEM;
+			if (copy_from_user(settings.reg_setting,
+				(void __user *)
+				compat_ptr(settings32.reg_setting),
+				sizeof(struct msm_camera_i2c_seq_reg_array))) {
+				pr_err("%s:%d failed\n", __func__, __LINE__);
+				return -EFAULT;
+			}
+
+			ois_data.cfg.settings = &settings;
+			parg = &ois_data;
+			break;
+		default:
+			parg = &ois_data;
+			break;
+		}
+		break;
+	case VIDIOC_MSM_OIS_CFG:
+		pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
+		return -EINVAL;
+	}
+	rc = msm_ois_subdev_ioctl(sd, cmd, parg);
+
+	return rc;
+}
+
+static long msm_ois_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_ois_subdev_do_ioctl);
+}
+#endif
+
+static int32_t msm_ois_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_camera_cci_client *cci_client = NULL;
+	struct msm_ois_ctrl_t *msm_ois_t = NULL;
+	struct msm_ois_vreg *vreg_cfg;
+
+	CDBG("Enter\n");
+
+	if (!pdev->dev.of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	msm_ois_t = kzalloc(sizeof(struct msm_ois_ctrl_t),
+		GFP_KERNEL);
+	if (!msm_ois_t)
+		return -ENOMEM;
+
+	msm_ois_t->oboard_info = kzalloc(sizeof(
+		struct msm_ois_board_info), GFP_KERNEL);
+	if (!msm_ois_t->oboard_info) {
+		kfree(msm_ois_t);
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+		&pdev->id);
+	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
+	if (rc < 0) {
+		pr_err("failed rc %d\n", rc);
+		goto release_memory;
+	}
+
+	rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master",
+		&msm_ois_t->cci_master);
+	CDBG("qcom,cci-master %d, rc %d\n", msm_ois_t->cci_master, rc);
+	if (rc < 0 || msm_ois_t->cci_master >= MASTER_MAX) {
+		pr_err("failed rc %d\n", rc);
+		goto release_memory;
+	}
+
+	if (of_find_property((&pdev->dev)->of_node,
+			"qcom,cam-vreg-name", NULL)) {
+		vreg_cfg = &msm_ois_t->vreg_cfg;
+		rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node,
+			&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+		if (rc < 0) {
+			pr_err("failed rc %d\n", rc);
+			goto release_memory;
+		}
+	}
+
+	rc = msm_sensor_driver_get_gpio_data(&(msm_ois_t->gconf),
+		(&pdev->dev)->of_node);
+	if (rc < 0) {
+		pr_err("%s: No/Error OIS GPIO\n", __func__);
+	} else {
+		msm_ois_t->cam_pinctrl_status = 1;
+		rc = msm_camera_pinctrl_init(
+			&(msm_ois_t->pinctrl_info), &(pdev->dev));
+		if (rc < 0) {
+			pr_err("ERR:%s: Error in reading OIS pinctrl\n",
+				__func__);
+			msm_ois_t->cam_pinctrl_status = 0;
+		}
+	}
+
+	msm_ois_t->ois_v4l2_subdev_ops = &msm_ois_subdev_ops;
+	msm_ois_t->ois_mutex = &msm_ois_mutex;
+
+	/* Set platform device handle */
+	msm_ois_t->pdev = pdev;
+	/* Set device type as platform device */
+	msm_ois_t->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	msm_ois_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+	msm_ois_t->i2c_client.cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!msm_ois_t->i2c_client.cci_client) {
+		kfree(msm_ois_t->vreg_cfg.cam_vreg);
+		rc = -ENOMEM;
+		goto release_memory;
+	}
+
+	cci_client = msm_ois_t->i2c_client.cci_client;
+	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = msm_ois_t->cci_master;
+	v4l2_subdev_init(&msm_ois_t->msm_sd.sd,
+		msm_ois_t->ois_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&msm_ois_t->msm_sd.sd, msm_ois_t);
+	msm_ois_t->msm_sd.sd.internal_ops = &msm_ois_internal_ops;
+	msm_ois_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(msm_ois_t->msm_sd.sd.name,
+		ARRAY_SIZE(msm_ois_t->msm_sd.sd.name), "msm_ois");
+	media_entity_pads_init(&msm_ois_t->msm_sd.sd.entity, 0, NULL);
+	msm_ois_t->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_OIS;
+	msm_ois_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+	msm_sd_register(&msm_ois_t->msm_sd);
+	msm_ois_t->ois_state = OIS_DISABLE_STATE;
+	msm_cam_copy_v4l2_subdev_fops(&msm_ois_v4l2_subdev_fops);
+#ifdef CONFIG_COMPAT
+	msm_ois_v4l2_subdev_fops.compat_ioctl32 =
+		msm_ois_subdev_fops_ioctl;
+#endif
+	msm_ois_t->msm_sd.sd.devnode->fops =
+		&msm_ois_v4l2_subdev_fops;
+
+	CDBG("Exit\n");
+	return rc;
+release_memory:
+	kfree(msm_ois_t->oboard_info);
+	kfree(msm_ois_t);
+	return rc;
+}
+
+static const struct of_device_id msm_ois_i2c_dt_match[] = {
+	{.compatible = "qcom,ois"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_ois_i2c_dt_match);
+
+static struct i2c_driver msm_ois_i2c_driver = {
+	.id_table = msm_ois_i2c_id,
+	.probe  = msm_ois_i2c_probe,
+	.remove = __exit_p(msm_ois_i2c_remove),
+	.driver = {
+		.name = "qcom,ois",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ois_i2c_dt_match,
+	},
+};
+
+static const struct of_device_id msm_ois_dt_match[] = {
+	{.compatible = "qcom,ois", .data = NULL},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_ois_dt_match);
+
+static struct platform_driver msm_ois_platform_driver = {
+	.probe = msm_ois_platform_probe,
+	.driver = {
+		.name = "qcom,ois",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ois_dt_match,
+	},
+};
+
+static int __init msm_ois_init_module(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter\n");
+	rc = platform_driver_register(&msm_ois_platform_driver);
+	if (!rc)
+		return rc;
+	CDBG("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&msm_ois_i2c_driver);
+}
+
+static void __exit msm_ois_exit_module(void)
+{
+	platform_driver_unregister(&msm_ois_platform_driver);
+	i2c_del_driver(&msm_ois_i2c_driver);
+}
+
+module_init(msm_ois_init_module);
+module_exit(msm_ois_exit_module);
+MODULE_DESCRIPTION("MSM OIS");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h
new file mode 100644
index 0000000..9cfd00c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_OIS_H
+#define MSM_OIS_H
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <soc/qcom/camera2.h>
+#include <media/v4l2-subdev.h>
+#include <media/msmb_camera.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+#define	MSM_OIS_MAX_VREGS (10)
+
+struct msm_ois_ctrl_t;
+
+enum msm_ois_state_t {
+	OIS_ENABLE_STATE,
+	OIS_OPS_ACTIVE,
+	OIS_OPS_INACTIVE,
+	OIS_DISABLE_STATE,
+};
+
+struct msm_ois_vreg {
+	struct camera_vreg_t *cam_vreg;
+	void *data[MSM_OIS_MAX_VREGS];
+	int num_vreg;
+};
+
+struct msm_ois_board_info {
+	char ois_name[MAX_OIS_NAME_SIZE];
+	uint32_t i2c_slaveaddr;
+	struct msm_ois_opcode opcode;
+};
+
+struct msm_ois_ctrl_t {
+	struct i2c_driver *i2c_driver;
+	struct platform_driver *pdriver;
+	struct platform_device *pdev;
+	struct msm_camera_i2c_client i2c_client;
+	enum msm_camera_device_type_t ois_device_type;
+	struct msm_sd_subdev msm_sd;
+	struct mutex *ois_mutex;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *ois_v4l2_subdev_ops;
+	void *user_data;
+	uint16_t i2c_tbl_index;
+	enum cci_i2c_master_t cci_master;
+	uint32_t subdev_id;
+	enum msm_ois_state_t ois_state;
+	struct msm_ois_vreg vreg_cfg;
+	struct msm_camera_gpio_conf *gconf;
+	struct msm_pinctrl_info pinctrl_info;
+	uint8_t cam_pinctrl_status;
+	struct msm_ois_board_info *oboard_info;
+};
+
+#endif
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 9d92acf..6dac1ed 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -217,12 +217,18 @@
 	SDEROT_DBG("w:%d h:%d fps:%d pixfmt:%8.8x yuv:%d res:%llu rd:%d\n",
 		width, height, fps, pixfmt, is_yuv, res, is_rd);
 
+	if (!is_yuv)
+		goto exit;
+
+	/*
+	 * If (total_source_pixels <= 62208000  && YUV) -> RD/WROT=2 //1080p30
+	 * If (total_source_pixels <= 124416000 && YUV) -> RD/WROT=4 //1080p60
+	 * If (total_source_pixels <= 2160p && YUV && FPS <= 30) -> RD/WROT = 32
+	 */
 	if (res <= (RES_1080p * 30))
 		ot_lim = 2;
 	else if (res <= (RES_1080p * 60))
 		ot_lim = 4;
-	else if (res <= (RES_UHD * 30))
-		ot_lim = 8;
 
 exit:
 	SDEROT_DBG("ot_lim=%d\n", ot_lim);
@@ -252,6 +258,8 @@
 	val &= (0xFF << bit_off);
 	val = val >> bit_off;
 
+	SDEROT_EVTLOG(val, ot_lim);
+
 	if (val == ot_lim)
 		ot_lim = 0;
 
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index b6f206e..3636aa1 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -575,9 +575,12 @@
 	case HAL_EXTRADATA_STREAM_USERDATA:
 		ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA;
 		break;
-	case HAL_EXTRADATA_FRAME_QP:
+	case HAL_EXTRADATA_DEC_FRAME_QP:
 		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA;
 		break;
+	case HAL_EXTRADATA_ENC_FRAME_QP:
+		ret = HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA;
+		break;
 	case HAL_EXTRADATA_FRAME_BITS_INFO:
 		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA;
 		break;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 44cc7dc..0881a30 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -856,6 +856,36 @@
 	return 0;
 }
 
+static int copy_nal_stream_format_caps_to_sessions(u32 nal_stream_format_value,
+		struct msm_vidc_capability *capabilities, u32 num_sessions,
+		u32 codecs, u32 domain) {
+	u32 i = 0;
+	struct msm_vidc_capability *capability;
+	u32 sess_codec;
+	u32 sess_domain;
+
+	for (i = 0; i < num_sessions; i++) {
+		sess_codec = 0;
+		sess_domain = 0;
+		capability = &capabilities[i];
+
+		if (capability->codec)
+			sess_codec =
+				vidc_get_hfi_codec(capability->codec);
+		if (capability->domain)
+			sess_domain =
+				vidc_get_hfi_domain(capability->domain);
+
+		if (!(sess_codec & codecs && sess_domain & domain))
+			continue;
+
+		capability->nal_stream_format.nal_stream_format_supported =
+				nal_stream_format_value;
+	}
+
+	return 0;
+}
+
 static enum vidc_status hfi_parse_init_done_properties(
 		struct msm_vidc_capability *capabilities,
 		u32 num_sessions, u8 *data_ptr, u32 num_properties,
@@ -984,6 +1014,15 @@
 		}
 		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
 		{
+			struct hfi_nal_stream_format_supported *prop =
+				(struct hfi_nal_stream_format_supported *)
+					(data_ptr + next_offset);
+
+			copy_nal_stream_format_caps_to_sessions(
+					prop->nal_stream_format_supported,
+					capabilities, num_sessions,
+					codecs, domain);
+
 			next_offset +=
 				sizeof(struct hfi_nal_stream_format_supported);
 			num_properties--;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index a80990c..be24f8d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -164,6 +164,15 @@
 	"Unlimited"
 };
 
+static const char *const mpeg_video_stream_format[] = {
+	"NAL Format Start Codes",
+	"NAL Format One NAL Per Buffer",
+	"NAL Format One Byte Length",
+	"NAL Format Two Byte Length",
+	"NAL Format Four Byte Length",
+	NULL
+};
+
 static struct msm_vidc_ctrl msm_venc_ctrls[] = {
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
@@ -675,7 +684,7 @@
 		.name = "Extradata Type",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
-		.maximum = V4L2_MPEG_VIDC_EXTRADATA_ROI_QP,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP,
 		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -695,7 +704,8 @@
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS)|
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP)
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP)|
+			(1UL << V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP)
 			),
 		.qmenu = mpeg_video_vidc_extradata,
 	},
@@ -1196,7 +1206,22 @@
 		.step = 1,
 		.qmenu = NULL,
 	},
-
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+		.name = "NAL Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+		),
+		.qmenu = mpeg_video_stream_format,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1357,6 +1382,7 @@
 	struct hal_vui_timing_info vui_timing_info = {0};
 	enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
 	u32 color_primaries, custom_matrix;
+	struct hal_nal_stream_format_select stream_format;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -1803,6 +1829,7 @@
 			break;
 		case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
 		case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP:
 		case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
 			inst->bufq[CAPTURE_PORT].num_planes = 2;
 			break;
@@ -2209,6 +2236,13 @@
 		vui_timing_info.time_scale = NSEC_PER_SEC;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+	{
+		property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+		stream_format.nal_stream_format_select = BIT(ctrl->val);
+		pdata = &stream_format;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
 	case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 349b982..b515ad4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -1523,6 +1523,11 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION:
 		ctrl->val = inst->capability.tme_version;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+		ctrl->val =
+			inst->capability.nal_stream_format.
+				nal_stream_format_supported;
+		break;
 	default:
 		/*
 		 * Other controls aren't really volatile, shouldn't need to
@@ -1613,6 +1618,7 @@
 	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_init(&inst->lock);
+	mutex_init(&inst->flush_lock);
 
 	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	INIT_MSM_VIDC_LIST(&inst->freqs);
@@ -1723,6 +1729,7 @@
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_destroy(&inst->lock);
+	mutex_destroy(&inst->flush_lock);
 
 	DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
@@ -1846,6 +1853,7 @@
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_destroy(&inst->lock);
+	mutex_destroy(&inst->flush_lock);
 
 	msm_vidc_debugfs_deinit_inst(inst);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 2d1ef10..0f74c7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -736,7 +736,7 @@
 
 	operating_rate = operating_rate >> 16;
 
-	if ((curr_operating_rate + ops_left) >= operating_rate ||
+	if ((curr_operating_rate * (1 + ops_left)) >= operating_rate ||
 			!msm_vidc_clock_scaling ||
 			inst->clk_data.buffer_counter < DCVS_FTB_WINDOW) {
 		dprintk(VIDC_DBG,
@@ -1018,9 +1018,10 @@
 		rc_mode =  msm_comm_g_ctrl_for_id(inst,
 				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
 		if (rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR ||
-			rc_mode ==
-				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR)
-			pdata.video_work_mode = VIDC_WORK_MODE_2;
+		    rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR ||
+		    rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR ||
+		    rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR)
+		pdata.video_work_mode = VIDC_WORK_MODE_2;
 	} else {
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index fd0fd39..a6af12a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -70,6 +70,7 @@
 	"Extradata display VUI",
 	"Extradata vpx color space",
 	"Extradata UBWC CR stats info",
+	"Extradata enc frame QP"
 };
 
 static void handle_session_error(enum hal_command_response cmd, void *data);
@@ -2044,6 +2045,7 @@
 		return;
 	}
 
+	mutex_lock(&inst->flush_lock);
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 
@@ -2086,6 +2088,7 @@
 	v4l2_event_queue_fh(&inst->event_handler, &flush_event);
 
 exit:
+	mutex_unlock(&inst->flush_lock);
 	put_inst(inst);
 }
 
@@ -3341,11 +3344,9 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&core->lock);
 	rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
 	if (rc)
 		dprintk(VIDC_WARN, "Failed to suspend\n");
-	mutex_unlock(&core->lock);
 
 	return rc;
 }
@@ -3919,13 +3920,17 @@
 		struct eos_buf *binfo = NULL;
 		u32 smem_flags = 0;
 
-		get_inst(inst->core, inst);
+		if (inst->state != MSM_VIDC_START_DONE) {
+			dprintk(VIDC_DBG,
+				"Inst = %pK is not ready for EOS\n", inst);
+			break;
+		}
 
 		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 		if (!binfo) {
 			dprintk(VIDC_ERR, "%s: Out of memory\n", __func__);
 			rc = -ENOMEM;
-			goto exit;
+			break;
 		}
 
 		if (inst->flags & VIDC_SECURE)
@@ -3935,26 +3940,25 @@
 				SZ_4K, 1, smem_flags,
 				HAL_BUFFER_INPUT, 0, &binfo->smem);
 		if (rc) {
+			kfree(binfo);
 			dprintk(VIDC_ERR,
 				"Failed to allocate output memory\n");
 			rc = -ENOMEM;
-			goto exit;
+			break;
 		}
 
 		mutex_lock(&inst->eosbufs.lock);
 		list_add_tail(&binfo->list, &inst->eosbufs.list);
 		mutex_unlock(&inst->eosbufs.lock);
 
-		if (inst->state != MSM_VIDC_START_DONE) {
-			dprintk(VIDC_DBG,
-				"Inst = %pK is not ready for EOS\n", inst);
-			goto exit;
-		}
-
 		rc = msm_vidc_send_pending_eos_buffers(inst);
-
-exit:
-		put_inst(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed pending_eos_buffers sending\n");
+			list_del(&binfo->list);
+			kfree(binfo);
+			break;
+		}
 		break;
 	}
 	default:
@@ -5116,6 +5120,7 @@
 		return 0;
 	}
 
+	mutex_lock(&inst->flush_lock);
 	/* enable in flush */
 	inst->in_flush = true;
 
@@ -5169,6 +5174,7 @@
 		rc = call_hfi_op(hdev, session_flush, inst->session,
 			HAL_FLUSH_OUTPUT);
 	}
+	mutex_unlock(&inst->flush_lock);
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"Sending flush to firmware failed, flush out all buffers\n");
@@ -5235,7 +5241,10 @@
 		ret = HAL_EXTRADATA_STREAM_USERDATA;
 		break;
 	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP:
-		ret = HAL_EXTRADATA_FRAME_QP;
+		ret = HAL_EXTRADATA_DEC_FRAME_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP:
+		ret = HAL_EXTRADATA_ENC_FRAME_QP;
 		break;
 	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO:
 		ret = HAL_EXTRADATA_FRAME_BITS_INFO;
@@ -6581,6 +6590,7 @@
 	bool found = false;
 	int i = 0;
 
+	mutex_lock(&inst->flush_lock);
 	mutex_lock(&inst->registeredbufs.lock);
 	found = false;
 	/* check if mbuf was not removed by any chance */
@@ -6661,6 +6671,7 @@
 			print_vidc_buffer(VIDC_ERR,
 				"rbr qbuf failed", inst, mbuf);
 	}
+	mutex_unlock(&inst->flush_lock);
 }
 
 int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index eda531e..90253fd 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -363,7 +363,7 @@
 
 struct msm_vidc_inst {
 	struct list_head list;
-	struct mutex sync_lock, lock;
+	struct mutex sync_lock, lock, flush_lock;
 	struct msm_vidc_core *core;
 	enum session_type session_type;
 	void *session;
@@ -429,7 +429,7 @@
 	s64 maximum;
 	s64 default_value;
 	u32 step;
-	u32 menu_skip_mask;
+	u64 menu_skip_mask;
 	u32 flags;
 	const char * const *qmenu;
 };
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index c84490f..cb581b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 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
@@ -179,7 +179,7 @@
 	},
 	{
 		.key = "qcom,max-hw-load",
-		.value = 1944000,
+		.value = 2009280,
 	},
 	{
 		.key = "qcom,max-hq-mbs-per-frame",
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 54cbdfc..2d9f3f1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -111,7 +111,8 @@
 	HAL_EXTRADATA_ASPECT_RATIO,
 	HAL_EXTRADATA_MPEG2_SEQDISP,
 	HAL_EXTRADATA_STREAM_USERDATA,
-	HAL_EXTRADATA_FRAME_QP,
+	HAL_EXTRADATA_DEC_FRAME_QP,
+	HAL_EXTRADATA_ENC_FRAME_QP,
 	HAL_EXTRADATA_FRAME_BITS_INFO,
 	HAL_EXTRADATA_INPUT_CROP,
 	HAL_EXTRADATA_DIGITAL_ZOOM,
diff --git a/drivers/media/platform/msm/vidc_3x/Kconfig b/drivers/media/platform/msm/vidc_3x/Kconfig
new file mode 100644
index 0000000..d95b0b5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/Kconfig
@@ -0,0 +1,10 @@
+#
+# VIDEO CORE
+#
+menuconfig MSM_VIDC_3X_V4L2
+	tristate "Qualcomm Technologies, Inc. MSM V4L2 3X based video driver"
+		depends on ARCH_QCOM && VIDEO_V4L2
+		select VIDEOBUF2_CORE
+
+source "drivers/media/platform/msm/vidc_3x/governors/Kconfig"
+source "drivers/media/platform/msm/vidc_3x/governors/Kconfig"
diff --git a/drivers/media/platform/msm/vidc_3x/Makefile b/drivers/media/platform/msm/vidc_3x/Makefile
new file mode 100644
index 0000000..749f057
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/Makefile
@@ -0,0 +1,18 @@
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) := 	msm_v4l2_vidc.o \
+				msm_vidc_common.o \
+				msm_vidc.o \
+				msm_vdec.o \
+				msm_venc.o \
+				msm_smem.o \
+				msm_vidc_debug.o \
+				msm_vidc_res_parse.o \
+				venus_hfi.o \
+				hfi_response_handler.o \
+				hfi_packetization.o \
+				vidc_hfi.o \
+				venus_boot.o \
+				msm_vidc_dcvs.o
+
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) += governors/
+
+obj-$(CONFIG_MSM_VIDC_VMEM) += vmem/
diff --git a/drivers/media/platform/msm/vidc_3x/governors/Kconfig b/drivers/media/platform/msm/vidc_3x/governors/Kconfig
new file mode 100644
index 0000000..4378088
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/Kconfig
@@ -0,0 +1,6 @@
+menuconfig MSM_VIDC_3X_GOVERNORS
+	tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver"
+	depends on MSM_VIDC_3X_V4L2 && PM_DEVFREQ
+	help
+	Chooses a set of devfreq governors aimed at providing accurate bandwidth
+	or clock frequency values for MSM V4L2 video driver.
diff --git a/drivers/media/platform/msm/vidc_3x/governors/Makefile b/drivers/media/platform/msm/vidc_3x/governors/Makefile
new file mode 100644
index 0000000..e834154
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -I$(srctree)/drivers/devfreq/ \
+	-I$(srctree)/drivers/media/platform/msm/vidc_3x/
+
+obj-$(CONFIG_MSM_VIDC_3X_GOVERNORS) := msm_vidc_dyn_gov.o \
+	msm_vidc_table_gov.o
diff --git a/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h b/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h
new file mode 100644
index 0000000..cbb1262
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015, 2018, 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.
+ */
+
+#ifdef _FIXP_ARITH_H
+#error "This implementation is meant to override fixp-arith.h, don't use both"
+#endif
+
+#ifndef __FP_H__
+#define __FP_H__
+
+/*
+ * Normally would typedef'ed, but checkpatch doesn't like typedef.
+ * Also should be normally typedef'ed to intmax_t but that doesn't seem to be
+ * available in the kernel
+ */
+#define fp_t size_t
+
+/* (Arbitrarily) make the first 25% of the bits to be the fractional bits */
+#define FP_FRACTIONAL_BITS ((sizeof(fp_t) * 8) / 4)
+
+#define FP(__i, __f_n, __f_d) \
+	((((fp_t)(__i)) << FP_FRACTIONAL_BITS) + \
+	(((__f_n) << FP_FRACTIONAL_BITS) / (__f_d)))
+
+#define FP_INT(__i) FP(__i, 0, 1)
+#define FP_ONE FP_INT(1)
+#define FP_ZERO FP_INT(0)
+
+static inline size_t fp_frac_base(void)
+{
+	return GENMASK(FP_FRACTIONAL_BITS - 1, 0);
+}
+
+static inline size_t fp_frac(fp_t a)
+{
+	return a & GENMASK(FP_FRACTIONAL_BITS - 1, 0);
+}
+
+static inline size_t fp_int(fp_t a)
+{
+	return a >> FP_FRACTIONAL_BITS;
+}
+
+static inline size_t fp_round(fp_t a)
+{
+	/* is the fractional part >= frac_max / 2? */
+	bool round_up = fp_frac(a) >= fp_frac_base() / 2;
+
+	return fp_int(a) + round_up;
+}
+
+static inline fp_t fp_mult(fp_t a, fp_t b)
+{
+	return (a * b) >> FP_FRACTIONAL_BITS;
+}
+
+
+static inline fp_t fp_div(fp_t a, fp_t b)
+{
+	return (a << FP_FRACTIONAL_BITS) / b;
+}
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c
new file mode 100644
index 0000000..3cbdee0
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c
@@ -0,0 +1,1154 @@
+/* Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "governor.h"
+#include "fixedpoint.h"
+#include "../msm_vidc_internal.h"
+#include "../msm_vidc_debug.h"
+#include "../vidc_hfi_api.h"
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+enum governor_mode {
+	GOVERNOR_DDR,
+	GOVERNOR_VMEM,
+	GOVERNOR_VMEM_PLUS,
+};
+
+struct governor {
+	enum governor_mode mode;
+	struct devfreq_governor devfreq_gov;
+};
+
+enum scenario {
+	SCENARIO_WORST,
+	SCENARIO_SUSTAINED_WORST,
+	SCENARIO_AVERAGE,
+	SCENARIO_MAX,
+};
+
+/*
+ * Minimum dimensions that the governor is willing to calculate
+ * bandwidth for.  This means that anything bandwidth(0, 0) ==
+ * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
+ */
+const struct {
+	int height, width;
+} BASELINE_DIMENSIONS = {
+	.width = 1280,
+	.height = 720,
+};
+
+/*
+ * These are hardcoded AB values that the governor votes for in certain
+ * situations, where a certain bus frequency is desired.  It isn't exactly
+ * scalable since different platforms have different bus widths, but we'll
+ * deal with that in the future.
+ */
+const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */,
+	SVS_BW_MBPS = 2000 /* ideally 100 Mhz */;
+
+/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
+#define kbps(__mbps) ((__mbps) * 1000)
+#define bps(__mbps) (kbps(__mbps) * 1000)
+
+#define GENERATE_SCENARIO_PROFILE(__average, __worst) {                        \
+	[SCENARIO_AVERAGE] = (__average),                                      \
+	[SCENARIO_WORST] =  (__worst),                                         \
+	[SCENARIO_SUSTAINED_WORST] = (__worst),                                \
+}
+
+#define GENERATE_COMPRESSION_PROFILE(__bpp, __average, __worst) {              \
+	.bpp = __bpp,                                                          \
+	.ratio = GENERATE_SCENARIO_PROFILE(__average, __worst),                \
+}
+
+/*
+ * The below table is a structural representation of the following table:
+ *  Resolution |    Bitrate |              Compression Ratio          |
+ * ............|............|.........................................|
+ * Width Height|Average High|Avg_8bpc Worst_8bpc Avg_10bpc Worst_10bpc|
+ *  1280    720|      7   14|    1.69       1.28      1.49        1.23|
+ *  1920   1080|     20   40|    1.69       1.28      1.49        1.23|
+ *  2560   1440|     32   64|     2.2       1.26      1.97        1.22|
+ *  3840   2160|     42   84|     2.2       1.26      1.97        1.22|
+ *  4096   2160|     44   88|     2.2       1.26      1.97        1.22|
+ *  4096   2304|     48   96|     2.2       1.26      1.97        1.22|
+ */
+#define COMPRESSION_RATIO_MAX 2
+static struct lut {
+	int frame_size; /* width x height */
+	unsigned long bitrate[SCENARIO_MAX];
+	struct {
+		int bpp;
+		fp_t ratio[SCENARIO_MAX];
+	} compression_ratio[COMPRESSION_RATIO_MAX];
+} const LUT[] = {
+	{
+		.frame_size = 1280 * 720,
+		.bitrate = GENERATE_SCENARIO_PROFILE(7, 14),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 69, 100),
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 1920 * 1088,
+		.bitrate = GENERATE_SCENARIO_PROFILE(20, 40),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 69, 100),
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 2560 * 1440,
+		.bitrate = GENERATE_SCENARIO_PROFILE(32, 64),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 3840 * 2160,
+		.bitrate = GENERATE_SCENARIO_PROFILE(42, 84),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2160,
+		.bitrate = GENERATE_SCENARIO_PROFILE(44, 88),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2304,
+		.bitrate = GENERATE_SCENARIO_PROFILE(48, 96),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+};
+
+static struct lut const *__lut(int width, int height)
+{
+	int frame_size = height * width, c = 0;
+
+	do {
+		if (LUT[c].frame_size >= frame_size)
+			return &LUT[c];
+	} while (++c < ARRAY_SIZE(LUT));
+
+	return &LUT[ARRAY_SIZE(LUT) - 1];
+}
+
+static fp_t __compression_ratio(struct lut const *entry, int bpp,
+		enum scenario s)
+{
+	int c = 0;
+
+	for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) {
+		if (entry->compression_ratio[c].bpp == bpp)
+			return entry->compression_ratio[c].ratio[s];
+	}
+
+	WARN(true, "Shouldn't be here, LUT possibly corrupted?\n");
+	return FP_ZERO; /* impossible */
+}
+
+#define DUMP_HEADER_MAGIC 0xdeadbeef
+#define DUMP_FP_FMT "%FP" /* special format for fp_t */
+struct dump {
+	char *key;
+	char *format;
+	size_t val;
+};
+
+static void __dump(struct dump dump[], int len)
+{
+	int c = 0;
+
+	for (c = 0; c < len; ++c) {
+		char format_line[128] = "", formatted_line[128] = "";
+
+		if (dump[c].val == DUMP_HEADER_MAGIC) {
+			snprintf(formatted_line, sizeof(formatted_line), "%s\n",
+					dump[c].key);
+		} else {
+			bool fp_format = !strcmp(dump[c].format, DUMP_FP_FMT);
+
+			if (!fp_format) {
+				snprintf(format_line, sizeof(format_line),
+						"    %-35s: %s\n", dump[c].key,
+						dump[c].format);
+				snprintf(formatted_line, sizeof(formatted_line),
+						format_line, dump[c].val);
+			} else {
+				size_t integer_part, fractional_part;
+
+				integer_part = fp_int(dump[c].val);
+				fractional_part = fp_frac(dump[c].val);
+				snprintf(formatted_line, sizeof(formatted_line),
+						"    %-35s: %zd + %zd/%zd\n",
+						dump[c].key, integer_part,
+						fractional_part,
+						fp_frac_base());
+
+
+			}
+		}
+
+		dprintk(VIDC_DBG, "%s", formatted_line);
+	}
+}
+
+static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	return 0;
+}
+
+static bool __ubwc(enum hal_uncompressed_format f)
+{
+	switch (f) {
+	case HAL_COLOR_FORMAT_NV12_UBWC:
+	case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int __bpp(enum hal_uncompressed_format f)
+{
+	switch (f) {
+	case HAL_COLOR_FORMAT_NV12:
+	case HAL_COLOR_FORMAT_NV21:
+	case HAL_COLOR_FORMAT_NV12_UBWC:
+		return 8;
+	case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
+		return 10;
+	default:
+		dprintk(VIDC_ERR,
+				"What's this?  We don't support this colorformat (%x)",
+				f);
+		return INT_MAX;
+	}
+}
+
+static unsigned long __calculate_vmem_plus_ab(struct vidc_bus_vote_data *d)
+{
+	unsigned long i = 0, vmem_plus = 0;
+
+	if (!d->imem_ab_tbl || !d->imem_ab_tbl_size) {
+		vmem_plus = 1; /* Vote for the min ab value */
+		goto exit;
+	}
+
+	/* Pick up vmem frequency based on venus core frequency */
+	for (i = 0; i < d->imem_ab_tbl_size; i++) {
+		if (d->imem_ab_tbl[i].core_freq == d->core_freq) {
+			vmem_plus = d->imem_ab_tbl[i].imem_ab;
+			break;
+		}
+	}
+
+	/* Incase we get an unsupported freq throw a warning
+	 * and set ab to the minimum value.
+	 */
+	if (!vmem_plus) {
+		vmem_plus = 1;
+		dprintk(VIDC_WARN,
+			"could not calculate vmem ab value due to core freq mismatch\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+
+exit:
+	return vmem_plus;
+}
+
+
+static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
+		enum governor_mode gm) {
+	/*
+	 * XXX: Don't fool around with any of the hardcoded numbers unless you
+	 * know /exactly/ what you're doing.  Many of these numbers are
+	 * measured heuristics and hardcoded numbers taken from the firmware.
+	 */
+	/* Decoder parameters */
+	enum scenario scenario;
+	int width, height, lcu_size, dpb_bpp, opb_bpp, fps;
+	bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled;
+	fp_t dpb_opb_scaling_ratio, dpb_compression_factor,
+		opb_compression_factor, qsmmu_bw_overhead_factor;
+	int vmem_size; /* in kB */
+
+	/* Derived parameters */
+	int lcu_per_frame, tnbr_per_lcu_10bpc, tnbr_per_lcu_8bpc, tnbr_per_lcu,
+		colocated_bytes_per_lcu, vmem_line_buffer, vmem_chroma_cache,
+		vmem_luma_cache, vmem_chroma_luma_cache;
+	unsigned long bitrate;
+	fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor,
+		ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor,
+		ocmem_usage_lcu_factor, ref_ocmem_bw_factor_read,
+		ref_ocmem_bw_factor_write, bw_for_1x_8bpc, dpb_bw_for_1x,
+		motion_vector_complexity, row_cache_penalty, opb_bw;
+
+	/* Output parameters */
+	struct {
+		fp_t vsp_read, vsp_write, collocated_read, collocated_write,
+			line_buffer_read, line_buffer_write, recon_read,
+			recon_write, opb_read, opb_write, dpb_read, dpb_write,
+			total;
+	} ddr, vmem;
+
+	unsigned long ret = 0;
+
+	/* Decoder parameters setup */
+	scenario = SCENARIO_WORST;
+
+	width = max(d->width, BASELINE_DIMENSIONS.width);
+	height = max(d->height, BASELINE_DIMENSIONS.height);
+
+	lcu_size = 32;
+
+	dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
+	opb_bpp = d->num_formats >= 2 ?  __bpp(d->color_formats[1]) : dpb_bpp;
+
+	fps = d->fps;
+
+	unified_dpb_opb = d->num_formats == 1;
+
+	dpb_opb_scaling_ratio = FP_ONE;
+
+	dpb_compression_enabled = d->num_formats >= 1 &&
+		__ubwc(d->color_formats[0]);
+	opb_compression_enabled = d->num_formats >= 2 &&
+		__ubwc(d->color_formats[1]);
+
+	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height), dpb_bpp, scenario);
+
+	opb_compression_factor = !opb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height), opb_bpp, scenario);
+
+	vmem_size = 512; /* in kB */
+
+	/* Derived parameters setup */
+	lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
+		DIV_ROUND_UP(height, lcu_size);
+
+	bitrate = __lut(width, height)->bitrate[scenario];
+
+	bins_to_bit_factor = FP(1, 60, 100);
+
+	dpb_write_factor = scenario == SCENARIO_AVERAGE ?
+		FP_ONE : FP(1, 5, 100);
+
+	ten_bpc_packing_factor = FP(1, 67, 1000);
+	ten_bpc_bpp_factor = FP(1, 1, 4);
+
+	vsp_read_factor = bins_to_bit_factor + FP_INT(2);
+	vsp_write_factor = bins_to_bit_factor;
+
+	tnbr_per_lcu_10bpc = lcu_size == 16 ? 384 + 192 :
+				lcu_size == 32 ? 640 + 256 :
+						1280 + 384;
+	tnbr_per_lcu_8bpc = lcu_size == 16 ? 256 + 192 :
+				lcu_size == 32 ? 512 + 256 :
+						1024 + 384;
+	tnbr_per_lcu = dpb_bpp == 10 ? tnbr_per_lcu_10bpc : tnbr_per_lcu_8bpc;
+
+	colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
+				lcu_size == 32 ? 64 : 256;
+
+	ocmem_usage_lcu_factor = lcu_size == 16 ? FP(1, 8, 10) :
+				lcu_size == 32 ? FP(1, 2, 10) :
+						FP_ONE;
+	ref_ocmem_bw_factor_read = vmem_size < 296 ? FP_ZERO :
+				vmem_size < 648 ? FP(0, 1, 4) :
+						FP(0, 55, 100);
+	ref_ocmem_bw_factor_write = vmem_size < 296 ? FP_ZERO :
+				vmem_size < 648 ? FP(0, 7, 10) :
+						FP(1, 4, 10);
+
+	/* Prelim b/w calculation */
+	bw_for_1x_8bpc = fp_mult(FP_INT(width * height * fps),
+			fp_mult(FP(1, 50, 100), dpb_write_factor));
+	bw_for_1x_8bpc = fp_div(bw_for_1x_8bpc, FP_INT(bps(1)));
+
+	dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+		fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+					ten_bpc_bpp_factor));
+	/* VMEM adjustments */
+	vmem_line_buffer = tnbr_per_lcu * DIV_ROUND_UP(width, lcu_size) / 1024;
+	vmem_chroma_cache = dpb_bpp == 10 ? 176 : 128;
+	vmem_luma_cache = dpb_bpp == 10 ? 353 : 256;
+	vmem_chroma_luma_cache = vmem_chroma_cache + vmem_luma_cache;
+
+	motion_vector_complexity = scenario == SCENARIO_AVERAGE ?
+		FP(2, 66, 100) : FP_INT(4);
+
+	row_cache_penalty = FP_ZERO;
+	if (vmem_size < vmem_line_buffer + vmem_chroma_cache)
+		row_cache_penalty = fp_mult(FP(0, 5, 100),
+				motion_vector_complexity);
+	else if (vmem_size < vmem_line_buffer + vmem_luma_cache)
+		row_cache_penalty = fp_mult(FP(0, 7, 100),
+				motion_vector_complexity);
+	else if (vmem_size < vmem_line_buffer + vmem_chroma_cache
+			+ vmem_luma_cache)
+		row_cache_penalty = fp_mult(FP(0, 3, 100),
+				motion_vector_complexity);
+	else
+		row_cache_penalty = FP_ZERO;
+
+
+	opb_bw = unified_dpb_opb ? FP_ZERO :
+		fp_div(fp_div(bw_for_1x_8bpc, dpb_opb_scaling_ratio),
+				opb_compression_factor);
+
+	/* B/W breakdown on a per buffer type basis for VMEM */
+	vmem.vsp_read = FP_ZERO;
+	vmem.vsp_write = FP_ZERO;
+
+	vmem.collocated_read = FP_ZERO;
+	vmem.collocated_write = FP_ZERO;
+
+	vmem.line_buffer_read = FP_INT(tnbr_per_lcu *
+			lcu_per_frame * fps / bps(1));
+	vmem.line_buffer_write = vmem.line_buffer_read;
+
+	vmem.recon_read = FP_ZERO;
+	vmem.recon_write = FP_ZERO;
+
+	vmem.opb_read = FP_ZERO;
+	vmem.opb_write = FP_ZERO;
+
+	vmem.dpb_read = fp_mult(ocmem_usage_lcu_factor, fp_mult(
+					ref_ocmem_bw_factor_read,
+					dpb_bw_for_1x));
+	vmem.dpb_write = fp_mult(ocmem_usage_lcu_factor, fp_mult(
+					ref_ocmem_bw_factor_write,
+					dpb_bw_for_1x));
+
+	vmem.total = vmem.vsp_read + vmem.vsp_write +
+		vmem.collocated_read + vmem.collocated_write +
+		vmem.line_buffer_read + vmem.line_buffer_write +
+		vmem.recon_read + vmem.recon_write +
+		vmem.opb_read + vmem.opb_write +
+		vmem.dpb_read + vmem.dpb_write;
+
+	/*
+	 * Attempt to force VMEM to a certain frequency for 4K
+	 */
+	if (width * height * fps >= 3840 * 2160 * 60)
+		vmem.total = FP_INT(NOMINAL_BW_MBPS);
+	else if (width * height * fps >= 3840 * 2160 * 30)
+		vmem.total = FP_INT(SVS_BW_MBPS);
+
+	/* ........................................ for DDR */
+	ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate),
+				vsp_read_factor), FP_INT(8));
+	ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate),
+				vsp_write_factor), FP_INT(8));
+
+	ddr.collocated_read = FP_INT(lcu_per_frame *
+			colocated_bytes_per_lcu * fps / bps(1));
+	ddr.collocated_write = FP_INT(lcu_per_frame *
+			colocated_bytes_per_lcu * fps / bps(1));
+
+	ddr.line_buffer_read = vmem_size ? FP_ZERO : vmem.line_buffer_read;
+	ddr.line_buffer_write = vmem_size ? FP_ZERO : vmem.line_buffer_write;
+
+	ddr.recon_read = FP_ZERO;
+	ddr.recon_write = fp_div(dpb_bw_for_1x, dpb_compression_factor);
+
+	ddr.opb_read = FP_ZERO;
+	ddr.opb_write = opb_bw;
+
+	ddr.dpb_read = fp_div(fp_mult(dpb_bw_for_1x,
+				motion_vector_complexity + row_cache_penalty),
+			dpb_compression_factor);
+	ddr.dpb_write = FP_ZERO;
+
+	ddr.total = ddr.vsp_read + ddr.vsp_write +
+		ddr.collocated_read + ddr.collocated_write +
+		ddr.line_buffer_read + ddr.line_buffer_write +
+		ddr.recon_read + ddr.recon_write +
+		ddr.opb_read + ddr.opb_write +
+		ddr.dpb_read + ddr.dpb_write;
+
+	qsmmu_bw_overhead_factor = FP(1, 3, 100);
+	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+
+	/* Dump all the variables for easier debugging */
+	if (debug) {
+		struct dump dump[] = {
+		{"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"content", "%d", scenario},
+		{"LCU size", "%d", lcu_size},
+		{"DPB bitdepth", "%d", dpb_bpp},
+		{"frame rate", "%d", fps},
+		{"DPB/OPB unified", "%d", unified_dpb_opb},
+		{"DPB/OPB downscaling ratio", DUMP_FP_FMT,
+			dpb_opb_scaling_ratio},
+		{"DPB compression", "%d", dpb_compression_enabled},
+		{"OPB compression", "%d", opb_compression_enabled},
+		{"DPB compression factor", DUMP_FP_FMT,
+			dpb_compression_factor},
+		{"OPB compression factor", DUMP_FP_FMT,
+			opb_compression_factor},
+		{"VMEM size", "%dkB", vmem_size},
+		{"frame width", "%d", width},
+		{"frame height", "%d", height},
+
+		{"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC},
+		{"LCUs/frame", "%d", lcu_per_frame},
+		{"bitrate (Mbit/sec)", "%d", bitrate},
+		{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
+		{"DPB write factor", DUMP_FP_FMT, dpb_write_factor},
+		{"10bpc packing factor", DUMP_FP_FMT,
+			ten_bpc_packing_factor},
+		{"10bpc,BPP factor", DUMP_FP_FMT, ten_bpc_bpp_factor},
+		{"VSP read factor", DUMP_FP_FMT, vsp_read_factor},
+		{"VSP write factor", DUMP_FP_FMT, vsp_write_factor},
+		{"TNBR/LCU_10bpc", "%d", tnbr_per_lcu_10bpc},
+		{"TNBR/LCU_8bpc", "%d", tnbr_per_lcu_8bpc},
+		{"TNBR/LCU", "%d", tnbr_per_lcu},
+		{"colocated bytes/LCU", "%d", colocated_bytes_per_lcu},
+		{"OCMEM usage LCU factor", DUMP_FP_FMT,
+			ocmem_usage_lcu_factor},
+		{"ref OCMEM b/w factor (read)", DUMP_FP_FMT,
+			ref_ocmem_bw_factor_read},
+		{"ref OCMEM b/w factor (write)", DUMP_FP_FMT,
+			ref_ocmem_bw_factor_write},
+		{"B/W for 1x (NV12 8bpc)", DUMP_FP_FMT, bw_for_1x_8bpc},
+		{"DPB B/W For 1x (NV12)", DUMP_FP_FMT, dpb_bw_for_1x},
+
+		{"VMEM", "", DUMP_HEADER_MAGIC},
+		{"line buffer", "%d", vmem_line_buffer},
+		{"chroma cache", "%d", vmem_chroma_cache},
+		{"luma cache", "%d", vmem_luma_cache},
+		{"luma & chroma cache", "%d", vmem_chroma_luma_cache},
+
+		{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
+		{"MV complexity", DUMP_FP_FMT, motion_vector_complexity},
+		{"row cache penalty", DUMP_FP_FMT, row_cache_penalty},
+		{"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw},
+
+		{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
+		{"VSP write", DUMP_FP_FMT, ddr.vsp_write},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
+		{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
+		{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
+		{"recon read", DUMP_FP_FMT, ddr.recon_read},
+		{"recon write", DUMP_FP_FMT, ddr.recon_write},
+		{"OPB read", DUMP_FP_FMT, ddr.opb_read},
+		{"OPB write", DUMP_FP_FMT, ddr.opb_write},
+		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
+		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+
+		{"INTERMEDIATE VMEM B/W", "", DUMP_HEADER_MAGIC},
+		{"VSP read", "%d", vmem.vsp_read},
+		{"VSP write", DUMP_FP_FMT, vmem.vsp_write},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
+		{"collocated write", DUMP_FP_FMT, vmem.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
+		{"line buffer write", DUMP_FP_FMT, vmem.line_buffer_write},
+		{"recon read", DUMP_FP_FMT, vmem.recon_read},
+		{"recon write", DUMP_FP_FMT, vmem.recon_write},
+		{"OPB read", DUMP_FP_FMT, vmem.opb_read},
+		{"OPB write", DUMP_FP_FMT, vmem.opb_write},
+		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
+		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
+		};
+		__dump(dump, ARRAY_SIZE(dump));
+	}
+
+	switch (gm) {
+	case GOVERNOR_DDR:
+		ret = kbps(fp_round(ddr.total));
+		break;
+	case GOVERNOR_VMEM:
+		ret = kbps(fp_round(vmem.total));
+		break;
+	case GOVERNOR_VMEM_PLUS:
+		ret = __calculate_vmem_plus_ab(d);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
+	}
+
+	return ret;
+}
+
+
+static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	/*
+	 * XXX: Don't fool around with any of the hardcoded numbers unless you
+	 * know /exactly/ what you're doing.  Many of these numbers are
+	 * measured heuristics and hardcoded numbers taken from the firmware.
+	 */
+	/* Encoder Parameters */
+	enum scenario scenario, bitrate_scenario;
+	enum hal_video_codec standard;
+	int width, height, fps, vmem_size;
+	enum hal_uncompressed_format dpb_color_format;
+	enum hal_uncompressed_format original_color_format;
+	bool dpb_compression_enabled, original_compression_enabled,
+		two_stage_encoding, low_power, rotation, cropping_or_scaling;
+	fp_t dpb_compression_factor, original_compression_factor,
+		qsmmu_bw_overhead_factor;
+	bool b_frames_enabled;
+
+	/* Derived Parameters */
+	int lcu_size;
+	enum gop {
+		GOP_IBBP,
+		GOP_IPPP,
+	} gop;
+	unsigned long bitrate;
+	fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
+		 chroma_luma_factor_original, one_frame_bw_original,
+		 line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
+		 original_vmem_requirement, bw_increase_p, bw_increase_b;
+	int collocated_mv_per_lcu, max_transaction_size,
+		search_window_size_vertical_p, search_window_factor_p,
+		search_window_factor_bw_p, vmem_size_p, available_vmem_p,
+		search_window_size_vertical_b, search_window_factor_b,
+		search_window_factor_bw_b, vmem_size_b, available_vmem_b;
+
+	/* Output paramaters */
+	struct {
+		fp_t vsp_read, vsp_write, collocated_read, collocated_write,
+			line_buffer_read, line_buffer_write, original_read,
+			original_write, dpb_read, dpb_write, total;
+	} ddr, vmem;
+
+	unsigned long ret = 0;
+
+	/* Encoder Parameters setup */
+	scenario = SCENARIO_WORST;
+
+	standard = d->codec;
+	width = max(d->width, BASELINE_DIMENSIONS.width);
+	height = max(d->height, BASELINE_DIMENSIONS.height);
+
+	dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
+	original_color_format = d->num_formats >= 1 ?
+		d->color_formats[0] : HAL_UNUSED_COLOR;
+
+	fps = d->fps;
+	bitrate_scenario = SCENARIO_WORST;
+
+	dpb_compression_enabled = __ubwc(dpb_color_format);
+	original_compression_enabled = __ubwc(original_color_format);
+
+	two_stage_encoding = false;
+	low_power = d->power_mode == VIDC_POWER_LOW;
+	b_frames_enabled = false;
+
+	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height),
+				__bpp(dpb_color_format), scenario);
+	original_compression_factor = !original_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height),
+				__bpp(original_color_format), scenario);
+
+	rotation = false;
+	cropping_or_scaling = false;
+	vmem_size = 512; /* in kB */
+
+	/* Derived Parameters */
+	lcu_size = 16;
+	gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
+	bitrate = __lut(width, height)->bitrate[bitrate_scenario];
+	bins_to_bit_factor = FP(1, 6, 10);
+
+	/*
+	 * FIXME: Minor color format related hack: a lot of the derived params
+	 * depend on the YUV bitdepth as a variable.  However, we don't have
+	 * appropriate enums defined yet (hence no support).  As a result omit
+	 * a lot of the checks (which should look like the snippet below) in
+	 * favour of hardcoding.
+	 *      dpb_color_format == YUV420 ? 0.5 :
+	 *      dpb_color_format == YUV422 ? 1.0 : 2.0
+	 * Similar hacks are annotated inline in code with the string "CF hack"
+	 * for documentation purposes.
+	 */
+	chroma_luma_factor_dpb = FP(0, 1, 2);
+	one_frame_bw_dpb = fp_mult(FP_ONE + chroma_luma_factor_dpb,
+			fp_div(FP_INT(width * height * fps),
+				FP_INT(1000 * 1000)));
+
+	chroma_luma_factor_original = FP(0, 1, 2); /* XXX: CF hack */
+	one_frame_bw_original = fp_mult(FP_ONE + chroma_luma_factor_original,
+			fp_div(FP_INT(width * height * fps),
+				FP_INT(1000 * 1000)));
+
+	line_buffer_size_per_lcu = FP_ZERO;
+	if (lcu_size == 16)
+		line_buffer_size_per_lcu = FP_INT(128) + fp_mult(FP_INT(256),
+					FP_ONE /*XXX: CF hack */);
+	else
+		line_buffer_size_per_lcu = FP_INT(192) + fp_mult(FP_INT(512),
+					FP_ONE /*XXX: CF hack */);
+
+	line_buffer_size = fp_div(
+			fp_mult(FP_INT(width / lcu_size),
+				line_buffer_size_per_lcu),
+			FP_INT(1024));
+	line_buffer_bw = fp_mult(line_buffer_size,
+			fp_div(FP_INT((height / lcu_size /
+				(two_stage_encoding ? 2 : 1) - 1) * fps),
+				FP_INT(1000)));
+
+	collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
+	max_transaction_size = 256;
+
+	original_vmem_requirement = FP_INT(3 *
+			(two_stage_encoding ? 2 : 1) * lcu_size);
+	original_vmem_requirement = fp_mult(original_vmem_requirement,
+			(FP_ONE + chroma_luma_factor_original));
+	original_vmem_requirement += FP_INT((cropping_or_scaling ? 3 : 0) * 2);
+	original_vmem_requirement = fp_mult(original_vmem_requirement,
+			FP_INT(max_transaction_size));
+	original_vmem_requirement = fp_div(original_vmem_requirement,
+			FP_INT(1024));
+
+	search_window_size_vertical_p = low_power ? 32 :
+					b_frames_enabled ? 80 :
+					width > 2048 ? 64 : 48;
+	search_window_factor_p = search_window_size_vertical_p * 2 / lcu_size;
+	search_window_factor_bw_p = !two_stage_encoding ?
+		search_window_size_vertical_p * 2 / lcu_size + 1 :
+		(search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
+	vmem_size_p = (search_window_factor_p * width + 128 * 2) *
+		lcu_size / 2 / 1024; /* XXX: CF hack */
+	bw_increase_p = fp_mult(one_frame_bw_dpb,
+			FP_INT(search_window_factor_bw_p - 1) / 3);
+	available_vmem_p = min_t(int, 3, (vmem_size - fp_int(line_buffer_size) -
+			fp_int(original_vmem_requirement)) / vmem_size_p);
+
+	search_window_size_vertical_b = 48;
+	search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
+	search_window_factor_bw_b = !two_stage_encoding ?
+		search_window_size_vertical_b * 2 / lcu_size + 1 :
+		(search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
+	vmem_size_b = (search_window_factor_b * width + 128 * 2) * lcu_size /
+		2 / 1024;
+	bw_increase_b = fp_mult(one_frame_bw_dpb,
+			FP_INT((search_window_factor_bw_b - 1) / 3));
+	available_vmem_b = min_t(int, 6, (vmem_size - fp_int(line_buffer_size) -
+			fp_int(original_vmem_requirement)) / vmem_size_b);
+
+	/* Output parameters for DDR */
+	ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
+			bins_to_bit_factor);
+	ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
+
+	ddr.collocated_read = fp_div(FP_INT(DIV_ROUND_UP(width, lcu_size) *
+			DIV_ROUND_UP(height, lcu_size) *
+			collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
+	ddr.collocated_write = ddr.collocated_read;
+
+	ddr.line_buffer_read = (FP_INT(vmem_size) >= line_buffer_size +
+		original_vmem_requirement) ? FP_ZERO : line_buffer_bw;
+	ddr.line_buffer_write = ddr.line_buffer_read;
+
+	ddr.original_read = fp_div(one_frame_bw_original,
+			original_compression_factor);
+	ddr.original_write = FP_ZERO;
+
+	ddr.dpb_read = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		ddr.dpb_read = one_frame_bw_dpb + fp_mult(bw_increase_p,
+			FP_INT(3 - available_vmem_p));
+	} else if (scenario == SCENARIO_WORST ||
+			scenario == SCENARIO_SUSTAINED_WORST) {
+		ddr.dpb_read = fp_mult(one_frame_bw_dpb, FP_INT(2));
+		ddr.dpb_read += fp_mult(FP_INT(6 - available_vmem_b),
+				bw_increase_b);
+	} else {
+		fp_t part_p, part_b;
+
+		part_p = one_frame_bw_dpb + fp_mult(bw_increase_p,
+				FP_INT(3 - available_vmem_p));
+		part_p = fp_div(part_p, FP_INT(3));
+
+		part_b = fp_mult(one_frame_bw_dpb, 2) +
+			fp_mult(FP_INT(6 - available_vmem_b), bw_increase_b);
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		ddr.dpb_read = part_p + part_b;
+	}
+
+	ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
+	ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
+
+	ddr.total = ddr.vsp_read + ddr.vsp_write +
+		ddr.collocated_read + ddr.collocated_write +
+		ddr.line_buffer_read + ddr.line_buffer_write +
+		ddr.original_read + ddr.original_write +
+		ddr.dpb_read + ddr.dpb_write;
+
+	qsmmu_bw_overhead_factor = FP(1, 3, 100);
+	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+
+	/* ................. for VMEM */
+	vmem.vsp_read = FP_ZERO;
+	vmem.vsp_write = FP_ZERO;
+
+	vmem.collocated_read = FP_ZERO;
+	vmem.collocated_write = FP_ZERO;
+
+	vmem.line_buffer_read = line_buffer_bw - ddr.line_buffer_read;
+	vmem.line_buffer_write = vmem.line_buffer_read;
+
+	vmem.original_read = FP_INT(vmem_size) >= original_vmem_requirement ?
+		ddr.original_read : FP_ZERO;
+	vmem.original_write = vmem.original_read;
+
+	vmem.dpb_read = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+			FP_INT(search_window_factor_bw_p * available_vmem_p));
+		temp = fp_div(temp, FP_INT(3));
+
+		vmem.dpb_read = temp;
+	} else if (scenario != SCENARIO_AVERAGE) {
+		fp_t temp = fp_mult(one_frame_bw_dpb, FP_INT(2));
+
+		temp = fp_mult(temp, FP_INT(search_window_factor_bw_b *
+					available_vmem_b));
+		temp = fp_div(temp, FP_INT(6));
+
+		vmem.dpb_read = temp;
+	} else {
+		fp_t part_p, part_b;
+
+		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
+					search_window_factor_bw_p *
+					available_vmem_p));
+		part_p = fp_div(part_p, FP_INT(3 * 3));
+
+		part_b = fp_mult(one_frame_bw_dpb, FP_INT(2 *
+					search_window_factor_bw_b *
+					available_vmem_b));
+		part_b = fp_div(part_b, FP_INT(6));
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		vmem.dpb_read = part_p + part_b;
+	}
+
+	vmem.dpb_write = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+				FP_INT(available_vmem_p));
+		temp = fp_div(temp, FP_INT(3));
+
+		vmem.dpb_write = temp;
+	} else if (scenario != SCENARIO_AVERAGE) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+				FP_INT(2 * available_vmem_b));
+		temp = fp_div(temp, FP_INT(6));
+
+		vmem.dpb_write = temp;
+	} else {
+		fp_t part_b, part_p;
+
+		part_b = fp_mult(one_frame_bw_dpb, FP_INT(available_vmem_p));
+		part_b = fp_div(part_b, FP_INT(9));
+
+		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
+					2 * available_vmem_b));
+		part_p = fp_div(part_p, FP_INT(6));
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		vmem.dpb_write = part_p + part_b;
+	}
+
+	vmem.total = vmem.vsp_read + vmem.vsp_write +
+		vmem.collocated_read + vmem.collocated_write +
+		vmem.line_buffer_read + vmem.line_buffer_write +
+		vmem.original_read + vmem.original_write +
+		vmem.dpb_read + vmem.dpb_write;
+
+	/*
+	 * When in low power mode, attempt to force the VMEM clocks a certain
+	 * frequency that DCVS would prefer
+	 */
+	if (width * height >= 3840 * 2160 && low_power)
+		vmem.total = FP_INT(NOMINAL_BW_MBPS);
+
+	if (debug) {
+		struct dump dump[] = {
+		{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"scenario", "%d", scenario},
+		{"standard", "%#x", standard},
+		{"width", "%d", width},
+		{"height", "%d", height},
+		{"DPB format", "%#x", dpb_color_format},
+		{"original frame format", "%#x", original_color_format},
+		{"fps", "%d", fps},
+		{"target bitrate", "%d", bitrate_scenario},
+		{"DPB compression enable", "%d", dpb_compression_enabled},
+		{"original compression enable", "%d",
+			original_compression_enabled},
+		{"two stage encoding", "%d", two_stage_encoding},
+		{"low power mode", "%d", low_power},
+		{"DPB compression factor", DUMP_FP_FMT,
+			dpb_compression_factor},
+		{"original compression factor", DUMP_FP_FMT,
+			original_compression_factor},
+		{"rotation", "%d", rotation},
+		{"cropping or scaling", "%d", cropping_or_scaling},
+		{"VMEM size (KB)", "%d", vmem_size},
+
+		{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"LCU size", "%d", lcu_size},
+		{"GOB pattern", "%d", gop},
+		{"bitrate (Mbit/sec)", "%lu", bitrate},
+		{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
+		{"B-frames enabled", "%d", b_frames_enabled},
+		{"search window size vertical (B)", "%d",
+			search_window_size_vertical_b},
+		{"search window factor (B)", "%d", search_window_factor_b},
+		{"search window factor BW (B)", "%d",
+			search_window_factor_bw_b},
+		{"VMEM size (B)", "%d", vmem_size_b},
+		{"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
+		{"available VMEM (B)", "%d", available_vmem_b},
+		{"search window size vertical (P)", "%d",
+			search_window_size_vertical_p},
+		{"search window factor (P)", "%d", search_window_factor_p},
+		{"search window factor BW (P)", "%d",
+			search_window_factor_bw_p},
+		{"VMEM size (P)", "%d", vmem_size_p},
+		{"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
+		{"available VMEM (P)", "%d", available_vmem_p},
+		{"chroma/luma factor DPB", DUMP_FP_FMT,
+			chroma_luma_factor_dpb},
+		{"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
+		{"chroma/Luma factor original", DUMP_FP_FMT,
+			chroma_luma_factor_original},
+		{"one frame BW original (MB/s)", DUMP_FP_FMT,
+			one_frame_bw_original},
+		{"line buffer size per LCU", DUMP_FP_FMT,
+			line_buffer_size_per_lcu},
+		{"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
+		{"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
+		{"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
+		{"original VMEM requirement (KB)", DUMP_FP_FMT,
+			original_vmem_requirement},
+
+		{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_write},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_write},
+		{"original read", DUMP_FP_FMT, ddr.original_read},
+		{"original read", DUMP_FP_FMT, ddr.original_write},
+		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
+		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+
+		{"INTERMEDIATE B/W VMEM", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, vmem.vsp_read},
+		{"VSP read", DUMP_FP_FMT, vmem.vsp_write},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_write},
+		{"original read", DUMP_FP_FMT, vmem.original_read},
+		{"original read", DUMP_FP_FMT, vmem.original_write},
+		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
+		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
+		};
+		__dump(dump, ARRAY_SIZE(dump));
+	}
+
+	switch (gm) {
+	case GOVERNOR_DDR:
+		ret = kbps(fp_round(ddr.total));
+		break;
+	case GOVERNOR_VMEM:
+		ret = kbps(fp_round(vmem.total));
+		break;
+	case GOVERNOR_VMEM_PLUS:
+		ret = __calculate_vmem_plus_ab(d);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
+	}
+
+	return ret;
+}
+
+static unsigned long __calculate(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	unsigned long (*calc[])(struct vidc_bus_vote_data *,
+			enum governor_mode) = {
+		[HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe,
+		[HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder,
+		[HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder,
+	};
+
+	return calc[d->domain](d, gm);
+}
+
+static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
+{
+	unsigned long ab_kbps = 0, c = 0;
+	struct devfreq_dev_status stats = {0};
+	struct msm_vidc_gov_data *vidc_data = NULL;
+	struct governor *gov = NULL;
+
+	if (!dev || !freq)
+		return -EINVAL;
+
+	gov = container_of(dev->governor,
+			struct governor, devfreq_gov);
+	dev->profile->get_dev_status(dev->dev.parent, &stats);
+	vidc_data = (struct msm_vidc_gov_data *)stats.private_data;
+
+	for (c = 0; c < vidc_data->data_count; ++c) {
+		if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
+			*freq = INT_MAX;
+			goto exit;
+		}
+	}
+
+	for (c = 0; c < vidc_data->data_count; ++c)
+		ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
+
+	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
+exit:
+	return 0;
+}
+
+static int __event_handler(struct devfreq *devfreq, unsigned int event,
+		void *data)
+{
+	int rc = 0;
+
+	if (!devfreq)
+		return -EINVAL;
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+	case DEVFREQ_GOV_RESUME:
+		mutex_lock(&devfreq->lock);
+		rc = update_devfreq(devfreq);
+		mutex_unlock(&devfreq->lock);
+		break;
+	}
+
+	return rc;
+}
+
+static struct governor governors[] = {
+	{
+		.mode = GOVERNOR_DDR,
+		.devfreq_gov = {
+			.name = "msm-vidc-ddr",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+	{
+		.mode = GOVERNOR_VMEM,
+		.devfreq_gov = {
+			.name = "msm-vidc-vmem",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+	{
+		.mode = GOVERNOR_VMEM_PLUS,
+		.devfreq_gov = {
+			.name = "msm-vidc-vmem+",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+};
+
+static int __init msm_vidc_bw_gov_init(void)
+{
+	int c = 0, rc = 0;
+
+	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
+		dprintk(VIDC_DBG, "Adding governor %s\n",
+				governors[c].devfreq_gov.name);
+
+		rc = devfreq_add_governor(&governors[c].devfreq_gov);
+		if (rc) {
+			dprintk(VIDC_ERR, "Error adding governor %s: %d\n",
+				governors[c].devfreq_gov.name, rc);
+			break;
+		}
+	}
+
+	return rc;
+}
+module_init(msm_vidc_bw_gov_init);
+
+static void __exit msm_vidc_bw_gov_exit(void)
+{
+	int c = 0;
+
+	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
+		dprintk(VIDC_DBG, "Removing governor %s\n",
+				governors[c].devfreq_gov.name);
+		devfreq_remove_governor(&governors[c].devfreq_gov);
+	}
+}
+module_exit(msm_vidc_bw_gov_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c
new file mode 100644
index 0000000..a702910
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include "governor.h"
+#include "../msm_vidc_debug.h"
+#include "../msm_vidc_res_parse.h"
+#include "../msm_vidc_internal.h"
+#include "../venus_hfi.h"
+#include "../vidc_hfi_api.h"
+
+
+enum bus_profile {
+	VIDC_BUS_PROFILE_NORMAL			= BIT(0),
+	VIDC_BUS_PROFILE_LOW			= BIT(1),
+	VIDC_BUS_PROFILE_UBWC			= BIT(2),
+};
+
+struct bus_profile_entry {
+	struct {
+		u32 load, freq;
+	} *bus_table;
+	u32 bus_table_size;
+	u32 codec_mask;
+	enum bus_profile profile;
+};
+
+struct msm_vidc_bus_table_gov {
+	struct bus_profile_entry *bus_prof_entries;
+	u32 count;
+	struct devfreq_governor devfreq_gov;
+};
+
+static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
+		struct vidc_bus_vote_data *data,
+		enum bus_profile profile)
+{
+	int i = 0, load = 0, freq = 0;
+	enum vidc_vote_data_session sess_type = 0;
+	struct bus_profile_entry *entry = NULL;
+	bool found = false;
+
+	load = NUM_MBS_PER_SEC(data->width, data->height, data->fps);
+	sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain);
+
+	/* check if ubwc bus profile is present */
+	for (i = 0; i < gov->count; i++) {
+		entry = &gov->bus_prof_entries[i];
+		if (!entry->bus_table || !entry->bus_table_size)
+			continue;
+		if (!venus_hfi_is_session_supported(
+				entry->codec_mask, sess_type))
+			continue;
+		if (entry->profile == profile) {
+			found = true;
+			break;
+		}
+	}
+
+	if (found) {
+		 /* loop over bus table and select frequency */
+		for (i = entry->bus_table_size - 1; i >= 0; --i) {
+			 /*load is arranged in descending order */
+			freq = entry->bus_table[i].freq;
+			if (load <= entry->bus_table[i].load)
+				break;
+		}
+	}
+
+	return freq;
+}
+
+
+static int msm_vidc_table_get_target_freq(struct devfreq *dev,
+		unsigned long *frequency)
+{
+	struct devfreq_dev_status status = {0};
+	struct msm_vidc_gov_data *vidc_data = NULL;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+	enum bus_profile profile = 0;
+	int i = 0;
+
+	if (!dev || !frequency) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK, %pK\n",
+			__func__, dev, frequency);
+		return -EINVAL;
+	}
+
+	gov = container_of(dev->governor,
+			struct msm_vidc_bus_table_gov, devfreq_gov);
+	if (!gov) {
+		dprintk(VIDC_ERR, "%s: governor not found\n", __func__);
+		return -EINVAL;
+	}
+
+	dev->profile->get_dev_status(dev->dev.parent, &status);
+	vidc_data = (struct msm_vidc_gov_data *)status.private_data;
+
+	*frequency = 0;
+	for (i = 0; i < vidc_data->data_count; i++) {
+		struct vidc_bus_vote_data *data = &vidc_data->data[i];
+		int freq = 0;
+
+		if (data->power_mode == VIDC_POWER_TURBO) {
+			dprintk(VIDC_DBG, "bus: found turbo session[%d] %#x\n",
+				i, VIDC_VOTE_DATA_SESSION_VAL(data->codec,
+					data->domain));
+			*frequency = INT_MAX;
+			goto exit;
+		}
+
+		profile = VIDC_BUS_PROFILE_NORMAL;
+		if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC ||
+			data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
+			profile = VIDC_BUS_PROFILE_UBWC;
+
+		freq = __get_bus_freq(gov, data, profile);
+
+		/* chose frequency from normal profile
+		 * if specific profile frequency was not found.
+		 */
+		if (!freq)
+			freq = __get_bus_freq(gov, data,
+				VIDC_BUS_PROFILE_NORMAL);
+
+		*frequency += (unsigned long)freq;
+
+		dprintk(VIDC_DBG,
+			"session[%d] %#x: wxh %dx%d, fps %d, bus_profile %#x, freq %d, total_freq %ld KBps\n",
+			i, VIDC_VOTE_DATA_SESSION_VAL(
+			data->codec, data->domain), data->width,
+			data->height, data->fps, profile,
+			freq, *frequency);
+	}
+exit:
+	return 0;
+}
+
+int msm_vidc_table_event_handler(struct devfreq *devfreq,
+		unsigned int event, void *data)
+{
+	int rc = 0;
+
+	if (!devfreq) {
+		dprintk(VIDC_ERR, "%s: NULL devfreq\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+	case DEVFREQ_GOV_RESUME:
+		mutex_lock(&devfreq->lock);
+		rc = update_devfreq(devfreq);
+		mutex_unlock(&devfreq->lock);
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_free_bus_table(struct platform_device *pdev,
+		struct msm_vidc_bus_table_gov *data)
+{
+	int rc = 0, i = 0;
+
+	if (!pdev || !data) {
+		dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n",
+			__func__, pdev, data);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < data->count; i++)
+		data->bus_prof_entries[i].bus_table = NULL;
+
+	data->bus_prof_entries = NULL;
+	data->count = 0;
+
+	return rc;
+}
+
+static int msm_vidc_load_bus_table(struct platform_device *pdev,
+		struct msm_vidc_bus_table_gov *data)
+{
+	int rc = 0, i = 0, j = 0;
+	const char *name = NULL;
+	struct bus_profile_entry *entry = NULL;
+	struct device_node *parent_node = NULL;
+	struct device_node *child_node = NULL;
+
+	if (!pdev || !data) {
+		dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n",
+			__func__, pdev, data);
+		return -EINVAL;
+	}
+
+	of_property_read_string(pdev->dev.of_node, "name", &name);
+	if (strlen(name) > ARRAY_SIZE(data->devfreq_gov.name) - 1) {
+		dprintk(VIDC_ERR,
+			"%s: name is too long, max should be %zu chars\n",
+			__func__, ARRAY_SIZE(data->devfreq_gov.name) - 1);
+		return -EINVAL;
+	}
+
+	strlcpy((char *)data->devfreq_gov.name, name,
+			ARRAY_SIZE(data->devfreq_gov.name));
+	data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq;
+	data->devfreq_gov.event_handler = msm_vidc_table_event_handler;
+
+	parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,bus-freq-table");
+	if (!parent_node) {
+		dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n");
+		return 0;
+	}
+
+	data->count = of_get_child_count(parent_node);
+	if (!data->count) {
+		dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n");
+		return 0;
+	}
+
+	data->bus_prof_entries = devm_kzalloc(&pdev->dev,
+			sizeof(*data->bus_prof_entries) * data->count,
+			GFP_KERNEL);
+	if (!data->bus_prof_entries) {
+		dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(parent_node, child_node) {
+
+		if (i >= data->count) {
+			dprintk(VIDC_ERR,
+				"qcom,bus-freq-table: invalid child node %d, max is %d\n",
+				i, data->count);
+			break;
+		}
+		entry = &data->bus_prof_entries[i];
+
+		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,codec-mask", &entry->codec_mask);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,codec-mask not found\n");
+				break;
+			}
+		}
+
+		if (of_find_property(child_node, "qcom,low-power-mode", NULL))
+			entry->profile = VIDC_BUS_PROFILE_LOW;
+		else if (of_find_property(child_node, "qcom,ubwc-mode", NULL))
+			entry->profile = VIDC_BUS_PROFILE_UBWC;
+		else
+			entry->profile = VIDC_BUS_PROFILE_NORMAL;
+
+		if (of_find_property(child_node,
+					"qcom,load-busfreq-tbl", NULL)) {
+			rc = msm_vidc_load_u32_table(pdev, child_node,
+						"qcom,load-busfreq-tbl",
+						sizeof(*entry->bus_table),
+						(u32 **)&entry->bus_table,
+						&entry->bus_table_size);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,load-busfreq-tbl failed\n");
+				break;
+			}
+		} else {
+			entry->bus_table = NULL;
+			entry->bus_table_size = 0;
+		}
+
+		dprintk(VIDC_DBG,
+			"qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n",
+			entry->bus_table_size, entry->codec_mask,
+			entry->profile);
+		for (j = 0; j < entry->bus_table_size; j++)
+			dprintk(VIDC_DBG, "   load %8d freq %8d\n",
+				entry->bus_table[j].load,
+				entry->bus_table[j].freq);
+
+		i++;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_bus_table_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	gov = devm_kzalloc(&pdev->dev, sizeof(*gov), GFP_KERNEL);
+	if (!gov) {
+		dprintk(VIDC_ERR, "%s: allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, gov);
+
+	rc = msm_vidc_load_bus_table(pdev, gov);
+	if (rc)
+		return rc;
+
+	rc = devfreq_add_governor(&gov->devfreq_gov);
+	if (rc)
+		dprintk(VIDC_ERR, "%s: add governor failed\n", __func__);
+
+	return rc;
+}
+
+static int msm_vidc_bus_table_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	gov = platform_get_drvdata(pdev);
+	if (IS_ERR_OR_NULL(gov))
+		return PTR_ERR(gov);
+
+	rc = msm_vidc_free_bus_table(pdev, gov);
+	if (rc)
+		dprintk(VIDC_WARN, "%s: free bus table failed\n", __func__);
+
+	rc = devfreq_remove_governor(&gov->devfreq_gov);
+
+	return rc;
+}
+
+static const struct of_device_id device_id[] = {
+	{.compatible = "qcom,msm-vidc,governor,table"},
+	{}
+};
+
+static struct platform_driver msm_vidc_bus_table_driver = {
+	.probe = msm_vidc_bus_table_probe,
+	.remove = msm_vidc_bus_table_remove,
+	.driver = {
+		.name = "msm_vidc_bus_table_governor",
+		.owner = THIS_MODULE,
+		.of_match_table = device_id,
+	},
+};
+
+static int __init msm_vidc_bus_table_init(void)
+{
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	return platform_driver_register(&msm_vidc_bus_table_driver);
+}
+
+module_init(msm_vidc_bus_table_init);
+
+static void __exit msm_vidc_bus_table_exit(void)
+{
+	dprintk(VIDC_DBG, "%s\n", __func__);
+	platform_driver_unregister(&msm_vidc_bus_table_driver);
+}
+
+module_exit(msm_vidc_bus_table_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_packetization.c b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c
new file mode 100644
index 0000000..b15baaa
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c
@@ -0,0 +1,2564 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/log2.h>
+#include <linux/hash.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+
+/* Set up look-up tables to convert HAL_* to HFI_*.
+ *
+ * The tables below mostly take advantage of the fact that most
+ * HAL_* types are defined bitwise. So if we index them normally
+ * when declaring the tables, we end up with huge arrays with wasted
+ * space.  So before indexing them, we apply log2 to use a more
+ * sensible index.
+ */
+static int profile_table[] = {
+	[ilog2(HAL_H264_PROFILE_BASELINE)] = HFI_H264_PROFILE_BASELINE,
+	[ilog2(HAL_H264_PROFILE_MAIN)] = HFI_H264_PROFILE_MAIN,
+	[ilog2(HAL_H264_PROFILE_HIGH)] = HFI_H264_PROFILE_HIGH,
+	[ilog2(HAL_H264_PROFILE_CONSTRAINED_BASE)] =
+		HFI_H264_PROFILE_CONSTRAINED_BASE,
+	[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
+		HFI_H264_PROFILE_CONSTRAINED_HIGH,
+	[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
+	[ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH,
+};
+
+static int entropy_mode[] = {
+	[ilog2(HAL_H264_ENTROPY_CAVLC)] = HFI_H264_ENTROPY_CAVLC,
+	[ilog2(HAL_H264_ENTROPY_CABAC)] = HFI_H264_ENTROPY_CABAC,
+};
+
+static int cabac_model[] = {
+	[ilog2(HAL_H264_CABAC_MODEL_0)] = HFI_H264_CABAC_MODEL_0,
+	[ilog2(HAL_H264_CABAC_MODEL_1)] = HFI_H264_CABAC_MODEL_1,
+	[ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
+};
+
+static int statistics_mode[] = {
+	[ilog2(HAL_STATISTICS_MODE_DEFAULT)] = HFI_STATISTICS_MODE_DEFAULT,
+	[ilog2(HAL_STATISTICS_MODE_1)] = HFI_STATISTICS_MODE_1,
+	[ilog2(HAL_STATISTICS_MODE_2)] = HFI_STATISTICS_MODE_2,
+	[ilog2(HAL_STATISTICS_MODE_3)] = HFI_STATISTICS_MODE_3,
+};
+
+static int color_format[] = {
+	[ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+	[ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+	[ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+	[ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+	[ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+	[ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+	[ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+	[ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+	[ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+	[ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+	[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+	[ilog2(HAL_COLOR_FORMAT_RGBA8888)] = HFI_COLOR_FORMAT_RGBA8888,
+	/* UBWC Color formats*/
+	[ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] =  HFI_COLOR_FORMAT_NV12_UBWC,
+	[ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] =
+			HFI_COLOR_FORMAT_YUV420_TP10_UBWC,
+	[ilog2(HAL_COLOR_FORMAT_RGBA8888_UBWC)] =
+			HFI_COLOR_FORMAT_RGBA8888_UBWC,
+};
+
+static int nal_type[] = {
+	[ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES,
+	[ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] =
+		HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER,
+	[ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_ONE_BYTE_LENGTH,
+	[ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_TWO_BYTE_LENGTH,
+	[ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_FOUR_BYTE_LENGTH,
+};
+
+static inline int hal_to_hfi_type(int property, int hal_type)
+{
+	if (hal_type <= 0 || roundup_pow_of_two(hal_type) != hal_type) {
+		/* Not a power of 2, it's not going
+		 * to be in any of the tables anyway
+		 */
+		return -EINVAL;
+	}
+
+	if (hal_type)
+		hal_type = ilog2(hal_type);
+
+	switch (property) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+		return (hal_type >= ARRAY_SIZE(profile_table)) ?
+			-ENOTSUPP : profile_table[hal_type];
+	case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+		return (hal_type >= ARRAY_SIZE(entropy_mode)) ?
+			-ENOTSUPP : entropy_mode[hal_type];
+	case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
+		return (hal_type >= ARRAY_SIZE(cabac_model)) ?
+			-ENOTSUPP : cabac_model[hal_type];
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+		return (hal_type >= ARRAY_SIZE(color_format)) ?
+			-ENOTSUPP : color_format[hal_type];
+	case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+		return (hal_type >= ARRAY_SIZE(nal_type)) ?
+			-ENOTSUPP : nal_type[hal_type];
+	case HAL_PARAM_VENC_MBI_STATISTICS_MODE:
+		return (hal_type >= ARRAY_SIZE(statistics_mode)) ?
+			-ENOTSUPP : statistics_mode[hal_type];
+	default:
+		return -ENOTSUPP;
+	}
+}
+
+u32 get_hfi_layout(enum hal_buffer_layout_type hal_buf_layout)
+{
+	u32 hfi_layout;
+
+	switch (hal_buf_layout) {
+	case HAL_BUFFER_LAYOUT_TOP_BOTTOM:
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM;
+		break;
+	case HAL_BUFFER_LAYOUT_SEQ:
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n",
+			hal_buf_layout);
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+		break;
+	}
+	return hfi_layout;
+}
+
+enum hal_domain vidc_get_hal_domain(u32 hfi_domain)
+{
+	enum hal_domain hal_domain = 0;
+
+	switch (hfi_domain) {
+	case HFI_VIDEO_DOMAIN_VPE:
+		hal_domain = HAL_VIDEO_DOMAIN_VPE;
+		break;
+	case HFI_VIDEO_DOMAIN_ENCODER:
+		hal_domain = HAL_VIDEO_DOMAIN_ENCODER;
+		break;
+	case HFI_VIDEO_DOMAIN_DECODER:
+		hal_domain = HAL_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid domain %x\n",
+			__func__, hfi_domain);
+		hal_domain = 0;
+		break;
+	}
+	return hal_domain;
+}
+
+enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec)
+{
+	enum hal_video_codec hal_codec = 0;
+
+	switch (hfi_codec) {
+	case HFI_VIDEO_CODEC_H264:
+		hal_codec = HAL_VIDEO_CODEC_H264;
+		break;
+	case HFI_VIDEO_CODEC_H263:
+		hal_codec = HAL_VIDEO_CODEC_H263;
+		break;
+	case HFI_VIDEO_CODEC_MPEG1:
+		hal_codec = HAL_VIDEO_CODEC_MPEG1;
+		break;
+	case HFI_VIDEO_CODEC_MPEG2:
+		hal_codec = HAL_VIDEO_CODEC_MPEG2;
+		break;
+	case HFI_VIDEO_CODEC_MPEG4:
+		hal_codec = HAL_VIDEO_CODEC_MPEG4;
+		break;
+	case HFI_VIDEO_CODEC_DIVX_311:
+		hal_codec = HAL_VIDEO_CODEC_DIVX_311;
+		break;
+	case HFI_VIDEO_CODEC_DIVX:
+		hal_codec = HAL_VIDEO_CODEC_DIVX;
+		break;
+	case HFI_VIDEO_CODEC_VC1:
+		hal_codec = HAL_VIDEO_CODEC_VC1;
+		break;
+	case HFI_VIDEO_CODEC_SPARK:
+		hal_codec = HAL_VIDEO_CODEC_SPARK;
+		break;
+	case HFI_VIDEO_CODEC_VP8:
+		hal_codec = HAL_VIDEO_CODEC_VP8;
+		break;
+	case HFI_VIDEO_CODEC_HEVC:
+		hal_codec = HAL_VIDEO_CODEC_HEVC;
+		break;
+	case HFI_VIDEO_CODEC_VP9:
+		hal_codec = HAL_VIDEO_CODEC_VP9;
+		break;
+	case HFI_VIDEO_CODEC_HEVC_HYBRID:
+		hal_codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
+			__func__, hfi_codec);
+		hal_codec = 0;
+		break;
+	}
+	return hal_codec;
+}
+
+
+u32 vidc_get_hfi_domain(enum hal_domain hal_domain)
+{
+	u32 hfi_domain;
+
+	switch (hal_domain) {
+	case HAL_VIDEO_DOMAIN_VPE:
+		hfi_domain = HFI_VIDEO_DOMAIN_VPE;
+		break;
+	case HAL_VIDEO_DOMAIN_ENCODER:
+		hfi_domain = HFI_VIDEO_DOMAIN_ENCODER;
+		break;
+	case HAL_VIDEO_DOMAIN_DECODER:
+		hfi_domain = HFI_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid domain 0x%x\n",
+			__func__, hal_domain);
+		hfi_domain = 0;
+		break;
+	}
+	return hfi_domain;
+}
+
+u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec)
+{
+	u32 hfi_codec = 0;
+
+	switch (hal_codec) {
+	case HAL_VIDEO_CODEC_MVC:
+	case HAL_VIDEO_CODEC_H264:
+		hfi_codec = HFI_VIDEO_CODEC_H264;
+		break;
+	case HAL_VIDEO_CODEC_H263:
+		hfi_codec = HFI_VIDEO_CODEC_H263;
+		break;
+	case HAL_VIDEO_CODEC_MPEG1:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG1;
+		break;
+	case HAL_VIDEO_CODEC_MPEG2:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG2;
+		break;
+	case HAL_VIDEO_CODEC_MPEG4:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG4;
+		break;
+	case HAL_VIDEO_CODEC_DIVX_311:
+		hfi_codec = HFI_VIDEO_CODEC_DIVX_311;
+		break;
+	case HAL_VIDEO_CODEC_DIVX:
+		hfi_codec = HFI_VIDEO_CODEC_DIVX;
+		break;
+	case HAL_VIDEO_CODEC_VC1:
+		hfi_codec = HFI_VIDEO_CODEC_VC1;
+		break;
+	case HAL_VIDEO_CODEC_SPARK:
+		hfi_codec = HFI_VIDEO_CODEC_SPARK;
+		break;
+	case HAL_VIDEO_CODEC_VP8:
+		hfi_codec = HFI_VIDEO_CODEC_VP8;
+		break;
+	case HAL_VIDEO_CODEC_HEVC:
+		hfi_codec = HFI_VIDEO_CODEC_HEVC;
+		break;
+	case HAL_VIDEO_CODEC_VP9:
+		hfi_codec = HFI_VIDEO_CODEC_VP9;
+		break;
+	case HAL_VIDEO_CODEC_HEVC_HYBRID:
+		hfi_codec = HFI_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
+			__func__, hal_codec);
+		hfi_codec = 0;
+		break;
+	}
+	return hfi_codec;
+}
+
+static void create_pkt_enable(void *pkt, u32 type, bool enable)
+{
+	u32 *pkt_header = pkt;
+	u32 *pkt_type = &pkt_header[0];
+	struct hfi_enable *hfi_enable = (struct hfi_enable *)&pkt_header[1];
+
+	*pkt_type = type;
+	hfi_enable->enable = enable;
+}
+
+int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt,
+			   u32 arch_type)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_INIT;
+	pkt->size = sizeof(struct hfi_cmd_sys_init_packet);
+	pkt->arch_type = arch_type;
+	return rc;
+}
+
+int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_PC_PREP;
+	pkt->size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
+	return rc;
+}
+
+int create_pkt_cmd_sys_idle_indicator(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 enable)
+{
+	struct hfi_enable *hfi;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_enable) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
+	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+	hfi->enable = enable;
+	return 0;
+}
+
+int create_pkt_cmd_sys_debug_config(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 mode)
+{
+	struct hfi_debug_config *hfi;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_debug_config) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
+	hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
+	hfi->debug_config = mode;
+	hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
+	if (msm_vidc_fw_debug_mode
+			<= (HFI_DEBUG_MODE_QUEUE | HFI_DEBUG_MODE_QDSS))
+		hfi->debug_mode = msm_vidc_fw_debug_mode;
+	return 0;
+}
+
+int create_pkt_cmd_sys_coverage_config(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 mode)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "In %s(), No input packet\n", __func__);
+		return -EINVAL;
+	}
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
+	pkt->rg_property_data[1] = mode;
+	dprintk(VIDC_DBG, "Firmware coverage mode %d\n",
+			pkt->rg_property_data[1]);
+	return 0;
+}
+
+int create_pkt_cmd_sys_set_resource(
+		struct hfi_cmd_sys_set_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr,
+		void *resource_value)
+{
+	int rc = 0;
+
+	if (!pkt || !resource_hdr || !resource_value)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE;
+	pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet);
+	pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+	switch (resource_hdr->resource_id) {
+	case VIDC_RESOURCE_OCMEM:
+	case VIDC_RESOURCE_VMEM:
+	{
+		struct hfi_resource_ocmem *hfioc_mem =
+			(struct hfi_resource_ocmem *)
+			&pkt->rg_resource_data[0];
+
+		phys_addr_t imem_addr = (phys_addr_t)resource_value;
+
+		pkt->resource_type = HFI_RESOURCE_OCMEM;
+		pkt->size += sizeof(struct hfi_resource_ocmem) - sizeof(u32);
+		hfioc_mem->size = (u32)resource_hdr->size;
+		hfioc_mem->mem = imem_addr;
+		break;
+	}
+	default:
+		dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+					resource_hdr->resource_id);
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_release_resource(
+		struct hfi_cmd_sys_release_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_release_resource_packet);
+	pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE;
+	pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+	switch (resource_hdr->resource_id) {
+	case VIDC_RESOURCE_OCMEM:
+	case VIDC_RESOURCE_VMEM:
+		pkt->resource_type = HFI_RESOURCE_OCMEM;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+					resource_hdr->resource_id);
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_ping(struct hfi_cmd_sys_ping_packet *pkt)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_ping_packet);
+	pkt->packet_type = HFI_CMD_SYS_PING;
+
+	return rc;
+}
+
+inline int create_pkt_cmd_sys_session_init(
+		struct hfi_cmd_sys_session_init_packet *pkt,
+		struct hal_session *session,
+		u32 session_domain, u32 session_codec)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_session_init_packet);
+	pkt->packet_type = HFI_CMD_SYS_SESSION_INIT;
+	pkt->session_id = hash32_ptr(session);
+	pkt->session_domain = vidc_get_hfi_domain(session_domain);
+	pkt->session_codec = vidc_get_hfi_codec(session_codec);
+	if (!pkt->session_codec)
+		return -EINVAL;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
+			int pkt_type, struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	/*
+	 * Legacy packetization should skip sending any 3xx specific session
+	 * cmds. Add 3xx specific packetization to the switch case below.
+	 */
+	switch (pkt_type) {
+	case HFI_CMD_SESSION_CONTINUE:
+		dprintk(VIDC_INFO,
+			"%s - skip sending %x for legacy hfi\n",
+			__func__, pkt_type);
+		return -EPERM;
+	default:
+		break;
+	}
+
+	pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
+	pkt->packet_type = pkt_type;
+	pkt->session_id = hash32_ptr(session);
+
+	return rc;
+}
+
+int create_3x_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
+			int pkt_type, struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
+	pkt->packet_type = pkt_type;
+	pkt->session_id = hash32_ptr(session);
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_power_control(
+	struct hfi_cmd_sys_set_property_packet *pkt, u32 enable)
+{
+	struct hfi_enable *hfi;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "No input packet\n");
+		return -EINVAL;
+	}
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_enable) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
+	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+	hfi->enable = enable;
+	return 0;
+}
+
+static u32 get_hfi_buffer(int hal_buffer)
+{
+	u32 buffer;
+
+	switch (hal_buffer) {
+	case HAL_BUFFER_INPUT:
+		buffer = HFI_BUFFER_INPUT;
+		break;
+	case HAL_BUFFER_OUTPUT:
+		buffer = HFI_BUFFER_OUTPUT;
+		break;
+	case HAL_BUFFER_OUTPUT2:
+		buffer = HFI_BUFFER_OUTPUT2;
+		break;
+	case HAL_BUFFER_EXTRADATA_INPUT:
+		buffer = HFI_BUFFER_EXTRADATA_INPUT;
+		break;
+	case HAL_BUFFER_EXTRADATA_OUTPUT:
+		buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
+		break;
+	case HAL_BUFFER_EXTRADATA_OUTPUT2:
+		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+		break;
+	case HAL_BUFFER_INTERNAL_PERSIST:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST;
+		break;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer: %#x\n",
+				hal_buffer);
+		buffer = 0;
+		break;
+	}
+	return buffer;
+}
+
+static int get_hfi_extradata_index(enum hal_extradata_id index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case HAL_EXTRADATA_MB_QUANTIZATION:
+		ret = HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION;
+		break;
+	case HAL_EXTRADATA_INTERLACE_VIDEO:
+		ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VC1_FRAMEDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VC1_SEQDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_TIMESTAMP:
+		ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_S3D_FRAME_PACKING:
+		ret = HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_RATE:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_PANSCAN_WINDOW:
+		ret = HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_RECOVERY_POINT_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MULTISLICE_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO;
+		break;
+	case HAL_EXTRADATA_NUM_CONCEALED_MB:
+		ret = HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB;
+		break;
+	case HAL_EXTRADATA_ASPECT_RATIO:
+	case HAL_EXTRADATA_INPUT_CROP:
+	case HAL_EXTRADATA_DIGITAL_ZOOM:
+	case HAL_EXTRADATA_OUTPUT_CROP:
+		ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MPEG2_SEQDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_STREAM_USERDATA:
+		ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_QP:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_BITS_INFO:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_LTR_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_LTR_INFO;
+		break;
+	case HAL_EXTRADATA_METADATA_MBI:
+		ret = HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+		break;
+	case HAL_EXTRADATA_VQZIP_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_YUV_STATS:
+		ret = HFI_PROPERTY_PARAM_VENC_YUVSTAT_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_ROI_QP:
+		ret = HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI:
+		ret =
+		HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VUI_DISPLAY_INFO:
+		ret = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VPX_COLORSPACE:
+		ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_PQ_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_OVERRIDE_QP_EXTRADATA;
+		break;
+	default:
+		dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
+		break;
+	}
+	return ret;
+}
+
+static int get_hfi_extradata_id(enum hal_extradata_id index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case HAL_EXTRADATA_ASPECT_RATIO:
+		ret = MSM_VIDC_EXTRADATA_ASPECT_RATIO;
+		break;
+	case HAL_EXTRADATA_INPUT_CROP:
+		ret = MSM_VIDC_EXTRADATA_INPUT_CROP;
+		break;
+	case HAL_EXTRADATA_DIGITAL_ZOOM:
+		ret = MSM_VIDC_EXTRADATA_DIGITAL_ZOOM;
+		break;
+	case HAL_EXTRADATA_OUTPUT_CROP:
+		ret = MSM_VIDC_EXTRADATA_OUTPUT_CROP;
+		break;
+	default:
+		ret = get_hfi_extradata_index(index);
+		break;
+	}
+	return ret;
+}
+
+static u32 get_hfi_buf_mode(enum buffer_mode_type hal_buf_mode)
+{
+	u32 buf_mode;
+
+	switch (hal_buf_mode) {
+	case HAL_BUFFER_MODE_STATIC:
+		buf_mode = HFI_BUFFER_MODE_STATIC;
+		break;
+	case HAL_BUFFER_MODE_RING:
+		buf_mode = HFI_BUFFER_MODE_RING;
+		break;
+	case HAL_BUFFER_MODE_DYNAMIC:
+		buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer mode: %#x\n",
+				hal_buf_mode);
+		buf_mode = 0;
+		break;
+	}
+	return buf_mode;
+}
+
+static u32 get_hfi_ltr_mode(enum ltr_mode ltr_mode_type)
+{
+	u32 ltrmode;
+
+	switch (ltr_mode_type) {
+	case HAL_LTR_MODE_DISABLE:
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	case HAL_LTR_MODE_MANUAL:
+		ltrmode = HFI_LTR_MODE_MANUAL;
+		break;
+	case HAL_LTR_MODE_PERIODIC:
+		ltrmode = HFI_LTR_MODE_PERIODIC;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n",
+			ltr_mode_type);
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	}
+	return ltrmode;
+}
+
+int create_pkt_cmd_session_set_buffers(
+		struct hfi_cmd_session_set_buffers_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info)
+{
+	int rc = 0;
+	int i = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_size = buffer_info->buffer_size;
+	pkt->min_buffer_size = buffer_info->buffer_size;
+	pkt->num_buffers = buffer_info->num_buffers;
+
+	if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+		buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+		struct hfi_buffer_info *buff;
+
+		pkt->extra_data_size = buffer_info->extradata_size;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+				sizeof(u32) + (buffer_info->num_buffers *
+				sizeof(struct hfi_buffer_info));
+		buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+		for (i = 0; i < pkt->num_buffers; i++) {
+			buff->buffer_addr =
+				(u32)buffer_info->align_device_addr;
+			buff->extra_data_addr =
+				(u32)buffer_info->extradata_addr;
+		}
+	} else {
+		pkt->extra_data_size = 0;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+			((buffer_info->num_buffers - 1) * sizeof(u32));
+		for (i = 0; i < pkt->num_buffers; i++) {
+			pkt->rg_buffer_info[i] =
+				(u32)buffer_info->align_device_addr;
+		}
+	}
+
+	pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+	if (!pkt->buffer_type)
+		return -EINVAL;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_release_buffers(
+		struct hfi_cmd_session_release_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info)
+{
+	int rc = 0;
+	int i = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_size = buffer_info->buffer_size;
+	pkt->num_buffers = buffer_info->num_buffers;
+
+	if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+		buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+		struct hfi_buffer_info *buff;
+
+		buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+		for (i = 0; i < pkt->num_buffers; i++) {
+			buff->buffer_addr =
+				(u32)buffer_info->align_device_addr;
+			buff->extra_data_addr =
+				(u32)buffer_info->extradata_addr;
+		}
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+				sizeof(u32) + (buffer_info->num_buffers *
+				sizeof(struct hfi_buffer_info));
+	} else {
+		for (i = 0; i < pkt->num_buffers; i++) {
+			pkt->rg_buffer_info[i] =
+				(u32)buffer_info->align_device_addr;
+		}
+		pkt->extra_data_size = 0;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+			((buffer_info->num_buffers - 1) * sizeof(u32));
+	}
+	pkt->response_req = buffer_info->response_required;
+	pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+	if (!pkt->buffer_type)
+		return -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_etb_decoder(
+	struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+	struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size =
+		sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet);
+	pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+	pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+	pkt->flags = input_frame->flags;
+	pkt->mark_target = input_frame->mark_target;
+	pkt->mark_data = input_frame->mark_data;
+	pkt->offset = input_frame->offset;
+	pkt->alloc_len = input_frame->alloc_len;
+	pkt->filled_len = input_frame->filled_len;
+	pkt->input_tag = input_frame->clnt_data;
+	pkt->packet_buffer = (u32)input_frame->device_addr;
+
+	trace_msm_v4l2_vidc_buffer_event_start("ETB",
+		input_frame->device_addr, input_frame->timestamp,
+		input_frame->alloc_len, input_frame->filled_len,
+		input_frame->offset);
+
+	if (!pkt->packet_buffer)
+		rc = -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_etb_encoder(
+	struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt,
+	struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct
+		hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
+	pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->view_id = 0;
+	pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+	pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+	pkt->flags = input_frame->flags;
+	pkt->mark_target = input_frame->mark_target;
+	pkt->mark_data = input_frame->mark_data;
+	pkt->offset = input_frame->offset;
+	pkt->alloc_len = input_frame->alloc_len;
+	pkt->filled_len = input_frame->filled_len;
+	pkt->input_tag = input_frame->clnt_data;
+	pkt->packet_buffer = (u32)input_frame->device_addr;
+	pkt->extra_data_buffer = (u32)input_frame->extradata_addr;
+
+	trace_msm_v4l2_vidc_buffer_event_start("ETB",
+		input_frame->device_addr, input_frame->timestamp,
+		input_frame->alloc_len, input_frame->filled_len,
+		input_frame->offset);
+
+	if (!pkt->packet_buffer)
+		rc = -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *output_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !output_frame)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet);
+	pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+
+	if (output_frame->buffer_type == HAL_BUFFER_OUTPUT)
+		pkt->stream_id = 0;
+	else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2)
+		pkt->stream_id = 1;
+
+	if (!output_frame->device_addr)
+		return -EINVAL;
+
+	pkt->packet_buffer = (u32)output_frame->device_addr;
+	pkt->extra_data_buffer = (u32)output_frame->extradata_addr;
+	pkt->alloc_len = output_frame->alloc_len;
+	pkt->filled_len = output_frame->filled_len;
+	pkt->offset = output_frame->offset;
+	pkt->rgData[0] = output_frame->extradata_size;
+
+	trace_msm_v4l2_vidc_buffer_event_start("FTB",
+		output_frame->device_addr, output_frame->timestamp,
+		output_frame->alloc_len, output_frame->filled_len,
+		output_frame->offset);
+	dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
+			pkt->alloc_len, pkt->filled_len, pkt->offset);
+
+	return rc;
+}
+
+int create_pkt_cmd_session_parse_seq_header(
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !seq_hdr)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_parse_sequence_header_packet);
+	pkt->packet_type = HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->header_len = seq_hdr->seq_hdr_len;
+	if (!seq_hdr->seq_hdr)
+		return -EINVAL;
+	pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+	return rc;
+}
+
+int create_pkt_cmd_session_get_seq_hdr(
+		struct hfi_cmd_session_get_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !seq_hdr)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_get_sequence_header_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_SEQUENCE_HEADER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_len = seq_hdr->seq_hdr_len;
+	if (!seq_hdr->seq_hdr)
+		return -EINVAL;
+	pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+	return rc;
+}
+
+int create_pkt_cmd_session_get_buf_req(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_flush(struct hfi_cmd_session_flush_packet *pkt,
+			struct hal_session *session, enum hal_flush flush_mode)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_flush_packet);
+	pkt->packet_type = HFI_CMD_SESSION_FLUSH;
+	pkt->session_id = hash32_ptr(session);
+	switch (flush_mode) {
+	case HAL_FLUSH_INPUT:
+		pkt->flush_type = HFI_FLUSH_INPUT;
+		break;
+	case HAL_FLUSH_OUTPUT:
+		pkt->flush_type = HFI_FLUSH_OUTPUT;
+		break;
+	case HAL_FLUSH_ALL:
+		pkt->flush_type = HFI_FLUSH_ALL;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid flush mode: %#x\n", flush_mode);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_get_property(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype)
+{
+	int rc = 0;
+
+	if (!pkt || !session) {
+		dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	switch (ptype) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
+			ptype);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int create_3x_pkt_cmd_session_get_property(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype)
+{
+	int rc = 0;
+
+	if (!pkt || !session) {
+		dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	switch (ptype) {
+	case HAL_CONFIG_VDEC_ENTROPY:
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VDEC_ENTROPY;
+		break;
+	default:
+		rc = create_pkt_cmd_session_get_property(pkt,
+				session, ptype);
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_set_property(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+
+	switch (ptype) {
+	case HAL_CONFIG_FRAME_RATE:
+	{
+		u32 buffer_type;
+		struct hfi_frame_rate *hfi;
+		struct hal_frame_rate *prop = (struct hal_frame_rate *) pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE;
+		hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->frame_rate = prop->frame_rate;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate);
+		break;
+	}
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+	{
+		u32 buffer_type;
+		struct hfi_uncompressed_format_select *hfi;
+		struct hal_uncompressed_format_select *prop =
+			(struct hal_uncompressed_format_select *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
+
+		hfi = (struct hfi_uncompressed_format_select *)
+					&pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->format = hal_to_hfi_type(
+				HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+				prop->format);
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_uncompressed_format_select);
+		break;
+	}
+	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+		break;
+	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+		break;
+	case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+		break;
+	case HAL_PARAM_FRAME_SIZE:
+	{
+		struct hfi_frame_size *hfi;
+		struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE;
+		hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->height = prop->height;
+		hfi->width = prop->width;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+		break;
+	}
+	case HAL_CONFIG_REALTIME:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_REALTIME,
+			(((struct hal_enable *) pdata)->enable));
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+	{
+		struct hfi_buffer_count_actual *hfi;
+		struct hal_buffer_count_actual *prop =
+			(struct hal_buffer_count_actual *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
+		hfi = (struct hfi_buffer_count_actual *)
+			&pkt->rg_property_data[1];
+		hfi->buffer_count_actual = prop->buffer_count_actual;
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		pkt->size += sizeof(u32) + sizeof(struct
+				hfi_buffer_count_actual);
+
+		break;
+	}
+	case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+	{
+		struct hfi_nal_stream_format_select *hfi;
+		struct hal_nal_stream_format_select *prop =
+			(struct hal_nal_stream_format_select *)pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
+		hfi = (struct hfi_nal_stream_format_select *)
+			&pkt->rg_property_data[1];
+		dprintk(VIDC_DBG, "data is :%d\n",
+				prop->nal_stream_format_select);
+		hfi->nal_stream_format_select = hal_to_hfi_type(
+				HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+				prop->nal_stream_format_select);
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_nal_stream_format_select);
+		break;
+	}
+	case HAL_PARAM_VDEC_OUTPUT_ORDER:
+	{
+		int *data = (int *) pdata;
+
+		pkt->rg_property_data[0] =
+				HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
+		switch (*data) {
+		case HAL_OUTPUT_ORDER_DECODE:
+			pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE;
+			break;
+		case HAL_OUTPUT_ORDER_DISPLAY:
+			pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "invalid output order: %#x\n",
+						  *data);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+	{
+		struct hfi_enable_picture *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
+		hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
+		hfi->picture_type =
+			((struct hfi_enable_picture *)pdata)->picture_type;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_MULTI_STREAM:
+	{
+		struct hfi_multi_stream *hfi;
+		struct hal_multi_stream *prop =
+			(struct hal_multi_stream *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+		hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1];
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->enable = prop->enable;
+		hfi->width = prop->width;
+		hfi->height = prop->height;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream);
+		break;
+	}
+	case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+	{
+		struct hfi_display_picture_buffer_count *hfi;
+		struct hal_display_picture_buffer_count *prop =
+			(struct hal_display_picture_buffer_count *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT;
+		hfi = (struct hfi_display_picture_buffer_count *)
+			&pkt->rg_property_data[1];
+		hfi->count = prop->count;
+		hfi->enable = prop->enable;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_display_picture_buffer_count);
+		break;
+	}
+	case HAL_PARAM_DIVX_FORMAT:
+	{
+		int *data = pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT;
+		switch (*data) {
+		case HAL_DIVX_FORMAT_4:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_4;
+			break;
+		case HAL_DIVX_FORMAT_5:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_5;
+			break;
+		case HAL_DIVX_FORMAT_6:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid divx format: %#x\n", *data);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_SYNC_FRAME_DECODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_REQUEST_IFRAME:
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
+		pkt->size += sizeof(u32);
+		break;
+	case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+		break;
+	case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+		break;
+	case HAL_CONFIG_VENC_TARGET_BITRATE:
+	{
+		struct hfi_bitrate *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+		hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+		hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+		hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+		break;
+	}
+	case HAL_CONFIG_VENC_MAX_BITRATE:
+	{
+		struct hfi_bitrate *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
+		hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+		hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+		hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+
+		pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+		break;
+	}
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+	{
+		struct hfi_profile_level *hfi;
+		struct hal_profile_level *prop =
+			(struct hal_profile_level *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+		hfi = (struct hfi_profile_level *)
+			&pkt->rg_property_data[1];
+		hfi->level = prop->level;
+		hfi->profile = hal_to_hfi_type(HAL_PARAM_PROFILE_LEVEL_CURRENT,
+				prop->profile);
+		if (hfi->profile <= 0) {
+			hfi->profile = HFI_H264_PROFILE_HIGH;
+			dprintk(VIDC_WARN,
+					"Profile %d not supported, falling back to high\n",
+					prop->profile);
+		}
+
+		if (!hfi->level) {
+			hfi->level = 1;
+			dprintk(VIDC_WARN,
+					"Level %d not supported, falling back to high\n",
+					prop->level);
+		}
+
+		pkt->size += sizeof(u32) + sizeof(struct hfi_profile_level);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+	{
+		struct hfi_h264_entropy_control *hfi;
+		struct hal_h264_entropy_control *prop =
+			(struct hal_h264_entropy_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
+		hfi = (struct hfi_h264_entropy_control *)
+			&pkt->rg_property_data[1];
+		hfi->entropy_mode = hal_to_hfi_type(
+		   HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+		   prop->entropy_mode);
+		if (hfi->entropy_mode == HAL_H264_ENTROPY_CABAC)
+			hfi->cabac_model = hal_to_hfi_type(
+			   HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+			   prop->cabac_model);
+		pkt->size += sizeof(u32) + sizeof(
+			struct hfi_h264_entropy_control);
+		break;
+	}
+	case HAL_PARAM_VENC_RATE_CONTROL:
+	{
+		u32 *rc;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
+		rc = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc) {
+		case HAL_RATE_CONTROL_OFF:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
+			break;
+		case HAL_RATE_CONTROL_CBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_CBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR;
+			break;
+		case HAL_RATE_CONTROL_VBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_VBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
+			break;
+		case HAL_RATE_CONTROL_MBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_MBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_VFR;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Invalid Rate control setting: %pK\n",
+					pdata);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+	{
+		struct hfi_mpeg4_time_resolution *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+		hfi = (struct hfi_mpeg4_time_resolution *)
+			&pkt->rg_property_data[1];
+		hfi->time_increment_resolution =
+			((struct hal_mpeg4_time_resolution *)pdata)->
+					time_increment_resolution;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+	{
+		struct hfi_mpeg4_header_extension *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION;
+		hfi = (struct hfi_mpeg4_header_extension *)
+			&pkt->rg_property_data[1];
+		hfi->header_extension = (u32)(unsigned long) pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+	{
+		struct hfi_h264_db_control *hfi;
+		struct hal_h264_db_control *prop =
+			(struct hal_h264_db_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1];
+		switch (prop->mode) {
+		case HAL_H264_DB_MODE_DISABLE:
+			hfi->mode = HFI_H264_DB_MODE_DISABLE;
+			break;
+		case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY:
+			hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+			break;
+		case HAL_H264_DB_MODE_ALL_BOUNDARY:
+			hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid deblocking mode: %#x\n",
+						  prop->mode);
+			break;
+		}
+		hfi->slice_alpha_offset = prop->slice_alpha_offset;
+		hfi->slice_beta_offset = prop->slice_beta_offset;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_h264_db_control);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP:
+	{
+		struct hfi_quantization *hfi;
+		struct hal_quantization *hal_quant =
+			(struct hal_quantization *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP;
+		hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
+		hfi->qp_i = hal_quant->qpi;
+		hfi->qp_p = hal_quant->qpp;
+		hfi->qp_b = hal_quant->qpb;
+		hfi->layer_id = hal_quant->layer_id;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP_RANGE:
+	{
+		struct hfi_quantization_range *hfi;
+		struct hfi_quantization_range *hal_range =
+			(struct hfi_quantization_range *) pdata;
+		u32 min_qp, max_qp;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+		hfi = (struct hfi_quantization_range *)
+				&pkt->rg_property_data[1];
+
+		min_qp = hal_range->min_qp;
+		max_qp = hal_range->max_qp;
+
+		/* We'll be packing in the qp, so make sure we
+		 * won't be losing data when masking
+		 */
+		if (min_qp > 0xff || max_qp > 0xff) {
+			dprintk(VIDC_ERR, "qp value out of range\n");
+			rc = -ERANGE;
+			break;
+		}
+
+		/* When creating the packet, pack the qp value as
+		 * 0xiippbb, where ii = qp range for I-frames,
+		 * pp = qp range for P-frames, etc.
+		 */
+		hfi->min_qp = min_qp | min_qp << 8 | min_qp << 16;
+		hfi->max_qp = max_qp | max_qp << 8 | max_qp << 16;
+		hfi->layer_id = hal_range->layer_id;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_quantization_range);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED:
+	{
+		struct hfi_quantization_range *hfi;
+		struct hfi_quantization_range *hal_range =
+			(struct hfi_quantization_range *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+		hfi = (struct hfi_quantization_range *)
+				&pkt->rg_property_data[1];
+
+		hfi->min_qp = hal_range->min_qp;
+		hfi->max_qp = hal_range->max_qp;
+		hfi->layer_id = hal_range->layer_id;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_quantization_range);
+		break;
+	}
+	case HAL_PARAM_VENC_SEARCH_RANGE:
+	{
+		struct hfi_vc1e_perf_cfg_type *hfi;
+		struct hal_vc1e_perf_cfg_type *hal_mv_searchrange =
+			(struct hal_vc1e_perf_cfg_type *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG;
+		hfi = (struct hfi_vc1e_perf_cfg_type *)
+				&pkt->rg_property_data[1];
+		hfi->search_range_x_subsampled[0] =
+			hal_mv_searchrange->i_frame.x_subsampled;
+		hfi->search_range_x_subsampled[1] =
+			hal_mv_searchrange->p_frame.x_subsampled;
+		hfi->search_range_x_subsampled[2] =
+			hal_mv_searchrange->b_frame.x_subsampled;
+		hfi->search_range_y_subsampled[0] =
+			hal_mv_searchrange->i_frame.y_subsampled;
+		hfi->search_range_y_subsampled[1] =
+			hal_mv_searchrange->p_frame.y_subsampled;
+		hfi->search_range_y_subsampled[2] =
+			hal_mv_searchrange->b_frame.y_subsampled;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_vc1e_perf_cfg_type);
+		break;
+	}
+	case HAL_PARAM_VENC_MAX_NUM_B_FRAMES:
+	{
+		struct hfi_max_num_b_frames *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES;
+		hfi = (struct hfi_max_num_b_frames *) &pkt->rg_property_data[1];
+		memcpy(hfi, (struct hfi_max_num_b_frames *) pdata,
+				sizeof(struct hfi_max_num_b_frames));
+		pkt->size += sizeof(u32) + sizeof(struct hfi_max_num_b_frames);
+		break;
+	}
+	case HAL_CONFIG_VENC_INTRA_PERIOD:
+	{
+		struct hfi_intra_period *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD;
+		hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1];
+		memcpy(hfi, (struct hfi_intra_period *) pdata,
+				sizeof(struct hfi_intra_period));
+		pkt->size += sizeof(u32) + sizeof(struct hfi_intra_period);
+		break;
+	}
+	case HAL_CONFIG_VENC_IDR_PERIOD:
+	{
+		struct hfi_idr_period *hfi;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
+		hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1];
+		hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_CONCEAL_COLOR:
+	{
+		struct hfi_conceal_color *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+		hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+		if (hfi)
+			hfi->conceal_color =
+				((struct hfi_conceal_color *) pdata)->
+				conceal_color;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VPE_OPERATIONS:
+	{
+		struct hfi_operations_type *hfi;
+
+		struct hal_operations *prop =
+			(struct hal_operations *) pdata;
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
+		hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+		switch (prop->rotate) {
+		case HAL_ROTATE_NONE:
+			hfi->rotation = HFI_ROTATE_NONE;
+			break;
+		case HAL_ROTATE_90:
+			hfi->rotation = HFI_ROTATE_90;
+			break;
+		case HAL_ROTATE_180:
+			hfi->rotation = HFI_ROTATE_180;
+			break;
+		case HAL_ROTATE_270:
+			hfi->rotation = HFI_ROTATE_270;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid rotation setting: %#x\n",
+				prop->rotate);
+			rc = -EINVAL;
+			break;
+		}
+		switch (prop->flip) {
+		case HAL_FLIP_NONE:
+			hfi->flip = HFI_FLIP_NONE;
+			break;
+		case HAL_FLIP_HORIZONTAL:
+			hfi->flip = HFI_FLIP_HORIZONTAL;
+			break;
+		case HAL_FLIP_VERTICAL:
+			hfi->flip = HFI_FLIP_VERTICAL;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid flip setting: %#x\n",
+				prop->flip);
+			rc = -EINVAL;
+			break;
+		}
+		pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
+		break;
+	}
+	case HAL_PARAM_VENC_INTRA_REFRESH:
+	{
+		struct hfi_intra_refresh *hfi;
+		struct hal_intra_refresh *prop =
+			(struct hal_intra_refresh *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+		hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1];
+		switch (prop->mode) {
+		case HAL_INTRA_REFRESH_NONE:
+			hfi->mode = HFI_INTRA_REFRESH_NONE;
+			break;
+		case HAL_INTRA_REFRESH_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+			break;
+		case HAL_INTRA_REFRESH_RANDOM:
+			hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Invalid intra refresh setting: %#x\n",
+					prop->mode);
+			break;
+		}
+		hfi->air_mbs = prop->air_mbs;
+		hfi->air_ref = prop->air_ref;
+		hfi->cir_mbs = prop->cir_mbs;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_intra_refresh);
+		break;
+	}
+	case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+	{
+		struct hfi_multi_slice_control *hfi;
+		struct hal_multi_slice_control *prop =
+			(struct hal_multi_slice_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL;
+		hfi = (struct hfi_multi_slice_control *)
+			&pkt->rg_property_data[1];
+		switch (prop->multi_slice) {
+		case HAL_MULTI_SLICE_OFF:
+			hfi->multi_slice = HFI_MULTI_SLICE_OFF;
+			break;
+		case HAL_MULTI_SLICE_GOB:
+			hfi->multi_slice = HFI_MULTI_SLICE_GOB;
+			break;
+		case HAL_MULTI_SLICE_BY_MB_COUNT:
+			hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT;
+			break;
+		case HAL_MULTI_SLICE_BY_BYTE_COUNT:
+			hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid slice settings: %#x\n",
+				prop->multi_slice);
+			break;
+		}
+		hfi->slice_size = prop->slice_size;
+		pkt->size += sizeof(u32) + sizeof(struct
+					hfi_multi_slice_control);
+		break;
+	}
+	case HAL_PARAM_INDEX_EXTRADATA:
+	{
+		struct hfi_index_extradata_config *hfi;
+		struct hal_extradata_enable *extra = pdata;
+		int id = 0;
+
+		pkt->rg_property_data[0] =
+			get_hfi_extradata_index(extra->index);
+		hfi = (struct hfi_index_extradata_config *)
+			&pkt->rg_property_data[1];
+		hfi->enable = extra->enable;
+		id = get_hfi_extradata_id(extra->index);
+		if (id)
+			hfi->index_extra_data_id = id;
+		else {
+			dprintk(VIDC_WARN,
+				"Failed to find extradata id: %d\n",
+				id);
+			rc = -EINVAL;
+		}
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_index_extradata_config);
+		break;
+	}
+	case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_VUI_TIMING_INFO:
+	{
+		struct hfi_h264_vui_timing_info *hfi;
+		struct hal_h264_vui_timing_info *timing_info = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
+
+		hfi = (struct hfi_h264_vui_timing_info *)&pkt->
+			rg_property_data[1];
+		hfi->enable = timing_info->enable;
+		hfi->fixed_frame_rate = timing_info->fixed_frame_rate;
+		hfi->time_scale = timing_info->time_scale;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_h264_vui_timing_info);
+		break;
+	}
+	case HAL_CONFIG_VPE_DEINTERLACE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_CONFIG_VPE_DEINTERLACE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_GENERATE_AUDNAL:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_BUFFER_ALLOC_MODE:
+	{
+		u32 buffer_type;
+		u32 buffer_mode;
+		struct hfi_buffer_alloc_mode *hfi;
+		struct hal_buffer_alloc_mode *alloc_info = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
+		hfi = (struct hfi_buffer_alloc_mode *)
+			&pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(alloc_info->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		buffer_mode = get_hfi_buf_mode(alloc_info->buffer_mode);
+		if (buffer_mode)
+			hfi->buffer_mode = buffer_mode;
+		else
+			return -EINVAL;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_buffer_alloc_mode);
+		break;
+	}
+	case HAL_PARAM_VDEC_FRAME_ASSEMBLY:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VDEC_SCS_THRESHOLD:
+	{
+		struct hfi_scs_threshold *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD;
+		hfi = (struct hfi_scs_threshold *) &pkt->rg_property_data[1];
+		hfi->threshold_value =
+			((struct hal_scs_threshold *) pdata)->threshold_value;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_scs_threshold);
+		break;
+	}
+	case HAL_PARAM_MVC_BUFFER_LAYOUT:
+	{
+		struct hfi_mvc_buffer_layout_descp_type *hfi;
+		struct hal_mvc_buffer_layout *layout_info = pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT;
+		hfi = (struct hfi_mvc_buffer_layout_descp_type *)
+			&pkt->rg_property_data[1];
+		hfi->layout_type = get_hfi_layout(layout_info->layout_type);
+		hfi->bright_view_first = layout_info->bright_view_first;
+		hfi->ngap = layout_info->ngap;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_mvc_buffer_layout_descp_type);
+		break;
+	}
+	case HAL_PARAM_VENC_LTRMODE:
+	{
+		struct hfi_ltr_mode *hfi;
+		struct hal_ltr_mode *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_LTRMODE;
+		hfi = (struct hfi_ltr_mode *) &pkt->rg_property_data[1];
+		hfi->ltr_mode = get_hfi_ltr_mode(hal->mode);
+		hfi->ltr_count = hal->count;
+		hfi->trust_mode = hal->trust_mode;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mode);
+		break;
+	}
+	case HAL_CONFIG_VENC_USELTRFRAME:
+	{
+		struct hfi_ltr_use *hfi;
+		struct hal_ltr_use *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_USELTRFRAME;
+		hfi = (struct hfi_ltr_use *) &pkt->rg_property_data[1];
+		hfi->frames = hal->frames;
+		hfi->ref_ltr = hal->ref_ltr;
+		hfi->use_constrnt = hal->use_constraint;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_use);
+		break;
+	}
+	case HAL_CONFIG_VENC_MARKLTRFRAME:
+	{
+		struct hfi_ltr_mark *hfi;
+		struct hal_ltr_mark *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME;
+		hfi = (struct hfi_ltr_mark *) &pkt->rg_property_data[1];
+		hfi->mark_frame = hal->mark_frame;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mark);
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_ENABLE_INITIAL_QP:
+	{
+		struct hfi_initial_quantization *hfi;
+		struct hal_initial_quantization *quant = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INITIAL_QP;
+		hfi = (struct hfi_initial_quantization *)
+			&pkt->rg_property_data[1];
+		hfi->init_qp_enable = quant->init_qp_enable;
+		hfi->qp_i = quant->qpi;
+		hfi->qp_p = quant->qpp;
+		hfi->qp_b = quant->qpb;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_initial_quantization);
+		break;
+	}
+	case HAL_PARAM_VPE_COLOR_SPACE_CONVERSION:
+	{
+		struct hfi_vpe_color_space_conversion *hfi = NULL;
+		struct hal_vpe_color_space_conversion *hal = pdata;
+
+		pkt->rg_property_data[0] =
+				HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION;
+		hfi = (struct hfi_vpe_color_space_conversion *)
+			&pkt->rg_property_data[1];
+		memcpy(hfi->csc_matrix, hal->csc_matrix,
+				sizeof(hfi->csc_matrix));
+		memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias));
+		memcpy(hfi->csc_limit, hal->csc_limit, sizeof(hfi->csc_limit));
+		pkt->size += sizeof(u32) +
+				sizeof(struct hfi_vpe_color_space_conversion);
+		break;
+	}
+	case HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_NAL_SVC_EXT:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_CONFIG_VENC_PERF_MODE:
+	{
+		u32 hfi_perf_mode = 0;
+		enum hal_perf_mode hal_perf_mode = *(enum hal_perf_mode *)pdata;
+
+		switch (hal_perf_mode) {
+		case HAL_PERF_MODE_POWER_SAVE:
+			hfi_perf_mode = HFI_VENC_PERFMODE_POWER_SAVE;
+			break;
+		case HAL_PERF_MODE_POWER_MAX_QUALITY:
+			hfi_perf_mode = HFI_VENC_PERFMODE_MAX_QUALITY;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+		pkt->rg_property_data[1] = hfi_perf_mode;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_NON_SECURE_OUTPUT2:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_P_HYBRID_MODE:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE;
+		pkt->rg_property_data[1] =
+			((struct hfi_hybrid_hierp *)pdata)->layers;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_hybrid_hierp);
+		break;
+	}
+	case HAL_PARAM_VENC_MBI_STATISTICS_MODE:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+		pkt->rg_property_data[1] = hal_to_hfi_type(
+			HAL_PARAM_VENC_MBI_STATISTICS_MODE,
+				*(u32 *)pdata);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_FRAME_QP:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_FRAME_QP;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_BASELAYER_PRIORITYID:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO:
+	{
+		struct hfi_aspect_ratio *hfi = NULL;
+		struct hal_aspect_ratio *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+		hfi = (struct hfi_aspect_ratio *)
+			&pkt->rg_property_data[1];
+		memcpy(hfi, hal,
+			sizeof(struct hfi_aspect_ratio));
+		pkt->size += sizeof(u32) +
+				sizeof(struct hfi_aspect_ratio);
+		break;
+	}
+	case HAL_PARAM_VENC_BITRATE_TYPE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_VIDEO_SIGNAL_INFO:
+	{
+		struct hal_video_signal_info *hal = pdata;
+		struct hfi_video_signal_metadata *signal_info =
+			(struct hfi_video_signal_metadata *)
+			&pkt->rg_property_data[1];
+
+		signal_info->enable = true;
+		signal_info->video_format = MSM_VIDC_NTSC;
+		signal_info->video_full_range = hal->full_range;
+		signal_info->color_description = MSM_VIDC_COLOR_DESC_PRESENT;
+		signal_info->color_primaries = hal->color_space;
+		signal_info->transfer_characteristics = hal->transfer_chars;
+		signal_info->matrix_coeffs = hal->matrix_coeffs;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pkt->size += sizeof(u32) + sizeof(*signal_info);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_TRANSFORM_8x8:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_IFRAMESIZE_TYPE:
+	{
+		enum hal_iframesize_type hal =
+			*(enum hal_iframesize_type *)pdata;
+		struct hfi_iframe_size *hfi = (struct hfi_iframe_size *)
+			&pkt->rg_property_data[1];
+
+		switch (hal) {
+		case HAL_IFRAMESIZE_TYPE_DEFAULT:
+			hfi->type = HFI_IFRAME_SIZE_DEFAULT;
+			break;
+		case HAL_IFRAMESIZE_TYPE_MEDIUM:
+			hfi->type = HFI_IFRAME_SIZE_MEDIUM;
+			break;
+		case HAL_IFRAMESIZE_TYPE_HUGE:
+			hfi->type = HFI_IFRAME_SIZE_HIGH;
+			break;
+		case HAL_IFRAMESIZE_TYPE_UNLIMITED:
+			hfi->type = HFI_IFRAME_SIZE_UNLIMITED;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VENC_IFRAMESIZE;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_iframe_size);
+		break;
+	}
+	/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
+	case HAL_CONFIG_BUFFER_REQUIREMENTS:
+	case HAL_CONFIG_PRIORITY:
+	case HAL_CONFIG_BATCH_INFO:
+	case HAL_PARAM_METADATA_PASS_THROUGH:
+	case HAL_SYS_IDLE_INDICATOR:
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+	case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+	case HAL_PARAM_CHROMA_SITE:
+	case HAL_PARAM_PROPERTIES_SUPPORTED:
+	case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+	case HAL_PARAM_CAPABILITY_SUPPORTED:
+	case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+	case HAL_PARAM_MULTI_VIEW_FORMAT:
+	case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+	case HAL_PARAM_CODEC_SUPPORTED:
+	case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+	case HAL_PARAM_VDEC_MB_QUANTIZATION:
+	case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+	case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+	case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+	case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+	case HAL_CONFIG_VDEC_MULTI_STREAM:
+	case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+	case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+	case HAL_PARAM_BUFFER_SIZE_MINIMUM:
+	default:
+		dprintk(VIDC_ERR, "DEFAULT: Calling %#x\n", ptype);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
+{
+	int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+
+	switch (type) {
+	case SSR_ERR_FATAL:
+		rc = HFI_TEST_SSR_SW_ERR_FATAL;
+		break;
+	case SSR_SW_DIV_BY_ZERO:
+		rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
+		break;
+	case SSR_HW_WDOG_IRQ:
+		rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+		break;
+	default:
+		dprintk(VIDC_WARN,
+			"SSR trigger type not recognized, using WDOG.\n");
+	}
+	return rc;
+}
+
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid params, device: %pK\n", pkt);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
+	pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
+	pkt->trigger_type = get_hfi_ssr_type(type);
+	return 0;
+}
+
+int create_pkt_cmd_sys_image_version(
+		struct hfi_cmd_sys_get_property_packet *pkt)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "%s invalid param :%pK\n", __func__, pkt);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet);
+	pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION;
+	return 0;
+}
+
+static int create_3x_pkt_cmd_session_set_property(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !pdata)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+
+	/*
+	 * Any session set property which is different in 3XX packetization
+	 * should be added as a new case below. All unchanged session set
+	 * properties will be handled in the default case.
+	 */
+	switch (ptype) {
+	case HAL_PARAM_VDEC_MULTI_STREAM:
+	{
+		u32 buffer_type;
+		struct hfi_3x_multi_stream *hfi;
+		struct hal_multi_stream *prop =
+			(struct hal_multi_stream *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+		hfi = (struct hfi_3x_multi_stream *) &pkt->rg_property_data[1];
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->enable = prop->enable;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_3x_multi_stream);
+		break;
+	}
+	case HAL_PARAM_VENC_INTRA_REFRESH:
+	{
+		struct hfi_3x_intra_refresh *hfi;
+		struct hal_intra_refresh *prop =
+			(struct hal_intra_refresh *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+		hfi = (struct hfi_3x_intra_refresh *) &pkt->rg_property_data[1];
+		hfi->mbs = 0;
+		switch (prop->mode) {
+		case HAL_INTRA_REFRESH_NONE:
+			hfi->mode = HFI_INTRA_REFRESH_NONE;
+			break;
+		case HAL_INTRA_REFRESH_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+			hfi->mbs = prop->air_mbs;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+			hfi->mbs = prop->cir_mbs;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+			hfi->mbs = prop->air_mbs;
+			break;
+		case HAL_INTRA_REFRESH_RANDOM:
+			hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+			hfi->mbs = prop->air_mbs;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Invalid intra refresh setting: %d\n",
+				prop->mode);
+			break;
+		}
+		pkt->size += sizeof(u32) + sizeof(struct hfi_3x_intra_refresh);
+		break;
+	}
+	case HAL_PARAM_SYNC_BASED_INTERRUPT:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_VQZIP_SEI:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_VQZIP_SEI_TYPE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	/* Deprecated param on Venus 3xx */
+	case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+	{
+		rc = -ENOTSUPP;
+		break;
+	}
+	case HAL_PARAM_BUFFER_SIZE_MINIMUM:
+	{
+		struct hfi_buffer_size_minimum *hfi;
+		struct hal_buffer_size_minimum *prop =
+			(struct hal_buffer_size_minimum *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM;
+
+		hfi = (struct hfi_buffer_size_minimum *)
+			&pkt->rg_property_data[1];
+		hfi->buffer_size = prop->buffer_size;
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		pkt->size += sizeof(u32) + sizeof(struct
+				hfi_buffer_count_actual);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_PIC_ORDER_CNT:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_LOW_LATENCY:
+	{
+		struct hfi_enable *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE;
+		hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+		hfi->enable = ((struct hal_enable *) pdata)->enable;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_BLUR_RESOLUTION:
+	{
+		struct hfi_frame_size *hfi;
+		struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE;
+		hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->height = prop->height;
+		hfi->width = prop->width;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+		break;
+	}
+	default:
+		rc = create_pkt_cmd_session_set_property(pkt,
+				session, ptype, pdata);
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_sync_process(
+		struct hfi_cmd_session_sync_process_packet *pkt,
+		struct hal_session *session)
+{
+	if (!pkt || !session)
+		return -EINVAL;
+
+	*pkt = (struct hfi_cmd_session_sync_process_packet) {0};
+	pkt->size = sizeof(*pkt);
+	pkt->packet_type = HFI_CMD_SESSION_SYNC;
+	pkt->session_id = hash32_ptr(session);
+	pkt->sync_id = 0;
+
+	return 0;
+}
+
+static struct hfi_packetization_ops hfi_default = {
+	.sys_init = create_pkt_cmd_sys_init,
+	.sys_pc_prep = create_pkt_cmd_sys_pc_prep,
+	.sys_idle_indicator = create_pkt_cmd_sys_idle_indicator,
+	.sys_power_control = create_pkt_cmd_sys_power_control,
+	.sys_set_resource = create_pkt_cmd_sys_set_resource,
+	.sys_debug_config = create_pkt_cmd_sys_debug_config,
+	.sys_coverage_config = create_pkt_cmd_sys_coverage_config,
+	.sys_release_resource = create_pkt_cmd_sys_release_resource,
+	.sys_ping = create_pkt_cmd_sys_ping,
+	.sys_image_version = create_pkt_cmd_sys_image_version,
+	.ssr_cmd = create_pkt_ssr_cmd,
+	.session_init = create_pkt_cmd_sys_session_init,
+	.session_cmd = create_pkt_cmd_session_cmd,
+	.session_set_buffers = create_pkt_cmd_session_set_buffers,
+	.session_release_buffers = create_pkt_cmd_session_release_buffers,
+	.session_etb_decoder = create_pkt_cmd_session_etb_decoder,
+	.session_etb_encoder = create_pkt_cmd_session_etb_encoder,
+	.session_ftb = create_pkt_cmd_session_ftb,
+	.session_parse_seq_header = create_pkt_cmd_session_parse_seq_header,
+	.session_get_seq_hdr = create_pkt_cmd_session_get_seq_hdr,
+	.session_get_buf_req = create_pkt_cmd_session_get_buf_req,
+	.session_flush = create_pkt_cmd_session_flush,
+	.session_get_property = create_pkt_cmd_session_get_property,
+	.session_set_property = create_pkt_cmd_session_set_property,
+};
+
+struct hfi_packetization_ops *get_venus_3x_ops(void)
+{
+	static struct hfi_packetization_ops hfi_venus_3x;
+
+	hfi_venus_3x = hfi_default;
+
+	/* Override new HFI functions for HFI_PACKETIZATION_3XX here. */
+	hfi_venus_3x.session_set_property =
+		create_3x_pkt_cmd_session_set_property;
+	hfi_venus_3x.session_get_property =
+		create_3x_pkt_cmd_session_get_property;
+	hfi_venus_3x.session_cmd = create_3x_pkt_cmd_session_cmd;
+	hfi_venus_3x.session_sync_process = create_pkt_cmd_session_sync_process;
+
+	return &hfi_venus_3x;
+}
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+			enum hfi_packetization_type type)
+{
+	dprintk(VIDC_DBG, "%s selected\n",
+		type == HFI_PACKETIZATION_LEGACY ? "legacy packetization" :
+		type == HFI_PACKETIZATION_3XX ? "3xx packetization" :
+		"Unknown hfi");
+
+	switch (type) {
+	case HFI_PACKETIZATION_LEGACY:
+		return &hfi_default;
+	case HFI_PACKETIZATION_3XX:
+		return get_venus_3x_ops();
+	}
+
+	return NULL;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_packetization.h b/drivers/media/platform/msm/vidc_3x/hfi_packetization.h
new file mode 100644
index 0000000..5fcbc5c
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_packetization.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __HFI_PACKETIZATION__
+#define __HFI_PACKETIZATION__
+
+#include <linux/types.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi.h"
+#include "vidc_hfi_api.h"
+
+#define call_hfi_pkt_op(q, op, args...)			\
+	(((q) && (q)->pkt_ops && (q)->pkt_ops->op) ?	\
+	((q)->pkt_ops->op(args)) : 0)
+
+enum hfi_packetization_type {
+	HFI_PACKETIZATION_LEGACY,
+	HFI_PACKETIZATION_3XX,
+};
+
+struct hfi_packetization_ops {
+	int (*sys_init)(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type);
+	int (*sys_pc_prep)(struct hfi_cmd_sys_pc_prep_packet *pkt);
+	int (*sys_idle_indicator)(struct hfi_cmd_sys_set_property_packet *pkt,
+		u32 enable);
+	int (*sys_power_control)(struct hfi_cmd_sys_set_property_packet *pkt,
+		u32 enable);
+	int (*sys_set_resource)(
+		struct hfi_cmd_sys_set_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr,
+		void *resource_value);
+	int (*sys_debug_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+			u32 mode);
+	int (*sys_coverage_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+			u32 mode);
+	int (*sys_release_resource)(
+		struct hfi_cmd_sys_release_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr);
+	int (*sys_ping)(struct hfi_cmd_sys_ping_packet *pkt);
+	int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt);
+	int (*ssr_cmd)(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt);
+	int (*session_init)(
+		struct hfi_cmd_sys_session_init_packet *pkt,
+		struct hal_session *session,
+		u32 session_domain, u32 session_codec);
+	int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt,
+		int pkt_type, struct hal_session *session);
+	int (*session_set_buffers)(
+		struct hfi_cmd_session_set_buffers_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info);
+	int (*session_release_buffers)(
+		struct hfi_cmd_session_release_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info);
+	int (*session_etb_decoder)(
+		struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *input_frame);
+	int (*session_etb_encoder)(
+		struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+		*pkt, struct hal_session *session,
+		struct vidc_frame_data *input_frame);
+	int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *output_frame);
+	int (*session_parse_seq_header)(
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_seq_hdr)(
+		struct hfi_cmd_session_get_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_buf_req)(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session);
+	int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt,
+		struct hal_session *session, enum hal_flush flush_mode);
+	int (*session_get_property)(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype);
+	int (*session_set_property)(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata);
+	int (*session_sync_process)(
+		struct hfi_cmd_session_sync_process_packet *pkt,
+		struct hal_session *session);
+};
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+		enum hfi_packetization_type);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
new file mode 100644
index 0000000..ffcbdd9
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
@@ -0,0 +1,1958 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/hash.h>
+#include <soc/qcom/smem.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_io.h"
+#include "msm_vidc_debug.h"
+#include "vidc_hfi.h"
+
+static enum vidc_status hfi_parse_init_done_properties(
+		struct msm_vidc_capability *capability,
+		u32 num_sessions, u8 *data_ptr, u32 num_properties,
+		u32 rem_bytes, u32 codec, u32 domain);
+
+static enum vidc_status hfi_map_err_status(u32 hfi_err)
+{
+	enum vidc_status vidc_err;
+
+	switch (hfi_err) {
+	case HFI_ERR_NONE:
+	case HFI_ERR_SESSION_SAME_STATE_OPERATION:
+		vidc_err = VIDC_ERR_NONE;
+		break;
+	case HFI_ERR_SYS_FATAL:
+		vidc_err = VIDC_ERR_HW_FATAL;
+		break;
+	case HFI_ERR_SYS_VERSION_MISMATCH:
+	case HFI_ERR_SYS_INVALID_PARAMETER:
+	case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE:
+	case HFI_ERR_SESSION_INVALID_PARAMETER:
+	case HFI_ERR_SESSION_INVALID_SESSION_ID:
+	case HFI_ERR_SESSION_INVALID_STREAM_ID:
+		vidc_err = VIDC_ERR_BAD_PARAM;
+		break;
+	case HFI_ERR_SYS_INSUFFICIENT_RESOURCES:
+	case HFI_ERR_SYS_UNSUPPORTED_DOMAIN:
+	case HFI_ERR_SYS_UNSUPPORTED_CODEC:
+	case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY:
+	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+	case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES:
+	case HFI_ERR_SESSION_UNSUPPORTED_STREAM:
+		vidc_err = VIDC_ERR_NOT_SUPPORTED;
+		break;
+	case HFI_ERR_SYS_MAX_SESSIONS_REACHED:
+		vidc_err = VIDC_ERR_MAX_CLIENTS;
+		break;
+	case HFI_ERR_SYS_SESSION_IN_USE:
+		vidc_err = VIDC_ERR_CLIENT_PRESENT;
+		break;
+	case HFI_ERR_SESSION_FATAL:
+		vidc_err = VIDC_ERR_CLIENT_FATAL;
+		break;
+	case HFI_ERR_SESSION_BAD_POINTER:
+		vidc_err = VIDC_ERR_BAD_PARAM;
+		break;
+	case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION:
+		vidc_err = VIDC_ERR_BAD_STATE;
+		break;
+	case HFI_ERR_SESSION_STREAM_CORRUPT:
+	case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED:
+		vidc_err = VIDC_ERR_BITSTREAM_ERR;
+		break;
+	case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED:
+		vidc_err = VIDC_ERR_IFRAME_EXPECTED;
+		break;
+	case HFI_ERR_SESSION_START_CODE_NOT_FOUND:
+		vidc_err = VIDC_ERR_START_CODE_NOT_FOUND;
+		break;
+	case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING:
+	default:
+		vidc_err = VIDC_ERR_FAIL;
+		break;
+	}
+	return vidc_err;
+}
+
+static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth)
+{
+	switch (hfi_bit_depth) {
+	case HFI_BITDEPTH_8: return MSM_VIDC_BIT_DEPTH_8;
+	case HFI_BITDEPTH_9:
+	case HFI_BITDEPTH_10: return MSM_VIDC_BIT_DEPTH_10;
+	}
+	dprintk(VIDC_ERR, "Unsupported bit depth: %d\n", hfi_bit_depth);
+	return MSM_VIDC_BIT_DEPTH_UNSUPPORTED;
+}
+
+static int hfi_process_sess_evt_seq_changed(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_event event_notify = {0};
+	int num_properties_changed;
+	struct hfi_frame_size *frame_sz;
+	struct hfi_profile_level *profile_level;
+	struct hfi_bit_depth *pixel_depth;
+	struct hfi_pic_struct *pic_struct;
+	u8 *data_ptr;
+	int prop_id;
+	enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth;
+	struct hfi_colour_space *colour_info;
+
+	 /* Initialize pic_struct to unknown as default */
+	//event_notify.pic_struct = MSM_VIDC_PIC_STRUCT_UNKNOWN;
+
+	if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	event_notify.device_id = device_id;
+	event_notify.session_id = (void *)(uintptr_t)pkt->session_id;
+	event_notify.status = VIDC_ERR_NONE;
+	num_properties_changed = pkt->event_data2;
+	switch (pkt->event_data1) {
+	case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES:
+		event_notify.hal_event_type =
+			HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES;
+		break;
+	case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES:
+		event_notify.hal_event_type =
+			HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES;
+		break;
+	default:
+		break;
+	}
+
+	if (num_properties_changed) {
+		data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+		do {
+			prop_id = (int) *((u32 *)data_ptr);
+			switch (prop_id) {
+			case HFI_PROPERTY_PARAM_FRAME_SIZE:
+				data_ptr = data_ptr + sizeof(u32);
+				frame_sz =
+					(struct hfi_frame_size *) data_ptr;
+				event_notify.width = frame_sz->width;
+				event_notify.height = frame_sz->height;
+				dprintk(VIDC_DBG, "height: %d width: %d\n",
+					frame_sz->height, frame_sz->width);
+				data_ptr +=
+					sizeof(struct hfi_frame_size);
+				break;
+			case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+				data_ptr = data_ptr + sizeof(u32);
+				profile_level =
+					(struct hfi_profile_level *) data_ptr;
+				dprintk(VIDC_DBG, "profile: %d level: %d\n",
+					profile_level->profile,
+					profile_level->level);
+				data_ptr +=
+					sizeof(struct hfi_profile_level);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
+				data_ptr = data_ptr + sizeof(u32);
+				pixel_depth = (struct hfi_bit_depth *) data_ptr;
+				/*
+				 * Luma and chroma can have different bitdepths.
+				 * Driver should rely on luma and chroma
+				 * bitdepth for determining output bitdepth
+				 * type.
+				 *
+				 * pixel_depth->bitdepth will include luma
+				 * bitdepth info in bits 0..15 and chroma
+				 * bitdept in bits 16..31.
+				 */
+				luma_bit_depth = get_hal_pixel_depth(
+					pixel_depth->bit_depth &
+					GENMASK(15, 0));
+				chroma_bit_depth = get_hal_pixel_depth(
+					(pixel_depth->bit_depth &
+					GENMASK(31, 16)) >> 16);
+				if (luma_bit_depth == MSM_VIDC_BIT_DEPTH_10 ||
+					chroma_bit_depth ==
+						MSM_VIDC_BIT_DEPTH_10)
+					event_notify.bit_depth =
+						MSM_VIDC_BIT_DEPTH_10;
+				else
+					event_notify.bit_depth = luma_bit_depth;
+				dprintk(VIDC_DBG,
+					"bitdepth(%d), luma_bit_depth(%d), chroma_bit_depth(%d)\n",
+					event_notify.bit_depth, luma_bit_depth,
+					chroma_bit_depth);
+				data_ptr += sizeof(struct hfi_bit_depth);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
+				data_ptr = data_ptr + sizeof(u32);
+				pic_struct = (struct hfi_pic_struct *) data_ptr;
+				event_notify.pic_struct =
+					pic_struct->progressive_only;
+				dprintk(VIDC_DBG,
+					"Progressive only flag: %d\n",
+						pic_struct->progressive_only);
+				data_ptr +=
+					sizeof(struct hfi_pic_struct);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
+				data_ptr = data_ptr + sizeof(u32);
+				colour_info =
+					(struct hfi_colour_space *) data_ptr;
+				event_notify.colour_space =
+					colour_info->colour_space;
+				dprintk(VIDC_DBG,
+					"Colour space value is: %d\n",
+						colour_info->colour_space);
+				data_ptr +=
+					sizeof(struct hfi_colour_space);
+				break;
+			default:
+				dprintk(VIDC_ERR,
+					"%s cmd: %#x not supported\n",
+					__func__, prop_id);
+				break;
+			}
+			num_properties_changed--;
+		} while (num_properties_changed > 0);
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_EVENT_CHANGE,
+		.response.event = event_notify,
+	};
+
+	return 0;
+}
+
+static int hfi_process_evt_release_buffer_ref(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_event event_notify = {0};
+	struct hfi_msg_release_buffer_ref_event_packet *data;
+
+	dprintk(VIDC_DBG,
+			"RECEIVED: EVENT_NOTIFY - release_buffer_reference\n");
+	if (sizeof(struct hfi_msg_event_notify_packet)
+		> pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	data = (struct hfi_msg_release_buffer_ref_event_packet *)
+				pkt->rg_ext_event_data;
+
+	event_notify.device_id = device_id;
+	event_notify.session_id = (void *)(uintptr_t)pkt->session_id;
+	event_notify.status = VIDC_ERR_NONE;
+	event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+	event_notify.packet_buffer = data->packet_buffer;
+	event_notify.extra_data_buffer = data->extra_data_buffer;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_EVENT_CHANGE,
+		.response.event = event_notify,
+	};
+
+	return 0;
+}
+
+static int hfi_process_sys_error(u32 device_id, struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device_id;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_ERROR,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_error(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->event_data1);
+	dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %d\n",
+		pkt->event_data1);
+	switch (pkt->event_data1) {
+	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
+	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
+	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
+		cmd_done.status = VIDC_ERR_NONE;
+		dprintk(VIDC_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n");
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_ERROR,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	}
+}
+
+static int hfi_process_event_notify(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n");
+
+	if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -E2BIG;
+	}
+
+	switch (pkt->event_id) {
+	case HFI_EVENT_SYS_ERROR:
+		dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n",
+			pkt->event_data1, pkt->event_data2);
+		return hfi_process_sys_error(device_id, info);
+	case HFI_EVENT_SESSION_ERROR:
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR[%#x]\n",
+				pkt->session_id);
+		return hfi_process_session_error(device_id, pkt, info);
+
+	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%#x]\n",
+			pkt->session_id);
+		return hfi_process_sess_evt_seq_changed(device_id, pkt, info);
+
+	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+		dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%#x]\n",
+			pkt->session_id);
+		return hfi_process_evt_release_buffer_ref(device_id, pkt, info);
+
+	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
+	default:
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+		};
+
+		return 0;
+	}
+}
+
+static int hfi_process_sys_init_done(u32 device_id,
+		struct hfi_msg_sys_init_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	enum vidc_status status = VIDC_ERR_NONE;
+
+	dprintk(VIDC_DBG, "RECEIVED: SYS_INIT_DONE\n");
+	if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
+		dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", __func__,
+				pkt->size);
+		return -E2BIG;
+	}
+	if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+				"hal_process_sys_init_done: no_properties\n");
+		status = VIDC_ERR_FAIL;
+		goto err_no_prop;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: status %#x\n",
+			__func__, status);
+		goto err_no_prop;
+	}
+
+err_no_prop:
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = NULL;
+	cmd_done.status = (u32)status;
+	cmd_done.size = sizeof(struct vidc_hal_sys_init_done);
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_INIT_DONE,
+		.response.cmd = cmd_done,
+	};
+	return 0;
+}
+
+static int hfi_process_sys_rel_resource_done(u32 device_id,
+		struct hfi_msg_sys_release_resource_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 pkt_size;
+
+	dprintk(VIDC_DBG, "RECEIVED: SYS_RELEASE_RESOURCE_DONE\n");
+	pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
+	if (pkt_size > pkt->size) {
+		dprintk(VIDC_ERR,
+			"hal_process_sys_rel_resource_done: bad size: %d\n",
+			pkt->size);
+		return -E2BIG;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = NULL;
+	cmd_done.status = (u32) status;
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_RELEASE_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+enum hal_capability get_hal_cap_type(u32 capability_type)
+{
+	enum hal_capability hal_cap = 0;
+
+	switch (capability_type) {
+	case HFI_CAPABILITY_FRAME_WIDTH:
+		hal_cap = HAL_CAPABILITY_FRAME_WIDTH;
+		break;
+	case HFI_CAPABILITY_FRAME_HEIGHT:
+		hal_cap = HAL_CAPABILITY_FRAME_HEIGHT;
+		break;
+	case HFI_CAPABILITY_MBS_PER_FRAME:
+		hal_cap = HAL_CAPABILITY_MBS_PER_FRAME;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND:
+		hal_cap = HAL_CAPABILITY_MBS_PER_SECOND;
+		break;
+	case HFI_CAPABILITY_FRAMERATE:
+		hal_cap = HAL_CAPABILITY_FRAMERATE;
+		break;
+	case HFI_CAPABILITY_SCALE_X:
+		hal_cap = HAL_CAPABILITY_SCALE_X;
+		break;
+	case HFI_CAPABILITY_SCALE_Y:
+		hal_cap = HAL_CAPABILITY_SCALE_Y;
+		break;
+	case HFI_CAPABILITY_BITRATE:
+		hal_cap = HAL_CAPABILITY_BITRATE;
+		break;
+	case HFI_CAPABILITY_BFRAME:
+		hal_cap = HAL_CAPABILITY_BFRAME;
+		break;
+	case HFI_CAPABILITY_PEAKBITRATE:
+		hal_cap = HAL_CAPABILITY_PEAKBITRATE;
+		break;
+	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_ENC_LTR_COUNT:
+		hal_cap = HAL_CAPABILITY_ENC_LTR_COUNT;
+		break;
+	case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
+		hal_cap = HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD;
+		break;
+	case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_LCU_SIZE:
+		hal_cap = HAL_CAPABILITY_LCU_SIZE;
+		break;
+	case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE:
+		hal_cap = HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE;
+		break;
+	default:
+		dprintk(VIDC_DBG, "%s: unknown capablity %#x\n",
+			__func__, capability_type);
+		break;
+	}
+
+	return hal_cap;
+}
+
+static inline void copy_cap_prop(
+		struct hfi_capability_supported *in,
+		struct msm_vidc_capability *capability)
+{
+	struct hal_capability_supported *out = NULL;
+
+	if (!in || !capability) {
+		dprintk(VIDC_ERR, "%s Invalid input parameters\n",
+			__func__);
+		return;
+	}
+
+	switch (in->capability_type) {
+	case HFI_CAPABILITY_FRAME_WIDTH:
+		out = &capability->width;
+		break;
+	case HFI_CAPABILITY_FRAME_HEIGHT:
+		out = &capability->height;
+		break;
+	case HFI_CAPABILITY_MBS_PER_FRAME:
+		out = &capability->mbs_per_frame;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND:
+		out = &capability->mbs_per_sec;
+		break;
+	case HFI_CAPABILITY_FRAMERATE:
+		out = &capability->frame_rate;
+		break;
+	case HFI_CAPABILITY_SCALE_X:
+		out = &capability->scale_x;
+		break;
+	case HFI_CAPABILITY_SCALE_Y:
+		out = &capability->scale_y;
+		break;
+	case HFI_CAPABILITY_BITRATE:
+		out = &capability->bitrate;
+		break;
+	case HFI_CAPABILITY_BFRAME:
+		out = &capability->bframe;
+		break;
+	case HFI_CAPABILITY_PEAKBITRATE:
+		out = &capability->peakbitrate;
+		break;
+	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+		out = &capability->hier_p;
+		break;
+	case HFI_CAPABILITY_ENC_LTR_COUNT:
+		out = &capability->ltr_count;
+		break;
+	case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
+		out = &capability->secure_output2_threshold;
+		break;
+	case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS:
+		out = &capability->hier_b;
+		break;
+	case HFI_CAPABILITY_LCU_SIZE:
+		out = &capability->lcu_size;
+		break;
+	case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS:
+		out = &capability->hier_p_hybrid;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE:
+		out = &capability->mbs_per_sec_power_save;
+		break;
+	default:
+		dprintk(VIDC_DBG, "%s: unknown capablity %#x\n",
+			__func__, in->capability_type);
+		break;
+	}
+
+	if (out) {
+		out->capability_type = get_hal_cap_type(in->capability_type);
+		out->min = in->min;
+		out->max = in->max;
+		out->step_size = in->step_size;
+	}
+}
+
+static int hfi_fill_codec_info(u8 *data_ptr,
+		struct vidc_hal_sys_init_done *sys_init_done) {
+	u32 i;
+	u32 codecs = 0, codec_count = 0, size = 0;
+	struct msm_vidc_capability *capability;
+	u32 prop_id = *((u32 *)data_ptr);
+	u8 *orig_data_ptr = data_ptr;
+
+	if (prop_id ==  HFI_PROPERTY_PARAM_CODEC_SUPPORTED) {
+		struct hfi_codec_supported *prop;
+
+		data_ptr = data_ptr + sizeof(u32);
+		prop = (struct hfi_codec_supported *) data_ptr;
+		sys_init_done->dec_codec_supported =
+			prop->decoder_codec_supported;
+		sys_init_done->enc_codec_supported =
+			prop->encoder_codec_supported;
+		size = sizeof(struct hfi_codec_supported) + sizeof(u32);
+	} else {
+		dprintk(VIDC_WARN,
+			"%s: prop_id %#x, expected codec_supported property\n",
+			__func__, prop_id);
+	}
+
+	codecs = sys_init_done->dec_codec_supported;
+	for (i = 0; i < 8 * sizeof(codecs); i++) {
+		if ((1 << i) & codecs) {
+			capability =
+				&sys_init_done->capabilities[codec_count++];
+			capability->codec =
+				vidc_get_hal_codec((1 << i) & codecs);
+			capability->domain =
+				vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+		}
+	}
+	codecs = sys_init_done->enc_codec_supported;
+	for (i = 0; i < 8 * sizeof(codecs); i++) {
+		if ((1 << i) & codecs) {
+			capability =
+				&sys_init_done->capabilities[codec_count++];
+			capability->codec =
+				vidc_get_hal_codec((1 << i) & codecs);
+			capability->domain =
+				vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+		}
+	}
+	sys_init_done->codec_count = codec_count;
+
+	prop_id = *((u32 *)(orig_data_ptr + size));
+	if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) {
+		struct hfi_max_sessions_supported *prop =
+			(struct hfi_max_sessions_supported *)
+			(orig_data_ptr + size + sizeof(u32));
+
+		sys_init_done->max_sessions_supported = prop->max_sessions;
+		size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32);
+		dprintk(VIDC_DBG, "max_sessions_supported %d\n",
+				prop->max_sessions);
+	}
+	return size;
+}
+
+enum vidc_status hfi_process_session_init_done_prop_read(
+		struct hfi_msg_sys_session_init_done_packet *pkt,
+		struct vidc_hal_session_init_done *session_init_done)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	struct msm_vidc_capability *capability = NULL;
+	u32 rem_bytes, num_properties;
+	u8 *data_ptr;
+
+	rem_bytes = pkt->size - sizeof(struct
+			hfi_msg_sys_session_init_done_packet) + sizeof(u32);
+	if (!rem_bytes) {
+		dprintk(VIDC_ERR, "%s: invalid property info\n", __func__);
+		return VIDC_ERR_FAIL;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: error status 0x%x\n", __func__, status);
+		return status;
+	}
+
+	data_ptr = (u8 *)&pkt->rg_property_data[0];
+	num_properties = pkt->num_properties;
+
+	capability = &session_init_done->capability;
+	status = hfi_parse_init_done_properties(
+			capability, 1, data_ptr, num_properties, rem_bytes,
+			vidc_get_hfi_codec(capability->codec),
+			vidc_get_hfi_domain(capability->domain));
+	if (status) {
+		dprintk(VIDC_ERR, "%s: parse status 0x%x\n", __func__, status);
+		return status;
+	}
+
+	return status;
+}
+
+static int copy_caps_to_sessions(struct hfi_capability_supported *cap,
+		u32 num_caps, struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u32 codecs, u32 domain)
+{
+	u32 i = 0, j = 0;
+	struct msm_vidc_capability *capability;
+	u32 sess_codec;
+	u32 sess_domain;
+
+	/*
+	 * iterate over num_sessions and copy all the capabilities
+	 * to matching sessions.
+	 */
+	for (i = 0; i < num_sessions; i++) {
+		sess_codec = 0;
+		sess_domain = 0;
+		capability = &capabilities[i];
+
+		if (capability->codec)
+			sess_codec =
+				vidc_get_hfi_codec(capability->codec);
+		if (capability->domain)
+			sess_domain =
+				vidc_get_hfi_domain(capability->domain);
+
+		if (!(sess_codec & codecs && sess_domain & domain))
+			continue;
+
+		for (j = 0; j < num_caps; j++)
+			copy_cap_prop(&cap[j], capability);
+	}
+
+	return 0;
+}
+
+static int copy_alloc_mode_to_sessions(
+		struct hfi_buffer_alloc_mode_supported *prop,
+		struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u32 codecs, u32 domain)
+{
+	u32 i = 0, j = 0;
+	struct msm_vidc_capability *capability;
+	u32 sess_codec;
+	u32 sess_domain;
+
+	/*
+	 * iterate over num_sessions and copy all the entries
+	 * to matching sessions.
+	 */
+	for (i = 0; i < num_sessions; i++) {
+		sess_codec = 0;
+		sess_domain = 0;
+		capability = &capabilities[i];
+
+		if (capability->codec)
+			sess_codec =
+				vidc_get_hfi_codec(capability->codec);
+		if (capability->domain)
+			sess_domain =
+				vidc_get_hfi_domain(capability->domain);
+
+		if (!(sess_codec & codecs && sess_domain & domain))
+			continue;
+
+		for (j = 0; j < prop->num_entries; j++) {
+			if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
+				prop->buffer_type == HFI_BUFFER_OUTPUT2) {
+				switch (prop->rg_data[j]) {
+				case HFI_BUFFER_MODE_STATIC:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_STATIC;
+					break;
+				case HFI_BUFFER_MODE_RING:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_RING;
+					break;
+				case HFI_BUFFER_MODE_DYNAMIC:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_DYNAMIC;
+					break;
+				}
+			} else if (prop->buffer_type == HFI_BUFFER_INPUT) {
+				switch (prop->rg_data[j]) {
+				case HFI_BUFFER_MODE_STATIC:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_STATIC;
+					break;
+				case HFI_BUFFER_MODE_RING:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_RING;
+					break;
+				case HFI_BUFFER_MODE_DYNAMIC:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_DYNAMIC;
+					break;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static enum vidc_status hfi_parse_init_done_properties(
+		struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u8 *data_ptr, u32 num_properties,
+		u32 rem_bytes, u32 codecs, u32 domain)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 prop_id, next_offset;
+
+	while (status == VIDC_ERR_NONE && num_properties &&
+			rem_bytes >= sizeof(u32)) {
+
+		prop_id = *((u32 *)data_ptr);
+		next_offset = sizeof(u32);
+
+		switch (prop_id) {
+		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
+		{
+			struct hfi_codec_mask_supported *prop =
+				(struct hfi_codec_mask_supported *)
+				(data_ptr + next_offset);
+
+			codecs = prop->codecs;
+			domain = prop->video_domains;
+			next_offset += sizeof(struct hfi_codec_mask_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+		{
+			struct hfi_capability_supported_info *prop =
+				(struct hfi_capability_supported_info *)
+				(data_ptr + next_offset);
+
+			if ((rem_bytes - next_offset) < prop->num_capabilities *
+				sizeof(struct hfi_capability_supported)) {
+				status = VIDC_ERR_BAD_PARAM;
+				break;
+			}
+			next_offset += sizeof(u32) +
+				prop->num_capabilities *
+				sizeof(struct hfi_capability_supported);
+
+			copy_caps_to_sessions(&prop->rg_data[0],
+					prop->num_capabilities,
+					capabilities, num_sessions,
+					codecs, domain);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+		{
+			struct hfi_uncompressed_format_supported *prop =
+				(struct hfi_uncompressed_format_supported *)
+				(data_ptr + next_offset);
+			u32 num_format_entries;
+			char *fmt_ptr;
+			struct hfi_uncompressed_plane_info *plane_info;
+
+			if ((rem_bytes - next_offset) < sizeof(*prop)) {
+				status = VIDC_ERR_BAD_PARAM;
+				break;
+			}
+			num_format_entries = prop->format_entries;
+			next_offset = sizeof(*prop);
+			fmt_ptr = (char *)&prop->rg_format_info[0];
+
+			while (num_format_entries) {
+				u32 bytes_to_skip;
+
+				plane_info =
+				(struct hfi_uncompressed_plane_info *) fmt_ptr;
+
+				if ((rem_bytes - next_offset) <
+						sizeof(*plane_info)) {
+					status = VIDC_ERR_BAD_PARAM;
+					break;
+				}
+				bytes_to_skip = sizeof(*plane_info) -
+					sizeof(struct
+					hfi_uncompressed_plane_constraints) +
+					plane_info->num_planes *
+					sizeof(struct
+					hfi_uncompressed_plane_constraints);
+
+				fmt_ptr += bytes_to_skip;
+				next_offset += bytes_to_skip;
+				num_format_entries--;
+			}
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED:
+		{
+			struct hfi_properties_supported *prop =
+				(struct hfi_properties_supported *)
+				(data_ptr + next_offset);
+			next_offset += sizeof(*prop) - sizeof(u32)
+				+ prop->num_properties * sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+		{
+			struct msm_vidc_capability capability;
+			char *ptr = NULL;
+			u32 count = 0;
+			u32 prof_count = 0;
+			struct hfi_profile_level *prof_level;
+			struct hfi_profile_level_supported *prop =
+				(struct hfi_profile_level_supported *)
+				(data_ptr + next_offset);
+
+			ptr = (char *) &prop->rg_profile_level[0];
+			prof_count = prop->profile_count;
+			next_offset += sizeof(u32);
+
+			if (prof_count > MAX_PROFILE_COUNT) {
+				prof_count = MAX_PROFILE_COUNT;
+				dprintk(VIDC_WARN,
+					"prop count exceeds max profile count\n");
+				break;
+			}
+			while (prof_count) {
+				prof_level = (struct hfi_profile_level *)ptr;
+				capability.
+				profile_level.profile_level[count].profile
+					= prof_level->profile;
+				capability.
+				profile_level.profile_level[count].level
+					= prof_level->level;
+				prof_count--;
+				count++;
+				ptr += sizeof(struct hfi_profile_level);
+				next_offset += sizeof(struct hfi_profile_level);
+			}
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED:
+		{
+			next_offset +=
+				sizeof(struct hfi_interlace_format_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+		{
+			next_offset +=
+				sizeof(struct hfi_nal_stream_format_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT:
+		{
+			next_offset += sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+		{
+			next_offset += sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH:
+		{
+			next_offset +=
+				sizeof(struct hfi_intra_refresh);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
+		{
+			struct hfi_buffer_alloc_mode_supported *prop =
+				(struct hfi_buffer_alloc_mode_supported *)
+				(data_ptr + next_offset);
+
+			if (prop->num_entries >= 32) {
+				dprintk(VIDC_ERR,
+					"%s - num_entries: %d from f/w seems suspect\n",
+					__func__, prop->num_entries);
+				break;
+			}
+			next_offset +=
+				sizeof(struct hfi_buffer_alloc_mode_supported) -
+				sizeof(u32) + prop->num_entries * sizeof(u32);
+
+			copy_alloc_mode_to_sessions(prop,
+					capabilities, num_sessions,
+					codecs, domain);
+
+			num_properties--;
+			break;
+		}
+		default:
+			dprintk(VIDC_DBG,
+				"%s: default case - data_ptr %pK, prop_id 0x%x\n",
+				__func__, data_ptr, prop_id);
+			break;
+		}
+		rem_bytes -= next_offset;
+		data_ptr += next_offset;
+	}
+
+	return status;
+}
+
+enum vidc_status hfi_process_sys_init_done_prop_read(
+	struct hfi_msg_sys_init_done_packet *pkt,
+	struct vidc_hal_sys_init_done *sys_init_done)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 rem_bytes, bytes_read, num_properties;
+	u8 *data_ptr;
+	u32 codecs = 0, domain = 0;
+
+	if (!pkt || !sys_init_done) {
+		dprintk(VIDC_ERR,
+			"hfi_msg_sys_init_done: Invalid input\n");
+		return VIDC_ERR_FAIL;
+	}
+
+	rem_bytes = pkt->size - sizeof(struct
+			hfi_msg_sys_init_done_packet) + sizeof(u32);
+
+	if (!rem_bytes) {
+		dprintk(VIDC_ERR,
+			"hfi_msg_sys_init_done: missing_prop_info\n");
+		return VIDC_ERR_FAIL;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: status %#x\n", __func__, status);
+		return status;
+	}
+
+	data_ptr = (u8 *) &pkt->rg_property_data[0];
+	num_properties = pkt->num_properties;
+	dprintk(VIDC_DBG,
+		"%s: data_start %pK, num_properties %#x\n",
+		__func__, data_ptr, num_properties);
+	if (!num_properties) {
+		sys_init_done->capabilities = NULL;
+		dprintk(VIDC_DBG,
+			"Venus didn't set any properties in SYS_INIT_DONE");
+		return status;
+	}
+	bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done);
+	data_ptr += bytes_read;
+	rem_bytes -= bytes_read;
+	num_properties--;
+
+	status = hfi_parse_init_done_properties(
+			sys_init_done->capabilities,
+			VIDC_MAX_SESSIONS, data_ptr, num_properties,
+			rem_bytes, codecs, domain);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: parse status %#x\n",
+			__func__, status);
+		return status;
+	}
+
+	return status;
+}
+
+static void hfi_process_sess_get_prop_dec_entropy(
+	struct hfi_msg_session_property_info_packet *prop,
+	enum hal_h264_entropy *entropy)
+{
+	u32 req_bytes, hfi_entropy;
+
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+
+	if (!req_bytes || req_bytes % sizeof(hfi_entropy)) {
+		dprintk(VIDC_ERR, "%s: bad packet: %d\n", __func__, req_bytes);
+		return;
+	}
+
+	hfi_entropy = prop->rg_property_data[1];
+	*entropy =
+		hfi_entropy == HFI_H264_ENTROPY_CAVLC ? HAL_H264_ENTROPY_CAVLC :
+		hfi_entropy == HFI_H264_ENTROPY_CABAC ? HAL_H264_ENTROPY_CABAC :
+							HAL_UNUSED_ENTROPY;
+}
+
+static void hfi_process_sess_get_prop_profile_level(
+	struct hfi_msg_session_property_info_packet *prop,
+	struct hfi_profile_level *profile_level)
+{
+	struct hfi_profile_level *hfi_profile_level;
+	u32 req_bytes;
+
+	dprintk(VIDC_DBG, "Entered %s\n", __func__);
+	if (!prop) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_profile_level: bad_prop: %pK\n",
+			prop);
+		return;
+	}
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+
+	if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_profile_level: bad_pkt: %d\n",
+			req_bytes);
+		return;
+	}
+	hfi_profile_level = (struct hfi_profile_level *)
+				&prop->rg_property_data[1];
+	profile_level->profile = hfi_profile_level->profile;
+	profile_level->level = hfi_profile_level->level;
+	dprintk(VIDC_DBG, "%s profile: %d level: %d\n",
+		__func__, profile_level->profile,
+		profile_level->level);
+}
+
+static void hfi_process_sess_get_prop_buf_req(
+	struct hfi_msg_session_property_info_packet *prop,
+	struct buffer_requirements *buffreq)
+{
+	struct hfi_buffer_requirements *hfi_buf_req;
+	u32 req_bytes;
+
+	if (!prop) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_prop: %pK\n",
+			prop);
+		return;
+	}
+
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+	if (!req_bytes || req_bytes % sizeof(struct hfi_buffer_requirements) ||
+		!prop->rg_property_data[1]) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_pkt: %d\n",
+			req_bytes);
+		return;
+	}
+
+	hfi_buf_req = (struct hfi_buffer_requirements *)
+		&prop->rg_property_data[1];
+
+	if (!hfi_buf_req) {
+		dprintk(VIDC_ERR, "%s - invalid buffer req pointer\n",
+			__func__);
+		return;
+	}
+
+	while (req_bytes) {
+		if (hfi_buf_req->buffer_size &&
+			hfi_buf_req->buffer_count_min > hfi_buf_req->
+			buffer_count_actual)
+			dprintk(VIDC_WARN,
+				"Bad buffer requirements for %#x: min %d, actual %d\n",
+				hfi_buf_req->buffer_type,
+				hfi_buf_req->buffer_count_min,
+				hfi_buf_req->buffer_count_actual);
+
+		dprintk(VIDC_DBG, "got buffer requirements for: %d\n",
+					hfi_buf_req->buffer_type);
+		switch (hfi_buf_req->buffer_type) {
+		case HFI_BUFFER_INPUT:
+			memcpy(&buffreq->buffer[0], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT;
+			break;
+		case HFI_BUFFER_OUTPUT:
+			memcpy(&buffreq->buffer[1], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT;
+			break;
+		case HFI_BUFFER_OUTPUT2:
+			memcpy(&buffreq->buffer[2], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2;
+			break;
+		case HFI_BUFFER_EXTRADATA_INPUT:
+			memcpy(&buffreq->buffer[3], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[3].buffer_type =
+				HAL_BUFFER_EXTRADATA_INPUT;
+			break;
+		case HFI_BUFFER_EXTRADATA_OUTPUT:
+			memcpy(&buffreq->buffer[4], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[4].buffer_type =
+				HAL_BUFFER_EXTRADATA_OUTPUT;
+			break;
+		case HFI_BUFFER_EXTRADATA_OUTPUT2:
+			memcpy(&buffreq->buffer[5], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[5].buffer_type =
+				HAL_BUFFER_EXTRADATA_OUTPUT2;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH:
+			memcpy(&buffreq->buffer[6], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[6].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_1:
+			memcpy(&buffreq->buffer[7], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[7].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_1;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_2:
+			memcpy(&buffreq->buffer[8], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[8].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_2;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST:
+			memcpy(&buffreq->buffer[9], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[9].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST_1:
+			memcpy(&buffreq->buffer[10], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[10].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST_1;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
+			hfi_buf_req->buffer_type);
+			break;
+		}
+		req_bytes -= sizeof(struct hfi_buffer_requirements);
+		hfi_buf_req++;
+	}
+}
+
+static int hfi_process_session_prop_info(u32 device_id,
+		struct hfi_msg_session_property_info_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	struct hfi_profile_level profile_level = {0};
+	enum hal_h264_entropy entropy = HAL_UNUSED_ENTROPY;
+	struct buffer_requirements buff_req = { { {0} } };
+
+	dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%#x]\n",
+			pkt->session_id);
+
+	if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_prop_info: bad_pkt_size\n");
+		return -E2BIG;
+	} else if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+			"hal_process_session_prop_info: no_properties\n");
+		return -EINVAL;
+	}
+
+	switch (pkt->rg_property_data[0]) {
+	case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+		hfi_process_sess_get_prop_buf_req(pkt, &buff_req);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.buf_req = buff_req;
+		cmd_done.size = sizeof(buff_req);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+
+		return 0;
+	case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+		hfi_process_sess_get_prop_profile_level(pkt, &profile_level);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.profile_level =
+			(struct hal_profile_level) {
+				.profile = profile_level.profile,
+				.level = profile_level.level,
+			};
+		cmd_done.size = sizeof(struct hal_profile_level);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
+		hfi_process_sess_get_prop_dec_entropy(pkt, &entropy);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.h264_entropy = entropy;
+		cmd_done.size = sizeof(enum hal_h264_entropy);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_DBG,
+				"hal_process_session_prop_info: unknown_prop_id: %x\n",
+				pkt->rg_property_data[0]);
+		return -ENOTSUPP;
+	}
+}
+
+static int hfi_process_session_init_done(u32 device_id,
+		struct hfi_msg_sys_session_init_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	struct vidc_hal_session_init_done session_init_done = { {0} };
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%x]\n", pkt->session_id);
+
+	if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	if (!cmd_done.status) {
+		cmd_done.status = hfi_process_session_init_done_prop_read(
+			pkt, &session_init_done);
+	}
+
+	cmd_done.data.session_init_done = session_init_done;
+	cmd_done.size = sizeof(struct vidc_hal_session_init_done);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_INIT_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_load_res_done(u32 device_id,
+		struct hfi_msg_session_load_resources_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n",
+		pkt->session_id);
+
+	if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
+		pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_load_res_done: bad packet size: %d\n",
+				pkt->size);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_LOAD_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_flush_done(u32 device_id,
+		struct hfi_msg_session_flush_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_flush_done: bad packet size: %d\n",
+				pkt->size);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = sizeof(u32);
+
+	switch (pkt->flush_type) {
+	case HFI_FLUSH_OUTPUT:
+		cmd_done.data.flush_type = HAL_FLUSH_OUTPUT;
+		break;
+	case HFI_FLUSH_INPUT:
+		cmd_done.data.flush_type = HAL_FLUSH_INPUT;
+		break;
+	case HFI_FLUSH_ALL:
+		cmd_done.data.flush_type = HAL_FLUSH_ALL;
+		break;
+	default:
+		dprintk(VIDC_ERR,
+				"%s: invalid flush type!", __func__);
+		return -EINVAL;
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_FLUSH_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_etb_done(u32 device_id,
+		struct hfi_msg_session_empty_buffer_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+	struct hfi_picture_type *hfi_picture_type = NULL;
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id);
+
+	if (!pkt || pkt->size <
+		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_etb_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	data_done.device_id = device_id;
+	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	data_done.status = hfi_map_err_status(pkt->error_type);
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.clnt_data = pkt->input_tag;
+	data_done.input_done.offset = pkt->offset;
+	data_done.input_done.filled_len = pkt->filled_len;
+	data_done.input_done.packet_buffer =
+		(ion_phys_addr_t)pkt->packet_buffer;
+	data_done.input_done.extra_data_buffer =
+		(ion_phys_addr_t)pkt->extra_data_buffer;
+	data_done.input_done.status =
+		hfi_map_err_status(pkt->error_type);
+	hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0];
+	if (hfi_picture_type->is_sync_frame) {
+		if (hfi_picture_type->picture_type)
+			data_done.input_done.flags =
+				hfi_picture_type->picture_type;
+		else
+			dprintk(VIDC_DBG,
+				"Non-Sync frame sent for H264/HEVC\n");
+	}
+
+	trace_msm_v4l2_vidc_buffer_event_end("ETB",
+		(u32)pkt->packet_buffer, -1, -1,
+		pkt->filled_len, pkt->offset);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_ETB_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_ftb_done(
+		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+	bool is_decoder = false, is_encoder = false;
+
+	if (!msg_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	is_encoder = msg_hdr->size == sizeof(struct
+			hfi_msg_session_fill_buffer_done_compressed_packet) + 4;
+	is_decoder = msg_hdr->size == sizeof(struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet) + 4;
+
+	if (!(is_encoder ^ is_decoder)) {
+		dprintk(VIDC_ERR, "Ambiguous packet (%#x) received (size %d)\n",
+				msg_hdr->packet, msg_hdr->size);
+		return -EBADHANDLE;
+	}
+
+	if (is_encoder) {
+		struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt =
+		(struct hfi_msg_session_fill_buffer_done_compressed_packet *)
+		msg_hdr;
+		dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n",
+				pkt->session_id);
+		if (sizeof(struct
+			hfi_msg_session_fill_buffer_done_compressed_packet)
+			> pkt->size) {
+			dprintk(VIDC_ERR,
+				"hal_process_session_ftb_done: bad_pkt_size\n");
+			return -E2BIG;
+		} else if (pkt->error_type != HFI_ERR_NONE) {
+			dprintk(VIDC_ERR,
+				"got buffer back with error %x\n",
+				pkt->error_type);
+			/* Proceed with the FBD */
+		}
+
+		data_done.device_id = device_id;
+		data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		data_done.status = hfi_map_err_status(pkt->error_type);
+		data_done.size = sizeof(struct msm_vidc_cb_data_done);
+		data_done.clnt_data = 0;
+
+		data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+		data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+		data_done.output_done.flags1 = pkt->flags;
+		data_done.output_done.mark_target = pkt->mark_target;
+		data_done.output_done.mark_data = pkt->mark_data;
+		data_done.output_done.stats = pkt->stats;
+		data_done.output_done.offset1 = pkt->offset;
+		data_done.output_done.alloc_len1 = pkt->alloc_len;
+		data_done.output_done.filled_len1 = pkt->filled_len;
+		data_done.output_done.picture_type = pkt->picture_type;
+		data_done.output_done.packet_buffer1 =
+			(ion_phys_addr_t)pkt->packet_buffer;
+		data_done.output_done.extra_data_buffer =
+			(ion_phys_addr_t)pkt->extra_data_buffer;
+		data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+	} else /* if (is_decoder) */ {
+		struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
+		(struct	hfi_msg_session_fbd_uncompressed_plane0_packet *)
+		msg_hdr;
+
+		dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n",
+				pkt->session_id);
+		if (sizeof(
+			struct hfi_msg_session_fbd_uncompressed_plane0_packet) >
+			pkt->size) {
+			dprintk(VIDC_ERR,
+					"hal_process_session_ftb_done: bad_pkt_size\n");
+			return -E2BIG;
+		}
+
+		data_done.device_id = device_id;
+		data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		data_done.status = hfi_map_err_status(pkt->error_type);
+		data_done.size = sizeof(struct msm_vidc_cb_data_done);
+		data_done.clnt_data = 0;
+
+		data_done.output_done.stream_id = pkt->stream_id;
+		data_done.output_done.view_id = pkt->view_id;
+		data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+		data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+		data_done.output_done.flags1 = pkt->flags;
+		data_done.output_done.mark_target = pkt->mark_target;
+		data_done.output_done.mark_data = pkt->mark_data;
+		data_done.output_done.stats = pkt->stats;
+		data_done.output_done.alloc_len1 = pkt->alloc_len;
+		data_done.output_done.filled_len1 = pkt->filled_len;
+		data_done.output_done.offset1 = pkt->offset;
+		data_done.output_done.frame_width = pkt->frame_width;
+		data_done.output_done.frame_height = pkt->frame_height;
+		data_done.output_done.start_x_coord = pkt->start_x_coord;
+		data_done.output_done.start_y_coord = pkt->start_y_coord;
+		data_done.output_done.input_tag1 = pkt->input_tag;
+		data_done.output_done.picture_type = pkt->picture_type;
+		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
+		data_done.output_done.extra_data_buffer =
+			pkt->extra_data_buffer;
+
+		if (!pkt->stream_id)
+			data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+		else if (pkt->stream_id == 1)
+			data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2;
+	}
+
+	trace_msm_v4l2_vidc_buffer_event_end("FTB",
+		(u32)data_done.output_done.packet_buffer1,
+		(((u64)data_done.output_done.timestamp_hi) << 32)
+		+ ((u64)data_done.output_done.timestamp_lo),
+		data_done.output_done.alloc_len1,
+		data_done.output_done.filled_len1,
+		data_done.output_done.offset1);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_FTB_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_start_done(u32 device_id,
+		struct hfi_msg_session_start_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_start_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_START_DONE,
+		.response.cmd = cmd_done,
+	};
+	return 0;
+}
+
+static int hfi_process_session_stop_done(u32 device_id,
+		struct hfi_msg_session_stop_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_stop_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_STOP_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_rel_res_done(u32 device_id,
+		struct hfi_msg_session_release_resources_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n",
+		pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_release_resources_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_RELEASE_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_rel_buf_done(u32 device_id,
+		struct hfi_msg_session_release_buffers_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	if (!pkt || pkt->size <
+		sizeof(struct hfi_msg_session_release_buffers_done_packet)) {
+		dprintk(VIDC_ERR, "bad packet/packet size %d\n",
+			pkt ? pkt->size : 0);
+		return -E2BIG;
+	}
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%#x]\n",
+			pkt->session_id);
+
+	cmd_done.device_id = device_id;
+	cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	if (pkt->rg_buffer_info) {
+		cmd_done.data.buffer_info =
+			*(struct hal_buffer_info *)pkt->rg_buffer_info;
+		cmd_done.size = sizeof(struct hal_buffer_info);
+	} else {
+		dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_RELEASE_BUFFER_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_end_done(u32 device_id,
+		struct hfi_msg_sys_session_end_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_sys_session_end_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n", __func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_END_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_abort_done(u32 device_id,
+	struct hfi_msg_sys_session_abort_done_packet *pkt,
+	struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size: %d\n",
+				__func__, pkt ? pkt->size : 0);
+		return -E2BIG;
+	}
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_ABORT_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_get_seq_hdr_done(
+		u32 device_id,
+		struct hfi_msg_session_get_sequence_header_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+
+	if (!pkt || pkt->size !=
+			sizeof(struct
+			hfi_msg_session_get_sequence_header_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_GET_SEQ_HDR_DONE[%#x]\n",
+			pkt->session_id);
+
+	data_done.device_id = device_id;
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	data_done.status = hfi_map_err_status(pkt->error_type);
+	data_done.output_done.packet_buffer1 =
+		(ion_phys_addr_t)pkt->sequence_header;
+	data_done.output_done.filled_len1 = pkt->header_len;
+	dprintk(VIDC_INFO, "seq_hdr: %#x, Length: %d\n",
+			pkt->sequence_header, pkt->header_len);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_GET_SEQ_HDR_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static void hfi_process_sys_get_prop_image_version(
+		struct hfi_msg_sys_property_info_packet *pkt)
+{
+	int i = 0;
+	u32 smem_block_size = 0;
+	u8 *smem_table_ptr;
+	char version[256];
+	const u32 version_string_size = 128;
+	const u32 smem_image_index_venus = 14 * 128;
+	u8 *str_image_version;
+	int req_bytes;
+
+	req_bytes = pkt->size - sizeof(*pkt);
+	if (req_bytes < version_string_size ||
+			!pkt->rg_property_data[1] ||
+			pkt->num_properties > 1) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_get_prop_image_version: bad_pkt: %d\n",
+				req_bytes);
+		return;
+	}
+	str_image_version = (u8 *)&pkt->rg_property_data[1];
+	/*
+	 * The version string returned by firmware includes null
+	 * characters at the start and in between. Replace the null
+	 * characters with space, to print the version info.
+	 */
+	for (i = 0; i < version_string_size; i++) {
+		if (str_image_version[i] != '\0')
+			version[i] = str_image_version[i];
+		else
+			version[i] = ' ';
+	}
+	version[i] = '\0';
+	dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size, 0, SMEM_ANY_HOST_FLAG);
+	if ((smem_image_index_venus + version_string_size) <= smem_block_size &&
+			smem_table_ptr)
+		memcpy(smem_table_ptr + smem_image_index_venus,
+				str_image_version, version_string_size);
+}
+
+static int hfi_process_sys_property_info(u32 device_id,
+		struct hfi_msg_sys_property_info_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+		return -EINVAL;
+	} else if (pkt->size < sizeof(*pkt)) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: bad_pkt_size\n");
+		return -E2BIG;
+	} else if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: no_properties\n");
+		return -EINVAL;
+	}
+
+	switch (pkt->rg_property_data[0]) {
+	case HFI_PROPERTY_SYS_IMAGE_VERSION:
+		hfi_process_sys_get_prop_image_version(pkt);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_DBG,
+				"hfi_process_sys_property_info: unknown_prop_id: %x\n",
+				pkt->rg_property_data[0]);
+		return -ENOTSUPP;
+	}
+
+}
+
+static int hfi_process_ignore(u32 device_id,
+		struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_RESPONSE_UNUSED,
+	};
+
+	return 0;
+}
+
+int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	typedef int (*pkt_func_def)(u32, void *, struct msm_vidc_cb_info *info);
+	pkt_func_def pkt_func = NULL;
+
+	if (!info || !msg_hdr || msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_DBG, "Parse response %#x\n", msg_hdr->packet);
+	switch (msg_hdr->packet) {
+	case HFI_MSG_EVENT_NOTIFY:
+		pkt_func = (pkt_func_def)hfi_process_event_notify;
+		break;
+	case  HFI_MSG_SYS_INIT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_sys_init_done;
+		break;
+	case HFI_MSG_SYS_SESSION_INIT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_init_done;
+		break;
+	case HFI_MSG_SYS_PROPERTY_INFO:
+		pkt_func = (pkt_func_def)hfi_process_sys_property_info;
+		break;
+	case HFI_MSG_SYS_SESSION_END_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_end_done;
+		break;
+	case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_load_res_done;
+		break;
+	case HFI_MSG_SESSION_START_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_start_done;
+		break;
+	case HFI_MSG_SESSION_STOP_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_stop_done;
+		break;
+	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_etb_done;
+		break;
+	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_ftb_done;
+		break;
+	case HFI_MSG_SESSION_FLUSH_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_flush_done;
+		break;
+	case HFI_MSG_SESSION_PROPERTY_INFO:
+		pkt_func = (pkt_func_def)hfi_process_session_prop_info;
+		break;
+	case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_rel_res_done;
+		break;
+	case HFI_MSG_SYS_RELEASE_RESOURCE:
+		pkt_func = (pkt_func_def)hfi_process_sys_rel_resource_done;
+		break;
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+		pkt_func = (pkt_func_def) hfi_process_session_get_seq_hdr_done;
+		break;
+	case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_rel_buf_done;
+		break;
+	case HFI_MSG_SYS_SESSION_ABORT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_abort_done;
+		break;
+	case HFI_MSG_SESSION_SYNC_DONE:
+		pkt_func = (pkt_func_def)hfi_process_ignore;
+		break;
+	default:
+		dprintk(VIDC_DBG, "Unable to parse message: %#x\n",
+				msg_hdr->packet);
+		break;
+	}
+
+	return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_smem.c b/drivers/media/platform/msm/vidc_3x/msm_smem.c
new file mode 100644
index 0000000..a6d5476
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_smem.c
@@ -0,0 +1,701 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/dma-iommu.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-direction.h>
+#include <linux/iommu.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/msm_ion.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "media/msm_vidc.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+
+struct smem_client {
+	int mem_type;
+	void *clnt;
+	struct msm_vidc_platform_resources *res;
+	enum session_type session_type;
+};
+
+static int get_device_address(struct smem_client *smem_client,
+		struct ion_handle *hndl, unsigned long align,
+		ion_phys_addr_t *iova, unsigned long *buffer_size,
+		unsigned long flags, enum hal_buffer buffer_type,
+		struct dma_mapping_info *mapping_info)
+{
+	int rc = 0;
+	struct ion_client *clnt = NULL;
+	struct dma_buf *buf = NULL;
+	struct dma_buf_attachment *attach;
+	struct sg_table *table = NULL;
+	struct context_bank_info *cb = NULL;
+
+	if (!iova || !buffer_size || !hndl || !smem_client || !mapping_info) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK, %pK, %pK\n",
+				smem_client, hndl, iova, buffer_size);
+		return -EINVAL;
+	}
+
+	clnt = smem_client->clnt;
+	if (!clnt) {
+		dprintk(VIDC_ERR, "Invalid client\n");
+		return -EINVAL;
+	}
+
+	if (is_iommu_present(smem_client->res)) {
+		cb = msm_smem_get_context_bank(smem_client, flags & SMEM_SECURE,
+				buffer_type);
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to get context bank device\n",
+				 __func__);
+			rc = -EIO;
+			goto mem_map_failed;
+		}
+
+		/* Convert an Ion handle to a dma buf */
+		buf = ion_share_dma_buf(clnt, hndl);
+		if (IS_ERR_OR_NULL(buf)) {
+			rc = PTR_ERR(buf) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Share ION buf to DMA failed\n");
+			goto mem_map_failed;
+		}
+
+		/* Prepare a dma buf for dma on the given device */
+		attach = dma_buf_attach(buf, cb->dev);
+		if (IS_ERR_OR_NULL(attach)) {
+			rc = PTR_ERR(attach) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Failed to attach dmabuf\n");
+			goto mem_buf_attach_failed;
+		}
+
+		/* Get the scatterlist for the given attachment */
+		table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+		if (IS_ERR_OR_NULL(table)) {
+			rc = PTR_ERR(table) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Failed to map table\n");
+			goto mem_map_table_failed;
+		}
+
+		/* debug trace's need to be updated later */
+		trace_msm_smem_buffer_iommu_op_start("MAP", 0, 0,
+			align, *iova, *buffer_size);
+
+		/* Map a scatterlist into an SMMU */
+		rc = msm_dma_map_sg_lazy(cb->dev, table->sgl, table->nents,
+				DMA_BIDIRECTIONAL, buf);
+		if (rc != table->nents) {
+			dprintk(VIDC_ERR,
+				"Mapping failed with rc(%d), expected rc(%d)\n",
+				rc, table->nents);
+			rc = -ENOMEM;
+			goto mem_map_sg_failed;
+		}
+		if (table->sgl) {
+			dprintk(VIDC_DBG,
+				"%s: CB : %s, DMA buf: %pK, device: %pK, attach: %pK, table: %pK, table sgl: %pK, rc: %d, dma_address: %pa\n",
+				__func__, cb->name, buf, cb->dev, attach,
+				table, table->sgl, rc,
+				&table->sgl->dma_address);
+
+			*iova = table->sgl->dma_address;
+			*buffer_size = table->sgl->dma_length;
+		} else {
+			dprintk(VIDC_ERR, "sgl is NULL\n");
+			rc = -ENOMEM;
+			goto mem_map_sg_failed;
+		}
+
+		mapping_info->dev = cb->dev;
+		mapping_info->mapping = cb->mapping;
+		mapping_info->table = table;
+		mapping_info->attach = attach;
+		mapping_info->buf = buf;
+
+		trace_msm_smem_buffer_iommu_op_end("MAP", 0, 0,
+			align, *iova, *buffer_size);
+	} else {
+		dprintk(VIDC_DBG, "Using physical memory address\n");
+		rc = ion_phys(clnt, hndl, iova, (size_t *)buffer_size);
+		if (rc) {
+			dprintk(VIDC_ERR, "ion memory map failed - %d\n", rc);
+			goto mem_map_failed;
+		}
+	}
+
+	dprintk(VIDC_DBG, "mapped ion handle %pK to %pa\n", hndl, iova);
+	return 0;
+mem_map_sg_failed:
+	dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
+mem_map_table_failed:
+	dma_buf_detach(buf, attach);
+mem_buf_attach_failed:
+	dma_buf_put(buf);
+mem_map_failed:
+	return rc;
+}
+
+static void put_device_address(struct smem_client *smem_client,
+	struct ion_handle *hndl, u32 flags,
+	struct dma_mapping_info *mapping_info,
+	enum hal_buffer buffer_type)
+{
+	struct ion_client *clnt = NULL;
+
+	if (!hndl || !smem_client || !mapping_info) {
+		dprintk(VIDC_WARN, "Invalid params: %pK, %pK\n",
+				smem_client, hndl);
+		return;
+	}
+
+	if (!mapping_info->dev || !mapping_info->table ||
+		!mapping_info->buf || !mapping_info->attach) {
+		dprintk(VIDC_WARN, "Invalid params:\n");
+		return;
+	}
+
+	clnt = smem_client->clnt;
+	if (!clnt) {
+		dprintk(VIDC_WARN, "Invalid client\n");
+		return;
+	}
+	if (is_iommu_present(smem_client->res)) {
+		dprintk(VIDC_DBG,
+			"Calling dma_unmap_sg - device: %pK, address: %pa, buf: %pK, table: %pK, attach: %pK\n",
+			mapping_info->dev,
+			&mapping_info->table->sgl->dma_address,
+			mapping_info->buf, mapping_info->table,
+			mapping_info->attach);
+
+		trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, 0, 0, 0);
+		msm_dma_unmap_sg(mapping_info->dev, mapping_info->table->sgl,
+			mapping_info->table->nents, DMA_BIDIRECTIONAL,
+			mapping_info->buf);
+		dma_buf_unmap_attachment(mapping_info->attach,
+			mapping_info->table, DMA_BIDIRECTIONAL);
+		dma_buf_detach(mapping_info->buf, mapping_info->attach);
+		dma_buf_put(mapping_info->buf);
+		trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0);
+	}
+}
+
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+		struct msm_smem *mem, enum hal_buffer buffer_type)
+{
+	struct ion_handle *hndl;
+	ion_phys_addr_t iova = 0;
+	unsigned long buffer_size = 0;
+	int rc = 0;
+	unsigned long align = SZ_4K;
+	unsigned long ion_flags = 0;
+
+	hndl = ion_import_dma_buf_fd(client->clnt, fd);
+	dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
+	if (IS_ERR_OR_NULL(hndl)) {
+		dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
+				client, fd, offset, hndl);
+		rc = -ENOMEM;
+		goto fail_import_fd;
+	}
+	mem->kvaddr = NULL;
+	rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+		goto fail_device_address;
+	}
+
+	mem->buffer_type = buffer_type;
+	if (ion_flags & ION_FLAG_CACHED)
+		mem->flags |= SMEM_CACHED;
+
+	if (ion_flags & ION_FLAG_SECURE)
+		mem->flags |= SMEM_SECURE;
+
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+				mem->flags, buffer_type, &mem->mapping_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
+		goto fail_device_address;
+	}
+
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	mem->device_addr = iova;
+	mem->size = buffer_size;
+	if ((u32)mem->device_addr != iova) {
+		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+			&iova, (u32)mem->device_addr);
+		goto fail_device_address;
+	}
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, fd = %d, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %d, flags = %#lx\n",
+		__func__, mem->smem_priv, fd, &mem->device_addr, mem->size,
+		mem->kvaddr, mem->buffer_type, mem->flags);
+	return rc;
+fail_device_address:
+	ion_free(client->clnt, hndl);
+fail_import_fd:
+	return rc;
+}
+
+static int get_secure_flag_for_buffer_type(
+		struct smem_client *client, enum hal_buffer buffer_type)
+{
+
+	if (!client) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (buffer_type) {
+	case HAL_BUFFER_INPUT:
+		if (client->session_type == MSM_VIDC_ENCODER)
+			return ION_FLAG_CP_PIXEL;
+		else
+			return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_OUTPUT:
+	case HAL_BUFFER_OUTPUT2:
+		if (client->session_type == MSM_VIDC_ENCODER)
+			return ION_FLAG_CP_BITSTREAM;
+		else
+			return ION_FLAG_CP_PIXEL;
+	case HAL_BUFFER_INTERNAL_SCRATCH:
+		return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		return ION_FLAG_CP_NON_PIXEL;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		return ION_FLAG_CP_PIXEL;
+	case HAL_BUFFER_INTERNAL_PERSIST:
+		return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		return ION_FLAG_CP_NON_PIXEL;
+	default:
+		WARN(1, "No matching secure flag for buffer type : %x\n",
+				buffer_type);
+		return -EINVAL;
+	}
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size, u32 align,
+	u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+	int map_kernel)
+{
+	struct ion_handle *hndl;
+	ion_phys_addr_t iova = 0;
+	unsigned long buffer_size = 0;
+	unsigned long heap_mask = 0;
+	int rc = 0;
+	int ion_flags = 0;
+
+	align = ALIGN(align, SZ_4K);
+	size = ALIGN(size, SZ_4K);
+
+	if (is_iommu_present(client->res)) {
+		heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID);
+	} else {
+		dprintk(VIDC_DBG,
+			"allocate shared memory from adsp heap size %zx align %d\n",
+			size, align);
+		heap_mask = ION_HEAP(ION_ADSP_HEAP_ID);
+	}
+
+	if (flags & SMEM_CACHED)
+		ion_flags |= ION_FLAG_CACHED;
+
+	if (flags & SMEM_SECURE) {
+		int secure_flag =
+			get_secure_flag_for_buffer_type(client, buffer_type);
+		if (secure_flag < 0) {
+			rc = secure_flag;
+			goto fail_shared_mem_alloc;
+		}
+
+		ion_flags |= ION_FLAG_SECURE | secure_flag;
+		heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
+
+		if (client->res->slave_side_cp) {
+			heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+			size = ALIGN(size, SZ_1M);
+			align = ALIGN(size, SZ_1M);
+		}
+	}
+
+	trace_msm_smem_buffer_ion_op_start("ALLOC", (u32)buffer_type,
+		heap_mask, size, align, flags, map_kernel);
+	hndl = ion_alloc(client->clnt, size, align, heap_mask, ion_flags);
+	if (IS_ERR_OR_NULL(hndl)) {
+		dprintk(VIDC_ERR,
+		"Failed to allocate shared memory = %pK, %zx, %d, %#x\n",
+		client, size, align, flags);
+		rc = -ENOMEM;
+		goto fail_shared_mem_alloc;
+	}
+	trace_msm_smem_buffer_ion_op_end("ALLOC", (u32)buffer_type,
+		heap_mask, size, align, flags, map_kernel);
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	mem->flags = flags;
+	mem->buffer_type = buffer_type;
+	if (map_kernel) {
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+		if (IS_ERR_OR_NULL(mem->kvaddr)) {
+			dprintk(VIDC_ERR,
+				"Failed to map shared mem in kernel\n");
+			rc = -EIO;
+			goto fail_map;
+		}
+	} else {
+		mem->kvaddr = NULL;
+	}
+
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+				flags, buffer_type, &mem->mapping_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
+			rc);
+		goto fail_device_address;
+	}
+	mem->device_addr = iova;
+	if ((u32)mem->device_addr != iova) {
+		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+			&iova, (u32)mem->device_addr);
+		goto fail_device_address;
+	}
+	mem->size = size;
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n",
+		__func__, mem->smem_priv, &mem->device_addr,
+		mem->size, mem->kvaddr, mem->buffer_type, mem->flags);
+	return rc;
+fail_device_address:
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, hndl);
+fail_map:
+	ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+	return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %#x\n",
+		__func__, mem->smem_priv, &mem->device_addr,
+		mem->size, mem->kvaddr, mem->buffer_type);
+
+	if (mem->device_addr)
+		put_device_address(client, mem->smem_priv, mem->flags,
+			&mem->mapping_info, mem->buffer_type);
+
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, mem->smem_priv);
+	if (mem->smem_priv) {
+		trace_msm_smem_buffer_ion_op_start("FREE",
+				(u32)mem->buffer_type, -1, mem->size, -1,
+				mem->flags, -1);
+		dprintk(VIDC_DBG,
+			"%s: Freeing handle %pK, client: %pK\n",
+			__func__, mem->smem_priv, client->clnt);
+		ion_free(client->clnt, mem->smem_priv);
+		trace_msm_smem_buffer_ion_op_end("FREE", (u32)mem->buffer_type,
+			-1, mem->size, -1, mem->flags, -1);
+	}
+}
+
+static void *ion_new_client(void)
+{
+	struct ion_client *client = NULL;
+
+	client = msm_ion_client_create("video_client");
+	if (!client)
+		dprintk(VIDC_ERR, "Failed to create smem client\n");
+	return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+	ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+		enum hal_buffer buffer_type)
+{
+	struct smem_client *client = clt;
+	int rc = 0;
+	struct msm_smem *mem;
+
+	if (fd < 0) {
+		dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv)
+{
+	struct smem_client *client = clt;
+	struct ion_handle *handle = NULL;
+	bool ret = false;
+
+	if (!clt || !priv) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
+			clt, priv);
+		return false;
+	}
+	handle = ion_import_dma_buf_fd(client->clnt, fd);
+	ret = handle == priv;
+	handle ? ion_free(client->clnt, handle) : 0;
+	return ret;
+}
+
+static int ion_cache_operations(struct smem_client *client,
+	struct msm_smem *mem, enum smem_cache_ops cache_op)
+{
+	unsigned long ionflag = 0;
+	int rc = 0;
+	int msm_cache_ops = 0;
+
+	if (!mem || !client) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
+			mem, client);
+		return -EINVAL;
+	}
+	rc = ion_handle_get_flags(client->clnt,	mem->smem_priv,
+		&ionflag);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"ion_handle_get_flags failed: %d\n", rc);
+		goto cache_op_failed;
+	}
+	if (ION_IS_CACHED(ionflag)) {
+		switch (cache_op) {
+		case SMEM_CACHE_CLEAN:
+			msm_cache_ops = ION_IOC_CLEAN_CACHES;
+			break;
+		case SMEM_CACHE_INVALIDATE:
+			msm_cache_ops = ION_IOC_INV_CACHES;
+			break;
+		case SMEM_CACHE_CLEAN_INVALIDATE:
+			msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+			break;
+		default:
+			dprintk(VIDC_ERR, "cache operation not supported\n");
+			rc = -EINVAL;
+			goto cache_op_failed;
+		}
+		rc = msm_ion_do_cache_op(client->clnt,
+				(struct ion_handle *)mem->smem_priv,
+				0, (unsigned long)mem->size,
+				msm_cache_ops);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"cache operation failed %d\n", rc);
+			goto cache_op_failed;
+		}
+	}
+cache_op_failed:
+	return rc;
+}
+
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops cache_op)
+{
+	struct smem_client *client = clt;
+	int rc = 0;
+
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n",
+			client);
+		return -EINVAL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_cache_operations(client, mem, cache_op);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"Failed cache operations: %d\n", rc);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	return rc;
+}
+
+void *msm_smem_new_client(enum smem_type mtype,
+		void *platform_resources, enum session_type stype)
+{
+	struct smem_client *client = NULL;
+	void *clnt = NULL;
+	struct msm_vidc_platform_resources *res = platform_resources;
+
+	switch (mtype) {
+	case SMEM_ION:
+		clnt = ion_new_client();
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	if (clnt) {
+		client = kzalloc(sizeof(*client), GFP_KERNEL);
+		if (client) {
+			client->mem_type = mtype;
+			client->clnt = clnt;
+			client->res = res;
+			client->session_type = stype;
+		}
+	} else {
+		dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
+			mtype);
+	}
+	return client;
+}
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+		enum hal_buffer buffer_type, int map_kernel)
+{
+	struct smem_client *client;
+	int rc = 0;
+	struct msm_smem *mem;
+
+	client = clt;
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
+		return NULL;
+	}
+	if (!size) {
+		dprintk(VIDC_ERR, "No need to allocate memory of size: %zx\n",
+			size);
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = alloc_ion_mem(client, size, align, flags, buffer_type,
+					mem, map_kernel);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+	struct smem_client *client = clt;
+
+	if (!client || !mem) {
+		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		free_ion_mem(client, mem);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+	struct smem_client *client = clt;
+
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		ion_delete_client(client);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	kfree(client);
+}
+
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+			bool is_secure, enum hal_buffer buffer_type)
+{
+	struct smem_client *client = clt;
+	struct context_bank_info *cb = NULL, *match = NULL;
+
+	if (!clt) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return NULL;
+	}
+
+	/*
+	 * HAL_BUFFER_INPUT is directly mapped to bitstream CB in DT
+	 * as the buffer type structure was initially designed
+	 * just for decoder. For Encoder, input should be mapped to
+	 * pixel_CB. So swap the buffer types just in this local scope.
+	 */
+	if (is_secure && client->session_type == MSM_VIDC_ENCODER) {
+		if (buffer_type == HAL_BUFFER_INPUT)
+			buffer_type = HAL_BUFFER_OUTPUT;
+		else if (buffer_type == HAL_BUFFER_OUTPUT)
+			buffer_type = HAL_BUFFER_INPUT;
+	}
+
+	list_for_each_entry(cb, &client->res->context_banks, list) {
+		if (cb->is_secure == is_secure &&
+				cb->buffer_type & buffer_type) {
+			match = cb;
+			dprintk(VIDC_DBG,
+				"context bank found for CB : %s, device: %pK mapping: %pK\n",
+				match->name, match->dev, match->mapping);
+			break;
+		}
+	}
+
+	return match;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c
new file mode 100644
index 0000000..9d5f255
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c
@@ -0,0 +1,829 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/io.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_common.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_res_parse.h"
+#include "msm_vidc_resources.h"
+#include "venus_boot.h"
+#include "vidc_hfi_api.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+uint32_t msm_vidc_pwr_collapse_delay = 2000;
+
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+	return container_of(filp->private_data,
+					struct msm_vidc_inst, event_handler);
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct msm_video_device *vid_dev =
+		container_of(vdev, struct msm_video_device, vdev);
+	struct msm_vidc_core *core = video_drvdata(filp);
+	struct msm_vidc_inst *vidc_inst;
+
+	trace_msm_v4l2_vidc_open_start("msm_v4l2_open start");
+	vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+	if (!vidc_inst) {
+		dprintk(VIDC_ERR,
+		"Failed to create video instance, core: %d, type = %d\n",
+		core->id, vid_dev->type);
+		return -ENOMEM;
+	}
+	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+	filp->private_data = &(vidc_inst->event_handler);
+	trace_msm_v4l2_vidc_open_end("msm_v4l2_open end");
+	return 0;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst;
+
+	trace_msm_v4l2_vidc_close_start("msm_v4l2_close start");
+	vidc_inst = get_vidc_inst(filp, NULL);
+	rc = msm_vidc_release_buffers(vidc_inst,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
+
+	rc = msm_vidc_close(vidc_inst);
+	trace_msm_v4l2_vidc_close_end("msm_v4l2_close end");
+	return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+			struct v4l2_capability *cap)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+
+	return msm_vidc_querycap((void *)vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+					struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_enum_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_s_ext_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_controls *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_ext_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+				struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	int rc = 0;
+
+	if (!b->count)
+		rc = msm_vidc_release_buffers(vidc_inst, b->type);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
+	return msm_vidc_reqbufs((void *)vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_streamon((void *)vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+
+	return msm_vidc_subscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+
+	return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+				struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec);
+}
+
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc);
+}
+static int msm_v4l2_s_parm(struct file *file, void *fh,
+			struct v4l2_streamparm *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_s_parm(vidc_inst, a);
+}
+static int msm_v4l2_g_parm(struct file *file, void *fh,
+		struct v4l2_streamparm *a)
+{
+	return 0;
+}
+
+static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+				struct v4l2_frmsizeenum *fsize)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
+}
+
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+	.vidioc_querycap = msm_v4l2_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+	.vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+	.vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+	.vidioc_reqbufs = msm_v4l2_reqbufs,
+	.vidioc_prepare_buf = msm_v4l2_prepare_buf,
+	.vidioc_qbuf = msm_v4l2_qbuf,
+	.vidioc_dqbuf = msm_v4l2_dqbuf,
+	.vidioc_streamon = msm_v4l2_streamon,
+	.vidioc_streamoff = msm_v4l2_streamoff,
+	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
+	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_s_ext_ctrls = msm_v4l2_s_ext_ctrl,
+	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+	.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
+	.vidioc_s_parm = msm_v4l2_s_parm,
+	.vidioc_g_parm = msm_v4l2_g_parm,
+	.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+	struct poll_table_struct *pt)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+
+	return msm_vidc_poll((void *)vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_v4l2_open,
+	.release = msm_v4l2_close,
+	.unlocked_ioctl = video_ioctl2,
+	.poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int read_platform_resources(struct msm_vidc_core *core,
+		struct platform_device *pdev)
+{
+	if (!core || !pdev) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK %pK\n",
+			__func__, core, pdev);
+		return -EINVAL;
+	}
+
+	core->hfi_type = VIDC_HFI_VENUS;
+	core->resources.pdev = pdev;
+	if (pdev->dev.of_node) {
+		/* Target supports DT, parse from it */
+		return read_platform_resources_from_dt(&core->resources);
+	}
+	dprintk(VIDC_ERR, "pdev node is NULL\n");
+	return -EINVAL;
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+				struct msm_vidc_core *core)
+{
+	int i = 0;
+	int rc = 0;
+
+	if (!core)
+		return -EINVAL;
+	rc = read_platform_resources(core, pdev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get platform resources\n");
+		return rc;
+	}
+
+	INIT_LIST_HEAD(&core->instances);
+	mutex_init(&core->lock);
+
+	core->state = VIDC_CORE_UNINIT;
+	for (i = SYS_MSG_INDEX(SYS_MSG_START);
+		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+		init_completion(&core->completions[i]);
+	}
+
+	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
+	return rc;
+}
+
+static ssize_t msm_vidc_link_name_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct msm_vidc_core *core = dev_get_drvdata(dev);
+
+	if (core)
+		if (dev == &core->vdev[MSM_VIDC_DECODER].vdev.dev)
+			return snprintf(buf, PAGE_SIZE, "venus_dec");
+		else if (dev == &core->vdev[MSM_VIDC_ENCODER].vdev.dev)
+			return snprintf(buf, PAGE_SIZE, "venus_enc");
+		else
+			return 0;
+	else
+		return 0;
+}
+
+static DEVICE_ATTR(link_name, 0444, msm_vidc_link_name_show, NULL);
+
+static ssize_t store_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long val = 0;
+	int rc = 0;
+
+	rc = kstrtoul(buf, 0, &val);
+	if (rc)
+		return rc;
+	else if (!val)
+		return -EINVAL;
+	msm_vidc_pwr_collapse_delay = val;
+	return count;
+}
+
+static ssize_t show_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", msm_vidc_pwr_collapse_delay);
+}
+
+static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay,
+		store_pwr_collapse_delay);
+
+static ssize_t show_thermal_level(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level);
+}
+
+static ssize_t store_thermal_level(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int rc = 0, val = 0;
+
+	rc = kstrtoint(buf, 0, &val);
+	if (rc || val < 0) {
+		dprintk(VIDC_WARN,
+			"Invalid thermal level value: %s\n", buf);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Thermal level old %d new %d\n",
+			vidc_driver->thermal_level, val);
+
+	if (val == vidc_driver->thermal_level)
+		return count;
+	vidc_driver->thermal_level = val;
+
+	msm_comm_handle_thermal_event();
+	return count;
+}
+
+static DEVICE_ATTR(thermal_level, 0644, show_thermal_level,
+		store_thermal_level);
+
+static ssize_t show_platform_version(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			vidc_driver->platform_version);
+}
+
+static ssize_t store_platform_version(struct device *dev,
+		struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	dprintk(VIDC_WARN, "store platform version is not allowed\n");
+	return count;
+}
+
+static DEVICE_ATTR(platform_version, 0444, show_platform_version,
+		store_platform_version);
+
+static ssize_t show_capability_version(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			vidc_driver->capability_version);
+}
+
+static ssize_t store_capability_version(struct device *dev,
+		struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	dprintk(VIDC_WARN, "store capability version is not allowed\n");
+	return count;
+}
+
+static DEVICE_ATTR(capability_version, 0444, show_capability_version,
+		store_capability_version);
+
+static struct attribute *msm_vidc_core_attrs[] = {
+		&dev_attr_pwr_collapse_delay.attr,
+		&dev_attr_thermal_level.attr,
+		&dev_attr_platform_version.attr,
+		&dev_attr_capability_version.attr,
+		NULL
+};
+
+static struct attribute_group msm_vidc_core_attr_group = {
+		.attrs = msm_vidc_core_attrs,
+};
+
+static const struct of_device_id msm_vidc_dt_match[] = {
+	{.compatible = "qcom,msm-vidc"},
+	{.compatible = "qcom,msm-vidc,context-bank"},
+	{.compatible = "qcom,msm-vidc,bus"},
+	{}
+};
+
+static u32 msm_vidc_read_efuse_version(struct platform_device *pdev,
+	struct version_table *table, const char *fuse_name)
+{
+	void __iomem *base;
+	struct resource *res;
+	u32 ret = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, fuse_name);
+	if (!res) {
+		dprintk(VIDC_DBG, "Failed to get resource %s\n", fuse_name);
+		goto exit;
+	}
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dprintk(VIDC_ERR,
+			"failed ioremap: res->start %#x, size %d\n",
+			(u32)res->start, (u32)resource_size(res));
+		goto exit;
+	} else {
+		ret = readl_relaxed(base);
+		ret = (ret & table->version_mask) >>
+			table->version_shift;
+
+		devm_iounmap(&pdev->dev, base);
+	}
+exit:
+	return ret;
+}
+
+static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct device *dev;
+	int nr = BASE_DEVICE_NUMBER;
+
+	if (!vidc_driver) {
+		dprintk(VIDC_ERR, "Invalid vidc driver\n");
+		return -EINVAL;
+	}
+
+	core = kzalloc(sizeof(*core), GFP_KERNEL);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"Failed to allocate memory for device core\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(&pdev->dev, core);
+	rc = msm_vidc_initialize_core(pdev, core);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init core\n");
+		goto err_core_init;
+	}
+	rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create attributes\n");
+		goto err_core_init;
+	}
+
+	core->id = MSM_VIDC_CORE_VENUS;
+
+	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
+		goto err_v4l2_register;
+	}
+
+	/* setup the decoder device */
+	core->vdev[MSM_VIDC_DECODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_DECODER].vdev.vfl_dir = VFL_DIR_M2M;
+	core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+	core->vdev[MSM_VIDC_DECODER].vdev.v4l2_dev = &core->v4l2_dev;
+	rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+					VFL_TYPE_GRABBER, nr);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register video decoder device");
+		goto err_dec_register;
+	}
+
+	video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+	dev = &core->vdev[MSM_VIDC_DECODER].vdev.dev;
+	rc = device_create_file(dev, &dev_attr_link_name);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create link name sysfs for decoder");
+		goto err_dec_attr_link_name;
+	}
+
+	/* setup the encoder device */
+	core->vdev[MSM_VIDC_ENCODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_ENCODER].vdev.vfl_dir = VFL_DIR_M2M;
+	core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+	core->vdev[MSM_VIDC_ENCODER].vdev.v4l2_dev = &core->v4l2_dev;
+	rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+				VFL_TYPE_GRABBER, nr + 1);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register video encoder device");
+		goto err_enc_register;
+	}
+
+	video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+	dev = &core->vdev[MSM_VIDC_ENCODER].vdev.dev;
+	rc = device_create_file(dev, &dev_attr_link_name);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create link name sysfs for encoder");
+		goto err_enc_attr_link_name;
+	}
+
+	/* finish setting up the 'core' */
+	mutex_lock(&vidc_driver->lock);
+	if (vidc_driver->num_cores  + 1 > MSM_VIDC_CORES_MAX) {
+		mutex_unlock(&vidc_driver->lock);
+		dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
+				vidc_driver->num_cores);
+		goto err_cores_exceeded;
+	}
+	vidc_driver->num_cores++;
+	mutex_unlock(&vidc_driver->lock);
+
+	core->device = vidc_hfi_initialize(core->hfi_type, core->id,
+				&core->resources, &handle_cmd_response);
+	if (IS_ERR_OR_NULL(core->device)) {
+		mutex_lock(&vidc_driver->lock);
+		vidc_driver->num_cores--;
+		mutex_unlock(&vidc_driver->lock);
+
+		rc = PTR_ERR(core->device) ?: -EBADHANDLE;
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "Failed to create HFI device\n");
+		else
+			dprintk(VIDC_DBG, "msm_vidc: request probe defer\n");
+		goto err_cores_exceeded;
+	}
+
+	mutex_lock(&vidc_driver->lock);
+	list_add_tail(&core->list, &vidc_driver->cores);
+	mutex_unlock(&vidc_driver->lock);
+
+	core->debugfs_root = msm_vidc_debugfs_init_core(
+		core, vidc_driver->debugfs_root);
+
+	vidc_driver->platform_version =
+		msm_vidc_read_efuse_version(pdev,
+			core->resources.pf_ver_tbl, "efuse");
+
+	vidc_driver->capability_version =
+		msm_vidc_read_efuse_version(
+			pdev, core->resources.pf_cap_tbl, "efuse2");
+
+	dprintk(VIDC_DBG, "populating sub devices\n");
+	/*
+	 * Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank.
+	 * When msm_vidc_probe is called for each sub-device, parse the
+	 * context-bank details and store it in core->resources.context_banks
+	 * list.
+	 */
+	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
+			&pdev->dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to trigger probe for sub-devices\n");
+		goto err_fail_sub_device_probe;
+	}
+
+	return rc;
+
+err_fail_sub_device_probe:
+	vidc_hfi_deinitialize(core->hfi_type, core->device);
+err_cores_exceeded:
+	device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+			&dev_attr_link_name);
+err_enc_attr_link_name:
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+	device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+			&dev_attr_link_name);
+err_dec_attr_link_name:
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+	v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+	sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+err_core_init:
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(core);
+	return rc;
+}
+
+static int msm_vidc_probe_context_bank(struct platform_device *pdev)
+{
+	return read_context_bank_resources_from_dt(pdev);
+}
+
+static int msm_vidc_probe_bus(struct platform_device *pdev)
+{
+	return read_bus_resources_from_dt(pdev);
+}
+
+static int msm_vidc_probe(struct platform_device *pdev)
+{
+	/*
+	 * Sub devices probe will be triggered by of_platform_populate() towards
+	 * the end of the probe function after msm-vidc device probe is
+	 * completed. Return immediately after completing sub-device probe.
+	 */
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) {
+		return msm_vidc_probe_vidc_device(pdev);
+	} else if (of_device_is_compatible(pdev->dev.of_node,
+		"qcom,msm-vidc,bus")) {
+		return msm_vidc_probe_bus(pdev);
+	} else if (of_device_is_compatible(pdev->dev.of_node,
+		"qcom,msm-vidc,context-bank")) {
+		return msm_vidc_probe_context_bank(pdev);
+	}
+	/* How did we end up here? */
+	WARN_ON(VIDC_DBG_WARN_ENABLE);
+	return -EINVAL;
+}
+
+static int msm_vidc_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "%s invalid input %pK", __func__, pdev);
+		return -EINVAL;
+	}
+
+	core = dev_get_drvdata(&pdev->dev);
+	if (!core) {
+		dprintk(VIDC_ERR, "%s invalid core", __func__);
+		return -EINVAL;
+	}
+
+	if (core->resources.use_non_secure_pil)
+		venus_boot_deinit();
+
+	vidc_hfi_deinitialize(core->hfi_type, core->device);
+	device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+				&dev_attr_link_name);
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+	device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+				&dev_attr_link_name);
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+	v4l2_device_unregister(&core->v4l2_dev);
+
+	msm_vidc_free_platform_resources(&core->resources);
+	sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(core);
+	return rc;
+}
+
+static int msm_vidc_pm_suspend(struct device *dev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	/*
+	 * Bail out if
+	 * - driver possibly not probed yet
+	 * - not the main device. We don't support power management on
+	 *   subdevices (e.g. context banks)
+	 */
+	if (!dev || !dev->driver ||
+		!of_device_is_compatible(dev->of_node, "qcom,msm-vidc"))
+		return 0;
+
+	core = dev_get_drvdata(dev);
+	if (!core) {
+		dprintk(VIDC_ERR, "%s invalid core\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_suspend(core->id);
+	if (rc == -ENOTSUPP)
+		rc = 0;
+	else if (rc)
+		dprintk(VIDC_WARN, "Failed to suspend: %d\n", rc);
+
+
+	return rc;
+}
+
+static int msm_vidc_pm_resume(struct device *dev)
+{
+	dprintk(VIDC_INFO, "%s\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops msm_vidc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume)
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+	.probe = msm_vidc_probe,
+	.remove = msm_vidc_remove,
+	.driver = {
+		.name = "msm_vidc_v4l2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vidc_dt_match,
+		.pm = &msm_vidc_pm_ops,
+	},
+};
+
+static int __init msm_vidc_init(void)
+{
+	int rc = 0;
+
+	vidc_driver = kzalloc(sizeof(*vidc_driver),
+						GFP_KERNEL);
+	if (!vidc_driver) {
+		dprintk(VIDC_ERR,
+			"Failed to allocate memroy for msm_vidc_drv\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&vidc_driver->cores);
+	mutex_init(&vidc_driver->lock);
+	vidc_driver->debugfs_root = msm_vidc_debugfs_init_drv();
+	if (!vidc_driver->debugfs_root)
+		dprintk(VIDC_ERR,
+			"Failed to create debugfs for msm_vidc\n");
+
+	rc = platform_driver_register(&msm_vidc_driver);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to register platform driver\n");
+		debugfs_remove_recursive(vidc_driver->debugfs_root);
+		kfree(vidc_driver);
+		vidc_driver = NULL;
+	}
+
+	return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+	platform_driver_unregister(&msm_vidc_driver);
+	debugfs_remove_recursive(vidc_driver->debugfs_root);
+	kfree(vidc_driver);
+	vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.c b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
new file mode 100644
index 0000000..04bdd65
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
@@ -0,0 +1,2751 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <soc/qcom/scm.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_OUTPUT_BUFFERS_VP9 6
+#define MIN_NUM_CAPTURE_BUFFERS 6
+#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS 1
+#define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
+#define MB_SIZE_IN_PIXEL (16 * 16)
+#define MAX_OPERATING_FRAME_RATE (300 << 16)
+#define OPERATING_FRAME_RATE_STEP (1 << 16)
+#define SLAVE_SIDE_CP_ALIGNMENT 0x100000
+#define MASTER_SIDE_CP_ALIGNMENT 0x1000
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+	"DIVX Format 3",
+	"DIVX Format 4",
+	"DIVX Format 5",
+	"DIVX Format 6",
+	NULL
+};
+static const char *const mpeg_video_stream_format[] = {
+	"NAL Format Start Codes",
+	"NAL Format One NAL Per Buffer",
+	"NAL Format One Byte Length",
+	"NAL Format Two Byte Length",
+	"NAL Format Four Byte Length",
+	NULL
+};
+static const char *const mpeg_video_output_order[] = {
+	"Display Order",
+	"Decode Order",
+	NULL
+};
+static const char *const mpeg_vidc_video_alloc_mode_type[] = {
+	"Buffer Allocation Static",
+	"Buffer Allocation Ring Buffer",
+	"Buffer Allocation Dynamic Buffer"
+};
+
+static const char *const perf_level[] = {
+	"Nominal",
+	"Performance",
+	"Turbo"
+};
+
+static const char *const h263_level[] = {
+	"1.0",
+	"2.0",
+	"3.0",
+	"4.0",
+	"4.5",
+	"5.0",
+	"6.0",
+	"7.0",
+};
+
+static const char *const h263_profile[] = {
+	"Baseline",
+	"H320 Coding",
+	"Backward Compatible",
+	"ISWV2",
+	"ISWV3",
+	"High Compression",
+	"Internet",
+	"Interlace",
+	"High Latency",
+};
+
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
+static const char *const mpeg2_profile[] = {
+	"Simple",
+	"Main",
+	"422",
+	"Snr Scalable",
+	"Spatial Scalable",
+	"High",
+};
+
+static const char *const mpeg2_level[] = {
+	"0",
+	"1",
+	"2",
+	"3",
+};
+static const char *const mpeg_vidc_video_entropy_mode[] = {
+	"CAVLC Entropy Mode",
+	"CABAC Entropy Mode",
+};
+
+static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
+	"Frame packing arrangement sequential",
+	"Frame packing arrangement top-bottom",
+};
+
+static const char *const mpeg_vidc_video_dpb_color_format[] = {
+	"DPB Color Format None",
+	"DPB Color Format UBWC",
+	"DPB Color Format UBWC TP10",
+};
+
+static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+		.name = "NAL Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+		),
+		.qmenu = mpeg_video_stream_format,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+		.name = "Output Order",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+			),
+		.qmenu = mpeg_video_output_order,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE,
+		.name = "Picture Type Decoding",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+		.name = "Keep Aspect Ratio",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+		.name = "Deblocker Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+		.name = "Divx Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+			),
+		.qmenu = mpeg_video_vidc_divx_format,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+		.name = "MB Error Map Reporting",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+		.name = "control",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
+		.name = "Sync Frame Decode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+		.name = "Secure mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+		.name = "Extradata Type",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE,
+		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI) |
+			(1 <<
+			V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE)
+			),
+		.qmenu = mpeg_video_vidc_extradata,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+		.name = "Decoder Performance Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+		.default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+		.qmenu = perf_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+		.name = "Buffer allocation mode for input",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+			),
+		.qmenu = mpeg_vidc_video_alloc_mode_type,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+		.name = "Buffer allocation mode for output",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+			),
+		.qmenu = mpeg_vidc_video_alloc_mode_type,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
+		.name = "Video frame assembly",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE,
+		.default_value =  V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
+		.name = "Video decoder multi stream",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.maximum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
+		.default_value =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.menu_skip_mask = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.name = "MPEG4 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum =
+		V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.name = "MPEG4 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		.name = "H264 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		.name = "H264 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+		.name = "H263 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+		),
+		.qmenu = h263_profile,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+		.name = "H263 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+		),
+		.qmenu = h263_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE,
+		.name = "MPEG2 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH)
+		),
+		.qmenu = mpeg2_profile,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL,
+		.name = "MPEG2 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3)
+		),
+		.qmenu = mpeg2_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD,
+		.name = "Video start code search threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = INT_MAX,
+		.default_value = INT_MAX,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT,
+		.name = "MVC buffer layout",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM)
+			),
+		.qmenu = mpeg_vidc_video_h264_mvc_layout,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
+		.name = "Picture concealed color",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x0,
+		.maximum = 0xffffff,
+		.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT,
+		.name = "Buffer size limit",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD,
+		.name = "Secure scaling output2 threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2,
+		.name = "Non-Secure output2",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT,
+		.name = "Video decoder dpb color format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC)
+			),
+		.qmenu = mpeg_vidc_video_dpb_color_format,
+	},
+	{
+		.id = V4L2_CID_VIDC_QBUF_MODE,
+		.name = "Allows batching of buffers for power savings",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_VIDC_QBUF_STANDARD,
+		.maximum = V4L2_VIDC_QBUF_BATCHED,
+		.default_value = V4L2_VIDC_QBUF_STANDARD,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		.name = "Entropy Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+		),
+		.qmenu = mpeg_vidc_video_entropy_mode,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY,
+		.name = "Session Priority",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE,
+		.name = "Set Decoder Operating rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_OPERATING_FRAME_RATE,
+		.default_value = 0,
+		.step = OPERATING_FRAME_RATE_STEP,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static int vdec_hal_to_v4l2(int id, int value);
+
+static u32 get_frame_size_nv12(int plane,
+					u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane,
+					u32 max_mbs_per_frame, u32 size_per_mb)
+{
+	return (max_mbs_per_frame * size_per_mb * 3/2)/2;
+}
+
+static u32 get_frame_size_nv12_ubwc_10bit(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
+}
+
+static u32 get_frame_size(struct msm_vidc_inst *inst,
+					const struct msm_vidc_format *fmt,
+					int fmt_type, int plane)
+{
+	u32 frame_size = 0;
+
+	if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		frame_size = fmt->get_frame_size(plane,
+					inst->capability.mbs_per_frame.max,
+					MB_SIZE_IN_PIXEL);
+		if (inst->buffer_size_limit &&
+			(inst->buffer_size_limit < frame_size)) {
+			frame_size = inst->buffer_size_limit;
+			dprintk(VIDC_DBG, "input buffer size limited to %d\n",
+				frame_size);
+		} else {
+			dprintk(VIDC_DBG, "set input buffer size to %d\n",
+				frame_size);
+		}
+	} else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		frame_size = fmt->get_frame_size(plane,
+					inst->capability.height.max,
+					inst->capability.width.max);
+		dprintk(VIDC_DBG, "set output buffer size to %d\n",
+			frame_size);
+	} else {
+		dprintk(VIDC_WARN, "Wrong format type\n");
+	}
+	return frame_size;
+}
+
+static u32 get_output_frame_size(struct msm_vidc_inst *inst,
+					const struct msm_vidc_format *fmt,
+					u32 height, u32 width, int plane)
+{
+	u32 frame_size = fmt->get_frame_size(plane,
+					height, width);
+
+	if (inst->flags & VIDC_SECURE) {
+		u32 alignment = inst->core->resources.slave_side_cp ?
+			SLAVE_SIDE_CP_ALIGNMENT : MASTER_SIDE_CP_ALIGNMENT;
+		frame_size = MSM_MEDIA_ALIGN(frame_size, alignment);
+	}
+	return frame_size;
+}
+
+static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
+					struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+		if (inst->fmts[OUTPUT_PORT].fourcc != V4L2_PIX_FMT_H264_MVC) {
+			dprintk(VIDC_ERR, "Control %#x only valid for MVC\n",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
+			ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
+			dprintk(VIDC_ERR,
+					"Profile %#x not supported for MVC\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
+			ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
+			dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+struct msm_vidc_format vdec_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0",
+		.description = "UBWC Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12_UBWC,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12_ubwc,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
+		.description = "UBWC Y/CbCr 4:2:0 10bit",
+		.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12_ubwc_10bit,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg2",
+		.description = "Mpeg2 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG2,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VC1",
+		.description = "VC-1 compressed format",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VC1 SP",
+		.description = "VC-1 compressed format G",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H264_MVC",
+		.description = "H264_MVC compressed format",
+		.fourcc = V4L2_PIX_FMT_H264_MVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "HEVC",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "HEVC_HYBRID",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VP8",
+		.description = "VP8 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VP9",
+		.description = "VP9 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP9,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "DIVX 311",
+		.description = "DIVX 311 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX_311,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "DIVX",
+		.description = "DIVX 4/5/6 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	}
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamon\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamoff\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vidc_buffer_addr_info buffer_info;
+	int extra_idx = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring prepare buf\n",
+				inst->core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+			"Planes mismatch: needed: %d, allocated: %d\n",
+			inst->fmts[CAPTURE_PORT].num_planes,
+			b->length);
+			rc = -EINVAL;
+			break;
+		}
+		for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); ++i) {
+			dprintk(VIDC_DBG,
+			"prepare plane: %d, device_addr = %#lx, size = %d\n",
+			i, b->m.planes[i].m.userptr,
+			b->m.planes[i].length);
+		}
+
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+			b->m.planes[extra_idx].m.userptr) {
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+			buffer_info.extradata_size =
+				b->m.planes[extra_idx].length;
+			dprintk(VIDC_DBG, "extradata: %pa, length = %d\n",
+				&buffer_info.extradata_addr,
+				buffer_info.extradata_size);
+		} else {
+			buffer_info.extradata_addr = 0;
+			buffer_info.extradata_size = 0;
+		}
+
+		rc = call_hfi_op(hdev, session_set_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"vidc_hal_session_set_buffers failed\n");
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vidc_buffer_addr_info buffer_info;
+	struct msm_vidc_core *core;
+	int extra_idx = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring release output buf\n",
+				core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+			"Planes mismatch: needed: %d, to release: %d\n",
+			inst->fmts[CAPTURE_PORT].num_planes, b->length);
+			rc = -EINVAL;
+			break;
+		}
+
+		for (i = 0; i < b->length; ++i) {
+			dprintk(VIDC_DBG,
+			"Release plane: %d device_addr = %#lx, size = %d\n",
+			i, b->m.planes[i].m.userptr,
+			b->m.planes[i].length);
+		}
+
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+		buffer_info.response_required = false;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES
+			&& b->m.planes[extra_idx].m.userptr)
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+		else
+			buffer_info.extradata_addr = 0;
+
+		rc = call_hfi_op(hdev, session_release_buffers,
+			(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"vidc_hal_session_release_buffers failed\n");
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	if (!inst || !b) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, buffer = %pK\n", inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	struct hfi_device *hdev;
+	int rc = 0, i = 0, stride = 0, scanlines = 0, color_format = 0;
+	unsigned int *plane_sizes = NULL, extra_idx = 0;
+
+	if (!inst || !f || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fmt = &inst->fmts[CAPTURE_PORT];
+	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fmt = &inst->fmts[OUTPUT_PORT];
+	else
+		return -ENOTSUPP;
+
+	f->fmt.pix_mp.pixelformat = fmt->fourcc;
+	f->fmt.pix_mp.num_planes = fmt->num_planes;
+	if (inst->in_reconfig) {
+		inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
+		inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"%s: unsupported session\n", __func__);
+			goto exit;
+		}
+	}
+
+	f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+	f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+	stride = inst->prop.width[CAPTURE_PORT];
+	scanlines = inst->prop.height[CAPTURE_PORT];
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		plane_sizes = &inst->bufq[OUTPUT_PORT].plane_sizes[0];
+		for (i = 0; i < fmt->num_planes; ++i) {
+			if (!plane_sizes[i]) {
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					get_frame_size(inst, fmt, f->type, i);
+				plane_sizes[i] = f->fmt.pix_mp.plane_fmt[i].
+					sizeimage;
+			} else
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					plane_sizes[i];
+		}
+		f->fmt.pix_mp.height = inst->prop.height[OUTPUT_PORT];
+		f->fmt.pix_mp.width = inst->prop.width[OUTPUT_PORT];
+		f->fmt.pix_mp.plane_fmt[0].bytesperline =
+			(__u16)inst->prop.width[OUTPUT_PORT];
+		f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+			(__u16)inst->prop.height[OUTPUT_PORT];
+	} else {
+		switch (fmt->fourcc) {
+		case V4L2_PIX_FMT_NV12:
+			color_format = COLOR_FMT_NV12;
+			break;
+		case V4L2_PIX_FMT_NV12_UBWC:
+			color_format = COLOR_FMT_NV12_UBWC;
+			break;
+		case V4L2_PIX_FMT_NV12_TP10_UBWC:
+			color_format = COLOR_FMT_NV12_BPP10_UBWC;
+			break;
+		default:
+			dprintk(VIDC_WARN, "Color format not recognized\n");
+			rc = -ENOTSUPP;
+			goto exit;
+		}
+
+		stride = VENUS_Y_STRIDE(color_format,
+				inst->prop.width[CAPTURE_PORT]);
+		scanlines = VENUS_Y_SCANLINES(color_format,
+				inst->prop.height[CAPTURE_PORT]);
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			get_output_frame_size(inst, fmt,
+			f->fmt.pix_mp.height, f->fmt.pix_mp.width, 0);
+
+		extra_idx = EXTRADATA_IDX(fmt->num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+
+		for (i = 0; i < fmt->num_planes; ++i)
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+
+		f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+		f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+		f->fmt.pix_mp.plane_fmt[0].bytesperline =
+			(__u16)stride;
+		f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+			(__u16)scanlines;
+	}
+
+exit:
+	return rc;
+}
+
+static int set_default_properties(struct msm_vidc_inst *inst)
+{
+	struct hfi_device *hdev;
+	struct v4l2_control ctrl = {0};
+	enum hal_default_properties defaults;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	defaults = call_hfi_op(hdev, get_default_properties,
+					hdev->hfi_device_data);
+
+	if (defaults & HAL_VIDEO_DYNAMIC_BUF_MODE) {
+		dprintk(VIDC_DBG, "Enable dynamic buffer mode\n");
+		ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT;
+		ctrl.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC;
+		rc = msm_comm_s_ctrl(inst, &ctrl);
+		if (rc)
+			dprintk(VIDC_ERR,
+				"Failed to enable dynamic buffer mode by default: %d\n",
+				rc);
+	}
+
+	return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	struct msm_vidc_format *fmt = NULL;
+	struct hal_frame_size frame_sz;
+	unsigned int extra_idx = 0;
+	int rc = 0;
+	int ret = 0;
+	int i;
+	int max_input_size = 0;
+
+	if (!inst || !inst->core || !f) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (!fmt || fmt->type != CAPTURE_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2,
+				f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_DBG,
+				"buffer type = %d width = %d, height = %d\n",
+				frame_sz.buffer_type, frame_sz.width,
+				frame_sz.height);
+			ret = msm_comm_try_set_prop(inst,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		} else {
+			msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
+				f->fmt.pix_mp.pixelformat);
+		}
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			get_output_frame_size(inst, &inst->fmts[fmt->type],
+			f->fmt.pix_mp.height, f->fmt.pix_mp.width, 0);
+
+		extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+
+		f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+				ARRAY_SIZE(vdec_formats),
+				f->fmt.pix_mp.pixelformat,
+				OUTPUT_PORT);
+		if (!fmt || fmt->type != OUTPUT_PORT) {
+			dprintk(VIDC_ERR,
+			"Format: %d not supported on OUTPUT port\n",
+			f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to initialize instance\n");
+			goto err_invalid_fmt;
+		}
+
+		if (!(get_hal_codec(inst->fmts[fmt->type].fourcc) &
+			inst->core->dec_codec_supported)) {
+			dprintk(VIDC_ERR,
+				"Codec(%#x) is not present in the supported codecs list(%#x)\n",
+				get_hal_codec(inst->fmts[fmt->type].fourcc),
+				inst->core->dec_codec_supported);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			goto err_invalid_fmt;
+		}
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto err_invalid_fmt;
+		}
+
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
+		dprintk(VIDC_DBG,
+			"buffer type = %d width = %d, height = %d\n",
+			frame_sz.buffer_type, frame_sz.width,
+			frame_sz.height);
+		msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+
+		max_input_size = get_frame_size(inst,
+					&inst->fmts[fmt->type], f->type, 0);
+		if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+			!f->fmt.pix_mp.plane_fmt[0].sizeimage) {
+			f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+		}
+
+		f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			inst->bufq[OUTPUT_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+
+		set_default_properties(inst);
+	}
+err_invalid_fmt:
+	return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, cap = %pK\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, f = %pK\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		dprintk(VIDC_DBG, "No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int set_actual_buffer_count(struct msm_vidc_inst *inst,
+			int count, enum hal_buffer type)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct hal_buffer_count_actual buf_count;
+
+	hdev = inst->core->device;
+
+	buf_count.buffer_type = type;
+	buf_count.buffer_count_actual = count;
+	rc = call_hfi_op(hdev, session_set_property,
+		inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL, &buf_count);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to set actual buffer count %d for buffer type %d\n",
+			count, type);
+	return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q,
+				unsigned int *num_buffers,
+				unsigned int *num_planes, unsigned int sizes[],
+				struct device *alloc_ctxs[])
+{
+	int i, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_buffer_requirements *bufreq;
+	int extra_idx = 0;
+	int min_buff_count = 0;
+
+	if (!q || !num_buffers || !num_planes
+		|| !sizes || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK, %pK, %pK\n",
+			q, num_buffers, num_planes);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"%s: Failed : Buffer requirements\n", __func__);
+		goto exit;
+	}
+
+
+
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+		/*
+		 * Increase input buffer count to 6 as for some
+		 * vp9 clips which have superframes with more
+		 * than 4 subframes requires more than 4
+		 * reference frames to decode.
+		 */
+		if (inst->fmts[OUTPUT_PORT].fourcc ==
+				V4L2_PIX_FMT_VP9 &&
+				*num_buffers < MIN_NUM_OUTPUT_BUFFERS_VP9)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS_VP9;
+
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = get_frame_size(inst,
+					&inst->fmts[OUTPUT_PORT], q->type, i);
+		}
+		rc = set_actual_buffer_count(inst, *num_buffers,
+			HAL_BUFFER_INPUT);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+		*num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			break;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
+			break;
+		}
+
+		bufreq = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"No buffer requirement for buffer type %x\n",
+				HAL_BUFFER_OUTPUT);
+			rc = -EINVAL;
+			break;
+		}
+
+		/* Pretend as if FW itself is asking for
+		 * additional buffers.
+		 * *num_buffers += MSM_VIDC_ADDITIONAL_BUFS_FOR_DCVS
+		 * is wrong since it will end up increasing the count
+		 * on every call to reqbufs if *num_bufs is larger
+		 * than min requirement.
+		 */
+		*num_buffers = max(*num_buffers, bufreq->buffer_count_min
+			+ msm_dcvs_get_extra_buff_count(inst));
+
+		min_buff_count = (!!(inst->flags & VIDC_THUMBNAIL)) ?
+			MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS :
+				MIN_NUM_CAPTURE_BUFFERS;
+
+		*num_buffers = clamp_val(*num_buffers,
+			min_buff_count, VB2_MAX_FRAME);
+
+		dprintk(VIDC_DBG, "Set actual output buffer count: %d\n",
+				*num_buffers);
+		rc = set_actual_buffer_count(inst, *num_buffers,
+					msm_comm_get_hal_output_buffer(inst));
+		if (rc)
+			break;
+
+		if (*num_buffers != bufreq->buffer_count_actual) {
+			rc = msm_comm_try_get_bufreqs(inst);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to get buf req, %d\n", rc);
+				break;
+			}
+		}
+		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
+				inst->buff_req.buffer[1].buffer_count_actual,
+				inst->buff_req.buffer[1].buffer_size,
+				inst->buff_req.buffer[1].buffer_alignment);
+		sizes[0] = inst->bufq[CAPTURE_PORT].plane_sizes[0];
+
+
+		/* Set actual buffer count to firmware for DPB buffers.
+		 * Firmware mandates setting of minimum buffer size
+		 * and actual buffer count for both OUTPUT and OUTPUT2.
+		 * Hence we are setting back the same buffer size
+		 * information back to firmware.
+		 */
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+			if (!bufreq) {
+				rc = -EINVAL;
+				break;
+			}
+
+			rc = set_actual_buffer_count(inst,
+				bufreq->buffer_count_actual,
+				HAL_BUFFER_OUTPUT);
+			if (rc)
+				break;
+		}
+
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			sizes[extra_idx] =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+exit:
+	return rc;
+}
+
+static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct {
+		enum hal_buffer type;
+		struct hal_buffer_requirements *req;
+		size_t size;
+	} internal_buffers[] = {
+		{ HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_PERSIST, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0},
+	};
+
+	struct hal_frame_size frame_sz;
+	int i;
+
+	frame_sz.buffer_type = HAL_BUFFER_INPUT;
+	frame_sz.width = inst->capability.width.max;
+	frame_sz.height =
+		(inst->capability.mbs_per_frame.max * 256) /
+		inst->capability.width.max;
+
+	dprintk(VIDC_DBG,
+		"Max buffer reqs, buffer type = %d width = %d, height = %d, max_mbs_per_frame = %d\n",
+		frame_sz.buffer_type, frame_sz.width,
+		frame_sz.height, inst->capability.mbs_per_frame.max);
+
+	msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s Failed to get max buf req, %d\n", __func__, rc);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) {
+		internal_buffers[i].req =
+			get_buff_req_buffer(inst, internal_buffers[i].type);
+		internal_buffers[i].size = internal_buffers[i].req ?
+			internal_buffers[i].req->buffer_size : 0;
+	}
+
+	frame_sz.buffer_type = HAL_BUFFER_INPUT;
+	frame_sz.width = inst->prop.width[OUTPUT_PORT];
+	frame_sz.height = inst->prop.height[OUTPUT_PORT];
+
+	msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s Failed to get back old buf req, %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG,
+			"Old buffer reqs, buffer type = %d width = %d, height = %d\n",
+			frame_sz.buffer_type, frame_sz.width,
+			frame_sz.height);
+
+	for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) {
+		if (internal_buffers[i].req) {
+			internal_buffers[i].req->buffer_size =
+				internal_buffers[i].size;
+			dprintk(VIDC_DBG,
+				"Changing buffer type : %d size to : %zd\n",
+				internal_buffers[i].type,
+				internal_buffers[i].size);
+		}
+	}
+	return 0;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	bool slave_side_cp = inst->core->resources.slave_side_cp;
+	struct hal_buffer_size_minimum b;
+	unsigned int buffer_size;
+	struct msm_vidc_format *fmt = NULL;
+
+	fmt = &inst->fmts[CAPTURE_PORT];
+	buffer_size = get_output_frame_size(inst, fmt,
+		inst->prop.height[CAPTURE_PORT],
+		inst->prop.width[CAPTURE_PORT], 0);
+	hdev = inst->core->device;
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_vidc_check_scaling_supported(inst);
+		b.buffer_type = HAL_BUFFER_OUTPUT2;
+	} else {
+		b.buffer_type = HAL_BUFFER_OUTPUT;
+	}
+
+	b.buffer_size = buffer_size;
+	rc = call_hfi_op(hdev, session_set_property,
+		 inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+		 &b);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+		return -EINVAL;
+	}
+	if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig &&
+		!slave_side_cp) {
+		rc = set_max_internal_buffers_size(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set max scratch buffer size: %d\n",
+				rc);
+			goto fail_start;
+		}
+	}
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_comm_set_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
+
+	/*
+	 * For seq_changed_insufficient, driver should set session_continue
+	 * to firmware after the following sequence
+	 * - driver raises insufficient event to v4l2 client
+	 * - all output buffers have been flushed and freed
+	 * - v4l2 client queries buffer requirements and splits/combines OPB-DPB
+	 * - v4l2 client sets new set of buffers to firmware
+	 * - v4l2 client issues CONTINUE to firmware to resume decoding of
+	 *   submitted ETBs.
+	 */
+	if (inst->in_reconfig) {
+		dprintk(VIDC_DBG, "send session_continue after reconfig\n");
+		rc = call_hfi_op(hdev, session_continue,
+			(void *) inst->session);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s - failed to send session_continue\n",
+				__func__);
+			goto fail_start;
+		}
+	}
+	inst->in_reconfig = false;
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto fail_start;
+	}
+	msm_dcvs_init_load(inst);
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_comm_queue_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to queue output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
+
+fail_start:
+	return rc;
+}
+
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+	return rc;
+}
+
+
+static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
+		q->type, inst);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		goto stream_start_failed;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Streamon failed on: %d capability for inst: %pK\n",
+			q->type, inst);
+		goto stream_start_failed;
+	}
+
+	rc = msm_comm_qbuf(inst, NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to commit buffers queued before STREAM_ON to hardware: %d\n",
+				rc);
+		goto stream_start_failed;
+	}
+
+stream_start_failed:
+	return rc;
+}
+
+static void msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return;
+	}
+
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = stop_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = stop_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR,
+			"Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+	int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+	.queue_setup = msm_vdec_queue_setup,
+	.start_streaming = msm_vdec_start_streaming,
+	.buf_queue = msm_vdec_buf_queue,
+	.stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+	return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
+		return -EINVAL;
+	}
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+	inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+	inst->capability.height.max = DEFAULT_HEIGHT;
+	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+	inst->capability.width.max = DEFAULT_WIDTH;
+	inst->capability.alloc_mode_in = HAL_BUFFER_MODE_STATIC;
+	inst->capability.alloc_mode_out = HAL_BUFFER_MODE_STATIC;
+	inst->capability.secure_output2_threshold.min = 0;
+	inst->capability.secure_output2_threshold.max = 0;
+	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->prop.fps = DEFAULT_FPS;
+	memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
+						sizeof(struct msm_vidc_format));
+	memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
+						sizeof(struct msm_vidc_format));
+	return rc;
+}
+
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+	switch (val) {
+	case V4L2_MPEG_VIDC_VIDEO_STATIC:
+		return HAL_BUFFER_MODE_STATIC;
+	case V4L2_MPEG_VIDC_VIDEO_RING:
+		return HAL_BUFFER_MODE_RING;
+	case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+		return HAL_BUFFER_MODE_DYNAMIC;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid buf type: %d\n", __func__, val);
+	}
+	return 0;
+}
+
+static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	union hal_get_property hprop;
+
+	if (!inst || !inst->core || !inst->core->device || !ctrl) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	/*
+	 * HACK: unlock the control prior to querying the hardware.  Otherwise
+	 * lower level code that attempts to do g_ctrl() will end up deadlocking
+	 * us.
+	 */
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting profile: %d",
+					__func__, rc);
+			break;
+		}
+		ctrl->val = vdec_hal_to_v4l2(ctrl->id,
+				hprop.profile_level.profile);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting level: %d",
+					__func__, rc);
+			break;
+		}
+
+		ctrl->val = vdec_hal_to_v4l2(ctrl->id,
+				hprop.profile_level.level);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD:
+		dprintk(VIDC_DBG, "Secure scaling threshold is: %d",
+				inst->capability.secure_output2_threshold.max);
+		ctrl->val = inst->capability.secure_output2_threshold.max;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_CONFIG_VDEC_ENTROPY, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting entropy type: %d",
+					__func__, rc);
+			break;
+		}
+		switch (hprop.h264_entropy) {
+		case HAL_H264_ENTROPY_CAVLC:
+			ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC;
+			break;
+		case HAL_H264_ENTROPY_CABAC:
+			ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC;
+			break;
+		case HAL_UNUSED_ENTROPY:
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	default:
+		/* Other controls aren't really volatile, shouldn't need to
+		 * modify ctrl->value
+		 */
+		break;
+	}
+	v4l2_ctrl_lock(ctrl);
+
+	return rc;
+}
+
+static int vdec_v4l2_to_hal(int id, int value)
+{
+	switch (id) {
+		/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			return HAL_H264_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+			return HAL_H264_PROFILE_CONSTRAINED_BASE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+			return HAL_H264_PROFILE_CONSTRAINED_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			return HAL_H264_PROFILE_MAIN;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+			return HAL_H264_PROFILE_EXTENDED;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			return HAL_H264_PROFILE_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+			return HAL_H264_PROFILE_HIGH10;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+			return HAL_H264_PROFILE_HIGH422;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+			return HAL_H264_PROFILE_HIGH444;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+			return HAL_H264_LEVEL_1;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+			return HAL_H264_LEVEL_1b;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+			return HAL_H264_LEVEL_11;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+			return HAL_H264_LEVEL_12;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+			return HAL_H264_LEVEL_13;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+			return HAL_H264_LEVEL_2;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+			return HAL_H264_LEVEL_21;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+			return HAL_H264_LEVEL_22;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+			return HAL_H264_LEVEL_31;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+			return HAL_H264_LEVEL_32;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+			return HAL_H264_LEVEL_4;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+			return HAL_H264_LEVEL_41;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+			return HAL_H264_LEVEL_42;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+			return HAL_H264_LEVEL_5;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+			return HAL_H264_LEVEL_51;
+		default:
+			goto unknown_value;
+		}
+	}
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+static int vdec_hal_to_v4l2(int id, int value)
+{
+	switch (id) {
+		/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case HAL_H264_PROFILE_BASELINE:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+		case HAL_H264_PROFILE_CONSTRAINED_BASE:
+			return
+			V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
+		case HAL_H264_PROFILE_MAIN:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+		case HAL_H264_PROFILE_EXTENDED:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
+		case HAL_H264_PROFILE_HIGH:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+		case HAL_H264_PROFILE_HIGH10:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
+		case HAL_H264_PROFILE_HIGH422:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
+		case HAL_H264_PROFILE_HIGH444:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case HAL_H264_LEVEL_1:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+		case HAL_H264_LEVEL_1b:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+		case HAL_H264_LEVEL_11:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+		case HAL_H264_LEVEL_12:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
+		case HAL_H264_LEVEL_13:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
+		case HAL_H264_LEVEL_2:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
+		case HAL_H264_LEVEL_21:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+		case HAL_H264_LEVEL_22:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+		case HAL_H264_LEVEL_3:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
+		case HAL_H264_LEVEL_31:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+		case HAL_H264_LEVEL_32:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+		case HAL_H264_LEVEL_4:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+		case HAL_H264_LEVEL_41:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
+		case HAL_H264_LEVEL_42:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+		case HAL_H264_LEVEL_5:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+		case HAL_H264_LEVEL_51:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+		/*
+		 * Extremely dirty hack: we haven't implemented g_ctrl of
+		 * any of these controls and have no intention of doing
+		 * so in the near future.  So just return 0 so that we
+		 * don't see the annoying "Unknown control" errors at the
+		 * bottom of this function.
+		 */
+		return 0;
+	}
+
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+		struct v4l2_ctrl **cluster, int ncontrols)
+{
+	int c;
+
+	for (c = 0; c < ncontrols; ++c)
+		if (cluster[c]->id == id)
+			return cluster[c];
+	return NULL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hal_nal_stream_format_supported stream_format;
+	struct hal_enable_picture enable_picture;
+	struct hal_enable hal_property;
+	enum hal_property property_id = 0;
+	u32 property_val = 0;
+	void *pdata = NULL;
+	struct hfi_device *hdev;
+	struct hal_extradata_enable extra;
+	struct hal_buffer_alloc_mode alloc_mode;
+	struct hal_multi_stream multi_stream;
+	struct hal_scs_threshold scs_threshold;
+	struct hal_mvc_buffer_layout layout;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	struct hal_profile_level profile_level;
+	struct hal_frame_size frame_sz;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	rc = is_ctrl_valid_for_codec(inst, ctrl);
+	if (rc)
+		return rc;
+
+	/* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+		struct v4l2_ctrl *__temp; \
+		__temp = get_ctrl_from_cluster( \
+			__ctrl_id, \
+			ctrl->cluster, ctrl->ncontrols); \
+		if (!__temp) { \
+			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+				#__ctrl_id, __ctrl_id); \
+			/* Clusters are hardcoded, if we can't find */ \
+			/* something then things are massively screwed up */ \
+			WARN_ON(VIDC_DBG_WARN_ENABLE); \
+		} \
+		__temp; \
+	})
+
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+		property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+		stream_format.nal_stream_format_supported = BIT(ctrl->val);
+		pdata = &stream_format;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+		property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE:
+		property_id = HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+		if (ctrl->val ==
+			V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON)
+			enable_picture.picture_type = HAL_PICTURE_I;
+		else
+			enable_picture.picture_type = HAL_PICTURE_I |
+				HAL_PICTURE_P | HAL_PICTURE_B |
+				HAL_PICTURE_IDR;
+		pdata = &enable_picture;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+		property_id = HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+		property_id = HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+		property_id = HAL_PARAM_DIVX_FORMAT;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+		property_id = HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+		property_id = HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE:
+			inst->flags &= ~VIDC_THUMBNAIL;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE:
+			inst->flags |= VIDC_THUMBNAIL;
+			break;
+		}
+
+		property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		inst->flags |= VIDC_SECURE;
+		dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
+				!!(inst->flags & VIDC_SECURE));
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+		property_id = HAL_PARAM_INDEX_EXTRADATA;
+		extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+		extra.enable = 1;
+		pdata = &extra;
+		break;
+	case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+			inst->flags &= ~VIDC_TURBO;
+			break;
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+			inst->flags |= VIDC_TURBO;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+		if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+		alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+		inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+		pdata = &alloc_mode;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
+		property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+
+		if (!(alloc_mode.buffer_mode &
+			inst->capability.alloc_mode_out)) {
+			dprintk(VIDC_WARN,
+				"buffer mode[%d] not supported for capture port[0x%x]\n",
+				ctrl->val, inst->capability.alloc_mode_out);
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &alloc_mode;
+		inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+				HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Downscaling not supported: %#x\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed : Enabling OUTPUT port : %d\n",
+					rc);
+				break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed:Disabling OUTPUT2 port : %d\n",
+					rc);
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed :Enabling OUTPUT2 port : %d\n",
+					rc);
+					break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed disabling OUTPUT port : %d\n",
+					rc);
+				break;
+			}
+
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			pdata = &frame_sz;
+			dprintk(VIDC_DBG,
+				"buffer type = %d width = %d, height = %d\n",
+				frame_sz.buffer_type, frame_sz.width,
+				frame_sz.height);
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_FRAME_SIZE, pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed setting OUTPUT2 size : %d\n",
+					rc);
+
+			alloc_mode.buffer_mode =
+				inst->buffer_mode_set[CAPTURE_PORT];
+			alloc_mode.buffer_type = HAL_BUFFER_OUTPUT2;
+			rc = call_hfi_op(hdev, session_set_property,
+				inst->session, HAL_PARAM_BUFFER_ALLOC_MODE,
+				&alloc_mode);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed to set alloc_mode on OUTPUT2: %d\n",
+					rc);
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Failed : Unsupported multi stream setting\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD:
+		property_id = HAL_PARAM_VDEC_SCS_THRESHOLD;
+		scs_threshold.threshold_value = ctrl->val;
+		pdata = &scs_threshold;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+		property_id = HAL_PARAM_MVC_BUFFER_LAYOUT;
+		layout.layout_type = msm_comm_get_hal_buffer_layout(ctrl->val);
+		layout.bright_view_first = 0;
+		layout.ngap = 0;
+		pdata = &layout;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
+		property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+		if (!temp_ctrl) {
+			dprintk(VIDC_ERR,
+				"failed to get control\n");
+			return -EINVAL;
+		}
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = vdec_v4l2_to_hal(ctrl->id,
+				ctrl->val);
+		profile_level.level = vdec_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+		if (!temp_ctrl) {
+			dprintk(VIDC_ERR,
+				"failed to get control\n");
+			return -EINVAL;
+		}
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = vdec_v4l2_to_hal(ctrl->id,
+				ctrl->val);
+		profile_level.profile = vdec_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT:
+		dprintk(VIDC_DBG,
+			"Limiting input buffer size from %u to %u\n",
+			inst->buffer_size_limit, ctrl->val);
+		inst->buffer_size_limit = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2:
+		property_id = HAL_PARAM_VDEC_NON_SECURE_OUTPUT2;
+		hal_property.enable = ctrl->val;
+		dprintk(VIDC_DBG, "%s non_secure output2\n",
+			ctrl->val ? "Enabling" : "Disabling");
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_VIDC_QBUF_MODE:
+		property_id = HAL_PARAM_SYNC_BASED_INTERRUPT;
+		hal_property.enable = ctrl->val == V4L2_VIDC_QBUF_BATCHED;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY:
+		property_id = HAL_CONFIG_REALTIME;
+		/* firmware has inverted values for realtime and
+		 * non-realtime priority
+		 */
+		hal_property.enable = !(ctrl->val);
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+		break;
+	default:
+		break;
+	}
+
+	v4l2_ctrl_lock(ctrl);
+#undef TRY_GET_CTRL
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG,
+			"Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
+			property_id, ctrl->id, ctrl->val);
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, property_id, pdata);
+	}
+
+	return rc;
+}
+
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0, i = 0, fourcc = 0;
+	struct v4l2_ext_control *ext_control;
+	struct v4l2_control control;
+
+	if (!inst || !inst->core || !ctrl) {
+		dprintk(VIDC_ERR,
+			"%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ext_control = ctrl->controls;
+	control.id =
+		V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+
+	for (i = 0; i < ctrl->count; i++) {
+		switch (ext_control[i].id) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+			control.value = ext_control[i].value;
+
+			rc = msm_comm_s_ctrl(inst, &control);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"%s Failed setting stream output mode : %d\n",
+					__func__, rc);
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
+			switch (ext_control[i].value) {
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
+				if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
+					rc = msm_comm_release_output_buffers(
+						inst);
+					if (rc)
+						dprintk(VIDC_ERR,
+							"%s Release output buffers failed\n",
+							__func__);
+				}
+				break;
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC:
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC:
+				if (ext_control[i].value ==
+					V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC)
+					fourcc = V4L2_PIX_FMT_NV12_UBWC;
+				else
+					fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC;
+				if (msm_comm_g_ctrl_for_id(inst, control.id)) {
+					rc = msm_comm_set_color_format(inst,
+						HAL_BUFFER_OUTPUT, fourcc);
+					if (rc) {
+						dprintk(VIDC_ERR,
+							"%s Failed setting output color format : %d\n",
+							__func__, rc);
+						break;
+					}
+					rc = msm_comm_try_get_bufreqs(inst);
+					if (rc)
+						dprintk(VIDC_ERR,
+							"%s Failed to get buffer requirements : %d\n",
+							__func__, rc);
+				}
+				break;
+			default:
+				dprintk(VIDC_ERR,
+					"%s Unsupported output color format\n",
+					__func__);
+				rc = -ENOTSUPP;
+				break;
+			}
+			break;
+		default:
+			dprintk(VIDC_ERR
+				, "%s Unsupported set control %d",
+				__func__, ext_control[i].id);
+			rc = -ENOTSUPP;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+				struct msm_vidc_inst, ctrl_handler);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			rc = try_set_ctrl(inst, ctrl->cluster[c]);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %x\n",
+						ctrl->cluster[c]->id);
+				break;
+			}
+		}
+	}
+
+failed_open_done:
+	return rc;
+}
+
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+				struct msm_vidc_inst, ctrl_handler);
+	struct v4l2_ctrl *master = ctrl->cluster[0];
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+	for (c = 0; c < master->ncontrols; ++c) {
+		int d = 0;
+
+		for (d = 0; d < NUM_CTRLS; ++d) {
+			if (master->cluster[c]->id == inst->ctrls[d]->id &&
+				inst->ctrls[d]->flags &
+				V4L2_CTRL_FLAG_VOLATILE) {
+				rc = try_get_ctrl(inst, master->cluster[c]);
+				if (rc) {
+					dprintk(VIDC_ERR, "Failed getting %x\n",
+							master->cluster[c]->id);
+					return rc;
+				}
+				break;
+			}
+		}
+	}
+	return rc;
+
+failed_open_done:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to get hal property\n");
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+	.s_ctrl = msm_vdec_op_s_ctrl,
+	.g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+	return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0;
+
+	rc = try_set_ext_ctrl(inst, ctrl);
+	if (rc) {
+		dprintk(VIDC_ERR, "Error setting extended control\n");
+		return rc;
+	}
+	return rc;
+}
+
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+	return msm_comm_ctrl_init(inst, msm_vdec_ctrls,
+		ARRAY_SIZE(msm_vdec_ctrls), &msm_vdec_ctrl_ops);
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.h b/drivers/media/platform/msm/vidc_3x/msm_vdec.h
new file mode 100644
index 0000000..065f02a
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012, 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c
new file mode 100644
index 0000000..a728b69
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c
@@ -0,0 +1,4599 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_CAPTURE_BUFFERS 4
+#define MIN_BIT_RATE 32000
+#define MAX_BIT_RATE 300000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define DEFAULT_FRAME_RATE 15
+#define MAX_OPERATING_FRAME_RATE (300 << 16)
+#define OPERATING_FRAME_RATE_STEP (1 << 16)
+#define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3)
+#define MIN_SLICE_BYTE_SIZE 512
+#define MAX_SLICE_MB_SIZE ((4096 * 2304) >> 8)
+#define I_FRAME_QP 26
+#define P_FRAME_QP 28
+#define B_FRAME_QP 30
+#define MAX_INTRA_REFRESH_MBS ((4096 * 2304) >> 8)
+#define MAX_NUM_B_FRAMES 4
+#define MAX_LTR_FRAME_COUNT 10
+#define MAX_HYBRID_HIER_P_LAYERS 6
+
+#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
+#define BITSTREAM_RESTRICT_ENABLED \
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED
+#define BITSTREAM_RESTRICT_DISABLED \
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED
+#define MIN_TIME_RESOLUTION 1
+#define MAX_TIME_RESOLUTION 0xFFFFFF
+#define DEFAULT_TIME_RESOLUTION 0x7530
+
+/*
+ * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
+ * coeffs are converted to s4.9 format (e.g. -22 converted to ((1 << 13) - 22)
+ * 3x3 transformation matrix coefficients in s4.9 fixed point format
+ */
+static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
+	470, 8170, 8148, 0, 490, 50, 0, 34, 483
+};
+
+/* offset coefficients in s9 fixed point format */
+static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
+	34, 0, 4
+};
+
+/* clamping value for Y/U/V([min,max] for Y/U/V) */
+static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
+	16, 235, 16, 240, 16, 240
+};
+
+static const char *const mpeg_video_rate_control[] = {
+	"No Rate Control",
+	"VBR VFR",
+	"VBR CFR",
+	"CBR VFR",
+	"CBR CFR",
+	"MBR CFR",
+	"MBR VFR",
+	NULL
+};
+
+static const char *const mpeg_video_rotation[] = {
+	"No Rotation",
+	"90 Degree Rotation",
+	"180 Degree Rotation",
+	"270 Degree Rotation",
+	NULL
+};
+
+static const char *const h264_video_entropy_cabac_model[] = {
+	"Model 0",
+	"Model 1",
+	"Model 2",
+	NULL
+};
+
+static const char *const h263_level[] = {
+	"1.0",
+	"2.0",
+	"3.0",
+	"4.0",
+	"4.5",
+	"5.0",
+	"6.0",
+	"7.0",
+};
+
+static const char *const h263_profile[] = {
+	"Baseline",
+	"H320 Coding",
+	"Backward Compatible",
+	"ISWV2",
+	"ISWV3",
+	"High Compression",
+	"Internet",
+	"Interlace",
+	"High Latency",
+};
+
+static const char *const hevc_tier_level[] = {
+	"Main Tier Level 1",
+	"Main Tier Level 2",
+	"Main Tier Level 2.1",
+	"Main Tier Level 3",
+	"Main Tier Level 3.1",
+	"Main Tier Level 4",
+	"Main Tier Level 4.1",
+	"Main Tier Level 5",
+	"Main Tier Level 5.1",
+	"Main Tier Level 5.2",
+	"Main Tier Level 6",
+	"Main Tier Level 6.1",
+	"Main Tier Level 6.2",
+	"High Tier Level 1",
+	"High Tier Level 2",
+	"High Tier Level 2.1",
+	"High Tier Level 3",
+	"High Tier Level 3.1",
+	"High Tier Level 4",
+	"High Tier Level 4.1",
+	"High Tier Level 5",
+	"High Tier Level 5.1",
+	"High Tier Level 5.2",
+	"High Tier Level 6",
+	"High Tier Level 6.1",
+	"High Tier Level 6.2",
+};
+
+static const char *const hevc_profile[] = {
+	"Main",
+	"Main10",
+	"Main Still Pic",
+};
+
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
+static const char *const perf_level[] = {
+	"Nominal",
+	"Performance",
+	"Turbo"
+};
+
+static const char *const mbi_statistics[] = {
+	"Camcorder Default",
+	"Mode 1",
+	"Mode 2",
+	"Mode 3"
+};
+
+static const char *const intra_refresh_modes[] = {
+	"None",
+	"Cyclic",
+	"Adaptive",
+	"Cyclic Adaptive",
+	"Random"
+};
+
+static const char *const timestamp_mode[] = {
+	"Honor",
+	"Ignore",
+};
+
+static const char *const iframe_sizes[] = {
+	"Default",
+	"Medium",
+	"Huge",
+	"Unlimited"
+};
+
+static struct msm_vidc_ctrl msm_venc_ctrls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
+		.name = "IDR Period",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = INT_MAX,
+		.default_value = DEFAULT_FRAME_RATE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
+		.name = "Intra Period for P frames",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 2*DEFAULT_FRAME_RATE-1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
+		.name = "Intra Period for B frames",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
+		.name = "Request I Frame",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
+		.name = "Video Framerate and Bitrate Control",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR)
+		),
+		.qmenu = mpeg_video_rate_control,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		.name = "Bitrate Control",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		.maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		.default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+		),
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
+		.name = "Bit Rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		.name = "Peak Bit Rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		.name = "Entropy Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+		.name = "CABAC Model",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
+		),
+		.qmenu = h264_video_entropy_cabac_model,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.name = "MPEG4 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum = CODING,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.name = "MPEG4 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		.name = "H264 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		.name = "H264 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+		.name = "H263 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+		),
+		.qmenu = h263_profile,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+		.name = "H263 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+		),
+		.qmenu = h263_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+		.name = "HEVC Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+		.menu_skip_mask =  ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC)
+		),
+		.qmenu = hevc_profile,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+		.name = "HEVC Tier and Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1)
+		),
+		.qmenu = hevc_tier_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+		.name = "Rotation",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
+		),
+		.qmenu = mpeg_video_rotation,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+		.name = "H264 I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+		.name = "H264 P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+		.name = "H264 B Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = B_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+		.name = "H263 I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+		.name = "H263 P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+		.name = "H263 B Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = B_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP,
+		.name = "VPX I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP,
+		.name = "VPX P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+		.name = "H264 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+		.name = "H264 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 51,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP,
+		.name = "VPX Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP,
+		.name = "VPX Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = 127,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP,
+		.name = "VP8 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 1,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP,
+		.name = "VP8 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 128,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+		.name = "MPEG4 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = 1,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+		.name = "MPEG4 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = 31,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED,
+		.name = "H264 Minimum QP PACKED",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x00010101,
+		.maximum = 0x00333333,
+		.default_value = 0x00010101,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED,
+		.name = "H264 Maximum QP PACKED",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x00010101,
+		.maximum = 0x00333333,
+		.default_value = 0x00333333,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		.name = "Slice Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB,
+		.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+		.name = "Slice Byte Size",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_SLICE_BYTE_SIZE,
+		.maximum = MAX_SLICE_BYTE_SIZE,
+		.default_value = MIN_SLICE_BYTE_SIZE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+		.name = "Slice MB Size",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = MAX_SLICE_MB_SIZE,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
+		.name = "Slice GOB",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = MAX_SLICE_MB_SIZE,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
+		.name = "Slice delivery mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
+		.name = "Intra Refresh Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
+		),
+		.qmenu = intra_refresh_modes,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
+		.name = "Intra Refresh AIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
+		.name = "Intra Refresh AIR REF",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+		.name = "H.264 Loop Filter Alpha Offset",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+		.name = "H.264 Loop Filter Beta Offset",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+		.name = "H.264 Loop Filter Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		.maximum = L_MODE,
+		.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
+		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
+		(1 << L_MODE)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		.name = "Sequence Header Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+		.default_value =
+			V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+		.name = "Secure mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+		.name = "Extradata Type",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO,
+		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS)|
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO)
+			),
+		.qmenu = mpeg_video_vidc_extradata,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO,
+		.name = "H264 VUI Timing Info",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER,
+		.name = "H264 AU Delimiter",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_ENABLED,
+		.step = 1,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+		.name = "Encoder Performance Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+		.default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+		.qmenu = perf_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT,
+		.name = "H264 VUI Timing Info",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = BITSTREAM_RESTRICT_DISABLED,
+		.maximum = BITSTREAM_RESTRICT_ENABLED,
+		.default_value = BITSTREAM_RESTRICT_ENABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY,
+		.name = "Preserve Text Qualty",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE,
+		.name = "Deinterlace for encoder",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION,
+		.name = "Vop time increment resolution",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_TIME_RESOLUTION,
+		.maximum = MAX_TIME_RESOLUTION,
+		.default_value = DEFAULT_TIME_RESOLUTION,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER,
+		.name = "Request Seq Header",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME,
+		.name = "H264 Use LTR",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT,
+		.name = "Ltr Count",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_LTR_FRAME_COUNT,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE,
+		.name = "Ltr Mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME,
+		.name = "H264 Mark LTR",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS,
+		.name = "Set Hier P num layers",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE,
+		.name = "Encoder Timestamp Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+		.maximum =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE)),
+		.qmenu = timestamp_mode,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE,
+		.name = "VP8 Error Resilience mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP,
+		.name = "Enable setting initial QP",
+		.type = V4L2_CTRL_TYPE_BITMASK,
+		.minimum = 0,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME |
+			V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME |
+			V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME,
+		.default_value = 0,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP,
+		.name = "Iframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP,
+		.name = "Pframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP,
+		.name = "Bframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP,
+		.name = "Iframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP,
+		.name = "Pframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP,
+		.name = "Bframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE,
+		.name = "I-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE,
+		.name = "I-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE,
+		.name = "P-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE,
+		.name = "P-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE,
+		.name = "B-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE,
+		.name = "B-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC,
+		.name = "Enable H264 SVC NAL",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE,
+		.name = "Set Encoder performance mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS,
+		.name = "Set Hier B num layers",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 3,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
+		.name = "Set Hybrid Hier P mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 5,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE,
+		.name = "MBI Statistics Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3)),
+		.qmenu = mbi_statistics,
+	},
+	{
+		.id = V4L2_CID_VIDC_QBUF_MODE,
+		.name = "Allows batching of buffers for power savings",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_VIDC_QBUF_STANDARD,
+		.maximum = V4L2_VIDC_QBUF_BATCHED,
+		.default_value = V4L2_VIDC_QBUF_STANDARD,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS,
+		.name = "Set Max Hier P num layers sessions",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID,
+		.name = "Set Base Layer ID for Hier-P",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP,
+		.name = "Set frame level QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH,
+		.name = "SAR Width",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 4096,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT,
+		.name = "SAR Height",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 2160,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY,
+		.name = "Session Priority",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI,
+		.name = "VQZIP SEI",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE,
+		.name = "Layer wise bitrate for H264/H265 Hybrid HP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE,
+		.name = "Set Encoder Operating rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_OPERATING_FRAME_RATE,
+		.default_value = 0,
+		.step = OPERATING_FRAME_RATE_STEP,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE,
+		.name = "BITRATE TYPE",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT,
+		.name = "Set H264 Picture Order Count",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2,
+		.default_value = 0,
+		.step = 2,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC,
+		.name = "Set VPE Color space conversion coefficients",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
+		.name = "Low Latency Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH,
+		.name = "Set Blur width",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2048,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT,
+		.name = "Set Blur height",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2048,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE,
+		.name = "Set Color space",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_BT709_5,
+		.maximum = MSM_VIDC_BT2020,
+		.default_value = MSM_VIDC_BT601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE,
+		.name = "Set Color space range",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS,
+		.name = "Set Color space transfer characterstics",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_TRANSFER_BT709_5,
+		.maximum = MSM_VIDC_TRANSFER_BT_2020_12,
+		.default_value = MSM_VIDC_TRANSFER_601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS,
+		.name = "Set Color space matrix coefficients",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_MATRIX_BT_709_5,
+		.maximum = MSM_VIDC_MATRIX_BT_2020_CONST,
+		.default_value = MSM_VIDC_MATRIX_601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8,
+		.name = "Transform 8x8",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE,
+		.name = "Bounds of I-frame size",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED)),
+		.qmenu = iframe_sizes,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
+
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_rgba(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
+}
+
+static u32 get_frame_size_rgba_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888_UBWC, width, height);
+}
+
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+	int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2;
+
+	return ALIGN(sz, SZ_4K);
+}
+
+static struct msm_vidc_format venc_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0",
+		.description = "UBWC Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12_UBWC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12_ubwc,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "RGBA 8:8:8:8",
+		.description = "RGBA 8:8:8:8",
+		.fourcc = V4L2_PIX_FMT_RGB32,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_rgba,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "UBWC RGBA 8:8:8:8",
+		.description = "UBWC RGBA 8:8:8:8",
+		.fourcc = V4L2_PIX_FMT_RGBA8888_UBWC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_rgba_ubwc,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "VP8",
+		.description = "VP8 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "HEVC",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "YCrCb Semiplanar 4:2:0",
+		.description = "Y/CrCb 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv21,
+		.type = OUTPUT_PORT,
+	},
+};
+
+static void msm_venc_update_plane_count(struct msm_vidc_inst *inst, int type)
+{
+	struct v4l2_ctrl *ctrl = NULL;
+	u32 extradata = 0;
+
+	if (!inst)
+		return;
+
+	inst->fmts[type].num_planes = 1;
+
+	ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+		V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+
+	if (ctrl)
+		extradata = v4l2_ctrl_g_ctrl(ctrl);
+
+	if (type == CAPTURE_PORT) {
+		switch (extradata) {
+		case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
+		case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
+		case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
+		case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+			inst->fmts[CAPTURE_PORT].num_planes = 2;
+		default:
+			break;
+		}
+	} else if (type == OUTPUT_PORT) {
+		switch (extradata) {
+		case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
+		case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
+		case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
+		case V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS:
+		case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP:
+		case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO:
+			inst->fmts[OUTPUT_PORT].num_planes = 2;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int msm_venc_set_csc(struct msm_vidc_inst *inst);
+
+static int msm_venc_queue_setup(struct vb2_queue *q,
+				unsigned int *num_buffers,
+				unsigned int *num_planes, unsigned int sizes[],
+				struct device *alloc_ctxs[])
+{
+	int i, temp, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_buffer_count_actual new_buf_count;
+	enum hal_property property_id;
+	struct hfi_device *hdev;
+	struct hal_buffer_requirements *buff_req;
+	u32 extra_idx = 0;
+	struct hal_buffer_requirements *buff_req_buffer = NULL;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to open instance\n");
+		return rc;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
+		return rc;
+	}
+
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		*num_planes = 1;
+
+		buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		if (buff_req) {
+
+			/* Pretend as if the FW itself is asking for additional
+			 * buffers, which are required for DCVS
+			 */
+			unsigned int min_req_buffers =
+				buff_req->buffer_count_min +
+				msm_dcvs_get_extra_buff_count(inst);
+			*num_buffers = max(*num_buffers, min_req_buffers);
+		}
+
+		if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS ||
+				*num_buffers > VB2_MAX_FRAME) {
+			int temp = *num_buffers;
+
+			*num_buffers = clamp_val(*num_buffers,
+					MIN_NUM_CAPTURE_BUFFERS,
+					VB2_MAX_FRAME);
+			dprintk(VIDC_INFO,
+				"Changing buffer count on CAPTURE_MPLANE from %d to %d for best effort encoding\n",
+				temp, *num_buffers);
+		}
+
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		*num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+
+		for (i = 0; i < *num_planes; i++) {
+			int extra_idx = EXTRADATA_IDX(*num_planes);
+
+			buff_req_buffer = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+
+			sizes[i] = buff_req_buffer ?
+				buff_req_buffer->buffer_size : 0;
+
+			if (extra_idx && i == extra_idx &&
+					extra_idx < VIDEO_MAX_PLANES) {
+				buff_req_buffer = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_OUTPUT);
+				if (!buff_req_buffer) {
+					dprintk(VIDC_ERR,
+						"%s: failed - invalid buffer req\n",
+						__func__);
+					return -EINVAL;
+				}
+
+				sizes[i] = buff_req_buffer->buffer_size;
+			}
+		}
+
+		dprintk(VIDC_DBG, "actual output buffer count set to fw = %d\n",
+				*num_buffers);
+		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+		new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+		new_buf_count.buffer_count_actual = *num_buffers;
+		rc = call_hfi_op(hdev, session_set_property, inst->session,
+			property_id, &new_buf_count);
+
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*num_planes = 1;
+
+		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
+			max(*num_buffers, inst->buff_req.buffer[0].
+				buffer_count_min);
+
+		temp = *num_buffers;
+
+		*num_buffers = clamp_val(*num_buffers,
+				MIN_NUM_OUTPUT_BUFFERS,
+				VB2_MAX_FRAME);
+		dprintk(VIDC_INFO,
+			"Changing buffer count on OUTPUT_MPLANE from %d to %d for best effort encoding\n",
+			temp, *num_buffers);
+
+		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+		new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+		new_buf_count.buffer_count_actual = *num_buffers;
+
+		dprintk(VIDC_DBG, "actual input buffer count set to fw = %d\n",
+				*num_buffers);
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		*num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+
+		rc = call_hfi_op(hdev, session_set_property, inst->session,
+					property_id, &new_buf_count);
+		if (rc)
+			dprintk(VIDC_ERR, "failed to set count to fw\n");
+
+		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
+				inst->buff_req.buffer[0].buffer_size,
+				inst->buff_req.buffer[0].buffer_alignment,
+				inst->buff_req.buffer[0].buffer_count_actual);
+		sizes[0] = inst->fmts[OUTPUT_PORT].get_frame_size(
+				0, inst->prop.height[OUTPUT_PORT],
+				inst->prop.width[OUTPUT_PORT]);
+
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[OUTPUT_PORT].num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			buff_req_buffer = get_buff_req_buffer(inst,
+				HAL_BUFFER_EXTRADATA_INPUT);
+			if (!buff_req_buffer) {
+				dprintk(VIDC_ERR,
+					"%s: failed - invalid buffer req\n",
+					__func__);
+				return -EINVAL;
+			}
+
+			sizes[extra_idx] = buff_req_buffer->buffer_size;
+		}
+
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
+{
+	int num_enh_layers = 0;
+	u32 property_id = 0;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_VP8)
+		return 0;
+
+	num_enh_layers = layers ? : 0;
+	dprintk(VIDC_DBG, "%s Hier-P in firmware\n",
+			num_enh_layers ? "Enable" : "Disable");
+
+	hdev = inst->core->device;
+	property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+	rc = call_hfi_op(hdev, session_set_property,
+			(void *)inst->session, property_id,
+			(void *)&num_enh_layers);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed with error = %d\n", __func__, rc);
+	}
+	return rc;
+}
+
+static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst)
+{
+	u32 rc = 0;
+	u32 prop_id = 0, power_save_min = 0, power_save_max = 0, inst_load = 0;
+	void *pdata = NULL;
+	struct hfi_device *hdev = NULL;
+	enum hal_perf_mode venc_mode;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	inst_load = msm_comm_get_inst_load(inst, quirks);
+	power_save_min = inst->capability.mbs_per_sec_power_save.min;
+	power_save_max = inst->capability.mbs_per_sec_power_save.max;
+
+	dprintk(VIDC_DBG,
+		"Power Save Mode min mb's %d max mb's %d inst load %d\n",
+		power_save_min, power_save_max, inst_load);
+
+	if (!power_save_min || !power_save_max)
+		return rc;
+
+	hdev = inst->core->device;
+	if (inst_load >= power_save_min) {
+		prop_id = HAL_CONFIG_VENC_PERF_MODE;
+		venc_mode = HAL_PERF_MODE_POWER_SAVE;
+		pdata = &venc_mode;
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, prop_id, pdata);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to set power save mode for inst: %pK\n",
+				__func__, inst);
+			goto fail_power_mode_set;
+		}
+		inst->flags |= VIDC_LOW_POWER;
+		msm_dcvs_enc_set_power_save_mode(inst, true);
+		dprintk(VIDC_INFO, "Power Save Mode set for inst: %pK\n", inst);
+	}
+
+fail_power_mode_set:
+	return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	msm_venc_power_save_mode_enable(inst);
+	if (inst->capability.pixelprocess_capabilities &
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
+		rc = msm_vidc_check_scaling_supported(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+		return -EINVAL;
+	}
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to get Buffer Requirements : %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto fail_start;
+	}
+	msm_dcvs_init_load(inst);
+
+fail_start:
+	return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
+		q->type, inst);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		goto stream_start_failed;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Streamon failed on: %d capability for inst: %pK\n",
+			q->type, inst);
+		goto stream_start_failed;
+	}
+
+	rc = msm_comm_qbuf(inst, NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to commit buffers queued before STREAM_ON to hardware: %d\n",
+				rc);
+		goto stream_start_failed;
+	}
+
+stream_start_failed:
+	return rc;
+}
+
+static void msm_venc_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "%s - Invalid input, q = %pK\n", __func__, q);
+		return;
+	}
+
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_CLOSE_DONE);
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+	int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+	.queue_setup = msm_venc_queue_setup,
+	.start_streaming = msm_venc_start_streaming,
+	.buf_queue = msm_venc_buf_queue,
+	.stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+	return &msm_venc_vb2q_ops;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+		struct v4l2_ctrl **cluster, int ncontrols)
+{
+	int c;
+
+	for (c = 0; c < ncontrols; ++c)
+		if (cluster[c]->id == id)
+			return cluster[c];
+	return NULL;
+}
+
+/* Helper function to translate V4L2_* to HAL_* */
+static inline int venc_v4l2_to_hal(int id, int value)
+{
+	switch (id) {
+	/* MPEG4 */
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+			return HAL_MPEG4_LEVEL_0;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+			return HAL_MPEG4_LEVEL_0b;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+			return HAL_MPEG4_LEVEL_1;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+			return HAL_MPEG4_LEVEL_2;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+			return HAL_MPEG4_LEVEL_3;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+			return HAL_MPEG4_LEVEL_4;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+			return HAL_MPEG4_LEVEL_5;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			return HAL_MPEG4_PROFILE_SIMPLE;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+		default:
+			goto unknown_value;
+		}
+	/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			return HAL_H264_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+			return HAL_H264_PROFILE_CONSTRAINED_BASE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			return HAL_H264_PROFILE_MAIN;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+			return HAL_H264_PROFILE_EXTENDED;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			return HAL_H264_PROFILE_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+			return HAL_H264_PROFILE_HIGH10;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+			return HAL_H264_PROFILE_HIGH422;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+			return HAL_H264_PROFILE_HIGH444;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+			return HAL_H264_PROFILE_CONSTRAINED_HIGH;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+			return HAL_H264_LEVEL_1;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+			return HAL_H264_LEVEL_1b;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+			return HAL_H264_LEVEL_11;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+			return HAL_H264_LEVEL_12;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+			return HAL_H264_LEVEL_13;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+			return HAL_H264_LEVEL_2;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+			return HAL_H264_LEVEL_21;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+			return HAL_H264_LEVEL_22;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+			return HAL_H264_LEVEL_31;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+			return HAL_H264_LEVEL_32;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+			return HAL_H264_LEVEL_4;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+			return HAL_H264_LEVEL_41;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+			return HAL_H264_LEVEL_42;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+			return HAL_H264_LEVEL_5;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+			return HAL_H264_LEVEL_51;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+			return HAL_H264_LEVEL_52;
+		default:
+			goto unknown_value;
+		}
+	/* H263 */
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+			return HAL_H263_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+			return HAL_H263_PROFILE_H320CODING;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+			return HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+			return HAL_H263_PROFILE_ISWV2;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+			return HAL_H263_PROFILE_ISWV3;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+			return HAL_H263_PROFILE_HIGHCOMPRESSION;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+			return HAL_H263_PROFILE_INTERNET;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+			return HAL_H263_PROFILE_INTERLACE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+			return HAL_H263_PROFILE_HIGHLATENCY;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
+			return HAL_H264_ENTROPY_CAVLC;
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
+			return HAL_H264_ENTROPY_CABAC;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0:
+			return HAL_H264_CABAC_MODEL_0;
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1:
+			return HAL_H264_CABAC_MODEL_1;
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2:
+			return HAL_H264_CABAC_MODEL_2;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+			return HAL_H263_LEVEL_10;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+			return HAL_H263_LEVEL_20;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+			return HAL_H263_LEVEL_30;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+			return HAL_H263_LEVEL_40;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+			return HAL_H263_LEVEL_45;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+			return HAL_H263_LEVEL_50;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+			return HAL_H263_LEVEL_60;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+			return HAL_H263_LEVEL_70;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+			return HAL_VPX_PROFILE_VERSION_0;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+			return HAL_VPX_PROFILE_VERSION_1;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+			return HAL_VPX_PROFILE_VERSION_2;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+			return HAL_VPX_PROFILE_VERSION_3;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+			return HAL_VPX_PROFILE_UNUSED;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN:
+			return HAL_HEVC_PROFILE_MAIN;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10:
+			return HAL_HEVC_PROFILE_MAIN10;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC:
+			return HAL_HEVC_PROFILE_MAIN_STILL_PIC;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_2_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3:
+			return HAL_HEVC_MAIN_TIER_LEVEL_3;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_3_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4:
+			return HAL_HEVC_MAIN_TIER_LEVEL_4;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_4_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2:
+			return HAL_HEVC_HIGH_TIER_LEVEL_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_2_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3:
+			return HAL_HEVC_HIGH_TIER_LEVEL_3;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_3_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4:
+			return HAL_HEVC_HIGH_TIER_LEVEL_4;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_4_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6:
+			return HAL_HEVC_HIGH_TIER_LEVEL_6;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
+			return HAL_ROTATE_NONE;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90:
+			return HAL_ROTATE_90;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180:
+			return HAL_ROTATE_180;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270:
+			return HAL_ROTATE_270;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+			return HAL_H264_DB_MODE_DISABLE;
+		case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+			return HAL_H264_DB_MODE_ALL_BOUNDARY;
+		case L_MODE:
+			return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT:
+			return HAL_STATISTICS_MODE_DEFAULT;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1:
+			return HAL_STATISTICS_MODE_1;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2:
+			return HAL_STATISTICS_MODE_2;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3:
+			return HAL_STATISTICS_MODE_3;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT:
+			return HAL_IFRAMESIZE_TYPE_DEFAULT;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM:
+			return HAL_IFRAMESIZE_TYPE_MEDIUM;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE:
+			return HAL_IFRAMESIZE_TYPE_HUGE;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED:
+			return HAL_IFRAMESIZE_TYPE_UNLIMITED;
+		default:
+			goto unknown_value;
+		}
+	}
+
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+/* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+		struct v4l2_ctrl *__temp; \
+		__temp = get_ctrl_from_cluster( \
+			__ctrl_id, \
+			ctrl->cluster, ctrl->ncontrols); \
+		if (!__temp) { \
+			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+				#__ctrl_id, __ctrl_id); \
+			/* Clusters are hardcoded, if we can't find */ \
+			/* something then things are massively screwed up */ \
+			WARN_ON(VIDC_DBG_WARN_ENABLE); \
+		} \
+		__temp; \
+	})
+
+static int msm_venc_validate_qp_value(struct msm_vidc_inst *inst,
+					struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, min, max;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	int qp_value = ctrl->val;
+
+#define VALIDATE_BOUNDARIES(__min, __max, __val) ({\
+	int __rc = __val >= __min && \
+			__val <= __max; \
+	if (!__rc) \
+		dprintk(VIDC_ERR, "QP beyond range: min(%d) max(%d) val(%d)", \
+				__min, __max, __val); \
+	__rc; \
+})
+
+	switch (inst->fmts[CAPTURE_PORT].fourcc) {
+	case V4L2_PIX_FMT_VP8:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP);
+		if (!temp_ctrl) {
+			dprintk(VIDC_ERR,
+				"failed to get control");
+			return -EINVAL;
+		}
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	case V4L2_PIX_FMT_H263:
+	case V4L2_PIX_FMT_MPEG4:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP);
+		if (!temp_ctrl) {
+			dprintk(VIDC_ERR,
+				"failed to get control");
+			return -EINVAL;
+		}
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_HEVC:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+		if (!temp_ctrl) {
+			dprintk(VIDC_ERR,
+				"failed to get control");
+			return -EINVAL;
+		}
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s Invalid Codec\n", __func__);
+		return -EINVAL;
+	}
+	return rc;
+#undef VALIDATE_BOUNDARIES
+}
+
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hal_request_iframe request_iframe;
+	struct hal_bitrate bitrate;
+	struct hal_profile_level profile_level;
+	struct hal_h264_entropy_control h264_entropy_control;
+	struct hal_quantization quantization;
+	struct hal_intra_period intra_period;
+	struct hal_idr_period idr_period;
+	struct hal_operations operations;
+	struct hal_intra_refresh intra_refresh;
+	struct hal_multi_slice_control multi_slice_control;
+	struct hal_h264_db_control h264_db_control;
+	struct hal_enable enable;
+	struct hal_h264_vui_timing_info vui_timing_info;
+	struct hal_quantization_range qp_range;
+	struct hal_h264_vui_bitstream_restrc vui_bitstream_restrict;
+	struct hal_preserve_text_quality preserve_text_quality;
+	u32 property_id = 0, property_val = 0;
+	void *pdata = NULL;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	struct hfi_device *hdev;
+	struct hal_extradata_enable extra;
+	struct hal_mpeg4_time_resolution time_res;
+	struct hal_ltr_use use_ltr;
+	struct hal_ltr_mark mark_ltr;
+	struct hal_hybrid_hierp hyb_hierp;
+	u32 hier_p_layers = 0, hier_b_layers = 0, mbi_statistics_mode = 0;
+	enum hal_perf_mode venc_mode;
+	int max_hierp_layers;
+	int baselayerid = 0;
+	int frameqp = 0;
+	int pic_order_cnt = 0;
+	struct hal_video_signal_info signal_info = {0};
+	enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	/*
+	 * Unlock the control prior to setting to the hardware. Otherwise
+	 * lower level code that attempts to do a get_ctrl() will end up
+	 * deadlocking.
+	 */
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
+		if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264 &&
+			inst->fmts[CAPTURE_PORT].fourcc !=
+				V4L2_PIX_FMT_H264_NO_SC &&
+			inst->fmts[CAPTURE_PORT].fourcc !=
+				V4L2_PIX_FMT_HEVC) {
+			dprintk(VIDC_ERR,
+				"Control %#x only valid for H264 and HEVC\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		property_id = HAL_CONFIG_VENC_IDR_PERIOD;
+		idr_period.idr_period = ctrl->val;
+		pdata = &idr_period;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+	{
+		int num_p, num_b;
+		u32 max_num_b_frames;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+		num_b = temp_ctrl->val;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
+		num_p = temp_ctrl->val;
+
+		if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES)
+			num_p = ctrl->val;
+		else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES)
+			num_b = ctrl->val;
+
+		max_num_b_frames = num_b ? MAX_NUM_B_FRAMES : 0;
+		property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
+		pdata = &max_num_b_frames;
+		rc = call_hfi_op(hdev, session_set_property,
+			(void *)inst->session, property_id, pdata);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed : Setprop MAX_NUM_B_FRAMES %d\n",
+				rc);
+			break;
+		}
+
+		property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+		intra_period.pframes = num_p;
+		intra_period.bframes = num_b;
+
+		/*
+		 *Incase firmware does not have B-Frame support,
+		 *offload the b-frame count to p-frame to make up
+		 *for the requested Intraperiod
+		 */
+		if (!inst->capability.bframe.max) {
+			intra_period.pframes = num_p + num_b;
+			intra_period.bframes = 0;
+			dprintk(VIDC_DBG,
+				"No bframe support, changing pframe from %d to %d\n",
+				num_p, intra_period.pframes);
+		}
+		pdata = &intra_period;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
+		property_id = HAL_CONFIG_VENC_REQUEST_IFRAME;
+		request_iframe.enable = true;
+		pdata = &request_iframe;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	{
+		int final_mode = 0;
+		struct v4l2_ctrl update_ctrl = {.id = 0};
+
+		/* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL
+		 * manipulate the same thing.  If one control's state
+		 * changes, try to mirror the state in the other control's
+		 * value
+		 */
+		if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) {
+			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+				final_mode = HAL_RATE_CONTROL_VBR_CFR;
+				update_ctrl.val =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
+			} else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */
+				final_mode = HAL_RATE_CONTROL_CBR_CFR;
+				update_ctrl.val =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+			}
+
+			update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
+
+		} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) {
+			switch (ctrl->val) {
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+				break;
+			}
+
+			final_mode = ctrl->val;
+			update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
+		}
+
+		if (update_ctrl.id) {
+			temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
+			temp_ctrl->val = update_ctrl.val;
+		}
+
+		property_id = HAL_PARAM_VENC_RATE_CONTROL;
+		property_val = final_mode;
+		pdata = &property_val;
+
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+	{
+		property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+		bitrate.bit_rate = ctrl->val;
+		bitrate.layer_id = 0;
+		pdata = &bitrate;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+	{
+		struct v4l2_ctrl *avg_bitrate = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDEO_BITRATE);
+
+		if (ctrl->val < avg_bitrate->val) {
+			dprintk(VIDC_ERR,
+				"Peak bitrate (%d) is lower than average bitrate (%d)\n",
+				ctrl->val, avg_bitrate->val);
+			rc = -EINVAL;
+			break;
+		} else if (ctrl->val < avg_bitrate->val * 2) {
+			dprintk(VIDC_WARN,
+				"Peak bitrate (%d) ideally should be twice the average bitrate (%d)\n",
+				ctrl->val, avg_bitrate->val);
+		}
+
+		property_id = HAL_CONFIG_VENC_MAX_BITRATE;
+		bitrate.bit_rate = ctrl->val;
+		bitrate.layer_id = 0;
+		pdata = &bitrate;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		temp_ctrl = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL);
+
+		property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+		h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+		h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+			temp_ctrl->val);
+		pdata = &h264_entropy_control;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE);
+
+		property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+		h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+		h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+			temp_ctrl->val);
+		pdata = &h264_entropy_control;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+						ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		dprintk(VIDC_DBG, "\nprofile: %d\n",
+			   profile_level.profile);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		dprintk(VIDC_DBG, "\nLevel: %d\n",
+			   profile_level.level);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+				ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+				ctrl->val);
+		profile_level.level = HAL_VPX_PROFILE_UNUSED;
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+	{
+		struct v4l2_ctrl *deinterlace = NULL;
+
+		if (!(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Rotation not supported: %#x\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		deinterlace =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE);
+		if (ctrl->val && deinterlace && deinterlace->val !=
+				V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED) {
+			dprintk(VIDC_ERR,
+				"Rotation not supported with deinterlacing\n");
+			rc = -EINVAL;
+			break;
+		}
+		property_id = HAL_CONFIG_VPE_OPERATIONS;
+		operations.rotate = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+				ctrl->val);
+		operations.flip = HAL_FLIP_NONE;
+		pdata = &operations;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp, *qpb;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpb;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpp;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpb = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpp = qpp->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp, *qpb;
+
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpb;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpp;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpb = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpp = qpp->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp;
+
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		/* Bframes are not supported for VPX */
+		quantization.qpb = 0;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		/* Bframes are not supported for VPX */
+		quantization.qpb = 0;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP PACKED (0x%x) > Max QP PACKED (0x%x)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP PACKED (%d) < Min QP PACKED (%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
+		int temp = 0;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+		default:
+			temp = 0;
+			break;
+		}
+
+		if (temp)
+			temp_ctrl = TRY_GET_CTRL(temp);
+
+		property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+		multi_slice_control.multi_slice = ctrl->val;
+		multi_slice_control.slice_size = temp ? temp_ctrl->val : 0;
+
+		pdata = &multi_slice_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+
+		property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+		multi_slice_control.multi_slice = temp_ctrl->val;
+		multi_slice_control.slice_size = ctrl->val;
+		pdata = &multi_slice_control;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
+		bool codec_avc =
+			inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 ||
+			inst->fmts[CAPTURE_PORT].fourcc ==
+							V4L2_PIX_FMT_H264_NO_SC;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+		if (codec_avc && temp_ctrl->val ==
+				V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+			property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
+			enable.enable = true;
+		} else {
+			dprintk(VIDC_WARN,
+			"Failed : slice delivery mode is not supported\n");
+			enable.enable = false;
+		}
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
+		struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
+		bool is_cont_intra_supported = false;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		is_cont_intra_supported =
+		(inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264) ||
+		(inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC);
+
+		if (is_cont_intra_supported) {
+			if (ctrl->val != HAL_INTRA_REFRESH_NONE)
+				enable.enable = true;
+			else
+				enable.enable = false;
+
+			rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session,
+				HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, &enable);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to set constrained intra\n");
+				rc = -EINVAL;
+				break;
+			}
+		}
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.mode = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.air_mbs = ctrl->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.air_ref = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = ir_mode->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+		struct v4l2_ctrl *air_mbs, *air_ref;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+	{
+		struct v4l2_ctrl *alpha, *beta;
+
+		alpha = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+		beta = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = alpha->val;
+		h264_db_control.slice_beta_offset = beta->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				ctrl->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+	{
+		struct v4l2_ctrl *mode, *beta;
+
+		mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+		beta = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = ctrl->val;
+		h264_db_control.slice_beta_offset = beta->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				mode->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+	{
+		struct v4l2_ctrl *mode, *alpha;
+
+		mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+		alpha = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = alpha->val;
+		h264_db_control.slice_beta_offset = ctrl->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				mode->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		property_id = HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+			enable.enable = 1;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		inst->flags |= VIDC_SECURE;
+		dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
+				!!(inst->flags & VIDC_SECURE));
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+		property_id = HAL_PARAM_INDEX_EXTRADATA;
+		extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+		extra.enable = 1;
+		pdata = &extra;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+	{
+		struct v4l2_ctrl *rc_mode;
+		bool cfr = false;
+
+		property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
+		rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+
+		switch (rc_mode->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			cfr = true;
+			break;
+		default:
+			cfr = false;
+			break;
+		}
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED:
+			vui_timing_info.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
+			vui_timing_info.enable = 1;
+			vui_timing_info.fixed_frame_rate = cfr;
+			vui_timing_info.time_scale = NSEC_PER_SEC;
+		}
+
+		pdata = &vui_timing_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER:
+		property_id = HAL_PARAM_VENC_GENERATE_AUDNAL;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_ENABLED:
+			enable.enable = 1;
+			break;
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+			if (inst->flags & VIDC_TURBO) {
+				inst->flags &= ~VIDC_TURBO;
+				msm_dcvs_init_load(inst);
+			}
+			break;
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+			inst->flags |= VIDC_TURBO;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT:
+		property_id = HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC;
+		vui_bitstream_restrict.enable = ctrl->val;
+		pdata = &vui_bitstream_restrict;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY:
+		property_id = HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY;
+		preserve_text_quality.enable = ctrl->val;
+		pdata = &preserve_text_quality;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION:
+		property_id = HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+		time_res.time_increment_resolution = ctrl->val;
+		pdata = &time_res;
+		break;
+
+	case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+	{
+		struct v4l2_ctrl *rotation = NULL;
+
+		if (!(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Deinterlace not supported: %#x\n",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		rotation = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+		if (ctrl->val && rotation && rotation->val !=
+			V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) {
+			dprintk(VIDC_ERR,
+				"Deinterlacing not supported with rotation");
+			rc = -EINVAL;
+			break;
+		}
+		property_id = HAL_CONFIG_VPE_DEINTERLACE;
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED:
+			enable.enable = 1;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED:
+		default:
+			enable.enable = 0;
+			break;
+		}
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER:
+		atomic_inc(&inst->seq_hdr_reqs);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
+		property_id = HAL_CONFIG_VENC_USELTRFRAME;
+		use_ltr.ref_ltr = ctrl->val;
+		use_ltr.use_constraint = false;
+		use_ltr.frames = 0;
+		pdata = &use_ltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME:
+		if (ctrl->val < inst->capability.ltr_count.min ||
+			ctrl->val >= inst->capability.ltr_count.max) {
+			dprintk(VIDC_ERR,
+				"Error setting markltr %d range: [%d,%d)\n",
+				ctrl->val, inst->capability.ltr_count.min,
+				inst->capability.ltr_count.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_CONFIG_VENC_MARKLTRFRAME;
+		mark_ltr.mark_frame = ctrl->val;
+		pdata = &mark_ltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
+		property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
+		hier_p_layers = ctrl->val;
+		if (hier_p_layers > inst->capability.hier_p.max) {
+			dprintk(VIDC_ERR,
+				"Error setting hier p num layers %d max supported is %d\n",
+				hier_p_layers, inst->capability.hier_p.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &hier_p_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE:
+		property_id = HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP;
+		enable.enable = (ctrl->val ==
+		V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE);
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE:
+		property_id = HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC:
+		property_id = HAL_PARAM_VENC_H264_NAL_SVC_EXT;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE:
+		property_id = HAL_CONFIG_VENC_PERF_MODE;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE:
+			inst->flags |= VIDC_LOW_POWER;
+			venc_mode = HAL_PERF_MODE_POWER_SAVE;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY:
+			inst->flags &= ~VIDC_LOW_POWER;
+			venc_mode = HAL_PERF_MODE_POWER_MAX_QUALITY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Power save mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			property_id = 0;
+			break;
+		}
+		pdata = &venc_mode;
+
+		msm_dcvs_enc_set_power_save_mode(inst,
+			ctrl->val == V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
+		if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) {
+			dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS;
+		hier_b_layers = ctrl->val;
+		pdata = &hier_b_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE:
+		property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE;
+		hyb_hierp.layers = ctrl->val;
+		pdata = &hyb_hierp;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE:
+		property_id = HAL_PARAM_VENC_MBI_STATISTICS_MODE;
+		mbi_statistics_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE,
+			ctrl->val);
+		pdata = &mbi_statistics_mode;
+		break;
+	case V4L2_CID_VIDC_QBUF_MODE:
+		property_id = HAL_PARAM_SYNC_BASED_INTERRUPT;
+		enable.enable = ctrl->val == V4L2_VIDC_QBUF_BATCHED;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS:
+		property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+		max_hierp_layers = ctrl->val;
+		if (max_hierp_layers > inst->capability.hier_p.max) {
+			dprintk(VIDC_ERR,
+				"Error max HP layers(%d)>max supported(%d)\n",
+				max_hierp_layers, inst->capability.hier_p.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &max_hierp_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID:
+		property_id = HAL_CONFIG_VENC_BASELAYER_PRIORITYID;
+		baselayerid = ctrl->val;
+		pdata = &baselayerid;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP:
+		/* Sanity check for the QP boundaries as we are using
+		 * same control to set dynamic QP for all the codecs
+		 */
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid QP Config QP Range\n");
+			break;
+		}
+		property_id = HAL_CONFIG_VENC_FRAME_QP;
+		frameqp = ctrl->val;
+		pdata = &frameqp;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial I QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial B QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial P QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI:
+		property_id = HAL_PARAM_VENC_VQZIP_SEI;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY:
+		property_id = HAL_CONFIG_REALTIME;
+		/* firmware has inverted values for realtime and
+		 * non-realtime priority
+		 */
+		enable.enable = !(ctrl->val);
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
+	{
+		property_id = HAL_PARAM_VENC_BITRATE_TYPE;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT:
+	{
+		property_id = HAL_PARAM_VENC_H264_PIC_ORDER_CNT;
+		pic_order_cnt = ctrl->val;
+		pdata = &pic_order_cnt;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE:
+	{
+		signal_info.color_space = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE:
+	{
+		signal_info.full_range = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS:
+	{
+		signal_info.transfer_chars = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS:
+	{
+		signal_info.matrix_coeffs = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC:
+		if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) {
+			rc = msm_venc_set_csc(inst);
+			if (rc)
+				dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
+		}
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
+	{
+		property_id = HAL_PARAM_VENC_LOW_LATENCY;
+		if (ctrl->val ==
+			V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE)
+			enable.enable = 1;
+		else
+			enable.enable = 0;
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
+		property_id = HAL_PARAM_VENC_H264_TRANSFORM_8x8;
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE:
+			enable.enable = 1;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE:
+			enable.enable = 0;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Invalid H264 8x8 transform control value %d\n",
+				ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE:
+		property_id = HAL_PARAM_VENC_IFRAMESIZE_TYPE;
+		iframesize_type = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE,
+				ctrl->val);
+		pdata = &iframesize_type;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id);
+		rc = -ENOTSUPP;
+		break;
+	}
+
+	v4l2_ctrl_lock(ctrl);
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
+				property_id,
+				ctrl->val);
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+	}
+
+	return rc;
+}
+#undef TRY_GET_CTRL
+
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0, i;
+	struct v4l2_ext_control *control;
+	struct hfi_device *hdev;
+	struct hal_ltr_mode ltr_mode;
+	struct hal_vc1e_perf_cfg_type search_range = { {0} };
+	u32 property_id = 0;
+	void *pdata = NULL;
+	struct msm_vidc_capability *cap = NULL;
+	struct hal_initial_quantization quant;
+	struct hal_aspect_ratio sar;
+	struct hal_bitrate bitrate;
+	struct hal_frame_size blur_res;
+	struct v4l2_control temp_ctrl;
+
+	if (!inst || !inst->core || !inst->core->device || !ctrl) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	cap = &inst->capability;
+
+	control = ctrl->controls;
+	for (i = 0; i < ctrl->count; i++) {
+		switch (control[i].id) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
+			if (control[i].value !=
+				V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE) {
+				rc = msm_venc_toggle_hier_p(inst, false);
+				if (rc)
+					break;
+			}
+			ltr_mode.mode = control[i].value;
+			ltr_mode.trust_mode = 1;
+			property_id = HAL_PARAM_VENC_LTRMODE;
+			pdata = &ltr_mode;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
+			ltr_mode.count =  control[i].value;
+			if (ltr_mode.count > cap->ltr_count.max) {
+				dprintk(VIDC_ERR,
+					"Invalid LTR count %d. Supported max: %d\n",
+					ltr_mode.count,
+					cap->ltr_count.max);
+				/*
+				 * FIXME: Return an error (-EINVALID)
+				 * here once VP8 supports LTR count
+				 * capability
+				 */
+				ltr_mode.count = 1;
+			}
+			ltr_mode.trust_mode = 1;
+			property_id = HAL_PARAM_VENC_LTRMODE;
+			pdata = &ltr_mode;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP:
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			quant.init_qp_enable = control[i].value;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
+			quant.qpi = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
+			quant.qpp = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
+			quant.qpb = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP:
+			/* Sanity check for the QP boundaries as we are using
+			 * same control to set Initial QP for all the codecs
+			 */
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial I Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpi = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial P Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpp = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial B Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpb = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE:
+			search_range.i_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE:
+			search_range.i_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE:
+			search_range.p_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE:
+			search_range.p_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE:
+			search_range.b_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE:
+			search_range.b_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
+			sar.aspect_width = control[i].value;
+			property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+			pdata = &sar;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT:
+			sar.aspect_height = control[i].value;
+			property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+			pdata = &sar;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE:
+		{
+			if (control[i].value) {
+				bitrate.layer_id = i;
+				bitrate.bit_rate = control[i].value;
+				property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+				pdata = &bitrate;
+				dprintk(VIDC_DBG, "bitrate for layer(%d)=%d\n",
+					i, bitrate.bit_rate);
+				rc = call_hfi_op(hdev, session_set_property,
+					(void *)inst->session, property_id,
+					 pdata);
+				if (rc) {
+					dprintk(VIDC_DBG, "prop %x failed\n",
+						property_id);
+					return rc;
+				}
+				if (i == MAX_HYBRID_HIER_P_LAYERS - 1) {
+					dprintk(VIDC_DBG, "HAL property=%x\n",
+						property_id);
+					property_id = 0;
+					rc = 0;
+				}
+			}
+			break;
+		}
+		case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH:
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			blur_res.width = control[i].value;
+			blur_res.buffer_type = HAL_BUFFER_INPUT;
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			pdata = &blur_res;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT:
+			blur_res.height = control[i].value;
+			blur_res.buffer_type = HAL_BUFFER_INPUT;
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			pdata = &blur_res;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid id set: %d\n",
+				control[i].id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if (rc)
+			break;
+	}
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x\n", property_id);
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+	}
+	return rc;
+}
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+	int rc = 0, c = 0;
+
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+					struct msm_vidc_inst, ctrl_handler);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			struct v4l2_ctrl *temp = ctrl->cluster[c];
+
+			rc = try_set_ctrl(inst, temp);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %s (%x)\n",
+						v4l2_ctrl_get_name(temp->id),
+						temp->id);
+				break;
+			}
+		}
+	}
+failed_open_done:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed setting control: %x (%s)",
+				ctrl->id, v4l2_ctrl_get_name(ctrl->id));
+	return rc;
+}
+
+static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_venc_ctrl_ops = {
+
+	.s_ctrl = msm_venc_op_s_ctrl,
+	.g_volatile_ctrl = msm_venc_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_venc_get_ctrl_ops(void)
+{
+	return &msm_venc_ctrl_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
+		return -EINVAL;
+	}
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+	inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+	inst->capability.height.max = DEFAULT_HEIGHT;
+	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+	inst->capability.width.max = DEFAULT_WIDTH;
+	inst->capability.alloc_mode_in = HAL_BUFFER_MODE_STATIC;
+	inst->capability.alloc_mode_out = HAL_BUFFER_MODE_STATIC;
+	inst->capability.secure_output2_threshold.min = 0;
+	inst->capability.secure_output2_threshold.max = 0;
+	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->prop.fps = DEFAULT_FPS;
+	inst->capability.pixelprocess_capabilities = 0;
+	memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
+						sizeof(struct msm_vidc_format));
+	memcpy(&inst->fmts[OUTPUT_PORT], &venc_formats[0],
+						sizeof(struct msm_vidc_format));
+	return rc;
+}
+
+int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0;
+
+	rc = try_set_ext_ctrl(inst, ctrl);
+	if (rc) {
+		dprintk(VIDC_ERR, "Error setting extended control\n");
+		return rc;
+	}
+	return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, cap = %pK\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, f = %pK\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		dprintk(VIDC_DBG, "No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_venc_set_csc(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int count = 0;
+	struct hal_vpe_color_space_conversion vpe_csc;
+
+	while (count < HAL_MAX_MATRIX_COEFFS) {
+		if (count < HAL_MAX_BIAS_COEFFS)
+			vpe_csc.csc_bias[count] =
+				vpe_csc_601_to_709_bias_coeff[count];
+		if (count < HAL_MAX_LIMIT_COEFFS)
+			vpe_csc.csc_limit[count] =
+				vpe_csc_601_to_709_limit_coeff[count];
+		vpe_csc.csc_matrix[count] =
+			vpe_csc_601_to_709_matrix_coeff[count];
+		count = count + 1;
+	}
+	rc = msm_comm_try_set_prop(inst,
+			HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
+	if (rc)
+		dprintk(VIDC_ERR, "Setting VPE coefficients failed\n");
+
+	return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	if (!inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (!fmt || fmt->type != CAPTURE_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		fmt->num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			goto exit;
+		}
+
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct hal_frame_size frame_sz;
+
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
+
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
+		dprintk(VIDC_DBG, "width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+			inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set framesize for Output port\n");
+			goto exit;
+		}
+
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			OUTPUT_PORT);
+		if (!fmt || fmt->type != OUTPUT_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on OUTPUT port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		fmt->num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+
+		msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc);
+	} else {
+		dprintk(VIDC_ERR, "%s - Unsupported buf type: %d\n",
+			__func__, f->type);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	f->fmt.pix_mp.num_planes = fmt->num_planes;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		struct hal_frame_size frame_sz = {0};
+		struct hal_buffer_requirements *bufreq = NULL;
+
+		frame_sz.width = inst->prop.width[CAPTURE_PORT];
+		frame_sz.height = inst->prop.height[CAPTURE_PORT];
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_FRAME_SIZE,
+				&frame_sz);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to set OUTPUT framesize\n");
+			goto exit;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"%s : Getting buffer reqs failed: %d\n",
+					__func__, rc);
+			goto exit;
+		}
+		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct hal_buffer_requirements *bufreq = NULL;
+		int extra_idx = 0;
+
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				inst->fmts[fmt->type].get_frame_size(i,
+				f->fmt.pix_mp.height, f->fmt.pix_mp.width);
+		}
+		extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_INPUT);
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				bufreq ? bufreq->buffer_size : 0;
+		}
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	u32 height, width, num_planes;
+	unsigned int extra_idx = 0;
+	struct hal_buffer_requirements *bufreq = NULL;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_WARN, "Getting buffer requirements failed: %d\n",
+				rc);
+		return rc;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = &inst->fmts[CAPTURE_PORT];
+		height = inst->prop.height[CAPTURE_PORT];
+		width = inst->prop.width[CAPTURE_PORT];
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = &inst->fmts[OUTPUT_PORT];
+		height = inst->prop.height[OUTPUT_PORT];
+		width = inst->prop.width[OUTPUT_PORT];
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+	} else {
+		dprintk(VIDC_ERR, "Invalid type: %x\n", f->type);
+		return -ENOTSUPP;
+	}
+
+	f->fmt.pix_mp.pixelformat = fmt->fourcc;
+	f->fmt.pix_mp.height = height;
+	f->fmt.pix_mp.width = width;
+	f->fmt.pix_mp.num_planes = num_planes;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		for (i = 0; i < num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				fmt->get_frame_size(i, height, width);
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_OUTPUT);
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	}
+	extra_idx = EXTRADATA_IDX(num_planes);
+	if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+		if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+			bufreq = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_OUTPUT);
+		else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			bufreq = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_INPUT);
+
+		f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	}
+
+	for (i = 0; i < num_planes; ++i) {
+		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			inst->bufq[OUTPUT_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+	}
+	return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	if (!inst || !b) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, buffer = %pK\n", inst, b);
+		return -EINVAL;
+	}
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+		"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info = {0};
+	struct hfi_device *hdev;
+	int extra_idx = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring prepare buf\n",
+				inst->core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+				"Planes mismatch: needed: %d, allocated: %d\n",
+				inst->fmts[CAPTURE_PORT].num_planes,
+				b->length);
+			rc = -EINVAL;
+			break;
+		}
+
+		for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); i++) {
+			dprintk(VIDC_DBG, "device_addr = %#lx, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+		}
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr =
+			b->m.planes[0].m.userptr;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+			dprintk(VIDC_DBG, "extradata: %#lx\n",
+					b->m.planes[extra_idx].m.userptr);
+			buffer_info.extradata_size =
+				b->m.planes[extra_idx].length;
+		}
+
+		rc = call_hfi_op(hdev, session_set_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed\n");
+		break;
+	default:
+		dprintk(VIDC_ERR,
+			"Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int i, rc = 0, extra_idx = 0;
+	struct vidc_buffer_addr_info buffer_info = {0};
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to release res done state\n",
+			inst);
+		goto exit;
+	}
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+		if (b->length !=
+			inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+					"Planes mismatch: needed: %d, to release: %d\n",
+					inst->fmts[CAPTURE_PORT].num_planes,
+					b->length);
+			rc = -EINVAL;
+			break;
+		}
+		for (i = 0; i < b->length; i++) {
+			dprintk(VIDC_DBG,
+				"Release device_addr = %#lx, size = %d, %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length, inst->state);
+		}
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr =
+			b->m.planes[0].m.userptr;
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+			buffer_info.extradata_addr =
+			b->m.planes[extra_idx].m.userptr;
+		buffer_info.response_required = false;
+		rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+					"vidc_hal_session_release_buffers failed\n");
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamon\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
+{
+	return msm_comm_ctrl_init(inst, msm_venc_ctrls,
+			ARRAY_SIZE(msm_venc_ctrls), &msm_venc_ctrl_ops);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.h b/drivers/media/platform/msm/vidc_3x/msm_venc.h
new file mode 100644
index 0000000..e357304
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.h
@@ -0,0 +1,37 @@
+/*Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
new file mode 100644
index 0000000..983e600c
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
@@ -0,0 +1,1438 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include <linux/delay.h>
+#include "vidc_hfi_api.h"
+#include "msm_vidc_dcvs.h"
+
+#define MAX_EVENTS 30
+
+static int get_poll_flags(void *instance)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+	struct vb2_buffer *out_vb = NULL;
+	struct vb2_buffer *cap_vb = NULL;
+	unsigned long flags;
+	int rc = 0;
+
+	if (v4l2_event_pending(&inst->event_handler))
+		rc |= POLLPRI;
+
+	spin_lock_irqsave(&capq->done_lock, flags);
+	if (!list_empty(&capq->done_list))
+		cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+								done_entry);
+	if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+				|| cap_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLIN | POLLRDNORM;
+	spin_unlock_irqrestore(&capq->done_lock, flags);
+
+	spin_lock_irqsave(&outq->done_lock, flags);
+	if (!list_empty(&outq->done_list))
+		out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+								done_entry);
+	if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+				|| out_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLOUT | POLLWRNORM;
+	spin_unlock_irqrestore(&outq->done_lock, flags);
+
+	return rc;
+}
+
+int msm_vidc_poll(void *instance, struct file *filp,
+		struct poll_table_struct *wait)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = NULL;
+	struct vb2_queue *capq = NULL;
+
+	if (!inst)
+		return -EINVAL;
+
+	outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+
+	poll_wait(filp, &inst->event_handler.wait, wait);
+	poll_wait(filp, &capq->done_wq, wait);
+	poll_wait(filp, &outq->done_wq, wait);
+	return get_poll_flags(inst);
+}
+EXPORT_SYMBOL(msm_vidc_poll);
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+	int rc = -EINVAL;
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !cap)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		rc = msm_vdec_querycap(instance, cap);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		rc = msm_venc_querycap(instance, cap);
+	else
+		goto exit;
+	if (!rc) {
+		cap->device_caps = cap->capabilities;
+		cap->capabilities |= V4L2_CAP_DEVICE_CAPS;
+	}
+exit:
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_querycap);
+
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_enum_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_enum_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_enum_fmt);
+
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_fmt(instance, f);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_fmt);
+
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_g_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_g_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_g_fmt);
+
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	return msm_comm_s_ctrl(instance, control);
+}
+EXPORT_SYMBOL(msm_vidc_s_ctrl);
+
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	return msm_comm_g_ctrl(instance, control);
+}
+EXPORT_SYMBOL(msm_vidc_g_ctrl);
+
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_ext_ctrl(instance, control);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_ext_ctrl(instance, control);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_ext_ctrl);
+
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_reqbufs(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_reqbufs(instance, b);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_reqbufs);
+
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b, int idx, int *plane)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	int i;
+	int fd = b->m.planes[idx].reserved[0];
+	u32 buff_off = b->m.planes[idx].reserved[1];
+	u32 size = b->m.planes[idx].length;
+	ion_phys_addr_t device_addr = b->m.planes[idx].m.userptr;
+
+	if (fd < 0 || !plane) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+
+	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
+		"Registered buf lock is not acquired for %s", __func__);
+
+	*plane = 0;
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			bool ion_hndl_matches = temp->handle[i] ?
+				msm_smem_compare_buffers(inst->mem_client, fd,
+				temp->handle[i]->smem_priv) : false;
+			bool device_addr_matches = device_addr ==
+						temp->device_addr[i];
+			bool contains_within = CONTAINS(temp->buff_off[i],
+					temp->size[i], buff_off) ||
+				CONTAINS(buff_off, size, temp->buff_off[i]);
+			bool overlaps = OVERLAPS(buff_off, size,
+					temp->buff_off[i], temp->size[i]);
+
+			if (!temp->inactive &&
+				(ion_hndl_matches || device_addr_matches) &&
+				(contains_within || overlaps)) {
+				dprintk(VIDC_DBG,
+						"This memory region is already mapped\n");
+				ret = temp;
+				*plane = i;
+				break;
+			}
+		}
+		if (ret)
+			break;
+	}
+
+err_invalid_input:
+	return ret;
+}
+
+static struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst, int fd)
+{
+	struct buffer_info *temp;
+	struct msm_smem *same_fd_handle = NULL;
+
+	int i;
+
+	if (!fd)
+		return NULL;
+
+	if (!inst || fd < 0) {
+		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
+		goto err_invalid_input;
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			bool ion_hndl_matches = temp->handle[i] ?
+				msm_smem_compare_buffers(inst->mem_client, fd,
+				temp->handle[i]->smem_priv) : false;
+			if (ion_hndl_matches && temp->mapped[i])  {
+				temp->same_fd_ref[i]++;
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				same_fd_handle = temp->handle[i];
+				break;
+			}
+		}
+		if (same_fd_handle)
+			break;
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+err_invalid_input:
+	return same_fd_handle;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+				ion_phys_addr_t device_addr)
+{
+	struct buffer_info *temp = NULL;
+	bool found = false;
+	int i;
+
+	if (!buf_list || !device_addr) {
+		dprintk(VIDC_ERR,
+			"Invalid input- device_addr: %pa buf_list: %pK\n",
+			&device_addr, buf_list);
+		goto err_invalid_input;
+	}
+
+	mutex_lock(&buf_list->lock);
+	list_for_each_entry(temp, &buf_list->list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			if (!temp->inactive &&
+				temp->device_addr[i] == device_addr)  {
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				found = true;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+	mutex_unlock(&buf_list->lock);
+
+err_invalid_input:
+	return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+			struct v4l2_buffer *b, u32 i)
+{
+	if (i >= VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
+		return;
+	}
+	binfo->type = b->type;
+	binfo->fd[i] = b->m.planes[i].reserved[0];
+	binfo->buff_off[i] = b->m.planes[i].reserved[1];
+	binfo->size[i] = b->m.planes[i].length;
+	binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+	binfo->num_planes = b->length;
+	binfo->memory = b->memory;
+	binfo->v4l2_index = b->index;
+	binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+	binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+	dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+			__func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+					struct buffer_info *binfo)
+{
+	int i = 0;
+
+	b->type = binfo->type;
+	b->length = binfo->num_planes;
+	b->memory = binfo->memory;
+	b->index = binfo->v4l2_index;
+	b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+	b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+	binfo->dequeued = false;
+	for (i = 0; i < binfo->num_planes; ++i) {
+		b->m.planes[i].reserved[0] = binfo->fd[i];
+		b->m.planes[i].reserved[1] = binfo->buff_off[i];
+		b->m.planes[i].length = binfo->size[i];
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "%s %d %d %d %pa\n", __func__, binfo->fd[i],
+				binfo->buff_off[i], binfo->size[i],
+				&binfo->device_addr[i]);
+	}
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+		struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+	struct msm_smem *handle = NULL;
+
+	handle = msm_comm_smem_user_to_kernel(inst,
+				p->reserved[0],
+				p->reserved[1],
+				buffer_type);
+	if (!handle) {
+		dprintk(VIDC_ERR,
+			"%s: Failed to get device buffer address\n", __func__);
+		return NULL;
+	}
+	return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+		struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return HAL_BUFFER_INPUT;
+	else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return HAL_BUFFER_OUTPUT;
+	else
+		return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+				struct msm_vidc_inst *inst)
+{
+	return b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+		inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC;
+}
+
+
+static inline bool is_encoder_input_buffer(struct v4l2_buffer *b,
+				struct msm_vidc_inst *inst)
+{
+	return b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+			inst->session_type == MSM_VIDC_ENCODER;
+}
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+						struct buffer_info *binfo)
+{
+	int i = 0;
+
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
+		populate_buf_info(binfo, b, i);
+	}
+}
+
+int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buffer_info *binfo = NULL;
+	struct buffer_info *temp = NULL, *iterator = NULL;
+	int plane = 0;
+	int i = 0, rc = 0;
+	struct msm_smem *same_fd_handle = NULL;
+
+	if (!b || !inst) {
+		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		dprintk(VIDC_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+			b->length, VIDEO_MAX_PLANES);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	dprintk(VIDC_DBG, "[MAP] Create binfo = %pK fd = %d type = %d\n",
+			binfo, b->m.planes[0].reserved[0], b->type);
+
+	for (i = 0; i < b->length; ++i) {
+		rc = 0;
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
+		mutex_lock(&inst->registeredbufs.lock);
+		temp = get_registered_buf(inst, b, i, &plane);
+		if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
+			dprintk(VIDC_DBG,
+				"This memory region has already been prepared\n");
+			rc = 0;
+			mutex_unlock(&inst->registeredbufs.lock);
+			goto exit;
+		}
+
+		if (temp && is_dynamic_output_buffer_mode(b, inst) && !i) {
+			/*
+			 * Buffer is already present in registered list
+			 * increment ref_count, populate new values of v4l2
+			 * buffer in existing buffer_info struct.
+			 *
+			 * We will use the saved buffer info and queue it when
+			 * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+			 */
+			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+			temp->inactive = false;
+			list_for_each_entry(iterator,
+				&inst->registeredbufs.list, list) {
+				if (iterator == temp) {
+					rc = buf_ref_get(inst, temp);
+					save_v4l2_buffer(b, temp);
+					break;
+				}
+			}
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+		/*
+		 * rc == 1,
+		 * buffer is mapped, fw has released all reference, so skip
+		 * mapping and queue it immediately.
+		 *
+		 * rc == 2,
+		 * buffer is mapped and fw is holding a reference, hold it in
+		 * the driver and queue it later when fw has released
+		 */
+		if (rc == 1) {
+			rc = 0;
+			goto exit;
+		} else if (rc == 2) {
+			rc = -EEXIST;
+			goto exit;
+		}
+
+		same_fd_handle = get_same_fd_buffer(
+				inst, b->m.planes[i].reserved[0]);
+
+		populate_buf_info(binfo, b, i);
+		if (same_fd_handle) {
+			binfo->device_addr[i] =
+			same_fd_handle->device_addr + binfo->buff_off[i];
+			b->m.planes[i].m.userptr = binfo->device_addr[i];
+			binfo->mapped[i] = false;
+			binfo->handle[i] = same_fd_handle;
+		} else {
+			binfo->handle[i] = map_buffer(inst, &b->m.planes[i],
+					get_hal_buffer_type(inst, b));
+			if (!binfo->handle[i]) {
+				rc = -EINVAL;
+				goto exit;
+			}
+
+			binfo->mapped[i] = true;
+			binfo->device_addr[i] = binfo->handle[i]->device_addr +
+				binfo->buff_off[i];
+			b->m.planes[i].m.userptr = binfo->device_addr[i];
+		}
+
+		/* We maintain one ref count for all planes*/
+		if (!i && is_dynamic_output_buffer_mode(b, inst)) {
+			rc = buf_ref_get(inst, binfo);
+			if (rc < 0)
+				goto exit;
+		}
+		dprintk(VIDC_DBG,
+			"%s: [MAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+			__func__, binfo, i, binfo->handle[i],
+			&binfo->device_addr[i], binfo->fd[i],
+			binfo->buff_off[i], binfo->mapped[i]);
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_add_tail(&binfo->list, &inst->registeredbufs.list);
+	mutex_unlock(&inst->registeredbufs.lock);
+	return 0;
+
+exit:
+	kfree(binfo);
+	return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	int i = 0;
+	struct buffer_info *temp = NULL;
+	bool found = false, keep_node = false;
+
+	if (!inst || !binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %pK %pK\n",
+			__func__, inst, binfo);
+		return -EINVAL;
+	}
+
+	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
+		"Registered buf lock is not acquired for %s", __func__);
+
+	/*
+	 * Make sure the buffer to be unmapped and deleted
+	 * from the registered list is present in the list.
+	 */
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		if (temp == binfo) {
+			found = true;
+			break;
+		}
+	}
+
+	/*
+	 * Free the buffer info only if
+	 * - buffer info has not been deleted from registered list
+	 * - vidc client has called dqbuf on the buffer
+	 * - no references are held on the buffer
+	 */
+	if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+		goto exit;
+
+	for (i = 0; i < temp->num_planes; i++) {
+		dprintk(VIDC_DBG,
+			"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+			__func__, temp, i, temp->handle[i],
+			&temp->device_addr[i], temp->fd[i],
+			temp->buff_off[i], temp->mapped[i]);
+		/*
+		 * Unmap the handle only if the buffer has been mapped and no
+		 * other buffer has a reference to this buffer.
+		 * In case of buffers with same fd, we will map the buffer only
+		 * once and subsequent buffers will refer to the mapped buffer's
+		 * device address.
+		 * For buffers which share the same fd, do not unmap and keep
+		 * the buffer info in registered list.
+		 */
+		if (temp->handle[i] && temp->mapped[i] &&
+			!temp->same_fd_ref[i]) {
+			msm_comm_smem_free(inst,
+				temp->handle[i]);
+		}
+
+		if (temp->same_fd_ref[i])
+			keep_node = true;
+		else {
+			temp->fd[i] = 0;
+			temp->handle[i] = 0;
+			temp->device_addr[i] = 0;
+			temp->uvaddr[i] = 0;
+		}
+	}
+	if (!keep_node) {
+		dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %pK\n", temp);
+		list_del(&temp->list);
+		kfree(temp);
+	} else {
+		temp->inactive = true;
+		dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %pK\n", temp);
+	}
+exit:
+	return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	struct v4l2_buffer b = {0};
+	struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %pK\n", __func__, binfo);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+	b.m.planes = plane;
+	repopulate_v4l2_buffer(&b, binfo);
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(inst, &b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(inst, &b);
+
+	return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo)
+{
+	int i = 0;
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return -EINVAL;
+	}
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s: invalid buffer info: %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
+	if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return 0;
+
+
+	for (i = 0; i < binfo->num_planes; i++) {
+		if (binfo->handle[i]) {
+			rc = msm_comm_smem_cache_operations(inst,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s: Failed to clean caches: %d\n",
+					__func__, rc);
+				return -EINVAL;
+			}
+		} else
+			dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
+					__func__, i);
+	}
+	return 0;
+}
+
+static bool valid_v4l2_buffer(struct v4l2_buffer *b,
+		struct msm_vidc_inst *inst) {
+	enum vidc_ports port =
+		!V4L2_TYPE_IS_MULTIPLANAR(b->type) ? MAX_PORT_NUM :
+		b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT :
+		b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? OUTPUT_PORT :
+								MAX_PORT_NUM;
+
+	return port != MAX_PORT_NUM &&
+		inst->fmts[port].num_planes == b->length;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		inst->core->state == VIDC_CORE_INVALID)
+		return -EINVAL;
+
+	if (is_dynamic_output_buffer_mode(b, inst))
+		return 0;
+
+	if (map_and_register_buf(inst, b))
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_prepare_buf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_prepare_buf(instance, b);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_prepare_buf);
+
+int msm_vidc_release_buffers(void *instance, int buffer_type)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *bi, *dummy;
+	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane[VIDEO_MAX_PLANES];
+	int i, rc = 0;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (!inst->in_reconfig &&
+		inst->state > MSM_VIDC_LOAD_RESOURCES &&
+		inst->state < MSM_VIDC_RELEASE_RESOURCES_DONE) {
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to move inst: %pK to release res done\n",
+					inst);
+		}
+	}
+
+	/*
+	 * In dynamic buffer mode, driver needs to release resources,
+	 * but not call release buffers on firmware, as the buffers
+	 * were never registered with firmware.
+	 */
+	if (buffer_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+		inst->buffer_mode_set[CAPTURE_PORT] ==
+				HAL_BUFFER_MODE_DYNAMIC) {
+		goto free_and_unmap;
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(bi, &inst->registeredbufs.list, list) {
+		bool release_buf = false;
+
+		if (bi->type == buffer_type) {
+			buffer_info.type = bi->type;
+			for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+						i++) {
+				plane[i].reserved[0] = bi->fd[i];
+				plane[i].reserved[1] = bi->buff_off[i];
+				plane[i].length = bi->size[i];
+				plane[i].m.userptr = bi->device_addr[i];
+				buffer_info.m.planes = plane;
+				dprintk(VIDC_DBG,
+					"Releasing buffer: %d, %d, %d\n",
+					buffer_info.m.planes[i].reserved[0],
+					buffer_info.m.planes[i].reserved[1],
+					buffer_info.m.planes[i].length);
+			}
+			buffer_info.length = bi->num_planes;
+			release_buf = true;
+		}
+
+		if (!release_buf)
+			continue;
+		if (inst->session_type == MSM_VIDC_DECODER)
+			rc = msm_vdec_release_buf(instance,
+				&buffer_info);
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			rc = msm_venc_release_buf(instance,
+				&buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+				"Failed Release buffer: %d, %d, %d\n",
+				buffer_info.m.planes[0].reserved[0],
+				buffer_info.m.planes[0].reserved[1],
+				buffer_info.m.planes[0].length);
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+free_and_unmap:
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+		if (bi->type == buffer_type) {
+			list_del(&bi->list);
+			for (i = 0; i < bi->num_planes; i++) {
+				if (bi->handle[i] && bi->mapped[i]) {
+					dprintk(VIDC_DBG,
+						"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+						__func__, bi, i, bi->handle[i],
+						&bi->device_addr[i], bi->fd[i],
+						bi->buff_off[i], bi->mapped[i]);
+					msm_comm_smem_free(inst,
+							bi->handle[i]);
+				}
+			}
+			kfree(bi);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_release_buffers);
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *binfo;
+	int plane = 0;
+	int rc = 0;
+	int i;
+
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		inst->core->state == VIDC_CORE_INVALID)
+		return -EINVAL;
+
+	rc = map_and_register_buf(inst, b);
+	if (rc == -EEXIST) {
+		if (atomic_read(&inst->in_flush) &&
+			is_dynamic_output_buffer_mode(b, inst)) {
+			dprintk(VIDC_ERR,
+				"Flush in progress, do not hold any buffers in driver\n");
+			msm_comm_flush_dynamic_buffers(inst);
+		}
+		return 0;
+	}
+	if (rc)
+		return rc;
+
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			b->m.planes[i].m.userptr = 0;
+			continue;
+		}
+		mutex_lock(&inst->registeredbufs.lock);
+		binfo = get_registered_buf(inst, b, i, &plane);
+		mutex_unlock(&inst->registeredbufs.lock);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"This buffer is not registered: %d, %d, %d\n",
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+			goto err_invalid_buff;
+		}
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "Queueing device address = %pa\n",
+				&binfo->device_addr[i]);
+
+		if (inst->fmts[OUTPUT_PORT].fourcc ==
+			V4L2_PIX_FMT_HEVC_HYBRID && binfo->handle[i] &&
+			b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			rc = msm_comm_smem_cache_operations(inst,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to inv caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+
+		if (binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			rc = msm_comm_smem_cache_operations(inst,
+					binfo->handle[i], SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+	}
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_qbuf);
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *buffer_info = NULL;
+	int i = 0, rc = 0;
+
+	if (!inst || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		rc = msm_vdec_dqbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		rc = msm_venc_dqbuf(instance, b);
+
+	if (rc)
+		return rc;
+
+	for (i = b->length - 1; i >= 0 ; i--) {
+		if (EXTRADATA_IDX(b->length) &&
+			i == EXTRADATA_IDX(b->length)) {
+			continue;
+		}
+		buffer_info = device_to_uvaddr(&inst->registeredbufs,
+			b->m.planes[i].m.userptr);
+
+		if (!buffer_info) {
+			dprintk(VIDC_ERR,
+				"%s no buffer info registered for buffer addr: %#lx\n",
+				__func__, b->m.planes[i].m.userptr);
+			return -EINVAL;
+		}
+
+		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+		b->m.planes[i].reserved[0] = buffer_info->fd[i];
+		b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
+
+		b->m.planes[i].reserved[2] = buffer_info->crop_data.nLeft;
+		b->m.planes[i].reserved[3] = buffer_info->crop_data.nTop;
+		b->m.planes[i].reserved[4] = buffer_info->crop_data.nWidth;
+		b->m.planes[i].reserved[5] = buffer_info->crop_data.nHeight;
+		b->m.planes[i].reserved[6] =
+				buffer_info->crop_data.width_height[0];
+		b->m.planes[i].reserved[7] =
+				buffer_info->crop_data.width_height[1];
+		if (!(inst->flags & VIDC_SECURE) && !b->m.planes[i].m.userptr) {
+			dprintk(VIDC_ERR,
+			"%s: Failed to find user virtual address, %#lx, %d, %d\n",
+			__func__, b->m.planes[i].m.userptr, b->type, i);
+			return -EINVAL;
+		}
+	}
+
+	if (!buffer_info) {
+		dprintk(VIDC_ERR,
+			"%s: error - no buffer info found in registered list\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = output_buffer_cache_invalidate(inst, buffer_info);
+	if (rc)
+		return rc;
+
+	if (is_dynamic_output_buffer_mode(b, inst)) {
+		buffer_info->dequeued = true;
+
+		dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+			buffer_info->fd[0]);
+		mutex_lock(&inst->registeredbufs.lock);
+		rc = unmap_and_deregister_buf(inst, buffer_info);
+		mutex_unlock(&inst->registeredbufs.lock);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqbuf);
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamon(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamon(instance, i);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamon);
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamoff(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamoff(instance, i);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamoff);
+
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct msm_vidc_capability *capability = NULL;
+
+	if (!inst || !fsize) {
+		dprintk(VIDC_ERR, "%s: invalid parameter: %pK %pK\n",
+				__func__, inst, fsize);
+		return -EINVAL;
+	}
+	if (!inst->core)
+		return -EINVAL;
+
+	capability = &inst->capability;
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = capability->width.min;
+	fsize->stepwise.max_width = capability->width.max;
+	fsize->stepwise.step_width = capability->width.step_size;
+	fsize->stepwise.min_height = capability->height.min;
+	fsize->stepwise.max_height = capability->height.max;
+	fsize->stepwise.step_height = capability->height.step_size;
+	return 0;
+}
+EXPORT_SYMBOL(msm_vidc_enum_framesizes);
+
+static void *vidc_get_userptr(struct device *dev, unsigned long vaddr,
+			unsigned long size, enum dma_data_direction dma_dir)
+{
+	return (void *)0xdeadbeef;
+}
+
+static void vidc_put_userptr(void *buf_priv)
+{
+
+}
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+	.get_userptr = vidc_get_userptr,
+	.put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+		enum v4l2_buf_type type, enum session_type sess)
+{
+	struct vb2_queue *q = NULL;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		q = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	} else {
+		dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
+		return -EINVAL;
+	}
+
+	q->type = type;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	if (sess == MSM_VIDC_DECODER)
+		q->ops = msm_vdec_get_vb2q_ops();
+	else if (sess == MSM_VIDC_ENCODER)
+		q->ops = msm_venc_get_vb2q_ops();
+	q->mem_ops = &msm_vidc_vb2_mem_ops;
+	q->drv_priv = inst;
+	q->allow_zero_bytesused = 1;
+	return vb2_queue_init(q);
+}
+
+static int setup_event_queue(void *inst,
+				struct video_device *pvdev)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+	v4l2_fh_add(&vidc_inst->event_handler);
+
+	return rc;
+}
+
+int msm_vidc_subscribe_event(void *inst,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_subscribe(&vidc_inst->event_handler,
+		sub, MAX_EVENTS, NULL);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_subscribe_event);
+
+int msm_vidc_unsubscribe_event(void *inst,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_unsubscribe_event);
+
+int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !event)
+		return -EINVAL;
+
+	rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqevent);
+
+static bool msm_vidc_check_for_inst_overload(struct msm_vidc_core *core)
+{
+	u32 instance_count = 0;
+	u32 secure_instance_count = 0;
+	struct msm_vidc_inst *inst = NULL;
+	bool overload = false;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		instance_count++;
+		/* This flag is not updated yet for the current instance */
+		if (inst->flags & VIDC_SECURE)
+			secure_instance_count++;
+	}
+	mutex_unlock(&core->lock);
+
+	/* Instance count includes current instance as well. */
+
+	if ((instance_count > core->resources.max_inst_count) ||
+		(secure_instance_count > core->resources.max_secure_inst_count))
+		overload = true;
+	return overload;
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_core *core = NULL;
+	int rc = 0;
+	int i = 0;
+
+	if (core_id >= MSM_VIDC_CORES_MAX ||
+			session_type >= MSM_VIDC_MAX_DEVICES) {
+		dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n",
+			core_id, session_type);
+		goto err_invalid_core;
+	}
+	core = get_vidc_core(core_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"Failed to find core for core_id = %d\n", core_id);
+		goto err_invalid_core;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		dprintk(VIDC_ERR, "Failed to allocate memory\n");
+		rc = -ENOMEM;
+		goto err_invalid_core;
+	}
+
+	pr_info(VIDC_DBG_TAG "Opening video instance: %pK, %d\n",
+		VIDC_MSG_PRIO2STRING(VIDC_INFO), inst, session_type);
+	mutex_init(&inst->sync_lock);
+	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
+	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
+	mutex_init(&inst->lock);
+
+	INIT_MSM_VIDC_LIST(&inst->pendingq);
+	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
+	INIT_MSM_VIDC_LIST(&inst->persistbufs);
+	INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
+	INIT_MSM_VIDC_LIST(&inst->outputbufs);
+	INIT_MSM_VIDC_LIST(&inst->registeredbufs);
+
+	kref_init(&inst->kref);
+
+	inst->session_type = session_type;
+	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+	inst->core = core;
+	inst->bit_depth = MSM_VIDC_BIT_DEPTH_8;
+	inst->instant_bitrate = 0;
+	inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE;
+	inst->colour_space = MSM_VIDC_BT601_6_525;
+
+	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+		init_completion(&inst->completions[i]);
+	}
+	inst->mem_client = msm_smem_new_client(SMEM_ION,
+					&inst->core->resources, session_type);
+	if (!inst->mem_client) {
+		dprintk(VIDC_ERR, "Failed to create memory client\n");
+		goto fail_mem_client;
+	}
+	if (session_type == MSM_VIDC_DECODER) {
+		msm_vdec_inst_init(inst);
+		rc = msm_vdec_ctrl_init(inst);
+	} else if (session_type == MSM_VIDC_ENCODER) {
+		msm_venc_inst_init(inst);
+		rc = msm_venc_ctrl_init(inst);
+	}
+
+	if (rc)
+		goto fail_bufq_capture;
+
+	msm_dcvs_init(inst);
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+			session_type);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
+		goto fail_bufq_capture;
+	}
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+			session_type);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
+		goto fail_bufq_output;
+	}
+
+	setup_event_queue(inst, &core->vdev[session_type].vdev);
+
+	mutex_lock(&core->lock);
+	list_add_tail(&inst->list, &core->instances);
+	mutex_unlock(&core->lock);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to init state\n");
+		goto fail_init;
+	}
+
+	if (msm_vidc_check_for_inst_overload(core)) {
+		dprintk(VIDC_ERR,
+			"Instance count reached Max limit, rejecting session");
+		goto fail_init;
+	}
+
+	inst->debugfs_root =
+		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
+
+	return inst;
+fail_init:
+	v4l2_fh_del(&inst->event_handler);
+	v4l2_fh_exit(&inst->event_handler);
+	vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+
+	mutex_lock(&core->lock);
+	list_del(&inst->list);
+	mutex_unlock(&core->lock);
+
+fail_bufq_output:
+	vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+	msm_comm_ctrl_deinit(inst);
+	msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+	kfree(inst);
+	inst = NULL;
+err_invalid_core:
+	return inst;
+}
+EXPORT_SYMBOL(msm_vidc_open);
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+	struct vb2_buf_entry *entry, *dummy;
+
+	if (inst) {
+
+		mutex_lock(&inst->pendingq.lock);
+		list_for_each_entry_safe(entry, dummy, &inst->pendingq.list,
+				list) {
+			list_del(&entry->list);
+			kfree(entry);
+		}
+		mutex_unlock(&inst->pendingq.lock);
+
+		if (msm_comm_release_scratch_buffers(inst, false)) {
+			dprintk(VIDC_ERR,
+				"Failed to release scratch buffers\n");
+		}
+
+		if (msm_comm_release_persist_buffers(inst)) {
+			dprintk(VIDC_ERR,
+				"Failed to release persist buffers\n");
+		}
+
+		if (msm_comm_release_output_buffers(inst)) {
+			dprintk(VIDC_ERR,
+				"Failed to release output buffers\n");
+		}
+
+		if (inst->extradata_handle)
+			msm_comm_smem_free(inst, inst->extradata_handle);
+
+		mutex_lock(&inst->pending_getpropq.lock);
+		if (!list_empty(&inst->pending_getpropq.list)) {
+			dprintk(VIDC_ERR,
+				"pending_getpropq not empty\n");
+			WARN_ON(VIDC_DBG_WARN_ENABLE);
+		}
+		mutex_unlock(&inst->pending_getpropq.lock);
+	}
+}
+
+int msm_vidc_destroy(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	int i = 0;
+
+	if (!inst || !inst->core)
+		return -EINVAL;
+
+	core = inst->core;
+
+	mutex_lock(&core->lock);
+	/* inst->list lives in core->instances */
+	list_del(&inst->list);
+	mutex_unlock(&core->lock);
+
+	msm_comm_ctrl_deinit(inst);
+
+	v4l2_fh_del(&inst->event_handler);
+	v4l2_fh_exit(&inst->event_handler);
+
+	for (i = 0; i < MAX_PORT_NUM; i++)
+		vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
+	mutex_destroy(&inst->sync_lock);
+	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
+	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
+	mutex_destroy(&inst->lock);
+
+	msm_vidc_debugfs_deinit_inst(inst);
+	pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n",
+			VIDC_MSG_PRIO2STRING(VIDC_INFO), inst);
+	kfree(inst);
+	return 0;
+}
+
+int msm_vidc_close(void *instance)
+{
+	void close_helper(struct kref *kref)
+	{
+		struct msm_vidc_inst *inst = container_of(kref,
+				struct msm_vidc_inst, kref);
+
+		msm_vidc_destroy(inst);
+	}
+
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *bi, *dummy;
+	int rc = 0;
+
+	if (!inst || !inst->core)
+		return -EINVAL;
+
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			int i = 0;
+
+			list_del(&bi->list);
+
+			for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+					i++) {
+				if (bi->handle[i] && bi->mapped[i])
+					msm_comm_smem_free(inst, bi->handle[i]);
+			}
+
+			kfree(bi);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+	cleanup_instance(inst);
+	if (inst->state != MSM_VIDC_CORE_INVALID &&
+		inst->core->state != VIDC_CORE_INVALID)
+		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+	else
+		rc = msm_comm_force_cleanup(inst);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to uninit state\n");
+
+	msm_comm_session_clean(inst);
+	msm_smem_delete_client(inst->mem_client);
+
+	kref_put(&inst->kref, close_helper);
+	return 0;
+}
+EXPORT_SYMBOL(msm_vidc_close);
+
+int msm_vidc_suspend(int core_id)
+{
+	return msm_comm_suspend(core_id);
+}
+EXPORT_SYMBOL(msm_vidc_suspend);
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
new file mode 100644
index 0000000..87150fa
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -0,0 +1,5283 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/boot_stats.h>
+#include <asm/div64.h>
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+	int __rc = (__p >= __d);\
+	__rc; \
+})
+
+#define SUM_ARRAY(__arr, __start, __end) ({\
+		int __index;\
+		typeof((__arr)[0]) __sum = 0;\
+		for (__index = (__start); __index <= (__end); __index++) {\
+			if (__index >= 0 && __index < ARRAY_SIZE(__arr))\
+				__sum += __arr[__index];\
+		} \
+		__sum;\
+})
+
+#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
+#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+		V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
+
+#define MAX_SUPPORTED_INSTANCES 16
+
+const char *const mpeg_video_vidc_extradata[] = {
+	"Extradata none",
+	"Extradata MB Quantization",
+	"Extradata Interlace Video",
+	"Extradata VC1 Framedisp",
+	"Extradata VC1 Seqdisp",
+	"Extradata timestamp",
+	"Extradata S3D Frame Packing",
+	"Extradata Frame Rate",
+	"Extradata Panscan Window",
+	"Extradata Recovery point SEI",
+	"Extradata Multislice info",
+	"Extradata number of concealed MB",
+	"Extradata metadata filler",
+	"Extradata input crop",
+	"Extradata digital zoom",
+	"Extradata aspect ratio",
+	"Extradata mpeg2 seqdisp",
+	"Extradata stream userdata",
+	"Extradata frame QP",
+	"Extradata frame bits info",
+	"Extradata LTR",
+	"Extradata macroblock metadata",
+	"Extradata VQZip SEI",
+	"Extradata YUV Stats",
+	"Extradata ROI QP",
+	"Extradata output crop",
+	"Extradata display colour SEI",
+	"Extradata light level SEI",
+	"Extradata display VUI",
+	"Extradata vpx color space",
+	"Extradata PQ Info",
+};
+
+struct getprop_buf {
+	struct list_head list;
+	void *data;
+};
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
+static void handle_session_error(enum hal_command_response cmd, void *data);
+
+bool msm_comm_turbo_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_TURBO);
+}
+
+static inline bool is_thumbnail_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_THUMBNAIL);
+}
+
+static inline bool is_low_power_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_LOW_POWER);
+}
+
+int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+
+int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl);
+}
+
+int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id)
+{
+	int rc = 0;
+	struct v4l2_control ctrl = {
+		.id = id,
+	};
+
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	return rc ?: ctrl.value;
+}
+
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+				int num_ctrls)
+{
+	int c = 0;
+	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+			num_ctrls, GFP_KERNEL);
+
+	if (!cluster || !inst)
+		return NULL;
+
+	for (c = 0; c < num_ctrls; c++)
+		cluster[c] =  inst->ctrls[c];
+
+	return cluster;
+}
+
+int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
+		struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
+		const struct v4l2_ctrl_ops *ctrl_ops)
+{
+	int idx = 0;
+	struct v4l2_ctrl_config ctrl_cfg = {0};
+	int ret_val = 0;
+
+	if (!inst || !drv_ctrls || !ctrl_ops || !num_ctrls) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	inst->ctrls = kcalloc(num_ctrls, sizeof(struct v4l2_ctrl *),
+				GFP_KERNEL);
+	if (!inst->ctrls) {
+		dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls);
+
+	if (ret_val) {
+		dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
+				inst->ctrl_handler.error);
+		return ret_val;
+	}
+
+	for (; idx < num_ctrls; idx++) {
+		struct v4l2_ctrl *ctrl = NULL;
+
+		if (IS_PRIV_CTRL(drv_ctrls[idx].id)) {
+			/*add private control*/
+			ctrl_cfg.def = drv_ctrls[idx].default_value;
+			ctrl_cfg.flags = 0;
+			ctrl_cfg.id = drv_ctrls[idx].id;
+			ctrl_cfg.max = drv_ctrls[idx].maximum;
+			ctrl_cfg.min = drv_ctrls[idx].minimum;
+			ctrl_cfg.menu_skip_mask =
+				drv_ctrls[idx].menu_skip_mask;
+			ctrl_cfg.name = drv_ctrls[idx].name;
+			ctrl_cfg.ops = ctrl_ops;
+			ctrl_cfg.step = drv_ctrls[idx].step;
+			ctrl_cfg.type = drv_ctrls[idx].type;
+			ctrl_cfg.qmenu = drv_ctrls[idx].qmenu;
+
+			ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler,
+					&ctrl_cfg, NULL);
+		} else {
+			if (drv_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+				ctrl = v4l2_ctrl_new_std_menu(
+					&inst->ctrl_handler,
+					ctrl_ops,
+					drv_ctrls[idx].id,
+					drv_ctrls[idx].maximum,
+					drv_ctrls[idx].menu_skip_mask,
+					drv_ctrls[idx].default_value);
+			} else {
+				ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
+					ctrl_ops,
+					drv_ctrls[idx].id,
+					drv_ctrls[idx].minimum,
+					drv_ctrls[idx].maximum,
+					drv_ctrls[idx].step,
+					drv_ctrls[idx].default_value);
+			}
+		}
+
+		if (!ctrl) {
+			dprintk(VIDC_ERR, "%s - invalid ctrl %s\n", __func__,
+				 drv_ctrls[idx].name);
+			return -EINVAL;
+		}
+
+		ret_val = inst->ctrl_handler.error;
+		if (ret_val) {
+			dprintk(VIDC_ERR,
+				"Error adding ctrl (%s) to ctrl handle, %d\n",
+				drv_ctrls[idx].name, inst->ctrl_handler.error);
+			return ret_val;
+		}
+
+		ctrl->flags |= drv_ctrls[idx].flags;
+		inst->ctrls[idx] = ctrl;
+	}
+
+	/* Construct a super cluster of all controls */
+	inst->cluster = get_super_cluster(inst, num_ctrls);
+	if (!inst->cluster) {
+		dprintk(VIDC_WARN,
+			"Failed to setup super cluster\n");
+		return -EINVAL;
+	}
+
+	v4l2_ctrl_cluster(num_ctrls, inst->cluster);
+
+	return ret_val;
+}
+
+int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	kfree(inst->ctrls);
+	kfree(inst->cluster);
+	v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
+	return 0;
+}
+
+static inline bool is_non_realtime_session(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct v4l2_control ctrl = {
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY
+	};
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	return (!rc && ctrl.value);
+}
+
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
+{
+	switch (msm_comm_g_ctrl_for_id(inst,
+				V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE)) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+			return HAL_VIDEO_DECODER_SECONDARY;
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+		default:
+			return HAL_VIDEO_DECODER_PRIMARY;
+	}
+}
+
+static int msm_comm_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int output_port_mbs, capture_port_mbs;
+
+	output_port_mbs = inst->in_reconfig ?
+			NUM_MBS_PER_FRAME(inst->reconfig_width,
+				inst->reconfig_height) :
+			NUM_MBS_PER_FRAME(inst->prop.width[OUTPUT_PORT],
+				inst->prop.height[OUTPUT_PORT]);
+	capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT],
+		inst->prop.height[CAPTURE_PORT]);
+
+	return max(output_port_mbs, capture_port_mbs);
+}
+
+static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
+{
+	int rc;
+	u32 fps;
+	struct v4l2_control ctrl;
+	int mb_per_frame;
+
+	mb_per_frame = msm_comm_get_mbs_per_frame(inst);
+
+	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	if (!rc && ctrl.value) {
+		fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1;
+		/*
+		 * Check if operating rate is less than fps.
+		 * If Yes, then use fps to scale the clocks
+		 */
+		fps = fps > inst->prop.fps ? fps : inst->prop.fps;
+		return (mb_per_frame * fps);
+	} else
+		return (mb_per_frame * inst->prop.fps);
+}
+
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+		enum load_calc_quirks quirks)
+{
+	int load = 0;
+
+	mutex_lock(&inst->lock);
+
+	if (!(inst->state >= MSM_VIDC_OPEN_DONE &&
+		inst->state < MSM_VIDC_STOP_DONE))
+		goto exit;
+
+	load = msm_comm_get_mbs_per_sec(inst);
+
+	if (is_thumbnail_session(inst)) {
+		if (quirks & LOAD_CALC_IGNORE_THUMBNAIL_LOAD)
+			load = 0;
+	}
+
+	if (msm_comm_turbo_session(inst)) {
+		if (!(quirks & LOAD_CALC_IGNORE_TURBO_LOAD))
+			load = inst->core->resources.max_load;
+	}
+
+	/*  Clock and Load calculations for REALTIME/NON-REALTIME
+	 *                        OPERATING RATE SET/NO OPERATING RATE SET
+	 *
+	 *                 | OPERATING RATE SET   | OPERATING RATE NOT SET |
+	 * ----------------|--------------------- |------------------------|
+	 * REALTIME        | load = res * op_rate |  load = res * fps      |
+	 *                 | clk  = res * op_rate |  clk  = res * fps      |
+	 * ----------------|----------------------|------------------------|
+	 * NON-REALTIME    | load = res * 1 fps   |  load = res * 1 fps    |
+	 *                 | clk  = res * op_rate |  clk  = res * fps      |
+	 * ----------------|----------------------|------------------------|
+	 */
+
+	if (is_non_realtime_session(inst) &&
+		(quirks & LOAD_CALC_IGNORE_NON_REALTIME_LOAD)) {
+		if (!inst->prop.fps) {
+			dprintk(VIDC_INFO, "instance:%pK fps = 0\n", inst);
+			load = 0;
+		} else {
+			load = msm_comm_get_mbs_per_sec(inst) / inst->prop.fps;
+		}
+	}
+
+exit:
+	mutex_unlock(&inst->lock);
+	return load;
+}
+
+int msm_comm_get_load(struct msm_vidc_core *core,
+	enum session_type type, enum load_calc_quirks quirks)
+{
+	struct msm_vidc_inst *inst = NULL;
+	int num_mbs_per_sec = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid args: %pK\n", core);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->session_type != type)
+			continue;
+
+		num_mbs_per_sec += msm_comm_get_inst_load(inst, quirks);
+	}
+	mutex_unlock(&core->lock);
+
+	return num_mbs_per_sec;
+}
+
+enum hal_domain get_hal_domain(int session_type)
+{
+	enum hal_domain domain;
+
+	switch (session_type) {
+	case MSM_VIDC_ENCODER:
+		domain = HAL_VIDEO_DOMAIN_ENCODER;
+		break;
+	case MSM_VIDC_DECODER:
+		domain = HAL_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Wrong domain\n");
+		domain = HAL_UNUSED_DOMAIN;
+		break;
+	}
+
+	return domain;
+}
+
+enum hal_video_codec get_hal_codec(int fourcc)
+{
+	enum hal_video_codec codec;
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_H264_NO_SC:
+		codec = HAL_VIDEO_CODEC_H264;
+		break;
+	case V4L2_PIX_FMT_H264_MVC:
+		codec = HAL_VIDEO_CODEC_MVC;
+		break;
+	case V4L2_PIX_FMT_H263:
+		codec = HAL_VIDEO_CODEC_H263;
+		break;
+	case V4L2_PIX_FMT_MPEG1:
+		codec = HAL_VIDEO_CODEC_MPEG1;
+		break;
+	case V4L2_PIX_FMT_MPEG2:
+		codec = HAL_VIDEO_CODEC_MPEG2;
+		break;
+	case V4L2_PIX_FMT_MPEG4:
+		codec = HAL_VIDEO_CODEC_MPEG4;
+		break;
+	case V4L2_PIX_FMT_VC1_ANNEX_G:
+	case V4L2_PIX_FMT_VC1_ANNEX_L:
+		codec = HAL_VIDEO_CODEC_VC1;
+		break;
+	case V4L2_PIX_FMT_VP8:
+		codec = HAL_VIDEO_CODEC_VP8;
+		break;
+	case V4L2_PIX_FMT_VP9:
+		codec = HAL_VIDEO_CODEC_VP9;
+		break;
+	case V4L2_PIX_FMT_DIVX_311:
+		codec = HAL_VIDEO_CODEC_DIVX_311;
+		break;
+	case V4L2_PIX_FMT_DIVX:
+		codec = HAL_VIDEO_CODEC_DIVX;
+		break;
+	case V4L2_PIX_FMT_HEVC:
+		codec = HAL_VIDEO_CODEC_HEVC;
+		break;
+	case V4L2_PIX_FMT_HEVC_HYBRID:
+		codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
+		codec = HAL_UNUSED_CODEC;
+		break;
+	}
+
+	return codec;
+}
+
+static enum hal_uncompressed_format get_hal_uncompressed(int fourcc)
+{
+	enum hal_uncompressed_format format = HAL_UNUSED_COLOR;
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		format = HAL_COLOR_FORMAT_NV12;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		format = HAL_COLOR_FORMAT_NV21;
+		break;
+	case V4L2_PIX_FMT_NV12_UBWC:
+		format = HAL_COLOR_FORMAT_NV12_UBWC;
+		break;
+	case V4L2_PIX_FMT_NV12_TP10_UBWC:
+		format = HAL_COLOR_FORMAT_NV12_TP10_UBWC;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		format = HAL_COLOR_FORMAT_RGBA8888;
+		break;
+	case V4L2_PIX_FMT_RGBA8888_UBWC:
+		format = HAL_COLOR_FORMAT_RGBA8888_UBWC;
+		break;
+	default:
+		format = HAL_UNUSED_COLOR;
+		break;
+	}
+
+	return format;
+}
+
+static int msm_comm_vote_bus(struct msm_vidc_core *core)
+{
+	int rc = 0, vote_data_count = 0, i = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_inst *inst = NULL;
+	struct vidc_bus_vote_data *vote_data = NULL;
+	unsigned long core_freq = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
+			__func__, hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list)
+		++vote_data_count;
+
+	vote_data = kcalloc(vote_data_count, sizeof(*vote_data),
+			GFP_TEMPORARY);
+	if (!vote_data) {
+		dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail_alloc;
+	}
+
+	core_freq = call_hfi_op(hdev, get_core_clock_rate,
+			hdev->hfi_device_data, 0);
+
+	list_for_each_entry(inst, &core->instances, list) {
+		int codec = 0, yuv = 0;
+		struct v4l2_control ctrl;
+
+		codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+		yuv = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[CAPTURE_PORT].fourcc :
+			inst->fmts[OUTPUT_PORT].fourcc;
+
+		vote_data[i].domain = get_hal_domain(inst->session_type);
+		vote_data[i].codec = get_hal_codec(codec);
+		vote_data[i].width =  max(inst->prop.width[CAPTURE_PORT],
+			inst->prop.width[OUTPUT_PORT]);
+		vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
+			inst->prop.height[OUTPUT_PORT]);
+
+		ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
+		rc = msm_comm_g_ctrl(inst, &ctrl);
+		if (!rc && ctrl.value)
+			vote_data[i].fps = (ctrl.value >> 16) ?
+				ctrl.value >> 16 : 1;
+		else
+			vote_data[i].fps = inst->prop.fps;
+
+		if (msm_comm_turbo_session(inst))
+			vote_data[i].power_mode = VIDC_POWER_TURBO;
+		else if (is_low_power_session(inst))
+			vote_data[i].power_mode = VIDC_POWER_LOW;
+		else
+			vote_data[i].power_mode = VIDC_POWER_NORMAL;
+		if (i == 0) {
+			vote_data[i].imem_ab_tbl = core->resources.imem_ab_tbl;
+			vote_data[i].imem_ab_tbl_size =
+				core->resources.imem_ab_tbl_size;
+			vote_data[i].core_freq = core_freq;
+		}
+
+		/*
+		 * TODO: support for OBP-DBP split mode hasn't been yet
+		 * implemented, once it is, this part of code needs to be
+		 * revisited since passing in accurate information to the bus
+		 * governor will drastically reduce bandwidth
+		 */
+		vote_data[i].color_formats[0] = get_hal_uncompressed(yuv);
+		vote_data[i].num_formats = 1;
+		i++;
+	}
+	mutex_unlock(&core->lock);
+
+	rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, vote_data,
+			vote_data_count);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+
+	kfree(vote_data);
+	return rc;
+
+fail_alloc:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+	struct msm_vidc_core *core;
+	int found = 0;
+
+	if (core_id > MSM_VIDC_CORES_MAX) {
+		dprintk(VIDC_ERR, "Core id = %d is greater than max = %d\n",
+			core_id, MSM_VIDC_CORES_MAX);
+		return NULL;
+	}
+	mutex_lock(&vidc_driver->lock);
+	list_for_each_entry(core, &vidc_driver->cores, list) {
+		if (core->id == core_id) {
+			found = 1;
+			break;
+		}
+	}
+	mutex_unlock(&vidc_driver->lock);
+	if (found)
+		return core;
+	return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+	int i, k = 0;
+
+	if (!fmt || index < 0) {
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK, index = %d\n",
+						fmt, index);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].type != fmt_type)
+			continue;
+		if (k == index)
+			break;
+		k++;
+	}
+	if (i == size) {
+		dprintk(VIDC_INFO, "Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+	int i;
+
+	if (!fmt) {
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK\n", fmt);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].fourcc == fourcc)
+			break;
+	}
+	if (i == size) {
+		dprintk(VIDC_INFO, "Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+
+struct buf_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return &inst->bufq[CAPTURE_PORT];
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return &inst->bufq[OUTPUT_PORT];
+	return NULL;
+}
+
+static void handle_sys_init_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+	struct vidc_hal_sys_init_done *sys_init_msg;
+	u32 index;
+
+	if (!IS_HAL_SYS_CMD(cmd)) {
+		dprintk(VIDC_ERR, "%s - invalid cmd\n", __func__);
+		return;
+	}
+
+	index = SYS_MSG_INDEX(cmd);
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
+		return;
+	}
+	sys_init_msg = &response->data.sys_init_done;
+	if (!sys_init_msg) {
+		dprintk(VIDC_ERR, "sys_init_done message not proper\n");
+		return;
+	}
+
+	core->enc_codec_supported = sys_init_msg->enc_codec_supported;
+	core->dec_codec_supported = sys_init_msg->dec_codec_supported;
+
+	/* This should come from sys_init_done */
+	core->resources.max_inst_count =
+		sys_init_msg->max_sessions_supported ? :
+		MAX_SUPPORTED_INSTANCES;
+
+	core->resources.max_secure_inst_count =
+		core->resources.max_secure_inst_count ? :
+		core->resources.max_inst_count;
+
+	if (core->id == MSM_VIDC_CORE_VENUS &&
+		(core->dec_codec_supported & HAL_VIDEO_CODEC_H264))
+		core->dec_codec_supported |=
+		HAL_VIDEO_CODEC_MVC;
+
+	core->codec_count = sys_init_msg->codec_count;
+	memcpy(core->capabilities, sys_init_msg->capabilities,
+		sys_init_msg->codec_count * sizeof(struct msm_vidc_capability));
+
+	dprintk(VIDC_DBG,
+		"%s: supported_codecs[%d]: enc = %#x, dec = %#x\n",
+		__func__, core->codec_count, core->enc_codec_supported,
+		core->dec_codec_supported);
+
+	complete(&(core->completions[index]));
+
+}
+
+void put_inst(struct msm_vidc_inst *inst)
+{
+	void put_inst_helper(struct kref *kref)
+	{
+		struct msm_vidc_inst *inst = container_of(kref,
+				struct msm_vidc_inst, kref);
+		msm_vidc_destroy(inst);
+	}
+
+	if (!inst)
+		return;
+
+	kref_put(&inst->kref, put_inst_helper);
+}
+
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+		void *session_id)
+{
+	struct msm_vidc_inst *inst = NULL;
+	bool matches = false;
+
+	if (!core || !session_id)
+		return NULL;
+
+	mutex_lock(&core->lock);
+	/*
+	 * This is as good as !list_empty(!inst->list), but at this point
+	 * we don't really know if inst was kfree'd via close syscall before
+	 * hardware could respond.  So manually walk thru the list of active
+	 * sessions
+	 */
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst == session_id) {
+			/*
+			 * Even if the instance is valid, we really shouldn't
+			 * be receiving or handling callbacks when we've deleted
+			 * our session with HFI
+			 */
+			matches = !!inst->session;
+			break;
+		}
+	}
+
+	/*
+	 * kref_* is atomic_int backed, so no need for inst->lock.  But we can
+	 * always acquire inst->lock and release it in put_inst for a stronger
+	 * locking system.
+	 */
+	inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
+	mutex_unlock(&core->lock);
+
+	return inst;
+}
+
+static void handle_session_release_buf_done(enum hal_command_response cmd,
+	void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct internal_buf *buf;
+	struct list_head *ptr, *next;
+	struct hal_buffer_info *buffer;
+	u32 buf_found = false;
+	u32 address;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	buffer = &response->data.buffer_info;
+	address = buffer->buffer_addr;
+
+	mutex_lock(&inst->scratchbufs.lock);
+	list_for_each_safe(ptr, next, &inst->scratchbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == (u32)buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing scratch: %pa\n",
+					&buf->handle->device_addr);
+			buf_found = true;
+		}
+	}
+	mutex_unlock(&inst->scratchbufs.lock);
+
+	mutex_lock(&inst->persistbufs.lock);
+	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == (u32)buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing persist: %pa\n",
+					&buf->handle->device_addr);
+			buf_found = true;
+		}
+	}
+	mutex_unlock(&inst->persistbufs.lock);
+
+	if (!buf_found)
+		dprintk(VIDC_ERR, "invalid buffer received from firmware");
+	if (IS_HAL_SESSION_CMD(cmd))
+		complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+	else
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+
+	put_inst(inst);
+}
+
+static void handle_sys_release_res_done(
+		enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
+		return;
+	}
+	complete(&core->completions[
+			SYS_MSG_INDEX(HAL_SYS_RELEASE_RESOURCE_DONE)]);
+}
+
+static void change_inst_state(struct msm_vidc_inst *inst,
+	enum instance_state state)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid parameter %s\n", __func__);
+		return;
+	}
+	mutex_lock(&inst->lock);
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_DBG,
+			"Inst: %pK is in bad state can't change state to %d\n",
+			inst, state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Moved inst: %pK from state: %d to state: %d\n",
+		   inst, inst->state, state);
+	inst->state = state;
+exit:
+	mutex_unlock(&inst->lock);
+}
+
+static int signal_session_msg_receipt(enum hal_command_response cmd,
+		struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid(%pK) instance id\n", inst);
+		return -EINVAL;
+	}
+	if (IS_HAL_SESSION_CMD(cmd)) {
+		complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+	} else {
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+	enum hal_command_response cmd)
+{
+	int rc = 0;
+
+	if (!IS_HAL_SESSION_CMD(cmd)) {
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+		return -EINVAL;
+	}
+	rc = wait_for_completion_timeout(
+		&inst->completions[SESSION_MSG_INDEX(cmd)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
+				SESSION_MSG_INDEX(cmd));
+		msm_comm_kill_session(inst);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EIO;
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+	enum instance_state flipped_state,
+	enum instance_state desired_state,
+	enum hal_command_response hal_cmd)
+{
+	int rc = 0;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto err_same_state;
+	}
+	dprintk(VIDC_DBG, "Waiting for hal_cmd: %d\n", hal_cmd);
+	rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+	if (!rc)
+		change_inst_state(inst, desired_state);
+err_same_state:
+	return rc;
+}
+
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+{
+	struct v4l2_event event = {.id = 0, .type = event_type};
+
+	v4l2_event_queue_fh(&inst->event_handler, &event);
+}
+
+static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
+{
+	enum hal_command_response cmd = HAL_SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+	dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
+	response.session_id = inst;
+	response.status = VIDC_ERR_MAX_CLIENTS;
+	handle_session_error(cmd, (void *)&response);
+}
+
+static void print_cap(const char *type,
+		struct hal_capability_supported *cap)
+{
+	dprintk(VIDC_DBG,
+		"%-24s: %-8d %-8d %-8d\n",
+		type, cap->min, cap->max, cap->step_size);
+}
+
+static void handle_session_init_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst = NULL;
+	struct vidc_hal_session_init_done *session_init_done = NULL;
+	struct msm_vidc_capability *capability = NULL;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	u32 i, codec;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+				"Failed to get valid response for session init\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+		response->session_id);
+
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (response->status) {
+		dprintk(VIDC_ERR,
+			"Session init response from FW : %#x\n",
+			response->status);
+		if (response->status == VIDC_ERR_MAX_CLIENTS)
+			msm_comm_generate_max_clients_error(inst);
+		else
+			msm_comm_generate_session_error(inst);
+
+		signal_session_msg_receipt(cmd, inst);
+		put_inst(inst);
+		return;
+	}
+
+	core = inst->core;
+	hdev = inst->core->device;
+	codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+	/* check if capabilities are available for this session */
+	for (i = 0; i < VIDC_MAX_SESSIONS; i++) {
+		if (core->capabilities[i].codec ==
+				get_hal_codec(codec) &&
+			core->capabilities[i].domain ==
+				get_hal_domain(inst->session_type)) {
+			capability = &core->capabilities[i];
+			break;
+		}
+	}
+
+	if (capability) {
+		dprintk(VIDC_DBG,
+			"%s: capabilities available for codec 0x%x, domain %#x\n",
+			__func__, capability->codec, capability->domain);
+		memcpy(&inst->capability, capability,
+			sizeof(struct msm_vidc_capability));
+	} else {
+		session_init_done = (struct vidc_hal_session_init_done *)
+				&response->data.session_init_done;
+		if (!session_init_done) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to get valid response for session init\n",
+				__func__);
+			return;
+		}
+		capability = &session_init_done->capability;
+		dprintk(VIDC_DBG,
+			"%s: got capabilities for codec 0x%x, domain 0x%x\n",
+			__func__, capability->codec,
+			capability->domain);
+		memcpy(&inst->capability, capability,
+			sizeof(struct msm_vidc_capability));
+	}
+	inst->capability.pixelprocess_capabilities =
+		call_hfi_op(hdev, get_core_capabilities, hdev->hfi_device_data);
+
+	dprintk(VIDC_DBG,
+		"Capability type : min      max      step size\n");
+	print_cap("width", &inst->capability.width);
+	print_cap("height", &inst->capability.height);
+	print_cap("mbs_per_frame", &inst->capability.mbs_per_frame);
+	print_cap("frame_rate", &inst->capability.frame_rate);
+	print_cap("scale_x", &inst->capability.scale_x);
+	print_cap("scale_y", &inst->capability.scale_y);
+	print_cap("hier_p", &inst->capability.hier_p);
+	print_cap("ltr_count", &inst->capability.ltr_count);
+	print_cap("mbs_per_sec_low_power",
+		&inst->capability.mbs_per_sec_power_save);
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_event_change(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_cb_event *event_notify = data;
+	int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+	struct v4l2_event seq_changed_event = {0};
+	int rc = 0;
+	struct hfi_device *hdev;
+	u32 *ptr = NULL;
+
+	if (!event_notify) {
+		dprintk(VIDC_WARN, "Got an empty event from hfi\n");
+		goto err_bad_event;
+	}
+
+	inst = get_inst(get_vidc_core(event_notify->device_id),
+			event_notify->session_id);
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		goto err_bad_event;
+	}
+	hdev = inst->core->device;
+
+	switch (event_notify->hal_event_type) {
+	case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+
+		rc = msm_comm_g_ctrl_for_id(inst,
+			V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER);
+
+		if (!IS_ERR_VALUE((unsigned long)rc) && rc == true) {
+			event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+
+			if (msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_SECONDARY) {
+				struct hal_frame_size frame_sz;
+
+				frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+				frame_sz.width = event_notify->width;
+				frame_sz.height = event_notify->height;
+				dprintk(VIDC_DBG,
+					"Update OPB dimensions to firmware if buffer requirements are sufficient\n");
+				rc = msm_comm_try_set_prop(inst,
+					HAL_PARAM_FRAME_SIZE, &frame_sz);
+			}
+
+			dprintk(VIDC_DBG,
+				"send session_continue after sufficient event\n");
+			rc = call_hfi_op(hdev, session_continue,
+					(void *) inst->session);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s - failed to send session_continue\n",
+					__func__);
+				goto err_bad_event;
+			}
+		}
+		break;
+	case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		break;
+	case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+	{
+		struct v4l2_event buf_event = {0};
+		struct buffer_info *binfo = NULL, *temp = NULL;
+		u32 *ptr = NULL;
+
+		dprintk(VIDC_DBG, "%s - inst: %pK buffer: %pa extra: %pa\n",
+				__func__, inst, &event_notify->packet_buffer,
+				&event_notify->extra_data_buffer);
+
+		if (inst->state == MSM_VIDC_CORE_INVALID ||
+				inst->core->state == VIDC_CORE_INVALID) {
+			dprintk(VIDC_DBG,
+					"Event release buf ref received in invalid state - discard\n");
+			goto err_bad_event;
+		}
+
+		/*
+		 * Get the buffer_info entry for the
+		 * device address.
+		 */
+		binfo = device_to_uvaddr(&inst->registeredbufs,
+				event_notify->packet_buffer);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+					"%s buffer not found in registered list\n",
+					__func__);
+			goto err_bad_event;
+		}
+
+		/* Fill event data to be sent to client*/
+		buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+		ptr = (u32 *)buf_event.u.data;
+		ptr[0] = binfo->fd[0];
+		ptr[1] = binfo->buff_off[0];
+
+		dprintk(VIDC_DBG,
+				"RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
+				ptr[0], ptr[1]);
+
+		/* Decrement buffer reference count*/
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry(temp, &inst->registeredbufs.list,
+				list) {
+			if (temp == binfo) {
+				buf_ref_put(inst, binfo);
+				break;
+			}
+		}
+
+		/*
+		 * Release buffer and remove from list
+		 * if reference goes to zero.
+		 */
+		if (unmap_and_deregister_buf(inst, binfo))
+			dprintk(VIDC_ERR,
+					"%s: buffer unmap failed\n", __func__);
+		mutex_unlock(&inst->registeredbufs.lock);
+
+		/*send event to client*/
+		v4l2_event_queue_fh(&inst->event_handler, &buf_event);
+		goto err_bad_event;
+	}
+	default:
+		break;
+	}
+
+	/* Bit depth and pic struct changed event are combined into a single
+	 * event (insufficient event) for the userspace. Currently bitdepth
+	 * changes is only for HEVC and interlaced support is for all
+	 * codecs except HEVC
+	 * event data is now as follows:
+	 * u32 *ptr = seq_changed_event.u.data;
+	 * ptr[0] = height
+	 * ptr[1] = width
+	 * ptr[2] = flag to indicate bit depth or/and pic struct changed
+	 * ptr[3] = bit depth
+	 * ptr[4] = pic struct (progressive or interlaced)
+	 * ptr[5] = colour space
+	 */
+
+	ptr = (u32 *)seq_changed_event.u.data;
+	ptr[2] = 0x0;
+	ptr[3] = inst->bit_depth;
+	ptr[4] = inst->pic_struct;
+	ptr[5] = inst->colour_space;
+
+	if (inst->bit_depth != event_notify->bit_depth) {
+		inst->bit_depth = event_notify->bit_depth;
+		ptr[2] |= V4L2_EVENT_BITDEPTH_FLAG;
+		ptr[3] = inst->bit_depth;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to bit-depth change\n");
+	}
+
+	if (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12 &&
+		event_notify->pic_struct != MSM_VIDC_PIC_STRUCT_UNKNOWN &&
+		inst->pic_struct != event_notify->pic_struct) {
+		inst->pic_struct = event_notify->pic_struct;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		ptr[2] |= V4L2_EVENT_PICSTRUCT_FLAG;
+		ptr[4] = inst->pic_struct;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to pic-struct change\n");
+	}
+
+	if (inst->bit_depth == MSM_VIDC_BIT_DEPTH_10
+		&& inst->colour_space !=
+		event_notify->colour_space) {
+		inst->colour_space = event_notify->colour_space;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		ptr[2] |= V4L2_EVENT_COLOUR_SPACE_FLAG;
+		ptr[5] = inst->colour_space;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to colour space change\n");
+	}
+
+	if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+		dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
+		inst->reconfig_height = event_notify->height;
+		inst->reconfig_width = event_notify->width;
+		inst->in_reconfig = true;
+	} else {
+		dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
+		dprintk(VIDC_DBG,
+			"event_notify->height = %d event_notify->width = %d\n",
+			event_notify->height,
+			event_notify->width);
+		inst->prop.height[OUTPUT_PORT] = event_notify->height;
+		inst->prop.width[OUTPUT_PORT] = event_notify->width;
+	}
+
+	inst->seqchanged_count++;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		msm_dcvs_init_load(inst);
+
+	rc = msm_vidc_check_session_supported(inst);
+	if (!rc) {
+		seq_changed_event.type = event;
+		if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+			u32 *ptr = NULL;
+
+			ptr = (u32 *)seq_changed_event.u.data;
+			ptr[0] = event_notify->height;
+			ptr[1] = event_notify->width;
+		}
+		v4l2_event_queue_fh(&inst->event_handler, &seq_changed_event);
+	} else if (rc == -ENOTSUPP) {
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED);
+	} else if (rc == -EBUSY) {
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
+	}
+
+err_bad_event:
+	put_inst(inst);
+}
+
+static void handle_session_prop_info(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct getprop_buf *getprop;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for prop info\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	getprop = kzalloc(sizeof(*getprop), GFP_KERNEL);
+	if (!getprop) {
+		dprintk(VIDC_ERR, "%s: getprop kzalloc failed\n", __func__);
+		goto err_prop_info;
+	}
+
+	getprop->data = kmemdup(&response->data.property,
+			sizeof(union hal_get_property), GFP_KERNEL);
+	if (!getprop->data) {
+		dprintk(VIDC_ERR, "%s: kmemdup failed\n", __func__);
+		kfree(getprop);
+		goto err_prop_info;
+	}
+
+	mutex_lock(&inst->pending_getpropq.lock);
+	list_add_tail(&getprop->list, &inst->pending_getpropq.list);
+	mutex_unlock(&inst->pending_getpropq.lock);
+
+	signal_session_msg_receipt(cmd, inst);
+err_prop_info:
+	put_inst(inst);
+}
+
+static void handle_load_resource_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for load resource\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (response->status) {
+		dprintk(VIDC_ERR,
+				"Load resource response from FW : %#x\n",
+				response->status);
+		msm_comm_generate_session_error(inst);
+	}
+
+	put_inst(inst);
+}
+
+static void handle_start_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for start\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_stop_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for stop\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_release_res_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for release resource\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+void validate_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	u32 buffers_owned_by_driver = 0;
+	struct hal_buffer_requirements *output_buf;
+
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		if (binfo->buffer_ownership != DRIVER) {
+			dprintk(VIDC_DBG,
+				"This buffer is with FW %pa\n",
+				&binfo->handle->device_addr);
+			continue;
+		}
+		buffers_owned_by_driver++;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+		dprintk(VIDC_WARN,
+			"OUTPUT Buffer count mismatch %d of %d\n",
+			buffers_owned_by_driver,
+			output_buf->buffer_count_actual);
+
+}
+
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	struct hfi_device *hdev;
+	struct msm_smem *handle;
+	struct vidc_frame_data frame_data = {0};
+	struct hal_buffer_requirements *output_buf, *extra_buf;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	extra_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		if (binfo->buffer_ownership != DRIVER)
+			continue;
+		handle = binfo->handle;
+		frame_data.alloc_len = output_buf->buffer_size;
+		frame_data.filled_len = 0;
+		frame_data.offset = 0;
+		frame_data.device_addr = handle->device_addr;
+		frame_data.flags = 0;
+		frame_data.extradata_addr = handle->device_addr +
+		output_buf->buffer_size;
+		frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_data.extradata_size = extra_buf ?
+			extra_buf->buffer_size : 0;
+		rc = call_hfi_op(hdev, session_ftb,
+			(void *) inst->session, &frame_data);
+		binfo->buffer_ownership = FIRMWARE;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	return 0;
+}
+
+static void handle_session_flush(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct v4l2_event flush_event = {0};
+	u32 *ptr = NULL;
+	enum hal_flush flush_type;
+	int rc;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+		validate_output_buffers(inst);
+		if (!inst->in_reconfig) {
+			rc = msm_comm_queue_output_buffers(inst);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to queue output buffers: %d\n",
+						rc);
+			}
+		}
+	}
+	atomic_dec(&inst->in_flush);
+	flush_event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+	ptr = (u32 *)flush_event.u.data;
+
+	flush_type = response->data.flush_type;
+	switch (flush_type) {
+	case HAL_FLUSH_INPUT:
+		ptr[0] = V4L2_QCOM_CMD_FLUSH_OUTPUT;
+		break;
+	case HAL_FLUSH_OUTPUT:
+		ptr[0] = V4L2_QCOM_CMD_FLUSH_CAPTURE;
+		break;
+	case HAL_FLUSH_ALL:
+		ptr[0] |= V4L2_QCOM_CMD_FLUSH_CAPTURE;
+		ptr[0] |= V4L2_QCOM_CMD_FLUSH_OUTPUT;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid flush type received!");
+		goto exit;
+	}
+
+	dprintk(VIDC_DBG,
+		"Notify flush complete, flush_type: %x\n", flush_type);
+	v4l2_event_queue_fh(&inst->event_handler, &flush_event);
+
+exit:
+	put_inst(inst);
+}
+
+static void handle_session_error(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct hfi_device *hdev = NULL;
+	struct msm_vidc_inst *inst = NULL;
+	int event = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session error\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	hdev = inst->core->device;
+	dprintk(VIDC_WARN, "Session error received for session %pK\n", inst);
+	change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+
+	if (response->status == VIDC_ERR_MAX_CLIENTS) {
+		dprintk(VIDC_WARN, "Too many clients, rejecting %pK", inst);
+		event = V4L2_EVENT_MSM_VIDC_MAX_CLIENTS;
+
+		/*
+		 * Clean the HFI session now. Since inst->state is moved to
+		 * INVALID, forward thread doesn't know FW has valid session
+		 * or not. This is the last place driver knows that there is
+		 * no session in FW. Hence clean HFI session now.
+		 */
+
+		msm_comm_session_clean(inst);
+	} else if (response->status == VIDC_ERR_NOT_SUPPORTED) {
+		dprintk(VIDC_WARN, "Unsupported bitstream in %pK", inst);
+		event = V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED;
+	} else {
+		dprintk(VIDC_WARN, "Unknown session error (%d) for %pK\n",
+				response->status, inst);
+		event = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+	}
+
+	msm_vidc_queue_v4l2_event(inst, event);
+	put_inst(inst);
+}
+
+static void msm_comm_clean_notify_client(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *inst = NULL;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return;
+	}
+
+	dprintk(VIDC_WARN, "%s: Core %pK\n", __func__, core);
+	mutex_lock(&core->lock);
+	core->state = VIDC_CORE_INVALID;
+
+	list_for_each_entry(inst, &core->instances, list) {
+		mutex_lock(&inst->lock);
+		inst->state = MSM_VIDC_CORE_INVALID;
+		mutex_unlock(&inst->lock);
+		dprintk(VIDC_WARN,
+			"%s Send sys error for inst %pK\n", __func__, inst);
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+	}
+	mutex_unlock(&core->lock);
+}
+
+static void handle_sys_error(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core = NULL;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	subsystem_crashed("venus");
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys error\n");
+		return;
+	}
+
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Got SYS_ERR but unable to identify core\n");
+		return;
+	}
+
+	dprintk(VIDC_WARN, "SYS_ERROR %d received for core %pK\n", cmd, core);
+	msm_comm_clean_notify_client(core);
+
+	hdev = core->device;
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_DBG, "Calling core_release\n");
+		rc = call_hfi_op(hdev, core_release,
+						 hdev->hfi_device_data);
+		if (rc) {
+			dprintk(VIDC_ERR, "core_release failed\n");
+			mutex_unlock(&core->lock);
+			return;
+		}
+		core->state = VIDC_CORE_UNINIT;
+	}
+	mutex_unlock(&core->lock);
+}
+
+void msm_comm_session_clean(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev = NULL;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return;
+	}
+
+	hdev = inst->core->device;
+	mutex_lock(&inst->lock);
+	if (hdev && inst->session) {
+		dprintk(VIDC_DBG, "cleaning up instance: %pK\n", inst);
+		rc = call_hfi_op(hdev, session_clean,
+				(void *)inst->session);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Session clean failed :%pK\n", inst);
+		}
+		inst->session = NULL;
+	}
+	mutex_unlock(&inst->lock);
+}
+
+static void handle_session_close(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session close\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	show_stats(inst);
+	put_inst(inst);
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
+		unsigned long dev_addr)
+{
+	struct vb2_buffer *vb = NULL;
+	struct vb2_queue *q = NULL;
+	int found = 0;
+
+	if (!bufq) {
+		dprintk(VIDC_ERR, "Invalid parameter\n");
+		return NULL;
+	}
+	q = &bufq->vb2_bufq;
+	mutex_lock(&bufq->lock);
+	list_for_each_entry(vb, &q->queued_list, queued_entry) {
+		if (vb->planes[0].m.userptr == dev_addr &&
+			vb->state == VB2_BUF_STATE_ACTIVE) {
+			found = 1;
+			dprintk(VIDC_DBG, "Found v4l2_buf index : %d\n",
+					vb->index);
+			break;
+		}
+	}
+	mutex_unlock(&bufq->lock);
+	if (!found) {
+		dprintk(VIDC_DBG,
+			"Failed to find buffer in queued list: %#lx, qtype = %d\n",
+			dev_addr, q->type);
+		vb = NULL;
+	}
+	return vb;
+}
+
+static void handle_ebd(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct vb2_buffer *vb;
+	struct msm_vidc_inst *inst;
+	struct vidc_hal_ebd *empty_buf_done;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT],
+			response->input_done.packet_buffer);
+	if (vb) {
+		vbuf = to_vb2_v4l2_buffer(vb);
+		vb->planes[0].bytesused = response->input_done.filled_len;
+		vb->planes[0].data_offset = response->input_done.offset;
+		if (vb->planes[0].data_offset > vb->planes[0].length)
+			dprintk(VIDC_INFO, "data_offset overflow length\n");
+		if (vb->planes[0].bytesused > vb->planes[0].length)
+			dprintk(VIDC_INFO, "bytesused overflow length\n");
+		if (vb->planes[0].m.userptr !=
+			response->clnt_data)
+			dprintk(VIDC_INFO, "Client data != bufaddr\n");
+		empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
+		if (empty_buf_done) {
+			if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
+				dprintk(VIDC_INFO,
+					"Failed : Unsupported input stream\n");
+				vbuf->flags |=
+					V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
+			}
+			if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) {
+				dprintk(VIDC_INFO,
+					"Failed : Corrupted input stream\n");
+				vbuf->flags |=
+					V4L2_QCOM_BUF_DATA_CORRUPT;
+			}
+			if (empty_buf_done->status ==
+				VIDC_ERR_START_CODE_NOT_FOUND) {
+				vbuf->flags |=
+					V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND;
+				dprintk(VIDC_INFO,
+					"Failed: Start code not found\n");
+			}
+			if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME)
+				vbuf->flags |=
+					V4L2_QCOM_BUF_FLAG_IDRFRAME |
+					V4L2_BUF_FLAG_KEYFRAME;
+		}
+		dprintk(VIDC_DBG,
+			"Got ebd from hal: device_addr: %pa, alloc: %d, status: %#x, pic_type: %#x, flags: %#x\n",
+			&empty_buf_done->packet_buffer,
+			empty_buf_done->alloc_len, empty_buf_done->status,
+			empty_buf_done->picture_type, empty_buf_done->flags);
+
+		mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD);
+	}
+
+	put_inst(inst);
+}
+
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int cnt = 0;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	atomic_inc(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	if (cnt > 2) {
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		cnt = -EINVAL;
+	}
+	if (cnt == 2)
+		inst->buffers_held_in_driver++;
+
+	dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+
+	return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int rc = 0;
+	int cnt;
+	bool release_buf = false;
+	bool qbuf_again = false;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	atomic_dec(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+	if (!cnt)
+		release_buf = true;
+	else if (cnt == 1)
+		qbuf_again = true;
+	else {
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		cnt = -EINVAL;
+	}
+
+	if (cnt < 0)
+		return cnt;
+
+	if (release_buf) {
+		/*
+		 * We can not delete binfo here as we need to set the user
+		 * virtual address saved in binfo->uvaddr to the dequeued v4l2
+		 * buffer.
+		 *
+		 * We will set the pending_deletion flag to true here and delete
+		 * binfo from registered list in dqbuf after setting the uvaddr.
+		 */
+		dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+			binfo->fd[0]);
+		binfo->pending_deletion = true;
+	} else if (qbuf_again) {
+		inst->buffers_held_in_driver--;
+		rc = qbuf_dynamic_buf(inst, binfo);
+		if (!rc)
+			return rc;
+	}
+	return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+		ion_phys_addr_t device_addr, u32 flags)
+{
+	struct buffer_info *binfo = NULL, *temp = NULL;
+
+	/*
+	 * Update reference count and release OR queue back the buffer,
+	 * only when firmware is not holding a reference.
+	 */
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		binfo = device_to_uvaddr(&inst->registeredbufs, device_addr);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"%s buffer not found in registered list\n",
+				__func__);
+			return;
+		}
+		if (flags & HAL_BUFFERFLAG_READONLY) {
+			dprintk(VIDC_DBG,
+				"FBD fd[0] = %d -> Reference with f/w, addr: %pa\n",
+				binfo->fd[0], &device_addr);
+		} else {
+			dprintk(VIDC_DBG,
+				"FBD fd[0] = %d -> FBD_ref_released, addr: %pa\n",
+				binfo->fd[0], &device_addr);
+
+			mutex_lock(&inst->registeredbufs.lock);
+			list_for_each_entry(temp, &inst->registeredbufs.list,
+							list) {
+				if (temp == binfo) {
+					buf_ref_put(inst, binfo);
+					break;
+				}
+			}
+			mutex_unlock(&inst->registeredbufs.lock);
+		}
+	}
+}
+
+static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
+		ion_phys_addr_t dev_addr)
+{
+	struct internal_buf *binfo;
+	struct msm_smem *handle;
+	bool found = false;
+
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		handle = binfo->handle;
+		if (handle && dev_addr == handle->device_addr) {
+			if (binfo->buffer_ownership == DRIVER) {
+				dprintk(VIDC_ERR,
+					"FW returned same buffer: %pa\n",
+					&dev_addr);
+				break;
+			}
+			binfo->buffer_ownership = DRIVER;
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	if (!found) {
+		dprintk(VIDC_ERR,
+			"Failed to find output buffer in queued list: %pa\n",
+			&dev_addr);
+	}
+
+	return 0;
+}
+
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
+{
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY)
+		return HAL_BUFFER_OUTPUT2;
+	else
+		return HAL_BUFFER_OUTPUT;
+}
+
+static void handle_fbd(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb = NULL;
+	struct vidc_hal_fbd *fill_buf_done;
+	enum hal_buffer buffer_type;
+	int extra_idx = 0;
+	int64_t time_usec = 0;
+	static int first_enc_frame = 1;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+	struct buffer_info *buffer_info = NULL;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	buffer_type = msm_comm_get_hal_output_buffer(inst);
+	if (fill_buf_done->buffer_type == buffer_type) {
+		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+				fill_buf_done->packet_buffer1);
+	} else {
+		if (handle_multi_stream_buffers(inst,
+				fill_buf_done->packet_buffer1))
+			dprintk(VIDC_ERR,
+				"Failed : Output buffer not found %pa\n",
+				&fill_buf_done->packet_buffer1);
+		goto err_handle_fbd;
+	}
+
+	if (vb) {
+		vbuf = to_vb2_v4l2_buffer(vb);
+		vb->planes[0].bytesused = fill_buf_done->filled_len1;
+		vb->planes[0].data_offset = fill_buf_done->offset1;
+		if (vb->planes[0].data_offset > vb->planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow data_offset = %d; length = %d\n",
+				vb->planes[0].data_offset,
+				vb->planes[0].length);
+		if (vb->planes[0].bytesused > vb->planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow bytesused = %d; length = %d\n",
+				vb->planes[0].bytesused,
+				vb->planes[0].length);
+
+		buffer_info = device_to_uvaddr(&inst->registeredbufs,
+			fill_buf_done->packet_buffer1);
+
+		if (!buffer_info) {
+			dprintk(VIDC_ERR,
+				"%s buffer not found in registered list\n",
+				__func__);
+			return;
+		}
+
+		buffer_info->crop_data.nLeft = fill_buf_done->start_x_coord;
+		buffer_info->crop_data.nTop = fill_buf_done->start_y_coord;
+		buffer_info->crop_data.nWidth = fill_buf_done->frame_width;
+		buffer_info->crop_data.nHeight = fill_buf_done->frame_height;
+		buffer_info->crop_data.width_height[0] =
+						inst->prop.width[CAPTURE_PORT];
+		buffer_info->crop_data.width_height[1] =
+						inst->prop.height[CAPTURE_PORT];
+
+		if (!(fill_buf_done->flags1 &
+			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+			time_usec = fill_buf_done->timestamp_hi;
+			time_usec = (time_usec << 32) |
+				fill_buf_done->timestamp_lo;
+		} else {
+			time_usec = 0;
+			dprintk(VIDC_DBG,
+					"Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
+					&fill_buf_done->packet_buffer1,
+					fill_buf_done->filled_len1,
+					fill_buf_done->timestamp_hi,
+					fill_buf_done->timestamp_lo);
+		}
+		vb->timestamp = (time_usec * NSEC_PER_USEC);
+		vbuf->flags = 0;
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			vb->planes[extra_idx].m.userptr =
+				(unsigned long)fill_buf_done->extra_data_buffer;
+			vb->planes[extra_idx].bytesused =
+				vb->planes[extra_idx].length;
+			vb->planes[extra_idx].data_offset = 0;
+		}
+
+		handle_dynamic_buffer(inst, fill_buf_done->packet_buffer1,
+					fill_buf_done->flags1);
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_READONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
+		/* if (fill_buf_done->flags1 & HAL_BUFFERFLAG_ENDOFFRAME)
+		 * vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_ENDOFFRAME;
+		 */
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+			vbuf->flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+			vbuf->flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
+			vbuf->flags |= V4L2_QCOM_BUF_DROP_FRAME;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_MBAFF)
+			vbuf->flags |= V4L2_MSM_BUF_FLAG_MBAFF;
+
+		switch (fill_buf_done->picture_type) {
+		case HAL_PICTURE_IDR:
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case HAL_PICTURE_I:
+			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case HAL_PICTURE_P:
+			vbuf->flags |= V4L2_BUF_FLAG_PFRAME;
+			break;
+		case HAL_PICTURE_B:
+			vbuf->flags |= V4L2_BUF_FLAG_BFRAME;
+			break;
+		case HAL_FRAME_NOTCODED:
+		case HAL_UNUSED_PICT:
+			/* Do we need to care about these? */
+		case HAL_FRAME_YUV:
+			break;
+		default:
+			break;
+		}
+
+		inst->count.fbd++;
+
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			dprintk(VIDC_DBG,
+				"extradata: userptr = %pK;"
+				" bytesused = %d; length = %d\n",
+				(u8 *)vb->planes[extra_idx].m.userptr,
+				vb->planes[extra_idx].bytesused,
+				vb->planes[extra_idx].length);
+		}
+		if (first_enc_frame == 1) {
+			boot_stats_init();
+			pr_debug("KPI: First Encoded frame received\n");
+			first_enc_frame++;
+		}
+		dprintk(VIDC_DBG,
+		"Got fbd from hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: %#x, crop: %d %d %d %d, pic_type: %#x, mark_data: %#x\n",
+		&fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
+		fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
+		fill_buf_done->flags1, fill_buf_done->start_x_coord,
+		fill_buf_done->start_y_coord, fill_buf_done->frame_width,
+		fill_buf_done->frame_height, fill_buf_done->picture_type,
+		fill_buf_done->mark_data);
+
+		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD);
+	}
+
+err_handle_fbd:
+	put_inst(inst);
+}
+
+static void handle_seq_hdr_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb;
+	struct vidc_hal_fbd *fill_buf_done;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+				fill_buf_done->packet_buffer1);
+	if (!vb) {
+		dprintk(VIDC_ERR,
+				"Failed to find video buffer for seq_hdr_done: %pa\n",
+				&fill_buf_done->packet_buffer1);
+		goto err_seq_hdr_done;
+	}
+	vbuf = to_vb2_v4l2_buffer(vb);
+	vb->planes[0].bytesused = fill_buf_done->filled_len1;
+	vb->planes[0].data_offset = fill_buf_done->offset1;
+
+	vbuf->flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+	vb->timestamp = 0;
+
+	dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
+				vb->planes[0].bytesused,
+				vb->planes[0].data_offset,
+				vbuf->flags);
+	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+
+err_seq_hdr_done:
+	put_inst(inst);
+}
+
+void handle_cmd_response(enum hal_command_response cmd, void *data)
+{
+	dprintk(VIDC_DBG, "Command response = %d\n", cmd);
+	switch (cmd) {
+	case HAL_SYS_INIT_DONE:
+		handle_sys_init_done(cmd, data);
+		break;
+	case HAL_SYS_RELEASE_RESOURCE_DONE:
+		handle_sys_release_res_done(cmd, data);
+		break;
+	case HAL_SESSION_INIT_DONE:
+		handle_session_init_done(cmd, data);
+		break;
+	case HAL_SESSION_PROPERTY_INFO:
+		handle_session_prop_info(cmd, data);
+		break;
+	case HAL_SESSION_LOAD_RESOURCE_DONE:
+		handle_load_resource_done(cmd, data);
+		break;
+	case HAL_SESSION_START_DONE:
+		handle_start_done(cmd, data);
+		break;
+	case HAL_SESSION_ETB_DONE:
+		handle_ebd(cmd, data);
+		break;
+	case HAL_SESSION_FTB_DONE:
+		handle_fbd(cmd, data);
+		break;
+	case HAL_SESSION_STOP_DONE:
+		handle_stop_done(cmd, data);
+		break;
+	case HAL_SESSION_RELEASE_RESOURCE_DONE:
+		handle_release_res_done(cmd, data);
+		break;
+	case HAL_SESSION_END_DONE:
+	case HAL_SESSION_ABORT_DONE:
+		handle_session_close(cmd, data);
+		break;
+	case HAL_SESSION_EVENT_CHANGE:
+		handle_event_change(cmd, data);
+		break;
+	case HAL_SESSION_FLUSH_DONE:
+		handle_session_flush(cmd, data);
+		break;
+	case HAL_SESSION_GET_SEQ_HDR_DONE:
+		handle_seq_hdr_done(cmd, data);
+		break;
+	case HAL_SYS_WATCHDOG_TIMEOUT:
+	case HAL_SYS_ERROR:
+		handle_sys_error(cmd, data);
+		break;
+	case HAL_SESSION_ERROR:
+		handle_session_error(cmd, data);
+		break;
+	case HAL_SESSION_RELEASE_BUFFER_DONE:
+		handle_session_release_buf_done(cmd, data);
+		break;
+	default:
+		dprintk(VIDC_DBG, "response unhandled: %d\n", cmd);
+		break;
+	}
+}
+
+int msm_comm_scale_clocks(struct msm_vidc_core *core)
+{
+	int num_mbs_per_sec =
+		msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS) +
+		msm_comm_get_load(core, MSM_VIDC_DECODER, LOAD_CALC_NO_QUIRKS);
+	return msm_comm_scale_clocks_load(core, num_mbs_per_sec,
+				LOAD_CALC_NO_QUIRKS);
+}
+
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core,
+		int num_mbs_per_sec, enum load_calc_quirks quirks)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_inst *inst = NULL;
+	unsigned long instant_bitrate = 0;
+	int num_sessions = 0;
+	struct vidc_clk_scale_data clk_scale_data = { {0} };
+	int codec = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
+			__func__, hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+
+		codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+		if (msm_comm_turbo_session(inst))
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_TURBO;
+		else if (is_low_power_session(inst))
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_LOW;
+		else
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_NORMAL;
+
+		if (inst->dcvs_mode)
+			clk_scale_data.load[num_sessions] = inst->dcvs.load;
+		else
+			clk_scale_data.load[num_sessions] =
+				msm_comm_get_inst_load(inst, quirks);
+
+		clk_scale_data.session[num_sessions] =
+				VIDC_VOTE_DATA_SESSION_VAL(
+				get_hal_codec(codec),
+				get_hal_domain(inst->session_type));
+		num_sessions++;
+
+		if (inst->instant_bitrate > instant_bitrate)
+			instant_bitrate = inst->instant_bitrate;
+
+	}
+	clk_scale_data.num_sessions = num_sessions;
+	mutex_unlock(&core->lock);
+
+
+	rc = call_hfi_op(hdev, scale_clocks,
+		hdev->hfi_device_data, num_mbs_per_sec,
+		&clk_scale_data, instant_bitrate);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
+
+	return rc;
+}
+
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return;
+	}
+	core = inst->core;
+	hdev = core->device;
+
+	if (msm_comm_scale_clocks(core)) {
+		dprintk(VIDC_WARN,
+				"Failed to scale clocks. Performance might be impacted\n");
+	}
+	if (msm_comm_vote_bus(core)) {
+		dprintk(VIDC_WARN,
+				"Failed to scale DDR bus. Performance might be impacted\n");
+	}
+}
+
+static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level)
+{
+	switch (level) {
+	case 0:
+		return VIDC_THERMAL_NORMAL;
+	case 1:
+		return VIDC_THERMAL_LOW;
+	case 2:
+		return VIDC_THERMAL_HIGH;
+	default:
+		return VIDC_THERMAL_CRITICAL;
+	}
+}
+
+static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core)
+{
+	struct hfi_device *hdev;
+	unsigned long freq = 0;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = core->device;
+
+	freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data, 1);
+	dprintk(VIDC_DBG, "clock freq %ld\n", freq);
+
+	return freq;
+}
+
+static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq)
+{
+	int i = 0;
+	struct msm_vidc_platform_resources *res = &core->resources;
+	struct load_freq_table *table = res->load_freq_tbl;
+	u32 max_freq = 0;
+
+	for (i = 0; i < res->load_freq_tbl_size; i++) {
+		if (max_freq < table[i].freq)
+			max_freq = table[i].freq;
+	}
+	return freq >= max_freq;
+}
+
+static bool is_thermal_permissible(struct msm_vidc_core *core)
+{
+	enum msm_vidc_thermal_level tl;
+	unsigned long freq = 0;
+	bool is_turbo = false;
+
+	if (!core->resources.thermal_mitigable)
+		return true;
+
+	if (!msm_vidc_thermal_mitigation_disabled) {
+		dprintk(VIDC_DBG,
+			"Thermal mitigation not enabled. debugfs %d\n",
+			msm_vidc_thermal_mitigation_disabled);
+		return true;
+	}
+
+	tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level);
+	freq = msm_comm_get_clock_rate(core);
+
+	is_turbo = is_core_turbo(core, freq);
+	dprintk(VIDC_DBG,
+		"Core freq %ld Thermal level %d Turbo mode %d\n",
+		freq, tl, is_turbo);
+
+	if (is_turbo && tl >= VIDC_THERMAL_LOW) {
+		dprintk(VIDC_ERR,
+			"Video session not allowed. Turbo mode %d Thermal level %d\n",
+			is_turbo, tl);
+		return false;
+	}
+	return true;
+}
+
+static int msm_comm_session_abort(struct msm_vidc_inst *inst)
+{
+	int rc = 0, abort_completion = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE);
+	init_completion(&inst->completions[abort_completion]);
+
+	rc = call_hfi_op(hdev, session_abort, (void *)inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s session_abort failed rc: %d\n", __func__, rc);
+		return rc;
+	}
+	rc = wait_for_completion_timeout(
+			&inst->completions[abort_completion],
+			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+				"%s: Wait interrupted or timed out [%pK]: %d\n",
+				__func__, inst, abort_completion);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EBUSY;
+	} else {
+		rc = 0;
+	}
+	msm_comm_session_clean(inst);
+	return rc;
+}
+
+static void handle_thermal_event(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return;
+	}
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (!inst->session)
+			continue;
+
+		mutex_unlock(&core->lock);
+		if (inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_CLOSE_DONE) {
+			dprintk(VIDC_WARN, "%s: abort inst %pK\n",
+				__func__, inst);
+			rc = msm_comm_session_abort(inst);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s session_abort failed rc: %d\n",
+					__func__, rc);
+				goto err_sess_abort;
+			}
+			change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+			dprintk(VIDC_WARN,
+				"%s Send sys error for inst %pK\n",
+				__func__, inst);
+			msm_vidc_queue_v4l2_event(inst,
+					V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+		} else {
+			msm_comm_generate_session_error(inst);
+		}
+		mutex_lock(&core->lock);
+	}
+	mutex_unlock(&core->lock);
+	return;
+
+err_sess_abort:
+	msm_comm_clean_notify_client(core);
+}
+
+void msm_comm_handle_thermal_event(void)
+{
+	struct msm_vidc_core *core;
+
+	list_for_each_entry(core, &vidc_driver->cores, list) {
+		if (!is_thermal_permissible(core)) {
+			dprintk(VIDC_WARN,
+				"Thermal level critical, stop all active sessions!\n");
+			handle_thermal_event(core);
+		}
+	}
+}
+
+int msm_comm_check_core_init(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	mutex_lock(&core->lock);
+	if (core->state >= VIDC_CORE_INIT_DONE) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
+	rc = wait_for_completion_timeout(
+		&core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
+				__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EIO;
+		goto exit;
+	} else {
+		core->state = VIDC_CORE_INIT_DONE;
+		rc = 0;
+	}
+	dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
+exit:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_comm_check_core_init(inst->core);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - failed to initialize core\n", __func__);
+		msm_comm_generate_sys_error(inst);
+		return rc;
+	}
+	change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+	return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core || !inst->core->device)
+		return -EINVAL;
+
+	core = inst->core;
+	hdev = core->device;
+	mutex_lock(&core->lock);
+	if (core->state >= VIDC_CORE_INIT) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_inited;
+	}
+	if (!core->capabilities) {
+		core->capabilities = kzalloc(VIDC_MAX_SESSIONS *
+				sizeof(struct msm_vidc_capability), GFP_KERNEL);
+		if (!core->capabilities) {
+			dprintk(VIDC_ERR,
+				"%s: failed to allocate capabilities\n",
+				__func__);
+			rc = -ENOMEM;
+			goto fail_cap_alloc;
+		}
+	} else {
+		dprintk(VIDC_WARN,
+			"%s: capabilities memory is expected to be freed\n",
+			__func__);
+	}
+
+	init_completion(&core->completions
+			[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)]);
+	rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
+				core->id);
+		goto fail_core_init;
+	}
+	core->state = VIDC_CORE_INIT;
+	core->smmu_fault_handled = false;
+core_already_inited:
+	change_inst_state(inst, MSM_VIDC_CORE_INIT);
+	mutex_unlock(&core->lock);
+	return rc;
+
+fail_core_init:
+	kfree(core->capabilities);
+fail_cap_alloc:
+	core->capabilities = NULL;
+	core->state = VIDC_CORE_UNINIT;
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	hdev = core->device;
+
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_uninited;
+	}
+	mutex_unlock(&core->lock);
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	mutex_lock(&core->lock);
+
+	if (!core->resources.never_unload_fw) {
+		cancel_delayed_work(&core->fw_unload_work);
+
+		/*
+		 * Delay unloading of firmware. This is useful
+		 * in avoiding firmware download delays in cases where we
+		 * will have a burst of back to back video playback sessions
+		 * e.g. thumbnail generation.
+		 */
+		schedule_delayed_work(&core->fw_unload_work,
+			msecs_to_jiffies(core->state == VIDC_CORE_INVALID ?
+					0 : msm_vidc_firmware_unload_delay));
+
+		dprintk(VIDC_DBG, "firmware unload delayed by %u ms\n",
+			core->state == VIDC_CORE_INVALID ?
+			0 : msm_vidc_firmware_unload_delay);
+	}
+
+core_already_uninited:
+	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+	mutex_unlock(&core->lock);
+	return 0;
+}
+
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst)
+{
+	msm_comm_kill_session(inst);
+	return msm_vidc_deinit_core(inst);
+}
+
+static int msm_comm_session_init(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int fourcc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		fourcc = inst->fmts[OUTPUT_PORT].fourcc;
+	} else if (inst->session_type == MSM_VIDC_ENCODER) {
+		fourcc = inst->fmts[CAPTURE_PORT].fourcc;
+	} else {
+		dprintk(VIDC_ERR, "Invalid session\n");
+		return -EINVAL;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_INIT_DONE)]);
+
+	rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
+			inst, get_hal_domain(inst->session_type),
+			get_hal_codec(fourcc),
+			&inst->session);
+
+	if (rc || !inst->session) {
+		dprintk(VIDC_ERR,
+			"Failed to call session init for: %pK, %pK, %d, %d\n",
+			inst->core->device, inst,
+			inst->session_type, fourcc);
+		rc = -EINVAL;
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+	return rc;
+}
+
+static void msm_vidc_print_running_insts(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *temp;
+
+	dprintk(VIDC_ERR, "Running instances:\n");
+	dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s|%4s\n",
+			"type", "w", "h", "fps", "prop");
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp->state >= MSM_VIDC_OPEN_DONE &&
+				temp->state < MSM_VIDC_STOP_DONE) {
+			char properties[4] = "";
+
+			if (is_thumbnail_session(temp))
+				strlcat(properties, "N", sizeof(properties));
+
+			if (msm_comm_turbo_session(temp))
+				strlcat(properties, "T", sizeof(properties));
+
+			dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4s\n",
+					temp->session_type,
+					max(temp->prop.width[CAPTURE_PORT],
+						temp->prop.width[OUTPUT_PORT]),
+					max(temp->prop.height[CAPTURE_PORT],
+						temp->prop.height[OUTPUT_PORT]),
+					temp->prop.fps, properties);
+		}
+	}
+	mutex_unlock(&core->lock);
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	int num_mbs_per_sec = 0, max_load_adj = 0;
+	struct msm_vidc_core *core;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD |
+		LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't do load res\n");
+		return -EINVAL;
+	}
+
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Instance is in invalid state can't do load res\n");
+		return -EINVAL;
+	}
+
+	num_mbs_per_sec =
+		msm_comm_get_load(core, MSM_VIDC_DECODER, quirks) +
+		msm_comm_get_load(core, MSM_VIDC_ENCODER, quirks);
+
+	max_load_adj = core->resources.max_load +
+		inst->capability.mbs_per_frame.max;
+
+	if (num_mbs_per_sec > max_load_adj) {
+		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+			num_mbs_per_sec, max_load_adj);
+		msm_vidc_print_running_insts(core);
+		inst->state = MSM_VIDC_CORE_INVALID;
+		msm_comm_kill_session(inst);
+		return -EBUSY;
+	}
+
+	hdev = core->device;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+
+	rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't do start\n");
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_START_DONE)]);
+	rc = call_hfi_op(hdev, session_start, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send start\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_START);
+exit:
+	return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Send Stop to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_STOP_DONE)]);
+	rc = call_hfi_op(hdev, session_stop, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to send stop\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+	return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG,
+		"Send release res to hal\n");
+	init_completion(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_RELEASE_RESOURCE_DONE)]);
+	rc = call_hfi_op(hdev, session_release_res, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send release resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_comm_session_close(int flipped_state,
+			struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG,
+		"Send session close to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_END_DONE)]);
+	rc = call_hfi_op(hdev, session_end, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send close\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_CLOSE);
+exit:
+	return rc;
+}
+
+int msm_comm_suspend(int core_id)
+{
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	int rc = 0;
+
+	core = get_vidc_core(core_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"%s: Failed to find core for core_id = %d\n",
+			__func__, core_id);
+		return -EINVAL;
+	}
+
+	hdev = (struct hfi_device *)core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"%s - fw is not in proper state, skip suspend\n",
+				__func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to suspend\n");
+
+exit:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int get_flipped_state(int present_state,
+	int desired_state)
+{
+	int flipped_state = present_state;
+
+	if (flipped_state < MSM_VIDC_STOP
+			&& desired_state > MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	} else if (flipped_state > MSM_VIDC_STOP
+			&& desired_state < MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP -
+			(flipped_state - MSM_VIDC_STOP + 1);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	}
+	return flipped_state;
+}
+
+struct hal_buffer_requirements *get_buff_req_buffer(
+		struct msm_vidc_inst *inst, enum hal_buffer buffer_type)
+{
+	int i;
+
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		if (inst->buff_req.buffer[i].buffer_type == buffer_type)
+			return &inst->buff_req.buffer[i];
+	}
+	return NULL;
+}
+
+static int set_output_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	u32 smem_flags = 0, buffer_size;
+	struct hal_buffer_requirements *output_buf, *extradata_buf;
+	int i;
+	struct hfi_device *hdev;
+	struct hal_buffer_size_minimum b;
+
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	buffer_size = output_buf->buffer_size;
+	b.buffer_type = buffer_type;
+	b.buffer_size = buffer_size;
+	rc = call_hfi_op(hdev, session_set_property,
+		inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+		&b);
+
+	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+	if (extradata_buf) {
+		dprintk(VIDC_DBG,
+			"extradata: num = %d, size = %d\n",
+			extradata_buf->buffer_count_actual,
+			extradata_buf->buffer_size);
+		buffer_size += extradata_buf->buffer_size;
+	} else {
+		dprintk(VIDC_DBG,
+			"This extradata buffer not required, buffer_type: %x\n",
+			buffer_type);
+	}
+
+	if (inst->flags & VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	if (output_buf->buffer_size) {
+		for (i = 0; i < output_buf->buffer_count_actual;
+				i++) {
+			handle = msm_comm_smem_alloc(inst,
+					buffer_size, 1, smem_flags,
+					buffer_type, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate output memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_comm_smem_cache_operations(inst,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+
+			binfo->handle = handle;
+			binfo->buffer_type = buffer_type;
+			binfo->buffer_ownership = DRIVER;
+			dprintk(VIDC_DBG, "Output buffer address: %pa\n",
+					&handle->device_addr);
+
+			if (inst->buffer_mode_set[CAPTURE_PORT] ==
+				HAL_BUFFER_MODE_STATIC) {
+				struct vidc_buffer_addr_info buffer_info = {0};
+
+				buffer_info.buffer_size =
+					output_buf->buffer_size;
+				buffer_info.buffer_type = buffer_type;
+				buffer_info.num_buffers = 1;
+				buffer_info.align_device_addr =
+					handle->device_addr;
+				buffer_info.extradata_addr =
+					handle->device_addr +
+					output_buf->buffer_size;
+				if (extradata_buf)
+					buffer_info.extradata_size =
+						extradata_buf->buffer_size;
+				rc = call_hfi_op(hdev, session_set_buffers,
+					(void *) inst->session, &buffer_info);
+				if (rc) {
+					dprintk(VIDC_ERR,
+						"%s : session_set_buffers failed\n",
+						__func__);
+					goto fail_set_buffers;
+				}
+			}
+			mutex_lock(&inst->outputbufs.lock);
+			list_add_tail(&binfo->list, &inst->outputbufs.list);
+			mutex_unlock(&inst->outputbufs.lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_comm_smem_free(inst, handle);
+err_no_mem:
+	return rc;
+}
+
+static inline char *get_buffer_name(enum hal_buffer buffer_type)
+{
+	switch (buffer_type) {
+	case HAL_BUFFER_INPUT: return "input";
+	case HAL_BUFFER_OUTPUT: return "output";
+	case HAL_BUFFER_OUTPUT2: return "output_2";
+	case HAL_BUFFER_EXTRADATA_INPUT: return "input_extra";
+	case HAL_BUFFER_EXTRADATA_OUTPUT: return "output_extra";
+	case HAL_BUFFER_EXTRADATA_OUTPUT2: return "output2_extra";
+	case HAL_BUFFER_INTERNAL_SCRATCH: return "scratch";
+	case HAL_BUFFER_INTERNAL_SCRATCH_1: return "scratch_1";
+	case HAL_BUFFER_INTERNAL_SCRATCH_2: return "scratch_2";
+	case HAL_BUFFER_INTERNAL_PERSIST: return "persist";
+	case HAL_BUFFER_INTERNAL_PERSIST_1: return "persist_1";
+	case HAL_BUFFER_INTERNAL_CMD_QUEUE: return "queue";
+	default: return "????";
+	}
+}
+
+static int set_internal_buf_on_fw(struct msm_vidc_inst *inst,
+				enum hal_buffer buffer_type,
+				struct msm_smem *handle, bool reuse)
+{
+	struct vidc_buffer_addr_info buffer_info;
+	struct hfi_device *hdev;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device || !handle) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	rc = msm_comm_smem_cache_operations(inst,
+					handle, SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Failed to clean cache. Undefined behavior\n");
+	}
+
+	buffer_info.buffer_size = handle->size;
+	buffer_info.buffer_type = buffer_type;
+	buffer_info.num_buffers = 1;
+	buffer_info.align_device_addr = handle->device_addr;
+	dprintk(VIDC_DBG, "%s %s buffer : %pa\n",
+				reuse ? "Reusing" : "Allocated",
+				get_buffer_name(buffer_type),
+				&buffer_info.align_device_addr);
+
+	rc = call_hfi_op(hdev, session_set_buffers,
+		(void *) inst->session, &buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"vidc_hal_session_set_buffers failed\n");
+		return rc;
+	}
+	return 0;
+}
+
+static bool reuse_internal_buffers(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, struct msm_vidc_list *buf_list)
+{
+	struct internal_buf *buf;
+	int rc = 0;
+	bool reused = false;
+
+	if (!inst || !buf_list) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
+		return false;
+	}
+
+	mutex_lock(&buf_list->lock);
+	list_for_each_entry(buf, &buf_list->list, list) {
+		if (!buf->handle) {
+			reused = false;
+			break;
+		}
+
+		if (buf->buffer_type != buffer_type)
+			continue;
+
+		/*
+		 * Persist buffer size won't change with resolution. If they
+		 * are in queue means that they are already allocated and
+		 * given to HW. HW can use them without reallocation. These
+		 * buffers are not released as part of port reconfig. So
+		 * driver no need to set them again.
+		 */
+
+		if (buffer_type != HAL_BUFFER_INTERNAL_PERSIST
+			&& buffer_type != HAL_BUFFER_INTERNAL_PERSIST_1) {
+
+			rc = set_internal_buf_on_fw(inst, buffer_type,
+					buf->handle, true);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s: session_set_buffers failed\n",
+					__func__);
+				reused = false;
+				break;
+			}
+		}
+		reused = true;
+		dprintk(VIDC_DBG,
+			"Re-using internal buffer type : %d\n", buffer_type);
+	}
+	mutex_unlock(&buf_list->lock);
+	return reused;
+}
+
+static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
+			struct hal_buffer_requirements *internal_bufreq,
+			struct msm_vidc_list *buf_list)
+{
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	u32 smem_flags = 0;
+	int rc = 0;
+	int i = 0;
+
+	if (!inst || !internal_bufreq || !buf_list)
+		return -EINVAL;
+
+	if (!internal_bufreq->buffer_size)
+		return 0;
+
+	if (inst->flags & VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	for (i = 0; i < internal_bufreq->buffer_count_actual; i++) {
+		handle = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size,
+				1, smem_flags, internal_bufreq->buffer_type, 0);
+		if (!handle) {
+			dprintk(VIDC_ERR,
+				"Failed to allocate scratch memory\n");
+			rc = -ENOMEM;
+			goto err_no_mem;
+		}
+
+		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+		if (!binfo) {
+			dprintk(VIDC_ERR, "Out of memory\n");
+			rc = -ENOMEM;
+			goto fail_kzalloc;
+		}
+
+		binfo->handle = handle;
+		binfo->buffer_type = internal_bufreq->buffer_type;
+
+		rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type,
+				handle, false);
+		if (rc)
+			goto fail_set_buffers;
+
+		mutex_lock(&buf_list->lock);
+		list_add_tail(&binfo->list, &buf_list->list);
+		mutex_unlock(&buf_list->lock);
+	}
+	return rc;
+
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_comm_smem_free(inst, handle);
+err_no_mem:
+	return rc;
+
+}
+
+static int set_internal_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type, struct msm_vidc_list *buf_list)
+{
+	struct hal_buffer_requirements *internal_buf;
+
+	internal_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!internal_buf) {
+		dprintk(VIDC_DBG,
+			"This internal buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "Buffer type %s: num = %d, size = %d\n",
+		get_buffer_name(buffer_type),
+		internal_buf->buffer_count_actual, internal_buf->buffer_size);
+
+	/*
+	 * Try reusing existing internal buffers first.
+	 * If it's not possible to reuse, allocate new buffers.
+	 */
+	if (reuse_internal_buffers(inst, buffer_type, buf_list))
+		return 0;
+
+	return allocate_and_set_internal_bufs(inst, internal_buf,
+				buf_list);
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+	int rc = 0;
+	int flipped_state;
+	struct msm_vidc_core *core;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG,
+			"Trying to move inst: %pK from: %#x to %#x\n",
+			inst, inst->state, state);
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->sync_lock);
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't change the state\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+	flipped_state = get_flipped_state(inst->state, state);
+	dprintk(VIDC_DBG,
+			"flipped_state = %#x\n", flipped_state);
+	switch (flipped_state) {
+	case MSM_VIDC_CORE_UNINIT_DONE:
+	case MSM_VIDC_CORE_INIT:
+		rc = msm_comm_init_core(inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_CORE_INIT_DONE:
+		rc = msm_comm_init_core_done(inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_OPEN:
+		rc = msm_comm_session_init(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_OPEN_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+			HAL_SESSION_INIT_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_LOAD_RESOURCES:
+		rc = msm_vidc_load_resources(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_LOAD_RESOURCES_DONE:
+	case MSM_VIDC_START:
+		rc = msm_vidc_start(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_START_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+				HAL_SESSION_START_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_STOP:
+		rc = msm_vidc_stop(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_STOP_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+				HAL_SESSION_STOP_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		dprintk(VIDC_DBG, "Moving to Stop Done state\n");
+	case MSM_VIDC_RELEASE_RESOURCES:
+		rc = msm_vidc_release_res(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_RELEASE_RESOURCES_DONE:
+		rc = wait_for_state(inst, flipped_state,
+			MSM_VIDC_RELEASE_RESOURCES_DONE,
+			HAL_SESSION_RELEASE_RESOURCE_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		dprintk(VIDC_DBG,
+				"Moving to release resources done state\n");
+	case MSM_VIDC_CLOSE:
+		rc = msm_comm_session_close(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_CLOSE_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+				HAL_SESSION_END_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		msm_comm_session_clean(inst);
+	case MSM_VIDC_CORE_UNINIT:
+	case MSM_VIDC_CORE_INVALID:
+		dprintk(VIDC_DBG, "Sending core uninit\n");
+		rc = msm_vidc_deinit_core(inst);
+		if (rc || state == get_flipped_state(inst->state, state))
+			break;
+	default:
+		dprintk(VIDC_ERR, "State not recognized\n");
+		rc = -EINVAL;
+		break;
+	}
+exit:
+	mutex_unlock(&inst->sync_lock);
+	if (rc)
+		dprintk(VIDC_ERR,
+				"Failed to move from state: %d to %d\n",
+				inst->state, state);
+	else
+		trace_msm_vidc_common_state_change((void *)inst,
+				inst->state, state);
+	return rc;
+}
+
+int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct v4l2_decoder_cmd *dec = NULL;
+	struct v4l2_encoder_cmd *enc = NULL;
+	struct msm_vidc_core *core;
+	int which_cmd = 0, flags = 0, rc = 0;
+
+	if (!inst || !inst->core || !cmd) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (inst->session_type == MSM_VIDC_ENCODER) {
+		enc = (struct v4l2_encoder_cmd *)cmd;
+		which_cmd = enc->cmd;
+		flags = enc->flags;
+	} else if (inst->session_type == MSM_VIDC_DECODER) {
+		dec = (struct v4l2_decoder_cmd *)cmd;
+		which_cmd = dec->cmd;
+		flags = dec->flags;
+	}
+
+
+	switch (which_cmd) {
+	case V4L2_QCOM_CMD_FLUSH:
+		if (core->state != VIDC_CORE_INVALID &&
+			inst->state ==  MSM_VIDC_CORE_INVALID) {
+			rc = msm_comm_kill_session(inst);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Fail to clean session: %d\n",
+					rc);
+		}
+		rc = msm_comm_flush(inst, flags);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to flush buffers: %d\n", rc);
+		}
+		break;
+	case V4L2_DEC_QCOM_CMD_RECONFIG_HINT:
+	{
+		u32 *ptr = NULL;
+		struct hal_buffer_requirements *output_buf;
+
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Getting buffer requirements failed: %d\n",
+					rc);
+			break;
+		}
+
+		output_buf = get_buff_req_buffer(inst,
+				msm_comm_get_hal_output_buffer(inst));
+		if (output_buf) {
+			if (dec) {
+				ptr = (u32 *)dec->raw.data;
+				ptr[0] = output_buf->buffer_size;
+				ptr[1] = output_buf->buffer_count_actual;
+				dprintk(VIDC_DBG,
+					"Reconfig hint, size is %u, count is %u\n",
+					ptr[0], ptr[1]);
+			} else {
+				dprintk(VIDC_ERR, "Null decoder\n");
+			}
+		} else {
+			dprintk(VIDC_DBG,
+					"This output buffer not required, buffer_type: %x\n",
+					HAL_BUFFER_OUTPUT);
+		}
+		break;
+	}
+	default:
+		dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static void populate_frame_data(struct vidc_frame_data *data,
+		const struct vb2_buffer *vb, struct msm_vidc_inst *inst)
+{
+	int64_t time_usec;
+	int extra_idx;
+	enum v4l2_buf_type type = vb->type;
+	enum vidc_ports port = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+		OUTPUT_PORT : CAPTURE_PORT;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	time_usec = vb->timestamp;
+	do_div(time_usec, NSEC_PER_USEC);
+
+	data->alloc_len = vb->planes[0].length;
+	data->device_addr = vb->planes[0].m.userptr;
+	data->timestamp = time_usec;
+	data->flags = 0;
+	data->clnt_data = data->device_addr;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		bool pic_decoding_mode = msm_comm_g_ctrl_for_id(inst,
+				V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE);
+
+		data->buffer_type = HAL_BUFFER_INPUT;
+		data->filled_len = vb->planes[0].bytesused;
+		data->offset = vb->planes[0].data_offset;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_EOS)
+			data->flags |= HAL_BUFFERFLAG_EOS;
+
+		if (vbuf->flags & V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP)
+			data->flags |= HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG)
+			data->flags |= HAL_BUFFERFLAG_CODECCONFIG;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY)
+			data->flags |= HAL_BUFFERFLAG_DECODEONLY;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_TIMESTAMP_INVALID)
+			data->timestamp = LLONG_MAX;
+
+		/* XXX: This is a dirty hack necessitated by the firmware,
+		 * which refuses to issue FBDs for non I-frames in Picture Type
+		 * Decoding mode, unless we pass in non-zero value in mark_data
+		 * and mark_target.
+		 */
+		data->mark_data = data->mark_target =
+			pic_decoding_mode ? 0xdeadbeef : 0;
+
+	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		data->buffer_type = msm_comm_get_hal_output_buffer(inst);
+	}
+
+	extra_idx = EXTRADATA_IDX(inst->fmts[port].num_planes);
+	if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+			vb->planes[extra_idx].m.userptr) {
+		data->extradata_addr = vb->planes[extra_idx].m.userptr;
+		data->extradata_size = vb->planes[extra_idx].length;
+		data->flags |= HAL_BUFFERFLAG_EXTRADATA;
+	}
+}
+
+static unsigned int count_single_batch(struct msm_vidc_list *list,
+		enum v4l2_buf_type type)
+{
+	struct vb2_buf_entry *buf;
+	int count = 0;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+
+	mutex_lock(&list->lock);
+	list_for_each_entry(buf, &list->list, list) {
+		if (buf->vb->type != type)
+			continue;
+
+		++count;
+
+		vbuf = to_vb2_v4l2_buffer(buf->vb);
+		if (!(vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER))
+			goto found_batch;
+	}
+	 /* don't have a full batch */
+	count = 0;
+
+found_batch:
+	mutex_unlock(&list->lock);
+	return count;
+}
+
+static unsigned int count_buffers(struct msm_vidc_list *list,
+		enum v4l2_buf_type type)
+{
+	struct vb2_buf_entry *buf;
+	int count = 0;
+
+	mutex_lock(&list->lock);
+	list_for_each_entry(buf, &list->list, list) {
+		if (buf->vb->type != type)
+			continue;
+
+		++count;
+	}
+	mutex_unlock(&list->lock);
+
+	return count;
+}
+
+static void log_frame(struct msm_vidc_inst *inst, struct vidc_frame_data *data,
+		enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		dprintk(VIDC_DBG,
+				"Sending etb (%pa) to hal: filled: %d, ts: %lld, flags = %#x\n",
+				&data->device_addr, data->filled_len,
+				data->timestamp, data->flags);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_ETB);
+
+		if (msm_vidc_bitrate_clock_scaling &&
+			inst->session_type == MSM_VIDC_DECODER &&
+			!inst->dcvs_mode)
+			inst->instant_bitrate =
+				data->filled_len * 8 * inst->prop.fps;
+		else
+			inst->instant_bitrate = 0;
+	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		dprintk(VIDC_DBG,
+				"Sending ftb (%pa) to hal: size: %d, ts: %lld, flags = %#x\n",
+				&data->device_addr, data->alloc_len,
+				data->timestamp, data->flags);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FTB);
+	}
+
+	msm_dcvs_check_and_scale_clocks(inst,
+			type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+	if (msm_vidc_bitrate_clock_scaling && !inst->dcvs_mode &&
+		type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+		inst->session_type == MSM_VIDC_DECODER)
+		if (msm_comm_scale_clocks(inst->core))
+			dprintk(VIDC_WARN,
+				"Failed to scale clocks. Performance might be impacted\n");
+}
+
+static int request_seq_header(struct msm_vidc_inst *inst,
+		struct vidc_frame_data *data)
+{
+	struct vidc_seq_hdr seq_hdr = {
+		.seq_hdr = data->device_addr,
+		.seq_hdr_len = data->alloc_len,
+	};
+
+	dprintk(VIDC_DBG, "Requesting sequence header in %pa\n",
+			&seq_hdr.seq_hdr);
+	return call_hfi_op(inst->core->device, session_get_seq_hdr,
+			inst->session, &seq_hdr);
+}
+
+/*
+ * Attempts to queue `vb` to hardware.  If, for various reasons, the buffer
+ * cannot be queued to hardware, the buffer will be staged for commit in the
+ * pending queue.  Once the hardware reaches a good state (or if `vb` is NULL,
+ * the subsequent *_qbuf will commit the previously staged buffers to hardware.
+ */
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb)
+{
+	int rc = 0;
+	int capture_count, output_count;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+	struct {
+		struct vidc_frame_data *data;
+		int count;
+	} etbs, ftbs;
+	bool defer = false, batch_mode;
+	struct vb2_buf_entry *temp, *next;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	hdev = core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		core->state == VIDC_CORE_INVALID ||
+		core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_ERR, "Core is in bad state. Can't Queue\n");
+		return -EINVAL;
+	}
+
+	/* Stick the buffer into the pendinq, we'll pop it out later on
+	 * if we want to commit it to hardware
+	 */
+	if (vb) {
+		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp) {
+			dprintk(VIDC_ERR, "Out of memory\n");
+			goto err_no_mem;
+		}
+
+		temp->vb = vb;
+		mutex_lock(&inst->pendingq.lock);
+		list_add_tail(&temp->list, &inst->pendingq.list);
+		mutex_unlock(&inst->pendingq.lock);
+	}
+
+	batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
+		== V4L2_VIDC_QBUF_BATCHED;
+	capture_count = (batch_mode ? &count_single_batch : &count_buffers)
+		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	output_count = (batch_mode ? &count_single_batch : &count_buffers)
+		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+	/*
+	 * Somewhat complicated logic to prevent queuing the buffer to hardware.
+	 * Don't queue if:
+	 * 1) Hardware isn't ready (that's simple)
+	 */
+	defer = defer ?: inst->state != MSM_VIDC_START_DONE;
+
+	/*
+	 * 2) The client explicitly tells us not to because it wants this
+	 * buffer to be batched with future frames.  The batch size (on both
+	 * capabilities) is completely determined by the client.
+	 */
+	defer = defer ?: vbuf && vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER;
+
+	/* 3) If we're in batch mode, we must have full batches of both types */
+	defer = defer ?: batch_mode && (!output_count || !capture_count);
+
+	if (defer) {
+		dprintk(VIDC_DBG, "Deferring queue of %pK\n", vb);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "%sing %d etbs and %d ftbs\n",
+			batch_mode ? "Batch" : "Process",
+			output_count, capture_count);
+
+	etbs.data = kcalloc(output_count, sizeof(*etbs.data), GFP_KERNEL);
+	ftbs.data = kcalloc(capture_count, sizeof(*ftbs.data), GFP_KERNEL);
+	/* Note that it's perfectly normal for (e|f)tbs.data to be NULL if
+	 * we're not in batch mode (i.e. (output|capture)_count == 0)
+	 */
+	if ((!etbs.data && output_count) ||
+			(!ftbs.data && capture_count)) {
+		dprintk(VIDC_ERR, "Failed to alloc memory for batching\n");
+		kfree(etbs.data);
+		etbs.data = NULL;
+
+		kfree(ftbs.data);
+		ftbs.data = NULL;
+		goto err_no_mem;
+	}
+
+	etbs.count = ftbs.count = 0;
+
+	/*
+	 * Try to collect all pending buffers into 2 batches of ftb and etb
+	 * Note that these "batches" might be empty if we're no in batching mode
+	 * and the pendingq is empty
+	 */
+	mutex_lock(&inst->pendingq.lock);
+	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
+		struct vidc_frame_data *frame_data = NULL;
+
+		switch (temp->vb->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			if (ftbs.count < capture_count && ftbs.data)
+				frame_data = &ftbs.data[ftbs.count++];
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			if (etbs.count < output_count && etbs.data)
+				frame_data = &etbs.data[etbs.count++];
+			break;
+		default:
+			break;
+		}
+
+		if (!frame_data)
+			continue;
+
+		populate_frame_data(frame_data, temp->vb, inst);
+
+		list_del(&temp->list);
+		kfree(temp);
+	}
+	mutex_unlock(&inst->pendingq.lock);
+
+	/* Finally commit all our frame(s) to H/W */
+	if (batch_mode) {
+		int ftb_index = 0, c = 0;
+
+		for (c = 0; atomic_read(&inst->seq_hdr_reqs) > 0; ++c) {
+			rc = request_seq_header(inst, &ftbs.data[c]);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed requesting sequence header: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			atomic_dec(&inst->seq_hdr_reqs);
+		}
+
+		ftb_index = c;
+		rc = call_hfi_op(hdev, session_process_batch, inst->session,
+				etbs.count, etbs.data,
+				ftbs.count - ftb_index, &ftbs.data[ftb_index]);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to queue batch of %d ETBs and %d FTBs\n",
+				etbs.count, ftbs.count);
+			goto err_bad_input;
+		}
+
+		for (c = ftb_index; c < ftbs.count; ++c) {
+			log_frame(inst, &ftbs.data[c],
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		}
+
+		for (c = 0; c < etbs.count; ++c) {
+			log_frame(inst, &etbs.data[c],
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+		}
+	}
+
+	if (!batch_mode && etbs.count) {
+		int c = 0;
+
+		for (c = 0; c < etbs.count; ++c) {
+			struct vidc_frame_data *frame_data = &etbs.data[c];
+
+			rc = call_hfi_op(hdev, session_etb, inst->session,
+					frame_data);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed to issue etb: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			log_frame(inst, frame_data,
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+		}
+	}
+
+	if (!batch_mode && ftbs.count) {
+		int c = 0;
+
+		for (c = 0; atomic_read(&inst->seq_hdr_reqs) > 0; ++c) {
+			rc = request_seq_header(inst, &ftbs.data[c]);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed requesting sequence header: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			atomic_dec(&inst->seq_hdr_reqs);
+		}
+
+		for (; c < ftbs.count; ++c) {
+			struct vidc_frame_data *frame_data = &ftbs.data[c];
+
+			rc = call_hfi_op(hdev, session_ftb,
+					inst->session, frame_data);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed to issue ftb: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			log_frame(inst, frame_data,
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		}
+	}
+
+err_bad_input:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer\n");
+
+	kfree(etbs.data);
+	kfree(ftbs.data);
+err_no_mem:
+	return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+	int rc = 0, i = 0;
+	union hal_get_property hprop;
+
+	rc = msm_comm_try_get_prop(inst, HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+					&hprop);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed getting buffer requirements: %d", rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG, "Buffer requirements:\n");
+	dprintk(VIDC_DBG, "%15s %8s %8s\n", "buffer type", "count", "size");
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		struct hal_buffer_requirements req = hprop.buf_req.buffer[i];
+
+		inst->buff_req.buffer[i] = req;
+		dprintk(VIDC_DBG, "%15s %8d %8d\n",
+				get_buffer_name(req.buffer_type),
+				req.buffer_count_actual, req.buffer_size);
+	}
+
+	dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n",
+			inst->buff_req.buffer[0].buffer_count_actual,
+			inst->buff_req.buffer[1].buffer_count_actual);
+	return rc;
+}
+
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
+				union hal_get_property *hprop)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct getprop_buf *buf;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE ||
+			inst->state >= MSM_VIDC_CLOSE) {
+
+		/* No need to check inst->state == MSM_VIDC_INVALID since
+		 * INVALID is > CLOSE_DONE. When core went to INVALID state,
+		 * we put all the active instances in INVALID. So > CLOSE_DONE
+		 * is enough check to have.
+		 */
+
+		dprintk(VIDC_ERR,
+			"In Wrong state to call Buf Req: Inst %pK or Core %pK\n",
+				inst, inst->core);
+		rc = -EAGAIN;
+		mutex_unlock(&inst->sync_lock);
+		goto exit;
+	}
+	mutex_unlock(&inst->sync_lock);
+
+	init_completion(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)]);
+	switch (ptype) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+	case HAL_CONFIG_VDEC_ENTROPY:
+		rc = call_hfi_op(hdev, session_get_property, inst->session,
+				ptype);
+		break;
+	case HAL_PARAM_GET_BUFFER_REQUIREMENTS:
+		rc = call_hfi_op(hdev, session_get_buf_req, inst->session);
+		break;
+	default:
+		rc = -EAGAIN;
+		break;
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Can't query hardware for property: %d\n",
+				rc);
+		goto exit;
+	}
+
+	rc = wait_for_completion_timeout(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+			"%s: Wait interrupted or timed out [%pK]: %d\n",
+			__func__, inst,
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
+		inst->state = MSM_VIDC_CORE_INVALID;
+		msm_comm_kill_session(inst);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -ETIMEDOUT;
+		goto exit;
+	} else {
+		/* wait_for_completion_timeout returns jiffies before expiry */
+		rc = 0;
+	}
+
+	mutex_lock(&inst->pending_getpropq.lock);
+	if (!list_empty(&inst->pending_getpropq.list)) {
+		buf = list_first_entry(&inst->pending_getpropq.list,
+					struct getprop_buf, list);
+		*hprop = *(union hal_get_property *)buf->data;
+		kfree(buf->data);
+		list_del(&buf->list);
+		kfree(buf);
+	} else {
+		dprintk(VIDC_ERR, "%s getprop list empty\n", __func__);
+		rc = -EINVAL;
+	}
+	mutex_unlock(&inst->pending_getpropq.lock);
+exit:
+	return rc;
+}
+
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct internal_buf *buf, *dummy;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	if (list_empty(&inst->outputbufs.list)) {
+		dprintk(VIDC_DBG, "%s - No OUTPUT buffers allocated\n",
+			__func__);
+		mutex_unlock(&inst->outputbufs.lock);
+		return 0;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry_safe(buf, dummy, &inst->outputbufs.list, list) {
+		handle = buf->handle;
+		if (!handle) {
+			dprintk(VIDC_ERR, "%s - invalid handle\n", __func__);
+			goto exit;
+		}
+
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->buffer_mode_set[CAPTURE_PORT] ==
+			HAL_BUFFER_MODE_STATIC &&
+			inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = false;
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel output buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+		}
+
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+
+exit:
+	mutex_unlock(&inst->outputbufs.lock);
+	return rc;
+}
+
+static enum hal_buffer scratch_buf_sufficient(struct msm_vidc_inst *inst,
+				enum hal_buffer buffer_type)
+{
+	struct hal_buffer_requirements *bufreq = NULL;
+	struct internal_buf *buf;
+	int count = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		goto not_sufficient;
+	}
+
+	bufreq = get_buff_req_buffer(inst, buffer_type);
+	if (!bufreq)
+		goto not_sufficient;
+
+	/* Check if current scratch buffers are sufficient */
+	mutex_lock(&inst->scratchbufs.lock);
+
+	list_for_each_entry(buf, &inst->scratchbufs.list, list) {
+		if (!buf->handle) {
+			dprintk(VIDC_ERR, "%s: invalid buf handle\n", __func__);
+			mutex_unlock(&inst->scratchbufs.lock);
+			goto not_sufficient;
+		}
+		if (buf->buffer_type == buffer_type &&
+			buf->handle->size >= bufreq->buffer_size)
+			count++;
+	}
+	mutex_unlock(&inst->scratchbufs.lock);
+
+	if (count != bufreq->buffer_count_actual)
+		goto not_sufficient;
+
+	dprintk(VIDC_DBG,
+		"Existing scratch buffer is sufficient for buffer type %#x\n",
+		buffer_type);
+
+	return buffer_type;
+
+not_sufficient:
+	return HAL_BUFFER_NONE;
+}
+
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+					bool check_for_reuse)
+{
+	struct msm_smem *handle;
+	struct internal_buf *buf, *dummy;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+	enum hal_buffer sufficiency = HAL_BUFFER_NONE;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	if (check_for_reuse) {
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH);
+
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH_1);
+
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH_2);
+	}
+
+	mutex_lock(&inst->scratchbufs.lock);
+	list_for_each_entry_safe(buf, dummy, &inst->scratchbufs.list, list) {
+		if (!buf->handle) {
+			dprintk(VIDC_ERR, "%s - buf->handle NULL\n", __func__);
+			rc = -EINVAL;
+			goto exit;
+		}
+
+		handle = buf->handle;
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = true;
+			init_completion(&inst->completions[SESSION_MSG_INDEX
+			   (HAL_SESSION_RELEASE_BUFFER_DONE)]);
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel scrtch buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+			mutex_unlock(&inst->scratchbufs.lock);
+			rc = wait_for_sess_signal_receipt(inst,
+				HAL_SESSION_RELEASE_BUFFER_DONE);
+			if (rc) {
+				change_inst_state(inst,
+					MSM_VIDC_CORE_INVALID);
+				msm_comm_kill_session(inst);
+			}
+			mutex_lock(&inst->scratchbufs.lock);
+		}
+
+		/*If scratch buffers can be reused, do not free the buffers*/
+		if (sufficiency & buf->buffer_type)
+			continue;
+
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+
+exit:
+	mutex_unlock(&inst->scratchbufs.lock);
+	return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->persistbufs.lock);
+	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		handle = buf->handle;
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = true;
+			init_completion(
+			   &inst->completions[SESSION_MSG_INDEX
+			   (HAL_SESSION_RELEASE_BUFFER_DONE)]);
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel prst buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+			mutex_unlock(&inst->persistbufs.lock);
+			rc = wait_for_sess_signal_receipt(inst,
+				HAL_SESSION_RELEASE_BUFFER_DONE);
+			if (rc) {
+				change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+				msm_comm_kill_session(inst);
+			}
+			mutex_lock(&inst->persistbufs.lock);
+		}
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+	mutex_unlock(&inst->persistbufs.lock);
+	return rc;
+}
+
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input: %pK\n", inst);
+		return -EINVAL;
+	}
+
+	if (!inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+		dprintk(VIDC_ERR, "Not in proper state to set property\n");
+		rc = -EAGAIN;
+		goto exit;
+	}
+	rc = call_hfi_op(hdev, session_set_property, (void *)inst->session,
+			ptype, pdata);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+	mutex_unlock(&inst->sync_lock);
+	return rc;
+}
+
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_comm_release_output_buffers(inst))
+		dprintk(VIDC_WARN, "Failed to release output buffers\n");
+
+	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
+	if (rc)
+		goto error;
+	return rc;
+error:
+	msm_comm_release_output_buffers(inst);
+	return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_comm_release_scratch_buffers(inst, true))
+		dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	return rc;
+error:
+	msm_comm_release_scratch_buffers(inst, false);
+	return rc;
+}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST,
+		&inst->persistbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1,
+		&inst->persistbufs);
+	if (rc)
+		goto error;
+	return rc;
+error:
+	msm_comm_release_persist_buffers(inst);
+	return rc;
+}
+
+static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst)
+{
+	struct list_head *ptr, *next;
+	enum vidc_ports ports[] = {OUTPUT_PORT, CAPTURE_PORT};
+	int c = 0;
+
+	for (c = 0; c < ARRAY_SIZE(ports); ++c) {
+		enum vidc_ports port = ports[c];
+
+		dprintk(VIDC_DBG, "Flushing buffers of type %d in bad state\n",
+				port);
+		mutex_lock(&inst->bufq[port].lock);
+		list_for_each_safe(ptr, next, &inst->bufq[port].
+				vb2_bufq.queued_list) {
+			struct vb2_buffer *vb = container_of(ptr,
+					struct vb2_buffer, queued_entry);
+
+			vb->planes[0].bytesused = 0;
+			vb->planes[0].data_offset = 0;
+
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		}
+		mutex_unlock(&inst->bufq[port].lock);
+	}
+
+	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+}
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *binfo = NULL;
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+		return;
+
+	/*
+	 * dynamic buffer mode:- if flush is called during seek
+	 * driver should not queue any new buffer it has been holding.
+	 *
+	 * Each dynamic o/p buffer can have one of following ref_count:
+	 * ref_count : 0 - f/w has released reference and sent fbd back.
+	 *		  The buffer has been returned back to client.
+	 *
+	 * ref_count : 1 - f/w is holding reference. f/w may have released
+	 *                 fbd as read_only OR fbd is pending. f/w will
+	 *		  release reference before sending flush_done.
+	 *
+	 * ref_count : 2 - f/w is holding reference, f/w has released fbd as
+	 *                 read_only, which client has queued back to driver.
+	 *                 driver holds this buffer and will queue back
+	 *                 only when f/w releases the reference. During
+	 *		  flush_done, f/w will release the reference but driver
+	 *		  should not queue back the buffer to f/w.
+	 *		  Flush all buffers with ref_count 2.
+	 */
+	mutex_lock(&inst->registeredbufs.lock);
+	if (!list_empty(&inst->registeredbufs.list)) {
+		struct v4l2_event buf_event = {0};
+		u32 *ptr = NULL;
+
+		list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+			if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+				atomic_read(&binfo->ref_count) == 2) {
+
+				atomic_dec(&binfo->ref_count);
+				buf_event.type =
+				V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+				ptr = (u32 *)buf_event.u.data;
+				ptr[0] = binfo->fd[0];
+				ptr[1] = binfo->buff_off[0];
+				ptr[2] = binfo->uvaddr[0];
+				ptr[3] = (u32) binfo->timestamp.tv_sec;
+				ptr[4] = (u32) binfo->timestamp.tv_usec;
+				ptr[5] = binfo->v4l2_index;
+				dprintk(VIDC_DBG,
+					"released buffer held in driver before issuing flush: %pa fd[0]: %d\n",
+					&binfo->device_addr[0], binfo->fd[0]);
+				/*send event to client*/
+				v4l2_event_queue_fh(&inst->event_handler,
+					&buf_event);
+			}
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+}
+
+void msm_comm_flush_pending_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *binfo = NULL;
+
+	if (!inst)
+		return;
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+		return;
+
+	if (list_empty(&inst->pendingq.list) ||
+		list_empty(&inst->registeredbufs.list))
+		return;
+
+	/*
+	 * Dynamic Buffer mode - Since pendingq is not empty
+	 * no output buffers have been sent to firmware yet.
+	 * Hence remove reference to all pendingq o/p buffers
+	 * before flushing them.
+	 */
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+		if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			dprintk(VIDC_DBG,
+				"%s: binfo = %pK device_addr = %pa\n",
+				__func__, binfo, &binfo->device_addr[0]);
+			buf_ref_put(inst, binfo);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+}
+
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
+{
+	int rc =  0;
+	bool ip_flush = false;
+	bool op_flush = false;
+	struct vb2_buf_entry *temp, *next;
+	struct mutex *lock;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
+	op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
+
+	if (ip_flush && !op_flush) {
+		dprintk(VIDC_INFO, "Input only flush not supported\n");
+		return 0;
+	}
+
+	msm_comm_flush_dynamic_buffers(inst);
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_ERR,
+				"Core %pK and inst %pK are in bad state\n",
+					core, inst);
+		msm_comm_flush_in_invalid_state(inst);
+		return 0;
+	}
+
+	if (inst->in_reconfig && !ip_flush && op_flush) {
+		mutex_lock(&inst->pendingq.lock);
+		if (!list_empty(&inst->pendingq.list)) {
+			/*
+			 * Execution can never reach here since port reconfig
+			 * wont happen unless pendingq is emptied out
+			 * (both pendingq and flush being secured with same
+			 * lock). Printing a message here incase this breaks.
+			 */
+			dprintk(VIDC_WARN,
+			"FLUSH BUG: Pending q not empty! It should be empty\n");
+		}
+		mutex_unlock(&inst->pendingq.lock);
+		atomic_inc(&inst->in_flush);
+		dprintk(VIDC_DBG, "Send flush Output to firmware\n");
+		rc = call_hfi_op(hdev, session_flush, inst->session,
+				HAL_FLUSH_OUTPUT);
+	} else {
+		msm_comm_flush_pending_dynamic_buffers(inst);
+		/*
+		 * If flush is called after queueing buffers but before
+		 * streamon driver should flush the pending queue
+		 */
+		mutex_lock(&inst->pendingq.lock);
+		list_for_each_entry_safe(temp, next,
+				&inst->pendingq.list, list) {
+			enum v4l2_buf_type type = temp->vb->type;
+
+			if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+				lock = &inst->bufq[CAPTURE_PORT].lock;
+			else
+				lock = &inst->bufq[OUTPUT_PORT].lock;
+
+			temp->vb->planes[0].bytesused = 0;
+
+			mutex_lock(lock);
+			vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
+			msm_vidc_debugfs_update(inst,
+				type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+					MSM_VIDC_DEBUGFS_EVENT_FBD :
+					MSM_VIDC_DEBUGFS_EVENT_EBD);
+			list_del(&temp->list);
+			mutex_unlock(lock);
+
+			kfree(temp);
+		}
+		mutex_unlock(&inst->pendingq.lock);
+
+		/*Do not send flush in case of session_error */
+		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+			  core->state != VIDC_CORE_INVALID))
+			atomic_inc(&inst->in_flush);
+			dprintk(VIDC_DBG, "Send flush all to firmware\n");
+			rc = call_hfi_op(hdev, session_flush, inst->session,
+				HAL_FLUSH_ALL);
+	}
+
+	return rc;
+}
+
+
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+	enum v4l2_mpeg_vidc_extradata index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case V4L2_MPEG_VIDC_EXTRADATA_NONE:
+		ret = HAL_EXTRADATA_NONE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION:
+		ret = HAL_EXTRADATA_MB_QUANTIZATION;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO:
+		ret = HAL_EXTRADATA_INTERLACE_VIDEO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP:
+		ret = HAL_EXTRADATA_VC1_FRAMEDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP:
+		ret = HAL_EXTRADATA_VC1_SEQDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP:
+		ret = HAL_EXTRADATA_TIMESTAMP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING:
+		ret = HAL_EXTRADATA_S3D_FRAME_PACKING;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE:
+		ret = HAL_EXTRADATA_FRAME_RATE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW:
+		ret = HAL_EXTRADATA_PANSCAN_WINDOW;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI:
+		ret = HAL_EXTRADATA_RECOVERY_POINT_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
+		ret = HAL_EXTRADATA_MULTISLICE_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
+		ret = HAL_EXTRADATA_NUM_CONCEALED_MB;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
+		ret = HAL_EXTRADATA_METADATA_FILLER;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
+		ret = HAL_EXTRADATA_ASPECT_RATIO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
+		ret = HAL_EXTRADATA_INPUT_CROP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
+		ret = HAL_EXTRADATA_DIGITAL_ZOOM;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
+		ret = HAL_EXTRADATA_MPEG2_SEQDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA:
+		ret = HAL_EXTRADATA_STREAM_USERDATA;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP:
+		ret = HAL_EXTRADATA_FRAME_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO:
+		ret = HAL_EXTRADATA_FRAME_BITS_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		ret = HAL_EXTRADATA_LTR_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+		ret = HAL_EXTRADATA_METADATA_MBI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI:
+		ret = HAL_EXTRADATA_VQZIP_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS:
+		ret = HAL_EXTRADATA_YUV_STATS;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP:
+		ret = HAL_EXTRADATA_ROI_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP:
+		ret = HAL_EXTRADATA_OUTPUT_CROP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI:
+		ret = HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI:
+		ret = HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY:
+		ret = HAL_EXTRADATA_VUI_DISPLAY_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE:
+		ret = HAL_EXTRADATA_VPX_COLORSPACE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO:
+		ret = HAL_EXTRADATA_PQ_INFO;
+		break;
+	default:
+		dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
+		break;
+	}
+	return ret;
+};
+
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+	enum v4l2_mpeg_vidc_video_mvc_layout index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL:
+		ret = HAL_BUFFER_LAYOUT_SEQ;
+		break;
+	case V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM:
+		ret = HAL_BUFFER_LAYOUT_TOP_BOTTOM;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_WARN, "Invalid parameters: %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (core->state == VIDC_CORE_INIT_DONE)
+		rc = call_hfi_op(hdev, core_trigger_ssr,
+				hdev->hfi_device_data, type);
+	return rc;
+}
+
+static int msm_vidc_load_supported(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_sec = 0, max_load_adj = 0;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD |
+		LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
+
+	if (inst->state == MSM_VIDC_OPEN_DONE) {
+		max_load_adj = inst->core->resources.max_load +
+			inst->capability.mbs_per_frame.max;
+		num_mbs_per_sec = msm_comm_get_load(inst->core,
+					MSM_VIDC_DECODER, quirks);
+		num_mbs_per_sec += msm_comm_get_load(inst->core,
+					MSM_VIDC_ENCODER, quirks);
+		if (num_mbs_per_sec > max_load_adj) {
+			dprintk(VIDC_ERR,
+				"H/W is overloaded. needed: %d max: %d\n",
+				num_mbs_per_sec,
+				max_load_adj);
+			msm_vidc_print_running_insts(inst->core);
+			return -EBUSY;
+		}
+	}
+	return 0;
+}
+
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+	u32 x_min, x_max, y_min, y_max;
+	u32 input_height, input_width, output_height, output_width;
+
+	input_height = inst->prop.height[OUTPUT_PORT];
+	input_width = inst->prop.width[OUTPUT_PORT];
+	output_height = inst->prop.height[CAPTURE_PORT];
+	output_width = inst->prop.width[CAPTURE_PORT];
+
+	if (!input_height || !input_width || !output_height || !output_width) {
+		dprintk(VIDC_ERR,
+			"Invalid : Input height = %d width = %d output height = %d width = %d\n",
+			input_height, input_width, output_height,
+			output_width);
+		return -ENOTSUPP;
+	}
+
+	if (!inst->capability.scale_x.min ||
+		!inst->capability.scale_x.max ||
+		!inst->capability.scale_y.min ||
+		!inst->capability.scale_y.max) {
+
+		if (input_width * input_height !=
+			output_width * output_height) {
+			dprintk(VIDC_ERR,
+				"%s: scaling is not supported (%dx%d != %dx%d)\n",
+				__func__, input_width, input_height,
+				output_width, output_height);
+			return -ENOTSUPP;
+		}
+		dprintk(VIDC_DBG, "%s: supported WxH = %dx%d\n",
+			__func__, input_width, input_height);
+		return 0;
+	}
+
+	x_min = (1<<16)/inst->capability.scale_x.min;
+	y_min = (1<<16)/inst->capability.scale_y.min;
+	x_max = inst->capability.scale_x.max >> 16;
+	y_max = inst->capability.scale_y.max >> 16;
+
+	if (input_height > output_height) {
+		if (input_height > x_min * output_height) {
+			dprintk(VIDC_ERR,
+				"Unsupported height downscale ratio %d vs %d\n",
+				input_height/output_height, x_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (output_height > x_max * input_height) {
+			dprintk(VIDC_ERR,
+				"Unsupported height upscale ratio %d vs %d\n",
+				input_height/output_height, x_max);
+			return -ENOTSUPP;
+		}
+	}
+	if (input_width > output_width) {
+		if (input_width > y_min * output_width) {
+			dprintk(VIDC_ERR,
+				"Unsupported width downscale ratio %d vs %d\n",
+				input_width/output_width, y_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (output_width > y_max * input_width) {
+			dprintk(VIDC_ERR,
+				"Unsupported width upscale ratio %d vs %d\n",
+				input_width/output_width, y_max);
+			return -ENOTSUPP;
+		}
+	}
+	return 0;
+}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_capability *capability;
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	int mbs_per_frame = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+	capability = &inst->capability;
+	hdev = inst->core->device;
+	core = inst->core;
+	rc = msm_vidc_load_supported(inst);
+	if (rc) {
+		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+		msm_comm_kill_session(inst);
+		dprintk(VIDC_WARN,
+			"%s: Hardware is overloaded\n", __func__);
+		return rc;
+	}
+
+	if (!is_thermal_permissible(core)) {
+		dprintk(VIDC_WARN,
+			"Thermal level critical, stop all active sessions!\n");
+		return -ENOTSUPP;
+	}
+
+	if (!rc) {
+		if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+			inst->prop.height[CAPTURE_PORT] <
+			capability->height.min) {
+			dprintk(VIDC_ERR,
+				"Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+				inst->prop.width[CAPTURE_PORT],
+				inst->prop.height[CAPTURE_PORT],
+				capability->width.min,
+				capability->height.min);
+			rc = -ENOTSUPP;
+		}
+		if (!rc && inst->prop.width[CAPTURE_PORT] >
+			capability->width.max) {
+			dprintk(VIDC_ERR,
+				"Unsupported width = %u supported max width = %u",
+				inst->prop.width[CAPTURE_PORT],
+				capability->width.max);
+				rc = -ENOTSUPP;
+		}
+
+		if (!rc && inst->prop.height[CAPTURE_PORT] >
+			capability->height.max) {
+			dprintk(VIDC_ERR,
+				"Unsupported height = %u supported max height = %u",
+				inst->prop.height[CAPTURE_PORT],
+				capability->height.max);
+				rc = -ENOTSUPP;
+		}
+
+		mbs_per_frame = msm_comm_get_mbs_per_frame(inst);
+		if (!rc && mbs_per_frame > capability->mbs_per_frame.max) {
+			dprintk(VIDC_ERR,
+			"Unsupported mbs per frame = %u, max supported is - %u\n",
+			mbs_per_frame,
+			capability->mbs_per_frame.max);
+			rc = -ENOTSUPP;
+		}
+	}
+	if (rc) {
+		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+		msm_comm_kill_session(inst);
+		dprintk(VIDC_ERR,
+			"%s: Resolution unsupported\n", __func__);
+	}
+	return rc;
+}
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+	enum hal_command_response cmd = HAL_SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
+	dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+
+	response.session_id = inst;
+	response.status = VIDC_ERR_FAIL;
+	handle_session_error(cmd, (void *)&response);
+}
+
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	enum hal_command_response cmd = HAL_SYS_ERROR;
+	struct msm_vidc_cb_cmd_done response  = {0};
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+	core = inst->core;
+	response.device_id = (u32) core->id;
+	handle_sys_error(cmd, (void *) &response);
+
+}
+
+int msm_comm_kill_session(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return -EINVAL;
+	} else if (!inst->session) {
+		/* There's no hfi session to kill */
+		return 0;
+	}
+
+	/*
+	 * We're internally forcibly killing the session, if fw is aware of
+	 * the session send session_abort to firmware to clean up and release
+	 * the session, else just kill the session inside the driver.
+	 */
+	if ((inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_CLOSE_DONE) ||
+			inst->state == MSM_VIDC_CORE_INVALID) {
+		rc = msm_comm_session_abort(inst);
+		if (rc == -EBUSY) {
+			msm_comm_generate_sys_error(inst);
+			return 0;
+		} else if (rc) {
+			return rc;
+		}
+		change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+		msm_comm_generate_session_error(inst);
+	} else {
+		dprintk(VIDC_WARN,
+				"Inactive session %pK, triggering an internal session error\n",
+				inst);
+		msm_comm_generate_session_error(inst);
+
+	}
+
+	return rc;
+}
+
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+			size_t size, u32 align, u32 flags,
+			enum hal_buffer buffer_type, int map_kernel)
+{
+	struct msm_smem *m = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return NULL;
+	}
+	m = msm_smem_alloc(inst->mem_client, size, align,
+				flags, buffer_type, map_kernel);
+	return m;
+}
+
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
+{
+	if (!inst || !inst->core || !mem) {
+		dprintk(VIDC_ERR,
+			"%s: invalid params: %pK %pK\n", __func__, inst, mem);
+		return;
+	}
+	msm_smem_free(inst->mem_client, mem);
+}
+
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+		struct msm_smem *mem, enum smem_cache_ops cache_ops)
+{
+	if (!inst || !mem) {
+		dprintk(VIDC_ERR,
+			"%s: invalid params: %pK %pK\n", __func__, inst, mem);
+		return -EINVAL;
+	}
+	return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+}
+
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+			int fd, u32 offset, enum hal_buffer buffer_type)
+{
+	struct msm_smem *m = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return NULL;
+	}
+
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR, "Core in Invalid state, returning from %s\n",
+			__func__);
+		return NULL;
+	}
+
+	m = msm_smem_user_to_kernel(inst->mem_client,
+			fd, offset, buffer_type);
+	return m;
+}
+
+void msm_vidc_fw_unload_handler(struct work_struct *work)
+{
+	struct msm_vidc_core *core = NULL;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	core = container_of(work, struct msm_vidc_core, fw_unload_work.work);
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+				__func__);
+		return;
+	}
+
+	hdev = core->device;
+
+	mutex_lock(&core->lock);
+	if (list_empty(&core->instances) &&
+		core->state != VIDC_CORE_UNINIT) {
+		if (core->state > VIDC_CORE_INIT) {
+			dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
+			rc = call_hfi_op(hdev, core_release,
+					hdev->hfi_device_data);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to release core, id = %d\n",
+					core->id);
+				mutex_unlock(&core->lock);
+				return;
+			}
+		}
+		core->state = VIDC_CORE_UNINIT;
+		kfree(core->capabilities);
+		core->capabilities = NULL;
+	}
+	mutex_unlock(&core->lock);
+}
+
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, int fourcc)
+{
+	struct hal_uncompressed_format_select hal_fmt = {0};
+	enum hal_uncompressed_format format = HAL_UNUSED_COLOR;
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	format = get_hal_uncompressed(fourcc);
+	if (format == HAL_UNUSED_COLOR) {
+		dprintk(VIDC_ERR, "Using unsupported colorformat %#x\n",
+				fourcc);
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	hal_fmt.buffer_type = buffer_type;
+	hal_fmt.format = format;
+
+	rc = call_hfi_op(hdev, session_set_property, inst->session,
+		HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to set input color format\n");
+	else
+		dprintk(VIDC_DBG, "Setting uncompressed colorformat to %#x\n",
+				format);
+
+exit:
+	return rc;
+}
+
+int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+	u32 property_id = 0;
+	u64 us_per_frame = 0;
+	void *pdata;
+	int rc = 0, fps = 0;
+	struct hal_frame_rate frame_rate;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device || !a) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	property_id = HAL_CONFIG_FRAME_RATE;
+
+	if (a->parm.output.timeperframe.denominator) {
+		switch (a->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			us_per_frame = a->parm.output.timeperframe.numerator *
+				(u64)USEC_PER_SEC;
+			do_div(us_per_frame, a->parm.output.
+				timeperframe.denominator);
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Scale clocks : Unknown buffer type %d\n",
+					a->type);
+			break;
+		}
+	}
+
+	if (!us_per_frame) {
+		dprintk(VIDC_ERR,
+				"Failed to scale clocks : time between frames is 0\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	fps = USEC_PER_SEC;
+	do_div(fps, us_per_frame);
+
+	if (fps % 15 == 14 || fps % 24 == 23)
+		fps = fps + 1;
+	else if ((fps > 1) && (fps % 24 == 1 || fps % 15 == 1))
+		fps = fps - 1;
+
+	if (inst->prop.fps != fps) {
+		dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
+				inst, inst->prop.fps, fps);
+		inst->prop.fps = fps;
+		frame_rate.frame_rate = inst->prop.fps * BIT(16);
+		frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &frame_rate;
+		if (inst->session_type == MSM_VIDC_ENCODER) {
+			rc = call_hfi_op(hdev, session_set_property,
+				inst->session, property_id, pdata);
+
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed to set frame rate %d\n", rc);
+		} else {
+			msm_dcvs_init_load(inst);
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+	}
+exit:
+	return rc;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h
new file mode 100644
index 0000000..9b71709
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h
@@ -0,0 +1,103 @@
+/*Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+	struct list_head list;
+	struct vb2_buffer *vb;
+};
+
+extern const char *const mpeg_video_vidc_extradata[];
+
+enum load_calc_quirks {
+	LOAD_CALC_NO_QUIRKS = 0,
+	LOAD_CALC_IGNORE_TURBO_LOAD = 1 << 0,
+	LOAD_CALC_IGNORE_THUMBNAIL_LOAD = 1 << 1,
+	LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2,
+};
+
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct buf_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata);
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, union hal_get_property *hprop);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
+int msm_comm_scale_clocks(struct msm_vidc_core *core);
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core,
+		int num_mbs_per_sec, enum load_calc_quirks quirks);
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst);
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+					bool check_for_reuse);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
+int msm_comm_suspend(int core_id);
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+	enum v4l2_mpeg_vidc_extradata index);
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+	enum v4l2_mpeg_vidc_video_mvc_layout index);
+struct hal_buffer_requirements *get_buff_req_buffer(
+			struct msm_vidc_inst *inst, u32 buffer_type);
+#define IS_PRIV_CTRL(idx) (\
+		(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \
+		V4L2_CTRL_DRIVER_PRIV(idx))
+void msm_comm_session_clean(struct msm_vidc_inst *inst);
+int msm_comm_kill_session(struct msm_vidc_inst *inst);
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+			size_t size, u32 align, u32 flags,
+			enum hal_buffer buffer_type, int map_kernel);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+		struct msm_smem *mem, enum smem_cache_ops cache_ops);
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+			int fd, u32 offset, enum hal_buffer buffer_type);
+enum hal_video_codec get_hal_codec(int fourcc);
+enum hal_domain get_hal_domain(int session_type);
+int msm_comm_check_core_init(struct msm_vidc_core *core);
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+			enum load_calc_quirks quirks);
+int msm_comm_get_load(struct msm_vidc_core *core,
+			enum session_type type, enum load_calc_quirks quirks);
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, int fourcc);
+int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
+int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
+int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id);
+int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
+		struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
+		const struct v4l2_ctrl_ops *ctrl_ops);
+int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst);
+void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst);
+int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+bool msm_comm_turbo_session(struct msm_vidc_inst *inst);
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, void *session_id);
+void put_inst(struct msm_vidc_inst *inst);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c
new file mode 100644
index 0000000..ac338e1
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c
@@ -0,0 +1,703 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_VALID_DCVS_SESSION(__cur_mbpf, __min_mbpf) \
+		((__cur_mbpf) >= (__min_mbpf))
+
+static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst);
+static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst);
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst);
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd);
+
+static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int height, width;
+
+	if (!inst->in_reconfig) {
+		height = max(inst->prop.height[CAPTURE_PORT],
+				inst->prop.height[OUTPUT_PORT]);
+		width = max(inst->prop.width[CAPTURE_PORT],
+				inst->prop.width[OUTPUT_PORT]);
+	} else {
+		height = inst->reconfig_height;
+		width = inst->reconfig_width;
+	}
+
+	return NUM_MBS_PER_FRAME(height, width);
+}
+
+static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core)
+{
+	int active_instances = 0;
+	struct msm_vidc_inst *inst = NULL;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s: Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_STOP_DONE)
+			active_instances++;
+	}
+	mutex_unlock(&core->lock);
+	return active_instances;
+}
+
+static bool msm_dcvs_check_codec_supported(int fourcc,
+		unsigned long codecs_supported, enum session_type type)
+{
+	int codec_bit, session_type_bit;
+	bool codec_type, session_type;
+	unsigned long session;
+
+	session = VIDC_VOTE_DATA_SESSION_VAL(get_hal_codec(fourcc),
+		get_hal_domain(type));
+
+	if (!codecs_supported || !session)
+		return false;
+
+	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
+	codec_bit = ffs(session) - 1;
+	session_type_bit = codec_bit + 1;
+
+	codec_type =
+		test_bit(codec_bit, &codecs_supported) ==
+		test_bit(codec_bit, &session);
+	session_type =
+		test_bit(session_type_bit, &codecs_supported) ==
+		test_bit(session_type_bit, &session);
+
+	return codec_type && session_type;
+}
+
+static void msm_dcvs_update_dcvs_params(int idx, struct msm_vidc_inst *inst)
+{
+	struct dcvs_stats *dcvs = NULL;
+	struct msm_vidc_platform_resources *res = NULL;
+	struct dcvs_table *table = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	dcvs = &inst->dcvs;
+	res = &inst->core->resources;
+	table = res->dcvs_tbl;
+
+	dcvs->load_low = table[idx].load_low;
+	dcvs->load_high = table[idx].load_high;
+	dcvs->supported_codecs = table[idx].supported_codecs;
+}
+
+static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (inst->session_type == MSM_VIDC_ENCODER && msm_vidc_enc_dcvs_mode) {
+		inst->dcvs_mode = msm_dcvs_check_supported(inst);
+		dprintk(VIDC_DBG, "%s: session DCVS %s supported\n",
+				__func__, inst->dcvs_mode ? "" : "not");
+
+		if (inst->dcvs_mode) {
+			rc = msm_dcvs_enc_scale_clocks(inst);
+			if (rc) {
+				dprintk(VIDC_DBG,
+				"ENC_DCVS: error while scaling clocks\n");
+			}
+		}
+	}
+}
+
+static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (inst->session_type != MSM_VIDC_DECODER || !msm_vidc_dec_dcvs_mode)
+		return;
+
+	if (msm_dcvs_check_supported(inst)) {
+		inst->dcvs_mode = true;
+		dprintk(VIDC_DBG,
+			"%s: session DCVS supported, decode_dcvs_mode = %d\n",
+			__func__, inst->dcvs_mode);
+	} else {
+		inst->dcvs_mode = false;
+		dprintk(VIDC_DBG,
+			"%s: session DCVS not supported, decode_dcvs_mode = %d\n",
+			__func__, inst->dcvs_mode);
+	}
+
+	if (msm_vidc_dec_dcvs_mode && inst->dcvs_mode) {
+		msm_dcvs_monitor_buffer(inst);
+		rc = msm_dcvs_dec_scale_clocks(inst, false);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to scale clocks in DCVS: %d\n",
+				__func__, rc);
+		}
+	}
+}
+
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	if (is_etb)
+		msm_dcvs_enc_check_and_scale_clocks(inst);
+	else
+		msm_dcvs_dec_check_and_scale_clocks(inst);
+}
+
+static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
+{
+	int fw_out_qsize = 0, buffers_in_driver = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->state >= MSM_VIDC_OPEN_DONE &&
+		inst->state < MSM_VIDC_STOP_DONE) {
+		fw_out_qsize = inst->count.ftb - inst->count.fbd;
+		buffers_in_driver = inst->buffers_held_in_driver;
+	}
+
+	return fw_out_qsize + buffers_in_driver;
+}
+
+static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
+{
+	dprintk(VIDC_DBG,
+		"DCVS: Load_Low %d, Load High %d\n",
+		dcvs->load_low,
+		dcvs->load_high);
+
+	dprintk(VIDC_DBG,
+		"DCVS: ThrDispBufLow %d, ThrDispBufHigh %d\n",
+		dcvs->threshold_disp_buf_low,
+		dcvs->threshold_disp_buf_high);
+
+	dprintk(VIDC_DBG,
+		"DCVS: min_threshold %d, max_threshold %d\n",
+		dcvs->min_threshold, dcvs->max_threshold);
+}
+
+void msm_dcvs_init_load(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+	struct dcvs_table *table;
+	struct msm_vidc_platform_resources *res = NULL;
+	int i, num_rows, fourcc;
+
+	dprintk(VIDC_DBG, "Init DCVS Load\n");
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	res = &core->resources;
+	dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+
+	num_rows = res->dcvs_tbl_size;
+	table = res->dcvs_tbl;
+
+	if (!num_rows || !table) {
+		dprintk(VIDC_ERR,
+				"%s: Dcvs table entry not found.\n", __func__);
+		return;
+	}
+
+	fourcc = inst->session_type == MSM_VIDC_DECODER ?
+				inst->fmts[OUTPUT_PORT].fourcc :
+				inst->fmts[CAPTURE_PORT].fourcc;
+
+	for (i = 0; i < num_rows; i++) {
+		bool matches = msm_dcvs_check_codec_supported(
+					fourcc,
+					table[i].supported_codecs,
+					inst->session_type);
+		if (!matches)
+			continue;
+
+		if (dcvs->load > table[i].load) {
+			msm_dcvs_update_dcvs_params(i, inst);
+			break;
+		}
+	}
+
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		goto print_stats;
+
+	output_buf_req = get_buff_req_buffer(inst,
+		msm_comm_get_hal_output_buffer(inst));
+
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR,
+			"%s: No buffer requirement for buffer type %x\n",
+			__func__, HAL_BUFFER_OUTPUT);
+		return;
+	}
+
+	dcvs->transition_turbo = false;
+
+	/* calculating the min and max threshold */
+	if (output_buf_req->buffer_count_actual) {
+		dcvs->min_threshold = output_buf_req->buffer_count_actual -
+			output_buf_req->buffer_count_min -
+			msm_dcvs_get_extra_buff_count(inst) + 1;
+		dcvs->max_threshold = output_buf_req->buffer_count_actual;
+		if (dcvs->max_threshold <= dcvs->min_threshold)
+			dcvs->max_threshold =
+				dcvs->min_threshold + DCVS_BUFFER_SAFEGUARD;
+		dcvs->threshold_disp_buf_low = dcvs->min_threshold;
+		dcvs->threshold_disp_buf_high = dcvs->max_threshold;
+	}
+
+print_stats:
+	msm_dcvs_print_dcvs_stats(dcvs);
+}
+
+void msm_dcvs_init(struct msm_vidc_inst *inst)
+{
+	dprintk(VIDC_DBG, "Init DCVS Struct\n");
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	inst->dcvs = (struct dcvs_stats){ {0} };
+	inst->dcvs.threshold_disp_buf_high = DCVS_NOMINAL_THRESHOLD;
+	inst->dcvs.threshold_disp_buf_low = DCVS_TURBO_THRESHOLD;
+}
+
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst)
+{
+	int new_ftb, i, prev_buf_count;
+	int fw_pending_bufs, total_output_buf, buffers_outside_fw;
+	struct dcvs_stats *dcvs;
+	struct hal_buffer_requirements *output_buf_req;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+	dcvs = &inst->dcvs;
+
+	mutex_lock(&inst->lock);
+	output_buf_req = get_buff_req_buffer(inst,
+				msm_comm_get_hal_output_buffer(inst));
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR, "%s : Get output buffer req failed %pK\n",
+			__func__, inst);
+		mutex_unlock(&inst->lock);
+		return;
+	}
+
+	total_output_buf = output_buf_req->buffer_count_actual;
+	fw_pending_bufs = get_pending_bufs_fw(inst);
+	mutex_unlock(&inst->lock);
+
+	buffers_outside_fw = total_output_buf - fw_pending_bufs;
+	dcvs->num_ftb[dcvs->ftb_index] = buffers_outside_fw;
+	dcvs->ftb_index = (dcvs->ftb_index + 1) % DCVS_FTB_WINDOW;
+
+	if (dcvs->ftb_counter < DCVS_FTB_WINDOW)
+		dcvs->ftb_counter++;
+
+	dprintk(VIDC_PROF,
+		"DCVS: ftb_counter %d\n", dcvs->ftb_counter);
+
+	if (dcvs->ftb_counter == DCVS_FTB_WINDOW) {
+		new_ftb = 0;
+		for (i = 0; i < dcvs->ftb_counter; i++) {
+			if (dcvs->num_ftb[i] > new_ftb)
+				new_ftb = dcvs->num_ftb[i];
+		}
+
+		dcvs->threshold_disp_buf_high = new_ftb;
+		if (dcvs->threshold_disp_buf_high <=
+			dcvs->threshold_disp_buf_low +
+			DCVS_BUFFER_SAFEGUARD) {
+			dcvs->threshold_disp_buf_high =
+				dcvs->threshold_disp_buf_low +
+				DCVS_BUFFER_SAFEGUARD
+				+ (DCVS_BUFFER_SAFEGUARD == 0);
+		}
+
+		dcvs->threshold_disp_buf_high =
+			clamp(dcvs->threshold_disp_buf_high,
+				dcvs->min_threshold,
+				dcvs->max_threshold);
+	}
+
+	if (dcvs->ftb_counter == DCVS_FTB_WINDOW &&
+			dcvs->load == dcvs->load_low) {
+		prev_buf_count =
+			dcvs->num_ftb[((dcvs->ftb_index - 2 +
+				DCVS_FTB_WINDOW) % DCVS_FTB_WINDOW)];
+		if (prev_buf_count == dcvs->threshold_disp_buf_low &&
+			buffers_outside_fw <= dcvs->threshold_disp_buf_low) {
+			dcvs->transition_turbo = true;
+		} else if (buffers_outside_fw > dcvs->threshold_disp_buf_low &&
+			(buffers_outside_fw -
+			 (prev_buf_count - buffers_outside_fw))
+			< dcvs->threshold_disp_buf_low){
+			dcvs->transition_turbo = true;
+		}
+	}
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_output_buf %d buffers_outside_fw %d load %d transition_turbo %d\n",
+		total_output_buf, buffers_outside_fw, dcvs->load_low,
+		dcvs->transition_turbo);
+}
+
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0, fw_pending_bufs = 0, total_input_buf = 0;
+	struct msm_vidc_core *core;
+	struct dcvs_stats *dcvs;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+
+	mutex_lock(&inst->lock);
+	total_input_buf = inst->buff_req.buffer[0].buffer_count_actual;
+	fw_pending_bufs = (inst->count.etb - inst->count.ebd);
+	mutex_unlock(&inst->lock);
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_input_buf %d, fw_pending_bufs %d\n",
+		total_input_buf, fw_pending_bufs);
+
+	if (dcvs->etb_counter < total_input_buf) {
+		dcvs->etb_counter++;
+		if (dcvs->etb_counter != total_input_buf)
+			return rc;
+	}
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_input_buf %d, fw_pending_bufs %d etb_counter %d  dcvs->load %d\n",
+		total_input_buf, fw_pending_bufs,
+		dcvs->etb_counter, dcvs->load);
+
+	if (fw_pending_bufs <= DCVS_ENC_LOW_THR &&
+		dcvs->load > dcvs->load_low) {
+		dcvs->load = dcvs->load_low;
+		dcvs->prev_freq_lowered = true;
+	} else {
+		dcvs->prev_freq_lowered = false;
+	}
+
+	if (fw_pending_bufs >= DCVS_ENC_HIGH_THR &&
+		dcvs->load <= dcvs->load_low) {
+		dcvs->load = dcvs->load_high;
+		dcvs->prev_freq_increased = true;
+	} else {
+		dcvs->prev_freq_increased = false;
+	}
+
+	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+		dprintk(VIDC_PROF,
+			"DCVS: (Scaling Clock %s)  etb clock set = %d total_input_buf = %d fw_pending_bufs %d\n",
+			dcvs->prev_freq_lowered ? "Lower" : "Higher",
+			dcvs->load, total_input_buf, fw_pending_bufs);
+
+		rc = msm_comm_scale_clocks_load(core, dcvs->load,
+				LOAD_CALC_NO_QUIRKS);
+		if (rc) {
+			dprintk(VIDC_PROF,
+				"Failed to set clock rate in FBD: %d\n", rc);
+		}
+	} else {
+		dprintk(VIDC_PROF,
+			"DCVS: etb clock load_old = %d total_input_buf = %d fw_pending_bufs %d\n",
+			dcvs->load, total_input_buf, fw_pending_bufs);
+	}
+
+	return rc;
+}
+
+
+/*
+ * In DCVS scale_clocks will be done both in qbuf and FBD
+ * 1 indicates call made from fbd that lowers clock
+ * 0 indicates call made from qbuf that increases clock
+ * based on DCVS algorithm
+ */
+
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd)
+{
+	int rc = 0;
+	int fw_pending_bufs = 0;
+	int total_output_buf = 0;
+	int buffers_outside_fw = 0;
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	mutex_lock(&inst->lock);
+	fw_pending_bufs = get_pending_bufs_fw(inst);
+
+	output_buf_req = get_buff_req_buffer(inst,
+		msm_comm_get_hal_output_buffer(inst));
+	mutex_unlock(&inst->lock);
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR,
+			"%s: No buffer requirement for buffer type %x\n",
+			__func__, HAL_BUFFER_OUTPUT);
+		return -EINVAL;
+	}
+
+	/* Total number of output buffers */
+	total_output_buf = output_buf_req->buffer_count_actual;
+
+	/* Buffers outside FW are with display */
+	buffers_outside_fw = total_output_buf - fw_pending_bufs;
+
+	if (buffers_outside_fw >= dcvs->threshold_disp_buf_high &&
+		!dcvs->prev_freq_increased &&
+		dcvs->load > dcvs->load_low) {
+		dcvs->load = dcvs->load_low;
+		dcvs->prev_freq_lowered = true;
+		dcvs->prev_freq_increased = false;
+	} else if (dcvs->transition_turbo && dcvs->load == dcvs->load_low) {
+		dcvs->load = dcvs->load_high;
+		dcvs->prev_freq_increased = true;
+		dcvs->prev_freq_lowered = false;
+		dcvs->transition_turbo = false;
+	} else {
+		dcvs->prev_freq_increased = false;
+		dcvs->prev_freq_lowered = false;
+	}
+
+	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+		dprintk(VIDC_PROF,
+			"DCVS: clock set = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+			dcvs->load, total_output_buf, buffers_outside_fw,
+			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+
+		rc = msm_comm_scale_clocks_load(core, dcvs->load,
+				LOAD_CALC_NO_QUIRKS);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set clock rate in FBD: %d\n", rc);
+		}
+	} else {
+		dprintk(VIDC_PROF,
+			"DCVS: clock old = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+			dcvs->load, total_output_buf, buffers_outside_fw,
+			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+	}
+	return rc;
+}
+
+static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_frame = 0;
+	long int instance_load = 0;
+	long int dcvs_limit = 0;
+	bool dcvs_check_passed = false, is_codec_supported  = false;
+	struct msm_vidc_platform_resources *res = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return dcvs_check_passed;
+	}
+
+	res = &inst->core->resources;
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_ERR,
+			"%s Dcvs limit table uninitialized\n", __func__);
+		return false;
+	}
+
+	is_codec_supported =
+		msm_dcvs_check_codec_supported(
+				inst->fmts[CAPTURE_PORT].fourcc,
+				inst->dcvs.supported_codecs,
+				inst->session_type);
+
+	num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+	instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+	dcvs_limit =
+		(long int)res->dcvs_limit[inst->session_type].min_mbpf *
+		res->dcvs_limit[inst->session_type].fps;
+
+	if (msm_vidc_enc_dcvs_mode && is_codec_supported &&
+		inst->dcvs.is_power_save_mode &&
+		IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+			res->dcvs_limit[inst->session_type].min_mbpf) &&
+		IS_VALID_DCVS_SESSION(instance_load, dcvs_limit)) {
+		dcvs_check_passed = true;
+	}
+	return dcvs_check_passed;
+}
+
+static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_frame = 0, instance_count = 0;
+	long int instance_load = 0;
+	long int dcvs_limit = 0;
+	struct msm_vidc_inst *temp = NULL;
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+	bool is_codec_supported = false;
+	struct msm_vidc_platform_resources *res = NULL;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	res = &core->resources;
+
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_WARN,
+				"%s: dcvs limit table not found\n", __func__);
+		return false;
+	}
+	instance_count = msm_dcvs_count_active_instances(core);
+
+	if (instance_count == 1 && inst->session_type == MSM_VIDC_DECODER &&
+		!msm_comm_turbo_session(inst)) {
+		num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+		instance_load = msm_comm_get_inst_load(inst,
+			LOAD_CALC_NO_QUIRKS);
+		output_buf_req = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
+		dcvs_limit =
+			(long int)res->dcvs_limit[inst->session_type].min_mbpf *
+			res->dcvs_limit[inst->session_type].fps;
+		is_codec_supported =
+			msm_dcvs_check_codec_supported(
+					inst->fmts[OUTPUT_PORT].fourcc,
+					inst->dcvs.supported_codecs,
+					inst->session_type);
+		if (!is_codec_supported ||
+			!IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+				res->dcvs_limit[inst->session_type].min_mbpf) ||
+			!IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) ||
+			inst->seqchanged_count > 1)
+			return false;
+
+		if (!output_buf_req) {
+			dprintk(VIDC_ERR,
+				"%s: No buffer requirement for buffer type %x\n",
+				__func__, HAL_BUFFER_OUTPUT);
+			return false;
+		}
+	} else if (instance_count == 1 &&
+			inst->session_type == MSM_VIDC_ENCODER &&
+			!msm_comm_turbo_session(inst)) {
+		if (!msm_dcvs_enc_check(inst))
+			return false;
+	} else {
+		/*
+		 * For multiple instance use case with 4K, clocks will be scaled
+		 * as per load in streamon, but the clocks may be scaled
+		 * down as DCVS is running for first playback instance
+		 * Rescaling the core clock for multiple instance use case
+		 */
+		if (!dcvs->is_clock_scaled) {
+			if (!msm_comm_scale_clocks(core)) {
+				dcvs->is_clock_scaled = true;
+				dprintk(VIDC_DBG,
+					"%s: Scaled clocks = %d\n",
+					__func__, dcvs->is_clock_scaled);
+			} else {
+				dprintk(VIDC_DBG,
+					"%s: Failed to Scale clocks. Perf might be impacted\n",
+					__func__);
+			}
+		}
+		/*
+		 * For multiple instance use case turn OFF DCVS algorithm
+		 * immediately
+		 */
+		if (instance_count > 1) {
+			mutex_lock(&core->lock);
+			list_for_each_entry(temp, &core->instances, list)
+				temp->dcvs_mode = false;
+			mutex_unlock(&core->lock);
+		}
+
+		return false;
+	}
+
+	return true;
+}
+
+int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst)
+{
+	int extra_buffer = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return 0;
+	}
+
+	if (inst->session_type == MSM_VIDC_ENCODER) {
+		if (msm_dcvs_enc_check(inst))
+			extra_buffer = DCVS_ENC_EXTRA_OUTPUT_BUFFERS;
+	} else if (inst->session_type == MSM_VIDC_DECODER) {
+		if (msm_dcvs_check_supported(inst))
+			extra_buffer = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+	}
+	return extra_buffer;
+}
+
+
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+					bool is_power_save_mode)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return;
+	}
+
+	inst->dcvs.is_power_save_mode = is_power_save_mode;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h
new file mode 100644
index 0000000..0f4d69e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_DCVS_H_
+#define _MSM_VIDC_DCVS_H_
+#include "msm_vidc_internal.h"
+
+/* Low threshold for encoder dcvs */
+#define DCVS_ENC_LOW_THR 4
+/* High threshold for encoder dcvs */
+#define DCVS_ENC_HIGH_THR 9
+/* extra o/p buffers in case of encoder dcvs */
+#define DCVS_ENC_EXTRA_OUTPUT_BUFFERS 2
+/* extra o/p buffers in case of decoder dcvs */
+#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
+/* Default threshold to reduce the core frequency */
+#define DCVS_NOMINAL_THRESHOLD 8
+/* Default threshold to increase the core frequency */
+#define DCVS_TURBO_THRESHOLD 4
+
+/* Considering one safeguard buffer */
+#define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)
+
+void msm_dcvs_init(struct msm_vidc_inst *inst);
+void msm_dcvs_init_load(struct msm_vidc_inst *inst);
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst);
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb);
+int  msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst);
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+		bool is_power_save_mode);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c
new file mode 100644
index 0000000..57e84bc
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c
@@ -0,0 +1,550 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define CREATE_TRACE_POINTS
+#include "msm_vidc_common.h"
+#define MAX_SSR_STRING_LEN 10
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
+int msm_vidc_fw_debug = 0x18;
+int msm_vidc_fw_debug_mode = 1;
+int msm_vidc_fw_low_power_mode = 1;
+int msm_vidc_hw_rsp_timeout = 1000;
+bool msm_vidc_fw_coverage = true;
+bool msm_vidc_dec_dcvs_mode = true;
+bool msm_vidc_enc_dcvs_mode = true;
+bool msm_vidc_sys_idle_indicator = true;
+int msm_vidc_firmware_unload_delay = 15000;
+bool msm_vidc_thermal_mitigation_disabled = true;
+bool msm_vidc_bitrate_clock_scaling = 1;
+bool msm_vidc_debug_timeout = true;
+
+#define MAX_DBG_BUF_SIZE 4096
+
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+	atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
+struct core_inst_pair {
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+};
+
+static int core_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static u32 write_str(char *buffer,
+		size_t size, const char *fmt, ...)
+{
+	va_list args;
+	u32 len;
+
+	va_start(args, fmt);
+	len = vscnprintf(buffer, size, fmt, args);
+	va_end(args);
+	return len;
+}
+
+static ssize_t core_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct msm_vidc_core *core = file->private_data;
+	struct hfi_device *hdev;
+	struct hal_fw_info fw_info = { {0} };
+	char *dbuf, *cur, *end;
+	int i = 0, rc = 0;
+	ssize_t len = 0;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
+		return 0;
+	}
+
+	dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
+	if (!dbuf) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		return -ENOMEM;
+	}
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+	hdev = core->device;
+
+	cur += write_str(cur, end - cur, "===============================\n");
+	cur += write_str(cur, end - cur, "CORE %d: %pK\n", core->id, core);
+	cur += write_str(cur, end - cur, "===============================\n");
+	cur += write_str(cur, end - cur, "Core state: %d\n", core->state);
+	rc = call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data, &fw_info);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to read FW info\n");
+		goto err_fw_info;
+	}
+
+	cur += write_str(cur, end - cur,
+		"FW version : %s\n", &fw_info.version);
+	cur += write_str(cur, end - cur,
+		"base addr: 0x%x\n", fw_info.base_addr);
+	cur += write_str(cur, end - cur,
+		"register_base: 0x%x\n", fw_info.register_base);
+	cur += write_str(cur, end - cur,
+		"register_size: %u\n", fw_info.register_size);
+	cur += write_str(cur, end - cur, "irq: %u\n", fw_info.irq);
+
+err_fw_info:
+	for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
+		cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
+			completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
+			"pending" : "done");
+	}
+	len = simple_read_from_buffer(buf, count, ppos,
+			dbuf, cur - dbuf);
+
+	kfree(dbuf);
+	return len;
+}
+
+static const struct file_operations core_info_fops = {
+	.open = core_info_open,
+	.read = core_info_read,
+};
+
+static int trigger_ssr_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *ppos) {
+	unsigned long ssr_trigger_val = 0;
+	int rc = 0;
+	struct msm_vidc_core *core = filp->private_data;
+	size_t size = MAX_SSR_STRING_LEN;
+	char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
+
+	if (!count)
+		goto exit;
+
+	if (count < size)
+		size = count;
+
+	if (copy_from_user(kbuf, buf, size)) {
+		dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
+		rc = -EFAULT;
+		goto exit;
+	}
+
+	rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
+	if (rc) {
+		dprintk(VIDC_WARN, "returning error err %d\n", rc);
+		rc = -EINVAL;
+	} else {
+		msm_vidc_trigger_ssr(core, ssr_trigger_val);
+		rc = count;
+	}
+exit:
+	return rc;
+}
+
+static const struct file_operations ssr_fops = {
+	.open = trigger_ssr_open,
+	.write = trigger_ssr_write,
+};
+
+struct dentry *msm_vidc_debugfs_init_drv(void)
+{
+	bool ok = false;
+	struct dentry *dir = NULL;
+
+	dir = debugfs_create_dir("msm_vidc", NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		goto failed_create_dir;
+	}
+
+#define __debugfs_create(__type, __name, __value) ({                          \
+	struct dentry *f = debugfs_create_##__type(__name, 0644, \
+		dir, __value);                                                \
+	if (IS_ERR_OR_NULL(f)) {                                              \
+		dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n",  \
+			dir, __name);                                         \
+		f = NULL;                                                     \
+	}                                                                     \
+	f;                                                                    \
+})
+
+	ok =
+	__debugfs_create(x32, "debug_level", &msm_vidc_debug) &&
+	__debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
+	__debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
+	__debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
+	__debugfs_create(bool, "dcvs_dec_mode", &msm_vidc_dec_dcvs_mode) &&
+	__debugfs_create(bool, "dcvs_enc_mode", &msm_vidc_enc_dcvs_mode) &&
+	__debugfs_create(u32, "fw_low_power_mode",
+			&msm_vidc_fw_low_power_mode) &&
+	__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
+	__debugfs_create(u32, "hw_rsp_timeout", &msm_vidc_hw_rsp_timeout) &&
+	__debugfs_create(bool, "sys_idle_indicator",
+			&msm_vidc_sys_idle_indicator) &&
+	__debugfs_create(u32, "firmware_unload_delay",
+			&msm_vidc_firmware_unload_delay) &&
+	__debugfs_create(bool, "disable_thermal_mitigation",
+			&msm_vidc_thermal_mitigation_disabled) &&
+	__debugfs_create(bool, "bitrate_clock_scaling",
+			&msm_vidc_bitrate_clock_scaling) &&
+	__debugfs_create(bool, "debug_timeout",
+			&msm_vidc_debug_timeout);
+
+#undef __debugfs_create
+
+	if (!ok)
+		goto failed_create_dir;
+
+	return dir;
+
+failed_create_dir:
+	if (dir)
+		debugfs_remove_recursive(vidc_driver->debugfs_root);
+
+	return NULL;
+}
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
+		goto failed_create_dir;
+	}
+
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+
+	if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_file("trigger_ssr", 0200,
+			dir, core, &ssr_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+failed_create_dir:
+	return dir;
+}
+
+static int inst_info_open(struct inode *inode, struct file *file)
+{
+	dprintk(VIDC_INFO, "Open inode ptr: %pK\n", inode->i_private);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int publish_unreleased_reference(struct msm_vidc_inst *inst,
+		char **dbuf, char *end)
+{
+	char *cur = *dbuf;
+	struct buffer_info *temp = NULL;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		cur += write_str(cur, end - cur, "Pending buffer references\n");
+
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+			if (temp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+			!temp->inactive && atomic_read(&temp->ref_count)) {
+				cur += write_str(cur, end - cur,
+					"\tpending buffer: %#lx fd[0] = %d ref_count = %d held by: %s\n",
+					temp->device_addr[0],
+					temp->fd[0],
+					atomic_read(&temp->ref_count),
+					DYNAMIC_BUF_OWNER(temp));
+			}
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+	}
+
+	*dbuf = cur;
+	return 0;
+}
+
+static void put_inst_helper(struct kref *kref)
+{
+	struct msm_vidc_inst *inst = container_of(kref,
+			struct msm_vidc_inst, kref);
+
+	msm_vidc_destroy(inst);
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct core_inst_pair *idata = file->private_data;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst, *temp = NULL;
+	char *dbuf, *cur, *end;
+	int i, j;
+	ssize_t len = 0;
+
+	if (!idata || !idata->core || !idata->inst) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return 0;
+	}
+
+	core = idata->core;
+	inst = idata->inst;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp == inst)
+			break;
+	}
+	inst = ((temp == inst) && kref_get_unless_zero(&inst->kref)) ?
+		inst : NULL;
+	mutex_unlock(&core->lock);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: Instance has become obsolete", __func__);
+		return 0;
+	}
+
+	dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
+	if (!dbuf) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		len = -ENOMEM;
+		goto failed_alloc;
+	}
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst,
+		inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "core: %pK\n", inst->core);
+	cur += write_str(cur, end - cur, "height: %d\n",
+		inst->prop.height[CAPTURE_PORT]);
+	cur += write_str(cur, end - cur, "width: %d\n",
+		inst->prop.width[CAPTURE_PORT]);
+	cur += write_str(cur, end - cur, "fps: %d\n", inst->prop.fps);
+	cur += write_str(cur, end - cur, "state: %d\n", inst->state);
+	cur += write_str(cur, end - cur, "secure: %d\n",
+		!!(inst->flags & VIDC_SECURE));
+	cur += write_str(cur, end - cur, "-----------Formats-------------\n");
+	for (i = 0; i < MAX_PORT_NUM; i++) {
+		cur += write_str(cur, end - cur, "capability: %s\n",
+			i == OUTPUT_PORT ? "Output" : "Capture");
+		cur += write_str(cur, end - cur, "name : %s\n",
+			inst->fmts[i].name);
+		cur += write_str(cur, end - cur, "planes : %d\n",
+			inst->fmts[i].num_planes);
+		cur += write_str(cur, end - cur,
+			"type: %s\n", inst->fmts[i].type == OUTPUT_PORT ?
+			"Output" : "Capture");
+
+		switch (inst->buffer_mode_set[i]) {
+		case HAL_BUFFER_MODE_STATIC:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "static");
+			break;
+		case HAL_BUFFER_MODE_RING:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "ring");
+			break;
+		case HAL_BUFFER_MODE_DYNAMIC:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "dynamic");
+			break;
+		default:
+			cur += write_str(cur, end - cur,
+				"buffer mode : unsupported\n");
+		}
+
+		cur += write_str(cur, end - cur, "count: %u\n",
+				inst->bufq[i].vb2_bufq.num_buffers);
+
+		for (j = 0; j < inst->fmts[i].num_planes; j++)
+			cur += write_str(cur, end - cur,
+			"size for plane %d: %u\n", j,
+			inst->bufq[i].plane_sizes[j]);
+
+		if (i < MAX_PORT_NUM - 1)
+			cur += write_str(cur, end - cur, "\n");
+	}
+	cur += write_str(cur, end - cur, "-------------------------------\n");
+	for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
+		cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
+		completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
+		"pending" : "done");
+	}
+
+	cur += write_str(cur, end - cur, "ETB Count: %d\n", inst->count.etb);
+	cur += write_str(cur, end - cur, "EBD Count: %d\n", inst->count.ebd);
+	cur += write_str(cur, end - cur, "FTB Count: %d\n", inst->count.ftb);
+	cur += write_str(cur, end - cur, "FBD Count: %d\n", inst->count.fbd);
+
+	publish_unreleased_reference(inst, &cur, end);
+	len = simple_read_from_buffer(buf, count, ppos,
+		dbuf, cur - dbuf);
+
+	kfree(dbuf);
+failed_alloc:
+	kref_put(&inst->kref, put_inst_helper);
+	return len;
+}
+
+static int inst_info_release(struct inode *inode, struct file *file)
+{
+	dprintk(VIDC_INFO, "Release inode ptr: %pK\n", inode->i_private);
+	file->private_data = NULL;
+	return 0;
+}
+
+static const struct file_operations inst_info_fops = {
+	.open = inst_info_open,
+	.read = inst_info_read,
+	.release = inst_info_release,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL, *info = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	struct core_inst_pair *idata = NULL;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst);
+		goto exit;
+	}
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst);
+
+	idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL);
+	if (!idata) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		goto exit;
+	}
+
+	idata->core = inst->core;
+	idata->inst = inst;
+
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+
+	info = debugfs_create_file("info", 0444, dir,
+			idata, &inst_info_fops);
+	if (!info) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_file;
+	}
+
+	dir->d_inode->i_private = info->d_inode->i_private;
+	inst->debug.pdata[FRAME_PROCESSING].sampling = true;
+	return dir;
+
+failed_create_file:
+	debugfs_remove_recursive(dir);
+	dir = NULL;
+failed_create_dir:
+	kfree(idata);
+exit:
+	return dir;
+}
+
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst)
+{
+	struct dentry *dentry = NULL;
+
+	if (!inst || !inst->debugfs_root)
+		return;
+
+	dentry = inst->debugfs_root;
+	if (dentry->d_inode) {
+		dprintk(VIDC_INFO, "Destroy %pK\n", dentry->d_inode->i_private);
+		kfree(dentry->d_inode->i_private);
+		dentry->d_inode->i_private = NULL;
+	}
+	debugfs_remove_recursive(dentry);
+	inst->debugfs_root = NULL;
+}
+
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+	enum msm_vidc_debugfs_event e)
+{
+	struct msm_vidc_debug *d = &inst->debug;
+	char a[64] = "Frame processing";
+
+	switch (e) {
+	case MSM_VIDC_DEBUGFS_EVENT_ETB:
+		mutex_lock(&inst->lock);
+		inst->count.etb++;
+		mutex_unlock(&inst->lock);
+		if (inst->count.ebd && inst->count.ftb > inst->count.fbd) {
+			d->pdata[FRAME_PROCESSING].name[0] = '\0';
+			tic(inst, FRAME_PROCESSING, a);
+		}
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_EBD:
+		mutex_lock(&inst->lock);
+		inst->count.ebd++;
+		mutex_unlock(&inst->lock);
+		if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
+			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
+		}
+		if (inst->count.ftb == inst->count.fbd)
+			dprintk(VIDC_PROF, "EBD: FW needs output buffers\n");
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_FTB: {
+		inst->count.ftb++;
+		if (inst->count.ebd && inst->count.etb > inst->count.ebd) {
+			d->pdata[FRAME_PROCESSING].name[0] = '\0';
+			tic(inst, FRAME_PROCESSING, a);
+		}
+	}
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_FBD:
+		inst->debug.samples++;
+		if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
+			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
+		}
+		if (inst->count.etb == inst->count.ebd)
+			dprintk(VIDC_PROF, "FBD: FW needs input buffers\n");
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e);
+		break;
+	}
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h
new file mode 100644
index 0000000..9b75c72
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h
@@ -0,0 +1,184 @@
+/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include "msm_vidc_internal.h"
+#include "trace/events/msm_vidc.h"
+
+#ifndef VIDC_DBG_LABEL
+#define VIDC_DBG_LABEL "msm_vidc"
+#endif
+
+#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: "
+#define VIDC_DBG_WARN_ENABLE (msm_vidc_debug & VIDC_INFO)
+
+/* To enable messages OR these values and
+ * echo the result to debugfs file.
+ *
+ * To enable all messages set debug_level = 0x101F
+ */
+
+enum vidc_msg_prio {
+	VIDC_ERR  = 0x0001,
+	VIDC_WARN = 0x0002,
+	VIDC_INFO = 0x0004,
+	VIDC_DBG  = 0x0008,
+	VIDC_PROF = 0x0010,
+	VIDC_PKT  = 0x0020,
+	VIDC_FW   = 0x1000,
+};
+
+enum vidc_msg_out {
+	VIDC_OUT_PRINTK = 0,
+	VIDC_OUT_FTRACE,
+};
+
+enum msm_vidc_debugfs_event {
+	MSM_VIDC_DEBUGFS_EVENT_ETB,
+	MSM_VIDC_DEBUGFS_EVENT_EBD,
+	MSM_VIDC_DEBUGFS_EVENT_FTB,
+	MSM_VIDC_DEBUGFS_EVENT_FBD,
+};
+
+extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
+extern int msm_vidc_fw_debug;
+extern int msm_vidc_fw_debug_mode;
+extern int msm_vidc_fw_low_power_mode;
+extern int msm_vidc_hw_rsp_timeout;
+extern bool msm_vidc_fw_coverage;
+extern int msm_vidc_vpe_csc_601_to_709;
+extern bool msm_vidc_dec_dcvs_mode;
+extern bool msm_vidc_enc_dcvs_mode;
+extern bool msm_vidc_sys_idle_indicator;
+extern int msm_vidc_firmware_unload_delay;
+extern bool msm_vidc_thermal_mitigation_disabled;
+extern bool msm_vidc_bitrate_clock_scaling;
+extern bool msm_vidc_debug_timeout;
+
+static inline char *VIDC_MSG_PRIO2STRING(int __level)
+{
+	char *__str;
+
+	switch (__level) {
+	case VIDC_ERR:
+		__str = "err";
+		break;
+	case VIDC_WARN:
+		__str = "warn";
+		break;
+	case VIDC_INFO:
+		__str = "info";
+		break;
+	case VIDC_DBG:
+		__str = "dbg";
+		break;
+	case VIDC_PROF:
+		__str = "prof";
+		break;
+	case VIDC_PKT:
+		__str = "pkt";
+		break;
+	case VIDC_FW:
+		__str = "fw";
+		break;
+	default:
+		__str = "????";
+		break;
+	}
+	return __str;
+}
+
+#define dprintk(__level, __fmt, arg...)	\
+	do { \
+		if (msm_vidc_debug & __level) { \
+			if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+				pr_info(VIDC_DBG_TAG __fmt, \
+						VIDC_MSG_PRIO2STRING(__level), \
+						## arg); \
+			} else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+				trace_printk(KERN_DEBUG VIDC_DBG_TAG __fmt, \
+						VIDC_MSG_PRIO2STRING(__level), \
+						## arg); \
+			} \
+		} \
+	} while (0)
+
+
+
+struct dentry *msm_vidc_debugfs_init_drv(void);
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent);
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+		enum msm_vidc_debugfs_event e);
+
+static inline void tic(struct msm_vidc_inst *i, enum profiling_points p,
+				 char *b)
+{
+	struct timeval __ddl_tv;
+
+	if (!i->debug.pdata[p].name[0])
+		memcpy(i->debug.pdata[p].name, b, 64);
+	if ((msm_vidc_debug & VIDC_PROF) &&
+		i->debug.pdata[p].sampling) {
+		do_gettimeofday(&__ddl_tv);
+		i->debug.pdata[p].start =
+			(__ddl_tv.tv_sec * 1000) + (__ddl_tv.tv_usec / 1000);
+			i->debug.pdata[p].sampling = false;
+	}
+}
+
+static inline void toc(struct msm_vidc_inst *i, enum profiling_points p)
+{
+	struct timeval __ddl_tv;
+
+	if ((msm_vidc_debug & VIDC_PROF) &&
+		!i->debug.pdata[p].sampling) {
+		do_gettimeofday(&__ddl_tv);
+		i->debug.pdata[p].stop = (__ddl_tv.tv_sec * 1000)
+			+ (__ddl_tv.tv_usec / 1000);
+		i->debug.pdata[p].cumulative += i->debug.pdata[p].stop -
+			i->debug.pdata[p].start;
+		i->debug.pdata[p].sampling = true;
+	}
+}
+
+static inline void show_stats(struct msm_vidc_inst *i)
+{
+	int x;
+
+	for (x = 0; x < MAX_PROFILING_POINTS; x++) {
+		if (i->debug.pdata[x].name[0] &&
+				(msm_vidc_debug & VIDC_PROF)) {
+			if (i->debug.samples) {
+				dprintk(VIDC_PROF, "%s averaged %d ms/sample\n",
+						i->debug.pdata[x].name,
+						i->debug.pdata[x].cumulative /
+						i->debug.samples);
+			}
+
+			dprintk(VIDC_PROF, "%s Samples: %d\n",
+					i->debug.pdata[x].name,
+					i->debug.samples);
+		}
+	}
+}
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
new file mode 100644
index 0000000..93368f6
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
@@ -0,0 +1,391 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/kref.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/msm_vidc.h>
+#include <media/msm_media_info.h>
+
+#include "vidc_hfi_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1)
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+#define DEFAULT_HEIGHT 1088
+#define DEFAULT_WIDTH 1920
+#define MIN_SUPPORTED_WIDTH 32
+#define MIN_SUPPORTED_HEIGHT 32
+#define DEFAULT_FPS 15
+
+/* Maintains the number of FTB's between each FBD over a window */
+#define DCVS_FTB_WINDOW 32
+
+#define V4L2_EVENT_VIDC_BASE  10
+
+#define SYS_MSG_START HAL_SYS_INIT_DONE
+#define SYS_MSG_END HAL_SYS_ERROR
+#define SESSION_MSG_START HAL_SESSION_EVENT_CHANGE
+#define SESSION_MSG_END HAL_SESSION_ERROR
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+
+#define MAX_NAME_LENGTH 64
+
+#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0)
+
+#define NUM_MBS_PER_SEC(__height, __width, __fps) \
+	(NUM_MBS_PER_FRAME(__height, __width) * __fps)
+
+#define NUM_MBS_PER_FRAME(__height, __width) \
+	((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16))
+
+enum vidc_ports {
+	OUTPUT_PORT,
+	CAPTURE_PORT,
+	MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+	VIDC_CORE_UNINIT = 0,
+	VIDC_CORE_INIT,
+	VIDC_CORE_INIT_DONE,
+	VIDC_CORE_INVALID
+};
+
+/* Do not change the enum values unless
+ * you know what you are doing
+ */
+enum instance_state {
+	MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+	MSM_VIDC_CORE_INIT,
+	MSM_VIDC_CORE_INIT_DONE,
+	MSM_VIDC_OPEN,
+	MSM_VIDC_OPEN_DONE,
+	MSM_VIDC_LOAD_RESOURCES,
+	MSM_VIDC_LOAD_RESOURCES_DONE,
+	MSM_VIDC_START,
+	MSM_VIDC_START_DONE,
+	MSM_VIDC_STOP,
+	MSM_VIDC_STOP_DONE,
+	MSM_VIDC_RELEASE_RESOURCES,
+	MSM_VIDC_RELEASE_RESOURCES_DONE,
+	MSM_VIDC_CLOSE,
+	MSM_VIDC_CLOSE_DONE,
+	MSM_VIDC_CORE_UNINIT,
+	MSM_VIDC_CORE_INVALID
+};
+
+struct buf_info {
+	struct list_head list;
+	struct vb2_buffer *buf;
+};
+
+struct msm_vidc_list {
+	struct list_head list;
+	struct mutex lock;
+};
+
+static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
+{
+	mutex_init(&mlist->lock);
+	INIT_LIST_HEAD(&mlist->list);
+}
+
+enum buffer_owner {
+	DRIVER,
+	FIRMWARE,
+	CLIENT,
+	MAX_OWNER
+};
+
+struct internal_buf {
+	struct list_head list;
+	enum hal_buffer buffer_type;
+	struct msm_smem *handle;
+	enum buffer_owner buffer_ownership;
+};
+
+struct msm_vidc_format {
+	char name[MAX_NAME_LENGTH];
+	u8 description[32];
+	u32 fourcc;
+	int num_planes;
+	int type;
+	u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+	struct mutex lock;
+	struct list_head cores;
+	int num_cores;
+	struct dentry *debugfs_root;
+	int thermal_level;
+	u32 platform_version;
+	u32 capability_version;
+};
+
+struct msm_video_device {
+	int type;
+	struct video_device vdev;
+};
+
+struct session_prop {
+	u32 width[MAX_PORT_NUM];
+	u32 height[MAX_PORT_NUM];
+	u32 fps;
+	u32 bitrate;
+};
+
+struct buf_queue {
+	struct vb2_queue vb2_bufq;
+	struct mutex lock;
+	unsigned int plane_sizes[VB2_MAX_PLANES];
+	int num_planes;
+};
+
+
+enum profiling_points {
+	SYS_INIT = 0,
+	SESSION_INIT,
+	LOAD_RESOURCES,
+	FRAME_PROCESSING,
+	FW_IDLE,
+	MAX_PROFILING_POINTS,
+};
+
+struct buf_count {
+	int etb;
+	int ftb;
+	int fbd;
+	int ebd;
+};
+
+struct dcvs_stats {
+	int num_ftb[DCVS_FTB_WINDOW];
+	bool transition_turbo;
+	int ftb_index;
+	int ftb_counter;
+	bool prev_freq_lowered;
+	bool prev_freq_increased;
+	int threshold_disp_buf_high;
+	int threshold_disp_buf_low;
+	int load;
+	int load_low;
+	int load_high;
+	int min_threshold;
+	int max_threshold;
+	bool is_clock_scaled;
+	int etb_counter;
+	bool is_power_save_mode;
+	u32 supported_codecs;
+};
+
+struct profile_data {
+	int start;
+	int stop;
+	int cumulative;
+	char name[64];
+	int sampling;
+	int average;
+};
+
+struct msm_vidc_debug {
+	struct profile_data pdata[MAX_PROFILING_POINTS];
+	int profile;
+	int samples;
+};
+
+enum msm_vidc_modes {
+	VIDC_SECURE = BIT(0),
+	VIDC_TURBO = BIT(1),
+	VIDC_THUMBNAIL = BIT(2),
+	VIDC_LOW_POWER = BIT(3),
+};
+
+struct msm_vidc_core {
+	struct list_head list;
+	struct mutex lock;
+	int id;
+	struct hfi_device *device;
+	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+	struct v4l2_device v4l2_dev;
+	struct list_head instances;
+	struct dentry *debugfs_root;
+	enum vidc_core_state state;
+	struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+	enum msm_vidc_hfi_type hfi_type;
+	struct msm_vidc_platform_resources resources;
+	u32 enc_codec_supported;
+	u32 dec_codec_supported;
+	u32 codec_count;
+	struct msm_vidc_capability *capabilities;
+	struct delayed_work fw_unload_work;
+	bool smmu_fault_handled;
+};
+
+struct msm_vidc_inst {
+	struct list_head list;
+	struct mutex sync_lock, lock;
+	struct msm_vidc_core *core;
+	enum session_type session_type;
+	void *session;
+	struct session_prop prop;
+	enum instance_state state;
+	struct msm_vidc_format fmts[MAX_PORT_NUM];
+	struct buf_queue bufq[MAX_PORT_NUM];
+	struct msm_vidc_list pendingq;
+	struct msm_vidc_list scratchbufs;
+	struct msm_vidc_list persistbufs;
+	struct msm_vidc_list pending_getpropq;
+	struct msm_vidc_list outputbufs;
+	struct msm_vidc_list registeredbufs;
+	struct buffer_requirements buff_req;
+	void *mem_client;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+	struct v4l2_ctrl **cluster;
+	struct v4l2_fh event_handler;
+	struct msm_smem *extradata_handle;
+	bool in_reconfig;
+	u32 reconfig_width;
+	u32 reconfig_height;
+	u32 seqchanged_count;
+	struct dentry *debugfs_root;
+	void *priv;
+	struct msm_vidc_debug debug;
+	struct buf_count count;
+	struct dcvs_stats dcvs;
+	enum msm_vidc_modes flags;
+	struct msm_vidc_capability capability;
+	u32 buffer_size_limit;
+	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+	atomic_t seq_hdr_reqs;
+	struct v4l2_ctrl **ctrls;
+	bool dcvs_mode;
+	enum msm_vidc_pixel_depth bit_depth;
+	struct kref kref;
+	unsigned long instant_bitrate;
+	u32 buffers_held_in_driver;
+	atomic_t in_flush;
+	u32 pic_struct;
+	u32 colour_space;
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl_cluster {
+	struct v4l2_ctrl **cluster;
+	struct list_head list;
+};
+
+struct msm_vidc_ctrl {
+	u32 id;
+	char name[MAX_NAME_LENGTH];
+	enum v4l2_ctrl_type type;
+	s32 minimum;
+	s32 maximum;
+	s32 default_value;
+	u32 step;
+	u32 menu_skip_mask;
+	u32 flags;
+	const char * const *qmenu;
+};
+
+void handle_cmd_response(enum hal_command_response cmd, void *data);
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+
+struct crop_info {
+	u32 nLeft;
+	u32 nTop;
+	u32 nWidth;
+	u32 nHeight;
+	u32 width_height[MAX_PORT_NUM];
+};
+
+struct buffer_info {
+	struct list_head list;
+	int type;
+	int num_planes;
+	int fd[VIDEO_MAX_PLANES];
+	int buff_off[VIDEO_MAX_PLANES];
+	int size[VIDEO_MAX_PLANES];
+	unsigned long uvaddr[VIDEO_MAX_PLANES];
+	ion_phys_addr_t device_addr[VIDEO_MAX_PLANES];
+	struct msm_smem *handle[VIDEO_MAX_PLANES];
+	enum v4l2_memory memory;
+	u32 v4l2_index;
+	bool pending_deletion;
+	atomic_t ref_count;
+	bool dequeued;
+	bool inactive;
+	bool mapped[VIDEO_MAX_PLANES];
+	int same_fd_ref[VIDEO_MAX_PLANES];
+	struct timeval timestamp;
+	struct crop_info crop_data;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+				ion_phys_addr_t device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
+
+void msm_comm_handle_thermal_event(void);
+void *msm_smem_new_client(enum smem_type mtype,
+		void *platform_resources, enum session_type stype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+		enum hal_buffer buffer_type, int map_kernel);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+				enum hal_buffer buffer_type);
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+		bool is_secure, enum hal_buffer buffer_type);
+void msm_vidc_fw_unload_handler(struct work_struct *work);
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv);
+/* XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
+ * whereas this is private
+ */
+int msm_vidc_destroy(struct msm_vidc_inst *inst);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
new file mode 100644
index 0000000..82e3b40
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
@@ -0,0 +1,1777 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+#include "msm_vidc_res_parse.h"
+#include "venus_boot.h"
+#include "soc/qcom/secure_buffer.h"
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+enum clock_properties {
+	CLOCK_PROP_HAS_SCALING = 1 << 0,
+};
+
+struct regulator *gdsc_venus;
+struct regulator *gdsc_venus_core0;
+
+static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+	return NULL;
+}
+
+static int msm_vidc_populate_legacy_context_bank(
+			struct msm_vidc_platform_resources *res);
+
+static size_t get_u32_array_num_elements(struct device_node *np,
+					char *name)
+{
+	int len;
+	size_t num_elements = 0;
+
+	if (!of_get_property(np, name, &len)) {
+		dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
+			name);
+		goto fail_read;
+	}
+
+	num_elements = len / sizeof(u32);
+	if (num_elements <= 0) {
+		dprintk(VIDC_ERR, "%s not specified in device tree\n",
+			name);
+		goto fail_read;
+	}
+	return num_elements;
+
+fail_read:
+	return 0;
+}
+
+static int venus_regulator_setup(struct msm_vidc_platform_resources *res)
+{
+	const char *reg_name = "venus";
+	const char *reg_name_core0 = "venus-core0";
+	int rc = 0;
+
+	gdsc_venus = devm_regulator_get(&res->pdev->dev, reg_name);
+	if (IS_ERR(gdsc_venus))
+		dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+
+	rc = regulator_enable(gdsc_venus);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus GDSC enable failed\n");
+
+	gdsc_venus_core0 = devm_regulator_get(&res->pdev->dev, reg_name_core0);
+	if (IS_ERR(gdsc_venus_core0))
+		dprintk(VIDC_ERR, "Failed to get Venus-Core0 GDSC\n");
+
+	rc = regulator_enable(gdsc_venus_core0);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus-Core0 GDSC enable failed\n");
+
+	dprintk(VIDC_DBG, "Vensu, Venus-Core0 GDSC's are enabled\n");
+	return rc;
+}
+
+
+static int venus_clock_setup(struct msm_vidc_platform_resources *res,
+		unsigned long rate)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+	cl = &res->clock_set.clock_tbl[i];
+		if (!cl->has_scaling)
+			continue;
+
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_set_rate(clk, clk_round_rate(clk, rate));
+
+		if (rc)
+			dprintk(VIDC_ERR,
+				"%s: Failed to set clock rate %s: %d\n",
+				__func__, cl->name, rc);
+
+		dprintk(VIDC_DBG, "%s clock set clock rate to %lu\n",
+				cl->name, rate);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static int venus_clock_prepare_enable(struct msm_vidc_platform_resources *res)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_prepare_enable(clk);
+
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to enable %s clock\n",
+					cl->name);
+			for (i--; i >= 0; i--) {
+				cl = &res->clock_set.clock_tbl[i];
+				clk = clk_get(&res->pdev->dev, cl->name);
+				clk_disable_unprepare(clk);
+				dprintk(VIDC_ERR, "clock %s unprepared\n",
+						cl->name);
+			}
+			return rc;
+		}
+		dprintk(VIDC_DBG, " Clock : %s enabled\n", cl->name);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static void venus_clk_disable_unprepare(struct msm_vidc_platform_resources *res)
+{
+	int i;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		dprintk(VIDC_DBG, "clock %s unprepared\n", cl->name);
+		clk_disable_unprepare(clk);
+	}
+
+	if (gdsc_venus) {
+		regulator_disable(gdsc_venus);
+		dprintk(VIDC_DBG, "Venus Regulator disabled\n");
+		gdsc_venus = NULL;
+	}
+	if (gdsc_venus_core0) {
+		regulator_disable(gdsc_venus_core0);
+		dprintk(VIDC_DBG, "Venus-Core0 Regulator disabled\n");
+		gdsc_venus_core0 = NULL;
+	}
+}
+
+static inline enum imem_type read_imem_type(struct platform_device *pdev)
+{
+	bool is_compatible(char *compat)
+	{
+		return !!of_find_compatible_node(NULL, NULL, compat);
+	}
+
+	return is_compatible("qcom,msm-ocmem") ? IMEM_OCMEM :
+		is_compatible("qcom,msm-vmem") ? IMEM_VMEM :
+						IMEM_NONE;
+
+}
+
+static inline void msm_vidc_free_allowed_clocks_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->allowed_clks_tbl = NULL;
+}
+
+static inline void msm_vidc_free_cycles_per_mb_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->clock_freq_tbl.clk_prof_entries = NULL;
+}
+
+static inline void msm_vidc_free_platform_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->pf_ver_tbl = NULL;
+}
+
+static inline void msm_vidc_free_capability_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->pf_cap_tbl = NULL;
+}
+
+static inline void msm_vidc_free_freq_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->load_freq_tbl = NULL;
+}
+
+static inline void msm_vidc_free_dcvs_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->dcvs_tbl = NULL;
+}
+
+static inline void msm_vidc_free_dcvs_limit(
+		struct msm_vidc_platform_resources *res)
+{
+	res->dcvs_limit = NULL;
+}
+
+static inline void msm_vidc_free_imem_ab_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->imem_ab_tbl = NULL;
+}
+
+static inline void msm_vidc_free_reg_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->reg_set.reg_tbl = NULL;
+}
+
+static inline void msm_vidc_free_qdss_addr_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->qdss_addr_set.addr_tbl = NULL;
+}
+
+static inline void msm_vidc_free_bus_vectors(
+			struct msm_vidc_platform_resources *res)
+{
+	kfree(res->bus_set.bus_tbl);
+	res->bus_set.bus_tbl = NULL;
+	res->bus_set.count = 0;
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
+static inline void msm_vidc_free_regulator_table(
+			struct msm_vidc_platform_resources *res)
+{
+	int c = 0;
+
+	for (c = 0; c < res->regulator_set.count; ++c) {
+		struct regulator_info *rinfo =
+			&res->regulator_set.regulator_tbl[c];
+
+		rinfo->name = NULL;
+	}
+
+	res->regulator_set.regulator_tbl = NULL;
+	res->regulator_set.count = 0;
+}
+
+static inline void msm_vidc_free_clock_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->clock_set.clock_tbl = NULL;
+	res->clock_set.count = 0;
+}
+
+void msm_vidc_free_platform_resources(
+			struct msm_vidc_platform_resources *res)
+{
+	msm_vidc_free_clock_table(res);
+	msm_vidc_free_regulator_table(res);
+	msm_vidc_free_freq_table(res);
+	msm_vidc_free_platform_version_table(res);
+	msm_vidc_free_capability_version_table(res);
+	msm_vidc_free_dcvs_table(res);
+	msm_vidc_free_dcvs_limit(res);
+	msm_vidc_free_cycles_per_mb_table(res);
+	msm_vidc_free_allowed_clocks_table(res);
+	msm_vidc_free_reg_table(res);
+	msm_vidc_free_qdss_addr_table(res);
+	msm_vidc_free_bus_vectors(res);
+	msm_vidc_free_buffer_usage_table(res);
+}
+
+static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
+{
+	struct reg_set *reg_set;
+	struct platform_device *pdev = res->pdev;
+	int i;
+	int rc = 0;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) {
+		/* qcom,reg-presets is an optional property.  It likely won't be
+		 * present if we don't have any register settings to program
+		 */
+		dprintk(VIDC_DBG, "qcom,reg-presets not found\n");
+		return 0;
+	}
+
+	reg_set = &res->reg_set;
+	reg_set->count = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,reg-presets");
+	reg_set->count /=  sizeof(*reg_set->reg_tbl) / sizeof(u32);
+
+	if (!reg_set->count) {
+		dprintk(VIDC_DBG, "no elements in reg set\n");
+		return rc;
+	}
+
+	reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count *
+			sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
+	if (!reg_set->reg_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
+		(u32 *)reg_set->reg_tbl, reg_set->count * 2)) {
+		dprintk(VIDC_ERR, "Failed to read register table\n");
+		msm_vidc_free_reg_table(res);
+		return -EINVAL;
+	}
+	for (i = 0; i < reg_set->count; i++) {
+		dprintk(VIDC_DBG,
+			"reg = %x, value = %x\n",
+			reg_set->reg_tbl[i].reg,
+			reg_set->reg_tbl[i].value
+		);
+	}
+	return rc;
+}
+static int msm_vidc_load_qdss_table(struct msm_vidc_platform_resources *res)
+{
+	struct addr_set *qdss_addr_set;
+	struct platform_device *pdev = res->pdev;
+	int i;
+	int rc = 0;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) {
+		/* qcom,qdss-presets is an optional property. It likely won't be
+		 * present if we don't have any register settings to program
+		 */
+		dprintk(VIDC_DBG, "qcom,qdss-presets not found\n");
+		return rc;
+	}
+
+	qdss_addr_set = &res->qdss_addr_set;
+	qdss_addr_set->count = get_u32_array_num_elements(pdev->dev.of_node,
+					"qcom,qdss-presets");
+	qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32);
+
+	if (!qdss_addr_set->count) {
+		dprintk(VIDC_DBG, "no elements in qdss reg set\n");
+		return rc;
+	}
+
+	qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev,
+			qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl),
+			GFP_KERNEL);
+	if (!qdss_addr_set->addr_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_qdss_addr_tbl;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets",
+		(u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read qdss address table\n");
+		msm_vidc_free_qdss_addr_table(res);
+		rc = -EINVAL;
+		goto err_qdss_addr_tbl;
+	}
+
+	for (i = 0; i < qdss_addr_set->count; i++) {
+		dprintk(VIDC_DBG, "qdss addr = %x, value = %x\n",
+				qdss_addr_set->addr_tbl[i].start,
+				qdss_addr_set->addr_tbl[i].size);
+	}
+err_qdss_addr_tbl:
+	return rc;
+}
+
+static int msm_vidc_load_imem_ab_table(struct msm_vidc_platform_resources *res)
+{
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,imem-ab-tbl", NULL)) {
+		/* optional property */
+		dprintk(VIDC_DBG, "qcom,imem-freq-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,imem-ab-tbl");
+	num_elements /= (sizeof(*res->imem_ab_tbl) / sizeof(u32));
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in imem ab table\n");
+		return -EINVAL;
+	}
+
+	res->imem_ab_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->imem_ab_tbl), GFP_KERNEL);
+	if (!res->imem_ab_tbl) {
+		dprintk(VIDC_ERR, "Failed to alloc imem_ab_tbl\n");
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,imem-ab-tbl", (u32 *)res->imem_ab_tbl,
+		num_elements * sizeof(*res->imem_ab_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read imem_ab_tbl\n");
+		msm_vidc_free_imem_ab_table(res);
+		return -EINVAL;
+	}
+
+	res->imem_ab_tbl_size = num_elements;
+
+	return 0;
+}
+
+/**
+ * msm_vidc_load_u32_table() - load dtsi table entries
+ * @pdev: A pointer to the platform device.
+ * @of_node:      A pointer to the device node.
+ * @table_name:   A pointer to the dtsi table entry name.
+ * @struct_size:  The size of the structure which is nothing but
+ *                a single entry in the dtsi table.
+ * @table:        A pointer to the table pointer which needs to be
+ *                filled by the dtsi table entries.
+ * @num_elements: Number of elements pointer which needs to be filled
+ *                with the number of elements in the table.
+ *
+ * This is a generic implementation to load single or multiple array
+ * table from dtsi. The array elements should be of size equal to u32.
+ *
+ * Return:        Return '0' for success else appropriate error value.
+ */
+int msm_vidc_load_u32_table(struct platform_device *pdev,
+		struct device_node *of_node, char *table_name, int struct_size,
+		u32 **table, u32 *num_elements)
+{
+	int rc = 0, num_elemts = 0;
+	u32 *ptbl = NULL;
+
+	if (!of_find_property(of_node, table_name, NULL)) {
+		dprintk(VIDC_DBG, "%s not found\n", table_name);
+		return 0;
+	}
+
+	num_elemts = get_u32_array_num_elements(of_node, table_name);
+	if (!num_elemts) {
+		dprintk(VIDC_ERR, "no elements in %s\n", table_name);
+		return 0;
+	}
+	num_elemts /= struct_size / sizeof(u32);
+
+	ptbl = devm_kzalloc(&pdev->dev, num_elemts * struct_size, GFP_KERNEL);
+	if (!ptbl) {
+		dprintk(VIDC_ERR, "Failed to alloc table %s\n", table_name);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(of_node, table_name, ptbl,
+			num_elemts * struct_size / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read %s\n", table_name);
+		return -EINVAL;
+	}
+
+	*table = ptbl;
+	if (num_elements)
+		*num_elements = num_elemts;
+
+	return rc;
+}
+
+static int msm_vidc_load_platform_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,platform-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,platform-version not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+			"qcom,platform-version",
+			sizeof(*res->pf_ver_tbl),
+			(u32 **)&res->pf_ver_tbl,
+			NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read platform version table\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int msm_vidc_load_capability_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,capability-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,capability-version not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+			"qcom,capability-version",
+			sizeof(*res->pf_cap_tbl),
+			(u32 **)&res->pf_cap_tbl,
+			NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read platform version table\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void clock_override(struct platform_device *pdev,
+	struct msm_vidc_platform_resources *platform_res,
+	struct allowed_clock_rates_table *clk_table)
+{
+	struct resource *res;
+	void __iomem *base = NULL;
+	u32 config_efuse, bin;
+	u32 venus_uplift_freq;
+	u32 is_speed_bin = 7;
+	int rc = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"efuse");
+	if (!res) {
+		dprintk(VIDC_DBG,
+			"Failed to get resource efuse\n");
+		return;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,venus-uplift-freq",
+			&venus_uplift_freq);
+	if (rc) {
+		dprintk(VIDC_DBG,
+			"Failed to determine venus-uplift-freq: %d\n", rc);
+		return;
+	}
+
+	if (!of_find_property(pdev->dev.of_node,
+		"qcom,speedbin-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,speedbin-version not found\n");
+		return;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+		"qcom,speedbin-version",
+		sizeof(*platform_res->pf_speedbin_tbl),
+		(u32 **)&platform_res->pf_speedbin_tbl,
+		NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read speedbin version table\n",
+			__func__);
+		return;
+	}
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			"Unable to ioremap efuse reg address. Defaulting to 0.\n");
+		return;
+	}
+
+	config_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	bin = (config_efuse >> platform_res->pf_speedbin_tbl->version_shift) &
+		platform_res->pf_speedbin_tbl->version_mask;
+
+	if (bin == is_speed_bin) {
+		dprintk(VIDC_DBG,
+			"Venus speed binning available overwriting %d to %d\n",
+			clk_table[0].clock_rate, venus_uplift_freq);
+		clk_table[0].clock_rate = venus_uplift_freq;
+	}
+}
+
+static int msm_vidc_load_allowed_clocks_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,allowed-clock-rates", NULL)) {
+		dprintk(VIDC_DBG, "qcom,allowed-clock-rates not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+				"qcom,allowed-clock-rates",
+				sizeof(*res->allowed_clks_tbl),
+				(u32 **)&res->allowed_clks_tbl,
+				&res->allowed_clks_tbl_size);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read allowed clocks table\n", __func__);
+		return rc;
+	}
+	if (res->allowed_clks_tbl_size)
+		clock_override(pdev, res, res->allowed_clks_tbl);
+
+	return 0;
+}
+
+static int msm_vidc_load_cycles_per_mb_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0, i = 0;
+	struct clock_freq_table *clock_freq_tbl = &res->clock_freq_tbl;
+	struct clock_profile_entry *entry = NULL;
+	struct device_node *parent_node = NULL;
+	struct device_node *child_node = NULL;
+	struct platform_device *pdev = res->pdev;
+
+	parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,clock-freq-tbl");
+	if (!parent_node) {
+		dprintk(VIDC_DBG, "Node qcom,clock-freq-tbl not found.\n");
+		return 0;
+	}
+
+	clock_freq_tbl->count = 0;
+	for_each_child_of_node(parent_node, child_node)
+		clock_freq_tbl->count++;
+
+	if (!clock_freq_tbl->count) {
+		dprintk(VIDC_DBG, "No child nodes in qcom,clock-freq-tbl\n");
+		return 0;
+	}
+
+	clock_freq_tbl->clk_prof_entries = devm_kzalloc(&pdev->dev,
+		sizeof(*clock_freq_tbl->clk_prof_entries) *
+		clock_freq_tbl->count, GFP_KERNEL);
+	if (!clock_freq_tbl->clk_prof_entries) {
+		dprintk(VIDC_DBG, "no memory to allocate clk_prof_entries\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(parent_node, child_node) {
+
+		if (i >= clock_freq_tbl->count) {
+			dprintk(VIDC_ERR,
+				"qcom,clock-freq-tbl: invalid child node %d, max is %d\n",
+				i, clock_freq_tbl->count);
+			break;
+		}
+
+		entry = &clock_freq_tbl->clk_prof_entries[i];
+		dprintk(VIDC_DBG, "qcom,clock-freq-tbl: profile[%d]\n", i);
+
+		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,codec-mask", &entry->codec_mask);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,codec-mask not found\n");
+				goto error;
+			}
+		} else {
+			entry->codec_mask = 0;
+		}
+		dprintk(VIDC_DBG, "codec_mask %#x\n", entry->codec_mask);
+
+		if (of_find_property(child_node, "qcom,cycles-per-mb", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,cycles-per-mb", &entry->cycles);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,cycles-per-mb not found\n");
+				goto error;
+			}
+		} else {
+			entry->cycles = 0;
+		}
+		dprintk(VIDC_DBG, "cycles_per_mb %d\n", entry->cycles);
+
+		if (of_find_property(child_node,
+				"qcom,low-power-mode-factor", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,low-power-mode-factor",
+					&entry->low_power_factor);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,low-power-mode-factor not found\n");
+				goto error;
+			}
+		} else {
+			entry->low_power_factor = 0;
+		}
+		dprintk(VIDC_DBG, "low_power_factor %d\n",
+				entry->low_power_factor);
+
+		i++;
+	}
+
+error:
+	return rc;
+}
+
+static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	/* A comparator to compare loads (needed later on) */
+	int cmp(const void *a, const void *b)
+	{
+		/* want to sort in reverse so flip the comparison */
+		return ((struct load_freq_table *)b)->load -
+			((struct load_freq_table *)a)->load;
+	}
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,load-freq-tbl", NULL)) {
+		/* qcom,load-freq-tbl is an optional property.  It likely won't
+		 * be present on cores that we can't clock scale on.
+		 */
+		dprintk(VIDC_DBG, "qcom,load-freq-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,load-freq-tbl");
+	num_elements /= sizeof(*res->load_freq_tbl) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in frequency table\n");
+		return rc;
+	}
+
+	res->load_freq_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->load_freq_tbl), GFP_KERNEL);
+	if (!res->load_freq_tbl) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc load_freq_tbl\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,load-freq-tbl", (u32 *)res->load_freq_tbl,
+		num_elements * sizeof(*res->load_freq_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read frequency table\n");
+		msm_vidc_free_freq_table(res);
+		return -EINVAL;
+	}
+
+	res->load_freq_tbl_size = num_elements;
+
+	/* The entries in the DT might not be sorted (for aesthetic purposes).
+	 * Given that we expect the loads in descending order for our scaling
+	 * logic to work, just sort it ourselves
+	 */
+	sort(res->load_freq_tbl, res->load_freq_tbl_size,
+			sizeof(*res->load_freq_tbl), cmp, NULL);
+	return rc;
+}
+
+static int msm_vidc_load_dcvs_table(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,dcvs-tbl", NULL)) {
+		/*
+		 * qcom,dcvs-tbl is an optional property. Incase qcom,dcvs-limit
+		 * property is present, it becomes mandatory. It likely won't
+		 * be present on targets that does not support the feature
+		 */
+		dprintk(VIDC_DBG, "qcom,dcvs-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,dcvs-tbl");
+	num_elements /= sizeof(*res->dcvs_tbl) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in dcvs table\n");
+		return rc;
+	}
+
+	res->dcvs_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->dcvs_tbl), GFP_KERNEL);
+	if (!res->dcvs_tbl) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc dcvs_tbl\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,dcvs-tbl", (u32 *)res->dcvs_tbl,
+		num_elements * sizeof(*res->dcvs_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read dcvs table\n");
+		msm_vidc_free_dcvs_table(res);
+		return -EINVAL;
+	}
+	res->dcvs_tbl_size = num_elements;
+
+	return rc;
+}
+
+static int msm_vidc_load_dcvs_limit(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,dcvs-limit", NULL)) {
+		/*
+		 * qcom,dcvs-limit is an optional property. Incase qcom,dcvs-tbl
+		 * property is present, it becomes mandatory. It likely won't
+		 * be present on targets that does not support the feature
+		 */
+		dprintk(VIDC_DBG, "qcom,dcvs-limit not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,dcvs-limit");
+	num_elements /= sizeof(*res->dcvs_limit) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in dcvs limit\n");
+		res->dcvs_limit = NULL;
+		return rc;
+	}
+
+	res->dcvs_limit = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->dcvs_limit), GFP_KERNEL);
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc dcvs_limit\n",
+				__func__);
+		return -ENOMEM;
+	}
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,dcvs-limit", (u32 *)res->dcvs_limit,
+		num_elements * sizeof(*res->dcvs_limit) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read dcvs limit\n");
+		msm_vidc_free_dcvs_limit(res);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int msm_vidc_populate_bus(struct device *dev,
+		struct msm_vidc_platform_resources *res)
+{
+	struct bus_set *buses = &res->bus_set;
+	const char *temp_name = NULL;
+	struct bus_info *bus = NULL, *temp_table;
+	u32 range[2];
+	int rc = 0;
+
+	temp_table = krealloc(buses->bus_tbl, sizeof(*temp_table) *
+			(buses->count + 1), GFP_KERNEL);
+	if (!temp_table) {
+		dprintk(VIDC_ERR, "%s: Failed to allocate memory", __func__);
+		rc = -ENOMEM;
+		goto err_bus;
+	}
+
+	buses->bus_tbl = temp_table;
+	bus = &buses->bus_tbl[buses->count];
+
+	rc = of_property_read_string(dev->of_node, "label", &temp_name);
+	if (rc) {
+		dprintk(VIDC_ERR, "'label' not found in node\n");
+		goto err_bus;
+	}
+	/* need a non-const version of name, hence copying it over */
+	bus->name = devm_kstrdup(dev, temp_name, GFP_KERNEL);
+	if (!bus->name) {
+		rc = -ENOMEM;
+		goto err_bus;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "qcom,bus-master",
+			&bus->master);
+	if (rc) {
+		dprintk(VIDC_ERR, "'qcom,bus-master' not found in node\n");
+		goto err_bus;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "qcom,bus-slave", &bus->slave);
+	if (rc) {
+		dprintk(VIDC_ERR, "'qcom,bus-slave' not found in node\n");
+		goto err_bus;
+	}
+
+	rc = of_property_read_string(dev->of_node, "qcom,bus-governor",
+			&bus->governor);
+	if (rc) {
+		rc = 0;
+		dprintk(VIDC_DBG,
+				"'qcom,bus-governor' not found, default to performance governor\n");
+		bus->governor = "performance";
+	}
+
+	rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps",
+			range, ARRAY_SIZE(range));
+	if (rc) {
+		rc = 0;
+		dprintk(VIDC_DBG,
+				"'qcom,range' not found defaulting to <0 INT_MAX>\n");
+		range[0] = 0;
+		range[1] = INT_MAX;
+	}
+
+	bus->range[0] = range[0]; /* min */
+	bus->range[1] = range[1]; /* max */
+
+	buses->count++;
+	bus->dev = dev;
+	dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n",
+			bus->name, bus->master, bus->slave, bus->governor);
+
+	venus_clk_disable_unprepare(res);
+err_bus:
+	return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+	if (!of_find_property(pdev->dev.of_node,
+				"qcom,buffer-type-tz-usage-table", NULL)) {
+		/* qcom,buffer-type-tz-usage-table is an optional property.  It
+		 * likely won't be present if the core doesn't support content
+		 * protection
+		 */
+		dprintk(VIDC_DBG, "buffer-type-tz-usage-table not found\n");
+		return 0;
+	}
+
+	buffer_usage_set->count = get_u32_array_num_elements(
+		pdev->dev.of_node, "qcom,buffer-type-tz-usage-table");
+	buffer_usage_set->count /=
+		sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32);
+	if (!buffer_usage_set->count) {
+		dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+		return 0;
+	}
+
+	buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev,
+			buffer_usage_set->count *
+			sizeof(*buffer_usage_set->buffer_usage_tbl),
+			GFP_KERNEL);
+	if (!buffer_usage_set->buffer_usage_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_load_buf_usage;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+		    "qcom,buffer-type-tz-usage-table",
+		(u32 *)buffer_usage_set->buffer_usage_tbl,
+		buffer_usage_set->count *
+		sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+		goto err_load_buf_usage;
+	}
+
+	return 0;
+err_load_buf_usage:
+	msm_vidc_free_buffer_usage_table(res);
+	return rc;
+}
+
+static int msm_vidc_load_regulator_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct regulator_set *regulators = &res->regulator_set;
+	struct device_node *domains_parent_node = NULL;
+	struct property *domains_property = NULL;
+	int reg_count = 0;
+
+	regulators->count = 0;
+	regulators->regulator_tbl = NULL;
+
+	domains_parent_node = pdev->dev.of_node;
+	for_each_property_of_node(domains_parent_node, domains_property) {
+		const char *search_string = "-supply";
+		char *supply;
+		bool matched = false;
+
+		/* check if current property is possibly a regulator */
+		supply = strnstr(domains_property->name, search_string,
+				strlen(domains_property->name) + 1);
+		matched = supply && (*(supply + strlen(search_string)) == '\0');
+		if (!matched)
+			continue;
+
+		reg_count++;
+	}
+
+	regulators->regulator_tbl = devm_kzalloc(&pdev->dev,
+			sizeof(*regulators->regulator_tbl) *
+			reg_count, GFP_KERNEL);
+
+	if (!regulators->regulator_tbl) {
+		rc = -ENOMEM;
+		dprintk(VIDC_ERR,
+			"Failed to alloc memory for regulator table\n");
+		goto err_reg_tbl_alloc;
+	}
+
+	for_each_property_of_node(domains_parent_node, domains_property) {
+		const char *search_string = "-supply";
+		char *supply;
+		bool matched = false;
+		struct device_node *regulator_node = NULL;
+		struct regulator_info *rinfo = NULL;
+
+		/* check if current property is possibly a regulator */
+		supply = strnstr(domains_property->name, search_string,
+				strlen(domains_property->name) + 1);
+		matched = supply && (supply[strlen(search_string)] == '\0');
+		if (!matched)
+			continue;
+
+		/* make sure prop isn't being misused */
+		regulator_node = of_parse_phandle(domains_parent_node,
+				domains_property->name, 0);
+		if (IS_ERR(regulator_node)) {
+			dprintk(VIDC_WARN, "%s is not a phandle\n",
+					domains_property->name);
+			continue;
+		}
+		regulators->count++;
+
+		/* populate regulator info */
+		rinfo = &regulators->regulator_tbl[regulators->count - 1];
+		rinfo->name = devm_kzalloc(&pdev->dev,
+			(supply - domains_property->name) + 1, GFP_KERNEL);
+		if (!rinfo->name) {
+			rc = -ENOMEM;
+			dprintk(VIDC_ERR,
+					"Failed to alloc memory for regulator name\n");
+			goto err_reg_name_alloc;
+		}
+		strlcpy(rinfo->name, domains_property->name,
+			(supply - domains_property->name) + 1);
+
+		rinfo->has_hw_power_collapse = of_property_read_bool(
+			regulator_node, "qcom,support-hw-trigger");
+
+		dprintk(VIDC_DBG, "Found regulator %s: h/w collapse = %s\n",
+				rinfo->name,
+				rinfo->has_hw_power_collapse ? "yes" : "no");
+	}
+
+	if (!regulators->count)
+		dprintk(VIDC_DBG, "No regulators found");
+
+	return 0;
+
+err_reg_name_alloc:
+err_reg_tbl_alloc:
+	msm_vidc_free_regulator_table(res);
+	return rc;
+}
+
+static int msm_vidc_load_clock_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0, num_clocks = 0, c = 0;
+	struct platform_device *pdev = res->pdev;
+	int *clock_props = NULL;
+	struct clock_set *clocks = &res->clock_set;
+
+	num_clocks = of_property_count_strings(pdev->dev.of_node,
+				"clock-names");
+	if (num_clocks <= 0) {
+		dprintk(VIDC_DBG, "No clocks found\n");
+		clocks->count = 0;
+		rc = 0;
+		goto err_load_clk_table_fail;
+	}
+
+	clock_props = devm_kzalloc(&pdev->dev, num_clocks *
+			sizeof(*clock_props), GFP_KERNEL);
+	if (!clock_props) {
+		dprintk(VIDC_ERR, "No memory to read clock properties\n");
+		rc = -ENOMEM;
+		goto err_load_clk_table_fail;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,clock-configs", clock_props,
+				num_clocks);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read clock properties: %d\n", rc);
+		goto err_load_clk_prop_fail;
+	}
+
+	clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl)
+			* num_clocks, GFP_KERNEL);
+	if (!clocks->clock_tbl) {
+		dprintk(VIDC_ERR, "Failed to allocate memory for clock tbl\n");
+		rc = -ENOMEM;
+		goto err_load_clk_prop_fail;
+	}
+
+	clocks->count = num_clocks;
+	dprintk(VIDC_DBG, "Found %d clocks\n", num_clocks);
+
+	for (c = 0; c < num_clocks; ++c) {
+		struct clock_info *vc = &res->clock_set.clock_tbl[c];
+
+		of_property_read_string_index(pdev->dev.of_node,
+				"clock-names", c, &vc->name);
+
+		if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
+			vc->has_scaling = true;
+			vc->count = res->load_freq_tbl_size;
+			vc->load_freq_tbl = res->load_freq_tbl;
+		} else {
+			vc->count = 0;
+			vc->load_freq_tbl = NULL;
+			vc->has_scaling = false;
+		}
+
+		dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name,
+			vc->count ? "yes" : "no");
+	}
+
+
+	return 0;
+
+err_load_clk_prop_fail:
+err_load_clk_table_fail:
+	return rc;
+}
+
+int read_platform_resources_from_dt(
+		struct msm_vidc_platform_resources *res)
+{
+	struct platform_device *pdev = res->pdev;
+	struct resource *kres = NULL;
+	int rc = 0;
+	uint32_t firmware_base = 0;
+
+	if (!pdev->dev.of_node) {
+		dprintk(VIDC_ERR, "DT node not found\n");
+		return -ENOENT;
+	}
+
+	INIT_LIST_HEAD(&res->context_banks);
+
+	res->firmware_base = (phys_addr_t)firmware_base;
+
+	kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res->register_base = kres ? kres->start : -1;
+	res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
+
+	kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	res->irq = kres ? kres->start : -1;
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,imem-size", &res->imem_size);
+	res->imem_type = read_imem_type(pdev);
+
+	res->sys_idle_indicator = of_property_read_bool(pdev->dev.of_node,
+			"qcom,enable-idle-indicator");
+
+	res->thermal_mitigable =
+			of_property_read_bool(pdev->dev.of_node,
+			"qcom,enable-thermal-mitigation");
+
+	rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+			&res->fw_name);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read firmware name: %d\n", rc);
+		goto err_load_freq_table;
+	}
+	dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
+
+	rc = of_property_read_string(pdev->dev.of_node, "qcom,hfi-version",
+			&res->hfi_version);
+	if (rc)
+		dprintk(VIDC_DBG, "HFI packetization will default to legacy\n");
+
+	rc = msm_vidc_load_platform_version_table(res);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to load pf version table: %d\n", rc);
+
+	rc = msm_vidc_load_capability_version_table(res);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to load pf capability table: %d\n", rc);
+
+	rc = msm_vidc_load_freq_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
+		goto err_load_freq_table;
+	}
+
+	rc = msm_vidc_load_dcvs_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load dcvs table: %d\n", rc);
+
+	rc = msm_vidc_load_dcvs_limit(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load dcvs limit: %d\n", rc);
+
+	rc = msm_vidc_load_imem_ab_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load freq table: %d\n", rc);
+
+	rc = msm_vidc_load_qdss_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load qdss reg table: %d\n", rc);
+
+	rc = msm_vidc_load_reg_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
+		goto err_load_reg_table;
+	}
+
+	rc = msm_vidc_load_buffer_usage_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load buffer usage table: %d\n", rc);
+		goto err_load_buffer_usage_table;
+	}
+
+	rc = msm_vidc_load_regulator_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load list of regulators %d\n", rc);
+		goto err_load_regulator_table;
+	}
+
+	rc = msm_vidc_load_clock_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load clock table: %d\n", rc);
+		goto err_load_clock_table;
+	}
+
+	rc = msm_vidc_load_cycles_per_mb_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load cycles per mb table: %d\n", rc);
+		goto err_load_cycles_per_mb_table;
+	}
+
+	rc = msm_vidc_load_allowed_clocks_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load allowed clocks table: %d\n", rc);
+		goto err_load_allowed_clocks_table;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+			&res->max_load);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to determine max load supported: %d\n", rc);
+		goto err_load_max_hw_load;
+	}
+
+	rc = msm_vidc_populate_legacy_context_bank(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to setup context banks %d\n", rc);
+		goto err_setup_legacy_cb;
+	}
+
+	res->use_non_secure_pil = of_property_read_bool(pdev->dev.of_node,
+			"qcom,use-non-secure-pil");
+
+	if (res->use_non_secure_pil || !is_iommu_present(res)) {
+		of_property_read_u32(pdev->dev.of_node, "qcom,fw-bias",
+				&firmware_base);
+		res->firmware_base = (phys_addr_t)firmware_base;
+		dprintk(VIDC_DBG,
+				"Using fw-bias : %pa", &res->firmware_base);
+	}
+
+	res->sw_power_collapsible = of_property_read_bool(pdev->dev.of_node,
+					"qcom,sw-power-collapse");
+	dprintk(VIDC_DBG, "Power collapse supported = %s\n",
+		res->sw_power_collapsible ? "yes" : "no");
+
+	res->never_unload_fw = of_property_read_bool(pdev->dev.of_node,
+			"qcom,never-unload-fw");
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
+
+	res->slave_side_cp = of_property_read_bool(pdev->dev.of_node,
+					"qcom,slave-side-cp");
+	dprintk(VIDC_DBG, "Slave side cp = %s\n",
+				res->slave_side_cp ? "yes" : "no");
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,max-secure-instances",
+			&res->max_secure_inst_count);
+
+	venus_regulator_setup(res);
+	venus_clock_setup(res, 0);
+	venus_clock_prepare_enable(res);
+	venus_clock_setup(res, 1);
+
+	return rc;
+
+err_setup_legacy_cb:
+err_load_max_hw_load:
+	msm_vidc_free_allowed_clocks_table(res);
+err_load_allowed_clocks_table:
+	msm_vidc_free_cycles_per_mb_table(res);
+err_load_cycles_per_mb_table:
+	msm_vidc_free_clock_table(res);
+err_load_clock_table:
+	msm_vidc_free_regulator_table(res);
+err_load_regulator_table:
+	msm_vidc_free_buffer_usage_table(res);
+err_load_buffer_usage_table:
+	msm_vidc_free_reg_table(res);
+err_load_reg_table:
+	msm_vidc_free_freq_table(res);
+err_load_freq_table:
+	return rc;
+}
+
+static int get_secure_vmid(struct context_bank_info *cb)
+{
+	if (!strcasecmp(cb->name, "venus_sec_bitstream"))
+		return VMID_CP_BITSTREAM;
+	else if (!strcasecmp(cb->name, "venus_sec_pixel"))
+		return VMID_CP_PIXEL;
+	else if (!strcasecmp(cb->name, "venus_sec_non_pixel"))
+		return VMID_CP_NON_PIXEL;
+
+	WARN(1, "No matching secure vmid for cb name: %s\n",
+		cb->name);
+	return VMID_INVAL;
+}
+
+static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
+		struct device *dev)
+{
+	int rc = 0;
+	int secure_vmid = VMID_INVAL;
+	struct bus_type *bus;
+
+	if (!dev || !cb) {
+		dprintk(VIDC_ERR,
+			"%s: Invalid Input params\n", __func__);
+		return -EINVAL;
+	}
+	cb->dev = dev;
+
+	bus = cb->dev->bus;
+	if (IS_ERR_OR_NULL(bus)) {
+		dprintk(VIDC_ERR, "%s - failed to get bus type\n", __func__);
+		rc = PTR_ERR(bus) ?: -ENODEV;
+		goto remove_cb;
+	}
+
+	cb->mapping = arm_iommu_create_mapping(bus, cb->addr_range.start,
+					cb->addr_range.size);
+	if (IS_ERR_OR_NULL(cb->mapping)) {
+		dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__);
+		rc = PTR_ERR(cb->mapping) ?: -ENODEV;
+		goto remove_cb;
+	}
+
+	if (cb->is_secure) {
+		secure_vmid = get_secure_vmid(cb);
+		rc = iommu_domain_set_attr(cb->mapping->domain,
+				DOMAIN_ATTR_SECURE_VMID, &secure_vmid);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"%s - programming secure vmid failed: %s %d\n",
+					__func__, dev_name(dev), rc);
+			goto release_mapping;
+		}
+	}
+
+	rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - Couldn't arm_iommu_attach_device\n",
+			__func__);
+		goto release_mapping;
+	}
+
+	dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(dev));
+	dprintk(VIDC_DBG,
+		"Context bank name:%s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, mapping: %pK",
+		cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
+		cb->addr_range.size, cb->dev, cb->mapping);
+
+	return rc;
+
+release_mapping:
+	arm_iommu_release_mapping(cb->mapping);
+remove_cb:
+	return rc;
+}
+
+int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags, void *token)
+{
+	struct msm_vidc_core *core = token;
+	struct msm_vidc_inst *inst;
+	struct buffer_info *temp;
+	struct internal_buf *buf;
+	int i = 0;
+	bool is_decode = false;
+	enum vidc_ports port;
+
+	if (!domain || !core) {
+		dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n",
+			__func__, domain, core);
+		return -EINVAL;
+	}
+
+	if (core->smmu_fault_handled)
+		return -EINVAL;
+
+	dprintk(VIDC_ERR, "%s - faulting address: %lx\n", __func__, iova);
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		is_decode = inst->session_type == MSM_VIDC_DECODER;
+		port = is_decode ? OUTPUT_PORT : CAPTURE_PORT;
+		dprintk(VIDC_ERR,
+			"%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n",
+			is_decode ? "Decode" : "Encode", inst->fmts[port].name,
+			inst->prop.height[port], inst->prop.width[port],
+			inst->prop.fps, inst->prop.bitrate,
+			!inst->bit_depth ? "8" : "10");
+
+		dprintk(VIDC_ERR,
+			"---Buffer details for inst: %pK of type: %d---\n",
+			inst, inst->session_type);
+		mutex_lock(&inst->registeredbufs.lock);
+		dprintk(VIDC_ERR, "registered buffer list:\n");
+		list_for_each_entry(temp, &inst->registeredbufs.list, list)
+			for (i = 0; i < temp->num_planes; i++)
+				dprintk(VIDC_ERR,
+					"type: %d plane: %d addr: %pa size: %d\n",
+					temp->type, i, &temp->device_addr[i],
+					temp->size[i]);
+
+		mutex_unlock(&inst->registeredbufs.lock);
+
+		mutex_lock(&inst->scratchbufs.lock);
+		dprintk(VIDC_ERR, "scratch buffer list:\n");
+		list_for_each_entry(buf, &inst->scratchbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->scratchbufs.lock);
+
+		mutex_lock(&inst->persistbufs.lock);
+		dprintk(VIDC_ERR, "persist buffer list:\n");
+		list_for_each_entry(buf, &inst->persistbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->persistbufs.lock);
+
+		mutex_lock(&inst->outputbufs.lock);
+		dprintk(VIDC_ERR, "dpb buffer list:\n");
+		list_for_each_entry(buf, &inst->outputbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->outputbufs.lock);
+	}
+	core->smmu_fault_handled = true;
+	mutex_unlock(&core->lock);
+	/*
+	 * Return -ENOSYS to elicit the default behaviour of smmu driver.
+	 * If we return -ENOSYS, then smmu driver assumes page fault handler
+	 * is not installed and prints a list of useful debug information like
+	 * FAR, SID etc. This information is not printed if we return 0.
+	 */
+	return -EINVAL;
+}
+
+static int msm_vidc_populate_context_bank(struct device *dev,
+		struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct context_bank_info *cb = NULL;
+	struct device_node *np = NULL;
+
+	if (!dev || !core) {
+		dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__);
+		return -EINVAL;
+	}
+
+	np = dev->of_node;
+	cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
+	if (!cb) {
+		dprintk(VIDC_ERR, "%s - Failed to allocate cb\n", __func__);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&cb->list);
+	list_add_tail(&cb->list, &core->resources.context_banks);
+
+	rc = of_property_read_string(np, "label", &cb->name);
+	if (rc) {
+		dprintk(VIDC_DBG,
+			"Failed to read cb label from device tree\n");
+		rc = 0;
+	}
+
+	dprintk(VIDC_DBG, "%s: context bank has name %s\n", __func__, cb->name);
+	rc = of_property_read_u32_array(np, "virtual-addr-pool",
+			(u32 *)&cb->addr_range, 2);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Could not read addr pool for context bank : %s %d\n",
+			cb->name, rc);
+		goto err_setup_cb;
+	}
+
+	cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank");
+	dprintk(VIDC_DBG, "context bank %s : secure = %d\n",
+			cb->name, cb->is_secure);
+
+	/* setup buffer type for each sub device*/
+	rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type);
+	if (rc) {
+		dprintk(VIDC_ERR, "failed to load buffer_type info %d\n", rc);
+		rc = -ENOENT;
+		goto err_setup_cb;
+	}
+	dprintk(VIDC_DBG,
+		"context bank %s address start = %x address size = %x buffer_type = %x\n",
+		cb->name, cb->addr_range.start,
+		cb->addr_range.size, cb->buffer_type);
+
+	rc = msm_vidc_setup_context_bank(cb, dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
+		goto err_setup_cb;
+	}
+
+	iommu_set_fault_handler(cb->mapping->domain,
+		msm_vidc_smmu_fault_handler, (void *)core);
+
+	return 0;
+
+err_setup_cb:
+	list_del(&cb->list);
+	return rc;
+}
+
+static int msm_vidc_populate_legacy_context_bank(
+			struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = NULL;
+	struct device_node *domains_parent_node = NULL;
+	struct device_node *domains_child_node = NULL;
+	struct device_node *ctx_node = NULL;
+	struct context_bank_info *cb;
+
+	if (!res || !res->pdev) {
+		dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__);
+		return -EINVAL;
+	}
+	pdev = res->pdev;
+
+	domains_parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,vidc-iommu-domains");
+	if (!domains_parent_node) {
+		dprintk(VIDC_DBG,
+			"%s legacy iommu domains not present\n", __func__);
+		return 0;
+	}
+
+	/* set up each context bank for legacy DT bindings*/
+	for_each_child_of_node(domains_parent_node,
+		domains_child_node) {
+		cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL);
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s - Failed to allocate cb\n", __func__);
+			return -ENOMEM;
+		}
+		INIT_LIST_HEAD(&cb->list);
+		list_add_tail(&cb->list, &res->context_banks);
+
+		ctx_node = of_parse_phandle(domains_child_node,
+				"qcom,vidc-domain-phandle", 0);
+		if (!ctx_node) {
+			dprintk(VIDC_ERR,
+				"%s Unable to parse pHandle\n", __func__);
+			rc = -EBADHANDLE;
+			goto err_setup_cb;
+		}
+
+		rc = of_property_read_string(ctx_node, "label", &(cb->name));
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not find label\n", __func__);
+			goto err_setup_cb;
+		}
+
+		rc = of_property_read_u32_array(ctx_node,
+			"qcom,virtual-addr-pool", (u32 *)&cb->addr_range, 2);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not read addr pool for group : %s (%d)\n",
+				__func__, cb->name, rc);
+			goto err_setup_cb;
+		}
+
+		cb->is_secure =
+			of_property_read_bool(ctx_node, "qcom,secure-domain");
+
+		rc = of_property_read_u32(domains_child_node,
+				"qcom,vidc-buffer-types", &cb->buffer_type);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not read buffer type (%d)\n",
+				__func__, rc);
+			goto err_setup_cb;
+		}
+
+		cb->dev = msm_iommu_get_ctx(cb->name);
+		if (IS_ERR_OR_NULL(cb->dev)) {
+			dprintk(VIDC_ERR, "%s could not get device for cb %s\n",
+					__func__, cb->name);
+			rc = -ENOENT;
+			goto err_setup_cb;
+		}
+
+		rc = msm_vidc_setup_context_bank(cb, cb->dev);
+		if (rc) {
+			dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
+			goto err_setup_cb;
+		}
+		dprintk(VIDC_DBG,
+			"%s: context bank %s secure %d addr start = %#x addr size = %#x buffer_type = %#x\n",
+			__func__, cb->name, cb->is_secure, cb->addr_range.start,
+			cb->addr_range.size, cb->buffer_type);
+	}
+	return rc;
+
+err_setup_cb:
+	list_del(&cb->list);
+	return rc;
+}
+
+int read_context_bank_resources_from_dt(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core;
+	int rc = 0;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "Invalid platform device\n");
+		return -EINVAL;
+	} else if (!pdev->dev.parent) {
+		dprintk(VIDC_ERR, "Failed to find a parent for %s\n",
+				dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	core = dev_get_drvdata(pdev->dev.parent);
+	if (!core) {
+		dprintk(VIDC_ERR, "Failed to find cookie in parent device %s",
+				dev_name(pdev->dev.parent));
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,fw-context-bank")) {
+		if (core->resources.use_non_secure_pil) {
+			struct context_bank_info *cb;
+
+			cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL);
+			if (!cb) {
+				dprintk(VIDC_ERR, "alloc venus cb failed\n");
+				return -ENOMEM;
+			}
+
+			cb->dev = &pdev->dev;
+			rc = venus_boot_init(&core->resources, cb);
+			if (rc) {
+				dprintk(VIDC_ERR,
+				"Failed to init non-secure PIL %d\n", rc);
+			}
+		}
+	} else {
+		rc = msm_vidc_populate_context_bank(&pdev->dev, core);
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to probe context bank\n");
+		else
+			dprintk(VIDC_DBG, "Successfully probed context bank\n");
+	}
+	return rc;
+}
+
+int read_bus_resources_from_dt(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "Invalid platform device\n");
+		return -EINVAL;
+	} else if (!pdev->dev.parent) {
+		dprintk(VIDC_ERR, "Failed to find a parent for %s\n",
+				dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	core = dev_get_drvdata(pdev->dev.parent);
+	if (!core) {
+		dprintk(VIDC_ERR, "Failed to find cookie in parent device %s",
+				dev_name(pdev->dev.parent));
+		return -EINVAL;
+	}
+
+	return msm_vidc_populate_bus(&pdev->dev, &core->resources);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h
new file mode 100644
index 0000000..8ee02e3
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h
@@ -0,0 +1,35 @@
+
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef DT_PARSE
+#define DT_PARSE
+#include <linux/of.h>
+#include "msm_vidc_resources.h"
+void msm_vidc_free_platform_resources(
+		struct msm_vidc_platform_resources *res);
+
+int read_hfi_type(struct platform_device *pdev);
+
+int read_platform_resources_from_dt(
+		struct msm_vidc_platform_resources *res);
+
+int read_context_bank_resources_from_dt(struct platform_device *pdev);
+
+int read_bus_resources_from_dt(struct platform_device *pdev);
+
+int msm_vidc_load_u32_table(struct platform_device *pdev,
+		struct device_node *of_node, char *table_name, int struct_size,
+		u32 **table, u32 *num_elements);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h
new file mode 100644
index 0000000..383aeda
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h
@@ -0,0 +1,203 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VIDC_RESOURCES_H__
+#define __MSM_VIDC_RESOURCES_H__
+
+#include <linux/devfreq.h>
+#include <linux/platform_device.h>
+#include <media/msm_vidc.h>
+#define MAX_BUFFER_TYPES 32
+
+struct version_table {
+	u32 version_mask;
+	u32 version_shift;
+};
+
+struct load_freq_table {
+	u32 load;
+	u32 freq;
+	u32 supported_codecs;
+};
+
+struct dcvs_table {
+	u32 load;
+	u32 load_low;
+	u32 load_high;
+	u32 supported_codecs;
+};
+
+struct dcvs_limit {
+	u32 min_mbpf;
+	u32 fps;
+};
+
+struct imem_ab_table {
+	u32 core_freq;
+	u32 imem_ab;
+};
+
+struct reg_value_pair {
+	u32 reg;
+	u32 value;
+};
+
+struct reg_set {
+	struct reg_value_pair *reg_tbl;
+	int count;
+};
+
+struct addr_range {
+	u32 start;
+	u32 size;
+};
+
+struct addr_set {
+	struct addr_range *addr_tbl;
+	int count;
+};
+
+struct context_bank_info {
+	struct list_head list;
+	const char *name;
+	u32 buffer_type;
+	bool is_secure;
+	struct addr_range addr_range;
+	struct device *dev;
+	struct dma_iommu_mapping *mapping;
+};
+
+struct buffer_usage_table {
+	u32 buffer_type;
+	u32 tz_usage;
+};
+
+struct buffer_usage_set {
+	struct buffer_usage_table *buffer_usage_tbl;
+	u32 count;
+};
+
+struct regulator_info {
+	struct regulator *regulator;
+	bool has_hw_power_collapse;
+	char *name;
+};
+
+struct regulator_set {
+	struct regulator_info *regulator_tbl;
+	u32 count;
+};
+
+struct clock_info {
+	const char *name;
+	struct clk *clk;
+	struct load_freq_table *load_freq_tbl;
+	u32 count;
+	bool has_scaling;
+};
+
+struct clock_set {
+	struct clock_info *clock_tbl;
+	u32 count;
+};
+
+struct bus_info {
+	char *name;
+	int master;
+	int slave;
+	unsigned int range[2];
+	const char *governor;
+	struct device *dev;
+	struct devfreq_dev_profile devfreq_prof;
+	struct devfreq *devfreq;
+	struct msm_bus_client_handle *client;
+};
+
+struct bus_set {
+	struct bus_info *bus_tbl;
+	u32 count;
+};
+
+enum imem_type {
+	IMEM_NONE,
+	IMEM_OCMEM,
+	IMEM_VMEM,
+	IMEM_MAX,
+};
+
+struct allowed_clock_rates_table {
+	u32 clock_rate;
+};
+
+struct clock_profile_entry {
+	u32 codec_mask;
+	u32 cycles;
+	u32 low_power_factor;
+};
+
+struct clock_freq_table {
+	struct clock_profile_entry *clk_prof_entries;
+	u32 count;
+};
+
+struct msm_vidc_platform_resources {
+	phys_addr_t firmware_base;
+	phys_addr_t register_base;
+	uint32_t register_size;
+	uint32_t irq;
+	struct version_table *pf_ver_tbl;
+	struct version_table *pf_cap_tbl;
+	struct version_table *pf_speedbin_tbl;
+	struct allowed_clock_rates_table *allowed_clks_tbl;
+	u32 allowed_clks_tbl_size;
+	struct clock_freq_table clock_freq_tbl;
+	struct load_freq_table *load_freq_tbl;
+	uint32_t load_freq_tbl_size;
+	struct dcvs_table *dcvs_tbl;
+	uint32_t dcvs_tbl_size;
+	struct dcvs_limit *dcvs_limit;
+	struct imem_ab_table *imem_ab_tbl;
+	u32 imem_ab_tbl_size;
+	struct reg_set reg_set;
+	struct addr_set qdss_addr_set;
+	struct buffer_usage_set buffer_usage_set;
+	uint32_t imem_size;
+	enum imem_type imem_type;
+	uint32_t max_load;
+	struct platform_device *pdev;
+	struct regulator_set regulator_set;
+	struct clock_set clock_set;
+	struct bus_set bus_set;
+	bool use_non_secure_pil;
+	bool sw_power_collapsible;
+	bool sys_idle_indicator;
+	bool slave_side_cp;
+	struct list_head context_banks;
+	bool thermal_mitigable;
+	const char *fw_name;
+	const char *hfi_version;
+	bool never_unload_fw;
+	uint32_t pm_qos_latency_us;
+	uint32_t max_inst_count;
+	uint32_t max_secure_inst_count;
+};
+
+static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
+{
+	return !list_empty(&res->context_banks);
+}
+
+extern uint32_t msm_vidc_pwr_collapse_delay;
+
+#endif
+
diff --git a/drivers/media/platform/msm/vidc_3x/venus_boot.c b/drivers/media/platform/msm/vidc_3x/venus_boot.c
new file mode 100644
index 0000000..715492b
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_boot.c
@@ -0,0 +1,488 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define VIDC_DBG_LABEL "venus_boot"
+
+#include <asm/dma-iommu.h>
+#include <asm/page.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_io.h"
+#include "venus_boot.h"
+
+/* VENUS WRAPPER registers */
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1018)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x101C)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1024)
+
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1024)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1028)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x102C)
+
+#define VENUS_WRAPPER_SW_RESET	(VIDC_WRAPPER_BASE_OFFS + 0x3000)
+
+/* VENUS VBIF registers */
+#define VENUS_VBIF_CLKON_FORCE_ON			BIT(0)
+
+#define VENUS_VBIF_ADDR_TRANS_EN  (VIDC_VBIF_BASE_OFFS + 0x1000)
+#define VENUS_VBIF_AT_OLD_BASE    (VIDC_VBIF_BASE_OFFS + 0x1004)
+#define VENUS_VBIF_AT_OLD_HIGH    (VIDC_VBIF_BASE_OFFS + 0x1008)
+#define VENUS_VBIF_AT_NEW_BASE    (VIDC_VBIF_BASE_OFFS + 0x1010)
+#define VENUS_VBIF_AT_NEW_HIGH    (VIDC_VBIF_BASE_OFFS + 0x1018)
+
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US				50
+
+#define VENUS_REGION_SIZE				0x00500000
+
+static struct {
+	struct msm_vidc_platform_resources *resources;
+	struct regulator *gdsc;
+	const char *reg_name;
+	void __iomem *reg_base;
+	struct device *iommu_ctx_bank_dev;
+	struct dma_iommu_mapping *mapping;
+	dma_addr_t fw_iova;
+	bool is_booted;
+	bool hw_ver_checked;
+	u32 fw_sz;
+	u32 hw_ver_major;
+	u32 hw_ver_minor;
+	void *venus_notif_hdle;
+} *venus_data = NULL;
+
+/* Get venus clocks and set rates for rate-settable clocks */
+static int venus_clock_setup(void)
+{
+	int i, rc = 0;
+	unsigned long rate;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		/* Make sure rate-settable clocks' rates are set */
+		if (!clk_get_rate(cl->clk) && cl->count) {
+			rate = clk_round_rate(cl->clk, 0);
+			rc = clk_set_rate(cl->clk, rate);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to set clock rate %lu %s: %d\n",
+						rate, cl->name, rc);
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int venus_clock_prepare_enable(void)
+{
+	int i, rc = 0;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to enable %s\n", cl->name);
+			for (i--; i >= 0; i--) {
+				cl = &res->clock_set.clock_tbl[i];
+				clk_disable_unprepare(cl->clk);
+			}
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static void venus_clock_disable_unprepare(void)
+{
+	int i;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk_disable_unprepare(cl->clk);
+	}
+}
+
+static int venus_setup_cb(struct device *dev,
+				u32 size)
+{
+	dma_addr_t va_start = 0x0;
+	size_t va_size = size;
+
+	venus_data->mapping = arm_iommu_create_mapping(
+		dev->bus, va_start, va_size);
+	if (IS_ERR_OR_NULL(venus_data->mapping)) {
+		dprintk(VIDC_ERR, "%s: failed to create mapping for %s\n",
+		__func__, dev_name(dev));
+		return -ENODEV;
+	}
+	dprintk(VIDC_DBG,
+		"%s Attached device %pK and created mapping %pK for %s\n",
+		__func__, dev, venus_data->mapping, dev_name(dev));
+	return 0;
+}
+
+static int pil_venus_mem_setup(size_t size)
+{
+	int rc = 0;
+
+	if (!venus_data->mapping) {
+		size = round_up(size, SZ_4K);
+		rc = venus_setup_cb(venus_data->iommu_ctx_bank_dev, size);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to setup context bank for venus : %s\n",
+				__func__,
+				dev_name(venus_data->iommu_ctx_bank_dev));
+			return rc;
+		}
+		venus_data->fw_sz = size;
+	}
+
+	return rc;
+}
+
+static int pil_venus_auth_and_reset(void)
+{
+	int rc;
+
+	phys_addr_t fw_bias = venus_data->resources->firmware_base;
+	void __iomem *reg_base = venus_data->reg_base;
+	u32 ver;
+	bool iommu_present = is_iommu_present(venus_data->resources);
+	struct device *dev = venus_data->iommu_ctx_bank_dev;
+
+	if (!fw_bias) {
+		dprintk(VIDC_ERR, "FW bias is not valid\n");
+		return -EINVAL;
+	}
+	venus_data->fw_iova = (dma_addr_t)NULL;
+	/* Get Venus version number */
+	if (!venus_data->hw_ver_checked) {
+		ver = readl_relaxed(reg_base + VIDC_WRAPPER_HW_VERSION);
+		venus_data->hw_ver_minor = (ver & 0x0FFF0000) >> 16;
+		venus_data->hw_ver_major = (ver & 0xF0000000) >> 28;
+		venus_data->hw_ver_checked = 1;
+	}
+
+	if (iommu_present) {
+		u32 cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr;
+		/* Get the cpa and fw start/end addr based on Venus version */
+		if (venus_data->hw_ver_major == 0x1 &&
+				venus_data->hw_ver_minor <= 1) {
+			cpa_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1;
+			cpa_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1;
+			fw_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1;
+			fw_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1;
+		} else {
+			cpa_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2;
+			cpa_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2;
+			fw_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2;
+			fw_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2;
+		}
+
+		/* Program CPA start and end address */
+		writel_relaxed(0, reg_base + cpa_start_addr);
+		writel_relaxed(venus_data->fw_sz, reg_base + cpa_end_addr);
+
+		/* Program FW start and end address */
+		writel_relaxed(0, reg_base + fw_start_addr);
+		writel_relaxed(venus_data->fw_sz, reg_base + fw_end_addr);
+	} else {
+		rc = regulator_enable(venus_data->gdsc);
+		if (rc) {
+			dprintk(VIDC_ERR, "GDSC enable failed\n");
+			goto err;
+		}
+
+		rc = venus_clock_prepare_enable();
+		if (rc) {
+			dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+			regulator_disable(venus_data->gdsc);
+			goto err;
+		}
+
+		writel_relaxed(0, reg_base + VENUS_VBIF_AT_OLD_BASE);
+		writel_relaxed(VENUS_REGION_SIZE,
+				reg_base + VENUS_VBIF_AT_OLD_HIGH);
+		writel_relaxed(fw_bias, reg_base + VENUS_VBIF_AT_NEW_BASE);
+		writel_relaxed(fw_bias + VENUS_REGION_SIZE,
+				reg_base + VENUS_VBIF_AT_NEW_HIGH);
+		writel_relaxed(0x7F007F, reg_base + VENUS_VBIF_ADDR_TRANS_EN);
+		venus_clock_disable_unprepare();
+		regulator_disable(venus_data->gdsc);
+	}
+	/* Make sure all register writes are committed. */
+	mb();
+
+	/*
+	 * Need to wait 10 cycles of internal clocks before bringing ARM9
+	 * out of reset.
+	 */
+	udelay(1);
+
+	if (iommu_present) {
+		phys_addr_t pa = fw_bias;
+
+		rc = arm_iommu_attach_device(dev, venus_data->mapping);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to attach iommu for %s : %d\n",
+				dev_name(dev), rc);
+			goto release_mapping;
+		}
+
+		dprintk(VIDC_DBG, "Attached and created mapping for %s\n",
+				dev_name(dev));
+
+		/* Map virtual addr space 0 - fw_sz to fw phys addr space */
+		rc = iommu_map(venus_data->mapping->domain,
+			venus_data->fw_iova, pa, venus_data->fw_sz,
+			IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV);
+		if (!rc) {
+			dprintk(VIDC_DBG,
+				"%s - Successfully mapped and performed test translation!\n",
+				dev_name(dev));
+		}
+
+		if (rc || (venus_data->fw_iova != 0)) {
+			dprintk(VIDC_ERR, "%s - Failed to setup IOMMU\n",
+					dev_name(dev));
+			goto err_iommu_map;
+		}
+	}
+	/* Bring Arm9 out of reset */
+	writel_relaxed(0, reg_base + VENUS_WRAPPER_SW_RESET);
+
+	venus_data->is_booted = 1;
+	return 0;
+
+err_iommu_map:
+	if (iommu_present)
+		arm_iommu_detach_device(dev);
+release_mapping:
+	if (iommu_present)
+		arm_iommu_release_mapping(venus_data->mapping);
+err:
+	return rc;
+}
+
+static int pil_venus_shutdown(void)
+{
+	void __iomem *reg_base = venus_data->reg_base;
+	u32 reg;
+	int rc;
+
+	if (!venus_data->is_booted)
+		return 0;
+
+	/* Assert the reset to ARM9 */
+	reg = readl_relaxed(reg_base + VENUS_WRAPPER_SW_RESET);
+	reg |= BIT(4);
+	writel_relaxed(reg, reg_base + VENUS_WRAPPER_SW_RESET);
+
+	/* Make sure reset is asserted before the mapping is removed */
+	mb();
+
+	if (is_iommu_present(venus_data->resources)) {
+		iommu_unmap(venus_data->mapping->domain, venus_data->fw_iova,
+			venus_data->fw_sz);
+		arm_iommu_detach_device(venus_data->iommu_ctx_bank_dev);
+	}
+	/*
+	 * Force the VBIF clk to be on to avoid AXI bridge halt ack failure
+	 * for certain Venus version.
+	 */
+	if (venus_data->hw_ver_major == 0x1 &&
+				(venus_data->hw_ver_minor == 0x2 ||
+				venus_data->hw_ver_minor == 0x3)) {
+		reg = readl_relaxed(reg_base + VIDC_VENUS_VBIF_CLK_ON);
+		reg |= VENUS_VBIF_CLKON_FORCE_ON;
+		writel_relaxed(reg, reg_base + VIDC_VENUS_VBIF_CLK_ON);
+	}
+
+	/* Halt AXI and AXI OCMEM VBIF Access */
+	reg = readl_relaxed(reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	writel_relaxed(reg, reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(reg_base + VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dprintk(VIDC_ERR, "Port halt timeout\n");
+
+	venus_data->is_booted = 0;
+
+	return 0;
+}
+
+static int venus_notifier_cb(struct notifier_block *this, unsigned long code,
+							void *ss_handle)
+{
+	struct notif_data *data = (struct notif_data *)ss_handle;
+	static bool venus_data_set;
+	int ret;
+
+	if (!data->no_auth)
+		return NOTIFY_DONE;
+
+	if (!venus_data_set) {
+		ret = venus_clock_setup();
+		if (ret)
+			return ret;
+
+		ret = of_property_read_string(data->pdev->dev.of_node,
+				"qcom,proxy-reg-names", &venus_data->reg_name);
+		if (ret)
+			return ret;
+
+		venus_data->gdsc = devm_regulator_get(
+				&data->pdev->dev, venus_data->reg_name);
+		if (IS_ERR(venus_data->gdsc)) {
+			dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+			return -ENODEV;
+		}
+
+		venus_data_set = true;
+	}
+
+	if (code != SUBSYS_AFTER_POWERUP && code != SUBSYS_AFTER_SHUTDOWN)
+		return NOTIFY_DONE;
+
+	ret = regulator_enable(venus_data->gdsc);
+	if (ret) {
+		dprintk(VIDC_ERR, "GDSC enable failed\n");
+		return ret;
+	}
+
+	ret = venus_clock_prepare_enable();
+	if (ret) {
+		dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+		goto err_clks;
+	}
+
+	if (code == SUBSYS_AFTER_POWERUP) {
+		if (is_iommu_present(venus_data->resources))
+			pil_venus_mem_setup(VENUS_REGION_SIZE);
+		pil_venus_auth_and_reset();
+	} else if (code == SUBSYS_AFTER_SHUTDOWN)
+		pil_venus_shutdown();
+
+	venus_clock_disable_unprepare();
+	regulator_disable(venus_data->gdsc);
+
+	return NOTIFY_DONE;
+err_clks:
+	regulator_disable(venus_data->gdsc);
+	return ret;
+}
+
+static struct notifier_block venus_notifier = {
+	.notifier_call = venus_notifier_cb,
+};
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+			struct context_bank_info *cb)
+{
+	int rc = 0;
+
+	if (!res || !cb) {
+		dprintk(VIDC_ERR, "Invalid platform resource handle\n");
+		return -EINVAL;
+	}
+	venus_data = kzalloc(sizeof(*venus_data), GFP_KERNEL);
+	if (!venus_data)
+		return -ENOMEM;
+
+	venus_data->resources = res;
+	venus_data->iommu_ctx_bank_dev = cb->dev;
+	if (!venus_data->iommu_ctx_bank_dev) {
+		dprintk(VIDC_ERR, "Invalid venus context bank device\n");
+		return -ENODEV;
+	}
+	venus_data->reg_base = ioremap_nocache(res->register_base,
+			(unsigned long)res->register_size);
+	if (!venus_data->reg_base) {
+		dprintk(VIDC_ERR,
+				"could not map reg addr %pa of size %d\n",
+				&res->register_base, res->register_size);
+		rc = -ENOMEM;
+		goto err_ioremap_fail;
+	}
+	venus_data->venus_notif_hdle = subsys_notif_register_notifier("venus",
+							&venus_notifier);
+	if (IS_ERR(venus_data->venus_notif_hdle)) {
+		dprintk(VIDC_ERR, "register event notification failed\n");
+		rc = PTR_ERR(venus_data->venus_notif_hdle);
+		goto err_subsys_notif;
+	}
+
+	return rc;
+
+err_subsys_notif:
+err_ioremap_fail:
+	kfree(venus_data);
+	return rc;
+}
+
+void venus_boot_deinit(void)
+{
+	venus_data->resources = NULL;
+	subsys_notif_unregister_notifier(venus_data->venus_notif_hdle,
+			&venus_notifier);
+	kfree(venus_data);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/venus_boot.h b/drivers/media/platform/msm/vidc_3x/venus_boot.h
new file mode 100644
index 0000000..11e2dc4
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_boot.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __VENUS_BOOT_H__
+#define __VENUS_BOOT_H__
+#include "msm_vidc_resources.h"
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+		struct context_bank_info *cb);
+void venus_boot_deinit(void);
+
+#endif /* __VENUS_BOOT_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
new file mode 100644
index 0000000..ec6f9b0
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
@@ -0,0 +1,4715 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/dma-iommu.h>
+#include <asm/memory.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/coresight-stm.h>
+#include <linux/delay.h>
+#include <linux/devfreq.h>
+#include <linux/hash.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/smem.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+#include "venus_hfi.h"
+#include "vidc_hfi_io.h"
+
+#define FIRMWARE_SIZE			0X00A00000
+#define REG_ADDR_OFFSET_BITMASK	0x000FFFFF
+#define QDSS_IOVA_START 0x80001000
+
+static struct hal_device_data hal_ctxt;
+
+#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
+struct tzbsp_memprot {
+	u32 cp_start;
+	u32 cp_size;
+	u32 cp_nonpixel_start;
+	u32 cp_nonpixel_size;
+};
+
+struct tzbsp_resp {
+	int ret;
+};
+
+#define TZBSP_VIDEO_SET_STATE 0xa
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
+enum tzbsp_video_state {
+	TZBSP_VIDEO_STATE_SUSPEND = 0,
+	TZBSP_VIDEO_STATE_RESUME = 1,
+	TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2,
+};
+
+struct tzbsp_video_set_state_req {
+	u32 state; /* should be tzbsp_video_state enum value */
+	u32 spare; /* reserved for future, should be zero */
+};
+
+const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = {
+	.data = NULL,
+	.data_count = 0,
+	.imem_size = 0,
+};
+
+const int max_packets = 250;
+
+static void venus_hfi_pm_handler(struct work_struct *work);
+static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler);
+static inline int __resume(struct venus_hfi_device *device);
+static inline int __suspend(struct venus_hfi_device *device);
+static int __disable_regulators(struct venus_hfi_device *device);
+static int __enable_regulators(struct venus_hfi_device *device);
+static inline int __prepare_enable_clks(struct venus_hfi_device *device);
+static inline void __disable_unprepare_clks(struct venus_hfi_device *device);
+static int __scale_clocks_load(struct venus_hfi_device *device, int load,
+		struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate);
+static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet);
+static int __initialize_packetization(struct venus_hfi_device *device);
+static struct hal_session *__get_session(struct venus_hfi_device *device,
+		u32 session_id);
+static int __iface_cmdq_write(struct venus_hfi_device *device,
+					void *pkt);
+static int __load_fw(struct venus_hfi_device *device);
+static void __unload_fw(struct venus_hfi_device *device);
+static int __tzbsp_set_video_state(enum tzbsp_video_state state);
+
+
+/**
+ * Utility function to enforce some of our assumptions.  Spam calls to this
+ * in hotspots in code to double check some of the assumptions that we hold.
+ */
+static inline void __strict_check(struct venus_hfi_device *device)
+{
+	if (!mutex_is_locked(&device->lock)) {
+		dprintk(VIDC_WARN,
+			"device->lock mutex is not locked\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+}
+
+static inline void __set_state(struct venus_hfi_device *device,
+		enum venus_hfi_state state)
+{
+	device->state = state;
+}
+
+static inline bool __core_in_valid_state(struct venus_hfi_device *device)
+{
+	return device->state != VENUS_STATE_DEINIT;
+}
+
+static void __dump_packet(u8 *packet)
+{
+	u32 c = 0, packet_size = *(u32 *)packet;
+	const int row_size = 32;
+	/* row must contain enough for 0xdeadbaad * 8 to be converted into
+	 * "de ad ba ab " * 8 + '\0'
+	 */
+	char row[3 * row_size];
+
+	for (c = 0; c * row_size < packet_size; ++c) {
+		int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+			packet_size % row_size : row_size;
+		hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+				row_size, 4, row, sizeof(row), false);
+		dprintk(VIDC_PKT, "%s\n", row);
+	}
+}
+
+static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device)
+{
+	struct hfi_cmd_sys_session_init_packet *sys_init;
+	struct hal_session *session = NULL;
+	u8 i;
+	phys_addr_t fw_bias = 0;
+
+	if (!device || !packet) {
+		dprintk(VIDC_ERR, "Invalid Param\n");
+		return;
+	} else if (!device->hal_data->firmware_base
+			|| is_iommu_present(device->res)) {
+		return;
+	}
+
+	fw_bias = device->hal_data->firmware_base;
+	sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
+
+	session = __get_session(device, sys_init->session_id);
+	if (!session) {
+		dprintk(VIDC_DBG, "%s :Invalid session id: %x\n",
+				__func__, sys_init->session_id);
+		return;
+	}
+
+	switch (sys_init->packet_type) {
+	case HFI_CMD_SESSION_EMPTY_BUFFER:
+		if (session->is_decoder) {
+			struct hfi_cmd_session_empty_buffer_compressed_packet
+			*pkt = (struct
+			hfi_cmd_session_empty_buffer_compressed_packet
+			*) packet;
+			pkt->packet_buffer -= fw_bias;
+		} else {
+			struct
+			hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			*pkt = (struct
+			hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			*) packet;
+			pkt->packet_buffer -= fw_bias;
+		}
+		break;
+	case HFI_CMD_SESSION_FILL_BUFFER:
+	{
+		struct hfi_cmd_session_fill_buffer_packet *pkt =
+			(struct hfi_cmd_session_fill_buffer_packet *)packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	case HFI_CMD_SESSION_SET_BUFFERS:
+	{
+		struct hfi_cmd_session_set_buffers_packet *pkt =
+			(struct hfi_cmd_session_set_buffers_packet *)packet;
+		if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+			pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+			struct hfi_buffer_info *buff;
+
+			buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+			buff->buffer_addr -= fw_bias;
+			if (buff->extra_data_addr >= fw_bias)
+				buff->extra_data_addr -= fw_bias;
+		} else {
+			for (i = 0; i < pkt->num_buffers; i++)
+				pkt->rg_buffer_info[i] -= fw_bias;
+		}
+		break;
+	}
+	case HFI_CMD_SESSION_RELEASE_BUFFERS:
+	{
+		struct hfi_cmd_session_release_buffer_packet *pkt =
+			(struct hfi_cmd_session_release_buffer_packet *)packet;
+		if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+			pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+			struct hfi_buffer_info *buff;
+
+			buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+			buff->buffer_addr -= fw_bias;
+			buff->extra_data_addr -= fw_bias;
+		} else {
+			for (i = 0; i < pkt->num_buffers; i++)
+				pkt->rg_buffer_info[i] -= fw_bias;
+		}
+		break;
+	}
+	case HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER:
+	{
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt =
+			(struct hfi_cmd_session_parse_sequence_header_packet *)
+		packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	case HFI_CMD_SESSION_GET_SEQUENCE_HEADER:
+	{
+		struct hfi_cmd_session_get_sequence_header_packet *pkt =
+			(struct hfi_cmd_session_get_sequence_header_packet *)
+		packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static int __acquire_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (rinfo->has_hw_power_collapse) {
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_NORMAL);
+		if (rc) {
+			/*
+			 * This is somewhat fatal, but nothing we can do
+			 * about it. We can't disable the regulator w/o
+			 * getting it back under s/w control
+			 */
+			dprintk(VIDC_WARN,
+				"Failed to acquire regulator control: %s\n",
+					rinfo->name);
+		} else {
+
+			dprintk(VIDC_DBG,
+					"Acquire regulator control from HW: %s\n",
+					rinfo->name);
+
+		}
+	}
+
+	if (!regulator_is_enabled(rinfo->regulator)) {
+		dprintk(VIDC_WARN, "Regulator is not enabled %s\n",
+			rinfo->name);
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+
+	return rc;
+}
+
+static int __hand_off_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (rinfo->has_hw_power_collapse) {
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_FAST);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"Failed to hand off regulator control: %s\n",
+					rinfo->name);
+		} else {
+			dprintk(VIDC_DBG,
+					"Hand off regulator control to HW: %s\n",
+					rinfo->name);
+		}
+	}
+
+	return rc;
+}
+
+static int __hand_off_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo;
+	int rc = 0, c = 0;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rc = __hand_off_regulator(rinfo);
+		/*
+		 * If one regulator hand off failed, driver should take
+		 * the control for other regulators back.
+		 */
+		if (rc)
+			goto err_reg_handoff_failed;
+		c++;
+	}
+
+	return rc;
+err_reg_handoff_failed:
+	venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+		__acquire_regulator(rinfo);
+
+	return rc;
+}
+
+static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
+		bool *rx_req_is_set)
+{
+	struct hfi_queue_header *queue;
+	u32 packet_size_in_words, new_write_idx;
+	u32 empty_space, read_idx;
+	u32 *write_ptr;
+
+	if (!qinfo || !packet) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
+
+	queue = (struct hfi_queue_header *) qinfo->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present\n");
+		return -ENOENT;
+	}
+
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
+		__dump_packet(packet);
+	}
+
+	packet_size_in_words = (*(u32 *)packet) >> 2;
+	if (!packet_size_in_words) {
+		dprintk(VIDC_ERR, "Zero packet size\n");
+		return -ENODATA;
+	}
+
+	read_idx = queue->qhdr_read_idx;
+
+	empty_space = (queue->qhdr_write_idx >=  read_idx) ?
+		(queue->qhdr_q_size - (queue->qhdr_write_idx -  read_idx)) :
+		(read_idx - queue->qhdr_write_idx);
+	if (empty_space <= packet_size_in_words) {
+		queue->qhdr_tx_req =  1;
+		dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
+					  empty_space, packet_size_in_words);
+		return -ENOTEMPTY;
+	}
+
+	queue->qhdr_tx_req =  0;
+
+	new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+	write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+		(queue->qhdr_write_idx << 2));
+	if (new_write_idx < queue->qhdr_q_size) {
+		memcpy(write_ptr, packet, packet_size_in_words << 2);
+	} else {
+		new_write_idx -= queue->qhdr_q_size;
+		memcpy(write_ptr, packet, (packet_size_in_words -
+			new_write_idx) << 2);
+		memcpy((void *)qinfo->q_array.align_virtual_addr,
+			packet + ((packet_size_in_words - new_write_idx) << 2),
+			new_write_idx  << 2);
+	}
+
+	/* Memory barrier to make sure packet is written before updating the
+	 * write index
+	 */
+	mb();
+	queue->qhdr_write_idx = new_write_idx;
+	if (rx_req_is_set)
+		*rx_req_is_set = queue->qhdr_rx_req == 1;
+	/* Memory barrier to make sure write index is updated before an
+	 * interrupt is raised on venus.
+	 */
+	mb();
+	return 0;
+}
+
+static void __hal_sim_modify_msg_packet(u8 *packet,
+					struct venus_hfi_device *device)
+{
+	struct hfi_msg_sys_session_init_done_packet *sys_idle;
+	struct hal_session *session = NULL;
+	phys_addr_t fw_bias = 0;
+
+	if (!device || !packet) {
+		dprintk(VIDC_ERR, "Invalid Param\n");
+		return;
+	} else if (!device->hal_data->firmware_base
+			|| is_iommu_present(device->res)) {
+		return;
+	}
+
+	fw_bias = device->hal_data->firmware_base;
+	sys_idle = (struct hfi_msg_sys_session_init_done_packet *)packet;
+	session = __get_session(device, sys_idle->session_id);
+
+	if (!session) {
+		dprintk(VIDC_DBG, "%s: Invalid session id: %x\n",
+				__func__, sys_idle->session_id);
+		return;
+	}
+
+	switch (sys_idle->packet_type) {
+	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+		if (session->is_decoder) {
+			struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet
+			*pkt_uc = (struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet
+			*) packet;
+			pkt_uc->packet_buffer += fw_bias;
+		} else {
+			struct
+			hfi_msg_session_fill_buffer_done_compressed_packet
+			*pkt = (struct
+			hfi_msg_session_fill_buffer_done_compressed_packet
+			*) packet;
+			pkt->packet_buffer += fw_bias;
+		}
+		break;
+	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+	{
+		struct hfi_msg_session_empty_buffer_done_packet *pkt =
+		(struct hfi_msg_session_empty_buffer_done_packet *)packet;
+		pkt->packet_buffer += fw_bias;
+		break;
+	}
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+	{
+		struct
+		hfi_msg_session_get_sequence_header_done_packet
+		*pkt =
+		(struct hfi_msg_session_get_sequence_header_done_packet *)
+		packet;
+		pkt->sequence_header += fw_bias;
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
+		u32 *pb_tx_req_is_set)
+{
+	struct hfi_queue_header *queue;
+	u32 packet_size_in_words, new_read_idx;
+	u32 *read_ptr;
+	u32 receive_request = 0;
+		int rc = 0;
+
+	if (!qinfo || !packet || !pb_tx_req_is_set) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
+
+	/*Memory barrier to make sure data is valid before
+	 *reading it
+	 */
+	mb();
+	queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+	if (!queue) {
+		dprintk(VIDC_ERR, "Queue memory is not allocated\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Do not set receive request for debug queue, if set,
+	 * Venus generates interrupt for debug messages even
+	 * when there is no response message available.
+	 * In general debug queue will not become full as it
+	 * is being emptied out for every interrupt from Venus.
+	 * Venus will anyway generates interrupt if it is full.
+	 */
+	if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
+		receive_request = 1;
+
+	if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+		queue->qhdr_rx_req = receive_request;
+		*pb_tx_req_is_set = 0;
+		dprintk(VIDC_DBG,
+			"%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n",
+			receive_request ? "message" : "debug",
+			queue->qhdr_rx_req, queue->qhdr_tx_req,
+			queue->qhdr_read_idx);
+		return -ENODATA;
+	}
+
+	read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+				(queue->qhdr_read_idx << 2));
+	packet_size_in_words = (*read_ptr) >> 2;
+	if (!packet_size_in_words) {
+		dprintk(VIDC_ERR, "Zero packet size\n");
+		return -ENODATA;
+	}
+
+	new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
+	if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
+			&& queue->qhdr_read_idx <= queue->qhdr_q_size) {
+		if (new_read_idx < queue->qhdr_q_size) {
+			memcpy(packet, read_ptr,
+					packet_size_in_words << 2);
+		} else {
+			new_read_idx -= queue->qhdr_q_size;
+			memcpy(packet, read_ptr,
+			(packet_size_in_words - new_read_idx) << 2);
+			memcpy(packet + ((packet_size_in_words -
+					new_read_idx) << 2),
+					(u8 *)qinfo->q_array.align_virtual_addr,
+					new_read_idx << 2);
+		}
+	} else {
+		dprintk(VIDC_WARN,
+			"BAD packet received, read_idx: %#x, pkt_size: %d\n",
+			queue->qhdr_read_idx, packet_size_in_words << 2);
+		dprintk(VIDC_WARN, "Dropping this packet\n");
+		new_read_idx = queue->qhdr_write_idx;
+		rc = -ENODATA;
+	}
+
+	queue->qhdr_read_idx = new_read_idx;
+
+	if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+		queue->qhdr_rx_req = 0;
+	else
+		queue->qhdr_rx_req = receive_request;
+
+	*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
+
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
+		__dump_packet(packet);
+	}
+
+	return rc;
+}
+
+static int __smem_alloc(struct venus_hfi_device *dev,
+			struct vidc_mem_addr *mem, u32 size, u32 align,
+			u32 flags, u32 usage)
+{
+	struct msm_smem *alloc = NULL;
+	int rc = 0;
+
+	if (!dev || !dev->hal_client || !mem || !size) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_INFO, "start to alloc size: %d, flags: %d\n", size, flags);
+	alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
+	if (!alloc) {
+		dprintk(VIDC_ERR, "Alloc failed\n");
+		rc = -ENOMEM;
+		goto fail_smem_alloc;
+	}
+
+	dprintk(VIDC_DBG, "__smem_alloc: ptr = %pK, size = %d\n",
+			alloc->kvaddr, size);
+	rc = msm_smem_cache_operations(dev->hal_client, alloc,
+		SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to clean cache\n");
+		dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+	}
+
+	mem->mem_size = alloc->size;
+	mem->mem_data = alloc;
+	mem->align_virtual_addr = alloc->kvaddr;
+	mem->align_device_addr = alloc->device_addr;
+	return rc;
+fail_smem_alloc:
+	return rc;
+}
+
+static void __smem_free(struct venus_hfi_device *dev, struct msm_smem *mem)
+{
+	if (!dev || !mem) {
+		dprintk(VIDC_ERR, "invalid param %pK %pK\n", dev, mem);
+		return;
+	}
+
+	msm_smem_free(dev->hal_client, mem);
+}
+
+static void __write_register(struct venus_hfi_device *device,
+		u32 reg, u32 value)
+{
+	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return;
+	}
+
+	__strict_check(device);
+
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Write register failed : Power is OFF\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return;
+	}
+
+	base_addr = device->hal_data->register_base;
+	dprintk(VIDC_DBG, "Base addr: %pK, written to: %#x, Value: %#x...\n",
+		base_addr, hwiosymaddr, value);
+	base_addr += hwiosymaddr;
+	writel_relaxed(value, base_addr);
+	/*
+	 * Memory barrier to make sure value is written into the register.
+	 */
+	wmb();
+}
+
+static int __read_register(struct venus_hfi_device *device, u32 reg)
+{
+	int rc = 0;
+	u8 *base_addr;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Read register failed : Power is OFF\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return -EINVAL;
+	}
+
+	base_addr = device->hal_data->register_base;
+
+	rc = readl_relaxed(base_addr + reg);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	dprintk(VIDC_DBG, "Base addr: %pK, read from: %#x, value: %#x...\n",
+		base_addr, reg, rc);
+
+	return rc;
+}
+
+static void __set_registers(struct venus_hfi_device *device)
+{
+	struct reg_set *reg_set;
+	int i;
+
+	if (!device->res) {
+		dprintk(VIDC_ERR,
+			"device resources null, cannot set registers\n");
+		return;
+	}
+
+	reg_set = &device->res->reg_set;
+	for (i = 0; i < reg_set->count; i++) {
+		__write_register(device, reg_set->reg_tbl[i].reg,
+				reg_set->reg_tbl[i].value);
+	}
+}
+
+/*
+ * The existence of this function is a hack for 8996 (or certain Venus versions)
+ * to overcome a hardware bug.  Whenever the GDSCs momentarily power collapse
+ * (after calling __hand_off_regulators()), the values of the threshold
+ * registers (typically programmed by TZ) are incorrectly reset.  As a result
+ * reprogram these registers at certain agreed upon points.
+ */
+static void __set_threshold_registers(struct venus_hfi_device *device)
+{
+	u32 version = __read_register(device, VIDC_WRAPPER_HW_VERSION);
+
+	version &= ~GENMASK(15, 0);
+	if (version != (0x3 << 28 | 0x43 << 16))
+		return;
+
+	if (__tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESTORE_THRESHOLD))
+		dprintk(VIDC_ERR, "Failed to restore threshold values\n");
+}
+
+static void __iommu_detach(struct venus_hfi_device *device)
+{
+	struct context_bank_info *cb;
+
+	if (!device || !device->res) {
+		dprintk(VIDC_ERR, "Invalid parameter: %pK\n", device);
+		return;
+	}
+
+	list_for_each_entry(cb, &device->res->context_banks, list) {
+		if (cb->dev)
+			arm_iommu_detach_device(cb->dev);
+		if (cb->mapping)
+			arm_iommu_release_mapping(cb->mapping);
+	}
+}
+
+static bool __is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type)
+{
+	bool same_codec, same_session_type;
+	int codec_bit, session_type_bit;
+	unsigned long session = session_type;
+
+	if (!sessions_supported || !session)
+		return false;
+
+	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
+	codec_bit = ffs(session) - 1;
+	session_type_bit = codec_bit + 1;
+
+	same_codec = test_bit(codec_bit, &sessions_supported) ==
+		test_bit(codec_bit, &session);
+	same_session_type = test_bit(session_type_bit, &sessions_supported) ==
+		test_bit(session_type_bit, &session);
+
+	return same_codec && same_session_type;
+}
+
+bool venus_hfi_is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type)
+{
+	return __is_session_supported(sessions_supported, session_type);
+}
+
+static int __devfreq_target(struct device *devfreq_dev,
+		unsigned long *freq, u32 flags)
+{
+	int rc = 0;
+	uint64_t ab = 0;
+	struct bus_info *bus = NULL, *temp = NULL;
+	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
+
+	venus_hfi_for_each_bus(device, temp) {
+		if (temp->dev == devfreq_dev) {
+			bus = temp;
+			break;
+		}
+	}
+
+	if (!bus) {
+		rc = -EBADHANDLE;
+		goto err_unknown_device;
+	}
+
+	/*
+	 * Clamp for all non zero frequencies. This clamp is necessary to stop
+	 * devfreq driver from spamming - Couldn't update frequency - logs, if
+	 * the scaled ab value is not part of the frequency table.
+	 */
+	if (*freq)
+		*freq = clamp_t(typeof(*freq), *freq, bus->range[0],
+				bus->range[1]);
+
+	/* we expect governors to provide values in kBps form, convert to Bps */
+	ab = *freq * 1000;
+	rc = msm_bus_scale_update_bw(bus->client, ab, 0);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d",
+				bus->name, ab, rc);
+		goto err_unknown_device;
+	}
+
+	dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab);
+
+	return 0;
+err_unknown_device:
+	return rc;
+}
+
+static int __devfreq_get_status(struct device *devfreq_dev,
+		struct devfreq_dev_status *stat)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL, *temp = NULL;
+	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
+
+	venus_hfi_for_each_bus(device, temp) {
+		if (temp->dev == devfreq_dev) {
+			bus = temp;
+			break;
+		}
+	}
+
+	if (!bus) {
+		rc = -EBADHANDLE;
+		goto err_unknown_device;
+	}
+
+	*stat = (struct devfreq_dev_status) {
+		.private_data = &device->bus_vote,
+		/*
+		 * Put in dummy place holder values for upstream govs, our
+		 * custom gov only needs .private_data.  We should fill this in
+		 * properly if we can actually measure busy_time accurately
+		 * (which we can't at the moment)
+		 */
+		.total_time = 1,
+		.busy_time = 1,
+		.current_frequency = 0,
+	};
+
+err_unknown_device:
+	return rc;
+}
+
+static int __unvote_buses(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+
+	venus_hfi_for_each_bus(device, bus) {
+		int local_rc = 0;
+		unsigned long zero = 0;
+
+		rc = devfreq_suspend_device(bus->devfreq);
+		if (rc)
+			goto err_unknown_device;
+
+		local_rc = __devfreq_target(bus->dev, &zero, 0);
+		rc = rc ?: local_rc;
+	}
+
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to unvote some buses\n");
+
+err_unknown_device:
+	return rc;
+}
+
+static int __vote_buses(struct venus_hfi_device *device,
+		struct vidc_bus_vote_data *data, int num_data)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+	struct vidc_bus_vote_data *new_data = NULL;
+
+	if (!num_data) {
+		dprintk(VIDC_DBG, "No vote data available\n");
+		goto no_data_count;
+	} else if (!data) {
+		dprintk(VIDC_ERR, "Invalid voting data\n");
+		return -EINVAL;
+	}
+
+	new_data = kmemdup(data, num_data * sizeof(*new_data), GFP_KERNEL);
+	if (!new_data) {
+		dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n");
+		rc = -ENOMEM;
+		goto err_no_mem;
+	}
+
+no_data_count:
+	kfree(device->bus_vote.data);
+	device->bus_vote.data = new_data;
+	device->bus_vote.data_count = num_data;
+	device->bus_vote.imem_size = device->res->imem_size;
+
+	venus_hfi_for_each_bus(device, bus) {
+		if (bus && bus->devfreq) {
+			/* NOP if already resume */
+			rc = devfreq_resume_device(bus->devfreq);
+			if (rc)
+				goto err_no_mem;
+
+			/* Kick devfreq awake incase _resume() didn't do it */
+			bus->devfreq->nb.notifier_call(
+				&bus->devfreq->nb, 0, NULL);
+		}
+	}
+
+err_no_mem:
+	return rc;
+}
+
+static int venus_hfi_vote_buses(void *dev, struct vidc_bus_vote_data *d, int n)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device)
+		return -EINVAL;
+
+	mutex_lock(&device->lock);
+	rc = __vote_buses(device, d, n);
+	mutex_unlock(&device->lock);
+
+	return rc;
+
+}
+static int __core_set_resource(struct venus_hfi_device *device,
+		struct vidc_resource_hdr *resource_hdr, void *resource_value)
+{
+	struct hfi_cmd_sys_set_resource_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+
+	if (!device || !resource_hdr || !resource_value) {
+		dprintk(VIDC_ERR, "set_res: Invalid Params\n");
+		return -EINVAL;
+	}
+
+	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
+
+	rc = call_hfi_pkt_op(device, sys_set_resource,
+			pkt, resource_hdr, resource_value);
+	if (rc) {
+		dprintk(VIDC_ERR, "set_res: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	rc = __iface_cmdq_write(device, pkt);
+	if (rc)
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static DECLARE_COMPLETION(release_resources_done);
+
+static int __alloc_imem(struct venus_hfi_device *device, unsigned long size)
+{
+	struct imem *imem = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	imem = &device->resources.imem;
+	if (imem->type) {
+		dprintk(VIDC_ERR, "IMEM of type %d already allocated\n",
+				imem->type);
+		return -ENOMEM;
+	}
+
+	switch (device->res->imem_type) {
+	case IMEM_VMEM:
+	{
+		phys_addr_t vmem_buffer = 0;
+
+		rc = vmem_allocate(size, &vmem_buffer);
+		if (rc) {
+			if (rc == -ENOTSUPP) {
+				dprintk(VIDC_DBG,
+					"Target does not support vmem\n");
+				rc = 0;
+			}
+			goto imem_alloc_failed;
+		} else if (!vmem_buffer) {
+			rc = -ENOMEM;
+			goto imem_alloc_failed;
+		}
+
+		imem->vmem = vmem_buffer;
+		break;
+	}
+	case IMEM_NONE:
+		rc = 0;
+		break;
+
+	default:
+		rc = -ENOTSUPP;
+		goto imem_alloc_failed;
+	}
+
+	imem->type = device->res->imem_type;
+	dprintk(VIDC_DBG, "Allocated %ld bytes of IMEM of type %d\n", size,
+			imem->type);
+	return 0;
+imem_alloc_failed:
+	imem->type = IMEM_NONE;
+	return rc;
+}
+
+static int __free_imem(struct venus_hfi_device *device)
+{
+	struct imem *imem = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	imem = &device->resources.imem;
+	switch (imem->type) {
+	case IMEM_NONE:
+		/* Follow the semantics of free(NULL), which is a no-op. */
+		break;
+	case IMEM_VMEM:
+		vmem_free(imem->vmem);
+		break;
+	default:
+		rc = -ENOTSUPP;
+		goto imem_free_failed;
+	}
+
+	imem->type = IMEM_NONE;
+	return 0;
+
+imem_free_failed:
+	return rc;
+}
+
+static int __set_imem(struct venus_hfi_device *device, struct imem *imem)
+{
+	struct vidc_resource_hdr rhdr;
+	phys_addr_t addr = 0;
+	int rc = 0;
+
+	if (!device || !device->res || !imem) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK, imem: %pK\n",
+			device, imem);
+		return -EINVAL;
+	}
+
+	rhdr.resource_handle = imem; /* cookie */
+	rhdr.size = device->res->imem_size;
+	rhdr.resource_id = VIDC_RESOURCE_NONE;
+
+	switch (imem->type) {
+	case IMEM_VMEM:
+		rhdr.resource_id = VIDC_RESOURCE_VMEM;
+		addr = imem->vmem;
+		break;
+	case IMEM_NONE:
+		dprintk(VIDC_DBG, "%s Target does not support IMEM", __func__);
+		rc = 0;
+		goto imem_set_failed;
+	default:
+		dprintk(VIDC_ERR, "IMEM of type %d unsupported\n", imem->type);
+		rc = -ENOTSUPP;
+		goto imem_set_failed;
+	}
+
+	WARN_ON(!addr);
+
+	rc = __core_set_resource(device, &rhdr, (void *)addr);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set IMEM on driver\n");
+		goto imem_set_failed;
+	}
+
+	dprintk(VIDC_DBG,
+			"Managed to set IMEM buffer of type %d sized %d bytes at %pa\n",
+			rhdr.resource_id, rhdr.size, &addr);
+
+	rc = __vote_buses(device, device->bus_vote.data,
+			device->bus_vote.data_count);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to vote for buses after setting imem: %d\n",
+				rc);
+	}
+
+imem_set_failed:
+	return rc;
+}
+
+static int __tzbsp_set_video_state(enum tzbsp_video_state state)
+{
+	struct tzbsp_video_set_state_req cmd = {0};
+	int tzbsp_rsp = 0;
+	int rc = 0;
+	struct scm_desc desc = {0};
+
+	desc.args[0] = cmd.state = state;
+	desc.args[1] = cmd.spare = 0;
+	desc.arginfo = SCM_ARGS(2);
+
+	if (!is_scm_armv8()) {
+		rc = scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &cmd,
+				sizeof(cmd), &tzbsp_rsp, sizeof(tzbsp_rsp));
+	} else {
+		rc = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT,
+				TZBSP_VIDEO_SET_STATE), &desc);
+		tzbsp_rsp = desc.ret[0];
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed scm_call %d\n", rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG, "Set state %d, resp %d\n", state, tzbsp_rsp);
+	if (tzbsp_rsp) {
+		dprintk(VIDC_ERR,
+				"Failed to set video core state to suspend: %d\n",
+				tzbsp_rsp);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int __boot_firmware(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	u32 ctrl_status = 0, count = 0, max_tries = 100;
+
+	__write_register(device, VIDC_CTRL_INIT, 0x1);
+	while (!ctrl_status && count < max_tries) {
+		ctrl_status = __read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+		if ((ctrl_status & 0xFE) == 0x4) {
+			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
+			break;
+		}
+
+		usleep_range(500, 1000);
+		count++;
+	}
+
+	if (count >= max_tries) {
+		dprintk(VIDC_ERR, "Error booting up vidc firmware\n");
+		rc = -ETIME;
+	}
+	return rc;
+}
+
+static struct clock_info *__get_clock(struct venus_hfi_device *device,
+		char *name)
+{
+	struct clock_info *vc;
+
+	venus_hfi_for_each_clock(device, vc) {
+		if (!strcmp(vc->name, name))
+			return vc;
+	}
+
+	dprintk(VIDC_WARN, "%s Clock %s not found\n", __func__, name);
+
+	return NULL;
+}
+
+static unsigned long __get_clock_rate(struct clock_info *clock,
+	int num_mbs_per_sec, struct vidc_clk_scale_data *data)
+{
+	int num_rows = clock->count;
+	struct load_freq_table *table = clock->load_freq_tbl;
+	unsigned long freq = table[0].freq, max_freq = 0;
+	int i = 0, j = 0;
+	unsigned long instance_freq[VIDC_MAX_SESSIONS] = {0};
+
+	if (!data && !num_rows) {
+		freq = 0;
+		goto print_clk;
+	}
+
+	if ((!num_mbs_per_sec || !data) && num_rows) {
+		freq = table[num_rows - 1].freq;
+		goto print_clk;
+	}
+
+	for (i = 0; i < num_rows; i++) {
+		if (num_mbs_per_sec > table[i].load)
+			break;
+		for (j = 0; j < data->num_sessions; j++) {
+			bool matches = __is_session_supported(
+				table[i].supported_codecs, data->session[j]);
+
+			if (!matches)
+				continue;
+			instance_freq[j] = table[i].freq;
+		}
+	}
+	for (i = 0; i < data->num_sessions; i++)
+		max_freq = max(instance_freq[i], max_freq);
+
+	freq = max_freq ? : freq;
+print_clk:
+	dprintk(VIDC_PROF, "Required clock rate = %lu num_mbs_per_sec %d\n",
+					freq, num_mbs_per_sec);
+	return freq;
+}
+
+static unsigned long __get_clock_rate_with_bitrate(struct clock_info *clock,
+		int num_mbs_per_sec, struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate)
+{
+	int num_rows = clock->count;
+	struct load_freq_table *table = clock->load_freq_tbl;
+	unsigned long freq = table[0].freq, max_freq = 0;
+	unsigned long base_freq, supported_clk[VIDC_MAX_SESSIONS] = {0};
+	int i, j;
+
+	if (!data && !num_rows) {
+		freq = 0;
+		goto print_clk;
+	}
+	if ((!num_mbs_per_sec || !data) && num_rows) {
+		freq = table[num_rows - 1].freq;
+		goto print_clk;
+	}
+
+	/* Get clock rate based on current load only */
+	base_freq = __get_clock_rate(clock, num_mbs_per_sec, data);
+
+	/*
+	 * Supported bitrate = 40% of clock frequency
+	 * Check if the instant bitrate is supported by the base frequency.
+	 * If not, move on to the next frequency which supports the bitrate.
+	 */
+
+	for (j = 0; j < data->num_sessions; j++) {
+		unsigned long supported_bitrate = 0;
+
+		for (i = num_rows - 1; i >= 0; i--) {
+			bool matches = __is_session_supported(
+				table[i].supported_codecs, data->session[j]);
+
+			if (!matches)
+				continue;
+			freq = table[i].freq;
+
+			supported_bitrate = freq * 40/100;
+			/*
+			 * Store this frequency for each instance, we need
+			 * to select the maximum freq among all the instances.
+			 */
+			if (freq >= base_freq &&
+				supported_bitrate >= instant_bitrate) {
+				supported_clk[j] = freq;
+				break;
+			}
+		}
+
+		/*
+		 * Current bitrate is higher than max supported load.
+		 * Select max frequency to handle this load.
+		 */
+		if (i < 0)
+			supported_clk[j] = table[0].freq;
+	}
+
+	for (i = 0; i < data->num_sessions; i++)
+		max_freq = max(supported_clk[i], max_freq);
+
+	freq = max_freq ? : base_freq;
+
+	if (base_freq == freq)
+		dprintk(VIDC_DBG, "Stay at base freq: %lu bitrate = %lu\n",
+			freq, instant_bitrate);
+	else
+		dprintk(VIDC_DBG, "Move up clock freq: %lu bitrate = %lu\n",
+			freq, instant_bitrate);
+print_clk:
+	dprintk(VIDC_PROF, "Required clock rate = %lu num_mbs_per_sec %d\n",
+					freq, num_mbs_per_sec);
+	return freq;
+}
+
+static unsigned long venus_hfi_get_core_clock_rate(void *dev, bool actual_rate)
+{
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+	struct clock_info *vc;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, device);
+		return -EINVAL;
+	}
+
+	if (actual_rate) {
+		vc = __get_clock(device, "core_clk");
+		if (vc)
+			return clk_get_rate(vc->clk);
+		else
+			return 0;
+	} else {
+		return device->scaled_rate;
+	}
+}
+
+static int venus_hfi_suspend(void *dev)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+		return -EINVAL;
+	} else if (!device->res->sw_power_collapsible) {
+		return -ENOTSUPP;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->power_enabled) {
+		dprintk(VIDC_DBG, "Venus is busy\n");
+		rc = -EBUSY;
+	} else {
+		dprintk(VIDC_DBG, "Venus is power suspended\n");
+		rc = 0;
+	}
+
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static enum hal_default_properties venus_hfi_get_default_properties(void *dev)
+{
+	enum hal_default_properties prop = 0;
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->packetization_type == HFI_PACKETIZATION_3XX)
+		prop = HAL_VIDEO_DYNAMIC_BUF_MODE;
+
+	mutex_unlock(&device->lock);
+	return prop;
+}
+
+static int __halt_axi(struct venus_hfi_device *device)
+{
+	u32 reg;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid input: %pK\n", device);
+		return -EINVAL;
+	}
+
+	/*
+	 * Driver needs to make sure that clocks are enabled to read Venus AXI
+	 * registers. If not skip AXI HALT.
+	 */
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"Clocks are OFF, skipping AXI HALT\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return -EINVAL;
+	}
+
+	/* Halt AXI and AXI IMEM VBIF Access */
+	reg = __read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	__write_register(device, VENUS_VBIF_AXI_HALT_CTRL0, reg);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(device->hal_data->register_base
+			+ VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+
+	return rc;
+}
+
+static int __scale_clocks_cycles_per_mb(struct venus_hfi_device *device,
+		struct vidc_clk_scale_data *data, unsigned long instant_bitrate)
+{
+	int rc = 0, i = 0, j = 0;
+	struct clock_info *cl;
+	struct clock_freq_table *clk_freq_tbl = NULL;
+	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
+	struct clock_profile_entry *entry = NULL;
+	u64 total_freq = 0, rate = 0;
+
+	clk_freq_tbl = &device->res->clock_freq_tbl;
+	allowed_clks_tbl = device->res->allowed_clks_tbl;
+
+	if (!data) {
+		dprintk(VIDC_DBG, "%s: NULL scale data\n", __func__);
+		total_freq = device->clk_freq;
+		goto get_clock_freq;
+	}
+
+	device->clk_bitrate = instant_bitrate;
+
+	for (i = 0; i < data->num_sessions; i++) {
+		/*
+		 * for each active session iterate through all possible
+		 * sessions and get matching session's cycles per mb
+		 * from dtsi and multiply with the session's load to
+		 * get the frequency required for the session.
+		 * accumulate all session's frequencies to get the
+		 * total clock frequency.
+		 */
+		for (j = 0; j < clk_freq_tbl->count; j++) {
+			bool matched = false;
+			u64 freq = 0;
+
+			entry = &clk_freq_tbl->clk_prof_entries[j];
+
+			matched = __is_session_supported(entry->codec_mask,
+					data->session[i]);
+			if (!matched)
+				continue;
+
+			freq = entry->cycles * data->load[i];
+
+			if (data->power_mode[i] == VIDC_POWER_LOW &&
+					entry->low_power_factor) {
+				/* low_power_factor is in Q16 format */
+				freq = (freq * entry->low_power_factor) >> 16;
+			}
+
+			total_freq += freq;
+
+			dprintk(VIDC_DBG,
+				"session[%d] %#x: cycles (%d), load (%d), freq (%llu), factor (%d)\n",
+				i, data->session[i], entry->cycles,
+				data->load[i], freq,
+				entry->low_power_factor);
+		}
+	}
+
+get_clock_freq:
+	/*
+	 * get required clock rate from allowed clock rates table
+	 */
+	for (i = device->res->allowed_clks_tbl_size - 1; i >= 0; i--) {
+		rate = allowed_clks_tbl[i].clock_rate;
+		if (rate >= total_freq)
+			break;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (!cl->has_scaling)
+			continue;
+
+		device->clk_freq = rate;
+		rc = clk_set_rate(cl->clk, rate);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to set clock rate %llu %s: %d\n",
+				__func__, rate, cl->name, rc);
+			return rc;
+		}
+		if (!strcmp(cl->name, "core_clk"))
+			device->scaled_rate = rate;
+
+		dprintk(VIDC_DBG,
+			"scaling clock %s to %llu (required freq %llu)\n",
+			cl->name, rate, total_freq);
+	}
+
+	return rc;
+}
+
+static int __scale_clocks_load(struct venus_hfi_device *device, int load,
+		struct vidc_clk_scale_data *data, unsigned long instant_bitrate)
+{
+	struct clock_info *cl;
+
+	device->clk_bitrate = instant_bitrate;
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (cl->has_scaling) {
+
+			unsigned long rate = 0;
+			int rc;
+			/*
+			 * load_fw and power_on needs to be addressed.
+			 * differently. Below check enforces the same.
+			 */
+			if (!device->clk_bitrate && !data && !load &&
+				device->clk_freq)
+				rate = device->clk_freq;
+
+			if (!rate) {
+				if (!device->clk_bitrate)
+					rate = __get_clock_rate(cl, load,
+							data);
+				else
+					rate = __get_clock_rate_with_bitrate(cl,
+							load, data,
+							instant_bitrate);
+			}
+			device->clk_freq = rate;
+			rc = clk_set_rate(cl->clk, rate);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to set clock rate %lu %s: %d\n",
+					rate, cl->name, rc);
+				return rc;
+			}
+
+			if (!strcmp(cl->name, "core_clk"))
+				device->scaled_rate = rate;
+
+			dprintk(VIDC_PROF, "Scaling clock %s to %lu\n",
+					cl->name, rate);
+		}
+	}
+
+	return 0;
+}
+
+static int __scale_clocks(struct venus_hfi_device *device,
+		int load, struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate)
+{
+	int rc = 0;
+
+	if (device->res->clock_freq_tbl.clk_prof_entries &&
+			device->res->allowed_clks_tbl)
+		rc = __scale_clocks_cycles_per_mb(device,
+				data, instant_bitrate);
+	else if (device->res->load_freq_tbl)
+		rc = __scale_clocks_load(device, load, data, instant_bitrate);
+	else
+		dprintk(VIDC_DBG, "Clock scaling is not supported\n");
+
+	return rc;
+}
+static int venus_hfi_scale_clocks(void *dev, int load,
+					struct vidc_clk_scale_data *data,
+					unsigned long instant_bitrate)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid args: %pK\n", device);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "Resume from power collapse failed\n");
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	rc = __scale_clocks(device, load, data, instant_bitrate);
+exit:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+/* Writes into cmdq without raising an interrupt */
+static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device,
+		void *pkt, bool *requires_interrupt)
+{
+	struct vidc_iface_q_info *q_info;
+	struct vidc_hal_cmd_pkt_hdr *cmd_packet;
+	int result = -E2BIG;
+
+	if (!device || !pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		result = -EINVAL;
+		goto err_q_null;
+	}
+
+	cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
+	device->last_packet_type = cmd_packet->packet_type;
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	if (!q_info) {
+		dprintk(VIDC_ERR, "cannot write to shared Q's\n");
+		goto err_q_null;
+	}
+
+	if (!q_info->q_array.align_virtual_addr) {
+		dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
+		result = -ENODATA;
+		goto err_q_null;
+	}
+
+	__sim_modify_cmd_packet((u8 *)pkt, device);
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
+		goto err_q_write;
+	}
+
+	if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) {
+		if (device->res->sw_power_collapsible) {
+			cancel_delayed_work(&venus_hfi_pm_work);
+			if (!queue_delayed_work(device->venus_pm_workq,
+				&venus_hfi_pm_work,
+				msecs_to_jiffies(
+				msm_vidc_pwr_collapse_delay))) {
+				dprintk(VIDC_DBG,
+				"PM work already scheduled\n");
+			}
+		}
+
+		result = 0;
+	} else {
+		dprintk(VIDC_ERR, "__iface_cmdq_write: queue full\n");
+	}
+
+err_q_write:
+err_q_null:
+	return result;
+}
+
+static int __iface_cmdq_write(struct venus_hfi_device *device, void *pkt)
+{
+	bool needs_interrupt = false;
+	int rc = __iface_cmdq_write_relaxed(device, pkt, &needs_interrupt);
+
+	if (!rc && needs_interrupt) {
+		/* Consumer of cmdq prefers that we raise an interrupt */
+		rc = 0;
+		__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+	}
+
+	return rc;
+}
+
+static int __iface_msgq_read(struct venus_hfi_device *device, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto read_error_null;
+	}
+
+	if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
+		q_array.align_virtual_addr == 0) {
+		dprintk(VIDC_ERR, "cannot read from shared MSG Q's\n");
+		rc = -ENODATA;
+		goto read_error_null;
+	}
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		__hal_sim_modify_msg_packet((u8 *)pkt, device);
+		if (tx_req_is_set)
+			__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+		rc = 0;
+	} else
+		rc = -ENODATA;
+
+read_error_null:
+	return rc;
+}
+
+static int __iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto dbg_error_null;
+	}
+
+	if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
+		q_array.align_virtual_addr == 0) {
+		dprintk(VIDC_ERR, "cannot read from shared DBG Q's\n");
+		rc = -ENODATA;
+		goto dbg_error_null;
+	}
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		if (tx_req_is_set)
+			__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+		rc = 0;
+	} else
+		rc = -ENODATA;
+
+dbg_error_null:
+	return rc;
+}
+
+static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
+{
+	q_hdr->qhdr_status = 0x1;
+	q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
+	q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
+	q_hdr->qhdr_pkt_size = 0;
+	q_hdr->qhdr_rx_wm = 0x1;
+	q_hdr->qhdr_tx_wm = 0x1;
+	q_hdr->qhdr_rx_req = 0x1;
+	q_hdr->qhdr_tx_req = 0x0;
+	q_hdr->qhdr_rx_irq_status = 0x0;
+	q_hdr->qhdr_tx_irq_status = 0x0;
+	q_hdr->qhdr_read_idx = 0x0;
+	q_hdr->qhdr_write_idx = 0x0;
+}
+
+static void __interface_queues_release(struct venus_hfi_device *device)
+{
+	int i;
+	struct hfi_mem_map_table *qdss;
+	struct hfi_mem_map *mem_map;
+	int num_entries = device->res->qdss_addr_set.count;
+	unsigned long mem_map_table_base_addr;
+	struct context_bank_info *cb;
+
+	if (device->qdss.mem_data) {
+		qdss = (struct hfi_mem_map_table *)
+			device->qdss.align_virtual_addr;
+		qdss->mem_map_num_entries = num_entries;
+		mem_map_table_base_addr =
+			device->qdss.align_device_addr +
+			sizeof(struct hfi_mem_map_table);
+		qdss->mem_map_table_base_addr =
+			(u32)mem_map_table_base_addr;
+		if ((unsigned long)qdss->mem_map_table_base_addr !=
+			mem_map_table_base_addr) {
+			dprintk(VIDC_ERR,
+				"Invalid mem_map_table_base_addr %#lx",
+				mem_map_table_base_addr);
+		}
+
+		mem_map = (struct hfi_mem_map *)(qdss + 1);
+		cb = msm_smem_get_context_bank(device->hal_client,
+					false, HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+		for (i = 0; cb && i < num_entries; i++) {
+			iommu_unmap(cb->mapping->domain,
+						mem_map[i].virtual_addr,
+						mem_map[i].size);
+		}
+
+		__smem_free(device, device->qdss.mem_data);
+	}
+
+	__smem_free(device, device->iface_q_table.mem_data);
+	__smem_free(device, device->sfr.mem_data);
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		device->iface_queues[i].q_hdr = NULL;
+		device->iface_queues[i].q_array.mem_data = NULL;
+		device->iface_queues[i].q_array.align_virtual_addr = NULL;
+		device->iface_queues[i].q_array.align_device_addr = 0;
+	}
+
+	device->iface_q_table.mem_data = NULL;
+	device->iface_q_table.align_virtual_addr = NULL;
+	device->iface_q_table.align_device_addr = 0;
+
+	device->qdss.mem_data = NULL;
+	device->qdss.align_virtual_addr = NULL;
+	device->qdss.align_device_addr = 0;
+
+	device->sfr.mem_data = NULL;
+	device->sfr.align_virtual_addr = NULL;
+	device->sfr.align_device_addr = 0;
+
+	device->mem_addr.mem_data = NULL;
+	device->mem_addr.align_virtual_addr = NULL;
+	device->mem_addr.align_device_addr = 0;
+
+	msm_smem_delete_client(device->hal_client);
+	device->hal_client = NULL;
+}
+
+static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev,
+		struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping)
+{
+	int i;
+	int rc = 0;
+	dma_addr_t iova = QDSS_IOVA_START;
+	int num_entries = dev->res->qdss_addr_set.count;
+	struct addr_range *qdss_addr_tbl = dev->res->qdss_addr_set.addr_tbl;
+
+	if (!num_entries)
+		return -ENODATA;
+
+	for (i = 0; i < num_entries; i++) {
+		if (mapping) {
+			rc = iommu_map(mapping->domain, iova,
+					qdss_addr_tbl[i].start,
+					qdss_addr_tbl[i].size,
+					IOMMU_READ | IOMMU_WRITE);
+
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"IOMMU QDSS mapping failed for addr %#x\n",
+						qdss_addr_tbl[i].start);
+				rc = -ENOMEM;
+				break;
+			}
+		} else {
+			iova =  qdss_addr_tbl[i].start;
+		}
+
+		mem_map[i].virtual_addr = (u32)iova;
+		mem_map[i].physical_addr = qdss_addr_tbl[i].start;
+		mem_map[i].size = qdss_addr_tbl[i].size;
+		mem_map[i].attr = 0x0;
+
+		iova += mem_map[i].size;
+	}
+
+	if (i < num_entries) {
+		dprintk(VIDC_ERR,
+			"QDSS mapping failed, Freeing other entries %d\n", i);
+
+		for (--i; mapping && i >= 0; i--) {
+			iommu_unmap(mapping->domain,
+				mem_map[i].virtual_addr,
+				mem_map[i].size);
+		}
+	}
+
+	return rc;
+}
+
+static void __setup_ucregion_memory_map(struct venus_hfi_device *device)
+{
+	__write_register(device, VIDC_UC_REGION_ADDR,
+			(u32)device->iface_q_table.align_device_addr);
+	__write_register(device, VIDC_UC_REGION_SIZE, SHARED_QSIZE);
+	__write_register(device, VIDC_CPU_CS_SCIACMDARG2,
+			(u32)device->iface_q_table.align_device_addr);
+	__write_register(device, VIDC_CPU_CS_SCIACMDARG1, 0x01);
+	if (device->sfr.align_device_addr)
+		__write_register(device, VIDC_SFR_ADDR,
+				(u32)device->sfr.align_device_addr);
+	if (device->qdss.align_device_addr)
+		__write_register(device, VIDC_MMAP_ADDR,
+				(u32)device->qdss.align_device_addr);
+}
+
+static int __interface_queues_init(struct venus_hfi_device *dev)
+{
+	struct hfi_queue_table_header *q_tbl_hdr;
+	struct hfi_queue_header *q_hdr;
+	u32 i;
+	int rc = 0;
+	struct hfi_mem_map_table *qdss;
+	struct hfi_mem_map *mem_map;
+	struct vidc_iface_q_info *iface_q;
+	struct hfi_sfr_struct *vsfr;
+	struct vidc_mem_addr *mem_addr;
+	int offset = 0;
+	int num_entries = dev->res->qdss_addr_set.count;
+	u32 value = 0;
+	phys_addr_t fw_bias = 0;
+	size_t q_size;
+	unsigned long mem_map_table_base_addr;
+	struct context_bank_info *cb;
+
+	q_size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE;
+	mem_addr = &dev->mem_addr;
+	if (!is_iommu_present(dev->res))
+		fw_bias = dev->hal_data->firmware_base;
+	rc = __smem_alloc(dev, mem_addr, q_size, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
+	if (rc) {
+		dprintk(VIDC_ERR, "iface_q_table_alloc_fail\n");
+		goto fail_alloc_queue;
+	}
+
+	dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr;
+	dev->iface_q_table.align_device_addr = mem_addr->align_device_addr -
+					fw_bias;
+	dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
+	dev->iface_q_table.mem_data = mem_addr->mem_data;
+	offset += dev->iface_q_table.mem_size;
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		iface_q = &dev->iface_queues[i];
+		iface_q->q_array.align_device_addr = mem_addr->align_device_addr
+			+ offset - fw_bias;
+		iface_q->q_array.align_virtual_addr =
+			mem_addr->align_virtual_addr + offset;
+		iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
+		iface_q->q_array.mem_data = NULL;
+		offset += iface_q->q_array.mem_size;
+		iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(
+				dev->iface_q_table.align_virtual_addr, i);
+		__set_queue_hdr_defaults(iface_q->q_hdr);
+	}
+
+	if ((msm_vidc_fw_debug_mode & HFI_DEBUG_MODE_QDSS) && num_entries) {
+		rc = __smem_alloc(dev, mem_addr,
+				ALIGNED_QDSS_SIZE, 1, 0,
+				HAL_BUFFER_INTERNAL_CMD_QUEUE);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"qdss_alloc_fail: QDSS messages logging will not work\n");
+			dev->qdss.align_device_addr = 0;
+		} else {
+			dev->qdss.align_device_addr =
+				mem_addr->align_device_addr - fw_bias;
+			dev->qdss.align_virtual_addr =
+				mem_addr->align_virtual_addr;
+			dev->qdss.mem_size = ALIGNED_QDSS_SIZE;
+			dev->qdss.mem_data = mem_addr->mem_data;
+		}
+	}
+
+	rc = __smem_alloc(dev, mem_addr,
+			ALIGNED_SFR_SIZE, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
+	if (rc) {
+		dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work\n");
+		dev->sfr.align_device_addr = 0;
+	} else {
+		dev->sfr.align_device_addr = mem_addr->align_device_addr -
+					fw_bias;
+		dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr;
+		dev->sfr.mem_size = ALIGNED_SFR_SIZE;
+		dev->sfr.mem_data = mem_addr->mem_data;
+	}
+
+	q_tbl_hdr = (struct hfi_queue_table_header *)
+			dev->iface_q_table.align_virtual_addr;
+	q_tbl_hdr->qtbl_version = 0;
+	q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE;
+	q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header);
+	q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header);
+	q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ;
+	q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ;
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid CMDQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid MSGQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
+	/*
+	 * Set receive request to zero on debug queue as there is no
+	 * need of interrupt from video hardware for debug messages
+	 */
+	q_hdr->qhdr_rx_req = 0;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid DBGQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	value = (u32)dev->iface_q_table.align_device_addr;
+	if ((ion_phys_addr_t)value !=
+		dev->iface_q_table.align_device_addr) {
+		dprintk(VIDC_ERR,
+			"Invalid iface_q_table device address (%pa)",
+			&dev->iface_q_table.align_device_addr);
+	}
+
+	if (dev->qdss.mem_data) {
+		qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr;
+		qdss->mem_map_num_entries = num_entries;
+		mem_map_table_base_addr = dev->qdss.align_device_addr +
+			sizeof(struct hfi_mem_map_table);
+		qdss->mem_map_table_base_addr =
+			(u32)mem_map_table_base_addr;
+		if ((ion_phys_addr_t)qdss->mem_map_table_base_addr !=
+				mem_map_table_base_addr) {
+			dprintk(VIDC_ERR,
+					"Invalid mem_map_table_base_addr (%#lx)",
+					mem_map_table_base_addr);
+		}
+
+		mem_map = (struct hfi_mem_map *)(qdss + 1);
+		cb = msm_smem_get_context_bank(dev->hal_client, false,
+				HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s: failed to get context bank\n", __func__);
+			return -EINVAL;
+		}
+
+		rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->mapping);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"IOMMU mapping failed, Freeing qdss memdata\n");
+			__smem_free(dev, dev->qdss.mem_data);
+			dev->qdss.mem_data = NULL;
+			dev->qdss.align_virtual_addr = NULL;
+			dev->qdss.align_device_addr = 0;
+		}
+
+		value = (u32)dev->qdss.align_device_addr;
+		if ((ion_phys_addr_t)value !=
+				dev->qdss.align_device_addr) {
+			dprintk(VIDC_ERR, "Invalid qdss device address (%pa)",
+					&dev->qdss.align_device_addr);
+		}
+	}
+
+	vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
+	vsfr->bufSize = ALIGNED_SFR_SIZE;
+	value = (u32)dev->sfr.align_device_addr;
+	if ((ion_phys_addr_t)value !=
+		dev->sfr.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid sfr device address (%pa)",
+			&dev->sfr.align_device_addr);
+	}
+
+	__setup_ucregion_memory_map(dev);
+	return 0;
+fail_alloc_queue:
+	return -ENOMEM;
+}
+
+static int __sys_set_debug(struct venus_hfi_device *device, u32 debug)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	rc = call_hfi_pkt_op(device, sys_debug_config, pkt, debug);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Debug mode setting to FW failed\n");
+		return -ENOTEMPTY;
+	}
+
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int __sys_set_coverage(struct venus_hfi_device *device, u32 mode)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	rc = call_hfi_pkt_op(device, sys_coverage_config,
+			pkt, mode);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Coverage mode setting to FW failed\n");
+		return -ENOTEMPTY;
+	}
+
+	if (__iface_cmdq_write(device, pkt)) {
+		dprintk(VIDC_WARN, "Failed to send coverage pkt to f/w\n");
+		return -ENOTEMPTY;
+	}
+
+	return 0;
+}
+
+static int __sys_set_idle_message(struct venus_hfi_device *device,
+	bool enable)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+	if (!enable) {
+		dprintk(VIDC_DBG, "sys_idle_indicator is not enabled\n");
+		return 0;
+	}
+
+	call_hfi_pkt_op(device, sys_idle_indicator, pkt, enable);
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int __sys_set_power_control(struct venus_hfi_device *device,
+	bool enable)
+{
+	struct regulator_info *rinfo;
+	bool supported = false;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		if (rinfo->has_hw_power_collapse) {
+			supported = true;
+			break;
+		}
+	}
+
+	if (!supported)
+		return 0;
+
+	call_hfi_pkt_op(device, sys_power_control, pkt, enable);
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int venus_hfi_core_init(void *device)
+{
+	struct hfi_cmd_sys_init_packet pkt;
+	struct hfi_cmd_sys_get_property_packet version_pkt;
+	int rc = 0;
+	struct list_head *ptr, *next;
+	struct hal_session *session = NULL;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	init_completion(&release_resources_done);
+
+	rc = __load_fw(dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load Venus FW\n");
+		goto err_load_fw;
+	}
+
+	__set_state(dev, VENUS_STATE_INIT);
+
+	list_for_each_safe(ptr, next, &dev->sess_head) {
+		/* This means that session list is not empty. Kick stale
+		 * sessions out of our valid instance list, but keep the
+		 * list_head inited so that list_del (in the future, called
+		 * by session_clean()) will be valid. When client doesn't close
+		 * them, then it is a genuine leak which driver can't fix.
+		 */
+		session = list_entry(ptr, struct hal_session, list);
+		list_del_init(&session->list);
+	}
+
+	INIT_LIST_HEAD(&dev->sess_head);
+
+	__set_registers(dev);
+
+	if (!dev->hal_client) {
+		dev->hal_client = msm_smem_new_client(
+				SMEM_ION, dev->res, MSM_VIDC_UNKNOWN);
+		if (dev->hal_client == NULL) {
+			dprintk(VIDC_ERR, "Failed to alloc ION_Client\n");
+			rc = -ENODEV;
+			goto err_core_init;
+		}
+
+		dprintk(VIDC_DBG, "Dev_Virt: %pa, Reg_Virt: %pK\n",
+			&dev->hal_data->firmware_base,
+			dev->hal_data->register_base);
+
+		rc = __interface_queues_init(dev);
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to init queues\n");
+			rc = -ENOMEM;
+			goto err_core_init;
+		}
+	} else {
+		dprintk(VIDC_ERR, "hal_client exists\n");
+		rc = -EEXIST;
+		goto err_core_init;
+	}
+
+	rc = __boot_firmware(dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to start core\n");
+		rc = -ENODEV;
+		goto err_core_init;
+	}
+
+	rc =  call_hfi_pkt_op(dev, sys_init, &pkt, HFI_VIDEO_ARCH_OX);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sys init pkt\n");
+		goto err_core_init;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt)) {
+		rc = -ENOTEMPTY;
+		goto err_core_init;
+	}
+
+	rc = call_hfi_pkt_op(dev, sys_image_version, &version_pkt);
+	if (rc || __iface_cmdq_write(dev, &version_pkt))
+		dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
+
+	if (dev->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+		dev->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+		dev->qos.irq = dev->hal_data->irq;
+#endif
+		pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
+				dev->res->pm_qos_latency_us);
+	}
+
+	mutex_unlock(&dev->lock);
+	return rc;
+err_core_init:
+	__set_state(dev, VENUS_STATE_DEINIT);
+	__unload_fw(dev);
+err_load_fw:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_core_release(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->res->pm_qos_latency_us &&
+		pm_qos_request_active(&device->qos))
+		pm_qos_remove_request(&device->qos);
+	__set_state(device, VENUS_STATE_DEINIT);
+	__unload_fw(device);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __get_q_size(struct venus_hfi_device *dev, unsigned int q_index)
+{
+	struct hfi_queue_header *queue;
+	struct vidc_iface_q_info *q_info;
+	u32 write_ptr, read_ptr;
+
+	if (q_index >= VIDC_IFACEQ_NUMQ) {
+		dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
+		return -ENOENT;
+	}
+
+	q_info = &dev->iface_queues[q_index];
+	if (!q_info) {
+		dprintk(VIDC_ERR, "cannot read shared Q's\n");
+		return -ENOENT;
+	}
+
+	queue = (struct hfi_queue_header *)q_info->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present\n");
+		return -ENOENT;
+	}
+
+	write_ptr = (u32)queue->qhdr_write_idx;
+	read_ptr = (u32)queue->qhdr_read_idx;
+	return read_ptr - write_ptr;
+}
+
+static void __core_clear_interrupt(struct venus_hfi_device *device)
+{
+	u32 intr_status = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+		return;
+	}
+
+	intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS);
+
+	if (intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK ||
+		intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK ||
+		intr_status &
+			VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK) {
+		device->intr_status |= intr_status;
+		device->reg_count++;
+		dprintk(VIDC_DBG,
+			"INTERRUPT for device: %pK: times: %d interrupt_status: %d\n",
+			device, device->reg_count, intr_status);
+	} else {
+		device->spur_count++;
+		dprintk(VIDC_INFO,
+			"SPURIOUS_INTR for device: %pK: times: %d interrupt_status: %d\n",
+			device, device->spur_count, intr_status);
+	}
+
+	__write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
+	__write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
+	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
+}
+
+static int venus_hfi_core_ping(void *device)
+{
+	struct hfi_cmd_sys_ping_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	rc = call_hfi_pkt_op(dev, sys_ping, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_core_trigger_ssr(void *device,
+		enum hal_ssr_trigger_type type)
+{
+	struct hfi_cmd_sys_test_ssr_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_session_set_property(void *sess,
+					enum hal_property ptype, void *pdata)
+{
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	struct hfi_cmd_session_set_property_packet *pkt =
+		(struct hfi_cmd_session_set_property_packet *) &packet;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session || !session->device || !pdata) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype);
+
+	rc = call_hfi_pkt_op(device, session_set_property,
+			pkt, session, ptype, pdata);
+
+	if (rc == -ENOTSUPP) {
+		dprintk(VIDC_DBG,
+			"set property: unsupported prop id: %#x\n", ptype);
+		rc = 0;
+		goto err_set_prop;
+	} else if (rc) {
+		dprintk(VIDC_ERR, "set property: failed to create packet\n");
+		rc = -EINVAL;
+		goto err_set_prop;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt)) {
+		rc = -ENOTEMPTY;
+		goto err_set_prop;
+	}
+
+err_set_prop:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_property(void *sess,
+					enum hal_property ptype)
+{
+	struct hfi_cmd_session_get_property_packet pkt = {0};
+	struct hal_session *session = sess;
+	int rc = 0;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype);
+
+	rc = call_hfi_pkt_op(device, session_get_property,
+				&pkt, session, ptype);
+	if (rc) {
+		dprintk(VIDC_ERR, "get property profile: pkt failed\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt)) {
+		rc = -ENOTEMPTY;
+		dprintk(VIDC_ERR, "%s cmdq_write error\n", __func__);
+	}
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static void __set_default_sys_properties(struct venus_hfi_device *device)
+{
+	if (__sys_set_debug(device, msm_vidc_fw_debug))
+		dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n");
+	if (__sys_set_idle_message(device,
+		device->res->sys_idle_indicator ||
+		!msm_vidc_sys_idle_indicator))
+		dprintk(VIDC_WARN, "Setting idle response ON failed\n");
+	if (__sys_set_power_control(device, msm_vidc_fw_low_power_mode))
+		dprintk(VIDC_WARN, "Setting h/w power collapse ON failed\n");
+}
+
+static void __session_clean(struct hal_session *session)
+{
+	dprintk(VIDC_DBG, "deleted the session: %pK\n", session);
+	list_del(&session->list);
+	/* Poison the session handle with zeros */
+	*session = (struct hal_session){ {0} };
+	kfree(session);
+}
+
+static int venus_hfi_session_clean(void *session)
+{
+	struct hal_session *sess_close;
+	struct venus_hfi_device *device;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess_close = session;
+	device = sess_close->device;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid device handle %s\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	__session_clean(sess_close);
+	__flush_debug_queue(device, NULL);
+
+	mutex_unlock(&device->lock);
+	return 0;
+}
+
+static int venus_hfi_session_init(void *device, void *session_id,
+		enum hal_domain session_type, enum hal_video_codec codec_type,
+		void **new_session)
+{
+	struct hfi_cmd_sys_session_init_packet pkt;
+	struct venus_hfi_device *dev;
+	struct hal_session *s;
+
+	if (!device || !new_session) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	s = kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+	if (!s) {
+		dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+		goto err_session_init_fail;
+	}
+
+	s->session_id = session_id;
+	s->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER);
+	s->device = dev;
+	s->codec = codec_type;
+	s->domain = session_type;
+	dprintk(VIDC_DBG,
+		"%s: inst %pK, session %pK, codec 0x%x, domain 0x%x\n",
+		__func__, session_id, s, s->codec, s->domain);
+
+	list_add_tail(&s->list, &dev->sess_head);
+
+	__set_default_sys_properties(device);
+
+	if (call_hfi_pkt_op(dev, session_init, &pkt,
+			s, session_type, codec_type)) {
+		dprintk(VIDC_ERR, "session_init: failed to create packet\n");
+		goto err_session_init_fail;
+	}
+
+	*new_session = s;
+	if (__iface_cmdq_write(dev, &pkt))
+		goto err_session_init_fail;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+
+err_session_init_fail:
+	if (s)
+		__session_clean(s);
+	*new_session = NULL;
+	mutex_unlock(&dev->lock);
+	return -EINVAL;
+}
+
+static int __send_session_cmd(struct hal_session *session, int pkt_type)
+{
+	struct vidc_hal_session_cmd_pkt pkt;
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+
+	rc = call_hfi_pkt_op(device, session_cmd,
+			&pkt, pkt_type, session);
+	if (rc == -EPERM)
+		return 0;
+
+	if (rc) {
+		dprintk(VIDC_ERR, "send session cmd: create pkt failed\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_end(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+
+	if (!msm_vidc_fw_coverage) {
+		if (__sys_set_coverage(sess->device, msm_vidc_fw_coverage))
+			dprintk(VIDC_WARN, "Fw_coverage msg ON failed\n");
+	}
+
+	rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_END);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_abort(void *sess)
+{
+	struct hal_session *session;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	session = sess;
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	device = session->device;
+
+	mutex_lock(&device->lock);
+
+	__flush_debug_queue(device, NULL);
+	rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_ABORT);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_set_buffers(void *sess,
+				struct vidc_buffer_addr_info *buffer_info)
+{
+	struct hfi_cmd_session_set_buffers_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !buffer_info) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
+		/*
+		 * Hardware doesn't care about input buffers being
+		 * published beforehand
+		 */
+		rc = 0;
+		goto err_create_pkt;
+	}
+
+	pkt = (struct hfi_cmd_session_set_buffers_packet *)packet;
+
+	rc = call_hfi_pkt_op(device, session_set_buffers,
+			pkt, session, buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "set buffers: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type);
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_release_buffers(void *sess,
+				struct vidc_buffer_addr_info *buffer_info)
+{
+	struct hfi_cmd_session_release_buffer_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !buffer_info) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
+		rc = 0;
+		goto err_create_pkt;
+	}
+
+	pkt = (struct hfi_cmd_session_release_buffer_packet *) packet;
+
+	rc = call_hfi_pkt_op(device, session_release_buffers,
+			pkt, session, buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "release buffers: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type);
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_load_res(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_LOAD_RESOURCES);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_release_res(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_RELEASE_RESOURCES);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_start(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_START);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_continue(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_CONTINUE);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_stop(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_STOP);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __session_etb(struct hal_session *session,
+		struct vidc_frame_data *input_frame, bool relaxed)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+
+	if (session->is_decoder) {
+		struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
+
+		rc = call_hfi_pkt_op(device, session_etb_decoder,
+				&pkt, session, input_frame);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Session etb decoder: failed to create pkt\n");
+			goto err_create_pkt;
+		}
+
+		if (!relaxed)
+			rc = __iface_cmdq_write(session->device, &pkt);
+		else
+			rc = __iface_cmdq_write_relaxed(session->device,
+					&pkt, NULL);
+		if (rc)
+			goto err_create_pkt;
+	} else {
+		struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			pkt;
+
+		rc = call_hfi_pkt_op(device, session_etb_encoder,
+					 &pkt, session, input_frame);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Session etb encoder: failed to create pkt\n");
+			goto err_create_pkt;
+		}
+
+		if (!relaxed)
+			rc = __iface_cmdq_write(session->device, &pkt);
+		else
+			rc = __iface_cmdq_write_relaxed(session->device,
+					&pkt, NULL);
+		if (rc)
+			goto err_create_pkt;
+	}
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_etb(void *sess,
+				struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !input_frame) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+	rc = __session_etb(session, input_frame, false);
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int __session_ftb(struct hal_session *session,
+		struct vidc_frame_data *output_frame, bool relaxed)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+	struct hfi_cmd_session_fill_buffer_packet pkt;
+
+	rc = call_hfi_pkt_op(device, session_ftb,
+			&pkt, session, output_frame);
+	if (rc) {
+		dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (!relaxed)
+		rc = __iface_cmdq_write(session->device, &pkt);
+	else
+		rc = __iface_cmdq_write_relaxed(session->device,
+				&pkt, NULL);
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_ftb(void *sess,
+				struct vidc_frame_data *output_frame)
+{
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !output_frame) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+	rc = __session_ftb(session, output_frame, false);
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_process_batch(void *sess,
+		int num_etbs, struct vidc_frame_data etbs[],
+		int num_ftbs, struct vidc_frame_data ftbs[])
+{
+	int rc = 0, c = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+	struct hfi_cmd_session_sync_process_packet pkt;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "%s: Invalid Params\n", __func__);
+		return -EINVAL;
+	}
+
+	device = session->device;
+
+	mutex_lock(&device->lock);
+	for (c = 0; c < num_ftbs; ++c) {
+		rc = __session_ftb(session, &ftbs[c], true);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to queue batched ftb: %d\n",
+					rc);
+			goto err_etbs_and_ftbs;
+		}
+	}
+
+	for (c = 0; c < num_etbs; ++c) {
+		rc = __session_etb(session, &etbs[c], true);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to queue batched etb: %d\n",
+					rc);
+			goto err_etbs_and_ftbs;
+		}
+	}
+
+	rc = call_hfi_pkt_op(device, session_sync_process, &pkt, session);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sync packet\n");
+		goto err_etbs_and_ftbs;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+
+err_etbs_and_ftbs:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_parse_seq_hdr(void *sess,
+					struct vidc_seq_hdr *seq_hdr)
+{
+	struct hfi_cmd_session_parse_sequence_header_packet *pkt;
+	int rc = 0;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !seq_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	pkt = (struct hfi_cmd_session_parse_sequence_header_packet *)packet;
+	rc = call_hfi_pkt_op(device, session_parse_seq_header,
+			pkt, session, seq_hdr);
+	if (rc) {
+		dprintk(VIDC_ERR,
+		"Session parse seq hdr: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_seq_hdr(void *sess,
+				struct vidc_seq_hdr *seq_hdr)
+{
+	struct hfi_cmd_session_get_sequence_header_packet *pkt;
+	int rc = 0;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !seq_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	pkt = (struct hfi_cmd_session_get_sequence_header_packet *)packet;
+	rc = call_hfi_pkt_op(device, session_get_seq_hdr,
+			pkt, session, seq_hdr);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Session get seq hdr: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_buf_req(void *sess)
+{
+	struct hfi_cmd_session_get_property_packet pkt;
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "invalid session");
+		return -ENODEV;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	rc = call_hfi_pkt_op(device, session_get_buf_req,
+			&pkt, session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Session get buf req: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
+{
+	struct hfi_cmd_session_flush_packet pkt;
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "invalid session");
+		return -ENODEV;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	rc = call_hfi_pkt_op(device, session_flush,
+			&pkt, session, flush_mode);
+	if (rc) {
+		dprintk(VIDC_ERR, "Session flush: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int __check_core_registered(struct hal_device_data core,
+		phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size,
+		phys_addr_t irq)
+{
+	struct venus_hfi_device *device;
+	struct list_head *curr, *next;
+
+	if (core.dev_count) {
+		list_for_each_safe(curr, next, &core.dev_head) {
+			device = list_entry(curr,
+				struct venus_hfi_device, list);
+			if (device && device->hal_data->irq == irq &&
+				(CONTAINS(device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE, fw_addr) ||
+				CONTAINS(fw_addr, FIRMWARE_SIZE,
+						device->hal_data->
+						firmware_base) ||
+				CONTAINS(device->hal_data->
+						register_base,
+						reg_size, reg_addr) ||
+				CONTAINS(reg_addr, reg_size,
+						device->hal_data->
+						register_base) ||
+				OVERLAPS(device->hal_data->
+						register_base,
+						reg_size, reg_addr, reg_size) ||
+				OVERLAPS(reg_addr, reg_size,
+						device->hal_data->
+						register_base, reg_size) ||
+				OVERLAPS(device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE, fw_addr,
+						FIRMWARE_SIZE) ||
+				OVERLAPS(fw_addr, FIRMWARE_SIZE,
+						device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE))) {
+				return 0;
+			}
+			dprintk(VIDC_INFO, "Device not registered\n");
+			return -EINVAL;
+		}
+	} else {
+		dprintk(VIDC_INFO, "no device Registered\n");
+	}
+
+	return -EINVAL;
+}
+
+static void __process_fatal_error(
+		struct venus_hfi_device *device)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device->device_id;
+	device->callback(HAL_SYS_ERROR, &cmd_done);
+}
+
+static int __prepare_pc(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct hfi_cmd_sys_pc_prep_packet pkt;
+
+	rc = call_hfi_pkt_op(device, sys_pc_prep, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
+		goto err_pc_prep;
+	}
+
+	if (__iface_cmdq_write(device, &pkt))
+		rc = -ENOTEMPTY;
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+err_pc_prep:
+	return rc;
+}
+
+static void venus_hfi_pm_handler(struct work_struct *work)
+{
+	int rc = 0;
+	u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
+	int count = 0;
+	const int max_tries = 5;
+	struct venus_hfi_device *device = list_first_entry(
+			&hal_ctxt.dev_head, struct venus_hfi_device, list);
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+		return;
+	}
+
+	/*
+	 * It is ok to check this variable outside the lock since
+	 * it is being updated in this context only
+	 */
+	if (device->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) {
+		dprintk(VIDC_WARN, "Failed to PC for %d times\n",
+				device->skip_pc_count);
+		device->skip_pc_count = 0;
+		__process_fatal_error(device);
+		return;
+	}
+	mutex_lock(&device->lock);
+	if (!device->power_enabled) {
+		dprintk(VIDC_DBG, "%s: Power already disabled\n",
+				__func__);
+		goto exit;
+	}
+
+	rc = __core_in_valid_state(device);
+	if (!rc) {
+		dprintk(VIDC_WARN,
+				"Core is in bad state, Skipping power collapse\n");
+		goto skip_power_off;
+	}
+	pc_ready = __read_register(device, VIDC_CPU_CS_SCIACMDARG0) &
+		VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY;
+	if (!pc_ready) {
+		wfi_status = __read_register(device,
+				VIDC_WRAPPER_CPU_STATUS);
+		idle_status = __read_register(device,
+				VIDC_CPU_CS_SCIACMDARG0);
+		if (!(wfi_status & BIT(0)) ||
+				!(idle_status & BIT(30))) {
+			dprintk(VIDC_WARN, "Skipping PC\n");
+			goto skip_power_off;
+		}
+
+		rc = __prepare_pc(device);
+		if (rc) {
+			dprintk(VIDC_WARN, "Failed PC %d\n", rc);
+			goto skip_power_off;
+		}
+
+		while (count < max_tries) {
+			wfi_status = __read_register(device,
+					VIDC_WRAPPER_CPU_STATUS);
+			pc_ready = __read_register(device,
+					VIDC_CPU_CS_SCIACMDARG0);
+			if ((wfi_status & BIT(0)) && (pc_ready &
+				VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
+				break;
+			usleep_range(1000, 1500);
+			count++;
+		}
+
+		if (count == max_tries) {
+			dprintk(VIDC_ERR,
+					"Skip PC. Core is not in right state (%#x, %#x)\n",
+					wfi_status, pc_ready);
+			goto skip_power_off;
+		}
+	}
+
+	rc = __suspend(device);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed venus power off\n");
+
+	/* Cancel pending delayed works if any */
+	cancel_delayed_work(&venus_hfi_pm_work);
+	device->skip_pc_count = 0;
+
+	mutex_unlock(&device->lock);
+	return;
+
+skip_power_off:
+	device->skip_pc_count++;
+	dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n",
+		device->skip_pc_count, wfi_status, idle_status, pc_ready);
+	queue_delayed_work(device->venus_pm_workq,
+			&venus_hfi_pm_work,
+			msecs_to_jiffies(msm_vidc_pwr_collapse_delay));
+exit:
+	mutex_unlock(&device->lock);
+}
+
+static void __dump_venus_debug_registers(struct venus_hfi_device *device)
+{
+	u32 reg;
+
+	dprintk(VIDC_ERR, "Dumping Venus registers...\n");
+	reg = __read_register(device, VENUS_VBIF_XIN_HALT_CTRL1);
+	dprintk(VIDC_ERR, "VENUS_VBIF_XIN_HALT_CTRL1: 0x%x\n", reg);
+
+	reg = __read_register(device,
+		VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS);
+	dprintk(VIDC_ERR,
+		"VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS: 0x%x\n", reg);
+
+	reg = __read_register(device, VIDC_WRAPPER_CPU_STATUS);
+	dprintk(VIDC_ERR, "VIDC_WRAPPER_CPU_STATUS: 0x%x\n", reg);
+
+	reg = __read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+	dprintk(VIDC_ERR, "VIDC_CPU_CS_SCIACMDARG0: 0x%x\n", reg);
+}
+
+static void __process_sys_error(struct venus_hfi_device *device)
+{
+	struct hfi_sfr_struct *vsfr = NULL;
+
+	__set_state(device, VENUS_STATE_DEINIT);
+
+	/* Once SYS_ERROR received from HW, it is safe to halt the AXI.
+	 * With SYS_ERROR, Venus FW may have crashed and HW might be
+	 * active and causing unnecessary transactions. Hence it is
+	 * safe to stop all AXI transactions from venus sub-system.
+	 */
+	if (__halt_axi(device))
+		dprintk(VIDC_WARN, "Failed to halt AXI after SYS_ERROR\n");
+
+	vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr;
+	if (vsfr) {
+		void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize);
+		/* SFR isn't guaranteed to be NULL terminated
+		 * since SYS_ERROR indicates that Venus is in the
+		 * process of crashing.
+		 */
+		if (p == NULL)
+			vsfr->rg_data[vsfr->bufSize - 1] = '\0';
+
+		dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
+				vsfr->rg_data);
+	}
+}
+
+static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet)
+{
+	bool local_packet = false;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return;
+	}
+
+	if (!packet) {
+		packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+		if (!packet) {
+			dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n",
+				__func__);
+			return;
+		}
+
+		local_packet = true;
+	}
+
+	while (!__iface_dbgq_read(device, packet)) {
+		struct hfi_msg_sys_coverage_packet *pkt =
+			(struct hfi_msg_sys_coverage_packet *) packet;
+		if (pkt->packet_type == HFI_MSG_SYS_COV) {
+			int stm_size = 0;
+
+			stm_size = stm_log_inv_ts(0, 0,
+				pkt->rg_msg_data, pkt->msg_size);
+			if (stm_size == 0)
+				dprintk(VIDC_ERR,
+					"In %s, stm_log returned size of 0\n",
+					__func__);
+		} else {
+			struct hfi_msg_sys_debug_packet *pkt =
+				(struct hfi_msg_sys_debug_packet *) packet;
+			dprintk(VIDC_FW, "%s", pkt->rg_msg_data);
+		}
+	}
+
+	if (local_packet)
+		kfree(packet);
+}
+
+static struct hal_session *__get_session(struct venus_hfi_device *device,
+		u32 session_id)
+{
+	struct hal_session *temp = NULL;
+
+	list_for_each_entry(temp, &device->sess_head, list) {
+		if (session_id == hash32_ptr(temp))
+			return temp;
+	}
+
+	return NULL;
+}
+
+static int __response_handler(struct venus_hfi_device *device)
+{
+	struct msm_vidc_cb_info *packets;
+	int packet_count = 0;
+	u8 *raw_packet = NULL;
+	bool requeue_pm_work = true;
+
+	if (!device || device->state != VENUS_STATE_INIT)
+		return 0;
+
+	packets = device->response_pkt;
+
+	raw_packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+	if (!raw_packet || !packets) {
+		dprintk(VIDC_ERR, "%s: Failed to allocate memory\n",  __func__);
+		kfree(raw_packet);
+		return 0;
+	}
+
+	if (device->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) {
+		struct hfi_sfr_struct *vsfr = (struct hfi_sfr_struct *)
+			device->sfr.align_virtual_addr;
+		struct msm_vidc_cb_info info = {
+			.response_type = HAL_SYS_WATCHDOG_TIMEOUT,
+			.response.cmd = {
+				.device_id = device->device_id,
+			}
+		};
+
+		if (vsfr)
+			dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
+					vsfr->rg_data);
+
+		__dump_venus_debug_registers(device);
+		dprintk(VIDC_ERR, "Received watchdog timeout\n");
+		packets[packet_count++] = info;
+		goto exit;
+	}
+
+	/* Bleed the msg queue dry of packets */
+	while (!__iface_msgq_read(device, raw_packet)) {
+		void **session_id = NULL;
+		struct msm_vidc_cb_info *info = &packets[packet_count++];
+		struct vidc_hal_sys_init_done sys_init_done = {0};
+		int rc = 0;
+
+		rc = hfi_process_msg_packet(device->device_id,
+			(struct vidc_hal_msg_pkt_hdr *)raw_packet, info);
+		if (rc) {
+			dprintk(VIDC_WARN,
+					"Corrupt/unknown packet found, discarding\n");
+			--packet_count;
+			continue;
+		}
+
+		/* Process the packet types that we're interested in */
+		switch (info->response_type) {
+		case HAL_SYS_ERROR:
+			__dump_venus_debug_registers(device);
+			__process_sys_error(device);
+			break;
+		case HAL_SYS_RELEASE_RESOURCE_DONE:
+			dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n");
+			complete(&release_resources_done);
+			break;
+		case HAL_SYS_INIT_DONE:
+			dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n");
+			/* Video driver intentionally does not unset
+			 * IMEM on venus to simplify power collapse.
+			 */
+			if (__set_imem(device, &device->resources.imem))
+				dprintk(VIDC_WARN,
+				"Failed to set IMEM. Performance will be impacted\n");
+			sys_init_done.capabilities =
+				device->sys_init_capabilities;
+			hfi_process_sys_init_done_prop_read(
+				(struct hfi_msg_sys_init_done_packet *)
+					raw_packet, &sys_init_done);
+			info->response.cmd.data.sys_init_done = sys_init_done;
+			break;
+		case HAL_SESSION_LOAD_RESOURCE_DONE:
+			/*
+			 * Work around for H/W bug, need to re-program these
+			 * registers as part of a handshake agreement with the
+			 * firmware.  This strictly only needs to be done for
+			 * decoder secure sessions, but there's no harm in doing
+			 * so for all sessions as it's at worst a NO-OP.
+			 */
+			__set_threshold_registers(device);
+			break;
+		default:
+			break;
+		}
+
+		/* For session-related packets, validate session */
+		switch (info->response_type) {
+		case HAL_SESSION_LOAD_RESOURCE_DONE:
+		case HAL_SESSION_INIT_DONE:
+		case HAL_SESSION_END_DONE:
+		case HAL_SESSION_ABORT_DONE:
+		case HAL_SESSION_START_DONE:
+		case HAL_SESSION_STOP_DONE:
+		case HAL_SESSION_FLUSH_DONE:
+		case HAL_SESSION_SUSPEND_DONE:
+		case HAL_SESSION_RESUME_DONE:
+		case HAL_SESSION_SET_PROP_DONE:
+		case HAL_SESSION_GET_PROP_DONE:
+		case HAL_SESSION_PARSE_SEQ_HDR_DONE:
+		case HAL_SESSION_RELEASE_BUFFER_DONE:
+		case HAL_SESSION_RELEASE_RESOURCE_DONE:
+		case HAL_SESSION_PROPERTY_INFO:
+			session_id = &info->response.cmd.session_id;
+			break;
+		case HAL_SESSION_ERROR:
+		case HAL_SESSION_GET_SEQ_HDR_DONE:
+		case HAL_SESSION_ETB_DONE:
+		case HAL_SESSION_FTB_DONE:
+			session_id = &info->response.data.session_id;
+			break;
+		case HAL_SESSION_EVENT_CHANGE:
+			session_id = &info->response.event.session_id;
+			break;
+		case HAL_RESPONSE_UNUSED:
+		default:
+			session_id = NULL;
+			break;
+		}
+
+		/*
+		 * hfi_process_msg_packet provides a session_id that's a hashed
+		 * value of struct hal_session, we need to coerce the hashed
+		 * value back to pointer that we can use. Ideally, hfi_process\
+		 * _msg_packet should take care of this, but it doesn't have
+		 * required information for it
+		 */
+		if (session_id) {
+			struct hal_session *session = NULL;
+
+			if (upper_32_bits((uintptr_t)*session_id) != 0) {
+				dprintk(VIDC_WARN,
+					"Upper 32 bits of session_id != 0\n");
+				WARN_ON(VIDC_DBG_WARN_ENABLE);
+			}
+			session = __get_session(device,
+					(u32)(uintptr_t)*session_id);
+			if (!session) {
+				dprintk(VIDC_ERR,
+						"Received a packet (%#x) for an unrecognized session (%pK), discarding\n",
+						info->response_type,
+						*session_id);
+				--packet_count;
+				continue;
+			}
+
+			*session_id = session->session_id;
+		}
+
+		if (packet_count >= max_packets &&
+				__get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
+			dprintk(VIDC_WARN,
+					"Too many packets in message queue to handle at once, deferring read\n");
+			break;
+		}
+	}
+
+	if (requeue_pm_work && device->res->sw_power_collapsible) {
+		cancel_delayed_work(&venus_hfi_pm_work);
+		if (!queue_delayed_work(device->venus_pm_workq,
+			&venus_hfi_pm_work,
+			msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
+			dprintk(VIDC_ERR, "PM work already scheduled\n");
+		}
+	}
+
+exit:
+	__flush_debug_queue(device, raw_packet);
+
+	kfree(raw_packet);
+	return packet_count;
+}
+
+static void venus_hfi_core_work_handler(struct work_struct *work)
+{
+	struct venus_hfi_device *device = list_first_entry(
+		&hal_ctxt.dev_head, struct venus_hfi_device, list);
+	int num_responses = 0, i = 0;
+
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "Handling interrupt\n");
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__);
+		goto err_no_work;
+	}
+
+	if (!device->callback) {
+		dprintk(VIDC_ERR, "No interrupt callback function: %pK\n",
+				device);
+		goto err_no_work;
+	}
+
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__);
+		goto err_no_work;
+	}
+
+	__core_clear_interrupt(device);
+	num_responses = __response_handler(device);
+
+err_no_work:
+	/* We need re-enable the irq which was disabled in ISR handler */
+	if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+		enable_irq(device->hal_data->irq);
+
+	mutex_unlock(&device->lock);
+
+	/*
+	 * Issue the callbacks outside of the locked contex to preserve
+	 * re-entrancy.
+	 */
+
+	for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) &&
+		i < num_responses; ++i) {
+		struct msm_vidc_cb_info *r = &device->response_pkt[i];
+
+		device->callback(r->response_type, &r->response);
+	}
+
+	/*
+	 * XXX: Don't add any code beyond here.  Reacquiring locks after release
+	 * it above doesn't guarantee the atomicity that we're aiming for.
+	 */
+}
+
+static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
+
+static irqreturn_t venus_hfi_isr(int irq, void *dev)
+{
+	struct venus_hfi_device *device = dev;
+
+	dprintk(VIDC_INFO, "Received an interrupt %d\n", irq);
+	disable_irq_nosync(irq);
+	queue_work(device->vidc_workq, &venus_hfi_work);
+	return IRQ_HANDLED;
+}
+
+static int __init_regs_and_interrupts(struct venus_hfi_device *device,
+		struct msm_vidc_platform_resources *res)
+{
+	struct hal_data *hal = NULL;
+	int rc = 0;
+
+	rc = __check_core_registered(hal_ctxt, res->firmware_base,
+			(u8 *)(uintptr_t)res->register_base,
+			res->register_size, res->irq);
+	if (!rc) {
+		dprintk(VIDC_ERR, "Core present/Already added\n");
+		rc = -EEXIST;
+		goto err_core_init;
+	}
+
+	dprintk(VIDC_DBG, "HAL_DATA will be assigned now\n");
+	hal = (struct hal_data *)
+		kzalloc(sizeof(struct hal_data), GFP_KERNEL);
+	if (!hal) {
+		dprintk(VIDC_ERR, "Failed to alloc\n");
+		rc = -ENOMEM;
+		goto err_core_init;
+	}
+
+	hal->irq = res->irq;
+	hal->firmware_base = res->firmware_base;
+	hal->register_base = devm_ioremap_nocache(&res->pdev->dev,
+			res->register_base, res->register_size);
+	hal->register_size = res->register_size;
+	if (!hal->register_base) {
+		dprintk(VIDC_ERR,
+			"could not map reg addr %pa of size %d\n",
+			&res->register_base, res->register_size);
+		goto error_irq_fail;
+	}
+
+	device->hal_data = hal;
+	rc = request_irq(res->irq, venus_hfi_isr, IRQF_TRIGGER_HIGH,
+			"msm_vidc", device);
+	if (unlikely(rc)) {
+		dprintk(VIDC_ERR, "() :request_irq failed\n");
+		goto error_irq_fail;
+	}
+
+	disable_irq_nosync(res->irq);
+	dprintk(VIDC_INFO,
+		"firmware_base = %pa, register_base = %pa, register_size = %d\n",
+		&res->firmware_base, &res->register_base,
+		res->register_size);
+	return rc;
+
+error_irq_fail:
+	kfree(hal);
+err_core_init:
+	return rc;
+
+}
+
+static inline void __deinit_clocks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl;
+
+	device->clk_freq = 0;
+	venus_hfi_for_each_clock_reverse(device, cl) {
+		if (cl->clk) {
+			clk_put(cl->clk);
+			cl->clk = NULL;
+		}
+	}
+}
+
+static inline int __init_clocks(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct clock_info *cl = NULL;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		int i = 0;
+
+		dprintk(VIDC_DBG, "%s: scalable? %d, count %d\n",
+				cl->name, cl->has_scaling, cl->count);
+		for (i = 0; i < cl->count; ++i) {
+			dprintk(VIDC_DBG,
+				"\tload = %d, freq = %d codecs supported %#x\n",
+				cl->load_freq_tbl[i].load,
+				cl->load_freq_tbl[i].freq,
+				cl->load_freq_tbl[i].supported_codecs);
+		}
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (!cl->clk) {
+			cl->clk = clk_get(&device->res->pdev->dev, cl->name);
+			if (IS_ERR_OR_NULL(cl->clk)) {
+				dprintk(VIDC_ERR,
+					"Failed to get clock: %s\n", cl->name);
+				rc = PTR_ERR(cl->clk) ?: -EINVAL;
+				cl->clk = NULL;
+				goto err_clk_get;
+			}
+		}
+	}
+	device->clk_freq = 0;
+	return 0;
+
+err_clk_get:
+	__deinit_clocks(device);
+	return rc;
+}
+
+
+static inline void __disable_unprepare_clks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		usleep_range(100, 500);
+		dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n",
+				cl->name);
+		clk_disable_unprepare(cl->clk);
+	}
+}
+
+static inline int __prepare_enable_clks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl = NULL, *cl_fail = NULL;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		/*
+		 * For the clocks we control, set the rate prior to preparing
+		 * them.  Since we don't really have a load at this point, scale
+		 * it to the lowest frequency possible
+		 */
+		if (cl->has_scaling)
+			clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
+
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to enable clocks\n");
+			cl_fail = cl;
+			goto fail_clk_enable;
+		}
+
+		dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name);
+	}
+
+	__write_register(device, VIDC_WRAPPER_CLOCK_CONFIG, 0);
+	__write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0);
+	return rc;
+
+fail_clk_enable:
+	venus_hfi_for_each_clock(device, cl) {
+		if (cl_fail == cl)
+			break;
+		usleep_range(100, 500);
+		dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n",
+			cl->name);
+		clk_disable_unprepare(cl->clk);
+	}
+
+	return rc;
+}
+
+static void __deinit_bus(struct venus_hfi_device *device)
+{
+	struct bus_info *bus = NULL;
+
+	if (!device)
+		return;
+
+	kfree(device->bus_vote.data);
+	device->bus_vote = DEFAULT_BUS_VOTE;
+
+	venus_hfi_for_each_bus_reverse(device, bus) {
+		devfreq_remove_device(bus->devfreq);
+		bus->devfreq = NULL;
+		dev_set_drvdata(bus->dev, NULL);
+
+		msm_bus_scale_unregister(bus->client);
+		bus->client = NULL;
+	}
+}
+
+static int __init_bus(struct venus_hfi_device *device)
+{
+	struct bus_info *bus = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	venus_hfi_for_each_bus(device, bus) {
+		struct devfreq_dev_profile profile = {
+			.initial_freq = 0,
+			.polling_ms = INT_MAX,
+			.freq_table = NULL,
+			.max_state = 0,
+			.target = __devfreq_target,
+			.get_dev_status = __devfreq_get_status,
+			.exit = NULL,
+		};
+
+		/*
+		 * This is stupid, but there's no other easy way to ahold
+		 * of struct bus_info in venus_hfi_devfreq_*()
+		 */
+		WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n",
+				dev_name(bus->dev));
+		dev_set_drvdata(bus->dev, device);
+
+		bus->client = msm_bus_scale_register(bus->master, bus->slave,
+				bus->name, false);
+		if (IS_ERR_OR_NULL(bus->client)) {
+			rc = PTR_ERR(bus->client) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR, "Failed to register bus %s: %d\n",
+					bus->name, rc);
+			bus->client = NULL;
+			goto err_add_dev;
+		}
+
+		bus->devfreq_prof = profile;
+		bus->devfreq = devfreq_add_device(bus->dev,
+				&bus->devfreq_prof, bus->governor, NULL);
+		if (IS_ERR_OR_NULL(bus->devfreq)) {
+			rc = PTR_ERR(bus->devfreq) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR,
+					"Failed to add devfreq device for bus %s and governor %s: %d\n",
+					bus->name, bus->governor, rc);
+			bus->devfreq = NULL;
+			goto err_add_dev;
+		}
+
+		/*
+		 * Devfreq starts monitoring immediately, since we are just
+		 * initializing stuff at this point, force it to suspend
+		 */
+		devfreq_suspend_device(bus->devfreq);
+	}
+
+	device->bus_vote = DEFAULT_BUS_VOTE;
+	return 0;
+
+err_add_dev:
+	__deinit_bus(device);
+	return rc;
+}
+
+static void __deinit_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator_reverse(device, rinfo) {
+		if (rinfo->regulator) {
+			regulator_put(rinfo->regulator);
+			rinfo->regulator = NULL;
+		}
+	}
+}
+
+static int __init_regulators(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rinfo->regulator = regulator_get(&device->res->pdev->dev,
+				rinfo->name);
+		if (IS_ERR_OR_NULL(rinfo->regulator)) {
+			rc = PTR_ERR(rinfo->regulator) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR, "Failed to get regulator: %s\n",
+					rinfo->name);
+			rinfo->regulator = NULL;
+			goto err_reg_get;
+		}
+	}
+
+	return 0;
+
+err_reg_get:
+	__deinit_regulators(device);
+	return rc;
+}
+
+static int __init_resources(struct venus_hfi_device *device,
+				struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+
+	rc = __init_regulators(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get all regulators\n");
+		return -ENODEV;
+	}
+
+	rc = __init_clocks(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init clocks\n");
+		rc = -ENODEV;
+		goto err_init_clocks;
+	}
+
+	rc = __init_bus(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init bus: %d\n", rc);
+		goto err_init_bus;
+	}
+
+	device->sys_init_capabilities =
+		kzalloc(sizeof(struct msm_vidc_capability)
+		* VIDC_MAX_SESSIONS, GFP_TEMPORARY);
+
+	return rc;
+
+err_init_bus:
+	__deinit_clocks(device);
+err_init_clocks:
+	__deinit_regulators(device);
+	return rc;
+}
+
+static void __deinit_resources(struct venus_hfi_device *device)
+{
+	__deinit_bus(device);
+	__deinit_clocks(device);
+	__deinit_regulators(device);
+	kfree(device->sys_init_capabilities);
+	device->sys_init_capabilities = NULL;
+}
+
+static int __protect_cp_mem(struct venus_hfi_device *device)
+{
+	struct tzbsp_memprot memprot;
+	unsigned int resp = 0;
+	int rc = 0;
+	struct context_bank_info *cb;
+	struct scm_desc desc = {0};
+
+	if (!device)
+		return -EINVAL;
+
+	memprot.cp_start = 0x0;
+	memprot.cp_size = 0x0;
+	memprot.cp_nonpixel_start = 0x0;
+	memprot.cp_nonpixel_size = 0x0;
+
+	list_for_each_entry(cb, &device->res->context_banks, list) {
+		if (!strcmp(cb->name, "venus_ns")) {
+			desc.args[1] = memprot.cp_size =
+				cb->addr_range.start;
+			dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n",
+				__func__, memprot.cp_size);
+		}
+
+		if (!strcmp(cb->name, "venus_sec_non_pixel")) {
+			desc.args[2] = memprot.cp_nonpixel_start =
+				cb->addr_range.start;
+			desc.args[3] = memprot.cp_nonpixel_size =
+				cb->addr_range.size;
+			dprintk(VIDC_DBG,
+				"%s memprot.cp_nonpixel_start: %#x size: %#x\n",
+				__func__, memprot.cp_nonpixel_start,
+				memprot.cp_nonpixel_size);
+		}
+	}
+
+	if (!is_scm_armv8()) {
+		rc = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
+			sizeof(memprot), &resp, sizeof(resp));
+	} else {
+		desc.arginfo = SCM_ARGS(4);
+		rc = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+			       TZBSP_MEM_PROTECT_VIDEO_VAR), &desc);
+		resp = desc.ret[0];
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to protect memory(%d) response: %d\n",
+				rc, resp);
+	}
+
+	trace_venus_hfi_var_done(
+		memprot.cp_start, memprot.cp_size,
+		memprot.cp_nonpixel_start, memprot.cp_nonpixel_size);
+	return rc;
+}
+
+static int __disable_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	dprintk(VIDC_DBG, "Disabling regulator %s\n", rinfo->name);
+
+	/*
+	 * This call is needed. Driver needs to acquire the control back
+	 * from HW in order to disable the regualtor. Else the behavior
+	 * is unknown.
+	 */
+
+	rc = __acquire_regulator(rinfo);
+	if (rc) {
+		/* This is somewhat fatal, but nothing we can do
+		 * about it. We can't disable the regulator w/o
+		 * getting it back under s/w control
+		 */
+		dprintk(VIDC_WARN,
+			"Failed to acquire control on %s\n",
+			rinfo->name);
+
+		goto disable_regulator_failed;
+	}
+
+	rc = regulator_disable(rinfo->regulator);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Failed to disable %s: %d\n",
+			rinfo->name, rc);
+		goto disable_regulator_failed;
+	}
+
+	return 0;
+disable_regulator_failed:
+
+	/* Bring attention to this issue */
+	WARN_ON(VIDC_DBG_WARN_ENABLE);
+	return rc;
+}
+
+static int __enable_hw_power_collapse(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!msm_vidc_fw_low_power_mode) {
+		dprintk(VIDC_DBG, "Not enabling hardware power collapse\n");
+		return 0;
+	}
+
+	rc = __hand_off_regulators(device);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"%s : Failed to enable HW power collapse %d\n",
+				__func__, rc);
+	return rc;
+}
+
+static int __enable_regulators(struct venus_hfi_device *device)
+{
+	int rc = 0, c = 0;
+	struct regulator_info *rinfo;
+
+	dprintk(VIDC_DBG, "Enabling regulators\n");
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rc = regulator_enable(rinfo->regulator);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to enable %s: %d\n",
+					rinfo->name, rc);
+			goto err_reg_enable_failed;
+		}
+
+		dprintk(VIDC_DBG, "Enabled regulator %s\n",
+				rinfo->name);
+		c++;
+	}
+
+	return 0;
+
+err_reg_enable_failed:
+	venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+		__disable_regulator(rinfo);
+
+	return rc;
+}
+
+static int __disable_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo;
+	int rc = 0;
+
+	dprintk(VIDC_DBG, "Disabling regulators\n");
+
+	venus_hfi_for_each_regulator_reverse(device, rinfo)
+		__disable_regulator(rinfo);
+
+	return rc;
+}
+
+static int __venus_power_on(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (device->power_enabled)
+		return 0;
+
+	device->power_enabled = true;
+	/* Vote for all hardware resources */
+	rc = __vote_buses(device, device->bus_vote.data,
+			device->bus_vote.data_count);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to vote buses, err: %d\n", rc);
+		goto fail_vote_buses;
+	}
+
+	rc = __alloc_imem(device, device->res->imem_size);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate IMEM\n");
+		goto fail_alloc_imem;
+	}
+
+	rc = __enable_regulators(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable GDSC, err = %d\n", rc);
+		goto fail_enable_gdsc;
+	}
+
+	rc = __prepare_enable_clks(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
+		goto fail_enable_clks;
+	}
+
+	rc = __scale_clocks(device, 0, NULL, 0);
+	if (rc) {
+		dprintk(VIDC_WARN,
+				"Failed to scale clocks, performance might be affected\n");
+		rc = 0;
+	}
+	__write_register(device, VIDC_WRAPPER_INTR_MASK,
+			VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
+	device->intr_status = 0;
+	enable_irq(device->hal_data->irq);
+
+	/*
+	 * Hand off control of regulators to h/w _after_ enabling clocks.
+	 * Note that the GDSC will turn off when switching from normal
+	 * (s/w triggered) to fast (HW triggered) unless the h/w vote is
+	 * present. Since Venus isn't up yet, the GDSC will be off briefly.
+	 */
+	if (__enable_hw_power_collapse(device))
+		dprintk(VIDC_ERR, "Failed to enabled inter-frame PC\n");
+
+	return rc;
+
+fail_enable_clks:
+	__disable_regulators(device);
+fail_enable_gdsc:
+	__free_imem(device);
+fail_alloc_imem:
+	__unvote_buses(device);
+fail_vote_buses:
+	device->power_enabled = false;
+	return rc;
+}
+
+static void __venus_power_off(struct venus_hfi_device *device, bool halt_axi)
+{
+	if (!device->power_enabled)
+		return;
+
+	if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+		disable_irq_nosync(device->hal_data->irq);
+	device->intr_status = 0;
+
+	/* Halt the AXI to make sure there are no pending transactions.
+	 * Clocks should be unprepared after making sure axi is halted.
+	 */
+	if (halt_axi && __halt_axi(device))
+		dprintk(VIDC_WARN, "Failed to halt AXI\n");
+
+	__disable_unprepare_clks(device);
+	if (__disable_regulators(device))
+		dprintk(VIDC_WARN, "Failed to disable regulators\n");
+
+	__free_imem(device);
+
+	if (__unvote_buses(device))
+		dprintk(VIDC_WARN, "Failed to unvote for buses\n");
+	device->power_enabled = false;
+}
+
+static inline int __suspend(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	} else if (!device->power_enabled) {
+		dprintk(VIDC_DBG, "Power already disabled\n");
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "Entering power collapse\n");
+
+	if (device->res->pm_qos_latency_us &&
+		pm_qos_request_active(&device->qos))
+		pm_qos_remove_request(&device->qos);
+
+	rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to suspend video core %d\n", rc);
+		goto err_tzbsp_suspend;
+	}
+
+	__venus_power_off(device, true);
+	dprintk(VIDC_INFO, "Venus power collapsed\n");
+	return rc;
+
+err_tzbsp_suspend:
+	return rc;
+}
+
+static inline int __resume(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	} else if (device->power_enabled) {
+		dprintk(VIDC_DBG, "Power is already enabled\n");
+		goto exit;
+	} else if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "venus_hfi_device in deinit state.");
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_DBG, "Resuming from power collapse\n");
+	rc = __venus_power_on(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to power on venus\n");
+		goto err_venus_power_on;
+	}
+
+	/* Reboot the firmware */
+	rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
+		goto err_set_video_state;
+	}
+
+	/*
+	 * Re-program all of the registers that get reset as a result of
+	 * regulator_disable() and _enable()
+	 */
+	__set_registers(device);
+	__setup_ucregion_memory_map(device);
+	/* Wait for boot completion */
+	rc = __boot_firmware(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to reset venus core\n");
+		goto err_reset_core;
+	}
+
+	/*
+	 * Work around for H/W bug, need to reprogram these registers once
+	 * firmware is out reset
+	 */
+	__set_threshold_registers(device);
+
+	if (device->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+		device->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+		device->qos.irq = device->hal_data->irq;
+#endif
+		pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY,
+				device->res->pm_qos_latency_us);
+	}
+	dprintk(VIDC_INFO, "Resumed from power collapse\n");
+exit:
+	device->skip_pc_count = 0;
+	return rc;
+err_reset_core:
+	__tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+err_set_video_state:
+	__venus_power_off(device, true);
+err_venus_power_on:
+	dprintk(VIDC_ERR, "Failed to resume from power collapse\n");
+	return rc;
+}
+
+static int __load_fw(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	/* Initialize resources */
+	rc = __init_resources(device, device->res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+		goto fail_init_res;
+	}
+
+	rc = __initialize_packetization(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to initialize packetization\n");
+		goto fail_init_pkt;
+	}
+	trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc venus_fw load start");
+
+	rc = __venus_power_on(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to power on venus in in load_fw\n");
+		goto fail_venus_power_on;
+	}
+
+	if ((!device->res->use_non_secure_pil && !device->res->firmware_base)
+			|| device->res->use_non_secure_pil) {
+		if (!device->resources.fw.cookie)
+			device->resources.fw.cookie =
+				subsystem_get_with_fwname("venus",
+				device->res->fw_name);
+
+		if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
+			dprintk(VIDC_ERR, "Failed to download firmware\n");
+			device->resources.fw.cookie = NULL;
+			rc = -ENOMEM;
+			goto fail_load_fw;
+		}
+	}
+
+	if (!device->res->use_non_secure_pil && !device->res->firmware_base) {
+		rc = __protect_cp_mem(device);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to protect memory\n");
+			goto fail_protect_mem;
+		}
+	}
+	trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+	return rc;
+fail_protect_mem:
+	if (device->resources.fw.cookie)
+		subsystem_put(device->resources.fw.cookie);
+	device->resources.fw.cookie = NULL;
+fail_load_fw:
+	__venus_power_off(device, true);
+fail_venus_power_on:
+fail_init_pkt:
+	__deinit_resources(device);
+fail_init_res:
+	trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+	return rc;
+}
+
+static void __unload_fw(struct venus_hfi_device *device)
+{
+	if (!device->resources.fw.cookie)
+		return;
+
+	cancel_delayed_work(&venus_hfi_pm_work);
+	if (device->state != VENUS_STATE_DEINIT)
+		flush_workqueue(device->venus_pm_workq);
+
+	__vote_buses(device, NULL, 0);
+	subsystem_put(device->resources.fw.cookie);
+	__interface_queues_release(device);
+	__venus_power_off(device, false);
+	device->resources.fw.cookie = NULL;
+	__deinit_resources(device);
+}
+
+static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info)
+{
+	int i = 0, j = 0;
+	struct venus_hfi_device *device = dev;
+	u32 smem_block_size = 0;
+	u8 *smem_table_ptr;
+	char version[VENUS_VERSION_LENGTH];
+	const u32 smem_image_index_venus = 14 * 128;
+
+	if (!device || !fw_info) {
+		dprintk(VIDC_ERR,
+			"%s Invalid parameter: device = %pK fw_info = %pK\n",
+			__func__, device, fw_info);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size, 0, SMEM_ANY_HOST_FLAG);
+	if (smem_table_ptr &&
+			((smem_image_index_venus +
+			  VENUS_VERSION_LENGTH) <= smem_block_size))
+		memcpy(version,
+			smem_table_ptr + smem_image_index_venus,
+			VENUS_VERSION_LENGTH);
+
+	while (version[i++] != 'V' && i < VENUS_VERSION_LENGTH)
+		;
+
+	if (i == VENUS_VERSION_LENGTH - 1) {
+		dprintk(VIDC_WARN, "Venus version string is not proper\n");
+		fw_info->version[0] = '\0';
+		goto fail_version_string;
+	}
+
+	for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH - 1; i++)
+		fw_info->version[j++] = version[i];
+	fw_info->version[j] = '\0';
+
+fail_version_string:
+	dprintk(VIDC_DBG, "F/W version retrieved : %s\n", fw_info->version);
+	fw_info->base_addr = device->hal_data->firmware_base;
+	fw_info->register_base = device->res->register_base;
+	fw_info->register_size = device->hal_data->register_size;
+	fw_info->irq = device->hal_data->irq;
+
+	mutex_unlock(&device->lock);
+	return 0;
+}
+
+static int venus_hfi_get_core_capabilities(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	mutex_lock(&device->lock);
+
+	rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
+		HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
+		HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __initialize_packetization(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	const char *hfi_version;
+
+	if (!device || !device->res) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	hfi_version = device->res->hfi_version;
+
+	if (!hfi_version) {
+		device->packetization_type = HFI_PACKETIZATION_LEGACY;
+	} else if (!strcmp(hfi_version, "3xx")) {
+		device->packetization_type = HFI_PACKETIZATION_3XX;
+	} else {
+		dprintk(VIDC_ERR, "Unsupported hfi version\n");
+		return -EINVAL;
+	}
+
+	device->pkt_ops = hfi_get_pkt_ops_handle(device->packetization_type);
+	if (!device->pkt_ops) {
+		rc = -EINVAL;
+		dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n");
+	}
+
+	return rc;
+}
+
+static struct venus_hfi_device *__add_device(u32 device_id,
+			struct msm_vidc_platform_resources *res,
+			hfi_cmd_response_callback callback)
+{
+	struct venus_hfi_device *hdevice = NULL;
+	int rc = 0;
+
+	if (!res || !callback) {
+		dprintk(VIDC_ERR, "Invalid Parameters\n");
+		return NULL;
+	}
+
+	dprintk(VIDC_INFO, "entered , device_id: %d\n", device_id);
+
+	hdevice = (struct venus_hfi_device *)
+			kzalloc(sizeof(struct venus_hfi_device), GFP_KERNEL);
+	if (!hdevice) {
+		dprintk(VIDC_ERR, "failed to allocate new device\n");
+		goto exit;
+	}
+
+	hdevice->response_pkt = kmalloc_array(max_packets,
+				sizeof(*hdevice->response_pkt), GFP_TEMPORARY);
+	if (!hdevice->response_pkt) {
+		dprintk(VIDC_ERR, "failed to allocate response_pkt\n");
+		goto err_cleanup;
+	}
+
+	rc = __init_regs_and_interrupts(hdevice, res);
+	if (rc)
+		goto err_cleanup;
+
+	hdevice->res = res;
+	hdevice->device_id = device_id;
+	hdevice->callback = callback;
+
+	hdevice->vidc_workq = create_singlethread_workqueue(
+		"msm_vidc_workerq_venus");
+	if (!hdevice->vidc_workq) {
+		dprintk(VIDC_ERR, ": create vidc workq failed\n");
+		goto err_cleanup;
+	}
+
+	hdevice->venus_pm_workq = create_singlethread_workqueue(
+			"pm_workerq_venus");
+	if (!hdevice->venus_pm_workq) {
+		dprintk(VIDC_ERR, ": create pm workq failed\n");
+		goto err_cleanup;
+	}
+
+	if (!hal_ctxt.dev_count)
+		INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+	mutex_init(&hdevice->lock);
+	INIT_LIST_HEAD(&hdevice->list);
+	INIT_LIST_HEAD(&hdevice->sess_head);
+	list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+	hal_ctxt.dev_count++;
+
+	return hdevice;
+
+err_cleanup:
+	if (hdevice->vidc_workq)
+		destroy_workqueue(hdevice->vidc_workq);
+	kfree(hdevice->response_pkt);
+	kfree(hdevice);
+exit:
+	return NULL;
+}
+
+static struct venus_hfi_device *__get_device(u32 device_id,
+				struct msm_vidc_platform_resources *res,
+				hfi_cmd_response_callback callback)
+{
+	if (!res || !callback) {
+		dprintk(VIDC_ERR, "Invalid params: %pK %pK\n", res, callback);
+		return NULL;
+	}
+
+	return __add_device(device_id, res, callback);
+}
+
+void venus_hfi_delete_device(void *device)
+{
+	struct venus_hfi_device *close, *tmp, *dev;
+
+	if (!device)
+		return;
+
+	dev = (struct venus_hfi_device *) device;
+
+	mutex_lock(&dev->lock);
+	__iommu_detach(dev);
+	mutex_unlock(&dev->lock);
+
+	list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
+		if (close->hal_data->irq == dev->hal_data->irq) {
+			hal_ctxt.dev_count--;
+			list_del(&close->list);
+			destroy_workqueue(close->vidc_workq);
+			destroy_workqueue(close->venus_pm_workq);
+			free_irq(dev->hal_data->irq, close);
+			iounmap(dev->hal_data->register_base);
+			kfree(close->hal_data);
+			kfree(close->response_pkt);
+			kfree(close);
+			break;
+		}
+	}
+}
+
+static void venus_init_hfi_callbacks(struct hfi_device *hdev)
+{
+	hdev->core_init = venus_hfi_core_init;
+	hdev->core_release = venus_hfi_core_release;
+	hdev->core_ping = venus_hfi_core_ping;
+	hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
+	hdev->session_init = venus_hfi_session_init;
+	hdev->session_end = venus_hfi_session_end;
+	hdev->session_abort = venus_hfi_session_abort;
+	hdev->session_clean = venus_hfi_session_clean;
+	hdev->session_set_buffers = venus_hfi_session_set_buffers;
+	hdev->session_release_buffers = venus_hfi_session_release_buffers;
+	hdev->session_load_res = venus_hfi_session_load_res;
+	hdev->session_release_res = venus_hfi_session_release_res;
+	hdev->session_start = venus_hfi_session_start;
+	hdev->session_continue = venus_hfi_session_continue;
+	hdev->session_stop = venus_hfi_session_stop;
+	hdev->session_etb = venus_hfi_session_etb;
+	hdev->session_ftb = venus_hfi_session_ftb;
+	hdev->session_process_batch = venus_hfi_session_process_batch;
+	hdev->session_parse_seq_hdr = venus_hfi_session_parse_seq_hdr;
+	hdev->session_get_seq_hdr = venus_hfi_session_get_seq_hdr;
+	hdev->session_get_buf_req = venus_hfi_session_get_buf_req;
+	hdev->session_flush = venus_hfi_session_flush;
+	hdev->session_set_property = venus_hfi_session_set_property;
+	hdev->session_get_property = venus_hfi_session_get_property;
+	hdev->scale_clocks = venus_hfi_scale_clocks;
+	hdev->vote_bus = venus_hfi_vote_buses;
+	hdev->get_fw_info = venus_hfi_get_fw_info;
+	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+	hdev->suspend = venus_hfi_suspend;
+	hdev->get_core_clock_rate = venus_hfi_get_core_clock_rate;
+	hdev->get_default_properties = venus_hfi_get_default_properties;
+}
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+		struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback)
+{
+	int rc = 0;
+
+	if (!hdev || !res || !callback) {
+		dprintk(VIDC_ERR, "Invalid params: %pK %pK %pK\n",
+			hdev, res, callback);
+		rc = -EINVAL;
+		goto err_venus_hfi_init;
+	}
+
+	hdev->hfi_device_data = __get_device(device_id, res, callback);
+
+	if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+		rc = PTR_ERR(hdev->hfi_device_data) ?: -EINVAL;
+		goto err_venus_hfi_init;
+	}
+
+	venus_init_hfi_callbacks(hdev);
+
+err_venus_hfi_init:
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.h b/drivers/media/platform/msm/vidc_3x/venus_hfi.h
new file mode 100644
index 0000000..9400430
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.h
@@ -0,0 +1,263 @@
+/* Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __H_VENUS_HFI_H__
+#define __H_VENUS_HFI_H__
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/spinlock.h>
+#include "vmem/vmem.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi.h"
+#include "msm_vidc_resources.h"
+#include "hfi_packetization.h"
+
+#define HFI_MASK_QHDR_TX_TYPE			0xFF000000
+#define HFI_MASK_QHDR_RX_TYPE			0x00FF0000
+#define HFI_MASK_QHDR_PRI_TYPE			0x0000FF00
+#define HFI_MASK_QHDR_Q_ID_TYPE			0x000000FF
+#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q		0x00
+#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q		0x01
+#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q	0x02
+#define HFI_MASK_QHDR_STATUS			0x000000FF
+
+#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES	3
+
+#define VIDC_IFACEQ_NUMQ					3
+#define VIDC_IFACEQ_CMDQ_IDX				0
+#define VIDC_IFACEQ_MSGQ_IDX				1
+#define VIDC_IFACEQ_DBGQ_IDX				2
+#define VIDC_IFACEQ_MAX_BUF_COUNT			50
+#define VIDC_IFACE_MAX_PARALLEL_CLNTS		16
+#define VIDC_IFACEQ_DFLT_QHDR				0x01010000
+
+#define VIDC_MAX_NAME_LENGTH 64
+#define VIDC_MAX_PC_SKIP_COUNT 10
+struct hfi_queue_table_header {
+	u32 qtbl_version;
+	u32 qtbl_size;
+	u32 qtbl_qhdr0_offset;
+	u32 qtbl_qhdr_size;
+	u32 qtbl_num_q;
+	u32 qtbl_num_active_q;
+};
+
+struct hfi_queue_header {
+	u32 qhdr_status;
+	u32 qhdr_start_addr;
+	u32 qhdr_type;
+	u32 qhdr_q_size;
+	u32 qhdr_pkt_size;
+	u32 qhdr_pkt_drop_cnt;
+	u32 qhdr_rx_wm;
+	u32 qhdr_tx_wm;
+	u32 qhdr_rx_req;
+	u32 qhdr_tx_req;
+	u32 qhdr_rx_irq_status;
+	u32 qhdr_tx_irq_status;
+	u32 qhdr_read_idx;
+	u32 qhdr_write_idx;
+};
+
+struct hfi_mem_map_table {
+	u32 mem_map_num_entries;
+	u32 mem_map_table_base_addr;
+};
+
+struct hfi_mem_map {
+	u32 virtual_addr;
+	u32 physical_addr;
+	u32 size;
+	u32 attr;
+};
+
+#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+	+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
+
+#define VIDC_IFACEQ_QUEUE_SIZE	(VIDC_IFACEQ_MAX_PKT_SIZE *  \
+	VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
+
+#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i)     \
+	(void *)((ptr + sizeof(struct hfi_queue_table_header)) + \
+		(i * sizeof(struct hfi_queue_header)))
+
+#define QDSS_SIZE 4096
+#define SFR_SIZE 4096
+
+#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
+	(VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ))
+
+#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K)
+#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K)
+#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K)
+#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \
+			ALIGNED_QDSS_SIZE, SZ_1M)
+
+enum vidc_hw_reg {
+	VIDC_HWREG_CTRL_STATUS =  0x1,
+	VIDC_HWREG_QTBL_INFO =  0x2,
+	VIDC_HWREG_QTBL_ADDR =  0x3,
+	VIDC_HWREG_CTRLR_RESET =  0x4,
+	VIDC_HWREG_IFACEQ_FWRXREQ =  0x5,
+	VIDC_HWREG_IFACEQ_FWTXREQ =  0x6,
+	VIDC_HWREG_VHI_SOFTINTEN =  0x7,
+	VIDC_HWREG_VHI_SOFTINTSTATUS =  0x8,
+	VIDC_HWREG_VHI_SOFTINTCLR =  0x9,
+	VIDC_HWREG_HVI_SOFTINTEN =  0xA,
+};
+
+struct vidc_mem_addr {
+	ion_phys_addr_t align_device_addr;
+	u8 *align_virtual_addr;
+	u32 mem_size;
+	struct msm_smem *mem_data;
+};
+
+struct vidc_iface_q_info {
+	void *q_hdr;
+	struct vidc_mem_addr q_array;
+};
+
+/*
+ * These are helper macros to iterate over various lists within
+ * venus_hfi_device->res.  The intention is to cut down on a lot of boiler-plate
+ * code
+ */
+
+/* Read as "for each 'thing' in a set of 'thingies'" */
+#define venus_hfi_for_each_thing(__device, __thing, __thingy) \
+	venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0)
+
+#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \
+	venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+			(__device)->res->__thingy##_set.count - 1)
+
+/* TODO: the __from parameter technically not required since we can figure it
+ * out with some pointer magic (i.e. __thing - __thing##_tbl[0]).  If this macro
+ * sees extensive use, probably worth cleaning it up but for now omitting it
+ * since it introduces unneccessary complexity.
+ */
+#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \
+	for (__thing = &(__device)->res->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing < &(__device)->res->__thingy##_set.__thingy##_tbl[0] + \
+			((__device)->res->__thingy##_set.count - __from); \
+		++__thing)
+
+#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+		__from) \
+	for (__thing = &(__device)->res->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing >= &(__device)->res->__thingy##_set.__thingy##_tbl[0]; \
+		--__thing)
+
+/* Regular set helpers */
+#define venus_hfi_for_each_regulator(__device, __rinfo) \
+	venus_hfi_for_each_thing(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \
+		__from) \
+	venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
+			regulator, __from)
+
+/* Clock set helpers */
+#define venus_hfi_for_each_clock(__device, __cinfo) \
+	venus_hfi_for_each_thing(__device, __cinfo, clock)
+
+#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __cinfo, clock)
+
+/* Bus set helpers */
+#define venus_hfi_for_each_bus(__device, __binfo) \
+	venus_hfi_for_each_thing(__device, __binfo, bus)
+#define venus_hfi_for_each_bus_reverse(__device, __binfo) \
+	venus_hfi_for_each_thing_reverse(__device, __binfo, bus)
+
+
+/* Internal data used in vidc_hal not exposed to msm_vidc*/
+struct hal_data {
+	u32 irq;
+	phys_addr_t firmware_base;
+	u8 __iomem *register_base;
+	u32 register_size;
+};
+
+struct imem {
+	enum imem_type type;
+	union {
+		phys_addr_t vmem;
+	};
+};
+
+struct venus_resources {
+	struct msm_vidc_fw fw;
+	struct imem imem;
+};
+
+enum venus_hfi_state {
+	VENUS_STATE_DEINIT = 1,
+	VENUS_STATE_INIT,
+};
+
+struct venus_hfi_device {
+	struct list_head list;
+	struct list_head sess_head;
+	u32 intr_status;
+	u32 device_id;
+	u32 clk_freq;
+	u32 last_packet_type;
+	unsigned long clk_bitrate;
+	unsigned long scaled_rate;
+	struct msm_vidc_gov_data bus_vote;
+	bool power_enabled;
+	struct mutex lock;
+	msm_vidc_callback callback;
+	struct vidc_mem_addr iface_q_table;
+	struct vidc_mem_addr qdss;
+	struct vidc_mem_addr sfr;
+	struct vidc_mem_addr mem_addr;
+	struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
+	struct smem_client *hal_client;
+	struct hal_data *hal_data;
+	struct workqueue_struct *vidc_workq;
+	struct workqueue_struct *venus_pm_workq;
+	int spur_count;
+	int reg_count;
+	struct venus_resources resources;
+	struct msm_vidc_platform_resources *res;
+	enum venus_hfi_state state;
+	struct hfi_packetization_ops *pkt_ops;
+	enum hfi_packetization_type packetization_type;
+	struct msm_vidc_cb_info *response_pkt;
+	struct pm_qos_request qos;
+	unsigned int skip_pc_count;
+	struct msm_vidc_capability *sys_init_capabilities;
+};
+
+void venus_hfi_delete_device(void *device);
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+		struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback);
+bool venus_hfi_is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi.c b/drivers/media/platform/msm/vidc_3x/vidc_hfi.c
new file mode 100644
index 0000000..98abd72
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+#include "venus_hfi.h"
+
+struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
+		u32 device_id, struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback)
+{
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	hdev = (struct hfi_device *)
+			kzalloc(sizeof(struct hfi_device), GFP_KERNEL);
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s: failed to allocate hdev\n", __func__);
+		return NULL;
+	}
+
+	switch (hfi_type) {
+	case VIDC_HFI_VENUS:
+		rc = venus_hfi_initialize(hdev, device_id, res, callback);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+		goto err_hfi_init;
+	}
+
+	if (rc) {
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "%s device init failed rc = %d",
+				__func__, rc);
+		goto err_hfi_init;
+	}
+
+	return hdev;
+
+err_hfi_init:
+	kfree(hdev);
+	return ERR_PTR(rc);
+}
+
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+			struct hfi_device *hdev)
+{
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s invalid device %pK", __func__, hdev);
+		return;
+	}
+
+	switch (hfi_type) {
+	case VIDC_HFI_VENUS:
+		venus_hfi_delete_device(hdev->hfi_device_data);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+	}
+
+	kfree(hdev);
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
new file mode 100644
index 0000000..d0fd493
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
@@ -0,0 +1,934 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __H_VIDC_HFI_H__
+#define __H_VIDC_HFI_H__
+
+#include <media/msm_media_info.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+
+#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
+#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
+
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES	\
+	(HFI_OX_BASE + 0x1)
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES	\
+	(HFI_OX_BASE + 0x2)
+
+#define HFI_BUFFERFLAG_EOS			0x00000001
+#define HFI_BUFFERFLAG_STARTTIME		0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY		0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT		0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME		0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME		0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA		0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG		0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID		0x00000100
+#define HFI_BUFFERFLAG_READONLY			0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME		0x00000400
+#define HFI_BUFFERFLAG_EOSEQ			0x00200000
+#define HFI_BUFFER_FLAG_MBAFF			0x08000000
+#define HFI_BUFFERFLAG_VPE_YUV_601_709_CSC_CLAMP \
+						0x10000000
+#define HFI_BUFFERFLAG_DROP_FRAME               0x20000000
+#define HFI_BUFFERFLAG_TEI			0x40000000
+#define HFI_BUFFERFLAG_DISCONTINUITY		0x80000000
+
+
+#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING	\
+	(HFI_OX_BASE + 0x1001)
+#define HFI_ERR_SESSION_SAME_STATE_OPERATION		\
+	(HFI_OX_BASE + 0x1002)
+#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED		\
+	(HFI_OX_BASE + 0x1003)
+#define  HFI_ERR_SESSION_START_CODE_NOT_FOUND		\
+	(HFI_OX_BASE + 0x1004)
+
+#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
+#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
+
+#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
+
+#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
+#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
+#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
+
+#define HFI_EXTRADATA_NONE					0x00000000
+#define HFI_EXTRADATA_MB_QUANTIZATION		0x00000001
+#define HFI_EXTRADATA_INTERLACE_VIDEO		0x00000002
+#define HFI_EXTRADATA_VC1_FRAMEDISP			0x00000003
+#define HFI_EXTRADATA_VC1_SEQDISP			0x00000004
+#define HFI_EXTRADATA_TIMESTAMP				0x00000005
+#define HFI_EXTRADATA_S3D_FRAME_PACKING		0x00000006
+#define HFI_EXTRADATA_FRAME_RATE			0x00000007
+#define HFI_EXTRADATA_PANSCAN_WINDOW		0x00000008
+#define HFI_EXTRADATA_RECOVERY_POINT_SEI	0x00000009
+#define HFI_EXTRADATA_MPEG2_SEQDISP		0x0000000D
+#define HFI_EXTRADATA_STREAM_USERDATA		0x0000000E
+#define HFI_EXTRADATA_FRAME_QP			0x0000000F
+#define HFI_EXTRADATA_FRAME_BITS_INFO		0x00000010
+#define HFI_EXTRADATA_VPX_COLORSPACE		0x00000014
+#define HFI_EXTRADATA_MULTISLICE_INFO		0x7F100000
+#define HFI_EXTRADATA_NUM_CONCEALED_MB		0x7F100001
+#define HFI_EXTRADATA_INDEX					0x7F100002
+#define HFI_EXTRADATA_METADATA_LTR			0x7F100004
+#define HFI_EXTRADATA_METADATA_FILLER		0x7FE00002
+
+#define HFI_INDEX_EXTRADATA_INPUT_CROP		0x0700000E
+#define HFI_INDEX_EXTRADATA_OUTPUT_CROP		0x0700000F
+#define HFI_INDEX_EXTRADATA_ASPECT_RATIO	0x7F100003
+
+struct hfi_buffer_alloc_mode {
+	u32 buffer_type;
+	u32 buffer_mode;
+};
+
+
+struct hfi_index_extradata_config {
+	int enable;
+	u32 index_extra_data_id;
+};
+
+struct hfi_extradata_header {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 type;
+	u32 data_size;
+	u8 rg_data[1];
+};
+
+#define HFI_INTERLACE_FRAME_PROGRESSIVE					0x01
+#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST	0x02
+#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST	0x04
+#define HFI_INTERLACE_FRAME_TOPFIELDFIRST				0x08
+#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST			0x10
+
+#define HFI_PROPERTY_SYS_OX_START			\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+
+#define HFI_PROPERTY_PARAM_OX_START				\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_CHROMA_SITE					\
+(HFI_PROPERTY_PARAM_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG		\
+	(HFI_PROPERTY_PARAM_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA             \
+	(HFI_PROPERTY_PARAM_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_DIVX_FORMAT					\
+	(HFI_PROPERTY_PARAM_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
+	(HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00E)
+
+#define HFI_PROPERTY_CONFIG_OX_START					\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
+#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS			\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_REALTIME					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_PRIORITY					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_BATCH_INFO					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VDEC_OX_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA  \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE   \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
+
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
+#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
+#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
+#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019)
+#define HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01A)
+#define HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001C)
+#define HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001D)
+#define HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E)
+#define HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F)
+
+#define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
+#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER	\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING	\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP			\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VDEC_ENTROPY \
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VENC_OX_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define  HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO       \
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
+#define  HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
+#define  HFI_PROPERTY_PARAM_VENC_LTR_INFO			\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x003)
+#define  HFI_PROPERTY_PARAM_VENC_MBI_DUMPING				\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x006)
+#define  HFI_PROPERTY_PARAM_VENC_YUVSTAT_INFO_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x008)
+#define  HFI_PROPERTY_PARAM_VENC_OVERRIDE_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x009)
+
+#define HFI_PROPERTY_CONFIG_VENC_OX_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
+#define  HFI_PROPERTY_CONFIG_VENC_FRAME_QP				\
+	(HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VPE_OX_START					\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
+#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION			\
+	(HFI_PROPERTY_PARAM_VPE_OX_START + 0x001)
+
+#define HFI_PROPERTY_CONFIG_VPE_OX_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
+
+struct hfi_batch_info {
+	u32 input_batch_count;
+	u32 output_batch_count;
+};
+
+struct hfi_buffer_count_actual {
+	u32 buffer_type;
+	u32 buffer_count_actual;
+};
+
+struct hfi_buffer_size_minimum {
+	u32 buffer_type;
+	u32 buffer_size;
+};
+
+struct hfi_buffer_requirements {
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 buffer_region_size;
+	u32 buffer_hold_count;
+	u32 buffer_count_min;
+	u32 buffer_count_actual;
+	u32 contiguous;
+	u32 buffer_alignment;
+};
+
+#define HFI_CHROMA_SITE_0			(HFI_OX_BASE + 0x1)
+#define HFI_CHROMA_SITE_1			(HFI_OX_BASE + 0x2)
+#define HFI_CHROMA_SITE_2			(HFI_OX_BASE + 0x3)
+#define HFI_CHROMA_SITE_3			(HFI_OX_BASE + 0x4)
+#define HFI_CHROMA_SITE_4			(HFI_OX_BASE + 0x5)
+#define HFI_CHROMA_SITE_5			(HFI_OX_BASE + 0x6)
+
+struct hfi_data_payload {
+	u32 size;
+	u8 rg_data[1];
+};
+
+struct hfi_enable_picture {
+	u32 picture_type;
+};
+
+struct hfi_display_picture_buffer_count {
+	int enable;
+	u32 count;
+};
+
+struct hfi_extra_data_header_config {
+	u32 type;
+	u32 buffer_type;
+	u32 version;
+	u32 port_index;
+	u32 client_extra_data_id;
+};
+
+struct hfi_interlace_format_supported {
+	u32 buffer_type;
+	u32 format;
+};
+
+struct hfi_buffer_alloc_mode_supported {
+	u32 buffer_type;
+	u32 num_entries;
+	u32 rg_data[1];
+};
+
+struct hfi_mb_error_map {
+	u32 error_map_size;
+	u8 rg_error_map[1];
+};
+
+struct hfi_metadata_pass_through {
+	int enable;
+	u32 size;
+};
+
+struct hfi_multi_view_select {
+	u32 view_index;
+};
+
+struct hfi_hybrid_hierp {
+	u32 layers;
+};
+
+#define HFI_PRIORITY_LOW		10
+#define HFI_PRIOIRTY_MEDIUM		20
+#define HFI_PRIORITY_HIGH		30
+
+#define HFI_OUTPUT_ORDER_DISPLAY	(HFI_OX_BASE + 0x1)
+#define HFI_OUTPUT_ORDER_DECODE		(HFI_OX_BASE + 0x2)
+
+#define HFI_RATE_CONTROL_OFF		(HFI_OX_BASE + 0x1)
+#define HFI_RATE_CONTROL_VBR_VFR	(HFI_OX_BASE + 0x2)
+#define HFI_RATE_CONTROL_VBR_CFR	(HFI_OX_BASE + 0x3)
+#define HFI_RATE_CONTROL_CBR_VFR	(HFI_OX_BASE + 0x4)
+#define HFI_RATE_CONTROL_CBR_CFR	(HFI_OX_BASE + 0x5)
+#define HFI_RATE_CONTROL_MBR_CFR	(HFI_OX_BASE + 0x6)
+#define HFI_RATE_CONTROL_MBR_VFR	(HFI_OX_BASE + 0x7)
+
+
+struct hfi_uncompressed_plane_actual_constraints_info {
+	u32 buffer_type;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+#define HFI_CMD_SYS_OX_START		\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000)
+#define HFI_CMD_SYS_SESSION_ABORT	(HFI_CMD_SYS_OX_START + 0x001)
+#define HFI_CMD_SYS_PING		(HFI_CMD_SYS_OX_START + 0x002)
+
+#define HFI_CMD_SESSION_OX_START	\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_LOAD_RESOURCES	(HFI_CMD_SESSION_OX_START + 0x001)
+#define HFI_CMD_SESSION_START		(HFI_CMD_SESSION_OX_START + 0x002)
+#define HFI_CMD_SESSION_STOP		(HFI_CMD_SESSION_OX_START + 0x003)
+#define HFI_CMD_SESSION_EMPTY_BUFFER	(HFI_CMD_SESSION_OX_START + 0x004)
+#define HFI_CMD_SESSION_FILL_BUFFER	(HFI_CMD_SESSION_OX_START + 0x005)
+#define HFI_CMD_SESSION_SUSPEND		(HFI_CMD_SESSION_OX_START + 0x006)
+#define HFI_CMD_SESSION_RESUME		(HFI_CMD_SESSION_OX_START + 0x007)
+#define HFI_CMD_SESSION_FLUSH		(HFI_CMD_SESSION_OX_START + 0x008)
+#define HFI_CMD_SESSION_GET_PROPERTY	(HFI_CMD_SESSION_OX_START + 0x009)
+#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER	\
+	(HFI_CMD_SESSION_OX_START + 0x00A)
+#define HFI_CMD_SESSION_RELEASE_BUFFERS		\
+	(HFI_CMD_SESSION_OX_START + 0x00B)
+#define HFI_CMD_SESSION_RELEASE_RESOURCES	\
+	(HFI_CMD_SESSION_OX_START + 0x00C)
+#define HFI_CMD_SESSION_CONTINUE	(HFI_CMD_SESSION_OX_START + 0x00D)
+#define HFI_CMD_SESSION_SYNC		(HFI_CMD_SESSION_OX_START + 0x00E)
+
+#define HFI_MSG_SYS_OX_START			\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_PING_ACK	(HFI_MSG_SYS_OX_START + 0x2)
+#define HFI_MSG_SYS_SESSION_ABORT_DONE	(HFI_MSG_SYS_OX_START + 0x4)
+
+#define HFI_MSG_SESSION_OX_START		\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE	(HFI_MSG_SESSION_OX_START + 0x1)
+#define HFI_MSG_SESSION_START_DONE		(HFI_MSG_SESSION_OX_START + 0x2)
+#define HFI_MSG_SESSION_STOP_DONE		(HFI_MSG_SESSION_OX_START + 0x3)
+#define HFI_MSG_SESSION_SUSPEND_DONE	(HFI_MSG_SESSION_OX_START + 0x4)
+#define HFI_MSG_SESSION_RESUME_DONE		(HFI_MSG_SESSION_OX_START + 0x5)
+#define HFI_MSG_SESSION_FLUSH_DONE		(HFI_MSG_SESSION_OX_START + 0x6)
+#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE	(HFI_MSG_SESSION_OX_START + 0x7)
+#define HFI_MSG_SESSION_FILL_BUFFER_DONE	(HFI_MSG_SESSION_OX_START + 0x8)
+#define HFI_MSG_SESSION_PROPERTY_INFO		(HFI_MSG_SESSION_OX_START + 0x9)
+#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE	\
+	(HFI_MSG_SESSION_OX_START + 0xA)
+#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE		\
+	(HFI_MSG_SESSION_OX_START + 0xB)
+#define  HFI_MSG_SESSION_RELEASE_BUFFERS_DONE			\
+	(HFI_MSG_SESSION_OX_START + 0xC)
+
+#define VIDC_IFACEQ_MAX_PKT_SIZE                        1024
+#define VIDC_IFACEQ_MED_PKT_SIZE                        768
+#define VIDC_IFACEQ_MIN_PKT_SIZE                        8
+#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE          100
+#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE          512
+#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE          (1024*12)
+
+
+struct hfi_cmd_sys_session_abort_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_ping_packet {
+	u32 size;
+	u32 packet_type;
+	u32 client_data;
+};
+
+struct hfi_cmd_session_load_resources_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_start_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_stop_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_empty_buffer_compressed_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 view_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer2;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer3;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_fill_buffer_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 stream_id;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 output_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_flush_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 flush_type;
+};
+
+struct hfi_cmd_session_suspend_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_resume_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_session_release_buffer_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 extra_data_size;
+	int response_req;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_resources_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_parse_sequence_header_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 header_len;
+	u32 packet_buffer;
+};
+
+struct hfi_msg_sys_session_abort_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_idle_packet {
+	u32 size;
+	u32 packet_type;
+};
+
+struct hfi_msg_sys_ping_ack_packet {
+	u32 size;
+	u32 packet_type;
+	u32 client_data;
+};
+
+struct hfi_msg_sys_property_info_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_load_resources_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_start_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_stop_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_suspend_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_resume_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_flush_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 flush_type;
+};
+
+struct hfi_msg_session_empty_buffer_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 offset;
+	u32 filled_len;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_compressed_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 error_type;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 input_tag;
+	u32 output_tag;
+	u32 picture_type;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fbd_uncompressed_plane0_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 stream_id;
+	u32 view_id;
+	u32 error_type;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 frame_width;
+	u32 frame_height;
+	u32 start_x_coord;
+	u32 start_y_coord;
+	u32 input_tag;
+	u32 input_tag2;
+	u32 output_tag;
+	u32 picture_type;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer2;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer3;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_parse_sequence_header_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_property_info_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_release_resources_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_release_buffers_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_extradata_mb_quantization_payload {
+	u8 rg_mb_qp[1];
+};
+
+struct hfi_extradata_vc1_pswnd {
+	u32 ps_wnd_h_offset;
+	u32 ps_wnd_v_offset;
+	u32 ps_wnd_width;
+	u32 ps_wnd_height;
+};
+
+struct hfi_extradata_vc1_framedisp_payload {
+	u32 res_pic;
+	u32 ref;
+	u32 range_map_present;
+	u32 range_map_y;
+	u32 range_map_uv;
+	u32 num_pan_scan_wnds;
+	struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
+};
+
+struct hfi_extradata_vc1_seqdisp_payload {
+	u32 prog_seg_frm;
+	u32 uv_sampling_fmt;
+	u32 color_fmt_flag;
+	u32 color_primaries;
+	u32 transfer_char;
+	u32 mat_coeff;
+	u32 aspect_ratio;
+	u32 aspect_horiz;
+	u32 aspect_vert;
+};
+
+struct hfi_extradata_timestamp_payload {
+	u32 time_stamp_low;
+	u32 time_stamp_high;
+};
+
+
+struct hfi_extradata_s3d_frame_packing_payload {
+	u32 fpa_id;
+	int cancel_flag;
+	u32 fpa_type;
+	int quin_cunx_flag;
+	u32 content_interprtation_type;
+	int spatial_flipping_flag;
+	int frame0_flipped_flag;
+	int field_views_flag;
+	int current_frame_isFrame0_flag;
+	int frame0_self_contained_flag;
+	int frame1_self_contained_flag;
+	u32 frame0_graid_pos_x;
+	u32 frame0_graid_pos_y;
+	u32 frame1_graid_pos_x;
+	u32 frame1_graid_pos_y;
+	u32 fpa_reserved_byte;
+	u32 fpa_repetition_period;
+	int fpa_extension_flag;
+};
+
+struct hfi_extradata_interlace_video_payload {
+	u32 format;
+};
+
+struct hfi_extradata_num_concealed_mb_payload {
+	u32 num_mb_concealed;
+};
+
+struct hfi_extradata_sliceinfo {
+	u32 offset_in_stream;
+	u32 slice_length;
+};
+
+struct hfi_extradata_multislice_info_payload {
+	u32 num_slices;
+	struct hfi_extradata_sliceinfo rg_slice_info[1];
+};
+
+struct hfi_index_extradata_input_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_index_extradata_output_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 display_width;
+	u32 display_height;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_index_extradata_digital_zoom_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	int width;
+	int height;
+};
+
+struct hfi_index_extradata_aspect_ratio_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 aspect_width;
+	u32 aspect_height;
+};
+struct hfi_extradata_panscan_wndw_payload {
+	u32 num_window;
+	struct hfi_extradata_vc1_pswnd wnd[1];
+};
+
+struct hfi_extradata_frame_type_payload {
+	u32 frame_rate;
+};
+
+struct hfi_extradata_recovery_point_sei_payload {
+	u32 flag;
+};
+
+struct hfi_cmd_session_continue_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hal_session {
+	struct list_head list;
+	void *session_id;
+	bool is_decoder;
+	enum hal_video_codec codec;
+	enum hal_domain domain;
+	void *device;
+};
+
+struct hal_device_data {
+	struct list_head dev_head;
+	int dev_count;
+};
+
+struct msm_vidc_fw {
+	void *cookie;
+};
+
+int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info);
+
+enum vidc_status hfi_process_sys_init_done_prop_read(
+	struct hfi_msg_sys_init_done_packet *pkt,
+	struct vidc_hal_sys_init_done *sys_init_done);
+
+enum vidc_status hfi_process_session_init_done_prop_read(
+	struct hfi_msg_sys_session_init_done_packet *pkt,
+	struct vidc_hal_session_init_done *session_init_done);
+
+#endif
+
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
new file mode 100644
index 0000000..04bf5a8
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
@@ -0,0 +1,1544 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __VIDC_HFI_API_H__
+#define __VIDC_HFI_API_H__
+
+#include <linux/log2.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_resources.h"
+
+#define CONTAINS(__a, __sz, __t) ({\
+	int __rc = __t >= __a && \
+			__t < __a + __sz; \
+	__rc; \
+})
+
+#define OVERLAPS(__t, __tsz, __a, __asz) ({\
+	int __rc = __t <= __a && \
+			__t + __tsz >= __a + __asz; \
+	__rc; \
+})
+
+#define HAL_BUFFERFLAG_EOS              0x00000001
+#define HAL_BUFFERFLAG_STARTTIME        0x00000002
+#define HAL_BUFFERFLAG_DECODEONLY       0x00000004
+#define HAL_BUFFERFLAG_DATACORRUPT      0x00000008
+#define HAL_BUFFERFLAG_ENDOFFRAME       0x00000010
+#define HAL_BUFFERFLAG_SYNCFRAME        0x00000020
+#define HAL_BUFFERFLAG_EXTRADATA        0x00000040
+#define HAL_BUFFERFLAG_CODECCONFIG      0x00000080
+#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HAL_BUFFERFLAG_READONLY         0x00000200
+#define HAL_BUFFERFLAG_ENDOFSUBFRAME    0x00000400
+#define HAL_BUFFERFLAG_EOSEQ            0x00200000
+#define HAL_BUFFERFLAG_MBAFF            0x08000000
+#define HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP   0x10000000
+#define HAL_BUFFERFLAG_DROP_FRAME       0x20000000
+#define HAL_BUFFERFLAG_TS_DISCONTINUITY	0x40000000
+#define HAL_BUFFERFLAG_TS_ERROR		0x80000000
+
+
+
+#define HAL_DEBUG_MSG_LOW				0x00000001
+#define HAL_DEBUG_MSG_MEDIUM			0x00000002
+#define HAL_DEBUG_MSG_HIGH				0x00000004
+#define HAL_DEBUG_MSG_ERROR				0x00000008
+#define HAL_DEBUG_MSG_FATAL				0x00000010
+#define MAX_PROFILE_COUNT	16
+
+#define HAL_MAX_MATRIX_COEFFS 9
+#define HAL_MAX_BIAS_COEFFS 3
+#define HAL_MAX_LIMIT_COEFFS 6
+#define VENUS_VERSION_LENGTH 128
+
+/* 16 encoder and 16 decoder sessions */
+#define VIDC_MAX_SESSIONS               32
+
+enum vidc_status {
+	VIDC_ERR_NONE = 0x0,
+	VIDC_ERR_FAIL = 0x80000000,
+	VIDC_ERR_ALLOC_FAIL,
+	VIDC_ERR_ILLEGAL_OP,
+	VIDC_ERR_BAD_PARAM,
+	VIDC_ERR_BAD_HANDLE,
+	VIDC_ERR_NOT_SUPPORTED,
+	VIDC_ERR_BAD_STATE,
+	VIDC_ERR_MAX_CLIENTS,
+	VIDC_ERR_IFRAME_EXPECTED,
+	VIDC_ERR_HW_FATAL,
+	VIDC_ERR_BITSTREAM_ERR,
+	VIDC_ERR_INDEX_NOMORE,
+	VIDC_ERR_SEQHDR_PARSE_FAIL,
+	VIDC_ERR_INSUFFICIENT_BUFFER,
+	VIDC_ERR_BAD_POWER_STATE,
+	VIDC_ERR_NO_VALID_SESSION,
+	VIDC_ERR_TIMEOUT,
+	VIDC_ERR_CMDQFULL,
+	VIDC_ERR_START_CODE_NOT_FOUND,
+	VIDC_ERR_CLIENT_PRESENT = 0x90000001,
+	VIDC_ERR_CLIENT_FATAL,
+	VIDC_ERR_CMD_QUEUE_FULL,
+	VIDC_ERR_UNUSED = 0x10000000
+};
+
+enum hal_extradata_id {
+	HAL_EXTRADATA_NONE,
+	HAL_EXTRADATA_MB_QUANTIZATION,
+	HAL_EXTRADATA_INTERLACE_VIDEO,
+	HAL_EXTRADATA_VC1_FRAMEDISP,
+	HAL_EXTRADATA_VC1_SEQDISP,
+	HAL_EXTRADATA_TIMESTAMP,
+	HAL_EXTRADATA_S3D_FRAME_PACKING,
+	HAL_EXTRADATA_FRAME_RATE,
+	HAL_EXTRADATA_PANSCAN_WINDOW,
+	HAL_EXTRADATA_RECOVERY_POINT_SEI,
+	HAL_EXTRADATA_MULTISLICE_INFO,
+	HAL_EXTRADATA_INDEX,
+	HAL_EXTRADATA_NUM_CONCEALED_MB,
+	HAL_EXTRADATA_METADATA_FILLER,
+	HAL_EXTRADATA_ASPECT_RATIO,
+	HAL_EXTRADATA_MPEG2_SEQDISP,
+	HAL_EXTRADATA_STREAM_USERDATA,
+	HAL_EXTRADATA_FRAME_QP,
+	HAL_EXTRADATA_FRAME_BITS_INFO,
+	HAL_EXTRADATA_INPUT_CROP,
+	HAL_EXTRADATA_DIGITAL_ZOOM,
+	HAL_EXTRADATA_LTR_INFO,
+	HAL_EXTRADATA_METADATA_MBI,
+	HAL_EXTRADATA_VQZIP_SEI,
+	HAL_EXTRADATA_YUV_STATS,
+	HAL_EXTRADATA_ROI_QP,
+	HAL_EXTRADATA_OUTPUT_CROP,
+	HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI,
+	HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI,
+	HAL_EXTRADATA_VUI_DISPLAY_INFO,
+	HAL_EXTRADATA_VPX_COLORSPACE,
+	HAL_EXTRADATA_PQ_INFO,
+};
+
+enum hal_property {
+	HAL_CONFIG_FRAME_RATE = 0x04000001,
+	HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
+	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+	HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
+	HAL_PARAM_INDEX_EXTRADATA,
+	HAL_PARAM_FRAME_SIZE,
+	HAL_CONFIG_REALTIME,
+	HAL_PARAM_BUFFER_COUNT_ACTUAL,
+	HAL_PARAM_BUFFER_SIZE_MINIMUM,
+	HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+	HAL_PARAM_VDEC_OUTPUT_ORDER,
+	HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
+	HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+	HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+	HAL_PARAM_VDEC_MULTI_STREAM,
+	HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
+	HAL_PARAM_DIVX_FORMAT,
+	HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+	HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+	HAL_CONFIG_VDEC_MB_ERROR_MAP,
+	HAL_CONFIG_VENC_REQUEST_IFRAME,
+	HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
+	HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
+	HAL_CONFIG_VENC_TARGET_BITRATE,
+	HAL_PARAM_PROFILE_LEVEL_CURRENT,
+	HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+	HAL_PARAM_VENC_RATE_CONTROL,
+	HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
+	HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
+	HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
+	HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
+	HAL_PARAM_VENC_SESSION_QP,
+	HAL_PARAM_VENC_SESSION_QP_RANGE,
+	HAL_CONFIG_VENC_INTRA_PERIOD,
+	HAL_CONFIG_VENC_IDR_PERIOD,
+	HAL_CONFIG_VPE_OPERATIONS,
+	HAL_PARAM_VENC_INTRA_REFRESH,
+	HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
+	HAL_CONFIG_VPE_DEINTERLACE,
+	HAL_SYS_DEBUG_CONFIG,
+	HAL_CONFIG_BUFFER_REQUIREMENTS,
+	HAL_CONFIG_PRIORITY,
+	HAL_CONFIG_BATCH_INFO,
+	HAL_PARAM_METADATA_PASS_THROUGH,
+	HAL_SYS_IDLE_INDICATOR,
+	HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
+	HAL_PARAM_INTERLACE_FORMAT_SUPPORTED,
+	HAL_PARAM_CHROMA_SITE,
+	HAL_PARAM_PROPERTIES_SUPPORTED,
+	HAL_PARAM_PROFILE_LEVEL_SUPPORTED,
+	HAL_PARAM_CAPABILITY_SUPPORTED,
+	HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
+	HAL_PARAM_MULTI_VIEW_FORMAT,
+	HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE,
+	HAL_PARAM_CODEC_SUPPORTED,
+	HAL_PARAM_VDEC_MULTI_VIEW_SELECT,
+	HAL_PARAM_VDEC_MB_QUANTIZATION,
+	HAL_PARAM_VDEC_NUM_CONCEALED_MB,
+	HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
+	HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
+	HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
+	HAL_CONFIG_BUFFER_COUNT_ACTUAL,
+	HAL_CONFIG_VDEC_MULTI_STREAM,
+	HAL_PARAM_VENC_MULTI_SLICE_INFO,
+	HAL_CONFIG_VENC_TIMESTAMP_SCALE,
+	HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+	HAL_PARAM_VDEC_SYNC_FRAME_DECODE,
+	HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+	HAL_CONFIG_VENC_MAX_BITRATE,
+	HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
+	HAL_PARAM_VENC_GENERATE_AUDNAL,
+	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
+	HAL_PARAM_BUFFER_ALLOC_MODE,
+	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+	HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
+	HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY,
+	HAL_PARAM_VDEC_CONCEAL_COLOR,
+	HAL_PARAM_VDEC_SCS_THRESHOLD,
+	HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+	HAL_PARAM_MVC_BUFFER_LAYOUT,
+	HAL_PARAM_VENC_LTRMODE,
+	HAL_CONFIG_VENC_MARKLTRFRAME,
+	HAL_CONFIG_VENC_USELTRFRAME,
+	HAL_CONFIG_VENC_LTRPERIOD,
+	HAL_CONFIG_VENC_HIER_P_NUM_FRAMES,
+	HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS,
+	HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP,
+	HAL_PARAM_VENC_ENABLE_INITIAL_QP,
+	HAL_PARAM_VENC_SEARCH_RANGE,
+	HAL_PARAM_VPE_COLOR_SPACE_CONVERSION,
+	HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
+	HAL_PARAM_VENC_H264_NAL_SVC_EXT,
+	HAL_CONFIG_VENC_PERF_MODE,
+	HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS,
+	HAL_PARAM_VDEC_NON_SECURE_OUTPUT2,
+	HAL_PARAM_VENC_HIER_P_HYBRID_MODE,
+	HAL_PARAM_VENC_MBI_STATISTICS_MODE,
+	HAL_PARAM_SYNC_BASED_INTERRUPT,
+	HAL_CONFIG_VENC_FRAME_QP,
+	HAL_CONFIG_VENC_BASELAYER_PRIORITYID,
+	HAL_PARAM_VENC_VQZIP_SEI,
+	HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO,
+	HAL_CONFIG_VDEC_ENTROPY,
+	HAL_PARAM_VENC_BITRATE_TYPE,
+	HAL_PARAM_VENC_H264_PIC_ORDER_CNT,
+	HAL_PARAM_VENC_LOW_LATENCY,
+	HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED,
+	HAL_CONFIG_VENC_BLUR_RESOLUTION,
+	HAL_PARAM_VENC_VIDEO_SIGNAL_INFO,
+	HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED,
+	HAL_PARAM_VENC_H264_TRANSFORM_8x8,
+	HAL_PARAM_VENC_IFRAMESIZE_TYPE,
+};
+
+enum hal_domain {
+	HAL_VIDEO_DOMAIN_VPE,
+	HAL_VIDEO_DOMAIN_ENCODER,
+	HAL_VIDEO_DOMAIN_DECODER,
+	HAL_UNUSED_DOMAIN = 0x10000000,
+};
+
+enum multi_stream {
+	HAL_VIDEO_DECODER_NONE = 0x00000000,
+	HAL_VIDEO_DECODER_PRIMARY = 0x00000001,
+	HAL_VIDEO_DECODER_SECONDARY = 0x00000002,
+	HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004,
+	HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000,
+};
+
+enum hal_core_capabilities {
+	HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001,
+	HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002,
+	HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004,
+	HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008,
+	HAL_VIDEO_UNUSED_CAPABILITY      = 0x10000000,
+};
+
+enum hal_default_properties {
+	HAL_VIDEO_DYNAMIC_BUF_MODE = 0x00000001,
+	HAL_VIDEO_CONTINUE_DATA_TRANSFER = 0x00000002,
+};
+
+enum hal_video_codec {
+	HAL_VIDEO_CODEC_UNKNOWN  = 0x00000000,
+	HAL_VIDEO_CODEC_MVC      = 0x00000001,
+	HAL_VIDEO_CODEC_H264     = 0x00000002,
+	HAL_VIDEO_CODEC_H263     = 0x00000004,
+	HAL_VIDEO_CODEC_MPEG1    = 0x00000008,
+	HAL_VIDEO_CODEC_MPEG2    = 0x00000010,
+	HAL_VIDEO_CODEC_MPEG4    = 0x00000020,
+	HAL_VIDEO_CODEC_DIVX_311 = 0x00000040,
+	HAL_VIDEO_CODEC_DIVX     = 0x00000080,
+	HAL_VIDEO_CODEC_VC1      = 0x00000100,
+	HAL_VIDEO_CODEC_SPARK    = 0x00000200,
+	HAL_VIDEO_CODEC_VP6      = 0x00000400,
+	HAL_VIDEO_CODEC_VP7      = 0x00000800,
+	HAL_VIDEO_CODEC_VP8      = 0x00001000,
+	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
+	HAL_VIDEO_CODEC_VP9      = 0x00004000,
+	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x80000000,
+	HAL_UNUSED_CODEC = 0x10000000,
+};
+
+enum hal_h263_profile {
+	HAL_H263_PROFILE_BASELINE           = 0x00000001,
+	HAL_H263_PROFILE_H320CODING         = 0x00000002,
+	HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
+	HAL_H263_PROFILE_ISWV2              = 0x00000008,
+	HAL_H263_PROFILE_ISWV3              = 0x00000010,
+	HAL_H263_PROFILE_HIGHCOMPRESSION    = 0x00000020,
+	HAL_H263_PROFILE_INTERNET           = 0x00000040,
+	HAL_H263_PROFILE_INTERLACE          = 0x00000080,
+	HAL_H263_PROFILE_HIGHLATENCY        = 0x00000100,
+	HAL_UNUSED_H263_PROFILE = 0x10000000,
+};
+
+enum hal_h263_level {
+	HAL_H263_LEVEL_10 = 0x00000001,
+	HAL_H263_LEVEL_20 = 0x00000002,
+	HAL_H263_LEVEL_30 = 0x00000004,
+	HAL_H263_LEVEL_40 = 0x00000008,
+	HAL_H263_LEVEL_45 = 0x00000010,
+	HAL_H263_LEVEL_50 = 0x00000020,
+	HAL_H263_LEVEL_60 = 0x00000040,
+	HAL_H263_LEVEL_70 = 0x00000080,
+	HAL_UNUSED_H263_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg2_profile {
+	HAL_MPEG2_PROFILE_SIMPLE  = 0x00000001,
+	HAL_MPEG2_PROFILE_MAIN    = 0x00000002,
+	HAL_MPEG2_PROFILE_422     = 0x00000004,
+	HAL_MPEG2_PROFILE_SNR     = 0x00000008,
+	HAL_MPEG2_PROFILE_SPATIAL = 0x00000010,
+	HAL_MPEG2_PROFILE_HIGH    = 0x00000020,
+	HAL_UNUSED_MPEG2_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg2_level {
+	HAL_MPEG2_LEVEL_LL  = 0x00000001,
+	HAL_MPEG2_LEVEL_ML  = 0x00000002,
+	HAL_MPEG2_LEVEL_H14 = 0x00000004,
+	HAL_MPEG2_LEVEL_HL  = 0x00000008,
+	HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg4_profile {
+	HAL_MPEG4_PROFILE_SIMPLE           = 0x00000001,
+	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00000002,
+	HAL_MPEG4_PROFILE_CORE             = 0x00000004,
+	HAL_MPEG4_PROFILE_MAIN             = 0x00000008,
+	HAL_MPEG4_PROFILE_NBIT             = 0x00000010,
+	HAL_MPEG4_PROFILE_SCALABLETEXTURE  = 0x00000020,
+	HAL_MPEG4_PROFILE_SIMPLEFACE       = 0x00000040,
+	HAL_MPEG4_PROFILE_SIMPLEFBA        = 0x00000080,
+	HAL_MPEG4_PROFILE_BASICANIMATED    = 0x00000100,
+	HAL_MPEG4_PROFILE_HYBRID           = 0x00000200,
+	HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
+	HAL_MPEG4_PROFILE_CORESCALABLE     = 0x00000800,
+	HAL_MPEG4_PROFILE_ADVANCEDCODING   = 0x00001000,
+	HAL_MPEG4_PROFILE_ADVANCEDCORE     = 0x00002000,
+	HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
+	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00008000,
+	HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg4_level {
+	HAL_MPEG4_LEVEL_0  = 0x00000001,
+	HAL_MPEG4_LEVEL_0b = 0x00000002,
+	HAL_MPEG4_LEVEL_1  = 0x00000004,
+	HAL_MPEG4_LEVEL_2  = 0x00000008,
+	HAL_MPEG4_LEVEL_3  = 0x00000010,
+	HAL_MPEG4_LEVEL_4  = 0x00000020,
+	HAL_MPEG4_LEVEL_4a = 0x00000040,
+	HAL_MPEG4_LEVEL_5  = 0x00000080,
+	HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
+	HAL_MPEG4_LEVEL_6  = 0x7F000001,
+	HAL_MPEG4_LEVEL_7  = 0x7F000002,
+	HAL_MPEG4_LEVEL_8  = 0x7F000003,
+	HAL_MPEG4_LEVEL_9  = 0x7F000004,
+	HAL_MPEG4_LEVEL_3b = 0x7F000005,
+	HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
+};
+
+enum hal_h264_profile {
+	HAL_H264_PROFILE_BASELINE = 0x00000001,
+	HAL_H264_PROFILE_MAIN     = 0x00000002,
+	HAL_H264_PROFILE_HIGH     = 0x00000004,
+	HAL_H264_PROFILE_EXTENDED = 0x00000008,
+	HAL_H264_PROFILE_HIGH10   = 0x00000010,
+	HAL_H264_PROFILE_HIGH422  = 0x00000020,
+	HAL_H264_PROFILE_HIGH444  = 0x00000040,
+	HAL_H264_PROFILE_CONSTRAINED_BASE  = 0x00000080,
+	HAL_H264_PROFILE_CONSTRAINED_HIGH  = 0x00000100,
+	HAL_UNUSED_H264_PROFILE = 0x10000000,
+};
+
+enum hal_h264_level {
+	HAL_H264_LEVEL_1  = 0x00000001,
+	HAL_H264_LEVEL_1b = 0x00000002,
+	HAL_H264_LEVEL_11 = 0x00000004,
+	HAL_H264_LEVEL_12 = 0x00000008,
+	HAL_H264_LEVEL_13 = 0x00000010,
+	HAL_H264_LEVEL_2  = 0x00000020,
+	HAL_H264_LEVEL_21 = 0x00000040,
+	HAL_H264_LEVEL_22 = 0x00000080,
+	HAL_H264_LEVEL_3  = 0x00000100,
+	HAL_H264_LEVEL_31 = 0x00000200,
+	HAL_H264_LEVEL_32 = 0x00000400,
+	HAL_H264_LEVEL_4  = 0x00000800,
+	HAL_H264_LEVEL_41 = 0x00001000,
+	HAL_H264_LEVEL_42 = 0x00002000,
+	HAL_H264_LEVEL_5  = 0x00004000,
+	HAL_H264_LEVEL_51 = 0x00008000,
+	HAL_H264_LEVEL_52 = 0x00010000,
+	HAL_UNUSED_H264_LEVEL = 0x10000000,
+};
+
+enum hal_hevc_profile {
+	HAL_HEVC_PROFILE_MAIN           = 0x00000001,
+	HAL_HEVC_PROFILE_MAIN10         = 0x00000002,
+	HAL_HEVC_PROFILE_MAIN_STILL_PIC = 0x00000004,
+	HAL_UNUSED_HEVC_PROFILE         = 0x10000000,
+};
+
+enum hal_hevc_level {
+	HAL_HEVC_MAIN_TIER_LEVEL_1      = 0x10000001,
+	HAL_HEVC_MAIN_TIER_LEVEL_2      = 0x10000002,
+	HAL_HEVC_MAIN_TIER_LEVEL_2_1    = 0x10000004,
+	HAL_HEVC_MAIN_TIER_LEVEL_3      = 0x10000008,
+	HAL_HEVC_MAIN_TIER_LEVEL_3_1    = 0x10000010,
+	HAL_HEVC_MAIN_TIER_LEVEL_4      = 0x10000020,
+	HAL_HEVC_MAIN_TIER_LEVEL_4_1    = 0x10000040,
+	HAL_HEVC_MAIN_TIER_LEVEL_5      = 0x10000080,
+	HAL_HEVC_MAIN_TIER_LEVEL_5_1    = 0x10000100,
+	HAL_HEVC_MAIN_TIER_LEVEL_5_2    = 0x10000200,
+	HAL_HEVC_MAIN_TIER_LEVEL_6      = 0x10000400,
+	HAL_HEVC_MAIN_TIER_LEVEL_6_1    = 0x10000800,
+	HAL_HEVC_MAIN_TIER_LEVEL_6_2    = 0x10001000,
+	HAL_HEVC_HIGH_TIER_LEVEL_1      = 0x20000001,
+	HAL_HEVC_HIGH_TIER_LEVEL_2      = 0x20000002,
+	HAL_HEVC_HIGH_TIER_LEVEL_2_1    = 0x20000004,
+	HAL_HEVC_HIGH_TIER_LEVEL_3      = 0x20000008,
+	HAL_HEVC_HIGH_TIER_LEVEL_3_1    = 0x20000010,
+	HAL_HEVC_HIGH_TIER_LEVEL_4      = 0x20000020,
+	HAL_HEVC_HIGH_TIER_LEVEL_4_1    = 0x20000040,
+	HAL_HEVC_HIGH_TIER_LEVEL_5      = 0x20000080,
+	HAL_HEVC_HIGH_TIER_LEVEL_5_1    = 0x20000100,
+	HAL_HEVC_HIGH_TIER_LEVEL_5_2    = 0x20000200,
+	HAL_HEVC_HIGH_TIER_LEVEL_6      = 0x20000400,
+	HAL_HEVC_HIGH_TIER_LEVEL_6_1    = 0x20000800,
+	HAL_HEVC_HIGH_TIER_LEVEL_6_2    = 0x20001000,
+	HAL_UNUSED_HEVC_TIER_LEVEL      = 0x80000000,
+};
+
+enum hal_hevc_tier {
+	HAL_HEVC_TIER_MAIN   = 0x00000001,
+	HAL_HEVC_TIER_HIGH   = 0x00000002,
+	HAL_UNUSED_HEVC_TIER = 0x10000000,
+};
+
+enum hal_vpx_profile {
+	HAL_VPX_PROFILE_SIMPLE    = 0x00000001,
+	HAL_VPX_PROFILE_ADVANCED  = 0x00000002,
+	HAL_VPX_PROFILE_VERSION_0 = 0x00000004,
+	HAL_VPX_PROFILE_VERSION_1 = 0x00000008,
+	HAL_VPX_PROFILE_VERSION_2 = 0x00000010,
+	HAL_VPX_PROFILE_VERSION_3 = 0x00000020,
+	HAL_VPX_PROFILE_UNUSED = 0x10000000,
+};
+
+enum hal_vc1_profile {
+	HAL_VC1_PROFILE_SIMPLE   = 0x00000001,
+	HAL_VC1_PROFILE_MAIN     = 0x00000002,
+	HAL_VC1_PROFILE_ADVANCED = 0x00000004,
+	HAL_UNUSED_VC1_PROFILE = 0x10000000,
+};
+
+enum hal_vc1_level {
+	HAL_VC1_LEVEL_LOW    = 0x00000001,
+	HAL_VC1_LEVEL_MEDIUM = 0x00000002,
+	HAL_VC1_LEVEL_HIGH   = 0x00000004,
+	HAL_VC1_LEVEL_0      = 0x00000008,
+	HAL_VC1_LEVEL_1      = 0x00000010,
+	HAL_VC1_LEVEL_2      = 0x00000020,
+	HAL_VC1_LEVEL_3      = 0x00000040,
+	HAL_VC1_LEVEL_4      = 0x00000080,
+	HAL_UNUSED_VC1_LEVEL = 0x10000000,
+};
+
+enum hal_divx_format {
+	HAL_DIVX_FORMAT_4,
+	HAL_DIVX_FORMAT_5,
+	HAL_DIVX_FORMAT_6,
+	HAL_UNUSED_DIVX_FORMAT = 0x10000000,
+};
+
+enum hal_divx_profile {
+	HAL_DIVX_PROFILE_QMOBILE  = 0x00000001,
+	HAL_DIVX_PROFILE_MOBILE   = 0x00000002,
+	HAL_DIVX_PROFILE_MT       = 0x00000004,
+	HAL_DIVX_PROFILE_HT       = 0x00000008,
+	HAL_DIVX_PROFILE_HD       = 0x00000010,
+	HAL_UNUSED_DIVX_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_profile {
+	HAL_MVC_PROFILE_STEREO_HIGH  = 0x00001000,
+	HAL_UNUSED_MVC_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_level {
+	HAL_MVC_LEVEL_1  = 0x00000001,
+	HAL_MVC_LEVEL_1b = 0x00000002,
+	HAL_MVC_LEVEL_11 = 0x00000004,
+	HAL_MVC_LEVEL_12 = 0x00000008,
+	HAL_MVC_LEVEL_13 = 0x00000010,
+	HAL_MVC_LEVEL_2  = 0x00000020,
+	HAL_MVC_LEVEL_21 = 0x00000040,
+	HAL_MVC_LEVEL_22 = 0x00000080,
+	HAL_MVC_LEVEL_3  = 0x00000100,
+	HAL_MVC_LEVEL_31 = 0x00000200,
+	HAL_MVC_LEVEL_32 = 0x00000400,
+	HAL_MVC_LEVEL_4  = 0x00000800,
+	HAL_MVC_LEVEL_41 = 0x00001000,
+	HAL_MVC_LEVEL_42 = 0x00002000,
+	HAL_MVC_LEVEL_5  = 0x00004000,
+	HAL_MVC_LEVEL_51 = 0x00008000,
+	HAL_UNUSED_MVC_LEVEL = 0x10000000,
+};
+
+struct hal_frame_rate {
+	enum hal_buffer buffer_type;
+	u32 frame_rate;
+};
+
+enum hal_uncompressed_format {
+	HAL_COLOR_FORMAT_MONOCHROME     = 0x00000001,
+	HAL_COLOR_FORMAT_NV12           = 0x00000002,
+	HAL_COLOR_FORMAT_NV21           = 0x00000004,
+	HAL_COLOR_FORMAT_NV12_4x4TILE   = 0x00000008,
+	HAL_COLOR_FORMAT_NV21_4x4TILE   = 0x00000010,
+	HAL_COLOR_FORMAT_YUYV           = 0x00000020,
+	HAL_COLOR_FORMAT_YVYU           = 0x00000040,
+	HAL_COLOR_FORMAT_UYVY           = 0x00000080,
+	HAL_COLOR_FORMAT_VYUY           = 0x00000100,
+	HAL_COLOR_FORMAT_RGB565         = 0x00000200,
+	HAL_COLOR_FORMAT_BGR565         = 0x00000400,
+	HAL_COLOR_FORMAT_RGB888         = 0x00000800,
+	HAL_COLOR_FORMAT_BGR888         = 0x00001000,
+	HAL_COLOR_FORMAT_NV12_UBWC      = 0x00002000,
+	HAL_COLOR_FORMAT_NV12_TP10_UBWC = 0x00004000,
+	HAL_COLOR_FORMAT_RGBA8888       = 0x00008000,
+	HAL_COLOR_FORMAT_RGBA8888_UBWC  = 0x00010000,
+	HAL_UNUSED_COLOR                = 0x10000000,
+};
+
+enum hal_statistics_mode_type {
+	HAL_STATISTICS_MODE_DEFAULT	= 0x00000001,
+	HAL_STATISTICS_MODE_1		= 0x00000002,
+	HAL_STATISTICS_MODE_2		= 0x00000004,
+	HAL_STATISTICS_MODE_3		= 0x00000008,
+};
+
+enum hal_ssr_trigger_type {
+	SSR_ERR_FATAL = 1,
+	SSR_SW_DIV_BY_ZERO,
+	SSR_HW_WDOG_IRQ,
+};
+
+struct hal_uncompressed_format_select {
+	enum hal_buffer buffer_type;
+	enum hal_uncompressed_format format;
+};
+
+struct hal_uncompressed_plane_actual {
+	int actual_stride;
+	u32 actual_plane_buffer_height;
+};
+
+struct hal_uncompressed_plane_actual_info {
+	enum hal_buffer buffer_type;
+	u32 num_planes;
+	struct hal_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hal_uncompressed_plane_constraints {
+	u32 stride_multiples;
+	u32 max_stride;
+	u32 min_plane_buffer_height_multiple;
+	u32 buffer_alignment;
+};
+
+struct hal_uncompressed_plane_actual_constraints_info {
+	enum hal_buffer buffer_type;
+	u32 num_planes;
+	struct hal_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hal_extra_data_header_config {
+	u32 type;
+	enum hal_buffer buffer_type;
+	u32 version;
+	u32 port_index;
+	u32 client_extradata_id;
+};
+
+struct hal_frame_size {
+	enum hal_buffer buffer_type;
+	u32 width;
+	u32 height;
+};
+
+struct hal_enable {
+	bool enable;
+};
+
+struct hal_buffer_count_actual {
+	enum hal_buffer buffer_type;
+	u32 buffer_count_actual;
+};
+
+struct hal_buffer_size_minimum {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+};
+
+struct hal_buffer_display_hold_count_actual {
+	enum hal_buffer buffer_type;
+	u32 hold_count;
+};
+
+enum hal_nal_stream_format {
+	HAL_NAL_FORMAT_STARTCODES         = 0x00000001,
+	HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
+	HAL_NAL_FORMAT_ONE_BYTE_LENGTH    = 0x00000004,
+	HAL_NAL_FORMAT_TWO_BYTE_LENGTH    = 0x00000008,
+	HAL_NAL_FORMAT_FOUR_BYTE_LENGTH   = 0x00000010,
+};
+
+enum hal_output_order {
+	HAL_OUTPUT_ORDER_DISPLAY,
+	HAL_OUTPUT_ORDER_DECODE,
+	HAL_UNUSED_OUTPUT = 0x10000000,
+};
+
+enum hal_picture {
+	HAL_PICTURE_I = 0x01,
+	HAL_PICTURE_P = 0x02,
+	HAL_PICTURE_B = 0x04,
+	HAL_PICTURE_IDR = 0x08,
+	HAL_PICTURE_CRA = 0x10,
+	HAL_FRAME_NOTCODED = 0x7F002000,
+	HAL_FRAME_YUV = 0x7F004000,
+	HAL_UNUSED_PICT = 0x10000000,
+};
+
+struct hal_extradata_enable {
+	u32 enable;
+	enum hal_extradata_id index;
+};
+
+struct hal_enable_picture {
+	u32 picture_type;
+};
+
+struct hal_multi_stream {
+	enum hal_buffer buffer_type;
+	u32 enable;
+	u32 width;
+	u32 height;
+};
+
+struct hal_display_picture_buffer_count {
+	u32 enable;
+	u32 count;
+};
+
+struct hal_mb_error_map {
+	u32 error_map_size;
+	u8 rg_error_map[1];
+};
+
+struct hal_request_iframe {
+	u32 enable;
+};
+
+struct hal_bitrate {
+	u32 bit_rate;
+	u32 layer_id;
+};
+
+struct hal_profile_level {
+	u32 profile;
+	u32 level;
+};
+
+struct hal_profile_level_supported {
+	u32 profile_count;
+	struct hal_profile_level profile_level[MAX_PROFILE_COUNT];
+};
+
+enum hal_h264_entropy {
+	HAL_H264_ENTROPY_CAVLC = 1,
+	HAL_H264_ENTROPY_CABAC = 2,
+	HAL_UNUSED_ENTROPY = 0x10000000,
+};
+
+enum hal_h264_cabac_model {
+	HAL_H264_CABAC_MODEL_0 = 1,
+	HAL_H264_CABAC_MODEL_1 = 2,
+	HAL_H264_CABAC_MODEL_2 = 4,
+	HAL_UNUSED_CABAC = 0x10000000,
+};
+
+struct hal_h264_entropy_control {
+	enum hal_h264_entropy entropy_mode;
+	enum hal_h264_cabac_model cabac_model;
+};
+
+enum hal_rate_control {
+	HAL_RATE_CONTROL_OFF,
+	HAL_RATE_CONTROL_VBR_VFR,
+	HAL_RATE_CONTROL_VBR_CFR,
+	HAL_RATE_CONTROL_CBR_VFR,
+	HAL_RATE_CONTROL_CBR_CFR,
+	HAL_RATE_CONTROL_MBR_CFR,
+	HAL_RATE_CONTROL_MBR_VFR,
+	HAL_UNUSED_RC = 0x10000000,
+};
+
+struct hal_mpeg4_time_resolution {
+	u32 time_increment_resolution;
+};
+
+struct hal_mpeg4_header_extension {
+	u32 header_extension;
+};
+
+enum hal_h264_db_mode {
+	HAL_H264_DB_MODE_DISABLE,
+	HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
+	HAL_H264_DB_MODE_ALL_BOUNDARY,
+	HAL_UNUSED_H264_DB = 0x10000000,
+};
+
+struct hal_h264_db_control {
+	enum hal_h264_db_mode mode;
+	int slice_alpha_offset;
+	int slice_beta_offset;
+};
+
+struct hal_temporal_spatial_tradeoff {
+	u32 ts_factor;
+};
+
+struct hal_quantization {
+	u32 qpi;
+	u32 qpp;
+	u32 qpb;
+	u32 layer_id;
+};
+
+struct hal_initial_quantization {
+	u32 qpi;
+	u32 qpp;
+	u32 qpb;
+	u32 init_qp_enable;
+};
+
+struct hal_quantization_range {
+	u32 min_qp;
+	u32 max_qp;
+	u32 layer_id;
+};
+
+struct hal_intra_period {
+	u32 pframes;
+	u32 bframes;
+};
+
+struct hal_idr_period {
+	u32 idr_period;
+};
+
+enum hal_rotate {
+	HAL_ROTATE_NONE,
+	HAL_ROTATE_90,
+	HAL_ROTATE_180,
+	HAL_ROTATE_270,
+	HAL_UNUSED_ROTATE = 0x10000000,
+};
+
+enum hal_flip {
+	HAL_FLIP_NONE,
+	HAL_FLIP_HORIZONTAL,
+	HAL_FLIP_VERTICAL,
+	HAL_UNUSED_FLIP = 0x10000000,
+};
+
+struct hal_operations {
+	enum hal_rotate rotate;
+	enum hal_flip flip;
+};
+
+enum hal_intra_refresh_mode {
+	HAL_INTRA_REFRESH_NONE,
+	HAL_INTRA_REFRESH_CYCLIC,
+	HAL_INTRA_REFRESH_ADAPTIVE,
+	HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE,
+	HAL_INTRA_REFRESH_RANDOM,
+	HAL_UNUSED_INTRA = 0x10000000,
+};
+
+struct hal_intra_refresh {
+	enum hal_intra_refresh_mode mode;
+	u32 air_mbs;
+	u32 air_ref;
+	u32 cir_mbs;
+};
+
+enum hal_multi_slice {
+	HAL_MULTI_SLICE_OFF,
+	HAL_MULTI_SLICE_BY_MB_COUNT,
+	HAL_MULTI_SLICE_BY_BYTE_COUNT,
+	HAL_MULTI_SLICE_GOB,
+	HAL_UNUSED_SLICE = 0x10000000,
+};
+
+struct hal_multi_slice_control {
+	enum hal_multi_slice multi_slice;
+	u32 slice_size;
+};
+
+struct hal_debug_config {
+	u32 debug_config;
+};
+
+struct hal_buffer_requirements {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+	u32 buffer_region_size;
+	u32 buffer_hold_count;
+	u32 buffer_count_min;
+	u32 buffer_count_actual;
+	u32 contiguous;
+	u32 buffer_alignment;
+};
+
+enum hal_priority {/* Priority increases with number */
+	HAL_PRIORITY_LOW = 10,
+	HAL_PRIOIRTY_MEDIUM = 20,
+	HAL_PRIORITY_HIGH = 30,
+	HAL_UNUSED_PRIORITY = 0x10000000,
+};
+
+struct hal_batch_info {
+	u32 input_batch_count;
+	u32 output_batch_count;
+};
+
+struct hal_metadata_pass_through {
+	u32 enable;
+	u32 size;
+};
+
+struct hal_uncompressed_format_supported {
+	enum hal_buffer buffer_type;
+	u32 format_entries;
+	u32 rg_format_info[1];
+};
+
+enum hal_interlace_format {
+	HAL_INTERLACE_FRAME_PROGRESSIVE                 = 0x01,
+	HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST    = 0x02,
+	HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+	HAL_INTERLACE_FRAME_TOPFIELDFIRST               = 0x08,
+	HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST            = 0x10,
+	HAL_UNUSED_INTERLACE = 0x10000000,
+};
+
+struct hal_interlace_format_supported {
+	enum hal_buffer buffer_type;
+	enum hal_interlace_format format;
+};
+
+enum hal_chroma_site {
+	HAL_CHROMA_SITE_0,
+	HAL_CHROMA_SITE_1,
+	HAL_UNUSED_CHROMA = 0x10000000,
+};
+
+struct hal_properties_supported {
+	u32 num_properties;
+	u32 rg_properties[1];
+};
+
+enum hal_capability {
+	HAL_CAPABILITY_FRAME_WIDTH = 0x1,
+	HAL_CAPABILITY_FRAME_HEIGHT,
+	HAL_CAPABILITY_MBS_PER_FRAME,
+	HAL_CAPABILITY_MBS_PER_SECOND,
+	HAL_CAPABILITY_FRAMERATE,
+	HAL_CAPABILITY_SCALE_X,
+	HAL_CAPABILITY_SCALE_Y,
+	HAL_CAPABILITY_BITRATE,
+	HAL_CAPABILITY_BFRAME,
+	HAL_CAPABILITY_PEAKBITRATE,
+	HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_ENC_LTR_COUNT,
+	HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD,
+	HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_LCU_SIZE,
+	HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE,
+	HAL_UNUSED_CAPABILITY = 0x10000000,
+};
+
+struct hal_capability_supported {
+	enum hal_capability capability_type;
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+struct hal_capability_supported_info {
+	u32 num_capabilities;
+	struct hal_capability_supported rg_data[1];
+};
+
+struct hal_nal_stream_format_supported {
+	u32 nal_stream_format_supported;
+};
+
+struct hal_nal_stream_format_select {
+	u32 nal_stream_format_select;
+};
+
+struct hal_multi_view_format {
+	u32 views;
+	u32 rg_view_order[1];
+};
+
+enum hal_buffer_layout_type {
+	HAL_BUFFER_LAYOUT_TOP_BOTTOM,
+	HAL_BUFFER_LAYOUT_SEQ,
+	HAL_UNUSED_BUFFER_LAYOUT = 0x10000000,
+};
+
+struct hal_mvc_buffer_layout {
+	enum hal_buffer_layout_type layout_type;
+	u32 bright_view_first;
+	u32 ngap;
+};
+
+struct hal_seq_header_info {
+	u32 nax_header_len;
+};
+
+struct hal_aspect_ratio {
+	u32 aspect_width;
+	u32 aspect_height;
+};
+
+struct hal_codec_supported {
+	u32 decoder_codec_supported;
+	u32 encoder_codec_supported;
+};
+
+struct hal_multi_view_select {
+	u32 view_index;
+};
+
+struct hal_timestamp_scale {
+	u32 time_stamp_scale;
+};
+
+
+struct hal_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
+struct hal_h264_vui_bitstream_restrc {
+	u32 enable;
+};
+
+struct hal_preserve_text_quality {
+	u32 enable;
+};
+
+struct hal_vc1e_perf_cfg_type {
+	struct {
+		u32 x_subsampled;
+		u32 y_subsampled;
+	} i_frame, p_frame, b_frame;
+};
+
+struct hal_vpe_color_space_conversion {
+	u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
+	u32 csc_bias[HAL_MAX_BIAS_COEFFS];
+	u32 csc_limit[HAL_MAX_LIMIT_COEFFS];
+};
+
+struct hal_video_signal_info {
+	u32 color_space;
+	u32 transfer_chars;
+	u32 matrix_coeffs;
+	bool full_range;
+};
+
+enum hal_iframesize_type {
+	HAL_IFRAMESIZE_TYPE_DEFAULT,
+	HAL_IFRAMESIZE_TYPE_MEDIUM,
+	HAL_IFRAMESIZE_TYPE_HUGE,
+	HAL_IFRAMESIZE_TYPE_UNLIMITED,
+};
+
+enum vidc_resource_id {
+	VIDC_RESOURCE_NONE,
+	VIDC_RESOURCE_OCMEM,
+	VIDC_RESOURCE_VMEM,
+	VIDC_UNUSED_RESOURCE = 0x10000000,
+};
+
+struct vidc_resource_hdr {
+	enum vidc_resource_id resource_id;
+	void *resource_handle;
+	u32 size;
+};
+
+struct vidc_buffer_addr_info {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+	u32 num_buffers;
+	ion_phys_addr_t align_device_addr;
+	ion_phys_addr_t extradata_addr;
+	u32 extradata_size;
+	u32 response_required;
+};
+
+/* Needs to be exactly the same as hfi_buffer_info */
+struct hal_buffer_info {
+	u32 buffer_addr;
+	u32 extra_data_addr;
+};
+
+struct vidc_frame_plane_config {
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+	u32 stride;
+	u32 scan_lines;
+};
+
+struct vidc_uncompressed_frame_config {
+	struct vidc_frame_plane_config luma_plane;
+	struct vidc_frame_plane_config chroma_plane;
+};
+
+struct vidc_frame_data {
+	enum hal_buffer buffer_type;
+	ion_phys_addr_t device_addr;
+	ion_phys_addr_t extradata_addr;
+	int64_t timestamp;
+	u32 flags;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 mark_target;
+	u32 mark_data;
+	u32 clnt_data;
+	u32 extradata_size;
+};
+
+struct vidc_seq_hdr {
+	ion_phys_addr_t seq_hdr;
+	u32 seq_hdr_len;
+};
+
+struct hal_fw_info {
+	char version[VENUS_VERSION_LENGTH];
+	phys_addr_t base_addr;
+	int register_base;
+	int register_size;
+	int irq;
+};
+
+enum hal_flush {
+	HAL_FLUSH_INPUT,
+	HAL_FLUSH_OUTPUT,
+	HAL_FLUSH_ALL,
+	HAL_UNUSED_FLUSH = 0x10000000,
+};
+
+enum hal_event_type {
+	HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
+	HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+	HAL_EVENT_RELEASE_BUFFER_REFERENCE,
+	HAL_UNUSED_SEQCHG = 0x10000000,
+};
+
+enum buffer_mode_type {
+	HAL_BUFFER_MODE_STATIC = 0x001,
+	HAL_BUFFER_MODE_RING = 0x010,
+	HAL_BUFFER_MODE_DYNAMIC = 0x100,
+};
+
+struct hal_buffer_alloc_mode {
+	enum hal_buffer buffer_type;
+	enum buffer_mode_type buffer_mode;
+};
+
+enum ltr_mode {
+	HAL_LTR_MODE_DISABLE,
+	HAL_LTR_MODE_MANUAL,
+	HAL_LTR_MODE_PERIODIC,
+};
+
+struct hal_ltr_mode {
+	enum ltr_mode mode;
+	u32 count;
+	u32 trust_mode;
+};
+
+struct hal_ltr_use {
+	u32 ref_ltr;
+	u32 use_constraint;
+	u32 frames;
+};
+
+struct hal_ltr_mark {
+	u32 mark_frame;
+};
+
+enum hal_perf_mode {
+	HAL_PERF_MODE_POWER_SAVE,
+	HAL_PERF_MODE_POWER_MAX_QUALITY,
+};
+
+struct hal_hybrid_hierp {
+	u32 layers;
+};
+
+struct hal_scs_threshold {
+	u32 threshold_value;
+};
+
+struct buffer_requirements {
+	struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
+};
+
+union hal_get_property {
+	struct hal_frame_rate frame_rate;
+	struct hal_uncompressed_format_select format_select;
+	struct hal_uncompressed_plane_actual plane_actual;
+	struct hal_uncompressed_plane_actual_info plane_actual_info;
+	struct hal_uncompressed_plane_constraints plane_constraints;
+	struct hal_uncompressed_plane_actual_constraints_info
+						plane_constraints_info;
+	struct hal_extra_data_header_config extra_data_header_config;
+	struct hal_frame_size frame_size;
+	struct hal_enable enable;
+	struct hal_buffer_count_actual buffer_count_actual;
+	struct hal_extradata_enable extradata_enable;
+	struct hal_enable_picture enable_picture;
+	struct hal_multi_stream multi_stream;
+	struct hal_display_picture_buffer_count display_picture_buffer_count;
+	struct hal_mb_error_map mb_error_map;
+	struct hal_request_iframe request_iframe;
+	struct hal_bitrate bitrate;
+	struct hal_profile_level profile_level;
+	struct hal_profile_level_supported profile_level_supported;
+	struct hal_mpeg4_time_resolution mpeg4_time_resolution;
+	struct hal_mpeg4_header_extension mpeg4_header_extension;
+	struct hal_h264_db_control h264_db_control;
+	struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff;
+	struct hal_quantization quantization;
+	struct hal_quantization_range quantization_range;
+	struct hal_intra_period intra_period;
+	struct hal_idr_period idr_period;
+	struct hal_operations operations;
+	struct hal_intra_refresh intra_refresh;
+	struct hal_multi_slice_control multi_slice_control;
+	struct hal_debug_config debug_config;
+	struct hal_batch_info batch_info;
+	struct hal_metadata_pass_through metadata_pass_through;
+	struct hal_uncompressed_format_supported uncompressed_format_supported;
+	struct hal_interlace_format_supported interlace_format_supported;
+	struct hal_properties_supported properties_supported;
+	struct hal_capability_supported capability_supported;
+	struct hal_capability_supported_info capability_supported_info;
+	struct hal_nal_stream_format_supported nal_stream_format_supported;
+	struct hal_nal_stream_format_select nal_stream_format_select;
+	struct hal_multi_view_format multi_view_format;
+	struct hal_seq_header_info seq_header_info;
+	struct hal_codec_supported codec_supported;
+	struct hal_multi_view_select multi_view_select;
+	struct hal_timestamp_scale timestamp_scale;
+	struct hal_h264_vui_timing_info h264_vui_timing_info;
+	struct hal_h264_vui_bitstream_restrc h264_vui_bitstream_restrc;
+	struct hal_preserve_text_quality preserve_text_quality;
+	struct hal_buffer_info buffer_info;
+	struct hal_buffer_alloc_mode buffer_alloc_mode;
+	struct buffer_requirements buf_req;
+	enum hal_h264_entropy h264_entropy;
+};
+
+/* HAL Response */
+#define IS_HAL_SYS_CMD(cmd) ((cmd) >= HAL_SYS_INIT_DONE && \
+		(cmd) <= HAL_SYS_ERROR)
+#define IS_HAL_SESSION_CMD(cmd) ((cmd) >= HAL_SESSION_EVENT_CHANGE && \
+		(cmd) <= HAL_SESSION_ERROR)
+enum hal_command_response {
+	/* SYSTEM COMMANDS_DONE*/
+	HAL_SYS_INIT_DONE,
+	HAL_SYS_SET_RESOURCE_DONE,
+	HAL_SYS_RELEASE_RESOURCE_DONE,
+	HAL_SYS_PING_ACK_DONE,
+	HAL_SYS_PC_PREP_DONE,
+	HAL_SYS_IDLE,
+	HAL_SYS_DEBUG,
+	HAL_SYS_WATCHDOG_TIMEOUT,
+	HAL_SYS_ERROR,
+	/* SESSION COMMANDS_DONE */
+	HAL_SESSION_EVENT_CHANGE,
+	HAL_SESSION_LOAD_RESOURCE_DONE,
+	HAL_SESSION_INIT_DONE,
+	HAL_SESSION_END_DONE,
+	HAL_SESSION_ABORT_DONE,
+	HAL_SESSION_START_DONE,
+	HAL_SESSION_STOP_DONE,
+	HAL_SESSION_ETB_DONE,
+	HAL_SESSION_FTB_DONE,
+	HAL_SESSION_FLUSH_DONE,
+	HAL_SESSION_SUSPEND_DONE,
+	HAL_SESSION_RESUME_DONE,
+	HAL_SESSION_SET_PROP_DONE,
+	HAL_SESSION_GET_PROP_DONE,
+	HAL_SESSION_PARSE_SEQ_HDR_DONE,
+	HAL_SESSION_GET_SEQ_HDR_DONE,
+	HAL_SESSION_RELEASE_BUFFER_DONE,
+	HAL_SESSION_RELEASE_RESOURCE_DONE,
+	HAL_SESSION_PROPERTY_INFO,
+	HAL_SESSION_ERROR,
+	HAL_RESPONSE_UNUSED = 0x10000000,
+};
+
+struct vidc_hal_ebd {
+	u32 timestamp_hi;
+	u32 timestamp_lo;
+	u32 flags;
+	enum vidc_status status;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	enum hal_picture picture_type;
+	ion_phys_addr_t packet_buffer;
+	ion_phys_addr_t extra_data_buffer;
+};
+
+struct vidc_hal_fbd {
+	u32 stream_id;
+	u32 view_id;
+	u32 timestamp_hi;
+	u32 timestamp_lo;
+	u32 flags1;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 alloc_len1;
+	u32 filled_len1;
+	u32 offset1;
+	u32 frame_width;
+	u32 frame_height;
+	u32 start_x_coord;
+	u32 start_y_coord;
+	u32 input_tag;
+	u32 input_tag1;
+	enum hal_picture picture_type;
+	ion_phys_addr_t packet_buffer1;
+	ion_phys_addr_t extra_data_buffer;
+	u32 flags2;
+	u32 alloc_len2;
+	u32 filled_len2;
+	u32 offset2;
+	ion_phys_addr_t packet_buffer2;
+	u32 flags3;
+	u32 alloc_len3;
+	u32 filled_len3;
+	u32 offset3;
+	ion_phys_addr_t packet_buffer3;
+	enum hal_buffer buffer_type;
+};
+
+struct msm_vidc_capability {
+	enum hal_domain domain;
+	enum hal_video_codec codec;
+	struct hal_capability_supported width;
+	struct hal_capability_supported height;
+	struct hal_capability_supported mbs_per_frame;
+	struct hal_capability_supported mbs_per_sec;
+	struct hal_capability_supported frame_rate;
+	struct hal_capability_supported scale_x;
+	struct hal_capability_supported scale_y;
+	struct hal_capability_supported bitrate;
+	struct hal_capability_supported bframe;
+	struct hal_capability_supported peakbitrate;
+	struct hal_capability_supported hier_p;
+	struct hal_capability_supported ltr_count;
+	struct hal_capability_supported secure_output2_threshold;
+	struct hal_capability_supported hier_b;
+	struct hal_capability_supported lcu_size;
+	struct hal_capability_supported hier_p_hybrid;
+	struct hal_capability_supported mbs_per_sec_power_save;
+	struct hal_profile_level_supported profile_level;
+	struct hal_uncompressed_format_supported uncomp_format;
+	struct hal_interlace_format_supported HAL_format;
+	struct hal_nal_stream_format_supported nal_stream_format;
+	struct hal_intra_refresh intra_refresh;
+	enum buffer_mode_type alloc_mode_out;
+	enum buffer_mode_type alloc_mode_in;
+	u32 pixelprocess_capabilities;
+};
+
+struct vidc_hal_sys_init_done {
+	u32 dec_codec_supported;
+	u32 enc_codec_supported;
+	u32 codec_count;
+	struct msm_vidc_capability *capabilities;
+	u32 max_sessions_supported;
+};
+
+struct vidc_hal_session_init_done {
+	struct msm_vidc_capability capability;
+};
+
+struct msm_vidc_cb_cmd_done {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 size;
+	union {
+		struct vidc_resource_hdr resource_hdr;
+		struct vidc_buffer_addr_info buffer_addr_info;
+		struct vidc_frame_plane_config frame_plane_config;
+		struct vidc_uncompressed_frame_config uncompressed_frame_config;
+		struct vidc_frame_data frame_data;
+		struct vidc_seq_hdr seq_hdr;
+		struct vidc_hal_ebd ebd;
+		struct vidc_hal_fbd fbd;
+		struct vidc_hal_sys_init_done sys_init_done;
+		struct vidc_hal_session_init_done session_init_done;
+		struct hal_buffer_info buffer_info;
+		union hal_get_property property;
+		enum hal_flush flush_type;
+	} data;
+};
+
+struct msm_vidc_cb_event {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 height;
+	u32 width;
+	enum msm_vidc_pixel_depth bit_depth;
+	u32 hal_event_type;
+	ion_phys_addr_t packet_buffer;
+	ion_phys_addr_t extra_data_buffer;
+	u32 pic_struct;
+	u32 colour_space;
+};
+
+struct msm_vidc_cb_data_done {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 size;
+	u32 clnt_data;
+	union {
+		struct vidc_hal_ebd input_done;
+		struct vidc_hal_fbd output_done;
+	};
+};
+
+struct msm_vidc_cb_info {
+	enum hal_command_response response_type;
+	union {
+		struct msm_vidc_cb_cmd_done cmd;
+		struct msm_vidc_cb_event event;
+		struct msm_vidc_cb_data_done data;
+	} response;
+};
+
+enum msm_vidc_hfi_type {
+	VIDC_HFI_VENUS,
+};
+
+enum msm_vidc_thermal_level {
+	VIDC_THERMAL_NORMAL = 0,
+	VIDC_THERMAL_LOW,
+	VIDC_THERMAL_HIGH,
+	VIDC_THERMAL_CRITICAL
+};
+
+enum vidc_vote_data_session {
+	VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0,
+	/* No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL
+	 * describe the enumerations e.g.:
+	 *
+	 * enum vidc_bus_vote_data_session_type h264_decoder_session =
+	 *        VIDC_VOTE_DATA_SESSION_VAL(HAL_VIDEO_CODEC_H264,
+	 *                 HAL_VIDEO_DOMAIN_DECODER);
+	 */
+};
+
+/* Careful modifying VIDC_VOTE_DATA_SESSION_VAL().
+ *
+ * This macro assigns two bits to each codec: the lower bit denoting the codec
+ * type, and the higher bit denoting session type.
+ */
+static inline enum vidc_vote_data_session VIDC_VOTE_DATA_SESSION_VAL(
+		enum hal_video_codec c, enum hal_domain d) {
+	if (d != HAL_VIDEO_DOMAIN_ENCODER && d != HAL_VIDEO_DOMAIN_DECODER)
+		return VIDC_BUS_VOTE_DATA_SESSION_INVALID;
+
+	return (1 << ilog2(c) * 2) | ((d - 1) << (ilog2(c) * 2 + 1));
+}
+
+struct msm_vidc_gov_data {
+	struct vidc_bus_vote_data *data;
+	u32 data_count;
+	int imem_size;
+};
+
+enum msm_vidc_power_mode {
+	VIDC_POWER_NORMAL = 0,
+	VIDC_POWER_LOW,
+	VIDC_POWER_TURBO
+};
+
+
+struct vidc_bus_vote_data {
+	enum hal_domain domain;
+	enum hal_video_codec codec;
+	enum hal_uncompressed_format color_formats[2];
+	int num_formats; /* 1 = DPB-OPB unified; 2 = split */
+	int height, width, fps;
+	enum msm_vidc_power_mode power_mode;
+	struct imem_ab_table *imem_ab_tbl;
+	u32 imem_ab_tbl_size;
+	unsigned long core_freq;
+};
+
+
+struct vidc_clk_scale_data {
+	enum vidc_vote_data_session session[VIDC_MAX_SESSIONS];
+	enum msm_vidc_power_mode power_mode[VIDC_MAX_SESSIONS];
+	u32 load[VIDC_MAX_SESSIONS];
+	int num_sessions;
+};
+
+struct hal_index_extradata_input_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
+struct hal_cmd_sys_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+#define call_hfi_op(q, op, args...)			\
+	(((q) && (q)->op) ? ((q)->op(args)) : 0)
+
+struct hfi_device {
+	void *hfi_device_data;
+
+	/*Add function pointers for all the hfi functions below*/
+	int (*core_init)(void *device);
+	int (*core_release)(void *device);
+	int (*core_ping)(void *device);
+	int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
+	int (*session_init)(void *device, void *session_id,
+		enum hal_domain session_type, enum hal_video_codec codec_type,
+		void **new_session);
+	int (*session_end)(void *session);
+	int (*session_abort)(void *session);
+	int (*session_set_buffers)(void *sess,
+				struct vidc_buffer_addr_info *buffer_info);
+	int (*session_release_buffers)(void *sess,
+				struct vidc_buffer_addr_info *buffer_info);
+	int (*session_load_res)(void *sess);
+	int (*session_release_res)(void *sess);
+	int (*session_start)(void *sess);
+	int (*session_continue)(void *sess);
+	int (*session_stop)(void *sess);
+	int (*session_etb)(void *sess, struct vidc_frame_data *input_frame);
+	int (*session_ftb)(void *sess, struct vidc_frame_data *output_frame);
+	int (*session_process_batch)(void *sess,
+		int num_etbs, struct vidc_frame_data etbs[],
+		int num_ftbs, struct vidc_frame_data ftbs[]);
+	int (*session_parse_seq_hdr)(void *sess,
+			struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_seq_hdr)(void *sess,
+			struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_buf_req)(void *sess);
+	int (*session_flush)(void *sess, enum hal_flush flush_mode);
+	int (*session_set_property)(void *sess, enum hal_property ptype,
+			void *pdata);
+	int (*session_get_property)(void *sess, enum hal_property ptype);
+	int (*scale_clocks)(void *dev, int load,
+			struct vidc_clk_scale_data *data,
+			unsigned long instant_bitrate);
+	int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data,
+			int num_data);
+	int (*get_fw_info)(void *dev, struct hal_fw_info *fw_info);
+	int (*session_clean)(void *sess);
+	int (*get_core_capabilities)(void *dev);
+	int (*suspend)(void *dev);
+	unsigned long (*get_core_clock_rate)(void *dev, bool actual_rate);
+	enum hal_default_properties (*get_default_properties)(void *dev);
+};
+
+typedef void (*hfi_cmd_response_callback) (enum hal_command_response cmd,
+			void *data);
+typedef void (*msm_vidc_callback) (u32 response, void *callback);
+
+struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
+		u32 device_id, struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback);
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+			struct hfi_device *hdev);
+u32 vidc_get_hfi_domain(enum hal_domain hal_domain);
+u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec);
+enum hal_domain vidc_get_hal_domain(u32 hfi_domain);
+enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec);
+
+#endif /*__VIDC_HFI_API_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
new file mode 100644
index 0000000..39904a5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
@@ -0,0 +1,1180 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __H_VIDC_HFI_HELPER_H__
+#define __H_VIDC_HFI_HELPER_H__
+
+#define HFI_COMMON_BASE				(0)
+#define HFI_OX_BASE					(0x01000000)
+
+#define HFI_VIDEO_DOMAIN_ENCODER	(HFI_COMMON_BASE + 0x1)
+#define HFI_VIDEO_DOMAIN_DECODER	(HFI_COMMON_BASE + 0x2)
+#define HFI_VIDEO_DOMAIN_VPE		(HFI_COMMON_BASE + 0x4)
+#define HFI_VIDEO_DOMAIN_MBI		(HFI_COMMON_BASE + 0x8)
+
+#define HFI_DOMAIN_BASE_COMMON		(HFI_COMMON_BASE + 0)
+#define HFI_DOMAIN_BASE_VDEC		(HFI_COMMON_BASE + 0x01000000)
+#define HFI_DOMAIN_BASE_VENC		(HFI_COMMON_BASE + 0x02000000)
+#define HFI_DOMAIN_BASE_VPE			(HFI_COMMON_BASE + 0x03000000)
+
+#define HFI_VIDEO_ARCH_OX			(HFI_COMMON_BASE + 0x1)
+
+#define HFI_ARCH_COMMON_OFFSET		(0)
+#define HFI_ARCH_OX_OFFSET			(0x00200000)
+
+#define  HFI_CMD_START_OFFSET		(0x00010000)
+#define  HFI_MSG_START_OFFSET		(0x00020000)
+
+#define HFI_ERR_NONE						HFI_COMMON_BASE
+#define HFI_ERR_SYS_FATAL				(HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_INVALID_PARAMETER		(HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_VERSION_MISMATCH		(HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES	(HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_MAX_SESSIONS_REACHED	(HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_UNSUPPORTED_CODEC		(HFI_COMMON_BASE + 0x6)
+#define HFI_ERR_SYS_SESSION_IN_USE			(HFI_COMMON_BASE + 0x7)
+#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE	(HFI_COMMON_BASE + 0x8)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN		(HFI_COMMON_BASE + 0x9)
+
+#define HFI_ERR_SESSION_FATAL			(HFI_COMMON_BASE + 0x1001)
+#define HFI_ERR_SESSION_INVALID_PARAMETER	(HFI_COMMON_BASE + 0x1002)
+#define HFI_ERR_SESSION_BAD_POINTER		(HFI_COMMON_BASE + 0x1003)
+#define HFI_ERR_SESSION_INVALID_SESSION_ID	(HFI_COMMON_BASE + 0x1004)
+#define HFI_ERR_SESSION_INVALID_STREAM_ID	(HFI_COMMON_BASE + 0x1005)
+#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION		\
+	(HFI_COMMON_BASE + 0x1006)
+#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY	(HFI_COMMON_BASE + 0x1007)
+
+#define HFI_ERR_SESSION_UNSUPPORTED_SETTING	(HFI_COMMON_BASE + 0x1008)
+
+#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES	(HFI_COMMON_BASE + 0x1009)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED	\
+	(HFI_COMMON_BASE + 0x100A)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT		(HFI_COMMON_BASE + 0x100B)
+#define HFI_ERR_SESSION_ENC_OVERFLOW		(HFI_COMMON_BASE + 0x100C)
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM	(HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_CMDSIZE			(HFI_COMMON_BASE + 0x100E)
+#define HFI_ERR_SESSION_UNSUPPORT_CMD		(HFI_COMMON_BASE + 0x100F)
+#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE	(HFI_COMMON_BASE + 0x1010)
+#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL	(HFI_COMMON_BASE + 0x1011)
+#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR	(HFI_COMMON_BASE + 0x1012)
+#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED	(HFI_COMMON_BASE + 0x1013)
+
+#define HFI_EVENT_SYS_ERROR				(HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_SESSION_ERROR			(HFI_COMMON_BASE + 0x2)
+
+#define HFI_VIDEO_CODEC_H264				0x00000002
+#define HFI_VIDEO_CODEC_H263				0x00000004
+#define HFI_VIDEO_CODEC_MPEG1				0x00000008
+#define HFI_VIDEO_CODEC_MPEG2				0x00000010
+#define HFI_VIDEO_CODEC_MPEG4				0x00000020
+#define HFI_VIDEO_CODEC_DIVX_311			0x00000040
+#define HFI_VIDEO_CODEC_DIVX				0x00000080
+#define HFI_VIDEO_CODEC_VC1				0x00000100
+#define HFI_VIDEO_CODEC_SPARK				0x00000200
+#define HFI_VIDEO_CODEC_VP8				0x00001000
+#define HFI_VIDEO_CODEC_HEVC				0x00002000
+#define HFI_VIDEO_CODEC_VP9				0x00004000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x80000000
+
+#define HFI_H264_PROFILE_BASELINE			0x00000001
+#define HFI_H264_PROFILE_MAIN				0x00000002
+#define HFI_H264_PROFILE_HIGH				0x00000004
+#define HFI_H264_PROFILE_STEREO_HIGH		0x00000008
+#define HFI_H264_PROFILE_MULTIVIEW_HIGH		0x00000010
+#define HFI_H264_PROFILE_CONSTRAINED_BASE	0x00000020
+#define HFI_H264_PROFILE_CONSTRAINED_HIGH	0x00000040
+
+#define HFI_H264_LEVEL_1					0x00000001
+#define HFI_H264_LEVEL_1b					0x00000002
+#define HFI_H264_LEVEL_11					0x00000004
+#define HFI_H264_LEVEL_12					0x00000008
+#define HFI_H264_LEVEL_13					0x00000010
+#define HFI_H264_LEVEL_2					0x00000020
+#define HFI_H264_LEVEL_21					0x00000040
+#define HFI_H264_LEVEL_22					0x00000080
+#define HFI_H264_LEVEL_3					0x00000100
+#define HFI_H264_LEVEL_31					0x00000200
+#define HFI_H264_LEVEL_32					0x00000400
+#define HFI_H264_LEVEL_4					0x00000800
+#define HFI_H264_LEVEL_41					0x00001000
+#define HFI_H264_LEVEL_42					0x00002000
+#define HFI_H264_LEVEL_5					0x00004000
+#define HFI_H264_LEVEL_51					0x00008000
+#define HFI_H264_LEVEL_52                                       0x00010000
+
+#define HFI_H263_PROFILE_BASELINE			0x00000001
+
+#define HFI_H263_LEVEL_10					0x00000001
+#define HFI_H263_LEVEL_20					0x00000002
+#define HFI_H263_LEVEL_30					0x00000004
+#define HFI_H263_LEVEL_40					0x00000008
+#define HFI_H263_LEVEL_45					0x00000010
+#define HFI_H263_LEVEL_50					0x00000020
+#define HFI_H263_LEVEL_60					0x00000040
+#define HFI_H263_LEVEL_70					0x00000080
+
+#define HFI_MPEG2_PROFILE_SIMPLE			0x00000001
+#define HFI_MPEG2_PROFILE_MAIN				0x00000002
+#define HFI_MPEG2_PROFILE_422				0x00000004
+#define HFI_MPEG2_PROFILE_SNR				0x00000008
+#define HFI_MPEG2_PROFILE_SPATIAL			0x00000010
+#define HFI_MPEG2_PROFILE_HIGH				0x00000020
+
+#define HFI_MPEG2_LEVEL_LL					0x00000001
+#define HFI_MPEG2_LEVEL_ML					0x00000002
+#define HFI_MPEG2_LEVEL_H14					0x00000004
+#define HFI_MPEG2_LEVEL_HL					0x00000008
+
+#define HFI_MPEG4_PROFILE_SIMPLE			0x00000001
+#define HFI_MPEG4_PROFILE_ADVANCEDSIMPLE	0x00000002
+
+#define HFI_MPEG4_LEVEL_0					0x00000001
+#define HFI_MPEG4_LEVEL_0b					0x00000002
+#define HFI_MPEG4_LEVEL_1					0x00000004
+#define HFI_MPEG4_LEVEL_2					0x00000008
+#define HFI_MPEG4_LEVEL_3					0x00000010
+#define HFI_MPEG4_LEVEL_4					0x00000020
+#define HFI_MPEG4_LEVEL_4a					0x00000040
+#define HFI_MPEG4_LEVEL_5					0x00000080
+#define HFI_MPEG4_LEVEL_6					0x00000100
+#define HFI_MPEG4_LEVEL_7					0x00000200
+#define HFI_MPEG4_LEVEL_8					0x00000400
+#define HFI_MPEG4_LEVEL_9					0x00000800
+#define HFI_MPEG4_LEVEL_3b					0x00001000
+
+#define HFI_VC1_PROFILE_SIMPLE				0x00000001
+#define HFI_VC1_PROFILE_MAIN				0x00000002
+#define HFI_VC1_PROFILE_ADVANCED			0x00000004
+
+#define HFI_VC1_LEVEL_LOW					0x00000001
+#define HFI_VC1_LEVEL_MEDIUM				0x00000002
+#define HFI_VC1_LEVEL_HIGH					0x00000004
+#define HFI_VC1_LEVEL_0						0x00000008
+#define HFI_VC1_LEVEL_1						0x00000010
+#define HFI_VC1_LEVEL_2						0x00000020
+#define HFI_VC1_LEVEL_3						0x00000040
+#define HFI_VC1_LEVEL_4						0x00000080
+
+#define HFI_VPX_PROFILE_SIMPLE				0x00000001
+#define HFI_VPX_PROFILE_ADVANCED			0x00000002
+#define HFI_VPX_PROFILE_VERSION_0			0x00000004
+#define HFI_VPX_PROFILE_VERSION_1			0x00000008
+#define HFI_VPX_PROFILE_VERSION_2			0x00000010
+#define HFI_VPX_PROFILE_VERSION_3			0x00000020
+
+#define HFI_DIVX_FORMAT_4				(HFI_COMMON_BASE + 0x1)
+#define HFI_DIVX_FORMAT_5				(HFI_COMMON_BASE + 0x2)
+#define HFI_DIVX_FORMAT_6				(HFI_COMMON_BASE + 0x3)
+
+#define HFI_DIVX_PROFILE_QMOBILE		0x00000001
+#define HFI_DIVX_PROFILE_MOBILE			0x00000002
+#define HFI_DIVX_PROFILE_MT				0x00000004
+#define HFI_DIVX_PROFILE_HT				0x00000008
+#define HFI_DIVX_PROFILE_HD				0x00000010
+
+#define  HFI_HEVC_PROFILE_MAIN			0x00000001
+#define  HFI_HEVC_PROFILE_MAIN10		0x00000002
+#define  HFI_HEVC_PROFILE_MAIN_STILL_PIC	0x00000004
+
+#define  HFI_HEVC_LEVEL_1	0x00000001
+#define  HFI_HEVC_LEVEL_2	0x00000002
+#define  HFI_HEVC_LEVEL_21	0x00000004
+#define  HFI_HEVC_LEVEL_3	0x00000008
+#define  HFI_HEVC_LEVEL_31	0x00000010
+#define  HFI_HEVC_LEVEL_4	0x00000020
+#define  HFI_HEVC_LEVEL_41	0x00000040
+#define  HFI_HEVC_LEVEL_5	0x00000080
+#define  HFI_HEVC_LEVEL_51	0x00000100
+#define  HFI_HEVC_LEVEL_52	0x00000200
+#define  HFI_HEVC_LEVEL_6	0x00000400
+#define  HFI_HEVC_LEVEL_61	0x00000800
+#define  HFI_HEVC_LEVEL_62	0x00001000
+
+#define HFI_HEVC_TIER_MAIN	0x1
+#define HFI_HEVC_TIER_HIGH0	0x2
+
+#define HFI_BUFFER_INPUT				(HFI_COMMON_BASE + 0x1)
+#define HFI_BUFFER_OUTPUT				(HFI_COMMON_BASE + 0x2)
+#define HFI_BUFFER_OUTPUT2				(HFI_COMMON_BASE + 0x3)
+#define HFI_BUFFER_INTERNAL_PERSIST		(HFI_COMMON_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_PERSIST_1		(HFI_COMMON_BASE + 0x5)
+
+#define  HFI_BITDEPTH_8				(HFI_COMMON_BASE + 0x0)
+#define  HFI_BITDEPTH_9				(HFI_COMMON_BASE + 0x1)
+#define  HFI_BITDEPTH_10			(HFI_COMMON_BASE + 0x2)
+
+#define HFI_VENC_PERFMODE_MAX_QUALITY	0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE	0x2
+
+struct hfi_buffer_info {
+	u32 buffer_addr;
+	u32 extra_data_addr;
+};
+
+#define HFI_PROPERTY_SYS_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_DEBUG_CONFIG		\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x001)
+#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO	\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x002)
+#define HFI_PROPERTY_SYS_CONFIG_VCODEC_CLKFREQ				\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x003)
+#define HFI_PROPERTY_SYS_IDLE_INDICATOR         \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x004)
+#define  HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL     \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x005)
+#define  HFI_PROPERTY_SYS_IMAGE_VERSION    \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x006)
+#define  HFI_PROPERTY_SYS_CONFIG_COVERAGE    \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_COMMON_START	\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_FRAME_SIZE		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO	\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
+#define  HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE        \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
+#define  HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED            \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
+#define  HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED	    \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
+
+#define HFI_PROPERTY_CONFIG_COMMON_START				\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
+#define HFI_PROPERTY_CONFIG_FRAME_RATE					\
+	(HFI_PROPERTY_CONFIG_COMMON_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VDEC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x003)
+#define  HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x009)
+#define  HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00A)
+
+
+#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000)
+
+#define HFI_PROPERTY_PARAM_VENC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
+#define  HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE     \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00B)
+#define  HFI_PROPERTY_PARAM_VENC_OPEN_GOP                   \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E)
+#define  HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F)
+#define  HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
+#define HFI_PROPERTY_PARAM_VENC_ADVANCED				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012)
+#define  HFI_PROPERTY_PARAM_VENC_H264_SPS_ID                \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014)
+#define  HFI_PROPERTY_PARAM_VENC_H264_PPS_ID               \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015)
+#define HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x016)
+#define HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x017)
+#define HFI_PROPERTY_PARAM_VENC_NUMREF					\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018)
+#define HFI_PROPERTY_PARAM_VENC_MULTIREF_P				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
+#define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VENC_LTRMODE		\
+	 (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C)
+#define HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
+#define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
+#define  HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021)
+#define HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x022)
+#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x023)
+#define HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x025)
+#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026)
+#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x027)
+#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028)
+#define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029)
+#define HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02B)
+#define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C)
+#define  HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02F)
+#define  HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x031)
+#define  HFI_PROPERTY_PARAM_VENC_VQZIP_SEI_TYPE		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x033)
+#define  HFI_PROPERTY_PARAM_VENC_IFRAMESIZE			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x034)
+
+#define HFI_PROPERTY_CONFIG_VENC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
+#define  HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE                \
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+#define  HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER	\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
+#define  HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009)
+#define  HFI_PROPERTY_CONFIG_VENC_USELTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A)
+#define  HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER		\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B)
+#define  HFI_PROPERTY_CONFIG_VENC_LTRPERIOD			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00C)
+#define  HFI_PROPERTY_CONFIG_VENC_PERF_MODE			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00E)
+#define HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID		\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00F)
+
+#define HFI_PROPERTY_CONFIG_VPE_COMMON_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
+#define  HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE		\
+	(HFI_PROPERTY_CONFIG_COMMON_START + 0x010)
+#define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE				\
+	(HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS				\
+	(HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
+
+struct hfi_pic_struct {
+	u32 progressive_only;
+};
+
+struct hfi_bitrate {
+	u32 bit_rate;
+	u32 layer_id;
+};
+
+struct hfi_colour_space {
+	u32 colour_space;
+};
+
+#define HFI_CAPABILITY_FRAME_WIDTH			(HFI_COMMON_BASE + 0x1)
+#define HFI_CAPABILITY_FRAME_HEIGHT			(HFI_COMMON_BASE + 0x2)
+#define HFI_CAPABILITY_MBS_PER_FRAME			(HFI_COMMON_BASE + 0x3)
+#define HFI_CAPABILITY_MBS_PER_SECOND			(HFI_COMMON_BASE + 0x4)
+#define HFI_CAPABILITY_FRAMERATE			(HFI_COMMON_BASE + 0x5)
+#define HFI_CAPABILITY_SCALE_X				(HFI_COMMON_BASE + 0x6)
+#define HFI_CAPABILITY_SCALE_Y				(HFI_COMMON_BASE + 0x7)
+#define HFI_CAPABILITY_BITRATE				(HFI_COMMON_BASE + 0x8)
+#define HFI_CAPABILITY_BFRAME				(HFI_COMMON_BASE + 0x9)
+#define HFI_CAPABILITY_PEAKBITRATE			(HFI_COMMON_BASE + 0xa)
+#define HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS		(HFI_COMMON_BASE + 0x10)
+#define HFI_CAPABILITY_ENC_LTR_COUNT			(HFI_COMMON_BASE + 0x11)
+#define HFI_CAPABILITY_CP_OUTPUT2_THRESH		(HFI_COMMON_BASE + 0x12)
+#define HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS	(HFI_COMMON_BASE + 0x13)
+#define HFI_CAPABILITY_LCU_SIZE				(HFI_COMMON_BASE + 0x14)
+#define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS	(HFI_COMMON_BASE + 0x15)
+#define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE		(HFI_COMMON_BASE + 0x16)
+
+struct hfi_capability_supported {
+	u32 capability_type;
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+struct hfi_capability_supported_info {
+	u32 num_capabilities;
+	struct hfi_capability_supported rg_data[1];
+};
+
+#define HFI_DEBUG_MSG_LOW					0x00000001
+#define HFI_DEBUG_MSG_MEDIUM					0x00000002
+#define HFI_DEBUG_MSG_HIGH					0x00000004
+#define HFI_DEBUG_MSG_ERROR					0x00000008
+#define HFI_DEBUG_MSG_FATAL					0x00000010
+#define HFI_DEBUG_MSG_PERF					0x00000020
+
+#define HFI_DEBUG_MODE_QUEUE					0x00000001
+#define HFI_DEBUG_MODE_QDSS					0x00000002
+
+struct hfi_debug_config {
+	u32 debug_config;
+	u32 debug_mode;
+};
+
+struct hfi_enable {
+	u32 enable;
+};
+
+#define HFI_H264_DB_MODE_DISABLE			(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY	\
+	(HFI_COMMON_BASE + 0x2)
+#define HFI_H264_DB_MODE_ALL_BOUNDARY		(HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_db_control {
+	u32 mode;
+	u32 slice_alpha_offset;
+	u32 slice_beta_offset;
+};
+
+#define HFI_H264_ENTROPY_CAVLC				(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_ENTROPY_CABAC				(HFI_COMMON_BASE + 0x2)
+
+#define HFI_H264_CABAC_MODEL_0				(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_CABAC_MODEL_1				(HFI_COMMON_BASE + 0x2)
+#define HFI_H264_CABAC_MODEL_2				(HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_entropy_control {
+	u32 entropy_mode;
+	u32 cabac_model;
+};
+
+struct hfi_frame_rate {
+	u32 buffer_type;
+	u32 frame_rate;
+};
+
+#define HFI_INTRA_REFRESH_NONE				(HFI_COMMON_BASE + 0x1)
+#define HFI_INTRA_REFRESH_CYCLIC			(HFI_COMMON_BASE + 0x2)
+#define HFI_INTRA_REFRESH_ADAPTIVE			(HFI_COMMON_BASE + 0x3)
+#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE	(HFI_COMMON_BASE + 0x4)
+#define HFI_INTRA_REFRESH_RANDOM			(HFI_COMMON_BASE + 0x5)
+
+struct hfi_intra_refresh {
+	u32 mode;
+	u32 air_mbs;
+	u32 air_ref;
+	u32 cir_mbs;
+};
+
+struct hfi_3x_intra_refresh {
+	u32 mode;
+	u32 mbs;
+};
+
+struct hfi_idr_period {
+	u32 idr_period;
+};
+
+struct hfi_operations_type {
+	u32 rotation;
+	u32 flip;
+};
+
+struct hfi_max_num_b_frames {
+	u32 max_num_b_frames;
+};
+
+struct hfi_vc1e_perf_cfg_type {
+	u32 search_range_x_subsampled[3];
+	u32 search_range_y_subsampled[3];
+};
+
+struct hfi_conceal_color {
+	u32 conceal_color;
+};
+
+struct hfi_intra_period {
+	u32 pframes;
+	u32 bframes;
+};
+
+struct hfi_mpeg4_header_extension {
+	u32 header_extension;
+};
+
+struct hfi_mpeg4_time_resolution {
+	u32 time_increment_resolution;
+};
+
+struct hfi_multi_stream {
+	u32 buffer_type;
+	u32 enable;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_3x_multi_stream {
+	u32 buffer_type;
+	u32 enable;
+};
+
+struct hfi_multi_view_format {
+	u32 views;
+	u32 rg_view_order[1];
+};
+
+#define HFI_MULTI_SLICE_OFF				(HFI_COMMON_BASE + 0x1)
+#define HFI_MULTI_SLICE_BY_MB_COUNT		(HFI_COMMON_BASE + 0x2)
+#define HFI_MULTI_SLICE_BY_BYTE_COUNT	(HFI_COMMON_BASE + 0x3)
+#define HFI_MULTI_SLICE_GOB				(HFI_COMMON_BASE + 0x4)
+
+struct hfi_multi_slice_control {
+	u32 multi_slice;
+	u32 slice_size;
+};
+
+#define HFI_NAL_FORMAT_STARTCODES			0x00000001
+#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER	0x00000002
+#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH		0x00000004
+#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH		0x00000008
+#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH		0x00000010
+
+struct hfi_nal_stream_format_supported {
+	u32 nal_stream_format_supported;
+};
+
+struct hfi_nal_stream_format_select {
+	u32 nal_stream_format_select;
+};
+#define HFI_PICTURE_TYPE_I					0x01
+#define HFI_PICTURE_TYPE_P					0x02
+#define HFI_PICTURE_TYPE_B					0x04
+#define HFI_PICTURE_TYPE_IDR					0x08
+#define HFI_PICTURE_TYPE_CRA					0x10
+
+struct hfi_profile_level {
+	u32 profile;
+	u32 level;
+};
+
+struct hfi_profile_level_supported {
+	u32 profile_count;
+	struct hfi_profile_level rg_profile_level[1];
+};
+
+struct hfi_quality_vs_speed {
+	u32 quality_vs_speed;
+};
+
+struct hfi_quantization {
+	u32 qp_i;
+	u32 qp_p;
+	u32 qp_b;
+	u32 layer_id;
+};
+
+struct hfi_initial_quantization {
+	u32 qp_i;
+	u32 qp_p;
+	u32 qp_b;
+	u32 init_qp_enable;
+};
+
+struct hfi_quantization_range {
+	u32 min_qp;
+	u32 max_qp;
+	u32 layer_id;
+};
+
+#define HFI_LTR_MODE_DISABLE	0x0
+#define HFI_LTR_MODE_MANUAL		0x1
+#define HFI_LTR_MODE_PERIODIC	0x2
+
+struct hfi_ltr_mode {
+	u32 ltr_mode;
+	u32 ltr_count;
+	u32 trust_mode;
+};
+
+struct hfi_ltr_use {
+	u32 ref_ltr;
+	u32 use_constrnt;
+	u32 frames;
+};
+
+struct hfi_ltr_mark {
+	u32 mark_frame;
+};
+
+struct hfi_frame_size {
+	u32 buffer_type;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_video_signal_metadata {
+	u32 enable;
+	u32 video_format;
+	u32 video_full_range;
+	u32 color_description;
+	u32 color_primaries;
+	u32 transfer_characteristics;
+	u32 matrix_coeffs;
+};
+
+struct hfi_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
+struct hfi_bit_depth {
+	u32 buffer_type;
+	u32 bit_depth;
+};
+
+struct hfi_picture_type {
+	u32 is_sync_frame;
+	u32 picture_type;
+};
+
+/* Base Offset for UBWC color formats  */
+#define HFI_COLOR_FORMAT_UBWC_BASE        (0x8000)
+/* Base Offset for 10-bit color formats */
+#define HFI_COLOR_FORMAT_10_BIT_BASE      (0x4000)
+
+#define HFI_COLOR_FORMAT_MONOCHROME			(HFI_COMMON_BASE + 0x1)
+#define HFI_COLOR_FORMAT_NV12				(HFI_COMMON_BASE + 0x2)
+#define HFI_COLOR_FORMAT_NV21				(HFI_COMMON_BASE + 0x3)
+#define HFI_COLOR_FORMAT_NV12_4x4TILE		(HFI_COMMON_BASE + 0x4)
+#define HFI_COLOR_FORMAT_NV21_4x4TILE		(HFI_COMMON_BASE + 0x5)
+#define HFI_COLOR_FORMAT_YUYV				(HFI_COMMON_BASE + 0x6)
+#define HFI_COLOR_FORMAT_YVYU				(HFI_COMMON_BASE + 0x7)
+#define HFI_COLOR_FORMAT_UYVY				(HFI_COMMON_BASE + 0x8)
+#define HFI_COLOR_FORMAT_VYUY				(HFI_COMMON_BASE + 0x9)
+#define HFI_COLOR_FORMAT_RGB565				(HFI_COMMON_BASE + 0xA)
+#define HFI_COLOR_FORMAT_BGR565				(HFI_COMMON_BASE + 0xB)
+#define HFI_COLOR_FORMAT_RGB888				(HFI_COMMON_BASE + 0xC)
+#define HFI_COLOR_FORMAT_BGR888				(HFI_COMMON_BASE + 0xD)
+#define HFI_COLOR_FORMAT_YUV444				(HFI_COMMON_BASE + 0xE)
+#define HFI_COLOR_FORMAT_RGBA8888			(HFI_COMMON_BASE + 0x10)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10					\
+		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_NV12_UBWC					\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC				\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_YUV420_TP10)
+
+#define  HFI_COLOR_FORMAT_RGBA8888_UBWC					\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_RGBA8888)
+
+#define HFI_MAX_MATRIX_COEFFS 9
+#define HFI_MAX_BIAS_COEFFS 3
+#define HFI_MAX_LIMIT_COEFFS 6
+
+#define HFI_STATISTICS_MODE_DEFAULT 0x10
+#define HFI_STATISTICS_MODE_1 0x11
+#define HFI_STATISTICS_MODE_2 0x12
+#define HFI_STATISTICS_MODE_3 0x13
+
+struct hfi_uncompressed_format_select {
+	u32 buffer_type;
+	u32 format;
+};
+
+struct hfi_uncompressed_format_supported {
+	u32 buffer_type;
+	u32 format_entries;
+	u32 rg_format_info[1];
+};
+
+struct hfi_uncompressed_plane_actual {
+	u32 actual_stride;
+	u32 actual_plane_buffer_height;
+};
+
+struct hfi_uncompressed_plane_actual_info {
+	u32 buffer_type;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_constraints {
+	u32 stride_multiples;
+	u32 max_stride;
+	u32 min_plane_buffer_height_multiple;
+	u32 buffer_alignment;
+};
+
+struct hfi_uncompressed_plane_info {
+	u32 format;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_codec_supported {
+	u32 decoder_codec_supported;
+	u32 encoder_codec_supported;
+};
+
+struct hfi_properties_supported {
+	u32 num_properties;
+	u32 rg_properties[1];
+};
+
+struct hfi_max_sessions_supported {
+	u32 max_sessions;
+};
+
+struct hfi_vpe_color_space_conversion {
+	u32 csc_matrix[HFI_MAX_MATRIX_COEFFS];
+	u32 csc_bias[HFI_MAX_BIAS_COEFFS];
+	u32 csc_limit[HFI_MAX_LIMIT_COEFFS];
+};
+
+struct hfi_scs_threshold {
+	u32 threshold_value;
+};
+
+#define HFI_ROTATE_NONE					(HFI_COMMON_BASE + 0x1)
+#define HFI_ROTATE_90					(HFI_COMMON_BASE + 0x2)
+#define HFI_ROTATE_180					(HFI_COMMON_BASE + 0x3)
+#define HFI_ROTATE_270					(HFI_COMMON_BASE + 0x4)
+
+#define HFI_FLIP_NONE					(HFI_COMMON_BASE + 0x1)
+#define HFI_FLIP_HORIZONTAL				(HFI_COMMON_BASE + 0x2)
+#define HFI_FLIP_VERTICAL				(HFI_COMMON_BASE + 0x3)
+
+struct hfi_operations {
+	u32 rotate;
+	u32 flip;
+};
+
+#define HFI_RESOURCE_OCMEM 0x00000001
+
+struct hfi_resource_ocmem {
+	u32 size;
+	u32 mem;
+};
+
+struct hfi_resource_ocmem_requirement {
+	u32 session_domain;
+	u32 width;
+	u32 height;
+	u32 size;
+};
+
+struct hfi_resource_ocmem_requirement_info {
+	u32 num_entries;
+	struct hfi_resource_ocmem_requirement rg_requirements[1];
+};
+
+struct hfi_property_sys_image_version_info_type {
+	u32 string_size;
+	u8  str_image_version[1];
+};
+
+struct hfi_venc_config_advanced {
+	u8 pipe2d;
+	u8 hw_mode;
+	u8 low_delay_enforce;
+	u8 worker_vppsg_delay;
+	u32 close_gop;
+	u32 h264_constrain_intra_pred;
+	u32 h264_transform_8x8_flag;
+	u32 mpeg4_qpel_enable;
+	u32 multi_refp_en;
+	u32 qmatrix_en;
+	u8 vpp_info_packet_mode;
+	u8 ref_tile_mode;
+	u8 bitstream_flush_mode;
+	u32 vppsg_vspap_fb_sync_delay;
+	u32 rc_initial_delay;
+	u32 peak_bitrate_constraint;
+	u32 ds_display_frame_width;
+	u32 ds_display_frame_height;
+	u32 perf_tune_param_ptr;
+	u32 input_x_offset;
+	u32 input_y_offset;
+	u32 input_roi_width;
+	u32 input_roi_height;
+	u32 vsp_fifo_dma_sel;
+	u32 h264_num_ref_frames;
+};
+
+struct hfi_vbv_hrd_bufsize {
+	u32 buffer_size;
+};
+
+struct hfi_codec_mask_supported {
+	u32 codecs;
+	u32 video_domains;
+};
+
+struct hfi_seq_header_info {
+	u32 max_hader_len;
+};
+
+struct hfi_aspect_ratio {
+	u32 aspect_width;
+	u32 aspect_height;
+};
+
+#define HFI_IFRAME_SIZE_DEFAULT			(HFI_COMMON_BASE + 0x1)
+#define HFI_IFRAME_SIZE_MEDIUM			(HFI_COMMON_BASE + 0x2)
+#define HFI_IFRAME_SIZE_HIGH			(HFI_COMMON_BASE + 0x3)
+#define HFI_IFRAME_SIZE_UNLIMITED		(HFI_COMMON_BASE + 0x4)
+struct hfi_iframe_size {
+	u32 type;
+};
+
+#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM  (0)
+#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE  (1)
+#define HFI_MVC_BUFFER_LAYOUT_SEQ         (2)
+struct hfi_mvc_buffer_layout_descp_type {
+	u32    layout_type;
+	u32    bright_view_first;
+	u32    ngap;
+};
+
+
+#define HFI_CMD_SYS_COMMON_START			\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
+	+ 0x0000)
+#define HFI_CMD_SYS_INIT		(HFI_CMD_SYS_COMMON_START + 0x001)
+#define HFI_CMD_SYS_PC_PREP		(HFI_CMD_SYS_COMMON_START + 0x002)
+#define HFI_CMD_SYS_SET_RESOURCE	(HFI_CMD_SYS_COMMON_START + 0x003)
+#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004)
+#define HFI_CMD_SYS_SET_PROPERTY	(HFI_CMD_SYS_COMMON_START + 0x005)
+#define HFI_CMD_SYS_GET_PROPERTY	(HFI_CMD_SYS_COMMON_START + 0x006)
+#define HFI_CMD_SYS_SESSION_INIT	(HFI_CMD_SYS_COMMON_START + 0x007)
+#define HFI_CMD_SYS_SESSION_END		(HFI_CMD_SYS_COMMON_START + 0x008)
+#define HFI_CMD_SYS_SET_BUFFERS		(HFI_CMD_SYS_COMMON_START + 0x009)
+#define HFI_CMD_SYS_TEST_START		(HFI_CMD_SYS_COMMON_START + 0x100)
+
+#define HFI_CMD_SESSION_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_SET_PROPERTY		\
+	(HFI_CMD_SESSION_COMMON_START + 0x001)
+#define HFI_CMD_SESSION_SET_BUFFERS			\
+	(HFI_CMD_SESSION_COMMON_START + 0x002)
+#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER	\
+	(HFI_CMD_SESSION_COMMON_START + 0x003)
+
+#define HFI_MSG_SYS_COMMON_START			\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_INIT_DONE			(HFI_MSG_SYS_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE		(HFI_MSG_SYS_COMMON_START + 0x2)
+#define HFI_MSG_SYS_RELEASE_RESOURCE	(HFI_MSG_SYS_COMMON_START + 0x3)
+#define HFI_MSG_SYS_DEBUG			(HFI_MSG_SYS_COMMON_START + 0x4)
+#define HFI_MSG_SYS_SESSION_INIT_DONE	(HFI_MSG_SYS_COMMON_START + 0x6)
+#define HFI_MSG_SYS_SESSION_END_DONE	(HFI_MSG_SYS_COMMON_START + 0x7)
+#define HFI_MSG_SYS_IDLE		(HFI_MSG_SYS_COMMON_START + 0x8)
+#define HFI_MSG_SYS_COV                 (HFI_MSG_SYS_COMMON_START + 0x9)
+#define HFI_MSG_SYS_PROPERTY_INFO	(HFI_MSG_SYS_COMMON_START + 0xA)
+#define HFI_MSG_SESSION_SYNC_DONE      (HFI_MSG_SESSION_OX_START + 0xD)
+
+#define HFI_MSG_SESSION_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_EVENT_NOTIFY	(HFI_MSG_SESSION_COMMON_START + 0x1)
+#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE	\
+	(HFI_MSG_SESSION_COMMON_START + 0x2)
+
+#define HFI_CMD_SYS_TEST_SSR	(HFI_CMD_SYS_TEST_START + 0x1)
+#define HFI_TEST_SSR_SW_ERR_FATAL	0x1
+#define HFI_TEST_SSR_SW_DIV_BY_ZERO	0x2
+#define HFI_TEST_SSR_HW_WDOG_IRQ	0x3
+
+struct vidc_hal_cmd_pkt_hdr {
+	u32 size;
+	u32 packet_type;
+};
+
+struct vidc_hal_msg_pkt_hdr {
+	u32 size;
+	u32 packet;
+};
+
+struct vidc_hal_session_cmd_pkt {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_init_packet {
+	u32 size;
+	u32 packet_type;
+	u32 arch_type;
+};
+
+struct hfi_cmd_sys_pc_prep_packet {
+	u32 size;
+	u32 packet_type;
+};
+
+struct hfi_cmd_sys_set_resource_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_handle;
+	u32 resource_type;
+	u32 rg_resource_data[1];
+};
+
+struct hfi_cmd_sys_release_resource_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_type;
+	u32 resource_handle;
+};
+
+struct hfi_cmd_sys_set_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_session_init_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 session_domain;
+	u32 session_codec;
+};
+
+struct hfi_cmd_sys_session_end_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_set_buffers_packet {
+	u32 size;
+	u32 packet_type;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 num_buffers;
+	u32 rg_buffer_addr[1];
+};
+
+struct hfi_cmd_session_set_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[0];
+};
+
+struct hfi_cmd_session_set_buffers_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 extra_data_size;
+	u32 min_buffer_size;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_get_sequence_header_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_len;
+	u32 packet_buffer;
+};
+
+struct hfi_cmd_session_sync_process_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 sync_id;
+	u32 rg_data[1];
+};
+
+struct hfi_msg_event_notify_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 event_id;
+	u32 event_data1;
+	u32 event_data2;
+	u32 rg_ext_event_data[1];
+};
+
+struct hfi_msg_release_buffer_ref_event_packet {
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 output_tag;
+};
+
+struct hfi_msg_sys_init_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_pc_prep_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_release_resource_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_handle;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_session_init_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_end_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_get_sequence_header_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 header_len;
+	u32 sequence_header;
+};
+
+struct hfi_msg_sys_debug_packet {
+	u32 size;
+	u32 packet_type;
+	u32 msg_type;
+	u32 msg_size;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u8 rg_msg_data[1];
+};
+
+struct hfi_msg_sys_coverage_packet {
+	u32 size;
+	u32 packet_type;
+	u32 msg_size;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u8 rg_msg_data[1];
+};
+
+enum HFI_VENUS_QTBL_STATUS {
+	HFI_VENUS_QTBL_DISABLED = 0x00,
+	HFI_VENUS_QTBL_ENABLED = 0x01,
+	HFI_VENUS_QTBL_INITIALIZING = 0x02,
+	HFI_VENUS_QTBL_DEINITIALIZING = 0x03
+};
+
+enum HFI_VENUS_CTRL_INIT_STATUS {
+	HFI_VENUS_CTRL_NOT_INIT = 0x0,
+	HFI_VENUS_CTRL_READY = 0x1,
+	HFI_VENUS_CTRL_ERROR_FATAL = 0x2
+};
+
+struct hfi_sfr_struct {
+	u32 bufSize;
+	u8 rg_data[1];
+};
+
+struct hfi_cmd_sys_test_ssr_packet {
+	u32 size;
+	u32 packet_type;
+	u32 trigger_type;
+};
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h
new file mode 100644
index 0000000..75f44ec
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h
@@ -0,0 +1,195 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __VIDC_HFI_IO_H__
+#define __VIDC_HFI_IO_H__
+
+#include <linux/io.h>
+
+#define VENUS_VCODEC_SS_CLOCK_HALT     0x0000000C
+#define VENUS_VPP_CORE_SW_RESET        0x00042004
+#define VENUS_VPP_CTRL_CTRL_RESET      0x00041008
+
+#define VIDC_VBIF_BASE_OFFS			0x00080000
+#define VIDC_VBIF_VERSION			(VIDC_VBIF_BASE_OFFS + 0x00)
+#define VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB		\
+			(VIDC_VBIF_BASE_OFFS + 0x124)
+
+#define VIDC_CPU_BASE_OFFS			0x000C0000
+#define VIDC_CPU_CS_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x00012000)
+#define VIDC_CPU_IC_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x0001F000)
+
+#define VIDC_CPU_CS_REMAP_OFFS		(VIDC_CPU_CS_BASE_OFFS + 0x00)
+#define VIDC_CPU_CS_TIMER_CONTROL	(VIDC_CPU_CS_BASE_OFFS + 0x04)
+#define VIDC_CPU_CS_A2HSOFTINTEN	(VIDC_CPU_CS_BASE_OFFS + 0x10)
+#define VIDC_CPU_CS_A2HSOFTINTENCLR	(VIDC_CPU_CS_BASE_OFFS + 0x14)
+#define VIDC_CPU_CS_A2HSOFTINT		(VIDC_CPU_CS_BASE_OFFS + 0x18)
+#define VIDC_CPU_CS_A2HSOFTINTCLR	(VIDC_CPU_CS_BASE_OFFS + 0x1C)
+#define VIDC_CPU_CS_SCIACMD			(VIDC_CPU_CS_BASE_OFFS + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define VIDC_CPU_CS_SCIACMDARG0		(VIDC_CPU_CS_BASE_OFFS + 0x4C)
+#define VIDC_CPU_CS_SCIACMDARG0_BMSK	0xff
+#define VIDC_CPU_CS_SCIACMDARG0_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK	0xfe
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT	0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK	0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY           0x100
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK     0x40000000
+
+/* HFI_QTBL_INFO */
+#define VIDC_CPU_CS_SCIACMDARG1		(VIDC_CPU_CS_BASE_OFFS + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define VIDC_CPU_CS_SCIACMDARG2		(VIDC_CPU_CS_BASE_OFFS + 0x54)
+
+/* HFI_VERSION_INFO */
+#define VIDC_CPU_CS_SCIACMDARG3		(VIDC_CPU_CS_BASE_OFFS + 0x58)
+#define VIDC_CPU_IC_IRQSTATUS		(VIDC_CPU_IC_BASE_OFFS + 0x00)
+#define VIDC_CPU_IC_FIQSTATUS		(VIDC_CPU_IC_BASE_OFFS + 0x04)
+#define VIDC_CPU_IC_RAWINTR			(VIDC_CPU_IC_BASE_OFFS + 0x08)
+#define VIDC_CPU_IC_INTSELECT		(VIDC_CPU_IC_BASE_OFFS + 0x0C)
+#define VIDC_CPU_IC_INTENABLE		(VIDC_CPU_IC_BASE_OFFS + 0x10)
+#define VIDC_CPU_IC_INTENACLEAR		(VIDC_CPU_IC_BASE_OFFS + 0x14)
+#define VIDC_CPU_IC_SOFTINT			(VIDC_CPU_IC_BASE_OFFS + 0x18)
+#define VIDC_CPU_IC_SOFTINT_H2A_BMSK	0x8000
+#define VIDC_CPU_IC_SOFTINT_H2A_SHFT	0xF
+#define VIDC_CPU_IC_SOFTINTCLEAR	(VIDC_CPU_IC_BASE_OFFS + 0x1C)
+
+/*---------------------------------------------------------------------------
+ * MODULE: vidc_wrapper
+ *--------------------------------------------------------------------------
+ */
+#define VIDC_WRAPPER_BASE_OFFS		0x000E0000
+
+#define VIDC_WRAPPER_HW_VERSION		(VIDC_WRAPPER_BASE_OFFS + 0x00)
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK  0x78000000
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK  0xFFF0000
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16
+#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK   0xFFFF
+#define VIDC_WRAPPER_CLOCK_CONFIG	(VIDC_WRAPPER_BASE_OFFS + 0x04)
+
+#define VIDC_WRAPPER_INTR_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x0C)
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK	0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT	0x2
+
+#define VIDC_WRAPPER_INTR_MASK		(VIDC_WRAPPER_BASE_OFFS + 0x10)
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK	0x8
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT	0x3
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK	0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT	0x2
+
+#define VIDC_WRAPPER_INTR_CLEAR		(VIDC_WRAPPER_BASE_OFFS + 0x14)
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK	0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT	0x2
+
+#define VIDC_WRAPPER_VBIF_XIN_SW_RESET	(VIDC_WRAPPER_BASE_OFFS + 0x18)
+#define VIDC_WRAPPER_VBIF_XIN_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x1C)
+#define VIDC_WRAPPER_CPU_CLOCK_CONFIG	(VIDC_WRAPPER_BASE_OFFS + 0x2000)
+#define VIDC_WRAPPER_VBIF_XIN_CPU_SW_RESET	\
+				(VIDC_WRAPPER_BASE_OFFS + 0x2004)
+#define VIDC_WRAPPER_AXI_HALT		(VIDC_WRAPPER_BASE_OFFS + 0x2008)
+#define VIDC_WRAPPER_AXI_HALT_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x200C)
+#define VIDC_WRAPPER_CPU_CGC_DIS	(VIDC_WRAPPER_BASE_OFFS + 0x2010)
+#define VIDC_WRAPPER_CPU_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x2014)
+#define VIDC_VENUS_VBIF_CLK_ON		(VIDC_VBIF_BASE_OFFS + 0x4)
+#define VIDC_VBIF_IN_RD_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xB0)
+#define VIDC_VBIF_IN_RD_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xB4)
+#define VIDC_VBIF_IN_RD_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xB8)
+#define VIDC_VBIF_IN_RD_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xBC)
+#define VIDC_VBIF_IN_WR_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xC0)
+#define VIDC_VBIF_IN_WR_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xC4)
+#define VIDC_VBIF_IN_WR_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xC8)
+#define VIDC_VBIF_IN_WR_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xCC)
+#define VIDC_VBIF_OUT_RD_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD0)
+#define VIDC_VBIF_OUT_WR_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD4)
+#define VIDC_VBIF_DDR_OUT_MAX_BURST     (VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VBIF_OCMEM_OUT_MAX_BURST   (VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VBIF_DDR_ARB_CONF0         (VIDC_VBIF_BASE_OFFS + 0xF4)
+#define VIDC_VBIF_DDR_ARB_CONF1         (VIDC_VBIF_BASE_OFFS + 0xF8)
+#define VIDC_VBIF_ROUND_ROBIN_QOS_ARB   (VIDC_VBIF_BASE_OFFS + 0x124)
+#define VIDC_VBIF_OUT_AXI_AOOO_EN       (VIDC_VBIF_BASE_OFFS + 0x178)
+#define VIDC_VBIF_OUT_AXI_AOOO          (VIDC_VBIF_BASE_OFFS + 0x17C)
+#define VIDC_VBIF_ARB_CTL               (VIDC_VBIF_BASE_OFFS + 0xF0)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF0 (VIDC_VBIF_BASE_OFFS + 0x160)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF1 (VIDC_VBIF_BASE_OFFS + 0x164)
+#define VIDC_VBIF_ADDR_TRANS_EN         (VIDC_VBIF_BASE_OFFS + 0xC00)
+#define VIDC_VBIF_AT_OLD_BASE           (VIDC_VBIF_BASE_OFFS + 0xC04)
+#define VIDC_VBIF_AT_OLD_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC08)
+#define VIDC_VBIF_AT_NEW_BASE           (VIDC_VBIF_BASE_OFFS + 0xC10)
+#define VIDC_VBIF_AT_NEW_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC18)
+#define VENUS_VBIF_XIN_HALT_CTRL1   (VIDC_VBIF_BASE_OFFS + 0x204)
+#define VENUS_VBIF_AXI_HALT_CTRL0   (VIDC_VBIF_BASE_OFFS + 0x208)
+#define VENUS_VBIF_AXI_HALT_CTRL1   (VIDC_VBIF_BASE_OFFS + 0x20C)
+
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ		BIT(0)
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK		BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US		500000
+
+#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
+	(VIDC_WRAPPER_BASE_OFFS + 0x20)
+#define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
+	(VIDC_WRAPPER_BASE_OFFS + 0x24)
+#define VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS \
+	(VIDC_WRAPPER_BASE_OFFS + 0x44)
+
+#define VIDC_CTRL_INIT 0x000D2048
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__M 0xFFFFFFFE
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__S 1
+#define VIDC_CTRL_INIT_CTRL__M 0x00000001
+#define VIDC_CTRL_INIT_CTRL__S 0
+
+#define VIDC_CTRL_STATUS 0x000D204C
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__M 0xFFFFFF00
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__S 8
+#define VIDC_CTRL_ERROR_STATUS__M             0x000000FE
+#define VIDC_CTRL_ERROR_STATUS__S             1
+#define VIDC_CTRL_INIT_STATUS__M              0x00000001
+#define VIDC_CTRL_INIT_STATUS__S              0
+
+#define VIDC_QTBL_INFO 0x000D2050
+#define VIDC_QTBL_HOSTID__M 0xFF000000
+#define VIDC_QTBL_HOSTID__S 24
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__M 0x00FFFF00
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__S 8
+#define VIDC_QTBL_STATUS__M 0x000000FF
+#define VIDC_QTBL_STATUS__S 0
+
+#define VIDC_QTBL_ADDR 0x000D2054
+
+#define VIDC_VERSION_INFO 0x000D2058
+#define VIDC_VERSION_INFO_MAJOR__M  0xF0000000
+#define VIDC_VERSION_INFO_MAJOR__S  28
+#define VIDC_VERSION_INFO_MINOR__M  0x0FFFFFE0
+#define VIDC_VERSION_INFO_MINOR__S  5
+#define VIDC_VERSION_INFO_BRANCH__M 0x0000001F
+#define VIDC_VERSION_INFO_BRANCH__S 0
+
+#define VIDC_SFR_ADDR 0x000D205C
+#define VIDC_MMAP_ADDR 0x000D2060
+#define VIDC_UC_REGION_ADDR 0x000D2064
+#define VIDC_UC_REGION_SIZE 0x000D2068
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/Kconfig b/drivers/media/platform/msm/vidc_3x/vmem/Kconfig
new file mode 100644
index 0000000..26a609e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/Kconfig
@@ -0,0 +1,3 @@
+menuconfig MSM_VIDC_VMEM
+	bool "Qualcomm Technologies Inc MSM VMEM driver"
+	depends on ARCH_MSM && MSM_VIDC_V4L2
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/Makefile b/drivers/media/platform/msm/vidc_3x/vmem/Makefile
new file mode 100644
index 0000000..713b92e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MSM_VIDC_VMEM) := vmem.o \
+				vmem_debugfs.o
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem.c b/drivers/media/platform/msm/vidc_3x/vmem/vmem.c
new file mode 100644
index 0000000..f4f8977
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem.c
@@ -0,0 +1,698 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msm-bus.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "vmem.h"
+#include "vmem_debugfs.h"
+
+/* Registers */
+#define OCIMEM_BASE(v)               ((uint8_t *)(v)->reg.base)
+#define OCIMEM_HW_VERSION(v)         (OCIMEM_BASE(v) + 0x00)
+#define OCIMEM_HW_PROFILE(v)         (OCIMEM_BASE(v) + 0x04)
+#define OCIMEM_GEN_CTL(v)            (OCIMEM_BASE(v) + 0x08)
+#define OCIMEM_GEN_STAT(v)           (OCIMEM_BASE(v) + 0x0C)
+#define OCIMEM_INTC_CLR(v)           (OCIMEM_BASE(v) + 0x10)
+#define OCIMEM_INTC_MASK(v)          (OCIMEM_BASE(v) + 0x14)
+#define OCIMEM_INTC_STAT(v)          (OCIMEM_BASE(v) + 0x18)
+#define OCIMEM_OSW_STATUS(v)         (OCIMEM_BASE(v) + 0x1C)
+#define OCIMEM_PSCGC_TIMERS(v)       (OCIMEM_BASE(v) + 0x34)
+#define OCIMEM_PSCGC_STAT(v)         (OCIMEM_BASE(v) + 0x38)
+#define OCIMEM_PSCGC_M0_M7_CTL(v)    (OCIMEM_BASE(v) + 0x3C)
+#define OCIMEM_ERR_ADDRESS(v)        (OCIMEM_BASE(v) + 0x60)
+#define OCIMEM_AXI_ERR_SYNDROME(v)   (OCIMEM_BASE(v) + 0x64)
+#define OCIMEM_DEBUG_CTL(v)          (OCIMEM_BASE(v) + 0x68)
+
+/*
+ * Helper macro to help out with masks and shifts for values packed into
+ * registers.
+ */
+#define DECLARE_TYPE(__type, __end, __start)                                   \
+	static const unsigned int __type##_BITS = (__end) - (__start) + 1;     \
+	static const unsigned int __type##_SHIFT = (__start);                  \
+	static const unsigned int __type##_MASK = GENMASK((__end), (__start)); \
+	static inline unsigned int __type(uint32_t val)                        \
+	{                                                                      \
+		return (val & __type##_MASK) >> __type##_SHIFT;                \
+	}                                                                      \
+	static inline uint32_t __type##_UPDATE(unsigned int val)               \
+	{                                                                      \
+		return (val << __type##_SHIFT) & __type##_MASK;                \
+	}
+
+/* Register masks */
+/* OCIMEM_PSCGC_M0_M7_CTL */
+DECLARE_TYPE(BANK0_STATE, 3, 0);
+DECLARE_TYPE(BANK1_STATE, 7, 4);
+DECLARE_TYPE(BANK2_STATE, 11, 8);
+DECLARE_TYPE(BANK3_STATE, 15, 12);
+/* OCIMEM_PSCGC_TIMERS */
+DECLARE_TYPE(TIMERS_WAKEUP, 3, 0);
+DECLARE_TYPE(TIMERS_SLEEP, 11, 8);
+/* OCIMEM_HW_VERSION */
+DECLARE_TYPE(VERSION_STEP, 15, 0);
+DECLARE_TYPE(VERSION_MINOR, 27, 16);
+DECLARE_TYPE(VERSION_MAJOR, 31, 28);
+/* OCIMEM_HW_PROFILE */
+DECLARE_TYPE(PROFILE_BANKS, 16, 12);
+/* OCIMEM_AXI_ERR_SYNDROME */
+DECLARE_TYPE(ERR_SYN_ATID, 14, 8);
+DECLARE_TYPE(ERR_SYN_AMID, 23, 16);
+DECLARE_TYPE(ERR_SYN_APID, 28, 24);
+DECLARE_TYPE(ERR_SYN_ABID, 31, 29);
+/* OCIMEM_INTC_MASK */
+DECLARE_TYPE(AXI_ERR_INT, 0, 0);
+
+/* Internal stuff */
+#define MAX_BANKS 4
+
+enum bank_state {
+	BANK_STATE_NORM_PASSTHRU = 0,
+	BANK_STATE_NORM_FORCE_CORE_ON = 2,
+	BANK_STATE_NORM_FORCE_PERIPH_ON = 1,
+	BANK_STATE_NORM_FORCE_ALL_ON = 3,
+	BANK_STATE_SLEEP_RET = 6,
+	BANK_STATE_SLEEP_RET_PERIPH_ON = 7,
+	BANK_STATE_SLEEP_NO_RET = 4,
+};
+
+struct vmem {
+	int irq;
+	int num_banks;
+	int bank_size;
+	struct {
+		struct resource *resource;
+		void __iomem *base;
+	} reg, mem;
+	struct regulator *vdd;
+	struct {
+		const char *name;
+		struct clk *clk;
+	} *clocks;
+	int num_clocks;
+	struct {
+		struct msm_bus_scale_pdata *pdata;
+		uint32_t priv;
+	} bus;
+	atomic_t alloc_count;
+	struct dentry *debugfs_root;
+};
+
+static struct vmem *vmem;
+
+static inline u32 __readl(void * __iomem addr)
+{
+	u32 value = 0;
+
+	pr_debug("read %pK ", addr);
+	value = readl_relaxed(addr);
+	pr_debug("-> %08x\n", value);
+
+	return value;
+}
+
+static inline void __writel(u32 val, void * __iomem addr)
+{
+	pr_debug("write %08x -> %pK\n", val, addr);
+	writel_relaxed(val, addr);
+	/*
+	 * Commit all writes via a mem barrier, as subsequent __readl()
+	 * will depend on the state that's set via __writel().
+	 */
+	mb();
+}
+
+static inline void __wait_timer(struct vmem *v, bool wakeup)
+{
+	uint32_t ticks = 0;
+	unsigned int (*timer)(uint32_t) = wakeup ?
+		TIMERS_WAKEUP : TIMERS_SLEEP;
+
+	ticks = timer(__readl(OCIMEM_PSCGC_TIMERS(v)));
+
+	/* Sleep for `ticks` nanoseconds as per h/w spec */
+	ndelay(ticks);
+}
+
+static inline void __wait_wakeup(struct vmem *v)
+{
+	return __wait_timer(v, true);
+}
+
+static inline void __wait_sleep(struct vmem *v)
+{
+	return __wait_timer(v, false);
+}
+
+static inline int __power_on(struct vmem *v)
+{
+	int rc = 0, c = 0;
+
+	rc = msm_bus_scale_client_update_request(v->bus.priv, 1);
+	if (rc) {
+		pr_err("Failed to vote for buses (%d)\n", rc);
+		goto exit;
+	}
+	pr_debug("Voted for buses\n");
+
+	rc = regulator_enable(v->vdd);
+	if (rc) {
+		pr_err("Failed to power on gdsc (%d)", rc);
+		goto unvote_bus;
+	}
+	pr_debug("Enabled regulator vdd\n");
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		rc = clk_prepare_enable(v->clocks[c].clk);
+		if (rc) {
+			pr_err("Failed to enable %s clock (%d)\n",
+					v->clocks[c].name, rc);
+			goto disable_clocks;
+		}
+
+		pr_debug("Enabled clock %s\n", v->clocks[c].name);
+	}
+
+	return 0;
+disable_clocks:
+	for (--c; c >= 0; c--)
+		clk_disable_unprepare(v->clocks[c].clk);
+	regulator_disable(v->vdd);
+unvote_bus:
+	msm_bus_scale_client_update_request(v->bus.priv, 0);
+exit:
+	return rc;
+}
+
+static inline int __power_off(struct vmem *v)
+{
+	int c = 0;
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		clk_disable_unprepare(v->clocks[c].clk);
+		pr_debug("Disabled clock %s\n", v->clocks[c].name);
+	}
+
+	regulator_disable(v->vdd);
+	pr_debug("Disabled regulator vdd\n");
+
+	msm_bus_scale_client_update_request(v->bus.priv, 0);
+	pr_debug("Unvoted for buses\n");
+
+	return 0;
+}
+
+static inline enum bank_state __bank_get_state(struct vmem *v,
+		unsigned int bank)
+{
+	unsigned int (*func[MAX_BANKS])(uint32_t) = {
+		BANK0_STATE, BANK1_STATE, BANK2_STATE, BANK3_STATE
+	};
+
+	WARN_ON(bank >= ARRAY_SIZE(func));
+	return func[bank](__readl(OCIMEM_PSCGC_M0_M7_CTL(v)));
+}
+
+static inline void __bank_set_state(struct vmem *v, unsigned int bank,
+		enum bank_state state)
+{
+	uint32_t bank_state = 0;
+	struct {
+		uint32_t (*update)(unsigned int);
+		uint32_t mask;
+	} banks[MAX_BANKS] = {
+		{BANK0_STATE_UPDATE, BANK0_STATE_MASK},
+		{BANK1_STATE_UPDATE, BANK1_STATE_MASK},
+		{BANK2_STATE_UPDATE, BANK2_STATE_MASK},
+		{BANK3_STATE_UPDATE, BANK3_STATE_MASK},
+	};
+
+	WARN_ON(bank >= ARRAY_SIZE(banks));
+
+	bank_state = __readl(OCIMEM_PSCGC_M0_M7_CTL(v));
+	bank_state &= ~banks[bank].mask;
+	bank_state |= banks[bank].update(state);
+
+	__writel(bank_state, OCIMEM_PSCGC_M0_M7_CTL(v));
+}
+
+static inline void __toggle_interrupts(struct vmem *v, bool enable)
+{
+	uint32_t ints = __readl(OCIMEM_INTC_MASK(v)),
+		mask = AXI_ERR_INT_MASK,
+		update = AXI_ERR_INT_UPDATE(!enable);
+
+	ints &= ~mask;
+	ints |= update;
+
+	__writel(ints, OCIMEM_INTC_MASK(v));
+}
+
+static void __enable_interrupts(struct vmem *v)
+{
+	pr_debug("Enabling interrupts\n");
+	enable_irq(v->irq);
+	__toggle_interrupts(v, true);
+}
+
+static void __disable_interrupts(struct vmem *v)
+{
+	pr_debug("Disabling interrupts\n");
+	__toggle_interrupts(v, false);
+	disable_irq_nosync(v->irq);
+}
+
+/**
+ * vmem_allocate: - Allocates memory from VMEM.  Allocations have a few
+ * restrictions: only allocations of the entire VMEM memory are allowed, and
+ * , as a result, only single outstanding allocations are allowed.
+ *
+ * @size: amount of bytes to allocate
+ * @addr: A pointer to phys_addr_t where the physical address of the memory
+ * allocated is stored.
+ *
+ * Return: 0 in case of successful allocation (i.e. *addr != NULL). -ENOTSUPP,
+ * if platform doesn't support VMEM. -EEXIST, if there are outstanding VMEM
+ * allocations.  -ENOMEM, if platform can't support allocation of `size` bytes.
+ * -EAGAIN, if `size` does not allocate the entire VMEM region.  -EIO in case of
+ * internal errors.
+ */
+int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+	int rc = 0, c = 0;
+	resource_size_t max_size = 0;
+
+	if (!vmem) {
+		pr_err("No vmem, try rebooting your device\n");
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+	if (!size) {
+		pr_err("%s Invalid size %ld\n", __func__, size);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	max_size = resource_size(vmem->mem.resource);
+
+	if (atomic_read(&vmem->alloc_count)) {
+		pr_err("Only single allocations allowed for vmem\n");
+		rc = -EEXIST;
+		goto exit;
+	} else if (size > max_size) {
+		pr_err("Out of memory, have max %pa\n", &max_size);
+		rc = -ENOMEM;
+		goto exit;
+	} else if (size != max_size) {
+		pr_err("Only support allocations of size %pa\n", &max_size);
+		rc = -EAGAIN;
+		goto exit;
+	}
+
+	rc = __power_on(vmem);
+	if (rc) {
+		pr_err("Failed power on (%d)\n", rc);
+		goto exit;
+	}
+
+	WARN_ON(vmem->num_banks != DIV_ROUND_UP(size, vmem->bank_size));
+
+	/* Turn on the necessary banks */
+	for (c = 0; c < vmem->num_banks; ++c) {
+		__bank_set_state(vmem, c, BANK_STATE_NORM_FORCE_CORE_ON);
+		__wait_wakeup(vmem);
+	}
+
+	/* Enable interrupts to detect faults */
+	__enable_interrupts(vmem);
+
+	atomic_inc(&vmem->alloc_count);
+	*addr = (phys_addr_t)vmem->mem.resource->start;
+	return 0;
+exit:
+	return rc;
+}
+
+/**
+ * vmem_free: - Frees the memory allocated via vmem_allocate.  Undefined
+ * behaviour if to_free is a not a pointer returned via vmem_allocate
+ */
+void vmem_free(phys_addr_t to_free)
+{
+	int c = 0;
+
+	if (!to_free || !vmem)
+		return;
+
+	WARN_ON(atomic_read(&vmem->alloc_count) == 0);
+
+	for (c = 0; c < vmem->num_banks; ++c) {
+		enum bank_state curr_state = __bank_get_state(vmem, c);
+
+		if (curr_state != BANK_STATE_NORM_FORCE_CORE_ON) {
+			pr_warn("When freeing, expected bank state to be %d, was instead %d\n",
+					BANK_STATE_NORM_FORCE_CORE_ON,
+					curr_state);
+		}
+
+		__bank_set_state(vmem, c, BANK_STATE_SLEEP_NO_RET);
+	}
+
+	__disable_interrupts(vmem);
+	__power_off(vmem);
+	atomic_dec(&vmem->alloc_count);
+}
+
+struct vmem_interrupt_cookie {
+	struct vmem *vmem;
+	struct work_struct work;
+};
+
+static void __irq_helper(struct work_struct *work)
+{
+	struct vmem_interrupt_cookie *cookie = container_of(work,
+			struct vmem_interrupt_cookie, work);
+	struct vmem *v = cookie->vmem;
+	unsigned int stat, gen_stat, pscgc_stat, err_addr_abs,
+		err_addr_rel, err_syn;
+
+	stat = __readl(OCIMEM_INTC_STAT(v));
+	gen_stat = __readl(OCIMEM_GEN_CTL(v));
+	pscgc_stat = __readl(OCIMEM_PSCGC_STAT(v));
+
+	err_addr_abs = __readl(OCIMEM_ERR_ADDRESS(v));
+	err_addr_rel = v->mem.resource->start - err_addr_abs;
+
+	err_syn = __readl(OCIMEM_AXI_ERR_SYNDROME(v));
+
+	pr_crit("Detected a fault on VMEM:\n");
+	pr_cont("\tinterrupt status: %x\n", stat);
+	pr_cont("\tgeneral status: %x\n", gen_stat);
+	pr_cont("\tmemory status: %x\n", pscgc_stat);
+	pr_cont("\tfault address: %x (absolute), %x (relative)\n",
+			err_addr_abs, err_addr_rel);
+	pr_cont("\tfault bank: %x\n", err_addr_rel / v->bank_size);
+	pr_cont("\tfault core: %u (mid), %u (pid), %u (bid)\n",
+			ERR_SYN_AMID(err_syn), ERR_SYN_APID(err_syn),
+			ERR_SYN_ABID(err_syn));
+
+	/* Clear the interrupt */
+	__writel(0, OCIMEM_INTC_CLR(v));
+
+	__enable_interrupts(v);
+}
+
+static struct vmem_interrupt_cookie interrupt_cookie;
+
+static irqreturn_t __irq_handler(int irq, void *cookie)
+{
+	struct vmem *v = cookie;
+	irqreturn_t status = __readl(OCIMEM_INTC_STAT(vmem)) ?
+		IRQ_HANDLED : IRQ_NONE;
+
+	if (status != IRQ_NONE) {
+		/* Mask further interrupts while handling this one */
+		__disable_interrupts(v);
+
+		interrupt_cookie.vmem = v;
+		INIT_WORK(&interrupt_cookie.work, __irq_helper);
+		schedule_work(&interrupt_cookie.work);
+	}
+
+	return status;
+}
+
+static inline int __init_resources(struct vmem *v,
+		struct platform_device *pdev)
+{
+	int rc = 0, c = 0;
+
+	v->irq = platform_get_irq(pdev, 0);
+	if (v->irq < 0) {
+		rc = v->irq;
+		pr_err("Failed to get irq (%d)\n", rc);
+		v->irq = 0;
+		goto exit;
+	}
+
+	/* Registers and memory */
+	v->reg.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"reg-base");
+	if (!v->reg.resource) {
+		pr_err("Failed to find register base\n");
+		rc = -ENOENT;
+		goto exit;
+	}
+
+	v->reg.base = devm_ioremap_resource(&pdev->dev, v->reg.resource);
+	if (IS_ERR_OR_NULL(v->reg.base)) {
+		rc = PTR_ERR(v->reg.base) ?: -EIO;
+		pr_err("Failed to map register base into kernel (%d)\n", rc);
+		v->reg.base = NULL;
+		goto exit;
+	}
+
+	pr_debug("Register range: %pa -> %pa\n", &v->reg.resource->start,
+			&v->reg.resource->end);
+
+	v->mem.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"mem-base");
+	if (!v->mem.resource) {
+		pr_err("Failed to find memory base\n");
+		rc = -ENOENT;
+		goto exit;
+	}
+
+	v->mem.base = NULL;
+	pr_debug("Memory range: %pa -> %pa\n", &v->mem.resource->start,
+			&v->mem.resource->end);
+
+	/* Buses, Clocks & Regulators*/
+	v->num_clocks = of_property_count_strings(pdev->dev.of_node,
+			"clock-names");
+	if (v->num_clocks <= 0) {
+		pr_err("Can't find any clocks\n");
+		goto exit;
+	}
+
+	v->clocks = devm_kzalloc(&pdev->dev, sizeof(*v->clocks) * v->num_clocks,
+			GFP_KERNEL);
+	if (!v->clocks) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		const char *name = NULL;
+		struct clk *temp = NULL;
+
+		of_property_read_string_index(pdev->dev.of_node, "clock-names",
+				c, &name);
+		temp = devm_clk_get(&pdev->dev, name);
+		if (IS_ERR_OR_NULL(temp)) {
+			rc = PTR_ERR(temp) ?: -ENOENT;
+			pr_err("Failed to find %s (%d)\n", name, rc);
+			goto exit;
+		}
+
+		v->clocks[c].clk = temp;
+		v->clocks[c].name = name;
+	}
+
+	v->vdd = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR_OR_NULL(v->vdd)) {
+		rc = PTR_ERR(v->vdd) ?: -ENOENT;
+		pr_err("Failed to find regulator (vdd) (%d)\n", rc);
+		goto exit;
+	}
+
+	v->bus.pdata = msm_bus_cl_get_pdata(pdev);
+	if (IS_ERR_OR_NULL(v->bus.pdata)) {
+		rc = PTR_ERR(v->bus.pdata) ?: -ENOENT;
+		pr_err("Failed to find bus vectors (%d)\n", rc);
+		goto exit;
+	}
+
+	v->bus.priv = msm_bus_scale_register_client(v->bus.pdata);
+	if (!v->bus.priv) {
+		rc = -EBADHANDLE;
+		pr_err("Failed to register bus client\n");
+		goto free_pdata;
+	}
+
+	/* Misc. */
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,bank-size",
+			&v->bank_size);
+	if (rc || !v->bank_size) {
+		pr_err("Failed reading (or found invalid) qcom,bank-size in %s (%d)\n",
+				of_node_full_name(pdev->dev.of_node), rc);
+		rc = -ENOENT;
+		goto free_pdata;
+	}
+
+	v->num_banks = resource_size(v->mem.resource) / v->bank_size;
+
+	pr_debug("Found configuration with %d banks with size %d\n",
+			v->num_banks, v->bank_size);
+
+	return 0;
+free_pdata:
+	msm_bus_cl_clear_pdata(v->bus.pdata);
+exit:
+	return rc;
+}
+
+static inline void __uninit_resources(struct vmem *v,
+		struct platform_device *pdev)
+{
+	int c = 0;
+
+	msm_bus_cl_clear_pdata(v->bus.pdata);
+	v->bus.pdata = NULL;
+	v->bus.priv = 0;
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		v->clocks[c].clk = NULL;
+		v->clocks[c].name = NULL;
+	}
+
+	v->vdd = NULL;
+}
+
+static int vmem_probe(struct platform_device *pdev)
+{
+	uint32_t version = 0, num_banks = 0, rc = 0;
+	struct vmem *v = NULL;
+
+	if (vmem) {
+		pr_err("Only one instance of %s allowed", pdev->name);
+		return -EEXIST;
+	}
+
+	v = devm_kzalloc(&pdev->dev, sizeof(*v), GFP_KERNEL);
+	if (!v)
+		return -ENOMEM;
+
+	rc = __init_resources(v, pdev);
+	if (rc) {
+		pr_err("Failed to read resources\n");
+		goto exit;
+	}
+
+	/*
+	 * For now, only support up to 4 banks. It's unrealistic that VMEM has
+	 * more banks than that (even in the future).
+	 */
+	if (v->num_banks > MAX_BANKS) {
+		pr_err("Number of banks (%d) exceeds what's supported (%d)\n",
+			v->num_banks, MAX_BANKS);
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	/* Cross check the platform resources with what's available on chip */
+	rc = __power_on(v);
+	if (rc) {
+		pr_err("Failed to power on (%d)\n", rc);
+		goto exit;
+	}
+
+	version = __readl(OCIMEM_HW_VERSION(v));
+	pr_debug("v%d.%d.%d\n", VERSION_MAJOR(version), VERSION_MINOR(version),
+			VERSION_STEP(version));
+
+	num_banks = PROFILE_BANKS(__readl(OCIMEM_HW_PROFILE(v)));
+	pr_debug("Found %d banks on chip\n", num_banks);
+	if (v->num_banks != num_banks) {
+		pr_err("Platform configuration of %d banks differs from what's available on chip (%d)\n",
+				v->num_banks, num_banks);
+		rc = -EINVAL;
+		goto disable_clocks;
+	}
+
+	rc = devm_request_irq(&pdev->dev, v->irq, __irq_handler,
+			IRQF_TRIGGER_HIGH, "vmem", v);
+	if (rc) {
+		pr_err("Failed to setup irq (%d)\n", rc);
+		goto disable_clocks;
+	}
+
+	__disable_interrupts(v);
+
+	/* Everything good so far, set up the global context and debug hooks */
+	pr_info("Up and running with %d banks of memory from %pR\n",
+			v->num_banks, &v->mem.resource);
+	v->debugfs_root = vmem_debugfs_init(pdev);
+	platform_set_drvdata(pdev, v);
+	vmem = v;
+
+disable_clocks:
+	__power_off(v);
+exit:
+	return rc;
+}
+
+static int vmem_remove(struct platform_device *pdev)
+{
+	struct vmem *v = platform_get_drvdata(pdev);
+
+	WARN_ON(v != vmem);
+
+	__uninit_resources(v, pdev);
+	vmem_debugfs_deinit(v->debugfs_root);
+	vmem = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id vmem_of_match[] = {
+	{.compatible = "qcom,msm-vmem"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, vmem_of_match);
+
+static struct platform_driver vmem_driver = {
+	.probe = vmem_probe,
+	.remove = vmem_remove,
+	.driver = {
+		.name = "msm_vidc_vmem",
+		.owner = THIS_MODULE,
+		.of_match_table = vmem_of_match,
+	},
+};
+
+static int __init vmem_init(void)
+{
+	return platform_driver_register(&vmem_driver);
+}
+
+static void __exit vmem_exit(void)
+{
+	platform_driver_unregister(&vmem_driver);
+}
+
+module_init(vmem_init);
+module_exit(vmem_exit);
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem.h b/drivers/media/platform/msm/vidc_3x/vmem/vmem.h
new file mode 100644
index 0000000..f874aa5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __VMEM_H__
+#define __VMEM_H__
+
+#ifdef CONFIG_MSM_VIDC_VMEM
+
+int vmem_allocate(size_t size, phys_addr_t *addr);
+void vmem_free(phys_addr_t to_free);
+
+#else
+
+static inline int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+	return -ENODEV;
+}
+
+static inline void vmem_free(phys_addr_t to_free)
+{
+}
+
+#endif
+
+#endif /* __VMEM_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c
new file mode 100644
index 0000000..358b75e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include "vmem.h"
+
+struct vmem_debugfs_cookie {
+	phys_addr_t addr;
+	size_t size;
+};
+
+static int __vmem_alloc_get(void *priv, u64 *val)
+{
+	struct vmem_debugfs_cookie *cookie = priv;
+
+	*val = cookie->size;
+	return 0;
+}
+
+static int __vmem_alloc_set(void *priv, u64 val)
+{
+	struct vmem_debugfs_cookie *cookie = priv;
+	int rc = 0;
+
+	switch (val) {
+	case 0: /* free */
+		vmem_free(cookie->addr);
+		cookie->size = 0;
+		break;
+	default:
+		rc = vmem_allocate(val, &cookie->addr);
+		cookie->size = val;
+		break;
+	}
+
+	return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_vmem_alloc, __vmem_alloc_get,
+		__vmem_alloc_set, "%llu");
+
+struct dentry *vmem_debugfs_init(struct platform_device *pdev)
+{
+	struct vmem_debugfs_cookie *alloc_cookie = NULL;
+	struct dentry *debugfs_root = NULL;
+
+	alloc_cookie = devm_kzalloc(&pdev->dev, sizeof(*alloc_cookie),
+			GFP_KERNEL);
+	if (!alloc_cookie)
+		goto exit;
+
+	debugfs_root = debugfs_create_dir("vmem", NULL);
+	if (IS_ERR_OR_NULL(debugfs_root)) {
+		pr_warn("Failed to create '<debugfs>/vmem'\n");
+		debugfs_root = NULL;
+		goto exit;
+	}
+
+	debugfs_create_file("alloc", 0600, debugfs_root,
+			alloc_cookie, &fops_vmem_alloc);
+
+exit:
+	return debugfs_root;
+}
+
+void vmem_debugfs_deinit(struct dentry *debugfs_root)
+{
+	debugfs_remove_recursive(debugfs_root);
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h
new file mode 100644
index 0000000..1aa764b
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __VMEM_DEBUGFS_H__
+#define __VMEM_DEBUGFS_H__
+
+#include <linux/debugfs.h>
+
+struct dentry *vmem_debugfs_init(struct platform_device *pdev);
+void vmem_debugfs_deinit(struct dentry *debugfs_root);
+
+#endif /* __VMEM_DEBUGFS_H__ */
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index f77252d..d29c248 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -418,3 +418,7 @@
 	mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
 }
 EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_DESCRIPTION("soc-camera scaling-cropping functions");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 0e8fb89..5c4aa24 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -504,18 +504,23 @@
 
 static int lme2510_return_status(struct dvb_usb_device *d)
 {
-	int ret = 0;
+	int ret;
 	u8 *data;
 
-	data = kzalloc(10, GFP_KERNEL);
+	data = kzalloc(6, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
-	ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
-			0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
-	info("Firmware Status: %x (%x)", ret , data[2]);
+	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+			      0x06, 0x80, 0x0302, 0x00,
+			      data, 0x6, 200);
+	if (ret != 6)
+		ret = -EINVAL;
+	else
+		ret = data[2];
 
-	ret = (ret < 0) ? -ENODEV : data[2];
+	info("Firmware Status: %6ph", data);
+
 	kfree(data);
 	return ret;
 }
@@ -1079,8 +1084,6 @@
 
 		if (adap->fe[0]) {
 			info("FE Found M88RS2000");
-			dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
-					&d->i2c_adap);
 			st->i2c_tuner_gate_w = 5;
 			st->i2c_tuner_gate_r = 5;
 			st->i2c_tuner_addr = 0x60;
@@ -1146,17 +1149,18 @@
 			ret = st->tuner_config;
 		break;
 	case TUNER_RS2000:
-		ret = st->tuner_config;
+		if (dvb_attach(ts2020_attach, adap->fe[0],
+			       &ts2020_config, &d->i2c_adap))
+			ret = st->tuner_config;
 		break;
 	default:
 		break;
 	}
 
-	if (ret)
+	if (ret) {
 		info("TUN Found %s tuner", tun_msg[ret]);
-	else {
-		info("TUN No tuner found --- resetting device");
-		lme_coldreset(d);
+	} else {
+		info("TUN No tuner found");
 		return -ENODEV;
 	}
 
@@ -1200,6 +1204,7 @@
 static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 {
 	struct lme2510_state *st = d->priv;
+	int status;
 
 	usb_reset_configuration(d->udev);
 
@@ -1208,12 +1213,16 @@
 
 	st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
 
-	if (lme2510_return_status(d) == 0x44) {
+	status = lme2510_return_status(d);
+	if (status == 0x44) {
 		*name = lme_firmware_switch(d, 0);
 		return COLD;
 	}
 
-	return 0;
+	if (status != 0x47)
+		return -EINVAL;
+
+	return WARM;
 }
 
 static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 9fd43a3..b20f03d 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -820,6 +820,8 @@
 	case XC2028_RESET_CLK:
 		deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
 		break;
+	case XC2028_I2C_FLUSH:
+		break;
 	default:
 		deb_info("%s: unknown command %d, arg %d\n", __func__,
 			 command, arg);
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index caa5540..2868766 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -431,6 +431,7 @@
 		state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
 		break;
 	case XC2028_RESET_CLK:
+	case XC2028_I2C_FLUSH:
 		break;
 	default:
 		err("%s: unknown command %d, arg %d\n", __func__,
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index a61d8fd..a20b60a 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -295,7 +295,7 @@
 	/* register v4l2_device early so it can be used for printks */
 	if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
 		dev_err(&interface->dev, "v4l2_device_register failed\n");
-		goto error;
+		goto error_free_dev;
 	}
 
 	mutex_init(&dev->io_mutex);
@@ -304,7 +304,7 @@
 	dev->usbc_buf = kmalloc(64, GFP_KERNEL);
 	if (!dev->usbc_buf) {
 		v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-		goto error;
+		goto error_v4l2_unregister;
 	}
 
 	init_waitqueue_head(&dev->wait_buffer);
@@ -342,13 +342,13 @@
 	}
 	if (!dev->bulk_in_endpointAddr) {
 		v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
-		goto error;
+		goto error_put_usb;
 	}
 
 	/* init the device */
 	if (hdpvr_device_init(dev)) {
 		v4l2_err(&dev->v4l2_dev, "device init failed\n");
-		goto error;
+		goto error_put_usb;
 	}
 
 	mutex_lock(&dev->io_mutex);
@@ -356,7 +356,7 @@
 		mutex_unlock(&dev->io_mutex);
 		v4l2_err(&dev->v4l2_dev,
 			 "allocating transfer buffers failed\n");
-		goto error;
+		goto error_put_usb;
 	}
 	mutex_unlock(&dev->io_mutex);
 
@@ -364,7 +364,7 @@
 	retval = hdpvr_register_i2c_adapter(dev);
 	if (retval < 0) {
 		v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
-		goto error;
+		goto error_free_buffers;
 	}
 
 	client = hdpvr_register_ir_rx_i2c(dev);
@@ -397,13 +397,17 @@
 reg_fail:
 #if IS_ENABLED(CONFIG_I2C)
 	i2c_del_adapter(&dev->i2c_adapter);
+error_free_buffers:
 #endif
+	hdpvr_free_buffers(dev);
+error_put_usb:
+	usb_put_dev(dev->udev);
+	kfree(dev->usbc_buf);
+error_v4l2_unregister:
+	v4l2_device_unregister(&dev->v4l2_dev);
+error_free_dev:
+	kfree(dev);
 error:
-	if (dev) {
-		flush_work(&dev->worker);
-		/* this frees allocated memory */
-		hdpvr_delete(dev);
-	}
 	return retval;
 }
 
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index dc76fd4..0324633 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -141,6 +141,7 @@
 
 static struct usb_device_id usbtv_id_table[] = {
 	{ USB_DEVICE(0x1b71, 0x3002) },
+	{ USB_DEVICE(0x1f71, 0x3301) },
 	{}
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index f37d64c..9eaab98 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -18,8 +18,18 @@
 #include <linux/videodev2.h>
 #include <linux/v4l2-subdev.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-ioctl.h>
 
+/* Use the same argument order as copy_in_user */
+#define assign_in_user(to, from)					\
+({									\
+	typeof(*from) __assign_tmp;					\
+									\
+	get_user(__assign_tmp, from) || put_user(__assign_tmp, to);	\
+})
+
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	long ret = -ENOIOCTLCMD;
@@ -33,157 +43,88 @@
 
 struct v4l2_clip32 {
 	struct v4l2_rect        c;
-	compat_caddr_t 		next;
+	compat_caddr_t		next;
 };
 
 struct v4l2_window32 {
 	struct v4l2_rect        w;
-	__u32		  	field;	/* enum v4l2_field */
+	__u32			field;	/* enum v4l2_field */
 	__u32			chromakey;
 	compat_caddr_t		clips; /* actually struct v4l2_clip32 * */
 	__u32			clipcount;
 	compat_caddr_t		bitmap;
+	__u8                    global_alpha;
 };
 
 static int get_v4l2_window32(struct v4l2_window __user *kp,
-			struct v4l2_window32 __user *up)
+			     struct v4l2_window32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
 {
-	u32 clipcount = 0;
+	struct v4l2_clip32 __user *uclips;
+	struct v4l2_clip __user *kclips;
+	compat_caddr_t p;
+	u32 clipcount;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
-		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_window)) ||
-		copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
-		copy_in_user(&kp->field, &up->field, sizeof(up->field)) ||
-		copy_in_user(&kp->chromakey, &up->chromakey,
-			sizeof(up->chromakey)) ||
-		copy_in_user(&kp->clipcount, &up->clipcount,
-			sizeof(up->clipcount)))
-			return -EFAULT;
-	if (get_user(clipcount, &kp->clipcount))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+	    assign_in_user(&kp->field, &up->field) ||
+	    assign_in_user(&kp->chromakey, &up->chromakey) ||
+	    assign_in_user(&kp->global_alpha, &up->global_alpha) ||
+	    get_user(clipcount, &up->clipcount) ||
+	    put_user(clipcount, &kp->clipcount))
 		return -EFAULT;
 	if (clipcount > 2048)
 		return -EINVAL;
-	if (clipcount) {
-		struct v4l2_clip32 __user *uclips;
-		struct v4l2_clip __user *kclips;
-		int n = clipcount;
-		compat_caddr_t p;
+	if (!clipcount)
+		return put_user(NULL, &kp->clips);
 
-		if (get_user(p, &up->clips))
+	if (get_user(p, &up->clips))
+		return -EFAULT;
+	uclips = compat_ptr(p);
+	if (aux_space < clipcount * sizeof(*kclips))
+		return -EFAULT;
+	kclips = aux_buf;
+	if (put_user(kclips, &kp->clips))
+		return -EFAULT;
+
+	while (clipcount--) {
+		if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
 			return -EFAULT;
-		uclips = compat_ptr(p);
-		kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
-		if (put_user(kclips, &kp->clips))
+		if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
 			return -EFAULT;
-		while (--n >= 0) {
-			if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
-				return -EFAULT;
-			if (put_user(n ? kclips + 1 : NULL, &kclips->next))
-				return -EFAULT;
-			uclips += 1;
-			kclips += 1;
-		}
-	} else {
-		if (put_user(NULL, &kp->clips))
-			return -EFAULT;
+		uclips++;
+		kclips++;
 	}
 	return 0;
 }
 
 static int put_v4l2_window32(struct v4l2_window __user *kp,
-			struct v4l2_window32 __user *up)
+			     struct v4l2_window32 __user *up)
 {
-	if (copy_in_user(&up->w, &kp->w, sizeof(up->w)) ||
-		copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
-		copy_in_user(&up->chromakey, &kp->chromakey,
-			sizeof(up->chromakey)) ||
-		copy_in_user(&up->clipcount, &kp->clipcount,
-			sizeof(up->clipcount)))
-		return -EFAULT;
-	return 0;
-}
+	struct v4l2_clip __user *kclips = kp->clips;
+	struct v4l2_clip32 __user *uclips;
+	compat_caddr_t p;
+	u32 clipcount;
 
-static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp,
-				struct v4l2_pix_format __user *up)
-{
-	if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format)))
+	if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
+	    assign_in_user(&up->field, &kp->field) ||
+	    assign_in_user(&up->chromakey, &kp->chromakey) ||
+	    assign_in_user(&up->global_alpha, &kp->global_alpha) ||
+	    get_user(clipcount, &kp->clipcount) ||
+	    put_user(clipcount, &up->clipcount))
 		return -EFAULT;
-	return 0;
-}
+	if (!clipcount)
+		return 0;
 
-static inline int get_v4l2_pix_format_mplane(
-				struct v4l2_pix_format_mplane __user *kp,
-				struct v4l2_pix_format_mplane __user *up)
-{
-	if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+	if (get_user(p, &up->clips))
 		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp,
-				struct v4l2_pix_format __user *up)
-{
-	if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_pix_format_mplane(
-				struct v4l2_pix_format_mplane __user *kp,
-				struct v4l2_pix_format_mplane __user *up)
-{
-	if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
-				struct v4l2_vbi_format __user *up)
-{
-	if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
-				struct v4l2_vbi_format __user *up)
-{
-	if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int get_v4l2_sliced_vbi_format(
-				struct v4l2_sliced_vbi_format __user *kp,
-				struct v4l2_sliced_vbi_format __user *up)
-{
-	if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_sliced_vbi_format(
-				struct v4l2_sliced_vbi_format __user *kp,
-				struct v4l2_sliced_vbi_format __user *up)
-{
-	if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
-				struct v4l2_sdr_format __user *up)
-{
-	if (copy_in_user(kp, up, sizeof(struct v4l2_sdr_format)))
-		return -EFAULT;
-	return 0;
-}
-
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
-					struct v4l2_sdr_format __user *up)
-{
-	if (copy_in_user(up, kp, sizeof(struct v4l2_sdr_format)))
-		return -EFAULT;
+	uclips = compat_ptr(p);
+	while (clipcount--) {
+		if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+			return -EFAULT;
+		uclips++;
+		kclips++;
+	}
 	return 0;
 }
 
@@ -217,120 +158,158 @@
 	__u32			reserved[8];
 };
 
-static int __get_v4l2_format32(struct v4l2_format __user *kp,
-				struct v4l2_format32 __user *up)
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 {
 	u32 type;
 
-	if (copy_in_user(&kp->type, &up->type, sizeof(up->type)))
+	if (get_user(type, &up->type))
 		return -EFAULT;
 
-	if (get_user(type, &kp->type))
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
+		u32 clipcount;
+
+		if (get_user(clipcount, &up->fmt.win.clipcount))
+			return -EFAULT;
+		if (clipcount > 2048)
+			return -EINVAL;
+		*size = clipcount * sizeof(struct v4l2_clip);
+		return 0;
+	}
+	default:
+		*size = 0;
+		return 0;
+	}
+}
+
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+{
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 		return -EFAULT;
+	return __bufsize_v4l2_format(up, size);
+}
+
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+			       struct v4l2_format32 __user *up,
+			       void __user *aux_buf, u32 aux_space)
+{
+	u32 type;
+
+	if (get_user(type, &up->type) || put_user(type, &kp->type))
+		return -EFAULT;
+
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+		return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
+				    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-						  &up->fmt.pix_mp);
+		return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+				    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
+					 aux_buf, aux_space);
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
-		return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+		return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
+				    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-		return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+		return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
+				    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
-		return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+		return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
+				    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
 	default:
-		pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-								kp->type);
 		return -EINVAL;
 	}
 }
 
 static int get_v4l2_format32(struct v4l2_format __user *kp,
-				struct v4l2_format32 __user *up)
+			     struct v4l2_format32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
 {
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
-		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_format)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 		return -EFAULT;
-	return __get_v4l2_format32(kp, up);
+	return __get_v4l2_format32(kp, up, aux_buf, aux_space);
+}
+
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
+			       u32 *size)
+{
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __bufsize_v4l2_format(&up->format, size);
 }
 
 static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
-				struct v4l2_create_buffers32 __user *up)
+			     struct v4l2_create_buffers32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
 {
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
-		!access_ok(VERIFY_WRITE, kp,
-			sizeof(struct v4l2_create_buffers)) ||
-		copy_in_user(kp, up,
-			offsetof(struct v4l2_create_buffers32, format)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    copy_in_user(kp, up,
+			 offsetof(struct v4l2_create_buffers32, format)))
 		return -EFAULT;
-	return __get_v4l2_format32(&kp->format, &up->format);
+	return __get_v4l2_format32(&kp->format, &up->format,
+				   aux_buf, aux_space);
 }
 
 static int __put_v4l2_format32(struct v4l2_format __user *kp,
-				struct v4l2_format32 __user *up)
+			       struct v4l2_format32 __user *up)
 {
 	u32 type;
 
-	if (copy_in_user(&up->type, &kp->type, sizeof(up->type)))
-		return -EFAULT;
-
 	if (get_user(type, &kp->type))
 		return -EFAULT;
 
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+		return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+				    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-						  &up->fmt.pix_mp);
+		return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+				    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
-		return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+		return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+				    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-		return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+		return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+				    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
-		return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+		return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+				    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
 	default:
-		pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-								kp->type);
 		return -EINVAL;
 	}
 }
 
 static int put_v4l2_format32(struct v4l2_format __user *kp,
-				struct v4l2_format32 __user *up)
+			     struct v4l2_format32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
-		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_format)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
 		return -EFAULT;
 	return __put_v4l2_format32(kp, up);
 }
 
 static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
-				struct v4l2_create_buffers32 __user *up)
+			     struct v4l2_create_buffers32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-		!access_ok(VERIFY_READ, kp,
-			sizeof(struct v4l2_create_buffers)) ||
-		copy_in_user(up, kp,
-			offsetof(struct v4l2_create_buffers32, format)) ||
-		copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    copy_in_user(up, kp,
+			 offsetof(struct v4l2_create_buffers32, format)) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
 		return -EFAULT;
 	return __put_v4l2_format32(&kp->format, &up->format);
 }
@@ -345,30 +324,27 @@
 };
 
 static int get_v4l2_standard32(struct v4l2_standard __user *kp,
-			struct v4l2_standard32 __user *up)
+			       struct v4l2_standard32 __user *up)
 {
 	/* other fields are not set by the user, nor used by the driver */
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
-		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_standard)) ||
-		copy_in_user(&kp->index, &up->index, sizeof(up->index)))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->index, &up->index))
 		return -EFAULT;
 	return 0;
 }
 
 static int put_v4l2_standard32(struct v4l2_standard __user *kp,
-				struct v4l2_standard32 __user *up)
+			       struct v4l2_standard32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
-		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_standard)) ||
-		copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
-		copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
-		copy_in_user(up->name, kp->name, 24) ||
-		copy_in_user(&up->frameperiod, &kp->frameperiod,
-			sizeof(up->frameperiod)) ||
-		copy_in_user(&up->framelines, &kp->framelines,
-			sizeof(up->framelines)) ||
-		copy_in_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->index, &kp->index) ||
+	    assign_in_user(&up->id, &kp->id) ||
+	    copy_in_user(up->name, kp->name, sizeof(up->name)) ||
+	    copy_in_user(&up->frameperiod, &kp->frameperiod,
+			 sizeof(up->frameperiod)) ||
+	    assign_in_user(&up->framelines, &kp->framelines) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -407,160 +383,192 @@
 	__u32			reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-				enum v4l2_memory memory)
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
+			    struct v4l2_plane32 __user *up32,
+			    enum v4l2_memory memory)
 {
-	void __user *up_pln;
-	compat_long_t p;
+	compat_ulong_t p;
 
 	if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
-		copy_in_user(&up->data_offset, &up32->data_offset,
-				sizeof(__u32)) ||
-		copy_in_user(up->reserved, up32->reserved,
-				sizeof(up->reserved)) ||
-		copy_in_user(&up->length, &up32->length,
-				sizeof(__u32)))
+	    copy_in_user(&up->data_offset, &up32->data_offset,
+			 sizeof(up->data_offset)) ||
+	    copy_in_user(up->reserved, up32->reserved,
+			 sizeof(up->reserved)) ||
+	    copy_in_user(&up->length, &up32->length,
+			 sizeof(up->length)))
 		return -EFAULT;
 
-	if (memory == V4L2_MEMORY_USERPTR) {
-		if (get_user(p, &up32->m.userptr))
-			return -EFAULT;
-		up_pln = compat_ptr(p);
-		if (put_user((unsigned long)up_pln, &up->m.userptr))
-			return -EFAULT;
-	} else if (memory == V4L2_MEMORY_DMABUF) {
-		if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
-			return -EFAULT;
-	} else {
+	switch (memory) {
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_OVERLAY:
 		if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
-					sizeof(__u32)))
+				 sizeof(up32->m.mem_offset)))
 			return -EFAULT;
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (get_user(p, &up32->m.userptr) ||
+		    put_user((unsigned long)compat_ptr(p), &up->m.userptr))
+			return -EFAULT;
+		break;
+	case V4L2_MEMORY_DMABUF:
+		if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+			return -EFAULT;
+		break;
 	}
 
 	return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-				enum v4l2_memory memory)
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
+			    struct v4l2_plane32 __user *up32,
+			    enum v4l2_memory memory)
 {
+	unsigned long p;
+
 	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
-		copy_in_user(&up32->data_offset, &up->data_offset,
-				sizeof(__u32)) ||
-		copy_in_user(up32->reserved, up->reserved,
-				sizeof(up32->reserved)))
+	    copy_in_user(&up32->data_offset, &up->data_offset,
+			 sizeof(up->data_offset)) ||
+	    copy_in_user(up32->reserved, up->reserved,
+			 sizeof(up32->reserved)))
 		return -EFAULT;
 
-	/* For MMAP, driver might've set up the offset, so copy it back.
-	 * USERPTR stays the same (was userspace-provided), so no copying. */
-	if (memory == V4L2_MEMORY_MMAP)
+	switch (memory) {
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_OVERLAY:
 		if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
-					sizeof(__u32)))
+				 sizeof(up->m.mem_offset)))
 			return -EFAULT;
-	/* For DMABUF, driver might've set up the fd, so copy it back. */
-	if (memory == V4L2_MEMORY_DMABUF)
-		if (copy_in_user(&up32->m.fd, &up->m.fd,
-					sizeof(int)))
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (get_user(p, &up->m.userptr) ||
+		    put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
+			     &up32->m.userptr))
 			return -EFAULT;
+		break;
+	case V4L2_MEMORY_DMABUF:
+		if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+			return -EFAULT;
+		break;
+	}
 
 	return 0;
 }
 
-static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
-				struct v4l2_buffer32 __user *up)
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
 {
+	u32 type;
+	u32 length;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(type, &up->type) ||
+	    get_user(length, &up->length))
+		return -EFAULT;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		if (length > VIDEO_MAX_PLANES)
+			return -EINVAL;
+
+		/*
+		 * We don't really care if userspace decides to kill itself
+		 * by passing a very big length value
+		 */
+		*size = length * sizeof(struct v4l2_plane);
+	} else {
+		*size = 0;
+	}
+	return 0;
+}
+
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+			     struct v4l2_buffer32 __user *up,
+			     void __user *aux_buf, u32 aux_space)
+{
+	u32 type;
+	u32 length;
+	enum v4l2_memory memory;
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
-	int num_planes;
-	struct timeval time;
-	u32 plane_count, memory, type;
 	int ret;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
-		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_buffer)) ||
-		copy_in_user(&kp->index, &up->index, sizeof(up->index)) ||
-		copy_in_user(&kp->type, &up->type, sizeof(up->type)) ||
-		copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
-		copy_in_user(&kp->memory, &up->memory, sizeof(up->memory)) ||
-		copy_in_user(&kp->length, &up->length, sizeof(up->length)))
-			return -EFAULT;
-
-	if (get_user(type, &kp->type))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->index, &up->index) ||
+	    get_user(type, &up->type) ||
+	    put_user(type, &kp->type) ||
+	    assign_in_user(&kp->flags, &up->flags) ||
+	    get_user(memory, &up->memory) ||
+	    put_user(memory, &kp->memory) ||
+	    get_user(length, &up->length) ||
+	    put_user(length, &kp->length))
 		return -EFAULT;
+
 	if (V4L2_TYPE_IS_OUTPUT(type))
-		if (copy_in_user(&kp->bytesused, &up->bytesused,
-				sizeof(up->bytesused)) ||
-			copy_in_user(&kp->field, &up->field,
-				sizeof(up->field)) ||
-			get_user(time.tv_sec, &up->timestamp.tv_sec) ||
-			get_user(time.tv_usec, &up->timestamp.tv_usec) ||
-			put_user(time.tv_sec, &kp->timestamp.tv_sec) ||
-			put_user(time.tv_usec, &kp->timestamp.tv_usec))
+		if (assign_in_user(&kp->bytesused, &up->bytesused) ||
+		    assign_in_user(&kp->field, &up->field) ||
+		    assign_in_user(&kp->timestamp.tv_sec,
+				   &up->timestamp.tv_sec) ||
+		    assign_in_user(&kp->timestamp.tv_usec,
+				   &up->timestamp.tv_usec))
 			return -EFAULT;
 
-	if (get_user(memory, &kp->memory))
-		return -EFAULT;
 	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
-		if (get_user(plane_count, &kp->length))
-			return -EFAULT;
-		num_planes = plane_count;
+		u32 num_planes = length;
+
 		if (num_planes == 0) {
-			if (put_user(NULL, &kp->m.planes))
-				return -EFAULT;
-			/* num_planes == 0 is legal, e.g. when userspace doesn't
-			 * need planes array on DQBUF*/
-			return 0;
+			/*
+			 * num_planes == 0 is legal, e.g. when userspace doesn't
+			 * need planes array on DQBUF
+			 */
+			return put_user(NULL, &kp->m.planes);
 		}
+		if (num_planes > VIDEO_MAX_PLANES)
+			return -EINVAL;
 
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 
 		uplane32 = compat_ptr(p);
 		if (!access_ok(VERIFY_READ, uplane32,
-				num_planes * sizeof(struct v4l2_plane32)))
+			       num_planes * sizeof(*uplane32)))
 			return -EFAULT;
 
-		/* We don't really care if userspace decides to kill itself
-		 * by passing a very big num_planes value */
-		uplane = compat_alloc_user_space(num_planes *
-						sizeof(struct v4l2_plane));
-		if (put_user(uplane, &kp->m.planes))
+		/*
+		 * We don't really care if userspace decides to kill itself
+		 * by passing a very big num_planes value
+		 */
+		if (aux_space < num_planes * sizeof(*uplane))
 			return -EFAULT;
 
-		while (--num_planes >= 0) {
+		uplane = aux_buf;
+		if (put_user((__force struct v4l2_plane *)uplane,
+			     &kp->m.planes))
+			return -EFAULT;
+
+		while (num_planes--) {
 			ret = get_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
-			++uplane;
-			++uplane32;
+			uplane++;
+			uplane32++;
 		}
 	} else {
 		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (copy_in_user(&kp->m.offset, &up->m.offset,
-				sizeof(up->m.offset)))
-				return -EFAULT;
-			break;
-		case V4L2_MEMORY_USERPTR:
-			{
-			compat_long_t tmp;
-			unsigned long userptr;
-
-			if (get_user(tmp, &up->m.userptr))
-				return -EFAULT;
-
-			userptr = (unsigned long)compat_ptr(tmp);
-			put_user(userptr, &kp->m.userptr);
-			}
-			break;
 		case V4L2_MEMORY_OVERLAY:
-			if (copy_in_user(&kp->m.offset, &up->m.offset,
-				sizeof(up->m.offset)))
+			if (assign_in_user(&kp->m.offset, &up->m.offset))
 				return -EFAULT;
 			break;
+		case V4L2_MEMORY_USERPTR: {
+			compat_ulong_t userptr;
+
+			if (get_user(userptr, &up->m.userptr) ||
+			    put_user((unsigned long)compat_ptr(userptr),
+				     &kp->m.userptr))
+				return -EFAULT;
+			break;
+		}
 		case V4L2_MEMORY_DMABUF:
-			if (copy_in_user(&kp->m.fd, &up->m.fd,
-				sizeof(up->m.fd)))
+			if (assign_in_user(&kp->m.fd, &up->m.fd))
 				return -EFAULT;
 			break;
 		}
@@ -570,59 +578,50 @@
 }
 
 static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
-				struct v4l2_buffer32 __user *up)
+			     struct v4l2_buffer32 __user *up)
 {
+	u32 type;
+	u32 length;
+	enum v4l2_memory memory;
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
-	int num_planes;
 	int ret;
-	struct timeval time;
-	u32 memory, type, length;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
-		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_buffer)) ||
-		copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
-		copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
-		copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
-		copy_in_user(&up->memory, &kp->memory, sizeof(up->memory)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->index, &kp->index) ||
+	    get_user(type, &kp->type) ||
+	    put_user(type, &up->type) ||
+	    assign_in_user(&up->flags, &kp->flags) ||
+	    get_user(memory, &kp->memory) ||
+	    put_user(memory, &up->memory))
 		return -EFAULT;
 
-	if (copy_in_user(&up->bytesused, &kp->bytesused,
-			sizeof(up->bytesused)) ||
-		copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
-		get_user(time.tv_sec, &kp->timestamp.tv_sec) ||
-		get_user(time.tv_usec, &kp->timestamp.tv_usec) ||
-		put_user(time.tv_sec, &up->timestamp.tv_sec) ||
-		put_user(time.tv_usec, &up->timestamp.tv_usec) ||
-		copy_in_user(&up->timecode, &kp->timecode,
-			sizeof(struct v4l2_timecode)) ||
-		copy_in_user(&up->sequence, &kp->sequence,
-			sizeof(up->sequence)) ||
-		copy_in_user(&up->reserved2, &kp->reserved2,
-			sizeof(up->reserved2)) ||
-		copy_in_user(&up->reserved, &kp->reserved,
-			sizeof(up->reserved)) ||
-		copy_in_user(&up->length, &kp->length, sizeof(up->length)))
+	if (assign_in_user(&up->bytesused, &kp->bytesused) ||
+	    assign_in_user(&up->field, &kp->field) ||
+	    assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+	    assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
+	    copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+	    assign_in_user(&up->sequence, &kp->sequence) ||
+	    assign_in_user(&up->reserved2, &kp->reserved2) ||
+	    assign_in_user(&up->reserved, &kp->reserved) ||
+	    get_user(length, &kp->length) ||
+	    put_user(length, &up->length))
 		return -EFAULT;
 
-	if (get_user(type, &kp->type) ||
-		get_user(memory, &kp->memory) ||
-		get_user(length, &kp->length))
-		return -EINVAL;
-
 	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
-		num_planes = length;
+		u32 num_planes = length;
+
 		if (num_planes == 0)
 			return 0;
 
-		if (get_user(uplane, &kp->m.planes))
+		if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
 			return -EFAULT;
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 		uplane32 = compat_ptr(p);
 
-		while (--num_planes >= 0) {
+		while (num_planes--) {
 			ret = put_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
@@ -632,23 +631,16 @@
 	} else {
 		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (copy_in_user(&up->m.offset, &kp->m.offset,
-				sizeof(up->m.offset)))
+		case V4L2_MEMORY_OVERLAY:
+			if (assign_in_user(&up->m.offset, &kp->m.offset))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_USERPTR:
-			if (copy_in_user(&up->m.userptr, &kp->m.userptr,
-				sizeof(up->m.userptr)))
-				return -EFAULT;
-			break;
-		case V4L2_MEMORY_OVERLAY:
-			if (copy_in_user(&up->m.offset, &kp->m.offset,
-				sizeof(up->m.offset)))
+			if (assign_in_user(&up->m.userptr, &kp->m.userptr))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_DMABUF:
-			if (copy_in_user(&up->m.fd, &kp->m.fd,
-				sizeof(up->m.fd)))
+			if (assign_in_user(&up->m.fd, &kp->m.fd))
 				return -EFAULT;
 			break;
 		}
@@ -660,7 +652,7 @@
 struct v4l2_framebuffer32 {
 	__u32			capability;
 	__u32			flags;
-	compat_caddr_t 		base;
+	compat_caddr_t		base;
 	struct {
 		__u32		width;
 		__u32		height;
@@ -674,39 +666,32 @@
 };
 
 static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
-					struct v4l2_framebuffer32 __user *up)
+				  struct v4l2_framebuffer32 __user *up)
 {
-	u32 tmp;
+	compat_caddr_t tmp;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
-		!access_ok(VERIFY_WRITE, kp,
-			sizeof(struct v4l2_framebuffer)) ||
-		get_user(tmp, &up->base) ||
-		put_user(compat_ptr(tmp), &kp->base) ||
-		copy_in_user(&kp->capability, &up->capability,
-			sizeof(up->capability)) ||
-		copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
-		copy_in_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
-			return -EFAULT;
-
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(tmp, &up->base) ||
+	    put_user((__force void *)compat_ptr(tmp), &kp->base) ||
+	    assign_in_user(&kp->capability, &up->capability) ||
+	    assign_in_user(&kp->flags, &up->flags) ||
+	    copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+		return -EFAULT;
 	return 0;
 }
 
 static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
-					struct v4l2_framebuffer32 __user *up)
+				  struct v4l2_framebuffer32 __user *up)
 {
-	unsigned long base;
+	void *base;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
-		!access_ok(VERIFY_READ, kp,
-			sizeof(struct v4l2_framebuffer)) ||
-		copy_from_user(&base, &kp->base, sizeof(base)) ||
-		put_user((u32)base, &up->base) ||
-		copy_in_user(&up->capability, &kp->capability,
-			sizeof(up->capability)) ||
-		copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
-		copy_in_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    get_user(base, &kp->base) ||
+	    put_user(ptr_to_compat(base), &up->base) ||
+	    assign_in_user(&up->capability, &kp->capability) ||
+	    assign_in_user(&up->flags, &kp->flags) ||
+	    copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -718,23 +703,26 @@
 	__u32        tuner;             /*  Associated tuner */
 	compat_u64   std;
 	__u32	     status;
-	__u32	     reserved[4];
+	__u32	     capabilities;
+	__u32	     reserved[3];
 };
 
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
-   Otherwise it is identical to the 32-bit version. */
+/*
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ * Otherwise it is identical to the 32-bit version.
+ */
 static inline int get_v4l2_input32(struct v4l2_input __user *kp,
-					struct v4l2_input32 __user *up)
+				   struct v4l2_input32 __user *up)
 {
-	if (copy_in_user(kp, up, sizeof(struct v4l2_input32)))
+	if (copy_in_user(kp, up, sizeof(*up)))
 		return -EFAULT;
 	return 0;
 }
 
 static inline int put_v4l2_input32(struct v4l2_input __user *kp,
-					struct v4l2_input32 __user *up)
+				   struct v4l2_input32 __user *up)
 {
-	if (copy_in_user(up, kp, sizeof(struct v4l2_input32)))
+	if (copy_in_user(up, kp, sizeof(*up)))
 		return -EFAULT;
 	return 0;
 }
@@ -758,70 +746,95 @@
 	};
 } __attribute__ ((packed));
 
-/* The following function really belong in v4l2-common, but that causes
-   a circular dependency between modules. We need to think about this, but
-   for now this will do. */
-
-/* Return non-zero if this control is a pointer type. Currently only
-   type STRING is a pointer type. */
-static inline int ctrl_is_pointer(u32 id)
+/* Return true if this control is a pointer type. */
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
 {
-	switch (id) {
-	case V4L2_CID_RDS_TX_PS_NAME:
-	case V4L2_CID_RDS_TX_RADIO_TEXT:
-		return 1;
-	default:
-		return 0;
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_fh *fh = NULL;
+	struct v4l2_ctrl_handler *hdl = NULL;
+	struct v4l2_query_ext_ctrl qec = { id };
+	const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+	if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+		fh = file->private_data;
+
+	if (fh && fh->ctrl_handler)
+		hdl = fh->ctrl_handler;
+	else if (vdev->ctrl_handler)
+		hdl = vdev->ctrl_handler;
+
+	if (hdl) {
+		struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
+
+		return ctrl && ctrl->is_ptr;
 	}
+
+	if (!ops || !ops->vidioc_query_ext_ctrl)
+		return false;
+
+	return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
+		(qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
 }
 
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
-					struct v4l2_ext_controls32 __user *up)
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
+				     u32 *size)
+{
+	u32 count;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    get_user(count, &up->count))
+		return -EFAULT;
+	if (count > V4L2_CID_MAX_CTRLS)
+		return -EINVAL;
+	*size = count * sizeof(struct v4l2_ext_control);
+	return 0;
+}
+
+static int get_v4l2_ext_controls32(struct file *file,
+				   struct v4l2_ext_controls __user *kp,
+				   struct v4l2_ext_controls32 __user *up,
+				   void __user *aux_buf, u32 aux_space)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
 	struct v4l2_ext_control __user *kcontrols;
-	int n;
-	compat_caddr_t p;
 	u32 count;
+	u32 n;
+	compat_caddr_t p;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-		!access_ok(VERIFY_WRITE, kp,
-			sizeof(struct v4l2_ext_controls)) ||
-		copy_in_user(&kp->which, &up->which,
-			sizeof(up->which)) ||
-		copy_in_user(&kp->count, &up->count, sizeof(up->count)) ||
-		copy_in_user(&kp->error_idx, &up->error_idx,
-			sizeof(up->error_idx)) ||
-		copy_in_user(kp->reserved, up->reserved,
-			       sizeof(up->reserved)))
-			return -EFAULT;
-
-	if (get_user(count, &kp->count))
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->which, &up->which) ||
+	    get_user(count, &up->count) ||
+	    put_user(count, &kp->count) ||
+	    assign_in_user(&kp->error_idx, &up->error_idx) ||
+	    copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
 		return -EFAULT;
-	n = count;
-	if (n == 0) {
-		if (put_user(NULL, &kp->controls))
-			return -EINVAL;
-		return 0;
-	}
+
+	if (count == 0)
+		return put_user(NULL, &kp->controls);
+	if (count > V4L2_CID_MAX_CTRLS)
+		return -EINVAL;
 	if (get_user(p, &up->controls))
 		return -EFAULT;
 	ucontrols = compat_ptr(p);
-	if (!access_ok(VERIFY_READ, ucontrols,
-			n * sizeof(struct v4l2_ext_control32)))
+	if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
 		return -EFAULT;
-	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-	if (put_user(kcontrols, &kp->controls))
+	if (aux_space < count * sizeof(*kcontrols))
+		return -EFAULT;
+	kcontrols = aux_buf;
+	if (put_user((__force struct v4l2_ext_control *)kcontrols,
+		     &kp->controls))
 		return -EFAULT;
 
-	while (--n >= 0) {
+	for (n = 0; n < count; n++) {
 		u32 id;
 
 		if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
 			return -EFAULT;
+
 		if (get_user(id, &kcontrols->id))
 			return -EFAULT;
-		if (ctrl_is_pointer(id)) {
+
+		if (ctrl_is_pointer(file, id)) {
 			void __user *s;
 
 			if (get_user(p, &ucontrols->string))
@@ -836,53 +849,55 @@
 	return 0;
 }
 
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
-				struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct file *file,
+				   struct v4l2_ext_controls __user *kp,
+				   struct v4l2_ext_controls32 __user *up)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
 	struct v4l2_ext_control __user *kcontrols;
-	int n;
 	u32 count;
+	u32 n;
 	compat_caddr_t p;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-		!access_ok(VERIFY_READ, kp,
-			sizeof(struct v4l2_ext_controls)) ||
-		copy_in_user(&up->which, &kp->which,
-			sizeof(up->which)) ||
-		copy_in_user(&up->count, &kp->count,
-			sizeof(up->count)) ||
-		copy_in_user(&up->error_idx, &kp->error_idx,
-			sizeof(up->error_idx)) ||
-		copy_in_user(up->reserved, kp->reserved,
-			sizeof(up->reserved)) ||
-		get_user(count, &kp->count) ||
-		get_user(kcontrols, &kp->controls))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->which, &kp->which) ||
+	    get_user(count, &kp->count) ||
+	    put_user(count, &up->count) ||
+	    assign_in_user(&up->error_idx, &kp->error_idx) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
+	    get_user(kcontrols, &kp->controls))
+		return -EFAULT;
+
 	if (!count)
 		return 0;
-
-	n = count;
 	if (get_user(p, &up->controls))
 		return -EFAULT;
 	ucontrols = compat_ptr(p);
-	if (!access_ok(VERIFY_WRITE, ucontrols,
-			n * sizeof(struct v4l2_ext_control32)))
+	if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
 		return -EFAULT;
 
-	while (--n >= 0) {
-		unsigned size = sizeof(*ucontrols);
+	for (n = 0; n < count; n++) {
+		unsigned int size = sizeof(*ucontrols);
 		u32 id;
 
-		if (get_user(id, &kcontrols->id))
+		if (get_user(id, &kcontrols->id) ||
+		    put_user(id, &ucontrols->id) ||
+		    assign_in_user(&ucontrols->size, &kcontrols->size) ||
+		    copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+				 sizeof(ucontrols->reserved2)))
 			return -EFAULT;
-		/* Do not modify the pointer when copying a pointer control.
-		   The contents of the pointer was changed, not the pointer
-		   itself. */
-		if (ctrl_is_pointer(id))
+
+		/*
+		 * Do not modify the pointer when copying a pointer control.
+		 * The contents of the pointer was changed, not the pointer
+		 * itself.
+		 */
+		if (ctrl_is_pointer(file, id))
 			size -= sizeof(ucontrols->value64);
+
 		if (copy_in_user(ucontrols, kcontrols, size))
 			return -EFAULT;
+
 		ucontrols++;
 		kcontrols++;
 	}
@@ -903,22 +918,18 @@
 };
 
 static int put_v4l2_event32(struct v4l2_event __user *kp,
-			struct v4l2_event32 __user *up)
+			    struct v4l2_event32 __user *up)
 {
-	struct timespec ts;
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
-		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_event)) ||
-		copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
-		copy_in_user(&up->u, &kp->u, sizeof(up->u)) ||
-		copy_in_user(&up->pending, &kp->pending,
-			sizeof(up->pending)) ||
-		copy_in_user(&up->sequence, &kp->sequence,
-			sizeof(up->sequence)) ||
-		copy_from_user(&ts, &kp->timestamp, sizeof(ts)) ||
-		compat_put_timespec(&ts, &up->timestamp) ||
-		copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
-		copy_in_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->type, &kp->type) ||
+	    copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
+	    assign_in_user(&up->pending, &kp->pending) ||
+	    assign_in_user(&up->sequence, &kp->sequence) ||
+	    assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+	    assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
+	    assign_in_user(&up->id, &kp->id) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -931,39 +942,34 @@
 };
 
 static int get_v4l2_edid32(struct v4l2_edid __user *kp,
-						struct v4l2_edid32 __user *up)
+			   struct v4l2_edid32 __user *up)
 {
-	u32 tmp;
+	compat_uptr_t tmp;
 
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
-		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_edid)) ||
-		copy_in_user(&kp->pad, &up->pad, sizeof(up->pad)) ||
-		copy_in_user(&kp->start_block, &up->start_block,
-			sizeof(up->start_block)) ||
-		copy_in_user(&kp->blocks, &up->blocks, sizeof(up->blocks)) ||
-		get_user(tmp, &up->edid) ||
-		put_user(compat_ptr(tmp), &kp->edid) ||
-		copy_in_user(kp->reserved, up->reserved,
-			sizeof(kp->reserved)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    assign_in_user(&kp->pad, &up->pad) ||
+	    assign_in_user(&kp->start_block, &up->start_block) ||
+	    assign_in_user(&kp->blocks, &up->blocks) ||
+	    get_user(tmp, &up->edid) ||
+	    put_user(compat_ptr(tmp), &kp->edid) ||
+	    copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
 static int put_v4l2_edid32(struct v4l2_edid __user *kp,
-			struct v4l2_edid32 __user *up)
+			   struct v4l2_edid32 __user *up)
 {
-	unsigned long ptr;
+	void *edid;
 
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
-		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_edid)) ||
-		copy_in_user(&up->pad, &kp->pad, sizeof(up->pad)) ||
-		copy_in_user(&up->start_block, &kp->start_block,
-			sizeof(up->start_block)) ||
-		copy_in_user(&up->blocks, &kp->blocks, sizeof(up->blocks)) ||
-		copy_from_user(&ptr, &kp->edid, sizeof(ptr)) ||
-		put_user((u32)ptr, &up->edid) ||
-		copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-			return -EFAULT;
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    assign_in_user(&up->pad, &kp->pad) ||
+	    assign_in_user(&up->start_block, &kp->start_block) ||
+	    assign_in_user(&up->blocks, &kp->blocks) ||
+	    get_user(edid, &kp->edid) ||
+	    put_user(ptr_to_compat(edid), &up->edid) ||
+	    copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -979,7 +985,7 @@
 #define VIDIOC_ENUMINPUT32	_IOWR('V', 26, struct v4l2_input32)
 #define VIDIOC_G_EDID32		_IOWR('V', 40, struct v4l2_edid32)
 #define VIDIOC_S_EDID32		_IOWR('V', 41, struct v4l2_edid32)
-#define VIDIOC_TRY_FMT32      	_IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_TRY_FMT32	_IOWR('V', 64, struct v4l2_format32)
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
@@ -995,30 +1001,26 @@
 #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
 #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
 
+static int alloc_userspace(unsigned int size, u32 aux_space,
+			   void __user **up_native)
+{
+	*up_native = compat_alloc_user_space(size + aux_space);
+	if (!*up_native)
+		return -ENOMEM;
+	if (clear_user(*up_native, size))
+		return -EFAULT;
+	return 0;
+}
+
 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	union {
-		struct v4l2_format v2f;
-		struct v4l2_buffer v2b;
-		struct v4l2_framebuffer v2fb;
-		struct v4l2_input v2i;
-		struct v4l2_standard v2s;
-		struct v4l2_ext_controls v2ecs;
-		struct v4l2_event v2ev;
-		struct v4l2_create_buffers v2crt;
-		struct v4l2_edid v2edid;
-		unsigned long vx;
-		int vi;
-	} *karg;
 	void __user *up = compat_ptr(arg);
+	void __user *up_native = NULL;
+	void __user *aux_buf;
+	u32 aux_space;
 	int compatible_arg = 1;
 	long err = 0;
 
-	karg = compat_alloc_user_space(sizeof(*karg));
-	if (karg == NULL) {
-		return -EFAULT;
-	}
-
 	/* First, convert the command. */
 	switch (cmd) {
 	case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
@@ -1054,31 +1056,52 @@
 	case VIDIOC_STREAMOFF:
 	case VIDIOC_S_INPUT:
 	case VIDIOC_S_OUTPUT:
-		err = copy_in_user(&karg->vi, (s32 __user *)up,
-			sizeof(karg->vi));
+		err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+		if (!err && assign_in_user((unsigned int __user *)up_native,
+					   (compat_uint_t __user *)up))
+			err = -EFAULT;
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_INPUT:
 	case VIDIOC_G_OUTPUT:
+		err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_EDID:
 	case VIDIOC_S_EDID:
-		err = get_v4l2_edid32(&karg->v2edid, up);
+		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
+		if (!err)
+			err = get_v4l2_edid32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = get_v4l2_format32(&karg->v2f, up);
+		err = bufsize_v4l2_format(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_format),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_format);
+			err = get_v4l2_format32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = get_v4l2_create32(&karg->v2crt, up);
+		err = bufsize_v4l2_create(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_create_buffers),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_create_buffers);
+			err = get_v4l2_create32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
@@ -1086,36 +1109,63 @@
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = get_v4l2_buffer32(&karg->v2b, up);
+		err = bufsize_v4l2_buffer(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_buffer),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_buffer);
+			err = get_v4l2_buffer32(up_native, up,
+						aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_S_FBUF:
-		err = get_v4l2_framebuffer32(&karg->v2fb, up);
+		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+				      &up_native);
+		if (!err)
+			err = get_v4l2_framebuffer32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_FBUF:
+		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+				      &up_native);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = get_v4l2_standard32(&karg->v2s, up);
+		err = alloc_userspace(sizeof(struct v4l2_standard), 0,
+				      &up_native);
+		if (!err)
+			err = get_v4l2_standard32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = get_v4l2_input32(&karg->v2i, up);
+		err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
+		if (!err)
+			err = get_v4l2_input32(up_native, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		err = get_v4l2_ext_controls32(&karg->v2ecs, up);
+		err = bufsize_v4l2_ext_controls(up, &aux_space);
+		if (!err)
+			err = alloc_userspace(sizeof(struct v4l2_ext_controls),
+					      aux_space, &up_native);
+		if (!err) {
+			aux_buf = up_native + sizeof(struct v4l2_ext_controls);
+			err = get_v4l2_ext_controls32(file, up_native, up,
+						      aux_buf, aux_space);
+		}
 		compatible_arg = 0;
 		break;
 	case VIDIOC_DQEVENT:
+		err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
 		compatible_arg = 0;
 		break;
 	}
@@ -1124,18 +1174,26 @@
 
 	if (compatible_arg)
 		err = native_ioctl(file, cmd, (unsigned long)up);
-	else {
-		err = native_ioctl(file, cmd, (unsigned long)karg);
-	}
+	else
+		err = native_ioctl(file, cmd, (unsigned long)up_native);
 
-	/* Special case: even after an error we need to put the
-	   results back for these ioctls since the error_idx will
-	   contain information on which control failed. */
+	if (err == -ENOTTY)
+		return err;
+
+	/*
+	 * Special case: even after an error we need to put the
+	 * results back for these ioctls since the error_idx will
+	 * contain information on which control failed.
+	 */
 	switch (cmd) {
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		if (put_v4l2_ext_controls32(&karg->v2ecs, up))
+		if (put_v4l2_ext_controls32(file, up_native, up))
+			err = -EFAULT;
+		break;
+	case VIDIOC_S_EDID:
+		if (put_v4l2_edid32(up_native, up))
 			err = -EFAULT;
 		break;
 	}
@@ -1147,44 +1205,46 @@
 	case VIDIOC_S_OUTPUT:
 	case VIDIOC_G_INPUT:
 	case VIDIOC_G_OUTPUT:
-		err = copy_in_user(up, &karg->vi, sizeof(s32));
+		if (assign_in_user((compat_uint_t __user *)up,
+				   ((unsigned int __user *)up_native)))
+			err = -EFAULT;
 		break;
 
 	case VIDIOC_G_FBUF:
-		err = put_v4l2_framebuffer32(&karg->v2fb, up);
+		err = put_v4l2_framebuffer32(up_native, up);
 		break;
 
 	case VIDIOC_DQEVENT:
-		err = put_v4l2_event32(&karg->v2ev, up);
+		err = put_v4l2_event32(up_native, up);
 		break;
 
 	case VIDIOC_G_EDID:
-	case VIDIOC_S_EDID:
-		err = put_v4l2_edid32(&karg->v2edid, up);
+		err = put_v4l2_edid32(up_native, up);
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = put_v4l2_format32(&karg->v2f, up);
+		err = put_v4l2_format32(up_native, up);
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = put_v4l2_create32(&karg->v2crt, up);
+		err = put_v4l2_create32(up_native, up);
 		break;
 
+	case VIDIOC_PREPARE_BUF:
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = put_v4l2_buffer32(&karg->v2b, up);
+		err = put_v4l2_buffer32(up_native, up);
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = put_v4l2_standard32(&karg->v2s, up);
+		err = put_v4l2_standard32(up_native, up);
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = put_v4l2_input32(&karg->v2i, up);
+		err = put_v4l2_input32(up_native, up);
 		break;
 	}
 	return err;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 98e5e3b..fa14101 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -307,6 +307,7 @@
 	static const char * const header_mode[] = {
 		"Separate Buffer",
 		"Joined With 1st Frame",
+		"Joined with I Frame",
 		NULL,
 	};
 	static const char * const multi_slice[] = {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 0e48938..e2e23ff 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1371,6 +1371,12 @@
 			descr = "VP9"; break;
 		case V4L2_PIX_FMT_TME:
 			descr = "TME"; break;
+		case V4L2_PIX_FMT_HEVC_HYBRID:
+			descr = "HEVC Hybrid"; break;
+		case V4L2_PIX_FMT_DIVX_311:
+			descr = "DIVX311"; break;
+		case V4L2_PIX_FMT_DIVX:
+			descr = "DIVX"; break;
 		default:
 			WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
 			if (fmt->description[0])
@@ -2946,8 +2952,11 @@
 
 	/* Handles IOCTL */
 	err = func(file, cmd, parg);
-	if (err == -ENOIOCTLCMD)
+	if (err == -ENOTTY || err == -ENOIOCTLCMD) {
 		err = -ENOTTY;
+		goto out;
+	}
+
 	if (err == 0) {
 		if (cmd == VIDIOC_DQBUF)
 			trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 744001a..fb07ce4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,7 +49,8 @@
 obj-$(CONFIG_SRAM)		+= sram.o
 obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
-obj-$(CONFIG_HDCP_QSEECOM)	+= hdcp.o
+obj-$(CONFIG_HDCP_QSEECOM)	+= hdcp_qseecom.o
+obj-$(CONFIG_HDCP_QSEECOM)	+= msm_hdcp.o
 obj-$(CONFIG_QSEECOM)		+= qseecom.o
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
deleted file mode 100644
index eab93cc..0000000
--- a/drivers/misc/hdcp.c
+++ /dev/null
@@ -1,2549 +0,0 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt)	"[hdcp-lib] %s: " fmt, __func__
-
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
-#include <linux/ion.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/errno.h>
-#include <linux/hdcp_qseecom.h>
-#include <linux/kthread.h>
-#include <linux/of.h>
-#include <video/msm_hdmi_hdcp_mgr.h>
-
-#include "qseecom_kernel.h"
-
-#define CLASS_NAME "hdcp"
-#define DRIVER_NAME "msm_hdcp"
-#define TZAPP_NAME            "hdcp2p2"
-#define HDCP1_APP_NAME        "hdcp1"
-#define QSEECOM_SBUFF_SIZE    0x1000
-
-#define MAX_TX_MESSAGE_SIZE	129
-#define MAX_RX_MESSAGE_SIZE	534
-#define MAX_TOPOLOGY_ELEMS	32
-#define HDCP1_AKSV_SIZE         8
-
-/* parameters related to LC_Init message */
-#define MESSAGE_ID_SIZE            1
-#define LC_INIT_MESSAGE_SIZE       (MESSAGE_ID_SIZE+BITS_64_IN_BYTES)
-
-/* parameters related to SKE_Send_EKS message */
-#define SKE_SEND_EKS_MESSAGE_SIZE \
-	(MESSAGE_ID_SIZE+BITS_128_IN_BYTES+BITS_64_IN_BYTES)
-
-/* all message IDs */
-#define INVALID_MESSAGE_ID               0
-#define AKE_INIT_MESSAGE_ID              2
-#define AKE_SEND_CERT_MESSAGE_ID         3
-#define AKE_NO_STORED_KM_MESSAGE_ID      4
-#define AKE_STORED_KM_MESSAGE_ID         5
-#define AKE_SEND_H_PRIME_MESSAGE_ID      7
-#define AKE_SEND_PAIRING_INFO_MESSAGE_ID 8
-#define LC_INIT_MESSAGE_ID               9
-#define LC_SEND_L_PRIME_MESSAGE_ID      10
-#define SKE_SEND_EKS_MESSAGE_ID         11
-#define REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID 12
-#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID      15
-#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
-#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID  17
-#define SKE_SEND_TYPE_ID                       18
-#define HDCP2P2_MAX_MESSAGES                   19
-
-#define HDCP1_SET_KEY_MESSAGE_ID       202
-#define HDCP1_SET_ENC_MESSAGE_ID       205
-
-#define BITS_40_IN_BYTES      5
-#define BITS_64_IN_BYTES      8
-#define BITS_128_IN_BYTES    16
-#define RXCAPS_SIZE           3
-#define RXINFO_SIZE           2
-#define SEQ_NUM_V_SIZE        3
-
-#define RCVR_ID_SIZE BITS_40_IN_BYTES
-#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
-#define MAX_RCVR_ID_LIST_SIZE \
-		(RCVR_ID_SIZE * MAX_RCVR_IDS_ALLOWED_IN_LIST)
-/*
- * Minimum wait as per standard is 200 ms. Keep it 220 ms
- * to be on safe side.
- */
-#define SLEEP_SET_HW_KEY_MS 220
-
-/* hdcp command status */
-#define HDCP_SUCCESS      0
-
-/* flags set by tz in response message */
-#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST       1
-
-#define HDCP_TXMTR_SERVICE_ID                 0x0001000
-#define SERVICE_CREATE_CMD(x)                 (HDCP_TXMTR_SERVICE_ID | x)
-
-#define HDCP_TXMTR_INIT                       SERVICE_CREATE_CMD(1)
-#define HDCP_TXMTR_DEINIT                     SERVICE_CREATE_CMD(2)
-#define HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE   SERVICE_CREATE_CMD(3)
-#define HDCP_TXMTR_SEND_MESSAGE_TIMEOUT       SERVICE_CREATE_CMD(4)
-#define HDCP_TXMTR_SET_HW_KEY                 SERVICE_CREATE_CMD(5)
-#define HDCP_TXMTR_QUERY_STREAM_TYPE          SERVICE_CREATE_CMD(6)
-#define HDCP_LIB_INIT                         SERVICE_CREATE_CMD(11)
-#define HDCP_LIB_DEINIT                       SERVICE_CREATE_CMD(12)
-#define HDCP_TXMTR_GET_VERSION                SERVICE_CREATE_CMD(14)
-#define HDCP_TXMTR_VERIFY_KEY                 SERVICE_CREATE_CMD(15)
-#define HDCP_SESSION_INIT                     SERVICE_CREATE_CMD(16)
-#define HDCP_SESSION_DEINIT                   SERVICE_CREATE_CMD(17)
-#define HDCP_TXMTR_START_AUTHENTICATE         SERVICE_CREATE_CMD(18)
-
-#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
-#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
-#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF)
-
-#define HDCP_CLIENT_MAJOR_VERSION 2
-#define HDCP_CLIENT_MINOR_VERSION 1
-#define HDCP_CLIENT_PATCH_VERSION 0
-#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \
-	((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
-
-#define REAUTH_REQ BIT(3)
-#define LINK_INTEGRITY_FAILURE BIT(4)
-
-#define HDCP_LIB_EXECUTE(x) {\
-		kthread_queue_work(&handle->worker, &handle->wk_##x);\
-}
-
-static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
-	[AKE_INIT_MESSAGE_ID] = { 2,
-		{ {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
-		0 },
-	[AKE_SEND_CERT_MESSAGE_ID] = { 3,
-		{ {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
-			{"RxCaps", 0x6921D, 3} },
-		0 },
-	[AKE_NO_STORED_KM_MESSAGE_ID] = { 1,
-		{ {"Ekpub_km", 0x69220, 128} },
-		0 },
-	[AKE_STORED_KM_MESSAGE_ID] = { 2,
-		{ {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
-		0 },
-	[AKE_SEND_H_PRIME_MESSAGE_ID] = { 1,
-		{ {"H'", 0x692C0, 32} },
-		(1 << 1) },
-	[AKE_SEND_PAIRING_INFO_MESSAGE_ID] =  { 1,
-		{ {"Ekh_km", 0x692E0, 16} },
-		(1 << 2) },
-	[LC_INIT_MESSAGE_ID] = { 1,
-		{ {"rn", 0x692F0, 8} },
-		0 },
-	[LC_SEND_L_PRIME_MESSAGE_ID] = { 1,
-		{ {"L'", 0x692F8, 32} },
-		0 },
-	[SKE_SEND_EKS_MESSAGE_ID] = { 2,
-		{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
-		0 },
-	[SKE_SEND_TYPE_ID] = { 1,
-		{ {"type", 0x69494, 1} },
-		0 },
-	[REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
-		{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
-			{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
-		(1 << 0) },
-	[REPEATER_AUTH_SEND_ACK_MESSAGE_ID] = { 1,
-		{ {"V", 0x693E0, 16} },
-		0 },
-	[REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID] = { 3,
-		{ {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
-			{"streamID_Type", 0x693F5, 126} },
-		0 },
-	[REPEATER_AUTH_STREAM_READY_MESSAGE_ID] = { 1,
-		{ {"M'", 0x69473, 32} },
-		0 }
-};
-
-enum hdcp_state {
-	HDCP_STATE_INIT = 0x00,
-	HDCP_STATE_APP_LOADED = 0x01,
-	HDCP_STATE_SESSION_INIT = 0x02,
-	HDCP_STATE_TXMTR_INIT = 0x04,
-	HDCP_STATE_AUTHENTICATED = 0x08,
-	HDCP_STATE_ERROR = 0x10
-};
-
-enum hdcp_element {
-	HDCP_TYPE_UNKNOWN,
-	HDCP_TYPE_RECEIVER,
-	HDCP_TYPE_REPEATER,
-};
-
-enum hdcp_version {
-	HDCP_VERSION_UNKNOWN,
-	HDCP_VERSION_2_2,
-	HDCP_VERSION_1_4
-};
-
-struct receiver_info {
-	unsigned char rcvrInfo[RCVR_ID_SIZE];
-	enum hdcp_element elem_type;
-	enum hdcp_version hdcp_version;
-};
-
-struct topology_info {
-	unsigned int nNumRcvrs;
-	struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS];
-};
-
-struct __attribute__ ((__packed__)) hdcp1_key_set_req {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp1_key_set_rsp {
-	uint32_t commandid;
-	uint32_t ret;
-	uint8_t ksv[HDCP1_AKSV_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_version_req {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_version_rsp {
-	uint32_t commandid;
-	uint32_t commandId;
-	uint32_t appversion;
-};
-
-struct __attribute__ ((__packed__)) hdcp_verify_key_req {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
-	uint32_t status;
-	uint32_t commandId;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_init_req_v1 {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_init_rsp_v1 {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t message[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_init_req {
-	uint32_t commandid;
-	uint32_t clientversion;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_init_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t appversion;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_deinit_req {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_deinit_rsp {
-	uint32_t status;
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_session_init_req {
-	uint32_t commandid;
-	uint32_t deviceid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_session_init_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t sessionid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_req {
-	uint32_t commandid;
-	uint32_t sessionid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_rsp {
-	uint32_t status;
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_tx_init_req_v1 {
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_tx_init_rsp_v1 {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t message[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_tx_init_req {
-	uint32_t commandid;
-	uint32_t sessionid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_tx_init_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_deinit_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_deinit_rsp {
-	uint32_t status;
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint32_t msglen;
-	uint8_t msg[MAX_RX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t state;
-	uint32_t timeout;
-	uint32_t flag;
-	uint32_t msglen;
-	uint8_t msg[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_set_hw_key_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp {
-	uint32_t status;
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_send_timeout_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t message[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_query_stream_type_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t msg[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_set_stream_type_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint8_t streamtype;
-};
-
-struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t message[MAX_TX_MESSAGE_SIZE];
-};
-
-struct __attribute__ ((__packed__)) hdcp_update_srm_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint32_t srmoffset;
-	uint32_t srmlength;
-};
-
-struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
-	uint32_t status;
-	uint32_t commandid;
-};
-
-struct __attribute__ ((__packed__)) hdcp_get_topology_req {
-	uint32_t commandid;
-	uint32_t ctxhandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_get_topology_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	struct topology_info topologyinfo;
-};
-
-struct __attribute__ ((__packed__)) rxvr_info_struct {
-	uint8_t rcvrCert[522];
-	uint8_t rrx[BITS_64_IN_BYTES];
-	uint8_t rxcaps[RXCAPS_SIZE];
-	bool repeater;
-};
-
-struct __attribute__ ((__packed__)) repeater_info_struct {
-	uint8_t RxInfo[RXINFO_SIZE];
-	uint8_t seq_num_V[SEQ_NUM_V_SIZE];
-	bool seq_num_V_Rollover_flag;
-	uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE];
-	uint32_t ReceiverIDListLen;
-};
-
-struct __attribute__ ((__packed__)) hdcp1_set_enc_req {
-	uint32_t commandid;
-	uint32_t enable;
-};
-
-struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp {
-	uint32_t commandid;
-	uint32_t ret;
-};
-
-struct __attribute__ ((__packed__)) hdcp_start_auth_req {
-	uint32_t commandid;
-	uint32_t ctxHandle;
-};
-
-struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
-	uint32_t status;
-	uint32_t commandid;
-	uint32_t ctxhandle;
-	uint32_t timeout;
-	uint32_t msglen;
-	uint8_t message[MAX_TX_MESSAGE_SIZE];
-};
-
-struct hdcp_lib_handle {
-	unsigned char *listener_buf;
-	uint32_t msglen;
-	uint32_t tz_ctxhandle;
-	uint32_t hdcp_timeout;
-	uint32_t timeout_left;
-	uint32_t wait_timeout;
-	bool no_stored_km_flag;
-	bool feature_supported;
-	bool authenticated;
-	void *client_ctx;
-	struct hdcp_client_ops *client_ops;
-	struct mutex msg_lock;
-	struct mutex wakeup_mutex;
-	enum hdcp_state hdcp_state;
-	enum hdcp_lib_wakeup_cmd wakeup_cmd;
-	bool repeater_flag;
-	bool update_stream;
-	struct qseecom_handle *qseecom_handle;
-	int last_msg_sent;
-	int last_msg;
-	char *last_msg_recvd_buf;
-	uint32_t last_msg_recvd_len;
-	atomic_t hdcp_off;
-	uint32_t session_id;
-	enum hdcp_device_type device_type;
-
-	struct task_struct *thread;
-	struct completion poll_wait;
-
-	struct kthread_worker worker;
-	struct kthread_work wk_init;
-	struct kthread_work wk_msg_sent;
-	struct kthread_work wk_msg_recvd;
-	struct kthread_work wk_timeout;
-	struct kthread_work wk_clean;
-	struct kthread_work wk_wait;
-	struct kthread_work wk_stream;
-
-	int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
-	int (*hdcp_txmtr_init)(struct hdcp_lib_handle *handle);
-};
-
-struct hdcp_lib_message_map {
-	int msg_id;
-	const char *msg_name;
-};
-
-struct msm_hdcp_mgr {
-	struct platform_device *pdev;
-	dev_t dev_num;
-	struct cdev cdev;
-	struct class *class;
-	struct device *device;
-	struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
-	u32 tp_msgid;
-	void *client_ctx;
-	struct hdcp_lib_handle *handle;
-};
-
-static struct msm_hdcp_mgr *hdcp_drv_mgr;
-static struct hdcp_lib_handle *drv_client_handle;
-
-static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
-static void hdcp_lib_init(struct hdcp_lib_handle *handle);
-static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
-static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle);
-static void hdcp_lib_timeout(struct hdcp_lib_handle *handle);
-static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
-static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
-
-static struct qseecom_handle *hdcp1_handle;
-static bool hdcp1_supported = true;
-static bool hdcp1_enc_enabled;
-static struct mutex hdcp1_ta_cmd_lock;
-
-static const char *hdcp_lib_message_name(int msg_id)
-{
-	/*
-	 * Message ID map. The first number indicates the message number
-	 * assigned to the message by the HDCP 2.2 spec. This is also the first
-	 * byte of every HDCP 2.2 authentication protocol message.
-	 */
-	static struct hdcp_lib_message_map hdcp_lib_msg_map[] = {
-		{2, "AKE_INIT"},
-		{3, "AKE_SEND_CERT"},
-		{4, "AKE_NO_STORED_KM"},
-		{5, "AKE_STORED_KM"},
-		{7, "AKE_SEND_H_PRIME"},
-		{8, "AKE_SEND_PAIRING_INFO"},
-		{9, "LC_INIT"},
-		{10, "LC_SEND_L_PRIME"},
-		{11, "SKE_SEND_EKS"},
-		{12, "REPEATER_AUTH_SEND_RECEIVERID_LIST"},
-		{15, "REPEATER_AUTH_SEND_ACK"},
-		{16, "REPEATER_AUTH_STREAM_MANAGE"},
-		{17, "REPEATER_AUTH_STREAM_READY"},
-		{18, "SKE_SEND_TYPE_ID"},
-	};
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(hdcp_lib_msg_map); i++) {
-		if (msg_id == hdcp_lib_msg_map[i].msg_id)
-			return hdcp_lib_msg_map[i].msg_name;
-	}
-	return "UNKNOWN";
-}
-
-static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
-				     struct hdcp_wakeup_data *data)
-{
-	switch (handle->last_msg) {
-	case INVALID_MESSAGE_ID:
-		return AKE_INIT_MESSAGE_ID;
-	case AKE_INIT_MESSAGE_ID:
-		return AKE_SEND_CERT_MESSAGE_ID;
-	case AKE_SEND_CERT_MESSAGE_ID:
-		if (handle->no_stored_km_flag)
-			return AKE_NO_STORED_KM_MESSAGE_ID;
-		else
-			return AKE_STORED_KM_MESSAGE_ID;
-	case AKE_STORED_KM_MESSAGE_ID:
-	case AKE_NO_STORED_KM_MESSAGE_ID:
-		return AKE_SEND_H_PRIME_MESSAGE_ID;
-	case AKE_SEND_H_PRIME_MESSAGE_ID:
-		if (handle->no_stored_km_flag)
-			return AKE_SEND_PAIRING_INFO_MESSAGE_ID;
-		else
-			return LC_INIT_MESSAGE_ID;
-	case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
-		return LC_INIT_MESSAGE_ID;
-	case LC_INIT_MESSAGE_ID:
-		return LC_SEND_L_PRIME_MESSAGE_ID;
-	case LC_SEND_L_PRIME_MESSAGE_ID:
-		return SKE_SEND_EKS_MESSAGE_ID;
-	case SKE_SEND_EKS_MESSAGE_ID:
-		if (!handle->repeater_flag)
-			return SKE_SEND_TYPE_ID;
-	case SKE_SEND_TYPE_ID:
-	case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
-	case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
-		if (!handle->repeater_flag)
-			return INVALID_MESSAGE_ID;
-
-		if (data->cmd == HDCP_WKUP_CMD_SEND_MESSAGE)
-			return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
-		else
-			return REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID;
-	case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
-		return REPEATER_AUTH_SEND_ACK_MESSAGE_ID;
-	case REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID:
-		return REPEATER_AUTH_STREAM_READY_MESSAGE_ID;
-	default:
-		pr_err("Uknown message ID (%d)", handle->last_msg);
-		return -EINVAL;
-	}
-}
-
-static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
-				       struct hdcp_wakeup_data *data)
-{
-	switch (handle->last_msg) {
-	case AKE_SEND_H_PRIME_MESSAGE_ID:
-		if (handle->no_stored_km_flag)
-			handle->wait_timeout = HZ;
-		else
-			handle->wait_timeout = HZ / 4;
-		break;
-	case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
-		handle->wait_timeout = HZ / 4;
-		break;
-	case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
-		if (!handle->authenticated)
-			handle->wait_timeout = HZ * 3;
-		else
-			handle->wait_timeout = 0;
-		break;
-	default:
-		handle->wait_timeout = 0;
-	}
-
-	if (handle->wait_timeout)
-		kthread_queue_work(&handle->worker, &handle->wk_wait);
-}
-
-static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
-				  struct hdcp_wakeup_data *data)
-{
-	int rc = 0, i;
-
-	if (!handle || !handle->client_ops || !handle->client_ops->wakeup ||
-	    !data || (data->cmd == HDCP_WKUP_CMD_INVALID))
-		return;
-
-	data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
-
-	if (data->cmd == HDCP_WKUP_CMD_RECV_MESSAGE ||
-	    data->cmd == HDCP_WKUP_CMD_LINK_POLL)
-		handle->last_msg = hdcp_lib_get_next_message(handle, data);
-
-	if (handle->last_msg != INVALID_MESSAGE_ID &&
-	    data->cmd != HDCP_WKUP_CMD_STATUS_SUCCESS &&
-	    data->cmd != HDCP_WKUP_CMD_STATUS_FAILED) {
-		u32 msg_num, rx_status;
-		const struct hdcp_msg_part *msg;
-
-		pr_debug("lib->client: %s (%s)\n",
-			hdcp_cmd_to_str(data->cmd),
-			hdcp_lib_message_name(handle->last_msg));
-
-		data->message_data = &hdcp_msg_lookup[handle->last_msg];
-
-		msg_num = data->message_data->num_messages;
-		msg = data->message_data->messages;
-		rx_status = data->message_data->rx_status;
-
-		pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
-
-		for (i = 0; i < msg_num; i++)
-			pr_debug("%10s | %6x | %4d\n",
-				msg[i].name, msg[i].offset,
-				msg[i].length);
-	} else {
-		pr_debug("lib->client: %s\n", hdcp_cmd_to_str(data->cmd));
-	}
-
-	rc = handle->client_ops->wakeup(data);
-	if (rc)
-		pr_err("error sending %s to client\n",
-		       hdcp_cmd_to_str(data->cmd));
-
-	hdcp_lib_wait_for_response(handle, data);
-}
-
-static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
-{
-	char msg_name[50];
-	struct hdcp_wakeup_data cdata = {
-		HDCP_WKUP_CMD_SEND_MESSAGE
-	};
-
-	cdata.context = handle->client_ctx;
-	cdata.send_msg_buf = handle->listener_buf;
-	cdata.send_msg_len = handle->msglen;
-	cdata.timeout = handle->hdcp_timeout;
-
-	snprintf(msg_name, sizeof(msg_name), "%s: ",
-		hdcp_lib_message_name((int)cdata.send_msg_buf[0]));
-
-	print_hex_dump(KERN_DEBUG, msg_name,
-		DUMP_PREFIX_NONE, 16, 1, cdata.send_msg_buf,
-		cdata.send_msg_len, false);
-
-	hdcp_lib_wakeup_client(handle, &cdata);
-}
-
-static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_set_hw_key_req *req_buf;
-	struct hdcp_set_hw_key_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto error;
-	}
-
-	/*
-	 * wait at least 200ms before enabling encryption
-	 * as per hdcp2p2 sepcifications.
-	 */
-	msleep(SLEEP_SET_HW_KEY_MS);
-
-	req_buf = (struct hdcp_set_hw_key_req *)(handle->qseecom_handle->sbuf);
-	req_buf->commandid = HDCP_TXMTR_SET_HW_KEY;
-	req_buf->ctxhandle = handle->tz_ctxhandle;
-
-	rsp_buf = (struct hdcp_set_hw_key_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_set_hw_key_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_set_hw_key_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_set_hw_key_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status < 0)) {
-		pr_err("qseecom cmd failed with err = %d status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto error;
-	}
-
-	/* reached an authenticated state */
-	handle->hdcp_state |= HDCP_STATE_AUTHENTICATED;
-
-	pr_debug("success\n");
-	return 0;
-error:
-	if (handle && !atomic_read(&handle->hdcp_off))
-		HDCP_LIB_EXECUTE(clean);
-
-	return rc;
-}
-
-static int hdcp_lib_get_version(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_version_req *req_buf;
-	struct hdcp_version_rsp *rsp_buf;
-	uint32_t app_major_version = 0;
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("library not loaded\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	/* get the TZ hdcp2p2 app version */
-	req_buf = (struct hdcp_version_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_GET_VERSION;
-
-	rsp_buf = (struct hdcp_version_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_version_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle,
-				  req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_init_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_init_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err = %d\n", rc);
-		goto exit;
-	}
-
-	app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion);
-
-	pr_debug("hdcp2p2 app major version %d, app version %d\n",
-		 app_major_version, rsp_buf->appversion);
-
-exit:
-	return rc;
-}
-
-static int hdcp_lib_verify_keys(struct hdcp_lib_handle *handle)
-{
-	int rc = -EINVAL;
-	struct hdcp_verify_key_req *req_buf;
-	struct hdcp_verify_key_rsp *rsp_buf;
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("app not loaded\n");
-		goto exit;
-	}
-
-	req_buf = (struct hdcp_verify_key_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_VERIFY_KEY;
-
-	rsp_buf = (struct hdcp_verify_key_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_verify_key_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle,
-				  req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_verify_key_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_verify_key_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err = %d\n", rc);
-		goto exit;
-	}
-
-	return rsp_buf->status;
-exit:
-	return rc;
-}
-
-static int hdcp_app_init(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_lib_init_req *req_buf;
-	struct hdcp_lib_init_rsp *rsp_buf;
-	uint32_t app_minor_version = 0;
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("library not loaded\n");
-		goto exit;
-	}
-
-	/* now load the app by sending hdcp_lib_init */
-	req_buf = (struct hdcp_lib_init_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_LIB_INIT;
-	req_buf->clientversion =
-	    HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION,
-				     HDCP_CLIENT_MINOR_VERSION,
-				     HDCP_CLIENT_PATCH_VERSION);
-	rsp_buf = (struct hdcp_lib_init_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_init_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle,
-				  req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_init_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_init_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err = %d\n", rc);
-		goto exit;
-	}
-
-	app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion);
-	if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) {
-		pr_err
-		    ("client-app minor version mismatch app(%d), client(%d)\n",
-		     app_minor_version, HDCP_CLIENT_MINOR_VERSION);
-		rc = -1;
-		goto exit;
-	}
-	pr_debug("success\n");
-	pr_debug("client version major(%d), minor(%d), patch(%d)\n",
-		 HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION,
-		 HDCP_CLIENT_PATCH_VERSION);
-	pr_debug("app version major(%d), minor(%d), patch(%d)\n",
-		 HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion),
-		 HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion),
-		 HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion));
-
-exit:
-	return rc;
-}
-
-static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		goto exit;
-	}
-
-	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
-		pr_err("library already loaded\n");
-		goto exit;
-	}
-
-	/*
-	 * allocating resource for qseecom handle
-	 * the app is not loaded here
-	 */
-	rc = qseecom_start_app(&(handle->qseecom_handle),
-			       TZAPP_NAME, QSEECOM_SBUFF_SIZE);
-	if (rc) {
-		pr_err("qseecom_start_app failed %d\n", rc);
-		goto exit;
-	}
-
-	handle->hdcp_state |= HDCP_STATE_APP_LOADED;
-	pr_debug("qseecom_start_app success\n");
-
-	rc = hdcp_lib_get_version(handle);
-	if (rc) {
-		pr_err("library get version failed\n");
-		goto exit;
-	}
-
-	handle->hdcp_app_init = hdcp_app_init;
-	handle->hdcp_txmtr_init = hdcp_lib_txmtr_init;
-
-	if (handle->hdcp_app_init == NULL) {
-		pr_err("invalid app init function pointer\n");
-		goto exit;
-	}
-
-	rc = handle->hdcp_app_init(handle);
-	if (rc) {
-		pr_err("app init failed\n");
-		goto exit;
-	}
-exit:
-	return rc;
-}
-
-static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_lib_deinit_req *req_buf;
-	struct hdcp_lib_deinit_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("library not loaded\n");
-		return rc;
-	}
-
-	/* unloading app by sending hdcp_lib_deinit cmd */
-	req_buf = (struct hdcp_lib_deinit_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_LIB_DEINIT;
-	rsp_buf = (struct hdcp_lib_deinit_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_deinit_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle,
-				  req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_deinit_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_lib_deinit_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err = %d\n", rc);
-		goto exit;
-	}
-
-	/* deallocate the resources for qseecom handle */
-	rc = qseecom_shutdown_app(&handle->qseecom_handle);
-	if (rc) {
-		pr_err("qseecom_shutdown_app failed err: %d\n", rc);
-		goto exit;
-	}
-
-	handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static int hdcp_lib_session_init(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_lib_session_init_req *req_buf;
-	struct hdcp_lib_session_init_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("app not loaded\n");
-		goto exit;
-	}
-
-	if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) {
-		pr_err("session already initialized\n");
-		goto exit;
-	}
-
-	/* send HDCP_Session_Init command to TZ */
-	req_buf =
-	    (struct hdcp_lib_session_init_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_SESSION_INIT;
-	req_buf->deviceid = handle->device_type;
-	rsp_buf = (struct hdcp_lib_session_init_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_init_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_lib_session_init_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_lib_session_init_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
-	    (rsp_buf->commandid != HDCP_SESSION_INIT)) {
-		pr_err("qseecom cmd failed with err = %d, status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	pr_debug("session id %d\n", rsp_buf->sessionid);
-
-	handle->session_id = rsp_buf->sessionid;
-	handle->hdcp_state |= HDCP_STATE_SESSION_INIT;
-
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static int hdcp_lib_session_deinit(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_lib_session_deinit_req *req_buf;
-	struct hdcp_lib_session_deinit_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("app not loaded\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
-		/* unload library here */
-		pr_err("session not initialized\n");
-		goto exit;
-	}
-
-	/* send command to TZ */
-	req_buf =
-	    (struct hdcp_lib_session_deinit_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_SESSION_DEINIT;
-	req_buf->sessionid = handle->session_id;
-	rsp_buf = (struct hdcp_lib_session_deinit_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_deinit_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_lib_session_deinit_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_lib_session_deinit_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status < 0) ||
-	    (rsp_buf->commandid != HDCP_SESSION_DEINIT)) {
-		pr_err("qseecom cmd failed with err = %d status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT;
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_tx_init_req *req_buf;
-	struct hdcp_tx_init_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
-		pr_err("session not initialized\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("library not loaded\n");
-		goto exit;
-	}
-
-	/* send HDCP_Txmtr_Init command to TZ */
-	req_buf = (struct hdcp_tx_init_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_INIT;
-	req_buf->sessionid = handle->session_id;
-	rsp_buf = (struct hdcp_tx_init_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_tx_init_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_tx_init_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_tx_init_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
-	    (rsp_buf->commandid != HDCP_TXMTR_INIT)) {
-		pr_err("qseecom cmd failed with err = %d, status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	handle->tz_ctxhandle = rsp_buf->ctxhandle;
-	handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
-
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static int hdcp_lib_txmtr_deinit(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_deinit_req *req_buf;
-	struct hdcp_deinit_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		pr_err("app not loaded\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
-		/* unload library here */
-		pr_err("txmtr not initialized\n");
-		goto exit;
-	}
-
-	/* send command to TZ */
-	req_buf = (struct hdcp_deinit_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_DEINIT;
-	req_buf->ctxhandle = handle->tz_ctxhandle;
-	rsp_buf = (struct hdcp_deinit_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_deinit_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status < 0) ||
-	    (rsp_buf->commandid != HDCP_TXMTR_DEINIT)) {
-		pr_err("qseecom cmd failed with err = %d status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT;
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_start_auth_req *req_buf;
-	struct hdcp_start_auth_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
-		pr_err("session not initialized\n");
-		goto exit;
-	}
-
-	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
-		pr_err("txmtr not initialized\n");
-		goto exit;
-	}
-
-	/* send HDCP_Txmtr_Start_Auth command to TZ */
-	req_buf = (struct hdcp_start_auth_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_START_AUTHENTICATE;
-	req_buf->ctxHandle = handle->tz_ctxhandle;
-	rsp_buf = (struct hdcp_start_auth_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_start_auth_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_start_auth_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_start_auth_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
-	    (rsp_buf->commandid != HDCP_TXMTR_START_AUTHENTICATE) ||
-	    (rsp_buf->msglen <= 0) || (rsp_buf->message == NULL)) {
-		pr_err("qseecom cmd failed with err = %d, status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	pr_debug("recvd %s from TZ at %dms\n",
-		 hdcp_lib_message_name((int)rsp_buf->message[0]),
-		 jiffies_to_msecs(jiffies));
-
-	handle->last_msg = (int)rsp_buf->message[0];
-
-	/* send the response to HDMI driver */
-	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
-	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
-	       rsp_buf->msglen);
-	handle->msglen = rsp_buf->msglen;
-	handle->hdcp_timeout = rsp_buf->timeout;
-
-	handle->tz_ctxhandle = rsp_buf->ctxhandle;
-
-	pr_debug("success\n");
-exit:
-	return rc;
-}
-
-static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_query_stream_type_req *req_buf;
-	struct hdcp_query_stream_type_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		return;
-	}
-
-	if (atomic_read(&handle->hdcp_off)) {
-		pr_debug("invalid state, hdcp off\n");
-		return;
-	}
-
-	if (!handle->repeater_flag) {
-		pr_debug("invalid state, not a repeater\n");
-		return;
-	}
-
-	/* send command to TZ */
-	req_buf =
-	    (struct hdcp_query_stream_type_req *)handle->qseecom_handle->sbuf;
-	req_buf->commandid = HDCP_TXMTR_QUERY_STREAM_TYPE;
-	req_buf->ctxhandle = handle->tz_ctxhandle;
-	rsp_buf = (struct hdcp_query_stream_type_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	     QSEECOM_ALIGN(sizeof(struct hdcp_query_stream_type_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_query_stream_type_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_query_stream_type_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status < 0) || (rsp_buf->msglen <= 0) ||
-	    (rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
-	    (rsp_buf->msg == NULL)) {
-		pr_err("qseecom cmd failed with err=%d status=%d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	pr_debug("message received from TZ: %s\n",
-		 hdcp_lib_message_name((int)rsp_buf->msg[0]));
-
-	handle->last_msg = (int)rsp_buf->msg[0];
-
-	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
-	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
-	       rsp_buf->msglen);
-	handle->hdcp_timeout = rsp_buf->timeout;
-	handle->msglen = rsp_buf->msglen;
-exit:
-	if (!rc && !atomic_read(&handle->hdcp_off))
-		hdcp_lib_send_message(handle);
-}
-
-static void hdcp_lib_query_stream_work(struct kthread_work *work)
-{
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_stream);
-
-	hdcp_lib_stream(handle);
-}
-
-static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
-{
-	int rc = 0;
-	bool supported = false;
-	struct hdcp_lib_handle *handle = phdcpcontext;
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		goto exit;
-	}
-
-	if (handle->feature_supported) {
-		supported = true;
-		goto exit;
-	}
-
-	rc = hdcp_lib_library_load(handle);
-	if (!rc) {
-		if (!hdcp_lib_verify_keys(handle)) {
-			pr_debug("HDCP2p2 supported\n");
-			handle->feature_supported = true;
-			supported = true;
-		}
-		hdcp_lib_library_unload(handle);
-	}
-exit:
-	return supported;
-}
-
-static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
-{
-	if (!list_empty(&handle->wk_init.node))
-		pr_debug("init work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_init)
-		pr_debug("init work executing\n");
-
-	if (!list_empty(&handle->wk_msg_sent.node))
-		pr_debug("msg_sent work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_msg_sent)
-		pr_debug("msg_sent work executing\n");
-
-	if (!list_empty(&handle->wk_msg_recvd.node))
-		pr_debug("msg_recvd work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_msg_recvd)
-		pr_debug("msg_recvd work executing\n");
-
-	if (!list_empty(&handle->wk_timeout.node))
-		pr_debug("timeout work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_timeout)
-		pr_debug("timeout work executing\n");
-
-	if (!list_empty(&handle->wk_clean.node))
-		pr_debug("clean work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_clean)
-		pr_debug("clean work executing\n");
-
-	if (!list_empty(&handle->wk_wait.node))
-		pr_debug("wait work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_wait)
-		pr_debug("wait work executing\n");
-
-	if (!list_empty(&handle->wk_stream.node))
-		pr_debug("stream work queued\n");
-
-	if (handle->worker.current_work == &handle->wk_stream)
-		pr_debug("stream work executing\n");
-}
-
-static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-
-	if (!list_empty(&handle->worker.work_list))
-		hdcp_lib_check_worker_status(handle);
-
-	if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
-		if (!list_empty(&handle->worker.work_list)) {
-			pr_debug("error: queue not empty\n");
-			rc = -EBUSY;
-			goto exit;
-		}
-
-		if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
-			pr_debug("library already loaded\n");
-			rc = -EBUSY;
-			goto exit;
-		}
-	} else {
-		if (atomic_read(&handle->hdcp_off)) {
-			pr_debug("hdcp2.2 session tearing down\n");
-			goto exit;
-		}
-
-		if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-			pr_debug("hdcp 2.2 app not loaded\n");
-			goto exit;
-		}
-	}
-exit:
-	return rc;
-}
-
-static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
-{
-	struct hdcp_lib_handle *handle;
-	int rc = 0;
-
-	if (!data)
-		return -EINVAL;
-
-	handle = data->context;
-	if (!handle)
-		return -EINVAL;
-
-	mutex_lock(&handle->wakeup_mutex);
-
-	handle->wakeup_cmd = data->cmd;
-	handle->timeout_left = data->timeout;
-
-	pr_debug("client->lib: %s (%s)\n",
-		hdcp_lib_cmd_to_str(data->cmd),
-		hdcp_lib_message_name(handle->last_msg));
-
-	rc = hdcp_lib_check_valid_state(handle);
-	if (rc)
-		goto exit;
-
-	mutex_lock(&handle->msg_lock);
-	if (data->recvd_msg_len) {
-		kzfree(handle->last_msg_recvd_buf);
-
-		handle->last_msg_recvd_len = data->recvd_msg_len;
-		handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len,
-						     GFP_KERNEL);
-		if (!handle->last_msg_recvd_buf) {
-			rc = -ENOMEM;
-			mutex_unlock(&handle->msg_lock);
-			goto exit;
-		}
-
-		memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
-		       data->recvd_msg_len);
-	}
-	mutex_unlock(&handle->msg_lock);
-
-	if (!completion_done(&handle->poll_wait))
-		complete_all(&handle->poll_wait);
-
-	switch (handle->wakeup_cmd) {
-	case HDCP_LIB_WKUP_CMD_START:
-		handle->no_stored_km_flag = 0;
-		handle->repeater_flag = false;
-		handle->update_stream = false;
-		handle->last_msg_sent = 0;
-		handle->last_msg = INVALID_MESSAGE_ID;
-		handle->hdcp_timeout = 0;
-		handle->timeout_left = 0;
-		atomic_set(&handle->hdcp_off, 0);
-		handle->hdcp_state = HDCP_STATE_INIT;
-
-		HDCP_LIB_EXECUTE(init);
-		break;
-	case HDCP_LIB_WKUP_CMD_STOP:
-		atomic_set(&handle->hdcp_off, 1);
-
-		HDCP_LIB_EXECUTE(clean);
-		break;
-	case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
-		handle->last_msg_sent = handle->listener_buf[0];
-
-		HDCP_LIB_EXECUTE(msg_sent);
-		break;
-	case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
-	case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
-	case HDCP_LIB_WKUP_CMD_LINK_FAILED:
-		handle->hdcp_state |= HDCP_STATE_ERROR;
-		HDCP_LIB_EXECUTE(clean);
-		break;
-	case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
-		HDCP_LIB_EXECUTE(msg_recvd);
-		break;
-	case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
-		HDCP_LIB_EXECUTE(timeout);
-		break;
-	case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
-		HDCP_LIB_EXECUTE(stream);
-		break;
-	default:
-		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
-	}
-exit:
-	mutex_unlock(&handle->wakeup_mutex);
-
-	return rc;
-}
-
-static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
-{
-	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
-
-	if (!handle) {
-		pr_err("invalid handle\n");
-		return;
-	}
-
-	cdata.context = handle->client_ctx;
-
-	switch (handle->last_msg_sent) {
-	case SKE_SEND_TYPE_ID:
-		if (!hdcp_lib_enable_encryption(handle)) {
-			handle->authenticated = true;
-
-			cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
-			hdcp_lib_wakeup_client(handle, &cdata);
-		}
-
-		/* poll for link check */
-		cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
-		break;
-	case SKE_SEND_EKS_MESSAGE_ID:
-		if (handle->repeater_flag) {
-			/* poll for link check */
-			cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
-		} else {
-			memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
-			handle->listener_buf[0] = SKE_SEND_TYPE_ID;
-			handle->msglen = 2;
-			cdata.cmd = HDCP_WKUP_CMD_SEND_MESSAGE;
-			cdata.send_msg_buf = handle->listener_buf;
-			cdata.send_msg_len = handle->msglen;
-			handle->last_msg = hdcp_lib_get_next_message(handle,
-						&cdata);
-		}
-		break;
-	case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
-		pr_debug("Repeater authentication successful\n");
-
-		if (handle->update_stream) {
-			HDCP_LIB_EXECUTE(stream);
-			handle->update_stream = false;
-		} else {
-			cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
-		}
-		break;
-	default:
-		cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
-		cdata.timeout = handle->timeout_left;
-	}
-
-	hdcp_lib_wakeup_client(handle, &cdata);
-}
-
-static void hdcp_lib_msg_sent_work(struct kthread_work *work)
-{
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_msg_sent);
-
-	if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
-		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
-		return;
-	}
-
-	hdcp_lib_msg_sent(handle);
-}
-
-static void hdcp_lib_init(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-
-	if (!handle) {
-		pr_err("invalid handle\n");
-		return;
-	}
-
-	if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) {
-		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
-		return;
-	}
-
-	rc = hdcp_lib_library_load(handle);
-	if (rc)
-		goto exit;
-
-	rc = hdcp_lib_session_init(handle);
-	if (rc)
-		goto exit;
-
-	if (handle->hdcp_txmtr_init == NULL) {
-		pr_err("invalid txmtr init function pointer\n");
-		return;
-	}
-
-	rc = handle->hdcp_txmtr_init(handle);
-	if (rc)
-		goto exit;
-
-	rc = hdcp_lib_start_auth(handle);
-	if (rc)
-		goto exit;
-
-	hdcp_lib_send_message(handle);
-
-	return;
-exit:
-	HDCP_LIB_EXECUTE(clean);
-}
-
-static void hdcp_lib_init_work(struct kthread_work *work)
-{
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_init);
-
-	hdcp_lib_init(handle);
-}
-
-static void hdcp_lib_timeout(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_send_timeout_req *req_buf;
-	struct hdcp_send_timeout_rsp *rsp_buf;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_debug("invalid handle\n");
-		return;
-	}
-
-	if (atomic_read(&handle->hdcp_off)) {
-		pr_debug("invalid state, hdcp off\n");
-		return;
-	}
-
-	req_buf = (struct hdcp_send_timeout_req *)
-	    (handle->qseecom_handle->sbuf);
-	req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
-	req_buf->ctxhandle = handle->tz_ctxhandle;
-
-	rsp_buf = (struct hdcp_send_timeout_rsp *)
-	    (handle->qseecom_handle->sbuf +
-	    QSEECOM_ALIGN(sizeof(struct hdcp_send_timeout_req)));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_send_timeout_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct
-						 hdcp_send_timeout_rsp)));
-
-	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
-		pr_err("qseecom cmd failed for with err = %d status = %d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto error;
-	}
-
-	if (rsp_buf->commandid == HDCP_TXMTR_SEND_MESSAGE_TIMEOUT) {
-		pr_err("HDCP_TXMTR_SEND_MESSAGE_TIMEOUT\n");
-		rc = -EINVAL;
-		goto error;
-	}
-
-	/*
-	 * if the response contains LC_Init message
-	 * send the message again to TZ
-	 */
-	if ((rsp_buf->commandid == HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) &&
-	    ((int)rsp_buf->message[0] == LC_INIT_MESSAGE_ID) &&
-	    (rsp_buf->msglen == LC_INIT_MESSAGE_SIZE)) {
-		if (!atomic_read(&handle->hdcp_off)) {
-			/* keep local copy of TZ response */
-			memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
-			memcpy(handle->listener_buf,
-			       (unsigned char *)rsp_buf->message,
-			       rsp_buf->msglen);
-			handle->hdcp_timeout = rsp_buf->timeout;
-			handle->msglen = rsp_buf->msglen;
-
-			hdcp_lib_send_message(handle);
-		}
-	}
-
-	return;
-error:
-	if (!atomic_read(&handle->hdcp_off))
-		HDCP_LIB_EXECUTE(clean);
-}
-
-static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
-{
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_timeout);
-
-	hdcp_lib_timeout(handle);
-}
-
-static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
-{
-	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		return;
-	}
-
-	handle->authenticated = false;
-
-	hdcp_lib_txmtr_deinit(handle);
-	hdcp_lib_session_deinit(handle);
-	hdcp_lib_library_unload(handle);
-
-	cdata.context = handle->client_ctx;
-	cdata.cmd = HDCP_WKUP_CMD_STATUS_FAILED;
-
-	if (!atomic_read(&handle->hdcp_off))
-		hdcp_lib_wakeup_client(handle, &cdata);
-
-	atomic_set(&handle->hdcp_off, 1);
-}
-
-static void hdcp_lib_cleanup_work(struct kthread_work *work)
-{
-
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_clean);
-
-	hdcp_lib_clean(handle);
-}
-
-static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
-{
-	int rc = 0;
-	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
-	struct hdcp_rcvd_msg_req *req_buf;
-	struct hdcp_rcvd_msg_rsp *rsp_buf;
-	uint32_t msglen;
-	char *msg = NULL;
-	char msg_name[50];
-	uint32_t message_id_bytes = 0;
-
-	if (!handle || !handle->qseecom_handle ||
-	    !handle->qseecom_handle->sbuf) {
-		pr_err("invalid handle\n");
-		return;
-	}
-
-	if (atomic_read(&handle->hdcp_off)) {
-		pr_debug("invalid state, hdcp off\n");
-		return;
-	}
-
-	cdata.context = handle->client_ctx;
-
-	mutex_lock(&handle->msg_lock);
-	msglen = handle->last_msg_recvd_len;
-
-	if (msglen <= 0) {
-		pr_err("invalid msg len\n");
-		mutex_unlock(&handle->msg_lock);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	/* If the client is DP then allocate extra byte for message ID. */
-	if (handle->device_type == HDCP_TXMTR_DP)
-		message_id_bytes = 1;
-
-	msglen += message_id_bytes;
-
-	msg = kzalloc(msglen, GFP_KERNEL);
-	if (!msg) {
-		mutex_unlock(&handle->msg_lock);
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-	/* copy the message id if needed */
-	if (message_id_bytes)
-		memcpy(msg, &handle->last_msg, message_id_bytes);
-
-	memcpy(msg + message_id_bytes,
-		handle->last_msg_recvd_buf,
-		handle->last_msg_recvd_len);
-
-	mutex_unlock(&handle->msg_lock);
-
-	snprintf(msg_name, sizeof(msg_name), "%s: ",
-		hdcp_lib_message_name((int)msg[0]));
-
-	print_hex_dump(KERN_DEBUG, msg_name,
-		DUMP_PREFIX_NONE, 16, 1, msg, msglen, false);
-
-	/* send the message to QSEECOM */
-	req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
-	req_buf->commandid = HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE;
-	memcpy(req_buf->msg, msg, msglen);
-	req_buf->msglen = msglen;
-	req_buf->ctxhandle = handle->tz_ctxhandle;
-
-	rsp_buf =
-	    (struct hdcp_rcvd_msg_rsp *)(handle->qseecom_handle->sbuf +
-					 QSEECOM_ALIGN(sizeof
-						       (struct
-							hdcp_rcvd_msg_req)));
-
-	pr_debug("writing %s to TZ at %dms\n",
-		 hdcp_lib_message_name((int)msg[0]), jiffies_to_msecs(jiffies));
-
-	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_rcvd_msg_req)),
-				  rsp_buf,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp_rcvd_msg_rsp)));
-
-	/* get next message from sink if we receive H PRIME on no store km */
-	if ((msg[0] == AKE_SEND_H_PRIME_MESSAGE_ID) &&
-	    handle->no_stored_km_flag) {
-		handle->hdcp_timeout = rsp_buf->timeout;
-
-		cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
-		cdata.timeout = handle->hdcp_timeout;
-
-		goto exit;
-	}
-
-	if ((msg[0] == REPEATER_AUTH_STREAM_READY_MESSAGE_ID) &&
-	    (rc == 0) && (rsp_buf->status == 0)) {
-		pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
-
-		if (!handle->authenticated &&
-		    !hdcp_lib_enable_encryption(handle)) {
-			handle->authenticated = true;
-
-			cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
-			hdcp_lib_wakeup_client(handle, &cdata);
-		}
-
-		cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
-		goto exit;
-	}
-
-	if ((rc < 0) || (rsp_buf->status != 0) || (rsp_buf->msglen <= 0) ||
-	    (rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
-	    (rsp_buf->msg == NULL)) {
-		pr_err("qseecom cmd failed with err=%d status=%d\n",
-		       rc, rsp_buf->status);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	pr_debug("recvd %s from TZ at %dms\n",
-		 hdcp_lib_message_name((int)rsp_buf->msg[0]),
-		 jiffies_to_msecs(jiffies));
-
-	handle->last_msg = (int)rsp_buf->msg[0];
-
-	/* set the flag if response is AKE_No_Stored_km */
-	if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
-		pr_debug("Setting no_stored_km_flag\n");
-		handle->no_stored_km_flag = 1;
-	} else {
-		handle->no_stored_km_flag = 0;
-	}
-
-	/* check if it's a repeater */
-	if ((rsp_buf->msg[0] == SKE_SEND_EKS_MESSAGE_ID) &&
-	    (rsp_buf->msglen == SKE_SEND_EKS_MESSAGE_SIZE)) {
-		if ((rsp_buf->flag ==
-		     HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) &&
-		    (rsp_buf->timeout > 0))
-			handle->repeater_flag = true;
-		handle->update_stream = true;
-	}
-
-	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
-	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
-	       rsp_buf->msglen);
-	handle->hdcp_timeout = rsp_buf->timeout;
-	handle->msglen = rsp_buf->msglen;
-
-	if (!atomic_read(&handle->hdcp_off))
-		hdcp_lib_send_message(handle);
-exit:
-	kzfree(msg);
-
-	hdcp_lib_wakeup_client(handle, &cdata);
-
-	if (rc && !atomic_read(&handle->hdcp_off))
-		HDCP_LIB_EXECUTE(clean);
-}
-
-static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
-{
-	struct hdcp_lib_handle *handle = container_of(work,
-						      struct hdcp_lib_handle,
-						      wk_msg_recvd);
-
-	hdcp_lib_msg_recvd(handle);
-}
-
-static void hdcp_lib_wait_work(struct kthread_work *work)
-{
-	u32 timeout;
-	struct hdcp_lib_handle *handle = container_of(work,
-				struct hdcp_lib_handle, wk_wait);
-
-	if (!handle) {
-		pr_err("invalid input\n");
-		return;
-	}
-
-	if (atomic_read(&handle->hdcp_off)) {
-		pr_debug("invalid state: hdcp off\n");
-		return;
-	}
-
-	if (handle->hdcp_state & HDCP_STATE_ERROR) {
-		pr_debug("invalid state: hdcp error\n");
-		return;
-	}
-
-	reinit_completion(&handle->poll_wait);
-	timeout = wait_for_completion_timeout(&handle->poll_wait,
-			handle->wait_timeout);
-	if (!timeout) {
-		pr_err("wait timeout\n");
-
-		if (!atomic_read(&handle->hdcp_off))
-			HDCP_LIB_EXECUTE(clean);
-	}
-
-	handle->wait_timeout = 0;
-}
-
-bool hdcp1_check_if_supported_load_app(void)
-{
-	int rc = 0;
-
-	/* start hdcp1 app */
-	if (hdcp1_supported && !hdcp1_handle) {
-		rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
-				       QSEECOM_SBUFF_SIZE);
-		if (rc) {
-			pr_err("qseecom_start_app failed %d\n", rc);
-			hdcp1_supported = false;
-		} else {
-			mutex_init(&hdcp1_ta_cmd_lock);
-		}
-	}
-
-	pr_debug("hdcp1 app %s loaded\n",
-		 hdcp1_supported ? "successfully" : "not");
-
-	return hdcp1_supported;
-}
-
-/* APIs exposed to all clients */
-int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
-{
-	int rc = 0;
-	struct hdcp1_key_set_req *key_set_req;
-	struct hdcp1_key_set_rsp *key_set_rsp;
-
-	if (aksv_msb == NULL || aksv_lsb == NULL)
-		return -EINVAL;
-
-	if (!hdcp1_supported || !hdcp1_handle)
-		return -EINVAL;
-
-	/* set keys and request aksv */
-	key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
-	key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
-	key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_handle->sbuf +
-			   QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
-	rc = qseecom_send_command(hdcp1_handle, key_set_req,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp1_key_set_req)),
-				  key_set_rsp,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp1_key_set_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err=%d\n", rc);
-		return -ENOKEY;
-	}
-
-	rc = key_set_rsp->ret;
-	if (rc) {
-		pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
-		return -ENOKEY;
-	}
-
-	/* copy bytes into msb and lsb */
-	*aksv_msb = key_set_rsp->ksv[0] << 24;
-	*aksv_msb |= key_set_rsp->ksv[1] << 16;
-	*aksv_msb |= key_set_rsp->ksv[2] << 8;
-	*aksv_msb |= key_set_rsp->ksv[3];
-	*aksv_lsb = key_set_rsp->ksv[4] << 24;
-	*aksv_lsb |= key_set_rsp->ksv[5] << 16;
-	*aksv_lsb |= key_set_rsp->ksv[6] << 8;
-	*aksv_lsb |= key_set_rsp->ksv[7];
-
-	return 0;
-}
-
-int hdcp1_set_enc(bool enable)
-{
-	int rc = 0;
-	struct hdcp1_set_enc_req *set_enc_req;
-	struct hdcp1_set_enc_rsp *set_enc_rsp;
-
-	mutex_lock(&hdcp1_ta_cmd_lock);
-
-	if (!hdcp1_supported || !hdcp1_handle) {
-		rc = -EINVAL;
-		goto end;
-	}
-
-	if (hdcp1_enc_enabled == enable) {
-		pr_info("already %s\n", enable ? "enabled" : "disabled");
-		goto end;
-	}
-
-	/* set keys and request aksv */
-	set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_handle->sbuf;
-	set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
-	set_enc_req->enable = enable;
-	set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_handle->sbuf +
-			QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
-	rc = qseecom_send_command(hdcp1_handle, set_enc_req,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp1_set_enc_req)),
-				  set_enc_rsp,
-				  QSEECOM_ALIGN(sizeof
-						(struct hdcp1_set_enc_rsp)));
-
-	if (rc < 0) {
-		pr_err("qseecom cmd failed err=%d\n", rc);
-		goto end;
-	}
-
-	rc = set_enc_rsp->ret;
-	if (rc) {
-		pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
-		rc = -EINVAL;
-		goto end;
-	}
-
-	hdcp1_enc_enabled = enable;
-	pr_info("%s success\n", enable ? "enable" : "disable");
-end:
-	mutex_unlock(&hdcp1_ta_cmd_lock);
-	return rc;
-}
-
-int hdcp_library_register(struct hdcp_register_data *data)
-{
-	int rc = 0;
-	struct hdcp_lib_handle *handle = NULL;
-
-	if (!data) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	if (!data->txmtr_ops) {
-		pr_err("invalid input: txmtr context\n");
-		return -EINVAL;
-	}
-
-	if (!data->client_ops) {
-		pr_err("invalid input: client_ops\n");
-		return -EINVAL;
-	}
-
-	if (!data->hdcp_ctx) {
-		pr_err("invalid input: hdcp_ctx\n");
-		return -EINVAL;
-	}
-
-	/* populate ops to be called by client */
-	data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
-	data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
-
-	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-	if (!handle) {
-		rc = -ENOMEM;
-		goto unlock;
-	}
-
-	handle->client_ctx = data->client_ctx;
-	handle->client_ops = data->client_ops;
-	handle->hdcp_app_init = NULL;
-	handle->hdcp_txmtr_init = NULL;
-	handle->device_type = data->device_type;
-
-	atomic_set(&handle->hdcp_off, 0);
-
-	mutex_init(&handle->msg_lock);
-	mutex_init(&handle->wakeup_mutex);
-
-	kthread_init_worker(&handle->worker);
-
-	kthread_init_work(&handle->wk_init, hdcp_lib_init_work);
-	kthread_init_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work);
-	kthread_init_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
-	kthread_init_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
-	kthread_init_work(&handle->wk_clean, hdcp_lib_cleanup_work);
-	kthread_init_work(&handle->wk_wait, hdcp_lib_wait_work);
-	kthread_init_work(&handle->wk_stream, hdcp_lib_query_stream_work);
-
-	init_completion(&handle->poll_wait);
-
-	handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
-	if (!(handle->listener_buf)) {
-		rc = -ENOMEM;
-		goto error;
-	}
-
-	*data->hdcp_ctx = handle;
-	/* Cache the client ctx to be used later
-	 * HDCP driver probe happens earlier than
-	 * SDE driver probe hence caching it to
-	 * be used later.
-	 */
-
-	drv_client_handle = handle;
-	handle->thread = kthread_run(kthread_worker_fn,
-				     &handle->worker, "hdcp_tz_lib");
-
-	if (IS_ERR(handle->thread)) {
-		pr_err("unable to start lib thread\n");
-		rc = PTR_ERR(handle->thread);
-		handle->thread = NULL;
-		goto error;
-	}
-
-	return 0;
-error:
-	kzfree(handle->listener_buf);
-	handle->listener_buf = NULL;
-	kzfree(handle);
-	handle = NULL;
-unlock:
-	return rc;
-}
-EXPORT_SYMBOL(hdcp_library_register);
-
-void hdcp_library_deregister(void *phdcpcontext)
-{
-	struct hdcp_lib_handle *handle = phdcpcontext;
-
-	if (!handle)
-		return;
-
-	kthread_stop(handle->thread);
-
-	kzfree(handle->qseecom_handle);
-	kzfree(handle->last_msg_recvd_buf);
-
-	mutex_destroy(&handle->wakeup_mutex);
-
-	kzfree(handle->listener_buf);
-	kzfree(handle);
-}
-EXPORT_SYMBOL(hdcp_library_deregister);
-
-void hdcp1_notify_topology(void)
-{
-	char *envp[4];
-	char *a;
-	char *b;
-
-	if (!hdcp_drv_mgr) {
-		pr_err("invalid input\n");
-		return;
-	}
-
-	a = kzalloc(SZ_16, GFP_KERNEL);
-
-	if (!a)
-		return;
-
-	b = kzalloc(SZ_16, GFP_KERNEL);
-
-	if (!b) {
-		kfree(a);
-		return;
-	}
-
-	envp[0] = "HDCP_MGR_EVENT=MSG_READY";
-	envp[1] = a;
-	envp[2] = b;
-	envp[3] = NULL;
-
-	snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
-	snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
-
-	kobject_uevent_env(&hdcp_drv_mgr->device->kobj, KOBJ_CHANGE, envp);
-	kfree(a);
-	kfree(b);
-}
-
-static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
-struct device_attribute *attr, char *buf)
-{
-	ssize_t ret = 0;
-
-	if (!hdcp_drv_mgr) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	switch (hdcp_drv_mgr->tp_msgid) {
-	case DOWN_CHECK_TOPOLOGY:
-	case DOWN_REQUEST_TOPOLOGY:
-		buf[MSG_ID_IDX]   = hdcp_drv_mgr->tp_msgid;
-		buf[RET_CODE_IDX] = HDCP_AUTHED;
-		ret = HEADER_LEN;
-
-		memcpy(buf + HEADER_LEN, &hdcp_drv_mgr->cached_tp,
-			   sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
-
-		ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
-
-		/* clear the flag once data is read back to user space*/
-		hdcp_drv_mgr->tp_msgid = -1;
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t count)
-{
-	int msgid = 0;
-	ssize_t ret = count;
-
-	if (!hdcp_drv_mgr || !buf) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	msgid = buf[0];
-
-	switch (msgid) {
-	case DOWN_CHECK_TOPOLOGY:
-	case DOWN_REQUEST_TOPOLOGY:
-		hdcp_drv_mgr->tp_msgid = msgid;
-		break;
-		/* more cases added here */
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static ssize_t hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t count)
-{
-	int rc;
-	int min_enc_lvl;
-	struct hdcp_lib_handle *handle;
-	ssize_t ret = count;
-
-	if (!hdcp_drv_mgr) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	handle = hdcp_drv_mgr->handle;
-
-	rc = kstrtoint(buf, 10, &min_enc_lvl);
-	if (rc) {
-		pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
-		return -EINVAL;
-	}
-
-	if (handle && handle->client_ops->notify_lvl_change) {
-		handle->client_ops->notify_lvl_change(handle->client_ctx,
-		min_enc_lvl);
-	}
-
-	return ret;
-}
-
-static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
-	msm_hdcp_1x_sysfs_wta_tp);
-
-static DEVICE_ATTR(min_level_change, 0200, NULL,
-	hdcp2p2_sysfs_wta_min_level_change);
-
-void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
-{
-	if (!hdcp_drv_mgr) {
-		pr_err("invalid input\n");
-		return;
-	}
-
-	memcpy((void *)&hdcp_drv_mgr->cached_tp,
-		   hdcp1_cached_tp,
-		   sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
-}
-
-static struct attribute *msm_hdcp_fs_attrs[] = {
-	&dev_attr_tp.attr,
-	&dev_attr_min_level_change.attr,
-	NULL
-};
-
-static struct attribute_group msm_hdcp_fs_attr_group = {
-	.attrs = msm_hdcp_fs_attrs
-};
-
-static int msm_hdcp_open(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int msm_hdcp_close(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static const struct file_operations msm_hdcp_fops = {
-	.owner = THIS_MODULE,
-	.open = msm_hdcp_open,
-	.release = msm_hdcp_close,
-};
-
-static const struct of_device_id msm_hdcp_dt_match[] = {
-	{ .compatible = "qcom,msm-hdcp",},
-	{}
-};
-
-MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
-
-static int msm_hdcp_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	hdcp_drv_mgr = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp_mgr),
-						   GFP_KERNEL);
-	if (!hdcp_drv_mgr)
-		return -ENOMEM;
-
-	hdcp_drv_mgr->pdev = pdev;
-
-	platform_set_drvdata(pdev, hdcp_drv_mgr);
-
-	ret = alloc_chrdev_region(&hdcp_drv_mgr->dev_num, 0, 1, DRIVER_NAME);
-	if (ret  < 0) {
-		pr_err("alloc_chrdev_region failed ret = %d\n", ret);
-		goto error_get_dev_num;
-	}
-
-	hdcp_drv_mgr->class = class_create(THIS_MODULE, CLASS_NAME);
-	if (IS_ERR(hdcp_drv_mgr->class)) {
-		ret = PTR_ERR(hdcp_drv_mgr->class);
-		pr_err("couldn't create class rc = %d\n", ret);
-		goto error_class_create;
-	}
-
-	hdcp_drv_mgr->device = device_create(hdcp_drv_mgr->class, NULL,
-		hdcp_drv_mgr->dev_num, NULL, DRIVER_NAME);
-	if (IS_ERR(hdcp_drv_mgr->device)) {
-		ret = PTR_ERR(hdcp_drv_mgr->device);
-		pr_err("device_create failed %d\n", ret);
-		goto error_class_device_create;
-	}
-
-	cdev_init(&hdcp_drv_mgr->cdev, &msm_hdcp_fops);
-	ret = cdev_add(&hdcp_drv_mgr->cdev,
-			MKDEV(MAJOR(hdcp_drv_mgr->dev_num), 0), 1);
-	if (ret < 0) {
-		pr_err("cdev_add failed %d\n", ret);
-		goto error_cdev_add;
-	}
-
-	ret = sysfs_create_group(&hdcp_drv_mgr->device->kobj,
-			&msm_hdcp_fs_attr_group);
-	if (ret)
-		pr_err("unable to register rotator sysfs nodes\n");
-
-	/* Store the handle in the hdcp drv mgr
-	 * to be used for the sysfs notifications
-	 */
-	hdcp_drv_mgr->handle = drv_client_handle;
-
-	return 0;
-error_cdev_add:
-	device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
-error_class_device_create:
-	class_destroy(hdcp_drv_mgr->class);
-error_class_create:
-	unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
-error_get_dev_num:
-	devm_kfree(&pdev->dev, hdcp_drv_mgr);
-	hdcp_drv_mgr = NULL;
-	return ret;
-}
-
-static int msm_hdcp_remove(struct platform_device *pdev)
-{
-	struct msm_hdcp_mgr *mgr;
-
-	mgr = (struct msm_hdcp_mgr *)platform_get_drvdata(pdev);
-	if (!mgr)
-		return -ENODEV;
-
-	sysfs_remove_group(&hdcp_drv_mgr->device->kobj,
-	&msm_hdcp_fs_attr_group);
-	cdev_del(&hdcp_drv_mgr->cdev);
-	device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num);
-	class_destroy(hdcp_drv_mgr->class);
-	unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1);
-
-	devm_kfree(&pdev->dev, hdcp_drv_mgr);
-	hdcp_drv_mgr = NULL;
-	return 0;
-}
-
-static struct platform_driver msm_hdcp_driver = {
-	.probe = msm_hdcp_probe,
-	.remove = msm_hdcp_remove,
-	.driver = {
-		.name = "msm_hdcp",
-		.of_match_table = msm_hdcp_dt_match,
-		.pm = NULL,
-	}
-};
-
-static int __init msm_hdcp_init(void)
-{
-	return platform_driver_register(&msm_hdcp_driver);
-}
-
-static void __exit msm_hdcp_exit(void)
-{
-	return platform_driver_unregister(&msm_hdcp_driver);
-}
-
-module_init(msm_hdcp_init);
-module_exit(msm_hdcp_exit);
-
-MODULE_DESCRIPTION("MSM HDCP driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/hdcp_qseecom.c b/drivers/misc/hdcp_qseecom.c
new file mode 100644
index 0000000..6ce3776
--- /dev/null
+++ b/drivers/misc/hdcp_qseecom.c
@@ -0,0 +1,2240 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"[hdcp-lib] %s: " fmt, __func__
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/hdcp_qseecom.h>
+#include <linux/kthread.h>
+#include <linux/of.h>
+#include <video/msm_hdmi_hdcp_mgr.h>
+
+#include "qseecom_kernel.h"
+
+#define TZAPP_NAME            "hdcp2p2"
+#define HDCP1_APP_NAME        "hdcp1"
+#define QSEECOM_SBUFF_SIZE    0x1000
+
+#define MAX_TX_MESSAGE_SIZE	129
+#define MAX_RX_MESSAGE_SIZE	534
+#define MAX_TOPOLOGY_ELEMS	32
+#define HDCP1_AKSV_SIZE         8
+
+/* parameters related to LC_Init message */
+#define MESSAGE_ID_SIZE            1
+#define LC_INIT_MESSAGE_SIZE       (MESSAGE_ID_SIZE+BITS_64_IN_BYTES)
+
+/* parameters related to SKE_Send_EKS message */
+#define SKE_SEND_EKS_MESSAGE_SIZE \
+	(MESSAGE_ID_SIZE+BITS_128_IN_BYTES+BITS_64_IN_BYTES)
+
+/* all message IDs */
+#define INVALID_MESSAGE_ID               0
+#define AKE_INIT_MESSAGE_ID              2
+#define AKE_SEND_CERT_MESSAGE_ID         3
+#define AKE_NO_STORED_KM_MESSAGE_ID      4
+#define AKE_STORED_KM_MESSAGE_ID         5
+#define AKE_SEND_H_PRIME_MESSAGE_ID      7
+#define AKE_SEND_PAIRING_INFO_MESSAGE_ID 8
+#define LC_INIT_MESSAGE_ID               9
+#define LC_SEND_L_PRIME_MESSAGE_ID      10
+#define SKE_SEND_EKS_MESSAGE_ID         11
+#define REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID 12
+#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID      15
+#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
+#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID  17
+#define SKE_SEND_TYPE_ID                       18
+#define HDCP2P2_MAX_MESSAGES                   19
+
+#define HDCP1_SET_KEY_MESSAGE_ID       202
+#define HDCP1_SET_ENC_MESSAGE_ID       205
+
+#define BITS_40_IN_BYTES      5
+#define BITS_64_IN_BYTES      8
+#define BITS_128_IN_BYTES    16
+#define RXCAPS_SIZE           3
+#define RXINFO_SIZE           2
+#define SEQ_NUM_V_SIZE        3
+
+#define RCVR_ID_SIZE BITS_40_IN_BYTES
+#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
+#define MAX_RCVR_ID_LIST_SIZE \
+		(RCVR_ID_SIZE * MAX_RCVR_IDS_ALLOWED_IN_LIST)
+/*
+ * Minimum wait as per standard is 200 ms. Keep it 220 ms
+ * to be on safe side.
+ */
+#define SLEEP_SET_HW_KEY_MS 220
+
+/* hdcp command status */
+#define HDCP_SUCCESS      0
+
+/* flags set by tz in response message */
+#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST       1
+
+#define HDCP_TXMTR_SERVICE_ID                 0x0001000
+#define SERVICE_CREATE_CMD(x)                 (HDCP_TXMTR_SERVICE_ID | x)
+
+#define HDCP_TXMTR_INIT                       SERVICE_CREATE_CMD(1)
+#define HDCP_TXMTR_DEINIT                     SERVICE_CREATE_CMD(2)
+#define HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE   SERVICE_CREATE_CMD(3)
+#define HDCP_TXMTR_SEND_MESSAGE_TIMEOUT       SERVICE_CREATE_CMD(4)
+#define HDCP_TXMTR_SET_HW_KEY                 SERVICE_CREATE_CMD(5)
+#define HDCP_TXMTR_QUERY_STREAM_TYPE          SERVICE_CREATE_CMD(6)
+#define HDCP_LIB_INIT                         SERVICE_CREATE_CMD(11)
+#define HDCP_LIB_DEINIT                       SERVICE_CREATE_CMD(12)
+#define HDCP_TXMTR_GET_VERSION                SERVICE_CREATE_CMD(14)
+#define HDCP_TXMTR_VERIFY_KEY                 SERVICE_CREATE_CMD(15)
+#define HDCP_SESSION_INIT                     SERVICE_CREATE_CMD(16)
+#define HDCP_SESSION_DEINIT                   SERVICE_CREATE_CMD(17)
+#define HDCP_TXMTR_START_AUTHENTICATE         SERVICE_CREATE_CMD(18)
+
+#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
+#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
+#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF)
+
+#define HDCP_CLIENT_MAJOR_VERSION 2
+#define HDCP_CLIENT_MINOR_VERSION 1
+#define HDCP_CLIENT_PATCH_VERSION 0
+#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \
+	((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
+
+#define REAUTH_REQ BIT(3)
+#define LINK_INTEGRITY_FAILURE BIT(4)
+
+#define HDCP_LIB_EXECUTE(x) {\
+		kthread_queue_work(&handle->worker, &handle->wk_##x);\
+}
+
+static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
+	[AKE_INIT_MESSAGE_ID] = { 2,
+		{ {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
+		0 },
+	[AKE_SEND_CERT_MESSAGE_ID] = { 3,
+		{ {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
+			{"RxCaps", 0x6921D, 3} },
+		0 },
+	[AKE_NO_STORED_KM_MESSAGE_ID] = { 1,
+		{ {"Ekpub_km", 0x69220, 128} },
+		0 },
+	[AKE_STORED_KM_MESSAGE_ID] = { 2,
+		{ {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
+		0 },
+	[AKE_SEND_H_PRIME_MESSAGE_ID] = { 1,
+		{ {"H'", 0x692C0, 32} },
+		(1 << 1) },
+	[AKE_SEND_PAIRING_INFO_MESSAGE_ID] =  { 1,
+		{ {"Ekh_km", 0x692E0, 16} },
+		(1 << 2) },
+	[LC_INIT_MESSAGE_ID] = { 1,
+		{ {"rn", 0x692F0, 8} },
+		0 },
+	[LC_SEND_L_PRIME_MESSAGE_ID] = { 1,
+		{ {"L'", 0x692F8, 32} },
+		0 },
+	[SKE_SEND_EKS_MESSAGE_ID] = { 2,
+		{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
+		0 },
+	[SKE_SEND_TYPE_ID] = { 1,
+		{ {"type", 0x69494, 1} },
+		0 },
+	[REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
+		{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
+			{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
+		(1 << 0) },
+	[REPEATER_AUTH_SEND_ACK_MESSAGE_ID] = { 1,
+		{ {"V", 0x693E0, 16} },
+		0 },
+	[REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID] = { 3,
+		{ {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
+			{"streamID_Type", 0x693F5, 126} },
+		0 },
+	[REPEATER_AUTH_STREAM_READY_MESSAGE_ID] = { 1,
+		{ {"M'", 0x69473, 32} },
+		0 }
+};
+
+enum hdcp_state {
+	HDCP_STATE_INIT = 0x00,
+	HDCP_STATE_APP_LOADED = 0x01,
+	HDCP_STATE_SESSION_INIT = 0x02,
+	HDCP_STATE_TXMTR_INIT = 0x04,
+	HDCP_STATE_AUTHENTICATED = 0x08,
+	HDCP_STATE_ERROR = 0x10
+};
+
+enum hdcp_element {
+	HDCP_TYPE_UNKNOWN,
+	HDCP_TYPE_RECEIVER,
+	HDCP_TYPE_REPEATER,
+};
+
+enum hdcp_version {
+	HDCP_VERSION_UNKNOWN,
+	HDCP_VERSION_2_2,
+	HDCP_VERSION_1_4
+};
+
+struct receiver_info {
+	unsigned char rcvrInfo[RCVR_ID_SIZE];
+	enum hdcp_element elem_type;
+	enum hdcp_version hdcp_version;
+};
+
+struct topology_info {
+	unsigned int nNumRcvrs;
+	struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS];
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_rsp {
+	uint32_t commandid;
+	uint32_t ret;
+	uint8_t ksv[HDCP1_AKSV_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_rsp {
+	uint32_t commandid;
+	uint32_t commandId;
+	uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
+	uint32_t status;
+	uint32_t commandId;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req_v1 {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp_v1 {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_req {
+	uint32_t commandid;
+	uint32_t clientversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_req {
+	uint32_t commandid;
+	uint32_t deviceid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_lib_session_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req_v1 {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp_v1 {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t msglen;
+	uint8_t msg[MAX_RX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t state;
+	uint32_t timeout;
+	uint32_t flag;
+	uint32_t msglen;
+	uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint8_t streamtype;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t srmoffset;
+	uint32_t srmlength;
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	struct topology_info topologyinfo;
+};
+
+struct __attribute__ ((__packed__)) rxvr_info_struct {
+	uint8_t rcvrCert[522];
+	uint8_t rrx[BITS_64_IN_BYTES];
+	uint8_t rxcaps[RXCAPS_SIZE];
+	bool repeater;
+};
+
+struct __attribute__ ((__packed__)) repeater_info_struct {
+	uint8_t RxInfo[RXINFO_SIZE];
+	uint8_t seq_num_V[SEQ_NUM_V_SIZE];
+	bool seq_num_V_Rollover_flag;
+	uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE];
+	uint32_t ReceiverIDListLen;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_req {
+	uint32_t commandid;
+	uint32_t enable;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp {
+	uint32_t commandid;
+	uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_req {
+	uint32_t commandid;
+	uint32_t ctxHandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct hdcp_lib_handle {
+	unsigned char *listener_buf;
+	uint32_t msglen;
+	uint32_t tz_ctxhandle;
+	uint32_t hdcp_timeout;
+	uint32_t timeout_left;
+	uint32_t wait_timeout;
+	bool no_stored_km_flag;
+	bool feature_supported;
+	bool authenticated;
+	void *client_ctx;
+	struct hdcp_client_ops *client_ops;
+	struct mutex msg_lock;
+	struct mutex wakeup_mutex;
+	enum hdcp_state hdcp_state;
+	enum hdcp_lib_wakeup_cmd wakeup_cmd;
+	bool repeater_flag;
+	bool update_stream;
+	struct qseecom_handle *qseecom_handle;
+	int last_msg_sent;
+	int last_msg;
+	char *last_msg_recvd_buf;
+	uint32_t last_msg_recvd_len;
+	atomic_t hdcp_off;
+	uint32_t session_id;
+	enum hdcp_device_type device_type;
+
+	struct task_struct *thread;
+	struct completion poll_wait;
+
+	struct kthread_worker worker;
+	struct kthread_work wk_init;
+	struct kthread_work wk_msg_sent;
+	struct kthread_work wk_msg_recvd;
+	struct kthread_work wk_timeout;
+	struct kthread_work wk_clean;
+	struct kthread_work wk_wait;
+	struct kthread_work wk_stream;
+
+	int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
+	int (*hdcp_txmtr_init)(struct hdcp_lib_handle *handle);
+};
+
+struct hdcp_lib_message_map {
+	int msg_id;
+	const char *msg_name;
+};
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
+static void hdcp_lib_init(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle);
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle);
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
+
+static struct qseecom_handle *hdcp1_handle;
+static bool hdcp1_supported = true;
+static bool hdcp1_enc_enabled;
+static struct mutex hdcp1_ta_cmd_lock;
+
+static const char *hdcp_lib_message_name(int msg_id)
+{
+	/*
+	 * Message ID map. The first number indicates the message number
+	 * assigned to the message by the HDCP 2.2 spec. This is also the first
+	 * byte of every HDCP 2.2 authentication protocol message.
+	 */
+	static struct hdcp_lib_message_map hdcp_lib_msg_map[] = {
+		{2, "AKE_INIT"},
+		{3, "AKE_SEND_CERT"},
+		{4, "AKE_NO_STORED_KM"},
+		{5, "AKE_STORED_KM"},
+		{7, "AKE_SEND_H_PRIME"},
+		{8, "AKE_SEND_PAIRING_INFO"},
+		{9, "LC_INIT"},
+		{10, "LC_SEND_L_PRIME"},
+		{11, "SKE_SEND_EKS"},
+		{12, "REPEATER_AUTH_SEND_RECEIVERID_LIST"},
+		{15, "REPEATER_AUTH_SEND_ACK"},
+		{16, "REPEATER_AUTH_STREAM_MANAGE"},
+		{17, "REPEATER_AUTH_STREAM_READY"},
+		{18, "SKE_SEND_TYPE_ID"},
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdcp_lib_msg_map); i++) {
+		if (msg_id == hdcp_lib_msg_map[i].msg_id)
+			return hdcp_lib_msg_map[i].msg_name;
+	}
+	return "UNKNOWN";
+}
+
+static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
+				     struct hdcp_wakeup_data *data)
+{
+	switch (handle->last_msg) {
+	case INVALID_MESSAGE_ID:
+		return AKE_INIT_MESSAGE_ID;
+	case AKE_INIT_MESSAGE_ID:
+		return AKE_SEND_CERT_MESSAGE_ID;
+	case AKE_SEND_CERT_MESSAGE_ID:
+		if (handle->no_stored_km_flag)
+			return AKE_NO_STORED_KM_MESSAGE_ID;
+		else
+			return AKE_STORED_KM_MESSAGE_ID;
+	case AKE_STORED_KM_MESSAGE_ID:
+	case AKE_NO_STORED_KM_MESSAGE_ID:
+		return AKE_SEND_H_PRIME_MESSAGE_ID;
+	case AKE_SEND_H_PRIME_MESSAGE_ID:
+		if (handle->no_stored_km_flag)
+			return AKE_SEND_PAIRING_INFO_MESSAGE_ID;
+		else
+			return LC_INIT_MESSAGE_ID;
+	case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+		return LC_INIT_MESSAGE_ID;
+	case LC_INIT_MESSAGE_ID:
+		return LC_SEND_L_PRIME_MESSAGE_ID;
+	case LC_SEND_L_PRIME_MESSAGE_ID:
+		return SKE_SEND_EKS_MESSAGE_ID;
+	case SKE_SEND_EKS_MESSAGE_ID:
+		if (!handle->repeater_flag)
+			return SKE_SEND_TYPE_ID;
+	case SKE_SEND_TYPE_ID:
+	case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
+	case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+		if (!handle->repeater_flag)
+			return INVALID_MESSAGE_ID;
+
+		if (data->cmd == HDCP_WKUP_CMD_SEND_MESSAGE)
+			return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
+		else
+			return REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID;
+	case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+		return REPEATER_AUTH_SEND_ACK_MESSAGE_ID;
+	case REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID:
+		return REPEATER_AUTH_STREAM_READY_MESSAGE_ID;
+	default:
+		pr_err("Uknown message ID (%d)", handle->last_msg);
+		return -EINVAL;
+	}
+}
+
+static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
+				       struct hdcp_wakeup_data *data)
+{
+	switch (handle->last_msg) {
+	case AKE_SEND_H_PRIME_MESSAGE_ID:
+		if (handle->no_stored_km_flag)
+			handle->wait_timeout = HZ;
+		else
+			handle->wait_timeout = HZ / 4;
+		break;
+	case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+		handle->wait_timeout = HZ / 4;
+		break;
+	case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+		if (!handle->authenticated)
+			handle->wait_timeout = HZ * 3;
+		else
+			handle->wait_timeout = 0;
+		break;
+	default:
+		handle->wait_timeout = 0;
+	}
+
+	if (handle->wait_timeout)
+		kthread_queue_work(&handle->worker, &handle->wk_wait);
+}
+
+static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
+				  struct hdcp_wakeup_data *data)
+{
+	int rc = 0, i;
+
+	if (!handle || !handle->client_ops || !handle->client_ops->wakeup ||
+	    !data || (data->cmd == HDCP_WKUP_CMD_INVALID))
+		return;
+
+	data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
+
+	if (data->cmd == HDCP_WKUP_CMD_RECV_MESSAGE ||
+	    data->cmd == HDCP_WKUP_CMD_LINK_POLL)
+		handle->last_msg = hdcp_lib_get_next_message(handle, data);
+
+	if (handle->last_msg != INVALID_MESSAGE_ID &&
+	    data->cmd != HDCP_WKUP_CMD_STATUS_SUCCESS &&
+	    data->cmd != HDCP_WKUP_CMD_STATUS_FAILED) {
+		u32 msg_num, rx_status;
+		const struct hdcp_msg_part *msg;
+
+		pr_debug("lib->client: %s (%s)\n",
+			hdcp_cmd_to_str(data->cmd),
+			hdcp_lib_message_name(handle->last_msg));
+
+		data->message_data = &hdcp_msg_lookup[handle->last_msg];
+
+		msg_num = data->message_data->num_messages;
+		msg = data->message_data->messages;
+		rx_status = data->message_data->rx_status;
+
+		pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
+
+		for (i = 0; i < msg_num; i++)
+			pr_debug("%10s | %6x | %4d\n",
+				msg[i].name, msg[i].offset,
+				msg[i].length);
+	} else {
+		pr_debug("lib->client: %s\n", hdcp_cmd_to_str(data->cmd));
+	}
+
+	rc = handle->client_ops->wakeup(data);
+	if (rc)
+		pr_err("error sending %s to client\n",
+		       hdcp_cmd_to_str(data->cmd));
+
+	hdcp_lib_wait_for_response(handle, data);
+}
+
+static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
+{
+	char msg_name[50];
+	struct hdcp_wakeup_data cdata = {
+		HDCP_WKUP_CMD_SEND_MESSAGE
+	};
+
+	cdata.context = handle->client_ctx;
+	cdata.send_msg_buf = handle->listener_buf;
+	cdata.send_msg_len = handle->msglen;
+	cdata.timeout = handle->hdcp_timeout;
+
+	snprintf(msg_name, sizeof(msg_name), "%s: ",
+		hdcp_lib_message_name((int)cdata.send_msg_buf[0]));
+
+	print_hex_dump(KERN_DEBUG, msg_name,
+		DUMP_PREFIX_NONE, 16, 1, cdata.send_msg_buf,
+		cdata.send_msg_len, false);
+
+	hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_set_hw_key_req *req_buf;
+	struct hdcp_set_hw_key_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/*
+	 * wait at least 200ms before enabling encryption
+	 * as per hdcp2p2 sepcifications.
+	 */
+	msleep(SLEEP_SET_HW_KEY_MS);
+
+	req_buf = (struct hdcp_set_hw_key_req *)(handle->qseecom_handle->sbuf);
+	req_buf->commandid = HDCP_TXMTR_SET_HW_KEY;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rsp_buf = (struct hdcp_set_hw_key_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_set_hw_key_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_set_hw_key_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_set_hw_key_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
+		pr_err("qseecom cmd failed with err = %d status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* reached an authenticated state */
+	handle->hdcp_state |= HDCP_STATE_AUTHENTICATED;
+
+	pr_debug("success\n");
+	return 0;
+error:
+	if (handle && !atomic_read(&handle->hdcp_off))
+		HDCP_LIB_EXECUTE(clean);
+
+	return rc;
+}
+
+static int hdcp_lib_get_version(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_version_req *req_buf;
+	struct hdcp_version_rsp *rsp_buf;
+	uint32_t app_major_version = 0;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("library not loaded\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	/* get the TZ hdcp2p2 app version */
+	req_buf = (struct hdcp_version_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_GET_VERSION;
+
+	rsp_buf = (struct hdcp_version_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_version_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle,
+				  req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_init_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_init_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err = %d\n", rc);
+		goto exit;
+	}
+
+	app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion);
+
+	pr_debug("hdcp2p2 app major version %d, app version %d\n",
+		 app_major_version, rsp_buf->appversion);
+
+exit:
+	return rc;
+}
+
+static int hdcp_lib_verify_keys(struct hdcp_lib_handle *handle)
+{
+	int rc = -EINVAL;
+	struct hdcp_verify_key_req *req_buf;
+	struct hdcp_verify_key_rsp *rsp_buf;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("app not loaded\n");
+		goto exit;
+	}
+
+	req_buf = (struct hdcp_verify_key_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_VERIFY_KEY;
+
+	rsp_buf = (struct hdcp_verify_key_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_verify_key_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle,
+				  req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_verify_key_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_verify_key_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err = %d\n", rc);
+		goto exit;
+	}
+
+	return rsp_buf->status;
+exit:
+	return rc;
+}
+
+static int hdcp_app_init(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_lib_init_req *req_buf;
+	struct hdcp_lib_init_rsp *rsp_buf;
+	uint32_t app_minor_version = 0;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("library not loaded\n");
+		goto exit;
+	}
+
+	/* now load the app by sending hdcp_lib_init */
+	req_buf = (struct hdcp_lib_init_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_LIB_INIT;
+	req_buf->clientversion =
+	    HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION,
+				     HDCP_CLIENT_MINOR_VERSION,
+				     HDCP_CLIENT_PATCH_VERSION);
+	rsp_buf = (struct hdcp_lib_init_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_init_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle,
+				  req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_init_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_init_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err = %d\n", rc);
+		goto exit;
+	}
+
+	app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion);
+	if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) {
+		pr_err
+		    ("client-app minor version mismatch app(%d), client(%d)\n",
+		     app_minor_version, HDCP_CLIENT_MINOR_VERSION);
+		rc = -1;
+		goto exit;
+	}
+	pr_debug("success\n");
+	pr_debug("client version major(%d), minor(%d), patch(%d)\n",
+		 HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION,
+		 HDCP_CLIENT_PATCH_VERSION);
+	pr_debug("app version major(%d), minor(%d), patch(%d)\n",
+		 HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion),
+		 HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion),
+		 HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion));
+
+exit:
+	return rc;
+}
+
+static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		goto exit;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_err("library already loaded\n");
+		goto exit;
+	}
+
+	/*
+	 * allocating resource for qseecom handle
+	 * the app is not loaded here
+	 */
+	rc = qseecom_start_app(&(handle->qseecom_handle),
+			       TZAPP_NAME, QSEECOM_SBUFF_SIZE);
+	if (rc) {
+		pr_err("qseecom_start_app failed %d\n", rc);
+		goto exit;
+	}
+
+	handle->hdcp_state |= HDCP_STATE_APP_LOADED;
+	pr_debug("qseecom_start_app success\n");
+
+	rc = hdcp_lib_get_version(handle);
+	if (rc) {
+		pr_err("library get version failed\n");
+		goto exit;
+	}
+
+	handle->hdcp_app_init = hdcp_app_init;
+	handle->hdcp_txmtr_init = hdcp_lib_txmtr_init;
+
+	if (handle->hdcp_app_init == NULL) {
+		pr_err("invalid app init function pointer\n");
+		goto exit;
+	}
+
+	rc = handle->hdcp_app_init(handle);
+	if (rc) {
+		pr_err("app init failed\n");
+		goto exit;
+	}
+exit:
+	return rc;
+}
+
+static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_lib_deinit_req *req_buf;
+	struct hdcp_lib_deinit_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("library not loaded\n");
+		return rc;
+	}
+
+	/* unloading app by sending hdcp_lib_deinit cmd */
+	req_buf = (struct hdcp_lib_deinit_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_LIB_DEINIT;
+	rsp_buf = (struct hdcp_lib_deinit_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_deinit_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle,
+				  req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_deinit_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_lib_deinit_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err = %d\n", rc);
+		goto exit;
+	}
+
+	/* deallocate the resources for qseecom handle */
+	rc = qseecom_shutdown_app(&handle->qseecom_handle);
+	if (rc) {
+		pr_err("qseecom_shutdown_app failed err: %d\n", rc);
+		goto exit;
+	}
+
+	handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static int hdcp_lib_session_init(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_lib_session_init_req *req_buf;
+	struct hdcp_lib_session_init_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("app not loaded\n");
+		goto exit;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) {
+		pr_err("session already initialized\n");
+		goto exit;
+	}
+
+	/* send HDCP_Session_Init command to TZ */
+	req_buf =
+	    (struct hdcp_lib_session_init_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_SESSION_INIT;
+	req_buf->deviceid = handle->device_type;
+	rsp_buf = (struct hdcp_lib_session_init_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_init_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_lib_session_init_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_lib_session_init_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+	    (rsp_buf->commandid != HDCP_SESSION_INIT)) {
+		pr_err("qseecom cmd failed with err = %d, status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	pr_debug("session id %d\n", rsp_buf->sessionid);
+
+	handle->session_id = rsp_buf->sessionid;
+	handle->hdcp_state |= HDCP_STATE_SESSION_INIT;
+
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static int hdcp_lib_session_deinit(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_lib_session_deinit_req *req_buf;
+	struct hdcp_lib_session_deinit_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("app not loaded\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		/* unload library here */
+		pr_err("session not initialized\n");
+		goto exit;
+	}
+
+	/* send command to TZ */
+	req_buf =
+	    (struct hdcp_lib_session_deinit_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_SESSION_DEINIT;
+	req_buf->sessionid = handle->session_id;
+	rsp_buf = (struct hdcp_lib_session_deinit_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_lib_session_deinit_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_lib_session_deinit_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_lib_session_deinit_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+	    (rsp_buf->commandid != HDCP_SESSION_DEINIT)) {
+		pr_err("qseecom cmd failed with err = %d status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT;
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_tx_init_req *req_buf;
+	struct hdcp_tx_init_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("library not loaded\n");
+		goto exit;
+	}
+
+	/* send HDCP_Txmtr_Init command to TZ */
+	req_buf = (struct hdcp_tx_init_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_INIT;
+	req_buf->sessionid = handle->session_id;
+	rsp_buf = (struct hdcp_tx_init_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_tx_init_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_tx_init_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_tx_init_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+	    (rsp_buf->commandid != HDCP_TXMTR_INIT)) {
+		pr_err("qseecom cmd failed with err = %d, status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	handle->tz_ctxhandle = rsp_buf->ctxhandle;
+	handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
+
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static int hdcp_lib_txmtr_deinit(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_deinit_req *req_buf;
+	struct hdcp_deinit_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("app not loaded\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		/* unload library here */
+		pr_err("txmtr not initialized\n");
+		goto exit;
+	}
+
+	/* send command to TZ */
+	req_buf = (struct hdcp_deinit_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_DEINIT;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+	rsp_buf = (struct hdcp_deinit_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof(struct hdcp_deinit_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_deinit_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+	    (rsp_buf->commandid != HDCP_TXMTR_DEINIT)) {
+		pr_err("qseecom cmd failed with err = %d status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT;
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_start_auth_req *req_buf;
+	struct hdcp_start_auth_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		goto exit;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		pr_err("txmtr not initialized\n");
+		goto exit;
+	}
+
+	/* send HDCP_Txmtr_Start_Auth command to TZ */
+	req_buf = (struct hdcp_start_auth_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_START_AUTHENTICATE;
+	req_buf->ctxHandle = handle->tz_ctxhandle;
+	rsp_buf = (struct hdcp_start_auth_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_start_auth_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_start_auth_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_start_auth_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+	    (rsp_buf->commandid != HDCP_TXMTR_START_AUTHENTICATE) ||
+	    (rsp_buf->msglen == 0) || (rsp_buf->message == NULL)) {
+		pr_err("qseecom cmd failed with err = %d, status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	pr_debug("recvd %s from TZ at %dms\n",
+		 hdcp_lib_message_name((int)rsp_buf->message[0]),
+		 jiffies_to_msecs(jiffies));
+
+	handle->last_msg = (int)rsp_buf->message[0];
+
+	/* send the response to HDMI driver */
+	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
+	       rsp_buf->msglen);
+	handle->msglen = rsp_buf->msglen;
+	handle->hdcp_timeout = rsp_buf->timeout;
+
+	handle->tz_ctxhandle = rsp_buf->ctxhandle;
+
+	pr_debug("success\n");
+exit:
+	return rc;
+}
+
+static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_query_stream_type_req *req_buf;
+	struct hdcp_query_stream_type_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	if (atomic_read(&handle->hdcp_off)) {
+		pr_debug("invalid state, hdcp off\n");
+		return;
+	}
+
+	if (!handle->repeater_flag) {
+		pr_debug("invalid state, not a repeater\n");
+		return;
+	}
+
+	/* send command to TZ */
+	req_buf =
+	    (struct hdcp_query_stream_type_req *)handle->qseecom_handle->sbuf;
+	req_buf->commandid = HDCP_TXMTR_QUERY_STREAM_TYPE;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+	rsp_buf = (struct hdcp_query_stream_type_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	     QSEECOM_ALIGN(sizeof(struct hdcp_query_stream_type_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_query_stream_type_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_query_stream_type_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+		(rsp_buf->msglen == 0) ||
+		(rsp_buf->commandid != HDCP_TXMTR_QUERY_STREAM_TYPE) ||
+		(rsp_buf->msg == NULL)) {
+		pr_err("qseecom cmd failed with err=%d status=%d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	pr_debug("message received from TZ: %s\n",
+		 hdcp_lib_message_name((int)rsp_buf->msg[0]));
+
+	handle->last_msg = (int)rsp_buf->msg[0];
+
+	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+	       rsp_buf->msglen);
+	handle->hdcp_timeout = rsp_buf->timeout;
+	handle->msglen = rsp_buf->msglen;
+exit:
+	if (!rc && !atomic_read(&handle->hdcp_off))
+		hdcp_lib_send_message(handle);
+}
+
+static void hdcp_lib_query_stream_work(struct kthread_work *work)
+{
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_stream);
+
+	hdcp_lib_stream(handle);
+}
+
+static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
+{
+	int rc = 0;
+	bool supported = false;
+	struct hdcp_lib_handle *handle = phdcpcontext;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		goto exit;
+	}
+
+	if (handle->feature_supported) {
+		supported = true;
+		goto exit;
+	}
+
+	rc = hdcp_lib_library_load(handle);
+	if (!rc) {
+		if (!hdcp_lib_verify_keys(handle)) {
+			pr_debug("HDCP2p2 supported\n");
+			handle->feature_supported = true;
+			supported = true;
+		}
+		hdcp_lib_library_unload(handle);
+	}
+exit:
+	return supported;
+}
+
+static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
+{
+	if (!list_empty(&handle->wk_init.node))
+		pr_debug("init work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_init)
+		pr_debug("init work executing\n");
+
+	if (!list_empty(&handle->wk_msg_sent.node))
+		pr_debug("msg_sent work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_msg_sent)
+		pr_debug("msg_sent work executing\n");
+
+	if (!list_empty(&handle->wk_msg_recvd.node))
+		pr_debug("msg_recvd work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_msg_recvd)
+		pr_debug("msg_recvd work executing\n");
+
+	if (!list_empty(&handle->wk_timeout.node))
+		pr_debug("timeout work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_timeout)
+		pr_debug("timeout work executing\n");
+
+	if (!list_empty(&handle->wk_clean.node))
+		pr_debug("clean work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_clean)
+		pr_debug("clean work executing\n");
+
+	if (!list_empty(&handle->wk_wait.node))
+		pr_debug("wait work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_wait)
+		pr_debug("wait work executing\n");
+
+	if (!list_empty(&handle->wk_stream.node))
+		pr_debug("stream work queued\n");
+
+	if (handle->worker.current_work == &handle->wk_stream)
+		pr_debug("stream work executing\n");
+}
+
+static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+
+	if (!list_empty(&handle->worker.work_list))
+		hdcp_lib_check_worker_status(handle);
+
+	if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
+		if (!list_empty(&handle->worker.work_list)) {
+			pr_debug("error: queue not empty\n");
+			rc = -EBUSY;
+			goto exit;
+		}
+
+		if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+			pr_debug("library already loaded\n");
+			rc = -EBUSY;
+			goto exit;
+		}
+	} else {
+		if (atomic_read(&handle->hdcp_off)) {
+			pr_debug("hdcp2.2 session tearing down\n");
+			goto exit;
+		}
+
+		if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+			pr_debug("hdcp 2.2 app not loaded\n");
+			goto exit;
+		}
+	}
+exit:
+	return rc;
+}
+
+static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
+{
+	struct hdcp_lib_handle *handle;
+	int rc = 0;
+
+	if (!data)
+		return -EINVAL;
+
+	handle = data->context;
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->wakeup_mutex);
+
+	handle->wakeup_cmd = data->cmd;
+	handle->timeout_left = data->timeout;
+
+	pr_debug("client->lib: %s (%s)\n",
+		hdcp_lib_cmd_to_str(data->cmd),
+		hdcp_lib_message_name(handle->last_msg));
+
+	rc = hdcp_lib_check_valid_state(handle);
+	if (rc)
+		goto exit;
+
+	mutex_lock(&handle->msg_lock);
+	if (data->recvd_msg_len) {
+		kzfree(handle->last_msg_recvd_buf);
+
+		handle->last_msg_recvd_len = data->recvd_msg_len;
+		handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len,
+						     GFP_KERNEL);
+		if (!handle->last_msg_recvd_buf) {
+			rc = -ENOMEM;
+			mutex_unlock(&handle->msg_lock);
+			goto exit;
+		}
+
+		memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
+		       data->recvd_msg_len);
+	}
+	mutex_unlock(&handle->msg_lock);
+
+	if (!completion_done(&handle->poll_wait))
+		complete_all(&handle->poll_wait);
+
+	switch (handle->wakeup_cmd) {
+	case HDCP_LIB_WKUP_CMD_START:
+		handle->no_stored_km_flag = 0;
+		handle->repeater_flag = false;
+		handle->update_stream = false;
+		handle->last_msg_sent = 0;
+		handle->last_msg = INVALID_MESSAGE_ID;
+		handle->hdcp_timeout = 0;
+		handle->timeout_left = 0;
+		atomic_set(&handle->hdcp_off, 0);
+		handle->hdcp_state = HDCP_STATE_INIT;
+
+		HDCP_LIB_EXECUTE(init);
+		break;
+	case HDCP_LIB_WKUP_CMD_STOP:
+		atomic_set(&handle->hdcp_off, 1);
+
+		HDCP_LIB_EXECUTE(clean);
+		break;
+	case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
+		handle->last_msg_sent = handle->listener_buf[0];
+
+		HDCP_LIB_EXECUTE(msg_sent);
+		break;
+	case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
+	case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
+	case HDCP_LIB_WKUP_CMD_LINK_FAILED:
+		handle->hdcp_state |= HDCP_STATE_ERROR;
+		HDCP_LIB_EXECUTE(clean);
+		break;
+	case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
+		HDCP_LIB_EXECUTE(msg_recvd);
+		break;
+	case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
+		HDCP_LIB_EXECUTE(timeout);
+		break;
+	case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
+		HDCP_LIB_EXECUTE(stream);
+		break;
+	default:
+		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+	}
+exit:
+	mutex_unlock(&handle->wakeup_mutex);
+
+	return rc;
+}
+
+static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
+{
+	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+	if (!handle) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	cdata.context = handle->client_ctx;
+
+	switch (handle->last_msg_sent) {
+	case SKE_SEND_TYPE_ID:
+		if (!hdcp_lib_enable_encryption(handle)) {
+			handle->authenticated = true;
+
+			cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+			hdcp_lib_wakeup_client(handle, &cdata);
+		}
+
+		/* poll for link check */
+		cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+		break;
+	case SKE_SEND_EKS_MESSAGE_ID:
+		if (handle->repeater_flag) {
+			/* poll for link check */
+			cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+		} else {
+			memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+			handle->listener_buf[0] = SKE_SEND_TYPE_ID;
+			handle->msglen = 2;
+			cdata.cmd = HDCP_WKUP_CMD_SEND_MESSAGE;
+			cdata.send_msg_buf = handle->listener_buf;
+			cdata.send_msg_len = handle->msglen;
+			handle->last_msg = hdcp_lib_get_next_message(handle,
+						&cdata);
+		}
+		break;
+	case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+		pr_debug("Repeater authentication successful\n");
+
+		if (handle->update_stream) {
+			HDCP_LIB_EXECUTE(stream);
+			handle->update_stream = false;
+		} else {
+			cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+		}
+		break;
+	default:
+		cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+		cdata.timeout = handle->timeout_left;
+	}
+
+	hdcp_lib_wakeup_client(handle, &cdata);
+}
+
+static void hdcp_lib_msg_sent_work(struct kthread_work *work)
+{
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_msg_sent);
+
+	if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
+		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+		return;
+	}
+
+	hdcp_lib_msg_sent(handle);
+}
+
+static void hdcp_lib_init(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+
+	if (!handle) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) {
+		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
+		return;
+	}
+
+	rc = hdcp_lib_library_load(handle);
+	if (rc)
+		goto exit;
+
+	rc = hdcp_lib_session_init(handle);
+	if (rc)
+		goto exit;
+
+	if (handle->hdcp_txmtr_init == NULL) {
+		pr_err("invalid txmtr init function pointer\n");
+		return;
+	}
+
+	rc = handle->hdcp_txmtr_init(handle);
+	if (rc)
+		goto exit;
+
+	rc = hdcp_lib_start_auth(handle);
+	if (rc)
+		goto exit;
+
+	hdcp_lib_send_message(handle);
+
+	return;
+exit:
+	HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_init_work(struct kthread_work *work)
+{
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_init);
+
+	hdcp_lib_init(handle);
+}
+
+static void hdcp_lib_timeout(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_send_timeout_req *req_buf;
+	struct hdcp_send_timeout_rsp *rsp_buf;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_debug("invalid handle\n");
+		return;
+	}
+
+	if (atomic_read(&handle->hdcp_off)) {
+		pr_debug("invalid state, hdcp off\n");
+		return;
+	}
+
+	req_buf = (struct hdcp_send_timeout_req *)
+	    (handle->qseecom_handle->sbuf);
+	req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rsp_buf = (struct hdcp_send_timeout_rsp *)
+	    (handle->qseecom_handle->sbuf +
+	    QSEECOM_ALIGN(sizeof(struct hdcp_send_timeout_req)));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_send_timeout_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct
+						 hdcp_send_timeout_rsp)));
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) {
+		pr_err("qseecom cmd failed for with err = %d status = %d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (rsp_buf->commandid == HDCP_TXMTR_SEND_MESSAGE_TIMEOUT) {
+		pr_err("HDCP_TXMTR_SEND_MESSAGE_TIMEOUT\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/*
+	 * if the response contains LC_Init message
+	 * send the message again to TZ
+	 */
+	if ((rsp_buf->commandid == HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) &&
+	    ((int)rsp_buf->message[0] == LC_INIT_MESSAGE_ID) &&
+	    (rsp_buf->msglen == LC_INIT_MESSAGE_SIZE)) {
+		if (!atomic_read(&handle->hdcp_off)) {
+			/* keep local copy of TZ response */
+			memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+			memcpy(handle->listener_buf,
+			       (unsigned char *)rsp_buf->message,
+			       rsp_buf->msglen);
+			handle->hdcp_timeout = rsp_buf->timeout;
+			handle->msglen = rsp_buf->msglen;
+
+			hdcp_lib_send_message(handle);
+		}
+	}
+
+	return;
+error:
+	if (!atomic_read(&handle->hdcp_off))
+		HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
+{
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_timeout);
+
+	hdcp_lib_timeout(handle);
+}
+
+static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
+{
+	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	handle->authenticated = false;
+
+	hdcp_lib_txmtr_deinit(handle);
+	hdcp_lib_session_deinit(handle);
+	hdcp_lib_library_unload(handle);
+
+	cdata.context = handle->client_ctx;
+	cdata.cmd = HDCP_WKUP_CMD_STATUS_FAILED;
+
+	if (!atomic_read(&handle->hdcp_off))
+		hdcp_lib_wakeup_client(handle, &cdata);
+
+	atomic_set(&handle->hdcp_off, 1);
+}
+
+static void hdcp_lib_cleanup_work(struct kthread_work *work)
+{
+
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_clean);
+
+	hdcp_lib_clean(handle);
+}
+
+static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
+{
+	int rc = 0;
+	struct hdcp_wakeup_data cdata = { HDCP_WKUP_CMD_INVALID };
+	struct hdcp_rcvd_msg_req *req_buf;
+	struct hdcp_rcvd_msg_rsp *rsp_buf;
+	uint32_t msglen;
+	char *msg = NULL;
+	char msg_name[50];
+	uint32_t message_id_bytes = 0;
+
+	if (!handle || !handle->qseecom_handle ||
+	    !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	if (atomic_read(&handle->hdcp_off)) {
+		pr_debug("invalid state, hdcp off\n");
+		return;
+	}
+
+	cdata.context = handle->client_ctx;
+
+	mutex_lock(&handle->msg_lock);
+	msglen = handle->last_msg_recvd_len;
+
+	if (msglen == 0) {
+		pr_err("invalid msg len\n");
+		mutex_unlock(&handle->msg_lock);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	/* If the client is DP then allocate extra byte for message ID. */
+	if (handle->device_type == HDCP_TXMTR_DP)
+		message_id_bytes = 1;
+
+	msglen += message_id_bytes;
+
+	msg = kzalloc(msglen, GFP_KERNEL);
+	if (!msg) {
+		mutex_unlock(&handle->msg_lock);
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	/* copy the message id if needed */
+	if (message_id_bytes)
+		memcpy(msg, &handle->last_msg, message_id_bytes);
+
+	memcpy(msg + message_id_bytes,
+		handle->last_msg_recvd_buf,
+		handle->last_msg_recvd_len);
+
+	mutex_unlock(&handle->msg_lock);
+
+	snprintf(msg_name, sizeof(msg_name), "%s: ",
+		hdcp_lib_message_name((int)msg[0]));
+
+	print_hex_dump(KERN_DEBUG, msg_name,
+		DUMP_PREFIX_NONE, 16, 1, msg, msglen, false);
+
+	/* send the message to QSEECOM */
+	req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
+	req_buf->commandid = HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE;
+	memcpy(req_buf->msg, msg, msglen);
+	req_buf->msglen = msglen;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rsp_buf =
+	    (struct hdcp_rcvd_msg_rsp *)(handle->qseecom_handle->sbuf +
+					 QSEECOM_ALIGN(sizeof
+						       (struct
+							hdcp_rcvd_msg_req)));
+
+	pr_debug("writing %s to TZ at %dms\n",
+		 hdcp_lib_message_name((int)msg[0]), jiffies_to_msecs(jiffies));
+
+	rc = qseecom_send_command(handle->qseecom_handle, req_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_rcvd_msg_req)),
+				  rsp_buf,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp_rcvd_msg_rsp)));
+
+	/* get next message from sink if we receive H PRIME on no store km */
+	if ((msg[0] == AKE_SEND_H_PRIME_MESSAGE_ID) &&
+	    handle->no_stored_km_flag) {
+		handle->hdcp_timeout = rsp_buf->timeout;
+
+		cdata.cmd = HDCP_WKUP_CMD_RECV_MESSAGE;
+		cdata.timeout = handle->hdcp_timeout;
+
+		goto exit;
+	}
+
+	if ((msg[0] == REPEATER_AUTH_STREAM_READY_MESSAGE_ID) &&
+	    (rc == 0) && (rsp_buf->status == 0)) {
+		pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
+
+		if (!handle->authenticated &&
+		    !hdcp_lib_enable_encryption(handle)) {
+			handle->authenticated = true;
+
+			cdata.cmd = HDCP_WKUP_CMD_STATUS_SUCCESS;
+			hdcp_lib_wakeup_client(handle, &cdata);
+		}
+
+		cdata.cmd = HDCP_WKUP_CMD_LINK_POLL;
+		goto exit;
+	}
+
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS) ||
+		(rsp_buf->msglen == 0) ||
+		(rsp_buf->commandid != HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE) ||
+		(rsp_buf->msg == NULL)) {
+		pr_err("qseecom cmd failed with err=%d status=%d\n",
+		       rc, rsp_buf->status);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	pr_debug("recvd %s from TZ at %dms\n",
+		 hdcp_lib_message_name((int)rsp_buf->msg[0]),
+		 jiffies_to_msecs(jiffies));
+
+	handle->last_msg = (int)rsp_buf->msg[0];
+
+	/* set the flag if response is AKE_No_Stored_km */
+	if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
+		pr_debug("Setting no_stored_km_flag\n");
+		handle->no_stored_km_flag = 1;
+	} else {
+		handle->no_stored_km_flag = 0;
+	}
+
+	/* check if it's a repeater */
+	if ((rsp_buf->msg[0] == SKE_SEND_EKS_MESSAGE_ID) &&
+	    (rsp_buf->msglen == SKE_SEND_EKS_MESSAGE_SIZE)) {
+		if ((rsp_buf->flag ==
+		     HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) &&
+		    (rsp_buf->timeout > 0))
+			handle->repeater_flag = true;
+		handle->update_stream = true;
+	}
+
+	memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+	memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
+	       rsp_buf->msglen);
+	handle->hdcp_timeout = rsp_buf->timeout;
+	handle->msglen = rsp_buf->msglen;
+
+	if (!atomic_read(&handle->hdcp_off))
+		hdcp_lib_send_message(handle);
+exit:
+	kzfree(msg);
+
+	hdcp_lib_wakeup_client(handle, &cdata);
+
+	if (rc && !atomic_read(&handle->hdcp_off))
+		HDCP_LIB_EXECUTE(clean);
+}
+
+static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
+{
+	struct hdcp_lib_handle *handle = container_of(work,
+						      struct hdcp_lib_handle,
+						      wk_msg_recvd);
+
+	hdcp_lib_msg_recvd(handle);
+}
+
+static void hdcp_lib_wait_work(struct kthread_work *work)
+{
+	u32 timeout;
+	struct hdcp_lib_handle *handle = container_of(work,
+				struct hdcp_lib_handle, wk_wait);
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	if (atomic_read(&handle->hdcp_off)) {
+		pr_debug("invalid state: hdcp off\n");
+		return;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_ERROR) {
+		pr_debug("invalid state: hdcp error\n");
+		return;
+	}
+
+	reinit_completion(&handle->poll_wait);
+	timeout = wait_for_completion_timeout(&handle->poll_wait,
+			handle->wait_timeout);
+	if (!timeout) {
+		pr_err("wait timeout\n");
+
+		if (!atomic_read(&handle->hdcp_off))
+			HDCP_LIB_EXECUTE(clean);
+	}
+
+	handle->wait_timeout = 0;
+}
+
+bool hdcp1_check_if_supported_load_app(void)
+{
+	int rc = 0;
+
+	/* start hdcp1 app */
+	if (hdcp1_supported && !hdcp1_handle) {
+		rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
+				       QSEECOM_SBUFF_SIZE);
+		if (rc) {
+			pr_err("qseecom_start_app failed %d\n", rc);
+			hdcp1_supported = false;
+		} else {
+			mutex_init(&hdcp1_ta_cmd_lock);
+		}
+	}
+
+	pr_debug("hdcp1 app %s loaded\n",
+		 hdcp1_supported ? "successfully" : "not");
+
+	return hdcp1_supported;
+}
+
+/* APIs exposed to all clients */
+int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
+{
+	int rc = 0;
+	struct hdcp1_key_set_req *key_set_req;
+	struct hdcp1_key_set_rsp *key_set_rsp;
+
+	if (aksv_msb == NULL || aksv_lsb == NULL)
+		return -EINVAL;
+
+	if (!hdcp1_supported || !hdcp1_handle)
+		return -EINVAL;
+
+	/* set keys and request aksv */
+	key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
+	key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
+	key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_handle->sbuf +
+			   QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
+	rc = qseecom_send_command(hdcp1_handle, key_set_req,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp1_key_set_req)),
+				  key_set_rsp,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp1_key_set_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err=%d\n", rc);
+		return -ENOKEY;
+	}
+
+	rc = key_set_rsp->ret;
+	if (rc) {
+		pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
+		return -ENOKEY;
+	}
+
+	/* copy bytes into msb and lsb */
+	*aksv_msb = key_set_rsp->ksv[0] << 24 | key_set_rsp->ksv[1] << 16 |
+		key_set_rsp->ksv[2] << 8 | key_set_rsp->ksv[3];
+	*aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 |
+		key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7];
+
+	return 0;
+}
+
+int hdcp1_set_enc(bool enable)
+{
+	int rc = 0;
+	struct hdcp1_set_enc_req *set_enc_req;
+	struct hdcp1_set_enc_rsp *set_enc_rsp;
+
+	mutex_lock(&hdcp1_ta_cmd_lock);
+
+	if (!hdcp1_supported || !hdcp1_handle) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (hdcp1_enc_enabled == enable) {
+		pr_info("already %s\n", enable ? "enabled" : "disabled");
+		goto end;
+	}
+
+	/* set keys and request aksv */
+	set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_handle->sbuf;
+	set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
+	set_enc_req->enable = enable;
+	set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_handle->sbuf +
+			QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
+	rc = qseecom_send_command(hdcp1_handle, set_enc_req,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp1_set_enc_req)),
+				  set_enc_rsp,
+				  QSEECOM_ALIGN(sizeof
+						(struct hdcp1_set_enc_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err=%d\n", rc);
+		goto end;
+	}
+
+	rc = set_enc_rsp->ret;
+	if (rc) {
+		pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	hdcp1_enc_enabled = enable;
+	pr_info("%s success\n", enable ? "enable" : "disable");
+end:
+	mutex_unlock(&hdcp1_ta_cmd_lock);
+	return rc;
+}
+
+int hdcp_library_register(struct hdcp_register_data *data)
+{
+	int rc = 0;
+	struct hdcp_lib_handle *handle = NULL;
+
+	if (!data) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	if (!data->txmtr_ops) {
+		pr_err("invalid input: txmtr context\n");
+		return -EINVAL;
+	}
+
+	if (!data->client_ops) {
+		pr_err("invalid input: client_ops\n");
+		return -EINVAL;
+	}
+
+	if (!data->hdcp_ctx) {
+		pr_err("invalid input: hdcp_ctx\n");
+		return -EINVAL;
+	}
+
+	/* populate ops to be called by client */
+	data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
+	data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle) {
+		rc = -ENOMEM;
+		goto unlock;
+	}
+
+	handle->client_ctx = data->client_ctx;
+	handle->client_ops = data->client_ops;
+	handle->hdcp_app_init = NULL;
+	handle->hdcp_txmtr_init = NULL;
+	handle->device_type = data->device_type;
+
+	atomic_set(&handle->hdcp_off, 0);
+
+	mutex_init(&handle->msg_lock);
+	mutex_init(&handle->wakeup_mutex);
+
+	kthread_init_worker(&handle->worker);
+
+	kthread_init_work(&handle->wk_init, hdcp_lib_init_work);
+	kthread_init_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work);
+	kthread_init_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
+	kthread_init_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
+	kthread_init_work(&handle->wk_clean, hdcp_lib_cleanup_work);
+	kthread_init_work(&handle->wk_wait, hdcp_lib_wait_work);
+	kthread_init_work(&handle->wk_stream, hdcp_lib_query_stream_work);
+
+	init_completion(&handle->poll_wait);
+
+	handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
+	if (!(handle->listener_buf)) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	*data->hdcp_ctx = handle;
+
+	handle->thread = kthread_run(kthread_worker_fn,
+				     &handle->worker, "hdcp_tz_lib");
+
+	if (IS_ERR(handle->thread)) {
+		pr_err("unable to start lib thread\n");
+		rc = PTR_ERR(handle->thread);
+		handle->thread = NULL;
+		goto error;
+	}
+
+	return 0;
+error:
+	kzfree(handle->listener_buf);
+	handle->listener_buf = NULL;
+	kzfree(handle);
+	handle = NULL;
+unlock:
+	return rc;
+}
+EXPORT_SYMBOL(hdcp_library_register);
+
+void hdcp_library_deregister(void *phdcpcontext)
+{
+	struct hdcp_lib_handle *handle = phdcpcontext;
+
+	if (!handle)
+		return;
+
+	kthread_stop(handle->thread);
+
+	kzfree(handle->qseecom_handle);
+	kzfree(handle->last_msg_recvd_buf);
+
+	mutex_destroy(&handle->wakeup_mutex);
+
+	kzfree(handle->listener_buf);
+	kzfree(handle);
+}
+EXPORT_SYMBOL(hdcp_library_deregister);
+
diff --git a/drivers/misc/msm_hdcp.c b/drivers/misc/msm_hdcp.c
new file mode 100644
index 0000000..ea8e84d
--- /dev/null
+++ b/drivers/misc/msm_hdcp.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"[msm-hdcp] %s: " fmt, __func__
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/msm_hdcp.h>
+#include <linux/of.h>
+
+#define CLASS_NAME "hdcp"
+#define DRIVER_NAME "msm_hdcp"
+
+struct msm_hdcp {
+	struct platform_device *pdev;
+	dev_t dev_num;
+	struct cdev cdev;
+	struct class *class;
+	struct device *device;
+	struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+	u32 tp_msgid;
+	void *client_ctx;
+	void (*cb)(void *ctx, int data);
+};
+
+void msm_hdcp_register_cb(struct device *dev, void *ctx,
+		void (*cb)(void *ctx, int data))
+{
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev) {
+		pr_err("invalid device pointer\n");
+		return;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return;
+	}
+
+	hdcp->cb = cb;
+	hdcp->client_ctx = ctx;
+}
+
+void msm_hdcp_notify_topology(struct device *dev)
+{
+	char *envp[4];
+	char tp[SZ_16];
+	char ver[SZ_16];
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev) {
+		pr_err("invalid device pointer\n");
+		return;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return;
+	}
+
+	snprintf(tp, SZ_16, "%d", DOWN_CHECK_TOPOLOGY);
+	snprintf(ver, SZ_16, "%d", HDCP_V1_TX);
+
+	envp[0] = "HDCP_MGR_EVENT=MSG_READY";
+	envp[1] = tp;
+	envp[2] = ver;
+	envp[3] = NULL;
+
+	kobject_uevent_env(&hdcp->device->kobj, KOBJ_CHANGE, envp);
+}
+
+void msm_hdcp_cache_repeater_topology(struct device *dev,
+			struct HDCP_V2V1_MSG_TOPOLOGY *tp)
+{
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev || !tp) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return;
+	}
+
+	memcpy(&hdcp->cached_tp, tp,
+		   sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+}
+
+static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev) {
+		pr_err("invalid device pointer\n");
+		return -ENODEV;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return -ENODEV;
+	}
+
+	switch (hdcp->tp_msgid) {
+	case DOWN_CHECK_TOPOLOGY:
+	case DOWN_REQUEST_TOPOLOGY:
+		buf[MSG_ID_IDX]   = hdcp->tp_msgid;
+		buf[RET_CODE_IDX] = HDCP_AUTHED;
+		ret = HEADER_LEN;
+
+		memcpy(buf + HEADER_LEN, &hdcp->cached_tp,
+			   sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+		ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+		/* clear the flag once data is read back to user space*/
+		hdcp->tp_msgid = -1;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int msgid = 0;
+	ssize_t ret = count;
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev) {
+		pr_err("invalid device pointer\n");
+		return -ENODEV;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return -ENODEV;
+	}
+
+	msgid = buf[0];
+
+	switch (msgid) {
+	case DOWN_CHECK_TOPOLOGY:
+	case DOWN_REQUEST_TOPOLOGY:
+		hdcp->tp_msgid = msgid;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static ssize_t msm_hdcp_2x_sysfs_wta_min_level_change(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc;
+	int min_enc_lvl;
+	ssize_t ret = count;
+	struct msm_hdcp *hdcp = NULL;
+
+	if (!dev) {
+		pr_err("invalid device pointer\n");
+		return -ENODEV;
+	}
+
+	hdcp = dev_get_drvdata(dev);
+	if (!hdcp) {
+		pr_err("invalid driver pointer\n");
+		return -ENODEV;
+	}
+
+	rc = kstrtoint(buf, 10, &min_enc_lvl);
+	if (rc) {
+		pr_err("kstrtoint failed. rc=%d\n", rc);
+		return -EINVAL;
+	}
+
+	if (hdcp->cb && hdcp->client_ctx)
+		hdcp->cb(hdcp->client_ctx, min_enc_lvl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
+	msm_hdcp_1x_sysfs_wta_tp);
+
+static DEVICE_ATTR(min_level_change, 0200, NULL,
+	msm_hdcp_2x_sysfs_wta_min_level_change);
+
+static struct attribute *msm_hdcp_fs_attrs[] = {
+	&dev_attr_tp.attr,
+	&dev_attr_min_level_change.attr,
+	NULL
+};
+
+static struct attribute_group msm_hdcp_fs_attr_group = {
+	.attrs = msm_hdcp_fs_attrs
+};
+
+static int msm_hdcp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int msm_hdcp_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations msm_hdcp_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_hdcp_open,
+	.release = msm_hdcp_close,
+};
+
+static const struct of_device_id msm_hdcp_dt_match[] = {
+	{ .compatible = "qcom,msm-hdcp",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
+
+static int msm_hdcp_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct msm_hdcp *hdcp;
+
+	hdcp = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp), GFP_KERNEL);
+	if (!hdcp)
+		return -ENOMEM;
+
+	hdcp->pdev = pdev;
+
+	platform_set_drvdata(pdev, hdcp);
+
+	ret = alloc_chrdev_region(&hdcp->dev_num, 0, 1, DRIVER_NAME);
+	if (ret  < 0) {
+		pr_err("alloc_chrdev_region failed ret = %d\n", ret);
+		goto error_get_dev_num;
+	}
+
+	hdcp->class = class_create(THIS_MODULE, CLASS_NAME);
+	if (IS_ERR(hdcp->class)) {
+		ret = PTR_ERR(hdcp->class);
+		pr_err("couldn't create class rc = %d\n", ret);
+		goto error_class_create;
+	}
+
+	hdcp->device = device_create(hdcp->class, NULL,
+		hdcp->dev_num, NULL, DRIVER_NAME);
+	if (IS_ERR(hdcp->device)) {
+		ret = PTR_ERR(hdcp->device);
+		pr_err("device_create failed %d\n", ret);
+		goto error_class_device_create;
+	}
+
+	cdev_init(&hdcp->cdev, &msm_hdcp_fops);
+	ret = cdev_add(&hdcp->cdev, MKDEV(MAJOR(hdcp->dev_num), 0), 1);
+	if (ret < 0) {
+		pr_err("cdev_add failed %d\n", ret);
+		goto error_cdev_add;
+	}
+
+	ret = sysfs_create_group(&hdcp->device->kobj, &msm_hdcp_fs_attr_group);
+	if (ret)
+		pr_err("unable to register msm_hdcp sysfs nodes\n");
+
+	return 0;
+error_cdev_add:
+	device_destroy(hdcp->class, hdcp->dev_num);
+error_class_device_create:
+	class_destroy(hdcp->class);
+error_class_create:
+	unregister_chrdev_region(hdcp->dev_num, 1);
+error_get_dev_num:
+	devm_kfree(&pdev->dev, hdcp);
+	hdcp = NULL;
+	return ret;
+}
+
+static int msm_hdcp_remove(struct platform_device *pdev)
+{
+	struct msm_hdcp *hdcp;
+
+	hdcp = platform_get_drvdata(pdev);
+	if (!hdcp)
+		return -ENODEV;
+
+	sysfs_remove_group(&hdcp->device->kobj,
+	&msm_hdcp_fs_attr_group);
+	cdev_del(&hdcp->cdev);
+	device_destroy(hdcp->class, hdcp->dev_num);
+	class_destroy(hdcp->class);
+	unregister_chrdev_region(hdcp->dev_num, 1);
+
+	devm_kfree(&pdev->dev, hdcp);
+	hdcp = NULL;
+	return 0;
+}
+
+static struct platform_driver msm_hdcp_driver = {
+	.probe = msm_hdcp_probe,
+	.remove = msm_hdcp_remove,
+	.driver = {
+		.name = "msm_hdcp",
+		.of_match_table = msm_hdcp_dt_match,
+		.pm = NULL,
+	}
+};
+
+static int __init msm_hdcp_init(void)
+{
+	return platform_driver_register(&msm_hdcp_driver);
+}
+
+static void __exit msm_hdcp_exit(void)
+{
+	return platform_driver_unregister(&msm_hdcp_driver);
+}
+
+module_init(msm_hdcp_init);
+module_exit(msm_hdcp_exit);
+
+MODULE_DESCRIPTION("MSM HDCP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 146ca6f..232b4ae 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,7 +1,7 @@
 /*
  * QTI Secure Execution Environment Communicator (QSEECOM) driver
  *
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -1848,7 +1848,7 @@
 	return ret;
 }
 
-static int __qseecom_process_blocked_on_listener_legacy(
+static int __qseecom_process_reentrancy_blocked_on_listener(
 				struct qseecom_command_scm_resp *resp,
 				struct qseecom_registered_app_list *ptr_app,
 				struct qseecom_dev_handle *data)
@@ -1857,8 +1857,11 @@
 	int ret = 0;
 	struct qseecom_continue_blocked_request_ireq ireq;
 	struct qseecom_command_scm_resp continue_resp;
-	bool found_app = false;
+	unsigned int session_id;
+	sigset_t new_sigset;
+	sigset_t old_sigset;
 	unsigned long flags;
+	bool found_app = false;
 
 	if (!resp || !data) {
 		pr_err("invalid resp or data pointer\n");
@@ -1889,137 +1892,81 @@
 		}
 	}
 
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-	ptr_app->blocked_on_listener_id = resp->data;
-
-	/* sleep until listener is available */
 	do {
-		qseecom.app_block_ref_cnt++;
-		ptr_app->app_blocked = true;
-		mutex_unlock(&app_access_lock);
-		if (wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use)) {
-			pr_err("Interrupted: listener_id %d, app_id %d\n",
-				resp->data, ptr_app->app_id);
-			ret = -ERESTARTSYS;
+		session_id = resp->resp_type;
+		list_ptr = __qseecom_find_svc(resp->data);
+		if (!list_ptr) {
+			pr_err("Invalid listener ID %d\n", resp->data);
+			ret = -ENODATA;
 			goto exit;
 		}
-		mutex_lock(&app_access_lock);
-		ptr_app->app_blocked = false;
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
+		ptr_app->blocked_on_listener_id = resp->data;
 
-	ptr_app->blocked_on_listener_id = 0;
-	/* notify the blocked app that listener is available */
-	pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n",
-		resp->data, data->client.app_id,
-		data->client.app_name);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = data->client.app_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n",
-			data->client.app_id,
-			data->client.app_name, ret);
-		goto exit;
-	}
-	/*
-	 * After TZ app is unblocked, then continue to next case
-	 * for incomplete request processing
-	 */
-	resp->result = QSEOS_RESULT_INCOMPLETE;
-exit:
-	return ret;
-}
+		pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
+			resp->data, list_ptr->listener_in_use,
+			session_id, data->client.app_id);
 
-static int __qseecom_process_blocked_on_listener_smcinvoke(
-			struct qseecom_command_scm_resp *resp, uint32_t app_id)
-{
-	struct qseecom_registered_listener_list *list_ptr;
-	int ret = 0;
-	struct qseecom_continue_blocked_request_ireq ireq;
-	struct qseecom_command_scm_resp continue_resp;
-	unsigned int session_id;
+		/* sleep until listener is available */
+		sigfillset(&new_sigset);
+		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
 
-	if (!resp) {
-		pr_err("invalid resp pointer\n");
-		ret = -EINVAL;
-		goto exit;
-	}
-	session_id = resp->resp_type;
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-	/* sleep until listener is available */
-	do {
-		qseecom.app_block_ref_cnt++;
-		mutex_unlock(&app_access_lock);
-		if (wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use)) {
-			pr_err("Interrupted: listener_id %d, session_id %d\n",
-				resp->data, session_id);
-			ret = -ERESTARTSYS;
-			goto exit;
-		}
-		mutex_lock(&app_access_lock);
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
+		do {
+			qseecom.app_block_ref_cnt++;
+			ptr_app->app_blocked = true;
+			mutex_unlock(&app_access_lock);
+			wait_event_freezable(
+				list_ptr->listener_block_app_wq,
+				!list_ptr->listener_in_use);
+			mutex_lock(&app_access_lock);
+			ptr_app->app_blocked = false;
+			qseecom.app_block_ref_cnt--;
+		}  while (list_ptr->listener_in_use);
 
-	/* notify TZ that listener is available */
-	pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
-			resp->data, session_id);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = session_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		/* retry with legacy cmd */
-		qseecom.smcinvoke_support = false;
-		ireq.app_or_session_id = app_id;
+		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+
+		ptr_app->blocked_on_listener_id = 0;
+		pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
+			resp->data, session_id, data->client.app_id);
+
+		/* notify TZ that listener is available */
+		ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
+
+		if (qseecom.smcinvoke_support)
+			ireq.app_or_session_id = session_id;
+		else
+			ireq.app_or_session_id = data->client.app_id;
+
 		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-		qseecom.smcinvoke_support = true;
-		if (ret) {
-			pr_err("cont block req for app %d or session %d fail\n",
-				app_id, session_id);
-			goto exit;
+					&ireq, sizeof(ireq),
+					&continue_resp, sizeof(continue_resp));
+		if (ret && qseecom.smcinvoke_support) {
+			/* retry with legacy cmd */
+			qseecom.smcinvoke_support = false;
+			ireq.app_or_session_id = data->client.app_id;
+			ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+				&ireq, sizeof(ireq),
+				&continue_resp, sizeof(continue_resp));
+			qseecom.smcinvoke_support = true;
+			if (ret) {
+				pr_err("unblock app %d or session %d fail\n",
+					data->client.app_id, session_id);
+				goto exit;
+			}
 		}
+		resp->result = continue_resp.result;
+		resp->resp_type = continue_resp.resp_type;
+		resp->data = continue_resp.data;
+		pr_debug("unblock resp = %d\n", resp->result);
+	} while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
+
+	if (resp->result != QSEOS_RESULT_INCOMPLETE) {
+		pr_err("Unexpected unblock resp %d\n", resp->result);
+		ret = -EINVAL;
 	}
-	resp->result = QSEOS_RESULT_INCOMPLETE;
 exit:
 	return ret;
 }
 
-static int __qseecom_process_reentrancy_blocked_on_listener(
-				struct qseecom_command_scm_resp *resp,
-				struct qseecom_registered_app_list *ptr_app,
-				struct qseecom_dev_handle *data)
-{
-	if (!qseecom.smcinvoke_support)
-		return __qseecom_process_blocked_on_listener_legacy(
-			resp, ptr_app, data);
-	else
-		return __qseecom_process_blocked_on_listener_smcinvoke(
-			resp, data->client.app_id);
-}
 static int __qseecom_reentrancy_process_incomplete_cmd(
 					struct qseecom_dev_handle *data,
 					struct qseecom_command_scm_resp *resp)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 89edc6d..289f3bc 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -470,6 +470,9 @@
 		mmc_host_clear_sdr104(host);
 		err = mmc_hw_reset(host);
 		host->card->sdr104_blocked = true;
+	} else {
+		/* If sdr104_wa is not present, just return status */
+		err = host->bus_ops->alive(host);
 	}
 	if (err)
 		pr_err("%s: %s: Fallback to lower speed mode failed with err=%d\n",
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 55ce946..01811d9 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -357,7 +357,7 @@
 	if (!cq_host->desc_base || !cq_host->trans_desc_base)
 		return -ENOMEM;
 
-	pr_info("desc-base: 0x%p trans-base: 0x%p\n desc_dma 0x%llx trans_dma: 0x%llx\n",
+	pr_debug("desc-base: 0x%pK trans-base: 0x%pK\n desc_dma 0x%llx trans_dma: 0x%llx\n",
 		 cq_host->desc_base, cq_host->trans_desc_base,
 		(unsigned long long)cq_host->desc_dma_base,
 		(unsigned long long) cq_host->trans_desc_dma_base);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 0d6f263..0bea2cb 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1916,7 +1916,11 @@
 			err = PTR_ERR(buf);
 		}
 	} else {
-		val = *buf;
+		/*
+		 * 30 bits from bit offset 0 would be read.
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
 		kfree(buf);
 	}
 
@@ -2688,6 +2692,52 @@
 			msm_host_offset->CORE_PWRCTL_CTL), irq_flags);
 }
 
+static int sdhci_msm_clear_pwrctl_status(struct sdhci_host *host, u8 value)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	const struct sdhci_msm_offset *msm_host_offset = msm_host->offset;
+	int ret = 0, retry = 10;
+
+	/*
+	 * There is a rare HW scenario where the first clear pulse could be
+	 * lost when actual reset and clear/read of status register is
+	 * happening at a time. Hence, retry for at least 10 times to make
+	 * sure status register is cleared. Otherwise, this will result in
+	 * a spurious power IRQ resulting in system instability.
+	 */
+	do {
+		if (retry == 0) {
+			pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
+				mmc_hostname(host->mmc), value);
+			sdhci_msm_dump_pwr_ctrl_regs(host);
+			WARN_ON(1);
+			ret = -EBUSY;
+			break;
+		}
+
+		/*
+		 * Clear the PWRCTL_STATUS interrupt bits by writing to the
+		 * corresponding bits in the PWRCTL_CLEAR register.
+		 */
+		sdhci_msm_writeb_relaxed(value, host,
+				msm_host_offset->CORE_PWRCTL_CLEAR);
+		/*
+		 * SDHC has core_mem and hc_mem device memory and these memory
+		 * addresses do not fall within 1KB region. Hence, any update
+		 * to core_mem address space would require an mb() to ensure
+		 * this gets completed before its next update to registers
+		 * within hc_mem.
+		 */
+		mb();
+		retry--;
+		udelay(10);
+	} while (value & sdhci_msm_readb_relaxed(host,
+				msm_host_offset->CORE_PWRCTL_STATUS));
+
+	return ret;
+}
+
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
 	struct sdhci_host *host = (struct sdhci_host *)data;
@@ -2700,7 +2750,6 @@
 	int ret = 0;
 	int pwr_state = 0, io_level = 0;
 	unsigned long flags;
-	int retry = 10;
 
 	irq_status = sdhci_msm_readb_relaxed(host,
 		msm_host_offset->CORE_PWRCTL_STATUS);
@@ -2708,40 +2757,7 @@
 	pr_debug("%s: Received IRQ(%d), status=0x%x\n",
 		mmc_hostname(msm_host->mmc), irq, irq_status);
 
-	/* Clear the interrupt */
-	sdhci_msm_writeb_relaxed(irq_status, host,
-		msm_host_offset->CORE_PWRCTL_CLEAR);
-
-	/*
-	 * SDHC has core_mem and hc_mem device memory and these memory
-	 * addresses do not fall within 1KB region. Hence, any update to
-	 * core_mem address space would require an mb() to ensure this gets
-	 * completed before its next update to registers within hc_mem.
-	 */
-	mb();
-	/*
-	 * There is a rare HW scenario where the first clear pulse could be
-	 * lost when actual reset and clear/read of status register is
-	 * happening at a time. Hence, retry for at least 10 times to make
-	 * sure status register is cleared. Otherwise, this will result in
-	 * a spurious power IRQ resulting in system instability.
-	 */
-	while (irq_status & sdhci_msm_readb_relaxed(host,
-		msm_host_offset->CORE_PWRCTL_STATUS)) {
-		if (retry == 0) {
-			pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
-				mmc_hostname(host->mmc), irq_status);
-			sdhci_msm_dump_pwr_ctrl_regs(host);
-			BUG_ON(1);
-		}
-		sdhci_msm_writeb_relaxed(irq_status, host,
-			msm_host_offset->CORE_PWRCTL_CLEAR);
-		retry--;
-		udelay(10);
-	}
-	if (likely(retry < 10))
-		pr_debug("%s: success clearing (0x%x) pwrctl status register, retries left %d\n",
-				mmc_hostname(host->mmc), irq_status, retry);
+	sdhci_msm_clear_pwrctl_status(host, irq_status);
 
 	/* Handle BUS ON/OFF*/
 	if (irq_status & CORE_PWRCTL_BUS_ON) {
@@ -3120,6 +3136,7 @@
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	u8 irq_status;
 	const struct sdhci_msm_offset *msm_host_offset =
 					msm_host->offset;
 
@@ -3127,10 +3144,9 @@
 		!msm_host->regs_restore.is_valid)
 		return;
 
+	writel_relaxed(0, host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
 	writel_relaxed(msm_host->regs_restore.vendor_func, host->ioaddr +
 			msm_host_offset->CORE_VENDOR_SPEC);
-	writel_relaxed(msm_host->regs_restore.vendor_pwrctl_mask,
-			host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
 	writel_relaxed(msm_host->regs_restore.vendor_func2,
 			host->ioaddr +
 			msm_host_offset->CORE_VENDOR_SPEC_FUNC2);
@@ -3141,8 +3157,6 @@
 			SDHCI_CLOCK_CONTROL);
 	sdhci_writel(host, msm_host->regs_restore.hc_3c_3e,
 			SDHCI_AUTO_CMD_ERR);
-	writel_relaxed(msm_host->regs_restore.vendor_pwrctl_ctl,
-			host->ioaddr + msm_host_offset->CORE_PWRCTL_CTL);
 	sdhci_writel(host, msm_host->regs_restore.hc_38_3a,
 			SDHCI_SIGNAL_ENABLE);
 	sdhci_writel(host, msm_host->regs_restore.hc_34_36,
@@ -3158,6 +3172,24 @@
 			msm_host_offset->CORE_TESTBUS_CONFIG);
 	msm_host->regs_restore.is_valid = false;
 
+	/*
+	 * Clear the PWRCTL_STATUS register.
+	 * There is a rare HW scenario where the first clear pulse could be
+	 * lost when actual reset and clear/read of status register is
+	 * happening at a time. Hence, retry for at least 10 times to make
+	 * sure status register is cleared. Otherwise, this will result in
+	 * a spurious power IRQ resulting in system instability.
+	 */
+	irq_status = sdhci_msm_readb_relaxed(host,
+				msm_host_offset->CORE_PWRCTL_STATUS);
+
+	sdhci_msm_clear_pwrctl_status(host, irq_status);
+
+	writel_relaxed(msm_host->regs_restore.vendor_pwrctl_ctl,
+			host->ioaddr + msm_host_offset->CORE_PWRCTL_CTL);
+	writel_relaxed(msm_host->regs_restore.vendor_pwrctl_mask,
+			host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
+
 	pr_debug("%s: %s: registers restored. PWRCTL_MASK = 0x%x\n",
 		mmc_hostname(host->mmc), __func__,
 		readl_relaxed(host->ioaddr +
@@ -4237,11 +4269,10 @@
 		group->latency = PM_QOS_DEFAULT_VALUE;
 		pm_qos_add_request(&group->req, PM_QOS_CPU_DMA_LATENCY,
 			group->latency);
-		pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d (0x%p)\n",
+		pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d\n",
 			__func__, i,
 			group->req.cpus_affine.bits[0],
-			group->latency,
-			&latency[i].latency[SDHCI_PERFORMANCE_MODE]);
+			group->latency);
 	}
 	msm_host->pm_qos_prev_cpu = -1;
 	msm_host->pm_qos_group_enable = true;
@@ -4808,8 +4839,6 @@
 			goto vreg_deinit;
 		}
 		writel_relaxed(readl_relaxed(tlmm_mem) | 0x2, tlmm_mem);
-		dev_dbg(&pdev->dev, "tlmm reg %pa value 0x%08x\n",
-				&tlmm_memres->start, readl_relaxed(tlmm_mem));
 	}
 
 	/*
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 566be69..b674b38 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3068,13 +3068,13 @@
 		struct sdhci_adma2_64_desc *dma_desc = desc;
 
 		if (host->flags & SDHCI_USE_64_BIT_DMA)
-			DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+			DBG("%s: %pK: DMA 0x%08x%08x, LEN 0x%04x,Attr=0x%02x\n",
 			    name, desc, le32_to_cpu(dma_desc->addr_hi),
 			    le32_to_cpu(dma_desc->addr_lo),
 			    le16_to_cpu(dma_desc->len),
 			    le16_to_cpu(dma_desc->cmd));
 		else
-			DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+			DBG("%s: %pK: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
 			    name, desc, le32_to_cpu(dma_desc->addr_lo),
 			    le16_to_cpu(dma_desc->len),
 			    le16_to_cpu(dma_desc->cmd));
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index d9fab22..1a4a790 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -2193,16 +2193,9 @@
 	if (ctrl->nand_version >= 0x0702)
 		tmp |= ACC_CONTROL_RD_ERASED;
 	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
-	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
-		/*
-		 * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
-		 * errors
-		 */
-		if (has_flash_dma(ctrl))
-			tmp &= ~ACC_CONTROL_PREFETCH;
-		else
-			tmp |= ACC_CONTROL_PREFETCH;
-	}
+	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
+		tmp &= ~ACC_CONTROL_PREFETCH;
+
 	nand_writereg(ctrl, offs, tmp);
 
 	return 0;
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
index de31514..d38527e 100644
--- a/drivers/mtd/nand/denali_pci.c
+++ b/drivers/mtd/nand/denali_pci.c
@@ -119,3 +119,7 @@
 };
 
 module_pci_driver(denali_pci_driver);
+
+MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a77cfd7..21c0308 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2320,6 +2320,7 @@
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			    struct mtd_oob_ops *ops)
 {
+	unsigned int max_bitflips = 0;
 	int page, realpage, chipnr;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct mtd_ecc_stats stats;
@@ -2377,6 +2378,8 @@
 				nand_wait_ready(mtd);
 		}
 
+		max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
 		readlen -= len;
 		if (!readlen)
 			break;
@@ -2402,7 +2405,7 @@
 	if (mtd->ecc_stats.failed - stats.failed)
 		return -EBADMSG;
 
-	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+	return max_bitflips;
 }
 
 /**
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index f9b2a77..e26c4f8 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1835,8 +1835,14 @@
 
 	/* Add ECC info retrieval from DT */
 	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
-		if (ecc->strength <= strengths[i])
+		if (ecc->strength <= strengths[i]) {
+			/*
+			 * Update ecc->strength value with the actual strength
+			 * that will be used by the ECC engine.
+			 */
+			ecc->strength = strengths[i];
 			break;
+		}
 	}
 
 	if (i >= ARRAY_SIZE(strengths)) {
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index d1e6931..46913ef2 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -99,6 +99,8 @@
 
 /* Linked list of all ubiblock instances */
 static LIST_HEAD(ubiblock_devices);
+static DEFINE_IDR(ubiblock_minor_idr);
+/* Protects ubiblock_devices and ubiblock_minor_idr */
 static DEFINE_MUTEX(devices_mutex);
 static int ubiblock_major;
 
@@ -353,8 +355,6 @@
 	.init_request	= ubiblock_init_request,
 };
 
-static DEFINE_IDR(ubiblock_minor_idr);
-
 int ubiblock_create(struct ubi_volume_info *vi)
 {
 	struct ubiblock *dev;
@@ -367,14 +367,15 @@
 	/* Check that the volume isn't already handled */
 	mutex_lock(&devices_mutex);
 	if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
-		mutex_unlock(&devices_mutex);
-		return -EEXIST;
+		ret = -EEXIST;
+		goto out_unlock;
 	}
-	mutex_unlock(&devices_mutex);
 
 	dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
 
 	mutex_init(&dev->dev_mutex);
 
@@ -439,14 +440,13 @@
 		goto out_free_queue;
 	}
 
-	mutex_lock(&devices_mutex);
 	list_add_tail(&dev->list, &ubiblock_devices);
-	mutex_unlock(&devices_mutex);
 
 	/* Must be the last step: anyone can call file ops from now on */
 	add_disk(dev->gd);
 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
 		 dev->ubi_num, dev->vol_id, vi->name);
+	mutex_unlock(&devices_mutex);
 	return 0;
 
 out_free_queue:
@@ -459,6 +459,8 @@
 	put_disk(dev->gd);
 out_free_dev:
 	kfree(dev);
+out_unlock:
+	mutex_unlock(&devices_mutex);
 
 	return ret;
 }
@@ -480,30 +482,36 @@
 int ubiblock_remove(struct ubi_volume_info *vi)
 {
 	struct ubiblock *dev;
+	int ret;
 
 	mutex_lock(&devices_mutex);
 	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
 	if (!dev) {
-		mutex_unlock(&devices_mutex);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out_unlock;
 	}
 
 	/* Found a device, let's lock it so we can check if it's busy */
 	mutex_lock(&dev->dev_mutex);
 	if (dev->refcnt > 0) {
-		mutex_unlock(&dev->dev_mutex);
-		mutex_unlock(&devices_mutex);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out_unlock_dev;
 	}
 
 	/* Remove from device list */
 	list_del(&dev->list);
-	mutex_unlock(&devices_mutex);
-
 	ubiblock_cleanup(dev);
 	mutex_unlock(&dev->dev_mutex);
+	mutex_unlock(&devices_mutex);
+
 	kfree(dev);
 	return 0;
+
+out_unlock_dev:
+	mutex_unlock(&dev->dev_mutex);
+out_unlock:
+	mutex_unlock(&devices_mutex);
+	return ret;
 }
 
 static int ubiblock_resize(struct ubi_volume_info *vi)
@@ -632,6 +640,7 @@
 	struct ubiblock *next;
 	struct ubiblock *dev;
 
+	mutex_lock(&devices_mutex);
 	list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
 		/* The module is being forcefully removed */
 		WARN_ON(dev->desc);
@@ -640,6 +649,7 @@
 		ubiblock_cleanup(dev);
 		kfree(dev);
 	}
+	mutex_unlock(&devices_mutex);
 }
 
 int __init ubiblock_init(void)
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index b5b8cd6..668b462 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1529,6 +1529,46 @@
 }
 
 /**
+ * erase_aeb - erase a PEB given in UBI attach info PEB
+ * @ubi: UBI device description object
+ * @aeb: UBI attach info PEB
+ * @sync: If true, erase synchronously. Otherwise schedule for erasure
+ */
+static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
+{
+	struct ubi_wl_entry *e;
+	int err;
+
+	e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+	if (!e)
+		return -ENOMEM;
+
+	e->pnum = aeb->pnum;
+	e->ec = aeb->ec;
+	ubi->lookuptbl[e->pnum] = e;
+
+	if (sync) {
+		err = sync_erase(ubi, e, false);
+		if (err)
+			goto out_free;
+
+		wl_tree_add(e, &ubi->free);
+		ubi->free_count++;
+	} else {
+		err = schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false);
+		if (err)
+			goto out_free;
+	}
+
+	return 0;
+
+out_free:
+	wl_entry_destroy(ubi, e);
+
+	return err;
+}
+
+/**
  * ubi_wl_init - initialize the WL sub-system using attaching information.
  * @ubi: UBI device description object
  * @ai: attaching information
@@ -1566,18 +1606,10 @@
 	list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
 		cond_resched();
 
-		e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-		if (!e)
+		err = erase_aeb(ubi, aeb, false);
+		if (err)
 			goto out_free;
 
-		e->pnum = aeb->pnum;
-		e->ec = aeb->ec;
-		ubi->lookuptbl[e->pnum] = e;
-		if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
-			wl_entry_destroy(ubi, e);
-			goto out_free;
-		}
-
 		found_pebs++;
 	}
 
@@ -1635,6 +1667,8 @@
 			ubi_assert(!ubi->lookuptbl[e->pnum]);
 			ubi->lookuptbl[e->pnum] = e;
 		} else {
+			bool sync = false;
+
 			/*
 			 * Usually old Fastmap PEBs are scheduled for erasure
 			 * and we don't have to care about them but if we face
@@ -1644,18 +1678,21 @@
 			if (ubi->lookuptbl[aeb->pnum])
 				continue;
 
-			e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-			if (!e)
-				goto out_free;
+			/*
+			 * The fastmap update code might not find a free PEB for
+			 * writing the fastmap anchor to and then reuses the
+			 * current fastmap anchor PEB. When this PEB gets erased
+			 * and a power cut happens before it is written again we
+			 * must make sure that the fastmap attach code doesn't
+			 * find any outdated fastmap anchors, hence we erase the
+			 * outdated fastmap anchor PEBs synchronously here.
+			 */
+			if (aeb->vol_id == UBI_FM_SB_VOLUME_ID)
+				sync = true;
 
-			e->pnum = aeb->pnum;
-			e->ec = aeb->ec;
-			ubi_assert(!ubi->lookuptbl[e->pnum]);
-			ubi->lookuptbl[e->pnum] = e;
-			if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
-				wl_entry_destroy(ubi, e);
+			err = erase_aeb(ubi, aeb, sync);
+			if (err)
 				goto out_free;
-			}
 		}
 
 		found_pebs++;
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index 3047325..7f5ec40 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -184,7 +184,7 @@
 	void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
 	int err = 0;
 	u8 *packet_ptr;
-	int i, n = 1, packet_len;
+	int packet_len;
 	ptrdiff_t cmd_len;
 
 	/* usb device unregistered? */
@@ -201,17 +201,13 @@
 	}
 
 	packet_ptr = cmd_head;
+	packet_len = cmd_len;
 
 	/* firmware is not able to re-assemble 512 bytes buffer in full-speed */
-	if ((dev->udev->speed != USB_SPEED_HIGH) &&
-	    (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) {
-		packet_len = PCAN_UFD_LOSPD_PKT_SIZE;
-		n += cmd_len / packet_len;
-	} else {
-		packet_len = cmd_len;
-	}
+	if (unlikely(dev->udev->speed != USB_SPEED_HIGH))
+		packet_len = min(packet_len, PCAN_UFD_LOSPD_PKT_SIZE);
 
-	for (i = 0; i < n; i++) {
+	do {
 		err = usb_bulk_msg(dev->udev,
 				   usb_sndbulkpipe(dev->udev,
 						   PCAN_USBPRO_EP_CMDOUT),
@@ -224,7 +220,12 @@
 		}
 
 		packet_ptr += packet_len;
-	}
+		cmd_len -= packet_len;
+
+		if (cmd_len < PCAN_UFD_LOSPD_PKT_SIZE)
+			packet_len = cmd_len;
+
+	} while (packet_len > 0);
 
 	return err;
 }
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index a7e04ff..cde4b96 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -1843,8 +1843,8 @@
 	/* Read A2 portion of the EEPROM */
 	if (length) {
 		start -= ETH_MODULE_SFF_8436_LEN;
-		bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1, start,
-						 length, data);
+		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1,
+						      start, length, data);
 	}
 	return rc;
 }
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 1644896..b2eeecb 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4733,6 +4733,15 @@
 
 	be_schedule_worker(adapter);
 
+	/*
+	 * The IF was destroyed and re-created. We need to clear
+	 * all promiscuous flags valid for the destroyed IF.
+	 * Without this promisc mode is not restored during
+	 * be_open() because the driver thinks that it is
+	 * already enabled in HW.
+	 */
+	adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS;
+
 	if (netif_running(netdev))
 		status = be_open(netdev);
 
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ca54f76..3a61491 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3273,7 +3273,7 @@
 
 int igb_close(struct net_device *netdev)
 {
-	if (netif_device_present(netdev))
+	if (netif_device_present(netdev) || netdev->dismantle)
 		return __igb_close(netdev, false);
 	return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 8aa91dd..1655601 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -765,11 +765,8 @@
 	dipn = htonl(dip);
 	dev = mlxsw_sp->rifs[rif]->dev;
 	n = neigh_lookup(&arp_tbl, &dipn, dev);
-	if (!n) {
-		netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n",
-			   &dip);
+	if (!n)
 		return;
-	}
 
 	netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
 	neigh_event_send(n, NULL);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index bdbcd2b..c3c28f0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -3849,7 +3849,7 @@
 	struct list_head *head = &mbx->cmd_q;
 	struct qlcnic_cmd_args *cmd = NULL;
 
-	spin_lock(&mbx->queue_lock);
+	spin_lock_bh(&mbx->queue_lock);
 
 	while (!list_empty(head)) {
 		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
@@ -3860,7 +3860,7 @@
 		qlcnic_83xx_notify_cmd_completion(adapter, cmd);
 	}
 
-	spin_unlock(&mbx->queue_lock);
+	spin_unlock_bh(&mbx->queue_lock);
 }
 
 static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
@@ -3896,12 +3896,12 @@
 {
 	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 
-	spin_lock(&mbx->queue_lock);
+	spin_lock_bh(&mbx->queue_lock);
 
 	list_del(&cmd->list);
 	mbx->num_cmds--;
 
-	spin_unlock(&mbx->queue_lock);
+	spin_unlock_bh(&mbx->queue_lock);
 
 	qlcnic_83xx_notify_cmd_completion(adapter, cmd);
 }
@@ -3966,7 +3966,7 @@
 		init_completion(&cmd->completion);
 		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
 
-		spin_lock(&mbx->queue_lock);
+		spin_lock_bh(&mbx->queue_lock);
 
 		list_add_tail(&cmd->list, &mbx->cmd_q);
 		mbx->num_cmds++;
@@ -3974,7 +3974,7 @@
 		*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
 		queue_work(mbx->work_q, &mbx->work);
 
-		spin_unlock(&mbx->queue_lock);
+		spin_unlock_bh(&mbx->queue_lock);
 
 		return 0;
 	}
@@ -4070,15 +4070,15 @@
 		mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
 		spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
-		spin_lock(&mbx->queue_lock);
+		spin_lock_bh(&mbx->queue_lock);
 
 		if (list_empty(head)) {
-			spin_unlock(&mbx->queue_lock);
+			spin_unlock_bh(&mbx->queue_lock);
 			return;
 		}
 		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
 
-		spin_unlock(&mbx->queue_lock);
+		spin_unlock_bh(&mbx->queue_lock);
 
 		mbx_ops->encode_cmd(adapter, cmd);
 		mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 2c4350a..18e68c9 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -1387,7 +1387,7 @@
 {
 	void __iomem *ioaddr = tp->mmio_addr;
 
-	return RTL_R8(IBISR0) & 0x02;
+	return RTL_R8(IBISR0) & 0x20;
 }
 
 static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
@@ -1395,7 +1395,7 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 
 	RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01);
-	rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000);
+	rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000);
 	RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20);
 	RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01);
 }
@@ -2222,19 +2222,14 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 	dma_addr_t paddr = tp->counters_phys_addr;
 	u32 cmd;
-	bool ret;
 
 	RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+	RTL_R32(CounterAddrHigh);
 	cmd = (u64)paddr & DMA_BIT_MASK(32);
 	RTL_W32(CounterAddrLow, cmd);
 	RTL_W32(CounterAddrLow, cmd | counter_cmd);
 
-	ret = rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
-
-	RTL_W32(CounterAddrLow, 0);
-	RTL_W32(CounterAddrHigh, 0);
-
-	return ret;
+	return rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
 }
 
 static bool rtl8169_reset_counters(struct net_device *dev)
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 6d68c8a..da4ec57 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -34,6 +34,7 @@
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
+	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index b883af9..fc4c2cc 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1002,17 +1002,18 @@
 	if (!ifname_is_set)
 		snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
 
+	mutex_unlock(&pn->all_ppp_mutex);
+
 	ret = register_netdevice(ppp->dev);
 	if (ret < 0)
 		goto err_unit;
 
 	atomic_inc(&ppp_unit_count);
 
-	mutex_unlock(&pn->all_ppp_mutex);
-
 	return 0;
 
 err_unit:
+	mutex_lock(&pn->all_ppp_mutex);
 	unit_put(&pn->units_idr, ppp->file.index);
 err:
 	mutex_unlock(&pn->all_ppp_mutex);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 4ddae81..dc36c2e 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -842,6 +842,7 @@
 	struct pppoe_hdr *ph;
 	struct net_device *dev;
 	char *start;
+	int hlen;
 
 	lock_sock(sk);
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
@@ -860,16 +861,16 @@
 	if (total_len > (dev->mtu + dev->hard_header_len))
 		goto end;
 
-
-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
-			   0, GFP_KERNEL);
+	hlen = LL_RESERVED_SPACE(dev);
+	skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len +
+			   dev->needed_tailroom, 0, GFP_KERNEL);
 	if (!skb) {
 		error = -ENOMEM;
 		goto end;
 	}
 
 	/* Reserve space for headers. */
-	skb_reserve(skb, dev->hard_header_len);
+	skb_reserve(skb, hlen);
 	skb_reset_network_header(skb);
 
 	skb->dev = dev;
@@ -930,7 +931,7 @@
 	/* Copy the data if there is no space for the header or if it's
 	 * read-only.
 	 */
-	if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+	if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph)))
 		goto abort;
 
 	__skb_push(skb, sizeof(*ph));
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 6f9fc27..9babe04 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -525,6 +525,14 @@
 	skb_queue_purge(&tfile->sk.sk_error_queue);
 }
 
+static void tun_cleanup_tx_array(struct tun_file *tfile)
+{
+	if (tfile->tx_array.ring.queue) {
+		skb_array_cleanup(&tfile->tx_array);
+		memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
+	}
+}
+
 static void __tun_detach(struct tun_file *tfile, bool clean)
 {
 	struct tun_file *ntfile;
@@ -566,8 +574,7 @@
 			    tun->dev->reg_state == NETREG_REGISTERED)
 				unregister_netdevice(tun->dev);
 		}
-		if (tun)
-			skb_array_cleanup(&tfile->tx_array);
+		tun_cleanup_tx_array(tfile);
 		sock_put(&tfile->sk);
 	}
 }
@@ -606,11 +613,13 @@
 		/* Drop read queue */
 		tun_queue_purge(tfile);
 		sock_put(&tfile->sk);
+		tun_cleanup_tx_array(tfile);
 	}
 	list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
 		tun_enable_queue(tfile);
 		tun_queue_purge(tfile);
 		sock_put(&tfile->sk);
+		tun_cleanup_tx_array(tfile);
 	}
 	BUG_ON(tun->numdisabled != 0);
 
@@ -2373,6 +2382,8 @@
 
 	sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
 
+	memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
+
 	return 0;
 }
 
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 9c257ff..c53385a 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2197,6 +2197,7 @@
 		buf = DEFAULT_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
 		dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE;
 		dev->rx_qlen = 4;
+		dev->tx_qlen = 4;
 	}
 
 	ret = lan78xx_write_reg(dev, BURST_CAP, buf);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index db65d9a..e1e5e84 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -944,6 +944,7 @@
 	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)},	/* Quectel EC25, EC20 R2.0  Mini PCIe */
 	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)},	/* Quectel EC21 Mini PCIe */
 	{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},	/* Quectel BG96 */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)},	/* Quectel EP06 Mini PCIe */
 
 	/* 4. Gobi 1000 devices */
 	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index ef83ae3..4afba17 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1616,7 +1616,6 @@
 					  rq->rx_ring[i].basePA);
 			rq->rx_ring[i].base = NULL;
 		}
-		rq->buf_info[i] = NULL;
 	}
 
 	if (rq->data_ring.base) {
@@ -1638,6 +1637,7 @@
 			(rq->rx_ring[0].size + rq->rx_ring[1].size);
 		dma_free_coherent(&adapter->pdev->dev, sz, rq->buf_info[0],
 				  rq->buf_info_pa);
+		rq->buf_info[0] = rq->buf_info[1] = NULL;
 	}
 }
 
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 75faeb1..bb2270b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -108,20 +108,8 @@
 	 for it's internal usage and release it to back to pre allocated pool.
 	 This memory is allocated at the cold boot time.
 
-config CLD_LL_CORE
-       tristate "QTI core WLAN driver for QCA6174 chipset"
-       select NL80211_TESTMODE
-       select WEXT_CORE
-       select WEXT_PRIV
-       select WEXT_SPY
-       select WIRELESS_EXT
-       ---help---
-         This section contains the necessary modules needed to enable the
-	 core WLAN driver for QTI QCA6174 chipset.
-	 Select Y to compile the driver in order to have WLAN functionality
-	 support.
-
 source "drivers/net/wireless/cnss2/Kconfig"
+source "drivers/net/wireless/cnss/Kconfig"
 source "drivers/net/wireless/cnss_utils/Kconfig"
 source "drivers/net/wireless/cnss_genl/Kconfig"
 
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4ffbd10..5c33140 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -27,8 +27,7 @@
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
 
 obj-$(CONFIG_CNSS2)	+= cnss2/
-
+obj-$(CONFIG_CNSS)              += cnss/
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
-
 obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h
index c131b5e..d32c1f4 100644
--- a/drivers/net/wireless/ath/wil6210/boot_loader.h
+++ b/drivers/net/wireless/ath/wil6210/boot_loader.h
@@ -1,4 +1,5 @@
 /* Copyright (c) 2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -39,7 +40,8 @@
 	/* valid only for version 2 and above */
 	__le32  bl_assert_code;         /* 0x880A58 BL Assert code */
 	__le32  bl_assert_blink;        /* 0x880A5C BL Assert Branch */
-	__le32  bl_reserved[22];        /* 0x880A60 - 0x880AB4 */
+	__le32  bl_shutdown_handshake;  /* 0x880A60 BL cleaner shutdown */
+	__le32  bl_reserved[21];        /* 0x880A64 - 0x880AB4 */
 	__le32  bl_magic_number;        /* 0x880AB8 BL Magic number */
 } __packed;
 
@@ -58,4 +60,9 @@
 	u8	mac_address[6];			/* 0x880A4c BL mac address */
 } __packed;
 
+/* bits for bl_shutdown_handshake */
+#define BL_SHUTDOWN_HS_GRTD		BIT(0)
+#define BL_SHUTDOWN_HS_RTD		BIT(1)
+#define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31)
+
 #endif /* BOOT_LOADER_EXPORT_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
index 2f2b910..2c7b24f 100644
--- a/drivers/net/wireless/ath/wil6210/fw.h
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -58,15 +59,30 @@
 	u8 data[0]; /* free-form data [data_size], see above */
 } __packed;
 
+/* Comment header - common for all comment record types */
+struct wil_fw_record_comment_hdr {
+	__le32 magic;
+};
+
 /* FW capabilities encoded inside a comment record */
 #define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba)
 struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
 	/* identifies capabilities record */
-	__le32 magic;
+	struct wil_fw_record_comment_hdr hdr;
 	/* capabilities (variable size), see enum wmi_fw_capability */
 	u8 capabilities[0];
 };
 
+/* brd file info encoded inside a comment record */
+#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
+struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */
+	/* identifies brd file record */
+	struct wil_fw_record_comment_hdr hdr;
+	__le32 version;
+	__le32 base_addr;
+	__le32 max_size_bytes;
+} __packed;
+
 /* perform action
  * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
  */
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 77d1902..914c010 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -128,14 +129,13 @@
 }
 
 static int
-fw_handle_comment(struct wil6210_priv *wil, const void *data,
-		  size_t size)
+fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
+		       size_t size)
 {
 	const struct wil_fw_record_capabilities *rec = data;
 	size_t capa_size;
 
-	if (size < sizeof(*rec) ||
-	    le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
+	if (size < sizeof(*rec)) {
 		wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
 				data, size, true);
 		return 0;
@@ -151,8 +151,56 @@
 	return 0;
 }
 
-static int fw_handle_data(struct wil6210_priv *wil, const void *data,
-			  size_t size)
+static int
+fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
+		   size_t size)
+{
+	const struct wil_fw_record_brd_file *rec = data;
+
+	if (size < sizeof(*rec)) {
+		wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
+				data, size, true);
+		return 0;
+	}
+
+	wil->brd_file_addr = le32_to_cpu(rec->base_addr);
+	wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes);
+
+	wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n",
+		   wil->brd_file_addr, wil->brd_file_max_size);
+
+	return 0;
+}
+
+static int
+fw_handle_comment(struct wil6210_priv *wil, const void *data,
+		  size_t size)
+{
+	const struct wil_fw_record_comment_hdr *hdr = data;
+	u32 magic;
+	int rc = 0;
+
+	if (size < sizeof(*hdr))
+		return 0;
+
+	magic = le32_to_cpu(hdr->magic);
+
+	switch (magic) {
+	case WIL_FW_CAPABILITIES_MAGIC:
+		wil_dbg_fw(wil, "magic is WIL_FW_CAPABILITIES_MAGIC\n");
+		rc = fw_handle_capabilities(wil, data, size);
+		break;
+	case WIL_BRD_FILE_MAGIC:
+		wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
+		rc = fw_handle_brd_file(wil, data, size);
+		break;
+	}
+
+	return rc;
+}
+
+static int __fw_handle_data(struct wil6210_priv *wil, const void *data,
+			    size_t size, __le32 addr)
 {
 	const struct wil_fw_record_data *d = data;
 	void __iomem *dst;
@@ -163,16 +211,23 @@
 		return -EINVAL;
 	}
 
-	if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
+	if (!wil_fw_addr_check(wil, &dst, addr, s, "address"))
 		return -EINVAL;
-	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
-		   s);
+	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s);
 	wil_memcpy_toio_32(dst, d->data, s);
 	wmb(); /* finish before processing next record */
 
 	return 0;
 }
 
+static int fw_handle_data(struct wil6210_priv *wil, const void *data,
+			  size_t size)
+{
+	const struct wil_fw_record_data *d = data;
+
+	return __fw_handle_data(wil, data, size, d->addr);
+}
+
 static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
 			  size_t size)
 {
@@ -552,6 +607,100 @@
 }
 
 /**
+ * wil_brd_process - process section from BRD file
+ *
+ * Return error code
+ */
+static int wil_brd_process(struct wil6210_priv *wil, const void *data,
+			   size_t size)
+{
+	int rc = 0;
+	const struct wil_fw_record_head *hdr = data;
+	size_t s, hdr_sz;
+	u16 type;
+
+	/* Assuming the board file includes only one header record and one data
+	 * record. Each record starts with wil_fw_record_head.
+	 */
+	if (size < sizeof(*hdr))
+		return -EINVAL;
+	s = sizeof(*hdr) + le32_to_cpu(hdr->size);
+	if (s > size)
+		return -EINVAL;
+
+	/* Skip the header record and handle the data record */
+	hdr = (const void *)hdr + s;
+	size -= s;
+	if (size < sizeof(*hdr))
+		return -EINVAL;
+	hdr_sz = le32_to_cpu(hdr->size);
+
+	if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size)
+		return -EINVAL;
+	if (sizeof(*hdr) + hdr_sz > size)
+		return -EINVAL;
+	if (hdr_sz % 4) {
+		wil_err_fw(wil, "unaligned record size: %zu\n",
+			   hdr_sz);
+		return -EINVAL;
+	}
+	type = le16_to_cpu(hdr->type);
+	if (type != wil_fw_type_data) {
+		wil_err_fw(wil, "invalid record type for board file: %d\n",
+			   type);
+		return -EINVAL;
+	}
+	if (hdr_sz < sizeof(struct wil_fw_record_data)) {
+		wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
+		return -EINVAL;
+	}
+
+	wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n",
+		   wil->brd_file_addr);
+
+	rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
+			      cpu_to_le32(wil->brd_file_addr));
+
+	return rc;
+}
+
+/**
+ * wil_request_board - Request board file
+ *
+ * Request board image from the file
+ * board file address and max size are read from FW file
+ * during initialization.
+ * brd file shall include one header and one data section.
+ *
+ * Return error code
+ */
+int wil_request_board(struct wil6210_priv *wil, const char *name)
+{
+	int rc, dlen;
+	const struct firmware *brd;
+
+	rc = request_firmware(&brd, name, wil_to_dev(wil));
+	if (rc) {
+		wil_err_fw(wil, "Failed to load brd %s\n", name);
+		return rc;
+	}
+	wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, brd->size);
+
+	/* Verify the header */
+	dlen = wil_fw_verify(wil, brd->data, brd->size);
+	if (dlen < 0) {
+		rc = dlen;
+		goto out;
+	}
+	/* Process the data record */
+	rc = wil_brd_process(wil, brd->data, dlen);
+
+out:
+	release_firmware(brd);
+	return rc;
+}
+
+/**
  * wil_fw_verify_file_exists - checks if firmware file exist
  *
  * @wil: driver context
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index dcf87a7..1835187 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -395,8 +396,9 @@
 	wil6210_mask_irq_misc(wil, false);
 
 	if (isr & ISR_MISC_FW_ERROR) {
-		u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
-		u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE);
+		u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
+		u32 ucode_assert_code =
+			wil_r(wil, wil->rgf_ucode_assert_code_addr);
 
 		wil_err(wil,
 			"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 8e13f24..9cef0f0 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -642,6 +643,98 @@
 	destroy_workqueue(wil->wmi_wq);
 }
 
+static void wil_shutdown_bl(struct wil6210_priv *wil)
+{
+	u32 val;
+
+	wil_s(wil, RGF_USER_BL +
+	      offsetof(struct bl_dedicated_registers_v1,
+		       bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD);
+
+	usleep_range(100, 150);
+
+	val = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v1,
+			     bl_shutdown_handshake));
+	if (val & BL_SHUTDOWN_HS_RTD) {
+		wil_dbg_misc(wil, "BL is ready for halt\n");
+		return;
+	}
+
+	wil_err(wil, "BL did not report ready for halt\n");
+}
+
+/* this format is used by ARC embedded CPU for instruction memory */
+static inline u32 ARC_me_imm32(u32 d)
+{
+	return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16);
+}
+
+/* defines access to interrupt vectors for wil_freeze_bl */
+#define ARC_IRQ_VECTOR_OFFSET(N)	((N) * 8)
+/* ARC long jump instruction */
+#define ARC_JAL_INST			(0x20200f80)
+
+static void wil_freeze_bl(struct wil6210_priv *wil)
+{
+	u32 jal, upc, saved;
+	u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3);
+
+	jal = wil_r(wil, wil->iccm_base + ivt3);
+	if (jal != ARC_me_imm32(ARC_JAL_INST)) {
+		wil_dbg_misc(wil, "invalid IVT entry found, skipping\n");
+		return;
+	}
+
+	/* prevent the target from entering deep sleep
+	 * and disabling memory access
+	 */
+	saved = wil_r(wil, RGF_USER_USAGE_8);
+	wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP);
+	usleep_range(20, 25); /* let the BL process the bit */
+
+	/* redirect to endless loop in the INT_L1 context and let it trap */
+	wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3));
+	usleep_range(20, 25); /* let the BL get into the trap */
+
+	/* verify the BL is frozen */
+	upc = wil_r(wil, RGF_USER_CPU_PC);
+	if (upc < ivt3 || (upc > (ivt3 + 8)))
+		wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc);
+
+	wil_w(wil, RGF_USER_USAGE_8, saved);
+}
+
+static void wil_bl_prepare_halt(struct wil6210_priv *wil)
+{
+	u32 tmp, ver;
+
+	/* before halting device CPU driver must make sure BL is not accessing
+	 * host memory. This is done differently depending on BL version:
+	 * 1. For very old BL versions the procedure is skipped
+	 * (not supported).
+	 * 2. For old BL version we use a special trick to freeze the BL
+	 * 3. For new BL versions we shutdown the BL using handshake procedure.
+	 */
+	tmp = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v0,
+			     boot_loader_struct_version));
+	if (!tmp) {
+		wil_dbg_misc(wil, "old BL, skipping halt preperation\n");
+		return;
+	}
+
+	tmp = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v1,
+			     bl_shutdown_handshake));
+	ver = BL_SHUTDOWN_HS_PROT_VER(tmp);
+
+	if (ver > 0)
+		wil_shutdown_bl(wil);
+	else
+		wil_freeze_bl(wil);
+}
+
 static inline void wil_halt_cpu(struct wil6210_priv *wil)
 {
 	wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
@@ -675,7 +768,7 @@
 	}
 }
 
-static int wil_target_reset(struct wil6210_priv *wil)
+static int wil_target_reset(struct wil6210_priv *wil, int no_flash)
 {
 	int delay = 0;
 	u32 x, x1 = 0;
@@ -689,9 +782,16 @@
 
 	wil_halt_cpu(wil);
 
-	/* clear all boot loader "ready" bits */
-	wil_w(wil, RGF_USER_BL +
-	      offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
+	if (!no_flash) {
+		/* clear all boot loader "ready" bits */
+		wil_w(wil, RGF_USER_BL +
+		      offsetof(struct bl_dedicated_registers_v0,
+			       boot_loader_ready), 0);
+		/* this should be safe to write even with old BLs */
+		wil_w(wil, RGF_USER_BL +
+		      offsetof(struct bl_dedicated_registers_v1,
+			       bl_shutdown_handshake), 0);
+	}
 	/* Clear Fw Download notification */
 	wil_c(wil, RGF_USER_USAGE_6, BIT(0));
 
@@ -732,21 +832,33 @@
 	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
 
 	/* wait until device ready. typical time is 20..80 msec */
-	do {
-		msleep(RST_DELAY);
-		x = wil_r(wil, RGF_USER_BL +
-			  offsetof(struct bl_dedicated_registers_v0,
-				   boot_loader_ready));
-		if (x1 != x) {
-			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
-			x1 = x;
-		}
-		if (delay++ > RST_COUNT) {
-			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
-				x);
-			return -ETIME;
-		}
-	} while (x != BL_READY);
+	if (no_flash)
+		do {
+			msleep(RST_DELAY);
+			x = wil_r(wil, USER_EXT_USER_PMU_3);
+			if (delay++ > RST_COUNT) {
+				wil_err(wil, "Reset not completed, PMU_3 0x%08x\n",
+					x);
+				return -ETIME;
+			}
+		} while ((x & BIT_PMU_DEVICE_RDY) == 0);
+	else
+		do {
+			msleep(RST_DELAY);
+			x = wil_r(wil, RGF_USER_BL +
+				  offsetof(struct bl_dedicated_registers_v0,
+					   boot_loader_ready));
+			if (x1 != x) {
+				wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n",
+					     x1, x);
+				x1 = x;
+			}
+			if (delay++ > RST_COUNT) {
+				wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
+					x);
+				return -ETIME;
+			}
+		} while (x != BL_READY);
 
 	wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
 
@@ -754,6 +866,21 @@
 	wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN |
 	      BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);
 
+	if (no_flash) {
+		/* Reset OTP HW vectors to fit 40MHz */
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001);
+		wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57);
+	}
+
 	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
 	return 0;
 }
@@ -911,6 +1038,27 @@
 	}
 }
 
+static int wil_get_otp_info(struct wil6210_priv *wil)
+{
+	struct net_device *ndev = wil_to_ndev(wil);
+	struct wiphy *wiphy = wil_to_wiphy(wil);
+	u8 mac[8];
+
+	wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC),
+			     sizeof(mac));
+	if (!is_valid_ether_addr(mac)) {
+		wil_err(wil, "Invalid MAC %pM\n", mac);
+		return -EINVAL;
+	}
+
+	ether_addr_copy(ndev->perm_addr, mac);
+	ether_addr_copy(wiphy->perm_addr, mac);
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		ether_addr_copy(ndev->dev_addr, mac);
+
+	return 0;
+}
+
 static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
 {
 	ulong to = msecs_to_jiffies(1000);
@@ -1004,6 +1152,7 @@
 {
 	int rc;
 	unsigned long status_flags = BIT(wil_status_resetting);
+	int no_flash;
 
 	wil_dbg_misc(wil, "reset\n");
 
@@ -1082,20 +1231,28 @@
 	flush_workqueue(wil->wq_service);
 	flush_workqueue(wil->wmi_wq);
 
-	wil_bl_crash_info(wil, false);
+	no_flash = test_bit(hw_capa_no_flash, wil->hw_capa);
+	if (!no_flash)
+		wil_bl_crash_info(wil, false);
 	wil_disable_irq(wil);
-	rc = wil_target_reset(wil);
+	rc = wil_target_reset(wil, no_flash);
 	wil6210_clear_irq(wil);
 	wil_enable_irq(wil);
 	wil_rx_fini(wil);
 	if (rc) {
-		wil_bl_crash_info(wil, true);
+		if (!no_flash)
+			wil_bl_crash_info(wil, true);
 		goto out;
 	}
 
-	rc = wil_get_bl_info(wil);
-	if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
-		rc = 0;
+	if (no_flash) {
+		rc = wil_get_otp_info(wil);
+	} else {
+		rc = wil_get_bl_info(wil);
+		if (rc == -EAGAIN && !load_fw)
+			/* ignore RF error if not going up */
+			rc = 0;
+	}
 	if (rc)
 		goto out;
 
@@ -1104,13 +1261,21 @@
 		wil_info(wil, "Use firmware <%s> + board <%s>\n",
 			 wil->wil_fw_name, WIL_BOARD_FILE_NAME);
 
+		if (!no_flash)
+			wil_bl_prepare_halt(wil);
+
 		wil_halt_cpu(wil);
 		memset(wil->fw_version, 0, sizeof(wil->fw_version));
 		/* Loading f/w from the file */
 		rc = wil_request_firmware(wil, wil->wil_fw_name, true);
 		if (rc)
 			goto out;
-		rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
+		if (wil->brd_file_addr)
+			rc = wil_request_board(wil, WIL_BOARD_FILE_NAME);
+		else
+			rc = wil_request_firmware(wil,
+						  WIL_BOARD_FILE_NAME,
+						  true);
 		if (rc)
 			goto out;
 
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 025bdd3..1875387 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -39,15 +40,16 @@
 #endif /* CONFIG_PM */
 
 static
-void wil_set_capabilities(struct wil6210_priv *wil)
+int wil_set_capabilities(struct wil6210_priv *wil)
 {
 	const char *wil_fw_name;
 	u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
 	u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
 			    RGF_USER_REVISION_ID_MASK);
 	int platform_capa;
+	struct fw_map *iccm_section, *sct;
 
-	bitmap_zero(wil->hw_capabilities, hw_capability_last);
+	bitmap_zero(wil->hw_capa, hw_capa_last);
 	bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
 	bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
 	wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
@@ -56,6 +58,8 @@
 
 	switch (jtag_id) {
 	case JTAG_DEV_ID_SPARROW:
+		memcpy(fw_mapping, sparrow_fw_mapping,
+		       sizeof(sparrow_fw_mapping));
 		switch (chip_revision) {
 		case REVISION_ID_SPARROW_D0:
 			wil->hw_name = "Sparrow D0";
@@ -65,6 +69,12 @@
 
 			if (wil_fw_verify_file_exists(wil, wil_fw_name))
 				wil->wil_fw_name = wil_fw_name;
+			sct = wil_find_fw_mapping("mac_rgf_ext");
+			if (!sct) {
+				wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n");
+				return -EINVAL;
+			}
+			memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct));
 			break;
 		case REVISION_ID_SPARROW_B0:
 			wil->hw_name = "Sparrow B0";
@@ -75,15 +85,36 @@
 			wil->hw_version = HW_VER_UNKNOWN;
 			break;
 		}
+		wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE;
+		wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE;
+		break;
+	case JTAG_DEV_ID_TALYN:
+		wil->hw_name = "Talyn";
+		wil->hw_version = HW_VER_TALYN;
+		memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping));
+		wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
+		wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
+		if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
+		    BIT_NO_FLASH_INDICATION)
+			set_bit(hw_capa_no_flash, wil->hw_capa);
 		break;
 	default:
 		wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
 			jtag_id, chip_revision);
 		wil->hw_name = "Unknown";
 		wil->hw_version = HW_VER_UNKNOWN;
+		return -EINVAL;
 	}
 
-	wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+	iccm_section = wil_find_fw_mapping("fw_code");
+	if (!iccm_section) {
+		wil_err(wil, "fw_code section not found in fw_mapping\n");
+		return -EINVAL;
+	}
+	wil->iccm_base = iccm_section->host;
+
+	wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name,
+		 test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : "");
 
 	/* Get platform capabilities */
 	if (wil->platform_ops.get_capa) {
@@ -96,6 +127,8 @@
 	/* extract FW capabilities from file without loading the FW */
 	wil_request_firmware(wil, wil->wil_fw_name, false);
 	wil_refresh_fw_capabilities(wil);
+
+	return 0;
 }
 
 void wil_disable_irq(struct wil6210_priv *wil)
@@ -299,7 +332,11 @@
 	/* rollback to err_iounmap */
 	wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
 
-	wil_set_capabilities(wil);
+	rc = wil_set_capabilities(wil);
+	if (rc) {
+		wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc);
+		goto err_iounmap;
+	}
 	wil6210_clear_irq(wil);
 
 	/* FW should raise IRQ when ready */
@@ -385,6 +422,7 @@
 static const struct pci_device_id wil6210_pcie_ids[] = {
 	{ PCI_DEVICE(0x1ae9, 0x0310) },
 	{ PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
+	{ PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */
 	{ /* end: all zeroes */	},
 };
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 62d1d07..dcec343 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -636,8 +636,8 @@
 			v->swtail = next_tail) {
 		rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
 		if (unlikely(rc)) {
-			wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
-				rc, v->swtail);
+			wil_err_ratelimited(wil, "Error %d in rx refill[%d]\n",
+					    rc, v->swtail);
 			break;
 		}
 	}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 33df230..2f6d6c9 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -170,6 +171,7 @@
 	#define HW_MACHINE_BOOT_DONE	(0x3fffffd)
 #define RGF_USER_USER_CPU_0		(0x8801e0)
 	#define BIT_USER_USER_CPU_MAN_RST	BIT(1) /* user_cpu_man_rst */
+#define RGF_USER_CPU_PC			(0x8801e8)
 #define RGF_USER_MAC_CPU_0		(0x8801fc)
 	#define BIT_USER_MAC_CPU_MAN_RST	BIT(1) /* mac_cpu_man_rst */
 #define RGF_USER_USER_SCRATCH_PAD	(0x8802bc)
@@ -195,6 +197,19 @@
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1	(0x880c2c)
 #define RGF_USER_SPARROW_M_4			(0x880c50) /* Sparrow */
 	#define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF	BIT(2)
+#define RGF_USER_OTP_HW_RD_MACHINE_1	(0x880ce0)
+	#define BIT_NO_FLASH_INDICATION		BIT(8)
+#define RGF_USER_XPM_IFC_RD_TIME1	(0x880cec)
+#define RGF_USER_XPM_IFC_RD_TIME2	(0x880cf0)
+#define RGF_USER_XPM_IFC_RD_TIME3	(0x880cf4)
+#define RGF_USER_XPM_IFC_RD_TIME4	(0x880cf8)
+#define RGF_USER_XPM_IFC_RD_TIME5	(0x880cfc)
+#define RGF_USER_XPM_IFC_RD_TIME6	(0x880d00)
+#define RGF_USER_XPM_IFC_RD_TIME7	(0x880d04)
+#define RGF_USER_XPM_IFC_RD_TIME8	(0x880d08)
+#define RGF_USER_XPM_IFC_RD_TIME9	(0x880d0c)
+#define RGF_USER_XPM_IFC_RD_TIME10	(0x880d10)
+#define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64)
 
 #define RGF_DMA_EP_TX_ICR		(0x881bb4) /* struct RGF_ICR */
 	#define BIT_DMA_EP_TX_ICR_TX_DONE	BIT(0)
@@ -285,22 +300,33 @@
 #define RGF_CAF_PLL_LOCK_STATUS		(0x88afec)
 	#define BIT_CAF_OSC_DIG_XTAL_STABLE	BIT(0)
 
+#define USER_EXT_USER_PMU_3		(0x88d00c)
+	#define BIT_PMU_DEVICE_RDY		BIT(0)
+
 #define RGF_USER_JTAG_DEV_ID	(0x880b34) /* device ID */
 	#define JTAG_DEV_ID_SPARROW	(0x2632072f)
+	#define JTAG_DEV_ID_TALYN	(0x7e0e1)
 
 #define RGF_USER_REVISION_ID		(0x88afe4)
 #define RGF_USER_REVISION_ID_MASK	(3)
 	#define REVISION_ID_SPARROW_B0	(0x0)
 	#define REVISION_ID_SPARROW_D0	(0x3)
 
+#define RGF_OTP_MAC			(0x8a0620)
+
 /* crash codes for FW/Ucode stored here */
-#define RGF_FW_ASSERT_CODE		(0x91f020)
-#define RGF_UCODE_ASSERT_CODE		(0x91f028)
+
+/* ASSERT RGFs */
+#define SPARROW_RGF_FW_ASSERT_CODE	(0x91f020)
+#define SPARROW_RGF_UCODE_ASSERT_CODE	(0x91f028)
+#define TALYN_RGF_FW_ASSERT_CODE	(0xa37020)
+#define TALYN_RGF_UCODE_ASSERT_CODE	(0xa37028)
 
 enum {
 	HW_VER_UNKNOWN,
 	HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
 	HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
+	HW_VER_TALYN,	/* JTAG_DEV_ID_TALYN */
 };
 
 /* popular locations */
@@ -316,6 +342,10 @@
 #define WIL_DATA_COMPLETION_TO_MS 200
 
 /* Hardware definitions end */
+#define SPARROW_FW_MAPPING_TABLE_SIZE 10
+#define TALYN_FW_MAPPING_TABLE_SIZE 13
+#define MAX_FW_MAPPING_TABLE_SIZE 13
+
 struct fw_map {
 	u32 from; /* linker address - from, inclusive */
 	u32 to;   /* linker address - to, exclusive */
@@ -325,7 +355,10 @@
 };
 
 /* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[10];
+extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE];
+extern const struct fw_map sparrow_d0_mac_rgf_ext;
+extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE];
+extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
 
 /**
  * mk_cidxtid - construct @cidxtid field
@@ -572,7 +605,8 @@
 };
 
 enum {
-	hw_capability_last
+	hw_capa_no_flash,
+	hw_capa_last
 };
 
 struct wil_probe_client_req {
@@ -648,7 +682,10 @@
 	u8 chip_revision;
 	const char *hw_name;
 	const char *wil_fw_name;
-	DECLARE_BITMAP(hw_capabilities, hw_capability_last);
+	char *board_file;
+	u32 brd_file_addr;
+	u32 brd_file_max_size;
+	DECLARE_BITMAP(hw_capa, hw_capa_last);
 	DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
 	DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
 	u8 n_mids; /* number of additional MIDs as reported by FW */
@@ -722,7 +759,7 @@
 	atomic_t isr_count_rx, isr_count_tx;
 	/* debugfs */
 	struct dentry *debug;
-	struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
+	struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE];
 	u8 discovery_mode;
 	u8 abft_len;
 	u8 wakeup_trigger;
@@ -770,6 +807,10 @@
 	bool suspend_resp_comp;
 	u32 bus_request_kbps;
 	u32 bus_request_kbps_pre_suspend;
+
+	u32 rgf_fw_assert_code_addr;
+	u32 rgf_ucode_assert_code_addr;
+	u32 iccm_base;
 };
 
 #define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -895,6 +936,7 @@
 int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
 void wil_set_ethtoolops(struct net_device *ndev);
 
+struct fw_map *wil_find_fw_mapping(const char *section);
 void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@ -1034,6 +1076,7 @@
 int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
 int wil_request_firmware(struct wil6210_priv *wil, const char *name,
 			 bool load);
+int wil_request_board(struct wil6210_priv *wil, const char *name);
 bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
 
 void wil_pm_runtime_allow(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 07659b12..f2dba31 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -71,23 +72,23 @@
  * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
  * AHB addresses starting from 0x880000
  *
- * Internally, firmware uses addresses that allows faster access but
+ * Internally, firmware uses addresses that allow faster access but
  * are invisible from the host. To read from these addresses, alternative
  * AHB address must be used.
- *
- * Memory mapping
- * Linker address         PCI/Host address
- *                        0x880000 .. 0xa80000  2Mb BAR0
- * 0x800000 .. 0x807000   0x900000 .. 0x907000  28k DCCM
- * 0x840000 .. 0x857000   0x908000 .. 0x91f000  92k PERIPH
  */
 
 /**
- * @fw_mapping provides memory remapping table
+ * @sparrow_fw_mapping provides memory remapping table for sparrow
  *
  * array size should be in sync with the declaration in the wil6210.h
+ *
+ * Sparrow memory mapping:
+ * Linker address         PCI/Host address
+ *                        0x880000 .. 0xa80000  2Mb BAR0
+ * 0x800000 .. 0x808000   0x900000 .. 0x908000  32k DCCM
+ * 0x840000 .. 0x860000   0x908000 .. 0x928000  128k PERIPH
  */
-const struct fw_map fw_mapping[] = {
+const struct fw_map sparrow_fw_mapping[] = {
 	/* FW code RAM 256k */
 	{0x000000, 0x040000, 0x8c0000, "fw_code", true},
 	/* FW data RAM 32k */
@@ -113,6 +114,59 @@
 	{0x800000, 0x804000, 0x940000, "uc_data", false},
 };
 
+/**
+ * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
+ * it is a bit larger to support extra features
+ */
+const struct fw_map sparrow_d0_mac_rgf_ext = {
+	0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
+};
+
+/**
+ * @talyn_fw_mapping provides memory remapping table for Talyn
+ *
+ * array size should be in sync with the declaration in the wil6210.h
+ *
+ * Talyn memory mapping:
+ * Linker address         PCI/Host address
+ *                        0x880000 .. 0xc80000  4Mb BAR0
+ * 0x800000 .. 0x820000   0xa00000 .. 0xa20000  128k DCCM
+ * 0x840000 .. 0x858000   0xa20000 .. 0xa38000  96k PERIPH
+ */
+const struct fw_map talyn_fw_mapping[] = {
+	/* FW code RAM 1M */
+	{0x000000, 0x100000, 0x900000, "fw_code", true},
+	/* FW data RAM 128k */
+	{0x800000, 0x820000, 0xa00000, "fw_data", true},
+	/* periph. data RAM 96k */
+	{0x840000, 0x858000, 0xa20000, "fw_peri", true},
+	/* various RGF 40k */
+	{0x880000, 0x88a000, 0x880000, "rgf", true},
+	/* AGC table 4k */
+	{0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
+	/* Pcie_ext_rgf 4k */
+	{0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
+	/* mac_ext_rgf 1344b */
+	{0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
+	/* ext USER RGF 4k */
+	{0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
+	/* OTP 4k */
+	{0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
+	/* DMA EXT RGF 64k */
+	{0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
+	/* upper area 1536k */
+	{0x900000, 0xa80000, 0x900000, "upper", true},
+	/* UCODE areas - accessible by debugfs blobs but not by
+	 * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
+	 */
+	/* ucode code RAM 256k */
+	{0x000000, 0x040000, 0xa38000, "uc_code", false},
+	/* ucode data RAM 32k */
+	{0x800000, 0x808000, 0xa78000, "uc_data", false},
+};
+
+struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
+
 struct blink_on_off_time led_blink_time[] = {
 	{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
 	{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
@@ -140,6 +194,24 @@
 }
 
 /**
+ * find fw_mapping entry by section name
+ * @section - section name
+ *
+ * Return pointer to section or NULL if not found
+ */
+struct fw_map *wil_find_fw_mapping(const char *section)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
+		if (fw_mapping[i].name &&
+		    !strcmp(section, fw_mapping[i].name))
+			return &fw_mapping[i];
+
+	return NULL;
+}
+
+/**
  * Check address validity for WMI buffer; remap if needed
  * @ptr - internal (linker) fw/ucode address
  * @size - if non zero, validate the block does not
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 6e5d909..a635fc6 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -71,8 +71,18 @@
 MODULE_FIRMWARE("b43/ucode13.fw");
 MODULE_FIRMWARE("b43/ucode14.fw");
 MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode16_lp.fw");
 MODULE_FIRMWARE("b43/ucode16_mimo.fw");
+MODULE_FIRMWARE("b43/ucode24_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_mimo.fw");
+MODULE_FIRMWARE("b43/ucode26_mimo.fw");
+MODULE_FIRMWARE("b43/ucode29_mimo.fw");
+MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
+MODULE_FIRMWARE("b43/ucode30_mimo.fw");
 MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode40.fw");
+MODULE_FIRMWARE("b43/ucode42.fw");
 MODULE_FIRMWARE("b43/ucode9.fw");
 
 static int modparam_bad_frames_preempt;
diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig
new file mode 100644
index 0000000..0b37af6
--- /dev/null
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -0,0 +1,116 @@
+config CNSS
+	tristate "CNSS driver for wifi module"
+	select CNSS_UTILS
+	select CRYPTO
+	select CRYPTO_HASH
+	select CRYPTO_BLKCIPHER
+	---help---
+	 This module adds support for the CNSS connectivity subsystem used
+	 for wifi devices based on the QCA AR6320 chipset.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework.
+
+config CNSS_SDIO
+	bool "Enable/disable cnss sdio platform driver for wifi module"
+	depends on CNSS
+	depends on MMC
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with SDIO bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a SDIO client device.
+
+config CNSS_PCI
+	bool "Enable/disable cnss pci platform driver for wifi module"
+	depends on CNSS
+	depends on PCI
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with PCIe bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a PCIe client device.
+
+config CNSS_ASYNC
+	bool "Enable/disable cnss pci platform driver asynchronous probe"
+	depends on CNSS_PCI
+	---help---
+	 If enabled, CNSS PCI platform driver would do asynchronous probe.
+	 Using asynchronous probe will allow CNSS PCI platform driver to
+	 probe in parallel with other device drivers and will help to
+	 reduce kernel boot time.
+
+config CNSS_MAC_BUG
+	bool "Enable/disable 0-4K memory initialization for QCA6174"
+	depends on CNSS
+	---help---
+	  If enabled, 0-4K memory is reserved for QCA6174 to address
+	  a MAC HW bug. MAC would do an invalid pointer fetch based on
+	  the data, that was read from 0 to 4K. So fill it with zero's;
+	  to an address for which PCIe root complex would honor the read
+	  without any errors.
+
+config CLD_DEBUG
+	bool "Enable/disable CLD debug features"
+	help
+	 WLAN CLD driver uses this config to enable certain debug features.
+	 Some of the debug features may affect performance or may compromise
+	 on security.
+
+	  Say N, if you are building a release kernel for production use.
+	  Only say Y, if you are building a kernel with debug support.
+
+config CLD_HL_SDIO_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface"
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	select WEXT_CORE
+	select WEXT_SPY
+	select NL80211_TESTMODE
+	depends on ARCH_QCOM
+	depends on MMC
+
+config CLD_LL_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver"
+	select NL80211_TESTMODE
+	select WEXT_CORE
+	select WEXT_PRIV
+	select WEXT_SPY
+	select WIRELESS_EXT
+	---help---
+	  This section contains the necessary modules needed to enable the
+	  core WLAN driver for Qualcomm Technologies Inc QCA6174 chipset.
+	  Select Y to compile the driver in order to have WLAN functionality
+	  support.
+
+config CNSS_SECURE_FW
+	bool "Enable/Disable Memory Allocation for Secure Firmware Feature"
+	depends on CNSS
+	---help---
+	  CLD Driver can use this for holding local copy of firmware
+	  binaries which is used for sha crypto computation.
+	  The Memory Allocation is done only if this Config Parameter is
+	  enabled
+
+config BUS_AUTO_SUSPEND
+	bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+	depends on CNSS
+	depends on PCI
+	---help---
+	  Runtime Power Management is supported for PCIe based WLAN Drivers.
+	  The features enable cld wlan driver to suspend pcie bus when APPS
+	  is awake based on the driver inactivity with the Firmware.
+	  The Feature uses runtime power management framework from kernel to
+	  track bus access clients and to synchronize the driver activity
+	  during system pm.
+	  This config flag controls the feature per target based. The feature
+	  requires CNSS driver support.
+
+source "drivers/net/wireless/cnss/logger/Kconfig"
+
+config WLAN_FEATURE_RX_WAKELOCK
+	bool "Enable RX wake lock feature"
+	help
+	Enable WLAN_FEATURE_HOLD_RX_WAKELOCK which is required to take rx
+	wakelock when driver receives packets from fw.
diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile
new file mode 100644
index 0000000..38ad562
--- /dev/null
+++ b/drivers/net/wireless/cnss/Makefile
@@ -0,0 +1,6 @@
+# Makefile for CNSS platform driver
+
+obj-$(CONFIG_CNSS_PCI)	+= cnss_pci.o
+obj-$(CONFIG_CNSS_SDIO)	+= cnss_sdio.o
+obj-$(CONFIG_CNSS)	+= cnss_common.o
+obj-$(CONFIG_CNSS_LOGGER)	+= logger/
diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c
new file mode 100644
index 0000000..a1731b0
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.c
@@ -0,0 +1,450 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <net/cfg80211.h>
+
+#define AR6320_REV1_VERSION             0x5000000
+#define AR6320_REV1_1_VERSION           0x5000001
+#define AR6320_REV1_3_VERSION           0x5000003
+#define AR6320_REV2_1_VERSION           0x5010000
+#define AR6320_REV3_VERSION             0x5020000
+#define AR6320_REV3_2_VERSION           0x5030000
+#define AR900B_DEV_VERSION              0x1000000
+#define QCA9377_REV1_1_VERSION          0x5020001
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_1 = {
+	"qwlan11.bin", "bdwlan11.bin", "otp11.bin", "utf11.bin",
+	"utfbd11.bin", "epping11.bin", "evicted11.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_2_0 = {
+	"qwlan20.bin", "bdwlan20.bin", "otp20.bin", "utf20.bin",
+	"utfbd20.bin", "epping20.bin", "evicted20.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_3 = {
+	"qwlan13.bin", "bdwlan13.bin", "otp13.bin", "utf13.bin",
+	"utfbd13.bin", "epping13.bin", "evicted13.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+	"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+	"utfbd30.bin", "epping30.bin", "evicted30.bin"};
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+	"qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+	"utfbd.bin", "epping.bin", "evicted.bin"};
+
+enum cnss_dev_bus_type {
+	CNSS_BUS_NONE = -1,
+	CNSS_BUS_PCI,
+	CNSS_BUS_SDIO
+};
+
+static DEFINE_MUTEX(unsafe_channel_list_lock);
+static DEFINE_MUTEX(dfs_nol_info_lock);
+
+static struct cnss_unsafe_channel_list {
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+} unsafe_channel_list;
+
+static struct cnss_dfs_nol_info {
+	void *dfs_nol_info;
+	u16 dfs_nol_info_len;
+} dfs_nol_info;
+
+static enum cnss_cc_src cnss_cc_source = CNSS_SOURCE_CORE;
+
+int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	unsafe_channel_list.unsafe_ch_count = ch_count;
+
+	if (ch_count != 0) {
+		memcpy(
+			(char *)unsafe_channel_list.unsafe_ch_list,
+			(char *)unsafe_ch_list, ch_count * sizeof(u16));
+	}
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel);
+
+int cnss_get_wlan_unsafe_channel(
+			u16 *unsafe_ch_list,
+			u16 *ch_count, u16 buf_len)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if (!unsafe_ch_list || !ch_count) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -ENOMEM;
+	}
+
+	*ch_count = unsafe_channel_list.unsafe_ch_count;
+	memcpy(
+		(char *)unsafe_ch_list,
+		(char *)unsafe_channel_list.unsafe_ch_list,
+		unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);
+
+int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
+{
+	void *temp;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	temp = kmalloc(info_len, GFP_KERNEL);
+	if (!temp) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOMEM;
+	}
+
+	memcpy(temp, info, info_len);
+	dfs_info = &dfs_nol_info;
+	kfree(dfs_info->dfs_nol_info);
+
+	dfs_info->dfs_nol_info = temp;
+	dfs_info->dfs_nol_info_len = info_len;
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_set_dfs_nol);
+
+int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+	int len;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	dfs_info = &dfs_nol_info;
+
+	if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOENT;
+	}
+
+	len = min(info_len, dfs_info->dfs_nol_info_len);
+
+	memcpy(info, dfs_info->dfs_nol_info, len);
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return len;
+}
+EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);
+
+void cnss_init_work(struct work_struct *work, work_func_t func)
+{
+	INIT_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_work);
+
+void cnss_flush_work(void *work)
+{
+	struct work_struct *cnss_work = work;
+
+	cancel_work_sync(cnss_work);
+}
+EXPORT_SYMBOL(cnss_flush_work);
+
+void cnss_flush_delayed_work(void *dwork)
+{
+	struct delayed_work *cnss_dwork = dwork;
+
+	cancel_delayed_work_sync(cnss_dwork);
+}
+EXPORT_SYMBOL(cnss_flush_delayed_work);
+
+void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name)
+{
+	wakeup_source_init(ws, name);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_init);
+
+void cnss_pm_wake_lock(struct wakeup_source *ws)
+{
+	__pm_stay_awake(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock);
+
+void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec)
+{
+	__pm_wakeup_event(ws, msec);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_timeout);
+
+void cnss_pm_wake_lock_release(struct wakeup_source *ws)
+{
+	__pm_relax(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_release);
+
+void cnss_pm_wake_lock_destroy(struct wakeup_source *ws)
+{
+	wakeup_source_trash(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_destroy);
+
+void cnss_get_monotonic_boottime(struct timespec *ts)
+{
+	get_monotonic_boottime(ts);
+}
+EXPORT_SYMBOL(cnss_get_monotonic_boottime);
+
+void cnss_get_boottime(struct timespec *ts)
+{
+	ktime_get_ts(ts);
+}
+EXPORT_SYMBOL(cnss_get_boottime);
+
+void cnss_init_delayed_work(struct delayed_work *work, work_func_t func)
+{
+	INIT_DELAYED_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_delayed_work);
+
+int cnss_vendor_cmd_reply(struct sk_buff *skb)
+{
+	return cfg80211_vendor_cmd_reply(skb);
+}
+EXPORT_SYMBOL(cnss_vendor_cmd_reply);
+
+int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu)
+{
+	return set_cpus_allowed_ptr(task, cpumask_of(cpu));
+}
+EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr);
+
+/* wlan prop driver cannot invoke show_stack
+ * function directly, so to invoke this function it
+ * call wcnss_dump_stack function
+ */
+void cnss_dump_stack(struct task_struct *task)
+{
+	show_stack(task, NULL);
+}
+EXPORT_SYMBOL(cnss_dump_stack);
+
+struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev)
+{
+	if (!dev)
+		return NULL;
+	else
+		return dev->platform_data;
+}
+
+int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->request_bus_bandwidth)
+		return pf_ops->request_bus_bandwidth(bandwidth);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_request_bus_bandwidth);
+
+void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_virt_ramdump_mem)
+		return pf_ops->get_virt_ramdump_mem(size);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem);
+
+void cnss_common_device_self_recovery(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_self_recovery)
+		pf_ops->device_self_recovery();
+}
+EXPORT_SYMBOL(cnss_common_device_self_recovery);
+
+void cnss_common_schedule_recovery_work(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->schedule_recovery_work)
+		pf_ops->schedule_recovery_work();
+}
+EXPORT_SYMBOL(cnss_common_schedule_recovery_work);
+
+void cnss_common_device_crashed(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_crashed)
+		pf_ops->device_crashed();
+}
+EXPORT_SYMBOL(cnss_common_device_crashed);
+
+u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_wlan_mac_address)
+		return pf_ops->get_wlan_mac_address(num);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_wlan_mac_address);
+
+int cnss_common_set_wlan_mac_address(
+		struct device *dev, const u8 *in, u32 len)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->set_wlan_mac_address)
+		return pf_ops->set_wlan_mac_address(in, len);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_set_wlan_mac_address);
+
+int cnss_power_up(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_up)
+		return pf_ops->power_up(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_down)
+		return pf_ops->power_down(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+			       u32 size, u32 tufello_dual_fw)
+{
+	if (tufello_dual_fw)
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+	else
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+}
+EXPORT_SYMBOL(cnss_get_qca9377_fw_files);
+
+int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+				 u32 target_type, u32 target_version)
+{
+	if (!pfw_files)
+		return -ENODEV;
+
+	switch (target_version) {
+	case AR6320_REV1_VERSION:
+	case AR6320_REV1_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_1, sizeof(*pfw_files));
+		break;
+	case AR6320_REV1_3_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_3, sizeof(*pfw_files));
+		break;
+	case AR6320_REV2_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_2_0, sizeof(*pfw_files));
+		break;
+	case AR6320_REV3_VERSION:
+	case AR6320_REV3_2_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+		break;
+	default:
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+		pr_err("%s default version 0x%X 0x%X", __func__,
+		       target_type, target_version);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+void cnss_set_cc_source(enum cnss_cc_src cc_source)
+{
+	cnss_cc_source = cc_source;
+}
+EXPORT_SYMBOL(cnss_set_cc_source);
+
+enum cnss_cc_src cnss_get_cc_source(void)
+{
+	return cnss_cc_source;
+}
+EXPORT_SYMBOL(cnss_get_cc_source);
+
+const char *cnss_wlan_get_evicted_data_file(void)
+{
+	return FW_FILES_QCA6174_FW_3_0.evicted_data;
+}
+
+int cnss_common_register_tsf_captured_handler(struct device *dev,
+					      irq_handler_t handler, void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->register_tsf_captured_handler)
+		return pf_ops->register_tsf_captured_handler(handler, ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler);
+
+int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->unregister_tsf_captured_handler)
+		return pf_ops->unregister_tsf_captured_handler(ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_unregister_tsf_captured_handler);
diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h
new file mode 100644
index 0000000..7013aba
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS_COMMON_H_
+#define _NET_CNSS_COMMON_H_
+
+/* max 20mhz channel count */
+#define CNSS_MAX_CH_NUM		45
+
+struct cnss_cap_tsf_info {
+	int irq_num;
+	void *context;
+	irq_handler_t irq_handler;
+};
+
+struct cnss_dev_platform_ops {
+	int (*request_bus_bandwidth)(int bandwidth);
+	void* (*get_virt_ramdump_mem)(unsigned long *size);
+	void (*device_self_recovery)(void);
+	void (*schedule_recovery_work)(void);
+	void (*device_crashed)(void);
+	u8 * (*get_wlan_mac_address)(u32 *num);
+	int (*set_wlan_mac_address)(const u8 *in, u32 len);
+	int (*power_up)(struct device *dev);
+	int (*power_down)(struct device *dev);
+	int (*register_tsf_captured_handler)(irq_handler_t handler,
+					     void *adapter);
+	int (*unregister_tsf_captured_handler)(void *adapter);
+};
+
+int cnss_pci_request_bus_bandwidth(int bandwidth);
+int cnss_sdio_request_bus_bandwidth(int bandwidth);
+
+void cnss_sdio_device_crashed(void);
+void cnss_pci_device_crashed(void);
+
+void cnss_pci_device_self_recovery(void);
+void cnss_sdio_device_self_recovery(void);
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
+
+void cnss_sdio_schedule_recovery_work(void);
+void cnss_pci_schedule_recovery_work(void);
+
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len);
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len);
+
+u8 *cnss_pci_get_wlan_mac_address(u32 *num);
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num);
+int cnss_sdio_power_up(struct device *dev);
+int cnss_sdio_power_down(struct device *dev);
+int cnss_pcie_power_up(struct device *dev);
+int cnss_pcie_power_down(struct device *dev);
+const char *cnss_wlan_get_evicted_data_file(void);
+#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
new file mode 100644
index 0000000..8797e68
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -0,0 +1,3835 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/esoc_client.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/log2.h>
+#include <linux/etherdevice.h>
+#include <linux/msm_pcie.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <net/cfg80211.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+#define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc)
+
+#define VREG_ON			1
+#define VREG_OFF		0
+#define WLAN_EN_HIGH		1
+#define WLAN_EN_LOW		0
+#define PCIE_LINK_UP		1
+#define PCIE_LINK_DOWN		0
+#define WLAN_BOOTSTRAP_HIGH	1
+#define WLAN_BOOTSTRAP_LOW	0
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN"
+
+#define QCA6174_VENDOR_ID	(0x168C)
+#define QCA6174_DEVICE_ID	(0x003E)
+#define BEELINER_DEVICE_ID      (0x0040)
+#define QCA6174_REV_ID_OFFSET	(0x08)
+#define QCA6174_FW_1_1	(0x11)
+#define QCA6174_FW_1_3	(0x13)
+#define QCA6174_FW_2_0	(0x20)
+#define QCA6174_FW_3_0	(0x30)
+#define QCA6174_FW_3_2	(0x32)
+#define BEELINER_FW	(0x00)
+
+#define QCA6180_VENDOR_ID	(0x168C)
+#define QCA6180_DEVICE_ID	(0x0041)
+#define QCA6180_REV_ID_OFFSET	(0x08)
+
+#define WLAN_EN_VREG_NAME	"vdd-wlan-en"
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_VREG_XTAL_AON_NAME	"vdd-wlan-xtal-aon"
+#define WLAN_VREG_CORE_NAME	"vdd-wlan-core"
+#define WLAN_VREG_SP2T_NAME	"vdd-wlan-sp2t"
+#define WLAN_SWREG_NAME		"wlan-soc-swreg"
+#define WLAN_ANT_SWITCH_NAME	"wlan-ant-switch"
+#define WLAN_EN_GPIO_NAME	"wlan-en-gpio"
+#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio"
+#define PM_OPTIONS		0
+#define PM_OPTIONS_SUSPEND_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+#define PM_OPTIONS_RESUME_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE)
+
+#define SOC_SWREG_VOLT_MAX	1200000
+#define SOC_SWREG_VOLT_MIN	1200000
+#define WLAN_ANT_SWITCH_VOLT_MAX	2700000
+#define WLAN_ANT_SWITCH_VOLT_MIN	2700000
+#define WLAN_ANT_SWITCH_CURR	20000
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define WLAN_VREG_CORE_MAX	1300000
+#define WLAN_VREG_CORE_MIN	1300000
+#define WLAN_VREG_SP2T_MAX	2700000
+#define WLAN_VREG_SP2T_MIN	2700000
+
+#define POWER_ON_DELAY		2
+#define WLAN_VREG_IO_DELAY_MIN	100
+#define WLAN_VREG_IO_DELAY_MAX	1000
+#define WLAN_ENABLE_DELAY	10
+#define PCIE_SWITCH_DELAY       20
+#define WLAN_RECOVERY_DELAY	1
+#define PCIE_ENABLE_DELAY	100
+#define WLAN_BOOTSTRAP_DELAY	10
+#define EVICT_BIN_MAX_SIZE      (512 * 1024)
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+#define FW_NAME_FIXED_LEN	(6)
+#define MAX_NUM_OF_SEGMENTS	(16)
+#define MAX_INDEX_FILE_SIZE	(512)
+#define FW_FILENAME_LENGTH	(13)
+#define TYPE_LENGTH		(4)
+#define PER_FILE_DATA		(21)
+#define MAX_IMAGE_SIZE		(2 * 1024 * 1024)
+#define FW_IMAGE_FTM		(0x01)
+#define FW_IMAGE_MISSION	(0x02)
+#define FW_IMAGE_BDATA		(0x03)
+#define FW_IMAGE_PRINT		(0x04)
+
+#define SEG_METADATA		(0x01)
+#define SEG_NON_PAGED		(0x02)
+#define SEG_LOCKED_PAGE		(0x03)
+#define SEG_UNLOCKED_PAGE	(0x04)
+#define SEG_NON_SECURE_DATA	(0x05)
+
+#define BMI_TEST_SETUP		(0x09)
+
+struct cnss_wlan_gpio_info {
+	char *name;
+	u32 num;
+	bool state;
+	bool init;
+	bool prop;
+};
+
+struct cnss_wlan_vreg_info {
+	struct regulator *wlan_en_reg;
+	struct regulator *wlan_reg;
+	struct regulator *soc_swreg;
+	struct regulator *ant_switch;
+	struct regulator *wlan_reg_io;
+	struct regulator *wlan_reg_xtal;
+	struct regulator *wlan_reg_xtal_aon;
+	struct regulator *wlan_reg_core;
+	struct regulator *wlan_reg_sp2t;
+	bool state;
+};
+
+struct segment_memory {
+	dma_addr_t dma_region;
+	void *cpu_region;
+	u32 size;
+};
+
+/* FW image descriptor lists */
+struct image_desc_hdr {
+	u8 image_id;
+	u8 reserved[3];
+	u32 segments_cnt;
+};
+
+struct segment_desc {
+	u8 segment_id;
+	u8 segment_idx;
+	u8 flags[2];
+	u32 addr_count;
+	u32 addr_low;
+	u32 addr_high;
+};
+
+struct region_desc {
+	u32 addr_low;
+	u32 addr_high;
+	u32 size;
+	u32 reserved;
+};
+
+struct index_file {
+	u32 type;
+	u32 segment_idx;
+	u8 file_name[13];
+};
+
+struct cnss_dual_wifi {
+	bool is_dual_wifi_enabled;
+};
+
+/**
+ * struct wlan_mac_addr - Structure to hold WLAN MAC Address
+ * @mac_addr: MAC address
+ */
+#define MAX_NO_OF_MAC_ADDR 4
+struct cnss_wlan_mac_addr {
+	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+	u32 no_of_mac_addr_set;
+};
+
+/* device_info is expected to be fully populated after cnss_config is invoked.
+ * The function pointer callbacks are expected to be non null as well.
+ */
+static struct cnss_data {
+	struct platform_device *pldev;
+	struct subsys_device *subsys;
+	struct subsys_desc    subsysdesc;
+	struct cnss_wlan_mac_addr wlan_mac_addr;
+	bool is_wlan_mac_set;
+	bool ramdump_dynamic;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	struct cnss_wlan_driver *driver;
+	struct pci_dev *pdev;
+	const struct pci_device_id *id;
+	struct dma_iommu_mapping *smmu_mapping;
+	dma_addr_t smmu_iova_start;
+	size_t smmu_iova_len;
+	struct cnss_wlan_vreg_info vreg_info;
+	bool wlan_en_vreg_support;
+	struct cnss_wlan_gpio_info gpio_info;
+	bool pcie_link_state;
+	bool pcie_link_down_ind;
+	bool pci_register_again;
+	bool notify_modem_status;
+	struct pci_saved_state *saved_state;
+	u16 revision_id;
+	bool recovery_in_progress;
+	atomic_t fw_available;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	/* Virtual Address of the DMA page */
+	void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
+	struct cnss_fw_files fw_files;
+	struct pm_qos_request qos_request;
+	void *modem_notify_handler;
+	int modem_current_status;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+	void *subsys_handle;
+	struct esoc_desc *esoc_desc;
+	struct cnss_platform_cap cap;
+	struct msm_pcie_register_event event_reg;
+	struct wakeup_source ws;
+	u32 recovery_count;
+	enum cnss_driver_status driver_status;
+#ifdef CONFIG_CNSS_SECURE_FW
+	void *fw_mem;
+#endif
+	u32 device_id;
+	int fw_image_setup;
+	u32 bmi_test;
+	void *fw_cpu;
+	dma_addr_t fw_dma;
+	u32 fw_dma_size;
+	u32 fw_seg_count;
+	struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
+	/* Firmware setup complete lock */
+	struct mutex fw_setup_stat_lock;
+	void *bdata_cpu;
+	dma_addr_t bdata_dma;
+	u32 bdata_dma_size;
+	u32 bdata_seg_count;
+	struct segment_memory bdata_seg_mem[MAX_NUM_OF_SEGMENTS];
+	int wlan_bootstrap_gpio;
+	atomic_t auto_suspended;
+	bool monitor_wake_intr;
+	struct cnss_dual_wifi dual_wifi_info;
+	struct cnss_dev_platform_ops platform_ops;
+} *penv;
+
+static unsigned int pcie_link_down_panic;
+module_param(pcie_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pcie_link_down_panic,
+		 "Trigger kernel panic when PCIe link down is detected");
+
+static void cnss_put_wlan_enable_gpio(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support)
+		regulator_put(vreg_info->wlan_en_reg);
+	else
+		gpio_free(gpio_info->num);
+}
+
+static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_enable_reg_core;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_enable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_enable_reg_io;
+		}
+
+		usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX);
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon enable failed\n",
+			       __func__);
+			goto error_enable_reg_xtal_aon;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_enable_reg_xtal;
+		}
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator enable failed for WLAN power\n",
+		       __func__);
+		goto error_enable;
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_enable_reg_sp2t;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_enable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator enable failed for ant_switch\n",
+			       __func__);
+			goto error_enable_ant_switch;
+		}
+	}
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator enable failed for external soc-swreg\n",
+			       __func__);
+			goto error_enable_soc_swreg;
+		}
+	}
+
+	return ret;
+
+error_enable_soc_swreg:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+error_enable_ant_switch:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+error_enable_reg_sp2t:
+	regulator_disable(vreg_info->wlan_reg);
+error_enable:
+	if (vreg_info->wlan_reg_xtal)
+		regulator_disable(vreg_info->wlan_reg_xtal);
+error_enable_reg_xtal:
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_disable(vreg_info->wlan_reg_xtal_aon);
+error_enable_reg_xtal_aon:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+error_enable_reg_io:
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+error_enable_reg_core:
+	return ret;
+}
+
+static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_disable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator disable failed for external soc-swreg\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_disable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator disable failed for ant_switch\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_disable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	ret = regulator_disable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator disable failed for WLAN power\n",
+		       __func__);
+		goto error_disable;
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon disable failed\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_disable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_disable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+error_disable:
+	return ret;
+}
+
+static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state)
+{
+	int ret = 0;
+
+	if (vreg_info->state == state) {
+		pr_debug("Already wlan vreg state is %s\n",
+			 state ? "enabled" : "disabled");
+		goto out;
+	}
+
+	if (state)
+		ret = cnss_wlan_vreg_on(vreg_info);
+	else
+		ret = cnss_wlan_vreg_off(vreg_info);
+
+	if (ret)
+		goto out;
+
+	pr_debug("%s: wlan vreg is now %s\n", __func__,
+		 state ? "enabled" : "disabled");
+	vreg_info->state = state;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_gpio_init(struct cnss_wlan_gpio_info *info)
+{
+	int ret = 0;
+
+	ret = gpio_request(info->num, info->name);
+
+	if (ret) {
+		pr_err("can't get gpio %s ret %d\n", info->name, ret);
+		goto err_gpio_req;
+	}
+
+	ret = gpio_direction_output(info->num, info->init);
+
+	if (ret) {
+		pr_err("can't set gpio direction %s ret %d\n", info->name, ret);
+		goto err_gpio_dir;
+	}
+	info->state = info->init;
+
+	return ret;
+
+err_gpio_dir:
+	gpio_free(info->num);
+
+err_gpio_req:
+
+	return ret;
+}
+
+static int cnss_wlan_bootstrap_gpio_init(void)
+{
+	int ret = 0;
+
+	ret = gpio_request(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_GPIO_NAME);
+	if (ret) {
+		pr_err("%s: Can't get GPIO %s, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		goto out;
+	}
+
+	ret = gpio_direction_output(penv->wlan_bootstrap_gpio,
+				    WLAN_BOOTSTRAP_HIGH);
+	if (ret) {
+		pr_err("%s: Can't set GPIO %s direction, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		gpio_free(penv->wlan_bootstrap_gpio);
+		goto out;
+	}
+
+	msleep(WLAN_BOOTSTRAP_DELAY);
+out:
+	return ret;
+}
+
+static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state)
+{
+	if (!info->prop)
+		return;
+
+	if (info->state == state) {
+		pr_debug("Already %s gpio is %s\n",
+			 info->name, state ? "high" : "low");
+		return;
+	}
+
+	gpio_set_value(info->num, state);
+	info->state = state;
+
+	pr_debug("%s: %s gpio is now %s\n", __func__,
+		 info->name, info->state ? "enabled" : "disabled");
+}
+
+static int cnss_configure_wlan_en_gpio(bool state)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support) {
+		if (state)
+			ret = regulator_enable(vreg_info->wlan_en_reg);
+		else
+			ret = regulator_disable(vreg_info->wlan_en_reg);
+	} else {
+		cnss_wlan_gpio_set(gpio_info, state);
+	}
+
+	msleep(WLAN_ENABLE_DELAY);
+	return ret;
+}
+
+static void cnss_disable_xtal_ldo(struct platform_device *pdev)
+{
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (info->wlan_reg_xtal) {
+		regulator_disable(info->wlan_reg_xtal);
+		regulator_put(info->wlan_reg_xtal);
+	}
+
+	if (info->wlan_reg_xtal_aon) {
+		regulator_disable(info->wlan_reg_xtal_aon);
+		regulator_put(info->wlan_reg_xtal_aon);
+	}
+}
+
+static int cnss_enable_xtal_ldo(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_AON_NAME "-supply", NULL))
+		goto enable_xtal;
+
+	info->wlan_reg_xtal_aon = regulator_get(&pdev->dev,
+						WLAN_VREG_XTAL_AON_NAME);
+	if (IS_ERR(info->wlan_reg_xtal_aon)) {
+		ret = PTR_ERR(info->wlan_reg_xtal_aon);
+		pr_err("%s: XTAL AON Regulator get failed err:%d\n", __func__,
+		       ret);
+		return ret;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal_aon);
+	if (ret) {
+		pr_err("%s: VREG_XTAL_ON enable failed\n", __func__);
+		goto end;
+	}
+
+enable_xtal:
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_NAME "-supply", NULL))
+		goto out_disable_xtal_aon;
+
+	info->wlan_reg_xtal = regulator_get(&pdev->dev, WLAN_VREG_XTAL_NAME);
+
+	if (IS_ERR(info->wlan_reg_xtal)) {
+		ret = PTR_ERR(info->wlan_reg_xtal);
+		pr_err("%s XTAL Regulator get failed err:%d\n", __func__, ret);
+		goto out_disable_xtal_aon;
+	}
+
+	ret = regulator_set_voltage(info->wlan_reg_xtal, WLAN_VREG_XTAL_MIN,
+				    WLAN_VREG_XTAL_MAX);
+	if (ret) {
+		pr_err("%s: Set wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal);
+	if (ret) {
+		pr_err("%s: Enable wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	return 0;
+
+out_put_xtal:
+	if (info->wlan_reg_xtal)
+		regulator_put(info->wlan_reg_xtal);
+
+out_disable_xtal_aon:
+	if (info->wlan_reg_xtal_aon)
+		regulator_disable(info->wlan_reg_xtal_aon);
+
+end:
+	if (info->wlan_reg_xtal_aon)
+		regulator_put(info->wlan_reg_xtal_aon);
+
+	return ret;
+}
+
+static int cnss_get_wlan_enable_gpio(
+	struct cnss_wlan_gpio_info *gpio_info,
+	struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+
+	if (!of_find_property(dev->of_node, gpio_info->name, NULL)) {
+		gpio_info->prop = false;
+		return -ENODEV;
+	}
+
+	gpio_info->prop = true;
+	ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0);
+	if (ret >= 0) {
+		gpio_info->num = ret;
+	} else {
+		if (ret == -EPROBE_DEFER)
+			pr_debug("get WLAN_EN GPIO probe defer\n");
+		else
+			pr_err(
+			"can't get gpio %s ret %d", gpio_info->name, ret);
+	}
+
+	ret = cnss_wlan_gpio_init(gpio_info);
+	if (ret)
+		pr_err("gpio init failed\n");
+
+	return ret;
+}
+
+static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device_node *node = (&pdev->dev)->of_node;
+
+	if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL))
+		return ret;
+
+	penv->wlan_bootstrap_gpio =
+		of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0);
+	if (penv->wlan_bootstrap_gpio > 0) {
+		ret = cnss_wlan_bootstrap_gpio_init();
+	} else {
+		ret = penv->wlan_bootstrap_gpio;
+		pr_err(
+		"%s: Can't get GPIO %s, ret = %d",
+		__func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+	}
+
+	return ret;
+}
+
+static int cnss_wlan_get_resources(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	struct device_node *node = pdev->dev.of_node;
+
+	if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_core = regulator_get(&pdev->dev,
+			WLAN_VREG_CORE_NAME);
+		if (IS_ERR(vreg_info->wlan_reg_core)) {
+			ret = PTR_ERR(vreg_info->wlan_reg_core);
+
+			if (ret == -EPROBE_DEFER) {
+				pr_err("%s: wlan_reg_core probe deferred\n",
+				       __func__);
+			} else {
+				pr_err("%s: Get wlan_reg_core failed\n",
+				       __func__);
+			}
+			goto err_reg_core_get;
+		}
+
+		ret = regulator_set_voltage(vreg_info->wlan_reg_core,
+					    WLAN_VREG_CORE_MIN,
+					    WLAN_VREG_CORE_MAX);
+		if (ret) {
+			pr_err("%s: Set wlan_reg_core failed\n", __func__);
+			goto err_reg_core_set;
+		}
+
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: Enable wlan_reg_core failed\n", __func__);
+			goto err_reg_core_enable;
+		}
+	}
+
+	if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_io = regulator_get(&pdev->dev,
+			WLAN_VREG_IO_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_io)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_io,
+						    WLAN_VREG_IO_MIN,
+						    WLAN_VREG_IO_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_io);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_enable;
+			}
+
+			usleep_range(WLAN_VREG_IO_DELAY_MIN,
+				     WLAN_VREG_IO_DELAY_MAX);
+		}
+	}
+
+	if (cnss_enable_xtal_ldo(pdev))
+		goto err_reg_xtal_enable;
+
+	vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
+
+	if (IS_ERR(vreg_info->wlan_reg)) {
+		if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
+			pr_err("%s: vreg probe defer\n", __func__);
+		else
+			pr_err("%s: vreg regulator get failed\n", __func__);
+		ret = PTR_ERR(vreg_info->wlan_reg);
+		goto err_reg_get;
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+
+	if (ret) {
+		pr_err("%s: vreg initial vote failed\n", __func__);
+		goto err_reg_enable;
+	}
+
+	if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_sp2t =
+			regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_sp2t)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_sp2t,
+						    WLAN_VREG_SP2T_MIN,
+						    WLAN_VREG_SP2T_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_enable;
+			}
+		}
+	}
+
+	if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) {
+		vreg_info->ant_switch =
+			regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME);
+		if (!IS_ERR(vreg_info->ant_switch)) {
+			ret = regulator_set_voltage(vreg_info->ant_switch,
+						    WLAN_ANT_SWITCH_VOLT_MIN,
+						    WLAN_ANT_SWITCH_VOLT_MAX);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch voltage failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_set_load(vreg_info->ant_switch,
+						 WLAN_ANT_SWITCH_CURR);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch current failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_enable(vreg_info->ant_switch);
+			if (ret < 0) {
+				pr_err("%s: Enable ant_switch failed\n",
+				       __func__);
+				goto err_ant_switch_enable;
+			}
+		}
+	}
+
+	if (of_find_property(node, "qcom,wlan-uart-access", NULL))
+		penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS;
+
+	if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) {
+		vreg_info->soc_swreg = regulator_get(&pdev->dev,
+			WLAN_SWREG_NAME);
+		if (IS_ERR(vreg_info->soc_swreg)) {
+			pr_err("%s: soc-swreg node not found\n",
+			       __func__);
+			goto err_reg_get2;
+		}
+		ret = regulator_set_voltage(vreg_info->soc_swreg,
+					    SOC_SWREG_VOLT_MIN,
+					    SOC_SWREG_VOLT_MAX);
+		if (ret) {
+			pr_err("%s: vreg initial voltage set failed on soc-swreg\n",
+			       __func__);
+			goto err_reg_set;
+		}
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: vreg initial vote failed\n", __func__);
+			goto err_reg_enable2;
+		}
+		penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG;
+	}
+
+	penv->wlan_en_vreg_support =
+		of_property_read_bool(node, "qcom,wlan-en-vreg-support");
+	if (penv->wlan_en_vreg_support) {
+		vreg_info->wlan_en_reg =
+			regulator_get(&pdev->dev, WLAN_EN_VREG_NAME);
+		if (IS_ERR(vreg_info->wlan_en_reg)) {
+			pr_err("%s:wlan_en vreg get failed\n", __func__);
+			ret = PTR_ERR(vreg_info->wlan_en_reg);
+			goto err_wlan_en_reg_get;
+		}
+	}
+
+	if (!penv->wlan_en_vreg_support) {
+		ret = cnss_get_wlan_enable_gpio(gpio_info, pdev);
+		if (ret) {
+			pr_err(
+			"%s:Failed to config the WLAN_EN gpio\n", __func__);
+			goto err_gpio_wlan_en;
+		}
+	}
+	vreg_info->state = VREG_ON;
+
+	ret = cnss_get_wlan_bootstrap_gpio(pdev);
+	if (ret) {
+		pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__);
+		goto err_gpio_wlan_bootstrap;
+	}
+
+	return ret;
+
+err_gpio_wlan_bootstrap:
+	cnss_put_wlan_enable_gpio();
+err_gpio_wlan_en:
+err_wlan_en_reg_get:
+	vreg_info->wlan_en_reg = NULL;
+	if (vreg_info->soc_swreg)
+		regulator_disable(vreg_info->soc_swreg);
+	vreg_info->state = VREG_OFF;
+
+err_reg_enable2:
+err_reg_set:
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+
+err_reg_get2:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+
+err_ant_switch_enable:
+err_ant_switch_set:
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+
+err_reg_sp2t_enable:
+err_reg_sp2t_set:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_disable(vreg_info->wlan_reg);
+
+err_reg_enable:
+	regulator_put(vreg_info->wlan_reg);
+err_reg_get:
+	cnss_disable_xtal_ldo(pdev);
+
+err_reg_xtal_enable:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+
+err_reg_io_enable:
+err_reg_io_set:
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+
+err_reg_core_enable:
+err_reg_core_set:
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+
+err_reg_core_get:
+	return ret;
+}
+
+static void cnss_wlan_release_resources(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_free(penv->wlan_bootstrap_gpio);
+	cnss_put_wlan_enable_gpio();
+	gpio_info->state = WLAN_EN_LOW;
+	gpio_info->prop = false;
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_put(vreg_info->wlan_reg);
+	if (vreg_info->wlan_reg_xtal)
+		regulator_put(vreg_info->wlan_reg_xtal);
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_put(vreg_info->wlan_reg_xtal_aon);
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+	vreg_info->state = VREG_OFF;
+}
+
+static u8 cnss_get_pci_dev_bus_number(struct pci_dev *pdev)
+{
+	return pdev->bus->number;
+}
+
+void cnss_setup_fw_files(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_1_1:
+		strlcpy(penv->fw_files.image_file, "qwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd11.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_1_3:
+		strlcpy(penv->fw_files.image_file, "qwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd13.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_2_0:
+		strlcpy(penv->fw_files.image_file, "qwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd20.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		strlcpy(penv->fw_files.image_file, "qwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd30.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	default:
+		strlcpy(penv->fw_files.image_file, "qwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+	}
+}
+
+int cnss_get_fw_files(struct cnss_fw_files *pfw_files)
+{
+	if (!penv || !pfw_files)
+		return -ENODEV;
+
+	*pfw_files = penv->fw_files;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+	penv->fw_mem = devm_kzalloc(&pdev->dev, MAX_FIRMWARE_SIZE, GFP_KERNEL);
+}
+#else
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+}
+#endif
+
+static int get_image_file(const u8 *index_info, u8 *file_name,
+			  u32 *type, u32 *segment_idx)
+{
+	if (!file_name || !index_info || !type)
+		return -EINVAL;
+
+	memcpy(type, index_info, TYPE_LENGTH);
+	memcpy(segment_idx, index_info + TYPE_LENGTH, TYPE_LENGTH);
+	memcpy(file_name, index_info + TYPE_LENGTH + TYPE_LENGTH,
+	       FW_FILENAME_LENGTH);
+
+	pr_debug("%u: %u: %s", *type, *segment_idx, file_name);
+
+	return PER_FILE_DATA;
+}
+
+static void print_allocated_image_table(void)
+{
+	u32 seg = 0, count = 0;
+	u8 *dump_addr;
+	struct segment_memory *pseg_mem = penv->fw_seg_mem;
+	struct segment_memory *p_bdata_seg_mem = penv->bdata_seg_mem;
+
+	pr_debug("%s: Dumping FW IMAGE\n", __func__);
+	while (seg++ < penv->fw_seg_count) {
+		dump_addr = (u8 *)pseg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < pseg_mem->size -
+				sizeof(struct region_desc); count++)
+			pr_debug("%02x", dump_addr[count]);
+
+		pseg_mem++;
+	}
+
+	seg = 0;
+	pr_debug("%s: Dumping BOARD DATA\n", __func__);
+	while (seg++ < penv->bdata_seg_count) {
+		dump_addr = (u8 *)p_bdata_seg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < p_bdata_seg_mem->size -
+			     sizeof(struct region_desc); count++)
+			pr_debug("%02x ", dump_addr[count]);
+
+		p_bdata_seg_mem++;
+	}
+}
+
+static void free_allocated_image_table(void)
+{
+	struct device *dev = &penv->pdev->dev;
+	struct segment_memory *pseg_mem;
+	u32 seg = 0;
+
+	/* free fw memroy */
+	pseg_mem = penv->fw_seg_mem;
+	while (seg++ < penv->fw_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region, pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->fw_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->fw_cpu, penv->fw_dma);
+	penv->fw_seg_count = 0;
+	penv->fw_dma = 0;
+	penv->fw_cpu = NULL;
+	penv->fw_dma_size = 0;
+
+	/* free bdata memory */
+	seg = 0;
+	pseg_mem = penv->bdata_seg_mem;
+	while (seg++ < penv->bdata_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region,
+				  pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->bdata_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->bdata_cpu, penv->bdata_dma);
+	penv->bdata_seg_count = 0;
+	penv->bdata_dma = 0;
+	penv->bdata_cpu = NULL;
+	penv->bdata_dma_size = 0;
+}
+
+static int cnss_setup_fw_image_table(int mode)
+{
+	struct image_desc_hdr *image_hdr;
+	struct segment_desc *pseg = NULL;
+	const struct firmware *fw_index, *fw_image;
+	struct device *dev = NULL;
+	char reserved[3] = "";
+	u8 image_file[FW_FILENAME_LENGTH] = "";
+	u8 index_file[FW_FILENAME_LENGTH] = "";
+	u8 index_info[MAX_INDEX_FILE_SIZE] = "";
+	size_t image_desc_size = 0, file_size = 0;
+	size_t index_pos = 0, image_pos = 0;
+	struct region_desc *reg_desc = NULL;
+	u32 type = 0;
+	u32 segment_idx = 0;
+	uintptr_t address;
+	int ret = 0;
+	dma_addr_t dma_addr;
+	void *vaddr = NULL;
+	dma_addr_t paddr;
+	struct segment_memory *pseg_mem;
+	u32 *pseg_count;
+
+	if (!penv || !penv->pdev) {
+		pr_err("cnss: invalid penv or pdev or dev\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dev = &penv->pdev->dev;
+
+	/*  meta data file has image details */
+	switch (mode) {
+	case FW_IMAGE_FTM:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qftm.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_MISSION:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qwlan.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_BDATA:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "bdwlan.bin");
+		pseg_mem = penv->bdata_seg_mem;
+		pseg_count = &penv->bdata_seg_count;
+		break;
+	default:
+		pr_err("%s: Unknown meta data file type 0x%x\n",
+		       __func__, mode);
+		ret = -EINVAL;
+	}
+	if (ret < 0)
+		goto err;
+
+	image_desc_size = sizeof(struct image_desc_hdr) +
+		sizeof(struct segment_desc) * MAX_NUM_OF_SEGMENTS;
+
+	vaddr = dma_alloc_coherent(dev, image_desc_size,
+				   &paddr, GFP_KERNEL);
+
+	if (!vaddr) {
+		pr_err("cnss: image desc allocation failure\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(vaddr, 0, image_desc_size);
+
+	image_hdr = (struct image_desc_hdr *)vaddr;
+	image_hdr->image_id = mode;
+	memcpy(image_hdr->reserved, reserved, 3);
+
+	pr_err("cnss: request meta data file %s\n", index_file);
+	ret = request_firmware(&fw_index, index_file, dev);
+	if (ret || !fw_index || !fw_index->data || !fw_index->size) {
+		pr_err("cnss: meta data file open failure %s\n", index_file);
+		goto err_free;
+	}
+
+	if (fw_index->size > MAX_INDEX_FILE_SIZE) {
+		pr_err("cnss: meta data file has invalid size %s: %zu\n",
+		       index_file, fw_index->size);
+		release_firmware(fw_index);
+		goto err_free;
+	}
+
+	memcpy(index_info, fw_index->data, fw_index->size);
+	file_size = fw_index->size;
+	release_firmware(fw_index);
+
+	while (file_size >= PER_FILE_DATA  && image_pos < image_desc_size &&
+	       image_hdr->segments_cnt < MAX_NUM_OF_SEGMENTS) {
+		ret = get_image_file(index_info + index_pos,
+				     image_file, &type, &segment_idx);
+		if (ret == -EINVAL)
+			goto err_free;
+
+		file_size -= ret;
+		index_pos += ret;
+		pseg = vaddr + image_pos +
+				sizeof(struct image_desc_hdr);
+
+		switch (type) {
+		case SEG_METADATA:
+		case SEG_NON_PAGED:
+		case SEG_LOCKED_PAGE:
+		case SEG_UNLOCKED_PAGE:
+		case SEG_NON_SECURE_DATA:
+
+			image_hdr->segments_cnt++;
+			pseg->segment_id = type;
+			pseg->segment_idx = (u8)(segment_idx & 0xff);
+			memcpy(pseg->flags, reserved, 2);
+
+			ret = request_firmware(&fw_image, image_file, dev);
+			if (ret || !fw_image || !fw_image->data ||
+			    !fw_image->size) {
+				pr_err("cnss: image file read failed %s",
+				       image_file);
+				goto err_free;
+			}
+			if (fw_image->size > MAX_IMAGE_SIZE) {
+				pr_err("cnss: %s: image file invalid size %zu\n",
+				       image_file, fw_image->size);
+				release_firmware(fw_image);
+				ret = -EINVAL;
+				goto err_free;
+			}
+			reg_desc =
+				dma_alloc_coherent(dev,
+						   sizeof(struct region_desc) +
+						   fw_image->size,
+						   &dma_addr, GFP_KERNEL);
+			if (!reg_desc) {
+				pr_err("cnss: region allocation failure\n");
+				ret = -ENOMEM;
+				release_firmware(fw_image);
+				goto err_free;
+			}
+			address = (uintptr_t)dma_addr;
+			pseg->addr_low = address & 0xFFFFFFFF;
+			pseg->addr_high = 0x00;
+			/* one region for one image file */
+			pseg->addr_count = 1;
+			memcpy((u8 *)reg_desc + sizeof(struct region_desc),
+			       fw_image->data, fw_image->size);
+			address += sizeof(struct region_desc);
+			reg_desc->addr_low = address & 0xFFFFFFFF;
+			reg_desc->addr_high = 0x00;
+			reg_desc->reserved = 0;
+			reg_desc->size = fw_image->size;
+
+			pseg_mem[*pseg_count].dma_region = dma_addr;
+			pseg_mem[*pseg_count].cpu_region = reg_desc;
+			pseg_mem[*pseg_count].size =
+				sizeof(struct region_desc) + fw_image->size;
+
+			release_firmware(fw_image);
+			(*pseg_count)++;
+			break;
+
+		default:
+			pr_err("cnss: Unknown segment %d", type);
+			ret = -EINVAL;
+			goto err_free;
+		}
+		image_pos += sizeof(struct segment_desc);
+	}
+	if (mode != FW_IMAGE_BDATA) {
+		penv->fw_cpu = vaddr;
+		penv->fw_dma = paddr;
+		penv->fw_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	} else {
+		penv->bdata_cpu = vaddr;
+		penv->bdata_dma = paddr;
+		penv->bdata_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	}
+	pr_info("%s: Mode %d: Image setup table built on host", __func__, mode);
+
+	return file_size;
+err_free:
+	free_allocated_image_table();
+err:
+	pr_err("cnss: image file setup failed %d\n", ret);
+	return ret;
+}
+
+int cnss_get_fw_image(struct image_desc_info *image_desc_info)
+{
+	if (!image_desc_info || !penv ||
+	    !penv->fw_seg_count || !penv->bdata_seg_count)
+		return -EINVAL;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	image_desc_info->fw_addr = penv->fw_dma;
+	image_desc_info->fw_size = penv->fw_dma_size;
+	image_desc_info->bdata_addr = penv->bdata_dma;
+	image_desc_info->bdata_size = penv->bdata_dma_size;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_image);
+
+static ssize_t wlan_setup_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->revision_id);
+}
+
+static DEVICE_ATTR(wlan_setup, 0400,
+			wlan_setup_show, NULL);
+
+static int cnss_wlan_is_codeswap_supported(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+static int cnss_smmu_init(struct device *dev)
+{
+	struct dma_iommu_mapping *mapping;
+	int atomic_ctx = 1;
+	int ret;
+
+	mapping = arm_iommu_create_mapping(&platform_bus_type,
+					   penv->smmu_iova_start,
+					   penv->smmu_iova_len);
+	if (IS_ERR(mapping)) {
+		ret = PTR_ERR(mapping);
+		pr_err("%s: create mapping failed, err = %d\n", __func__, ret);
+		goto map_fail;
+	}
+
+	ret = iommu_domain_set_attr(mapping->domain,
+				    DOMAIN_ATTR_ATOMIC,
+				    &atomic_ctx);
+	if (ret) {
+		pr_err("%s: set atomic_ctx attribute failed, err = %d\n",
+		       __func__, ret);
+		goto set_attr_fail;
+	}
+
+	ret = arm_iommu_attach_device(dev, mapping);
+	if (ret) {
+		pr_err("%s: attach device failed, err = %d\n", __func__, ret);
+		goto attach_fail;
+	}
+
+	penv->smmu_mapping = mapping;
+
+	return ret;
+
+attach_fail:
+set_attr_fail:
+	arm_iommu_release_mapping(mapping);
+map_fail:
+	return ret;
+}
+
+static void cnss_smmu_remove(struct device *dev)
+{
+	arm_iommu_detach_device(dev);
+	arm_iommu_release_mapping(penv->smmu_mapping);
+
+	penv->smmu_mapping = NULL;
+}
+
+#ifdef CONFIG_PCI_MSM
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return pci_store_saved_state(dev);
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return msm_pcie_pm_control(pm_opt, bus_num, pdev, NULL, options);
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return pci_load_and_free_saved_state(dev, state);
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return msm_pcie_shadow_control(dev, enable);
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_deregister_event(reg);
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return msm_pcie_recover_config(dev);
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_register_event(reg);
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return msm_pcie_enumerate(rc_idx);
+}
+#else /* !defined CONFIG_PCI_MSM */
+
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return NULL;
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return -ENODEV;
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return 0;
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return -EPROBE_DEFER;
+}
+#endif
+
+static void cnss_pcie_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth;
+	pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_pci_device_self_recovery;
+	pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work;
+	pf_ops->device_crashed = cnss_pci_device_crashed;
+	pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address;
+	pf_ops->power_up = cnss_pcie_power_up;
+	pf_ops->power_down = cnss_pcie_power_down;
+
+	dev->platform_data = pf_ops;
+}
+
+static void cnss_pcie_reset_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	dev->platform_data = NULL;
+}
+
+static int cnss_wlan_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	void *cpu_addr;
+	dma_addr_t dma_handle;
+	struct codeswap_codeseg_info *cnss_seg_info = NULL;
+	struct device *dev = &pdev->dev;
+
+	cnss_pcie_set_platform_ops(dev);
+	penv->pdev = pdev;
+	penv->id = id;
+	atomic_set(&penv->fw_available, 0);
+	penv->device_id = pdev->device;
+
+	if (penv->smmu_iova_len) {
+		ret = cnss_smmu_init(&pdev->dev);
+		if (ret) {
+			pr_err("%s: SMMU init failed, err = %d\n",
+			       __func__, ret);
+			goto smmu_init_fail;
+		}
+	}
+
+	if (penv->pci_register_again) {
+		pr_debug("%s: PCI re-registration complete\n", __func__);
+		penv->pci_register_again = false;
+		return 0;
+	}
+
+	switch (pdev->device) {
+	case QCA6180_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6180_REV_ID_OFFSET,
+				     &penv->revision_id);
+		break;
+
+	case QCA6174_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6174_REV_ID_OFFSET,
+				     &penv->revision_id);
+		cnss_setup_fw_files(penv->revision_id);
+		break;
+
+	default:
+		pr_err("cnss: unknown device found %d\n", pdev->device);
+		ret = -EPROBE_DEFER;
+		goto err_unknown;
+	}
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("Failed to shutdown PCIe link\n");
+			goto err_pcie_suspend;
+		}
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+
+	if (ret) {
+		pr_err("can't turn off wlan vreg\n");
+		goto err_pcie_suspend;
+	}
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	cnss_wlan_fw_mem_alloc(pdev);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup);
+
+	if (ret) {
+		pr_err("Can't Create Device file\n");
+		goto err_pcie_suspend;
+	}
+
+	if (cnss_wlan_is_codeswap_supported(penv->revision_id)) {
+		pr_debug("Code-swap not enabled: %d\n", penv->revision_id);
+		goto err_pcie_suspend;
+	}
+
+	cpu_addr = dma_alloc_coherent(dev, EVICT_BIN_MAX_SIZE,
+				      &dma_handle, GFP_KERNEL);
+	if (!cpu_addr || !dma_handle) {
+		pr_err("cnss: Memory Alloc failed for codeswap feature\n");
+		goto err_pcie_suspend;
+	}
+
+	memset(cpu_addr, 0, EVICT_BIN_MAX_SIZE);
+	cnss_seg_info = devm_kzalloc(dev, sizeof(*cnss_seg_info),
+				     GFP_KERNEL);
+	if (!cnss_seg_info)
+		goto end_dma_alloc;
+
+	memset(cnss_seg_info, 0, sizeof(*cnss_seg_info));
+	cnss_seg_info->codeseg_busaddr[0]   = (void *)dma_handle;
+	penv->codeseg_cpuaddr[0]            = cpu_addr;
+	cnss_seg_info->codeseg_size         = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->codeseg_total_bytes  = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->num_codesegs         = 1;
+	cnss_seg_info->codeseg_size_log2    = ilog2(EVICT_BIN_MAX_SIZE);
+
+	penv->cnss_seg_info = cnss_seg_info;
+	pr_debug("%s: Successfully allocated memory for CODESWAP\n", __func__);
+
+	return ret;
+
+end_dma_alloc:
+	dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle);
+err_unknown:
+err_pcie_suspend:
+smmu_init_fail:
+	cnss_pcie_reset_platform_ops(dev);
+	return ret;
+}
+
+static void cnss_wlan_pci_remove(struct pci_dev *pdev)
+{
+	struct device *dev;
+
+	if (!penv)
+		return;
+
+	dev = &penv->pldev->dev;
+	cnss_pcie_reset_platform_ops(dev);
+	device_remove_file(dev, &dev_attr_wlan_setup);
+
+	if (penv->smmu_mapping)
+		cnss_smmu_remove(&pdev->dev);
+}
+
+static int cnss_wlan_pci_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->suspend) {
+		ret = wdriver->suspend(pdev, state);
+
+		if (penv->pcie_link_state) {
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+		}
+	}
+	penv->monitor_wake_intr = false;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_pci_resume(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->resume && !penv->pcie_link_down_ind) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+		pci_restore_state(pdev);
+
+		ret = wdriver->resume(pdev);
+	}
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdrv;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime suspend start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_suspend)
+		ret = wdrv->runtime_ops->runtime_suspend(to_pci_dev(dev));
+
+	pr_info("cnss: runtime suspend status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_resume(struct device *dev)
+{
+	struct cnss_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime resume start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_resume)
+		ret = wdrv->runtime_ops->runtime_resume(to_pci_dev(dev));
+
+	pr_info("cnss: runtime resume status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_idle(struct device *dev)
+{
+	pr_debug("cnss: runtime idle\n");
+
+	pm_request_autosuspend(dev);
+
+	return -EBUSY;
+}
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+static int cnss_pm_notify(struct notifier_block *b,
+			  unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&cnss_pm_sem);
+		break;
+
+	case PM_POST_SUSPEND:
+		up_write(&cnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cnss_pm_notifier = {
+	.notifier_call = cnss_pm_notify,
+};
+
+static const struct pci_device_id cnss_wlan_pci_id_table[] = {
+	{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6174_VENDOR_ID, BEELINER_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6180_VENDOR_ID, QCA6180_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_wlan_pci_id_table);
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops cnss_wlan_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cnss_wlan_pci_suspend, cnss_wlan_pci_resume)
+	SET_RUNTIME_PM_OPS(cnss_wlan_runtime_suspend, cnss_wlan_runtime_resume,
+			   cnss_wlan_runtime_idle)
+};
+#endif
+
+struct pci_driver cnss_wlan_pci_driver = {
+	.name     = "cnss_wlan_pci",
+	.id_table = cnss_wlan_pci_id_table,
+	.probe    = cnss_wlan_pci_probe,
+	.remove   = cnss_wlan_pci_remove,
+#ifdef CONFIG_PM
+	.driver = {
+		.pm = &cnss_wlan_pm_ops,
+	},
+#endif
+};
+
+static ssize_t fw_image_setup_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->fw_image_setup);
+}
+
+static ssize_t fw_image_setup_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int val;
+	int ret;
+
+	if (!penv)
+		return -ENODEV;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	pr_info("%s: Firmware setup in progress\n", __func__);
+
+	if (kstrtoint(buf, 0, &val)) {
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -EINVAL;
+	}
+
+	if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION ||
+	    val == FW_IMAGE_BDATA) {
+		pr_info("%s: fw image setup triggered %d\n", __func__, val);
+		ret = cnss_setup_fw_image_table(val);
+		if (ret != 0) {
+			pr_err("%s: Invalid parsing of FW image files %d\n",
+			       __func__, ret);
+			mutex_unlock(&penv->fw_setup_stat_lock);
+			return -EINVAL;
+		}
+		penv->fw_image_setup = val;
+	} else if (val == FW_IMAGE_PRINT) {
+		print_allocated_image_table();
+	} else if (val == BMI_TEST_SETUP) {
+		penv->bmi_test = val;
+	}
+
+	pr_info("%s: Firmware setup completed\n", __func__);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+	return count;
+}
+
+static DEVICE_ATTR(fw_image_setup, 0600,
+	fw_image_setup_show, fw_image_setup_store);
+
+void cnss_pci_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_pci_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_pci_recovery_work, cnss_pci_recovery_work_handler);
+
+void cnss_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery_work);
+
+static inline void __cnss_disable_irq(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	disable_irq(pdev->irq);
+}
+
+void cnss_pci_events_cb(struct msm_pcie_notify *notify)
+{
+	unsigned long flags;
+
+	if (!notify)
+		return;
+
+	switch (notify->event) {
+	case MSM_PCIE_EVENT_LINKDOWN:
+		if (pcie_link_down_panic)
+			panic("PCIe link is down\n");
+
+		spin_lock_irqsave(&pci_link_down_lock, flags);
+		if (penv->pcie_link_down_ind) {
+			pr_debug("PCI link down recovery is in progress, ignore\n");
+			spin_unlock_irqrestore(&pci_link_down_lock, flags);
+			return;
+		}
+		penv->pcie_link_down_ind = true;
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+		pr_err("PCI link down, schedule recovery\n");
+		__cnss_disable_irq(notify->user);
+		schedule_work(&cnss_pci_recovery_work);
+		break;
+
+	case MSM_PCIE_EVENT_WAKEUP:
+		if (penv->monitor_wake_intr &&
+		    atomic_read(&penv->auto_suspended)) {
+			penv->monitor_wake_intr = false;
+			pm_request_resume(&penv->pdev->dev);
+		}
+		break;
+
+	default:
+		pr_err("cnss: invalid event from PCIe callback %d\n",
+		       notify->event);
+	}
+}
+
+void cnss_wlan_pci_link_down(void)
+{
+	unsigned long flags;
+
+	if (pcie_link_down_panic)
+		panic("PCIe link is down\n");
+
+	spin_lock_irqsave(&pci_link_down_lock, flags);
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress, ignore\n");
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+		return;
+	}
+	penv->pcie_link_down_ind = true;
+	spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+	pr_err("PCI link down detected by host driver, schedule recovery\n");
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_wlan_pci_link_down);
+
+int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return cnss_msm_pcie_shadow_control(dev, enable);
+}
+EXPORT_SYMBOL(cnss_pcie_shadow_control);
+
+int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
+{
+	struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	if (!cnss_seg_info) {
+		swap_seg = NULL;
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	if (!atomic_read(&penv->fw_available)) {
+		pr_debug("%s: fw is not available\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	*swap_seg = *cnss_seg_info;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_codeswap_struct);
+
+static void cnss_wlan_memory_expansion(void)
+{
+	struct device *dev;
+	const struct firmware *fw_entry;
+	const char *filename;
+	u32 fw_entry_size, size_left, dma_size_left, length;
+	char *fw_temp;
+	char *fw_data;
+	char *dma_virt_addr;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	u32 total_length = 0;
+	struct pci_dev *pdev;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	filename = cnss_wlan_get_evicted_data_file();
+	pdev = penv->pdev;
+	dev = &pdev->dev;
+	cnss_seg_info = penv->cnss_seg_info;
+
+	if (!cnss_seg_info) {
+		pr_debug("cnss: cnss_seg_info is NULL\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (atomic_read(&penv->fw_available)) {
+		pr_debug("cnss: fw code already copied to host memory\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (request_firmware(&fw_entry, filename, dev) != 0) {
+		pr_debug("cnss: failed to get fw: %s\n", filename);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (!fw_entry || !fw_entry->data) {
+		pr_err("%s: INVALID FW entries\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto release_fw;
+	}
+
+	dma_virt_addr = (char *)penv->codeseg_cpuaddr[0];
+	fw_data = (u8 *)fw_entry->data;
+	fw_temp = fw_data;
+	fw_entry_size = fw_entry->size;
+	if (fw_entry_size > EVICT_BIN_MAX_SIZE)
+		fw_entry_size = EVICT_BIN_MAX_SIZE;
+	size_left = fw_entry_size;
+	dma_size_left = EVICT_BIN_MAX_SIZE;
+	while ((size_left && fw_temp) && (dma_size_left > 0)) {
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		length = *(int *)fw_temp;
+		if ((length > size_left || length <= 0) ||
+		    (dma_size_left <= 0 || length > dma_size_left)) {
+			pr_err("cnss: wrong length read:%d\n",
+			       length);
+			break;
+		}
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		memcpy(dma_virt_addr, fw_temp, length);
+		dma_size_left = dma_size_left - length;
+		size_left = size_left - length;
+		fw_temp = fw_temp + length;
+		dma_virt_addr = dma_virt_addr + length;
+		total_length += length;
+		pr_debug("cnss: bytes_left to copy: fw:%d; dma_page:%d\n",
+			 size_left, dma_size_left);
+	}
+	pr_debug("cnss: total_bytes copied: %d\n", total_length);
+	cnss_seg_info->codeseg_total_bytes = total_length;
+
+	atomic_set(&penv->fw_available, 1);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+release_fw:
+	release_firmware(fw_entry);
+end:
+	return;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_pci_get_wlan_mac_address(u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+
+end:
+	*num = 0;
+	return NULL;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+end:
+	*num = 0;
+	return NULL;
+}
+EXPORT_SYMBOL(cnss_get_wlan_mac_address);
+
+/**
+ * cnss_pcie_set_wlan_mac_address() - API to get two wlan mac address
+ * @in: Input buffer with wlan mac addresses
+ * @len: Size of the buffer passed
+ *
+ * API to store wlan mac address passed by the caller. The stored mac
+ * addresses are used by the wlan functional driver to program wlan HW.
+ *
+ * Return: kernel error code.
+ */
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	u32 no_of_mac_addr;
+	struct cnss_wlan_mac_addr *addr = NULL;
+	int iter = 0;
+	u8 *temp = NULL;
+
+	if (len == 0 || (len % ETH_ALEN) != 0) {
+		pr_err("%s: Invalid Length:%d\n", __func__, len);
+		return -EINVAL;
+	}
+
+	no_of_mac_addr = len / ETH_ALEN;
+
+	if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
+		pr_err("%s: Num of supported MAC  addresses are:%d given:%d\n",
+		       __func__, MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
+		return -EINVAL;
+	}
+
+	if (!penv) {
+		pr_err("%s: Invalid CNSS Platform Context\n", __func__);
+		return -ENOENT;
+	}
+
+	if (penv->is_wlan_mac_set) {
+		pr_info("%s: Already MAC address are configured\n", __func__);
+		return 0;
+	}
+
+	penv->is_wlan_mac_set = true;
+	addr = &penv->wlan_mac_addr;
+	addr->no_of_mac_addr_set = no_of_mac_addr;
+	temp = &addr->mac_addr[0][0];
+
+	for (; iter < no_of_mac_addr; ++iter, temp += ETH_ALEN, in +=
+	     ETH_ALEN) {
+		ether_addr_copy(temp, in);
+		pr_debug("%s MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+			 __func__, temp[0], temp[1], temp[2], temp[3], temp[4],
+			 temp[5]);
+	}
+	return 0;
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver)
+{
+	int ret = 0;
+	int probe_again = 0;
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return -ENODEV;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!penv->driver) {
+		penv->driver = driver;
+		wdrv = penv->driver;
+	} else {
+		pr_err("driver already registered\n");
+		return -EEXIST;
+	}
+
+again:
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("wlan vreg ON failed\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+
+	if (!pdev) {
+		pr_debug("%s: invalid pdev. register pci device\n", __func__);
+		ret = pci_register_driver(&cnss_wlan_pci_driver);
+
+		if (ret) {
+			pr_err("%s: pci registration failed\n", __func__);
+			goto err_pcie_reg;
+		}
+		pdev = penv->pdev;
+		if (!pdev) {
+			pr_err("%s: pdev is still invalid\n", __func__);
+			goto err_pcie_reg;
+		}
+	}
+
+	penv->event_reg.events = MSM_PCIE_EVENT_LINKDOWN |
+			MSM_PCIE_EVENT_WAKEUP;
+	penv->event_reg.user = pdev;
+	penv->event_reg.mode = MSM_PCIE_TRIGGER_CALLBACK;
+	penv->event_reg.callback = cnss_pci_events_cb;
+	penv->event_reg.options = MSM_PCIE_CONFIG_NO_RECOVERY;
+	ret = cnss_msm_pcie_register_event(&penv->event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	if (!penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("PCIe link bring-up failed\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+	} else if (!penv->pcie_link_state && penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("PCIe link bring-up failed (link down option)\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+
+		ret = cnss_msm_pcie_recover_config(pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (!cnss_wlan_is_codeswap_supported(penv->revision_id))
+		cnss_wlan_memory_expansion();
+
+	if (wdrv->probe) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->probe(pdev, penv->id);
+		if (ret) {
+			wcnss_prealloc_check_memory_leak();
+			wcnss_pre_alloc_reset();
+
+			if (probe_again > 3) {
+				pr_err("Failed to probe WLAN\n");
+				goto err_wlan_probe;
+			}
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+			cnss_msm_pcie_deregister_event(&penv->event_reg);
+			cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS);
+			penv->pcie_link_state = PCIE_LINK_DOWN;
+			cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+			cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+			msleep(POWER_ON_DELAY);
+			probe_again++;
+			goto again;
+		}
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return ret;
+
+err_wlan_probe:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+err_pcie_link_up:
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+	if (penv->pcie_link_state) {
+		cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+err_pcie_reg:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering PCI device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	penv->driver = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto cut_power;
+	}
+
+	if (wdrv->remove)
+		wdrv->remove(pdev);
+
+	wcnss_prealloc_check_memory_leak();
+	wcnss_pre_alloc_reset();
+
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+
+	if (penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS)) {
+			pr_err("Failed to shutdown PCIe link\n");
+			return;
+		}
+	} else if (penv->pcie_link_state && penv->pcie_link_down_ind) {
+		penv->saved_state = NULL;
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_err("Failed to shutdown PCIe link (with linkdown option)\n");
+			return;
+		}
+	}
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+	penv->driver_status = CNSS_UNINITIALIZED;
+	penv->monitor_wake_intr = false;
+	atomic_set(&penv->auto_suspended, 0);
+
+cut_power:
+	penv->driver = NULL;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("wlan vreg OFF failed\n");
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+#ifdef CONFIG_PCI_MSM
+int cnss_wlan_pm_control(bool vote)
+{
+	if (!penv || !penv->pdev)
+		return -ENODEV;
+
+	return cnss_msm_pcie_pm_control(
+		vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC,
+		cnss_get_pci_dev_bus_number(penv->pdev),
+		penv->pdev, PM_OPTIONS);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+#endif
+
+void cnss_lock_pm_sem(void)
+{
+	down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(void)
+{
+	up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+void cnss_pci_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+
+void cnss_pci_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+
+void *cnss_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	penv->recovery_in_progress = true;
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	if (!pdev) {
+		ret = -EINVAL;
+		goto cut_power;
+	}
+
+	if (wdrv && wdrv->shutdown)
+		wdrv->shutdown(pdev);
+
+	if (penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_debug("cnss: Failed to shutdown PCIe link\n");
+			ret = -EFAULT;
+		}
+		penv->saved_state = NULL;
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+cut_power:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("cnss: Failed to set WLAN VREG_OFF\n");
+
+	return ret;
+}
+
+static int cnss_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->driver)
+		goto out;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("cnss: Failed to set WLAN VREG_ON\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	/**
+	 *  Some platforms have wifi and other PCIE card attached with PCIE
+	 *  switch on the same RC like P5459 board(ROME 3.2 PCIE card + Ethernet
+	 *  PCI), it will need extra time to stable the signals when do SSR,
+	 *  otherwise fail to create the PCIE link, so add PCIE_SWITCH_DELAY.
+	 */
+	msleep(PCIE_SWITCH_DELAY);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto err_pcie_link_up;
+	}
+
+	if (!penv->pcie_link_state) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("cnss: Failed to bring-up PCIe link\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+		ret = cnss_msm_pcie_recover_config(penv->pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (wdrv && wdrv->reinit) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->reinit(pdev, penv->id);
+		if (ret) {
+			pr_err("%d: Failed to do reinit\n", __LINE__);
+			goto err_wlan_reinit;
+		}
+	} else {
+		pr_err("%d: wdrv->reinit is invalid\n", __LINE__);
+			goto err_pcie_link_up;
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+out:
+	penv->recovery_in_progress = false;
+	return ret;
+
+err_wlan_reinit:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+	cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+err_pcie_link_up:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering pci device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	return ret;
+}
+
+void cnss_pci_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+
+static int cnss_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct ramdump_segment segment;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = penv->ramdump_addr;
+	segment.size = penv->ramdump_size;
+
+	return do_ramdump(penv->ramdump_dev, &segment, 1);
+}
+
+static void cnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (pdev && wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(pdev);
+}
+
+void cnss_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+EXPORT_SYMBOL(cnss_device_self_recovery);
+
+static int cnss_modem_notifier_nb(struct notifier_block *this,
+				  unsigned long code,
+				  void *ss_handle)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	pr_debug("%s: Modem-Notify: event %lu\n", __func__, code);
+
+	if (!penv)
+		return NOTIFY_DONE;
+
+	if (code == SUBSYS_AFTER_POWERUP)
+		penv->modem_current_status = 1;
+	else if (code == SUBSYS_BEFORE_SHUTDOWN)
+		penv->modem_current_status = 0;
+	else
+		return NOTIFY_DONE;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (!wdrv || !pdev || !wdrv->modem_status)
+		return NOTIFY_DONE;
+
+	wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = cnss_modem_notifier_nb,
+};
+
+static int cnss_init_dump_entry(void)
+{
+	struct msm_dump_entry dump_entry;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_dynamic)
+		return 0;
+
+	penv->dump_data.addr = penv->ramdump_phys;
+	penv->dump_data.len = penv->ramdump_size;
+	penv->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(penv->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(penv->dump_data.name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&penv->dump_data);
+
+	return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct esoc_desc *desc;
+	const char *client_desc;
+	struct device *dev = &pdev->dev;
+	u32 rc_num;
+	struct resource *res;
+	u32 ramdump_size = 0;
+	u32 smmu_iova_address[2];
+
+	if (penv)
+		return -ENODEV;
+
+	penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL);
+	if (!penv)
+		return -ENOMEM;
+
+	penv->pldev = pdev;
+	penv->esoc_desc = NULL;
+
+	penv->gpio_info.name = WLAN_EN_GPIO_NAME;
+	penv->gpio_info.num = 0;
+	penv->gpio_info.state = WLAN_EN_LOW;
+	penv->gpio_info.init = WLAN_EN_LOW;
+	penv->gpio_info.prop = false;
+	penv->vreg_info.wlan_reg = NULL;
+	penv->vreg_info.state = VREG_OFF;
+	penv->pci_register_again = false;
+	mutex_init(&penv->fw_setup_stat_lock);
+
+	ret = cnss_wlan_get_resources(pdev);
+	if (ret)
+		goto err_get_wlan_res;
+
+	ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	if (ret) {
+		pr_err("%s: Failed to enable WLAN enable gpio\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+	if (ret) {
+		pr_err("%s: Failed to find PCIe RC number\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = cnss_msm_pcie_enumerate(rc_num);
+	if (ret) {
+		pr_err("%s: Failed to enable PCIe RC%x\n", __func__, rc_num);
+		goto err_pcie_enumerate;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	penv->notify_modem_status =
+		of_property_read_bool(dev->of_node,
+				      "qcom,notify-modem-status");
+
+	if (penv->notify_modem_status) {
+		ret = of_property_read_string_index(dev->of_node, "esoc-names",
+						    0, &client_desc);
+		if (ret) {
+			pr_debug("%s: esoc-names is not defined in DT, SKIP\n",
+				 __func__);
+		} else {
+			desc = devm_register_esoc_client(dev, client_desc);
+			if (IS_ERR_OR_NULL(desc)) {
+				ret = PTR_RET(desc);
+				pr_err("%s: can't find esoc desc\n", __func__);
+				goto err_esoc_reg;
+			}
+			penv->esoc_desc = desc;
+		}
+	}
+
+	penv->subsysdesc.name = "AR6320";
+	penv->subsysdesc.owner = THIS_MODULE;
+	penv->subsysdesc.shutdown = cnss_shutdown;
+	penv->subsysdesc.powerup = cnss_powerup;
+	penv->subsysdesc.ramdump = cnss_ramdump;
+	penv->subsysdesc.crash_shutdown = cnss_crash_shutdown;
+	penv->subsysdesc.dev = &pdev->dev;
+	penv->subsys = subsys_register(&penv->subsysdesc);
+	if (IS_ERR(penv->subsys)) {
+		ret = PTR_ERR(penv->subsys);
+		goto err_subsys_reg;
+	}
+
+	penv->subsys_handle = subsystem_get(penv->subsysdesc.name);
+
+	if (of_property_read_bool(dev->of_node, "qcom,is-dual-wifi-enabled"))
+		penv->dual_wifi_info.is_dual_wifi_enabled = true;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		penv->ramdump_addr = dma_alloc_coherent(&pdev->dev,
+				ramdump_size, &penv->ramdump_phys, GFP_KERNEL);
+
+		if (penv->ramdump_addr)
+			penv->ramdump_size = ramdump_size;
+		penv->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(penv->pldev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			penv->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			penv->ramdump_addr = ioremap(penv->ramdump_phys,
+					ramdump_size);
+
+			if (penv->ramdump_addr)
+				penv->ramdump_size = ramdump_size;
+
+			penv->ramdump_dynamic = false;
+		}
+	}
+
+	pr_debug("%s: ramdump addr: %p, phys: %pa\n", __func__,
+		 penv->ramdump_addr, &penv->ramdump_phys);
+
+	if (penv->ramdump_size == 0) {
+		pr_info("%s: CNSS ramdump will not be collected\n", __func__);
+		goto skip_ramdump;
+	}
+
+	ret = cnss_init_dump_entry();
+	if (ret) {
+		pr_err("%s: Dump table setup failed: %d\n", __func__, ret);
+		goto err_ramdump_create;
+	}
+
+	penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name,
+				penv->subsysdesc.dev);
+	if (!penv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump_create;
+	}
+
+skip_ramdump:
+	penv->modem_current_status = 0;
+
+	if (penv->notify_modem_status) {
+		penv->modem_notify_handler =
+			subsys_notif_register_notifier(penv->esoc_desc ?
+						       penv->esoc_desc->name :
+						       "modem", &mnb);
+		if (IS_ERR(penv->modem_notify_handler)) {
+			ret = PTR_ERR(penv->modem_notify_handler);
+			pr_err("%s: Register notifier Failed\n", __func__);
+			goto err_notif_modem;
+		}
+	}
+
+	if (of_property_read_u32_array(dev->of_node,
+				       "qcom,wlan-smmu-iova-address",
+				       smmu_iova_address, 2) == 0) {
+		penv->smmu_iova_start = smmu_iova_address[0];
+		penv->smmu_iova_len = smmu_iova_address[1];
+	}
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret)
+		goto err_pci_reg;
+
+	penv->bus_scale_table = 0;
+	penv->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+
+	if (penv->bus_scale_table)  {
+		penv->bus_client =
+			msm_bus_scale_register_client(penv->bus_scale_table);
+
+		if (!penv->bus_client) {
+			pr_err("Failed to register with bus_scale client\n");
+			goto err_bus_reg;
+		}
+	}
+	cnss_pm_wake_lock_init(&penv->ws, "cnss_wlock");
+
+	register_pm_notifier(&cnss_pm_notifier);
+
+#ifdef CONFIG_CNSS_MAC_BUG
+	/* 0-4K memory is reserved for QCA6174 to address a MAC HW bug.
+	 * MAC would do an invalid pointer fetch based on the data
+	 * that was read from 0 to 4K. So fill it with zero's (to an
+	 * address for which PCIe RC honored the read without any errors).
+	 */
+	memset(phys_to_virt(0), 0, SZ_4K);
+#endif
+
+	ret = device_create_file(dev, &dev_attr_fw_image_setup);
+	if (ret) {
+		pr_err("cnss: fw_image_setup sys file creation failed\n");
+		goto err_bus_reg;
+	}
+	pr_debug("cnss: Platform driver probed successfully.\n");
+	return ret;
+
+err_bus_reg:
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+	pci_unregister_driver(&cnss_wlan_pci_driver);
+
+err_pci_reg:
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier
+			(penv->modem_notify_handler, &mnb);
+
+err_notif_modem:
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+
+err_ramdump_create:
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	if (penv->subsys_handle)
+		subsystem_put(penv->subsys_handle);
+
+	subsys_unregister(penv->subsys);
+
+err_subsys_reg:
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+
+err_esoc_reg:
+err_pcie_enumerate:
+err_get_rc:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_release_resources();
+
+err_get_wlan_res:
+	penv = NULL;
+
+	return ret;
+}
+
+static int cnss_remove(struct platform_device *pdev)
+{
+	unregister_pm_notifier(&cnss_pm_notifier);
+	device_remove_file(&pdev->dev, &dev_attr_fw_image_setup);
+
+	cnss_pm_wake_lock_destroy(&penv->ws);
+
+	if (penv->bus_client)
+		msm_bus_scale_unregister_client(penv->bus_client);
+
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+	cnss_wlan_release_resources();
+
+	return 0;
+}
+
+static const struct of_device_id cnss_dt_match[] = {
+	{.compatible = "qcom,cnss"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cnss_dt_match);
+
+static struct platform_driver cnss_driver = {
+	.probe  = cnss_probe,
+	.remove = cnss_remove,
+	.driver = {
+		.name = "cnss",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_dt_match,
+#ifdef CONFIG_CNSS_ASYNC
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+	},
+};
+
+static int __init cnss_initialize(void)
+{
+	return platform_driver_register(&cnss_driver);
+}
+
+static void __exit cnss_exit(void)
+{
+	struct platform_device *pdev = penv->pldev;
+
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier(penv->modem_notify_handler,
+						 &mnb);
+	subsys_unregister(penv->subsys);
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+	platform_driver_unregister(&cnss_driver);
+}
+
+void cnss_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos_type);
+
+void cnss_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos_type);
+
+void cnss_pci_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos);
+
+void cnss_pci_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_pci_remove_pm_qos);
+
+int cnss_pci_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+int cnss_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct cnss_platform_cap *cap)
+{
+	if (!penv)
+		return -ENODEV;
+
+	if (cap)
+		*cap = penv->cap;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+void cnss_set_driver_status(enum cnss_driver_status driver_status)
+{
+	penv->driver_status = driver_status;
+}
+EXPORT_SYMBOL(cnss_set_driver_status);
+
+int cnss_get_bmi_setup(void)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return penv->bmi_test;
+}
+EXPORT_SYMBOL(cnss_get_bmi_setup);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out)
+{
+	struct scatterlist sg;
+	struct hash_desc desc;
+	int ret = 0;
+
+	if (!out) {
+		pr_err("memory for output buffer is not allocated\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	desc.tfm   = crypto_alloc_hash(hash_idx, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		pr_err("crypto_alloc_hash failed:%ld\n", PTR_ERR(desc.tfm));
+		ret = PTR_ERR(desc.tfm);
+		goto end;
+	}
+
+	sg_init_one(&sg, data, data_len);
+	ret = crypto_hash_digest(&desc, &sg, sg.length, out);
+	crypto_free_hash(desc.tfm);
+end:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_get_sha_hash);
+
+void *cnss_get_fw_ptr(void)
+{
+	if (!penv)
+		return NULL;
+
+	return penv->fw_mem;
+}
+EXPORT_SYMBOL(cnss_get_fw_ptr);
+#endif
+
+int cnss_auto_suspend(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+		pci_disable_device(pdev);
+		ret = pci_set_power_state(pdev, PCI_D3hot);
+		if (ret)
+			pr_err("%s: Set D3Hot failed: %d\n", __func__, ret);
+		if (cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to shutdown PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+	atomic_set(&penv->auto_suspended, 1);
+	penv->monitor_wake_intr = true;
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    CNSS_BUS_WIDTH_NONE);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+	if (!penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to resume PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+		ret = pci_enable_device(pdev);
+		if (ret)
+			pr_err("%s: enable device failed: %d\n", __func__, ret);
+		penv->pcie_link_state = PCIE_LINK_UP;
+	}
+
+	if (penv->saved_state)
+		cnss_pci_load_and_free_saved_state(pdev, &penv->saved_state);
+
+	pci_restore_state(pdev);
+	pci_set_master(pdev);
+
+	atomic_set(&penv->auto_suspended, 0);
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    penv->current_bandwidth_vote);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_runtime_request(struct device *dev,
+			    enum cnss_runtime_request request)
+{
+	int ret = 0;
+
+	switch (request) {
+	case CNSS_PM_RUNTIME_GET:
+		ret = pm_runtime_get(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT:
+		ret = pm_runtime_put(dev);
+		break;
+	case CNSS_PM_RUNTIME_MARK_LAST_BUSY:
+		pm_runtime_mark_last_busy(dev);
+		break;
+	case CNSS_PM_RUNTIME_RESUME:
+		ret = pm_runtime_resume(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_AUTO:
+		ret = pm_runtime_put_autosuspend(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_NOIDLE:
+		pm_runtime_put_noidle(dev);
+		break;
+	case CNSS_PM_REQUEST_RESUME:
+		ret = pm_request_resume(dev);
+		break;
+	case CNSS_PM_GET_NORESUME:
+		pm_runtime_get_noresume(dev);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_pm_runtime_request);
+
+void cnss_runtime_init(struct device *dev, int auto_delay)
+{
+	pm_runtime_set_autosuspend_delay(dev, auto_delay);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_allow(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_noidle(dev);
+	pm_suspend_ignore_children(dev, true);
+}
+EXPORT_SYMBOL(cnss_runtime_init);
+
+void cnss_runtime_exit(struct device *dev)
+{
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+}
+EXPORT_SYMBOL(cnss_runtime_exit);
+
+static void __cnss_set_pcie_monitor_intr(struct device *dev, bool val)
+{
+	penv->monitor_wake_intr = val;
+}
+
+static void __cnss_set_auto_suspend(struct device *dev, int val)
+{
+	atomic_set(&penv->auto_suspended, val);
+}
+
+static int __cnss_resume_link(struct device *dev, u32 flags)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_RESUME, bus_num, pdev, flags);
+	if (ret)
+		pr_err("%s: PCIe link resume failed with flags:%d bus_num:%d\n",
+		       __func__, flags, bus_num);
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	return ret;
+}
+
+static int __cnss_suspend_link(struct device *dev, u32 flags)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+	int ret;
+
+	if (!penv->pcie_link_state)
+		return 0;
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus_num, pdev, flags);
+	if (ret) {
+		pr_err("%s: Failed to suspend link\n", __func__);
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return ret;
+}
+
+static int __cnss_pcie_recover_config(struct device *dev)
+{
+	int ret;
+
+	ret = cnss_msm_pcie_recover_config(to_pci_dev(dev));
+	if (ret)
+		pr_err("%s: PCIe Recover config failed\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_event_reg(struct device *dev)
+{
+	int ret;
+	struct msm_pcie_register_event *event_reg;
+
+	event_reg = &penv->event_reg;
+
+	event_reg->events = MSM_PCIE_EVENT_LINKDOWN |
+		MSM_PCIE_EVENT_WAKEUP;
+	event_reg->user = to_pci_dev(dev);
+	event_reg->mode = MSM_PCIE_TRIGGER_CALLBACK;
+	event_reg->callback = cnss_pci_events_cb;
+	event_reg->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+	ret = cnss_msm_pcie_register_event(event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	return ret;
+}
+
+static void __cnss_event_dereg(struct device *dev)
+{
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+}
+
+static struct pci_dev *__cnss_get_pcie_dev(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = penv->pdev;
+
+	if (pdev)
+		return pdev;
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret) {
+		pr_err("%s: pci re-registration failed\n", __func__);
+		return NULL;
+	}
+
+	pdev = penv->pdev;
+
+	return pdev;
+}
+
+static int __cnss_pcie_power_up(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("%s: WLAN VREG ON Failed\n", __func__);
+		return ret;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	return 0;
+}
+
+static int __cnss_pcie_power_down(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (ret)
+		pr_err("%s: Failed to turn off 3.3V regulator\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_suspend_link_state(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int link_ind;
+
+	if (!penv->pcie_link_state) {
+		pr_debug("%s: Link is already suspended\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	if (!link_ind)
+		pci_save_state(pdev);
+
+	penv->saved_state = link_ind ? NULL : cnss_pci_store_saved_state(pdev);
+
+	ret = link_ind ? __cnss_suspend_link(dev, PM_OPTIONS_SUSPEND_LINK_DOWN)
+		: __cnss_suspend_link(dev, PM_OPTIONS);
+	if (ret) {
+		pr_err("%s: Link Suspend failed in state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return 0;
+}
+
+static int __cnss_restore_pci_config_space(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int ret = 0;
+
+	if (penv->saved_state)
+		ret = cnss_pci_load_and_free_saved_state(pdev,
+							 &penv->saved_state);
+	pci_restore_state(pdev);
+
+	return ret;
+}
+
+static int __cnss_resume_link_state(struct device *dev)
+{
+	int ret;
+	int link_ind;
+
+	if (penv->pcie_link_state) {
+		pr_debug("%s: Link is already in active state\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	ret = link_ind ? __cnss_resume_link(dev, PM_OPTIONS_RESUME_LINK_DOWN) :
+		__cnss_resume_link(dev, PM_OPTIONS);
+
+	if (ret) {
+		pr_err("%s: Resume Link failed in link state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	ret = link_ind ?  __cnss_pcie_recover_config(dev) :
+		__cnss_restore_pci_config_space(dev);
+
+	if (ret) {
+		pr_err("%s: Link Recovery Config Failed link_state:%s\n",
+		       __func__, link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+		return ret;
+	}
+
+	penv->pcie_link_down_ind  = false;
+	return ret;
+}
+
+int cnss_pcie_power_up(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev;
+
+	if (!penv) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = __cnss_pcie_power_up(dev);
+	if (ret) {
+		pr_err("%s: Power UP Failed\n", __func__);
+		return ret;
+	}
+
+	pdev = __cnss_get_pcie_dev(dev);
+	if (!pdev) {
+		pr_err("%s: PCIe Dev is NULL\n", __func__);
+		goto power_down;
+	}
+
+	ret = __cnss_event_reg(dev);
+
+	if (ret)
+		pr_err("%s: PCIe event registration failed\n", __func__);
+
+	ret = __cnss_resume_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Link Bring Up Failed\n", __func__);
+		goto event_dereg;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, true);
+
+	return ret;
+
+event_dereg:
+	__cnss_event_dereg(dev);
+power_down:
+	__cnss_pcie_power_down(dev);
+	pr_err("%s: Device Power Up Failed Fatal Error\n", __func__);
+	return ret;
+}
+
+static void __cnss_vote_bus_width(struct device *dev, u32 option)
+{
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client, option);
+}
+
+int cnss_pcie_power_down(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform data\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!pdev) {
+		pr_err("%s: Invalid Pdev, Cut Power to device\n", __func__);
+		__cnss_pcie_power_down(dev);
+		return -ENODEV;
+	}
+
+	__cnss_vote_bus_width(dev, CNSS_BUS_WIDTH_NONE);
+	__cnss_event_dereg(dev);
+
+	ret = __cnss_suspend_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Suspend Link failed\n", __func__);
+		return ret;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, false);
+	__cnss_set_auto_suspend(dev, 0);
+
+	ret = __cnss_pcie_power_down(dev);
+	if (ret)
+		pr_err("%s: Power Down Failed\n", __func__);
+
+	return ret;
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS Driver");
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
new file mode 100644
index 0000000..c35ba38
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -0,0 +1,1564 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "cnss_sdio:%s:%d:: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <linux/pm_qos.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_DSRC_NAME	"vdd-wlan-dsrc"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_GPIO_CAPTSF_NAME	"qcom,cap-tsf-gpio"
+
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define POWER_ON_DELAY		4
+
+/* Values for Dynamic Ramdump Collection*/
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN_SDIO"
+#define CNSS_PINCTRL_SLEEP_STATE	"sleep"
+#define CNSS_PINCTRL_ACTIVE_STATE	"active"
+
+#define CNSS_HW_SLEEP 0
+#define CNSS_HW_ACTIVE 1
+
+struct cnss_sdio_regulator {
+	struct regulator *wlan_io;
+	struct regulator *wlan_xtal;
+	struct regulator *wlan_vreg;
+	struct regulator *wlan_vreg_dsrc;
+};
+
+struct cnss_sdio_info {
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct sdio_func *func;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	struct device *dev;
+	const struct sdio_device_id *id;
+	bool skip_wlan_en_toggle;
+	bool cnss_hw_state;
+	struct cnss_cap_tsf_info cap_tsf_info;
+};
+
+struct cnss_ssr_info {
+	struct subsys_device *subsys;
+	struct subsys_desc subsysdesc;
+	void *subsys_handle;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	bool ramdump_dynamic;
+	char subsys_name[10];
+};
+
+struct cnss_wlan_pinctrl_info {
+	bool is_antenna_shared;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *sleep;
+	struct pinctrl_state *active;
+};
+
+struct cnss_sdio_bus_bandwidth {
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+};
+
+static struct cnss_sdio_data {
+	struct cnss_sdio_regulator regulator;
+	struct platform_device *pdev;
+	struct cnss_sdio_info cnss_sdio_info;
+	struct cnss_ssr_info ssr_info;
+	struct pm_qos_request qos_request;
+	struct cnss_wlan_pinctrl_info pinctrl_info;
+	struct cnss_sdio_bus_bandwidth bus_bandwidth;
+	struct cnss_dev_platform_ops platform_ops;
+} *cnss_pdata;
+
+#define WLAN_RECOVERY_DELAY 1
+/* cnss sdio subsytem device name, required property */
+#define CNSS_SUBSYS_NAME_KEY "subsys-name"
+
+/* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_AR6320_BASE        0x500
+#define MANUFACTURER_ID_QCA9377_BASE       0x700
+#define MANUFACTURER_CODE                  0x271
+
+static const struct sdio_device_id ar6k_id_table[] = {
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))},
+	{},
+};
+MODULE_DEVICE_TABLE(sdio, ar6k_id_table);
+
+void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(&cnss_pdata->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos_type);
+
+int cnss_sdio_request_bus_bandwidth(int bandwidth)
+{
+	int ret;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (!bus_bandwidth->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, bandwidth);
+		if (!ret) {
+			bus_bandwidth->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_debug(
+			"could not set bus bandwidth %d, ret = %d\n",
+			 bandwidth, ret);
+		}
+		break;
+	default:
+		pr_debug("Invalid request %d\n", bandwidth);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void cnss_sdio_request_pm_qos(u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(
+		&cnss_pdata->qos_request,
+		PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos);
+
+void cnss_sdio_remove_pm_qos(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	pm_qos_remove_request(&cnss_pdata->qos_request);
+	pr_debug("PM QoS removed\n");
+}
+EXPORT_SYMBOL(cnss_sdio_remove_pm_qos);
+
+static int cnss_put_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct cnss_sdio_info *info;
+	struct mmc_host *host;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_SLEEP) {
+		pr_debug("HW resources are already released\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC host is invalid\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = mmc_power_save_host(host);
+	if (ret) {
+		pr_err("Failed to Power Save Host err:%d\n",
+		       ret);
+		return ret;
+	}
+
+	regulator_disable(cnss_pdata->regulator.wlan_vreg);
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+
+	return ret;
+}
+
+static int cnss_get_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct mmc_host *host;
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_ACTIVE) {
+		pr_debug("HW resources are already active\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC Host is Invalid; Enumeration Failed\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+	if (ret) {
+		pr_err("Failed to enable wlan vreg\n");
+		return ret;
+	}
+
+	ret = mmc_power_restore_host(host);
+	if (ret) {
+		pr_err("Failed to restore host power ret:%d\n",
+		       ret);
+		regulator_disable(cnss_pdata->regulator.wlan_vreg);
+		return ret;
+	}
+
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+	return ret;
+}
+
+static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (!wdrv)
+		return 0;
+	if (!wdrv->shutdown)
+		return 0;
+
+	wdrv->shutdown(cnss_info->func);
+	ret = cnss_put_hw_resources(cnss_info->dev);
+
+	if (ret)
+		pr_err("Failed to put hw resources\n");
+
+	return ret;
+}
+
+static int cnss_sdio_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+
+	if (!wdrv)
+		return 0;
+
+	if (!wdrv->reinit)
+		return 0;
+
+	ret = cnss_get_hw_resources(cnss_info->dev);
+	if (ret) {
+		pr_err("Failed to power up HW\n");
+		return ret;
+	}
+
+	ret = wdrv->reinit(cnss_info->func, cnss_info->id);
+	if (ret)
+		pr_err("wlan reinit error=%d\n", ret);
+
+	return ret;
+}
+
+static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+
+	if (!cnss_pdata)
+		return;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(cnss_info->func);
+}
+
+static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct ramdump_segment segment;
+	int ret;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	if (!cnss_pdata->ssr_info.ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = ssr_info->ramdump_addr;
+	segment.size = ssr_info->ramdump_size;
+	ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1);
+	if (ret)
+		pr_err("do_ramdump failed error=%d\n", ret);
+	return ret;
+}
+
+static int cnss_subsys_init(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	ssr_info->subsysdesc.name = ssr_info->subsys_name;
+	ssr_info->subsysdesc.owner = THIS_MODULE;
+	ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown;
+	ssr_info->subsysdesc.powerup = cnss_sdio_powerup;
+	ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump;
+	ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown;
+	ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev;
+	ssr_info->subsys = subsys_register(&ssr_info->subsysdesc);
+	if (IS_ERR(ssr_info->subsys)) {
+		ret = PTR_ERR(ssr_info->subsys);
+		ssr_info->subsys = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n",
+			ret);
+		goto err_subsys_reg;
+	}
+	ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name);
+	if (IS_ERR(ssr_info->subsys_handle)) {
+		ret = PTR_ERR(ssr_info->subsys_handle);
+		ssr_info->subsys_handle = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n",
+			ret);
+		goto err_subsys_get;
+	}
+	return 0;
+err_subsys_get:
+	subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+err_subsys_reg:
+	return ret;
+}
+
+static void cnss_subsys_exit(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys_handle)
+		subsystem_put(ssr_info->subsys_handle);
+	ssr_info->subsys_handle = NULL;
+	if (ssr_info->subsys)
+		subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+}
+
+static int cnss_configure_dump_table(struct cnss_ssr_info *ssr_info)
+{
+	struct msm_dump_entry dump_entry;
+	int ret;
+
+	ssr_info->dump_data.addr = ssr_info->ramdump_phys;
+	ssr_info->dump_data.len = ssr_info->ramdump_size;
+	ssr_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	ssr_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(ssr_info->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(ssr_info->dump_data.name));
+
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&ssr_info->dump_data);
+
+	ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+	if (ret)
+		pr_err("Dump table setup failed: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_configure_ramdump(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+	struct resource *res;
+	const char *name;
+	u32 ramdump_size = 0;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	dev = &cnss_pdata->pdev->dev;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	ret = of_property_read_string(dev->of_node, CNSS_SUBSYS_NAME_KEY,
+				      &name);
+	if (ret) {
+		pr_err("cnss missing DT key '%s'\n",
+		       CNSS_SUBSYS_NAME_KEY);
+		ret = -ENODEV;
+		goto err_subsys_name_query;
+	}
+
+	strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name));
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		ssr_info->ramdump_addr = dma_alloc_coherent(dev, ramdump_size,
+							&ssr_info->ramdump_phys,
+							GFP_KERNEL);
+		if (ssr_info->ramdump_addr)
+			ssr_info->ramdump_size = ramdump_size;
+		ssr_info->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(cnss_pdata->pdev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			ssr_info->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys,
+								ramdump_size);
+			if (ssr_info->ramdump_addr)
+				ssr_info->ramdump_size = ramdump_size;
+			ssr_info->ramdump_dynamic = false;
+		}
+	}
+
+	pr_info("ramdump addr: %p, phys: %pa subsys:'%s'\n",
+		ssr_info->ramdump_addr, &ssr_info->ramdump_phys,
+		ssr_info->subsys_name);
+
+	if (ssr_info->ramdump_size == 0) {
+		pr_info("CNSS ramdump will not be collected\n");
+		return 0;
+	}
+
+	if (ssr_info->ramdump_dynamic) {
+		ret = cnss_configure_dump_table(ssr_info);
+		if (ret)
+			goto err_configure_dump_table;
+	}
+
+	ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name,
+									dev);
+	if (!ssr_info->ramdump_dev) {
+		ret = -ENOMEM;
+		pr_err("ramdump dev create failed: error=%d\n",
+		       ret);
+		goto err_configure_dump_table;
+	}
+
+	return 0;
+
+err_configure_dump_table:
+	if (ssr_info->ramdump_dynamic)
+		dma_free_coherent(dev, ssr_info->ramdump_size,
+				  ssr_info->ramdump_addr,
+				  ssr_info->ramdump_phys);
+	else
+		iounmap(ssr_info->ramdump_addr);
+
+	ssr_info->ramdump_addr = NULL;
+	ssr_info->ramdump_size = 0;
+err_subsys_name_query:
+	return ret;
+}
+
+static void cnss_ramdump_cleanup(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return;
+
+	dev = &cnss_pdata->pdev->dev;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->ramdump_addr) {
+		if (ssr_info->ramdump_dynamic)
+			dma_free_coherent(dev, ssr_info->ramdump_size,
+					  ssr_info->ramdump_addr,
+					  ssr_info->ramdump_phys);
+		else
+			iounmap(ssr_info->ramdump_addr);
+	}
+
+	ssr_info->ramdump_addr = NULL;
+	if (ssr_info->ramdump_dev)
+		destroy_ramdump_device(ssr_info->ramdump_dev);
+	ssr_info->ramdump_dev = NULL;
+}
+
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!cnss_pdata || !cnss_pdata->pdev)
+		return NULL;
+
+	*size = cnss_pdata->ssr_info.ramdump_size;
+
+	return cnss_pdata->ssr_info.ramdump_addr;
+}
+
+void cnss_sdio_device_self_recovery(void)
+{
+	cnss_sdio_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_sdio_powerup(NULL);
+}
+
+void cnss_sdio_device_crashed(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys) {
+		subsys_set_crash_status(ssr_info->subsys, true);
+		subsystem_restart_dev(ssr_info->subsys);
+	}
+}
+
+static void cnss_sdio_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_sdio_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_sdio_recovery_work, cnss_sdio_recovery_work_handler);
+
+void cnss_sdio_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_sdio_recovery_work);
+}
+
+/**
+ * cnss_get_restart_level() - cnss get restart level API
+ *
+ * Wlan sdio function driver uses this API to get the current
+ * subsystem restart level.
+ *
+ * Return: CNSS_RESET_SOC - "SYSTEM", restart system
+ *         CNSS_RESET_SUBSYS_COUPLED - "RELATED",restart subsystem
+ */
+int cnss_get_restart_level(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int level;
+
+	if (!cnss_pdata)
+		return CNSS_RESET_SOC;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (!ssr_info->subsys)
+		return CNSS_RESET_SOC;
+	level = subsys_get_restart_level(ssr_info->subsys);
+	switch (level) {
+	case RESET_SOC:
+		return CNSS_RESET_SOC;
+	case RESET_SUBSYS_COUPLED:
+		return CNSS_RESET_SUBSYS_COUPLED;
+	default:
+		return CNSS_RESET_SOC;
+	}
+}
+EXPORT_SYMBOL(cnss_get_restart_level);
+
+static inline int cnss_get_tsf_cap_irq(struct device *dev)
+{
+	int irq = -EINVAL;
+	int gpio;
+
+	if (!dev)
+		return -ENODEV;
+
+	gpio = of_get_named_gpio(dev->of_node, WLAN_GPIO_CAPTSF_NAME, 0);
+	if (gpio >= 0)
+		irq = gpio_to_irq(gpio);
+
+	return irq;
+}
+
+static int cnss_sdio_register_tsf_captured_handler(irq_handler_t handler,
+						   void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	tsf_info->irq_handler = handler;
+	tsf_info->context = ctx;
+	return 0;
+}
+
+static int cnss_sdio_unregister_tsf_captured_handler(void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	if (ctx == tsf_info->context) {
+		tsf_info->irq_handler = NULL;
+		tsf_info->context = NULL;
+	}
+	return 0;
+}
+
+static irqreturn_t cnss_sdio_tsf_captured_handler(int irq, void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return IRQ_HANDLED;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0 || tsf_info->irq_num != irq ||
+	    !tsf_info->irq_handler || !tsf_info->context)
+		return IRQ_HANDLED;
+
+	return tsf_info->irq_handler(irq, tsf_info->context);
+}
+
+static void cnss_sdio_tsf_init(struct device *dev,
+			       struct cnss_cap_tsf_info *tsf_info)
+{
+	int ret, irq;
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+
+	irq = cnss_get_tsf_cap_irq(dev);
+	if (irq < 0) {
+		dev_err(dev, "%s: fail to get irq: %d\n", __func__, irq);
+		return;
+	}
+
+	ret = request_irq(irq, cnss_sdio_tsf_captured_handler,
+			  IRQF_SHARED | IRQF_TRIGGER_RISING, dev_name(dev),
+			  (void *)tsf_info);
+	dev_err(dev, "%s: request irq[%d] for dev: %s, result: %d\n",
+		__func__, irq, dev_name(dev), ret);
+	if (!ret)
+		tsf_info->irq_num = irq;
+}
+
+static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info)
+{
+	int irq = tsf_info->irq_num;
+
+	if (irq < 0)
+		return;
+
+	free_irq(irq, (void *)tsf_info);
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+}
+
+static void cnss_sdio_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+
+	pf_ops->power_up = cnss_sdio_power_up;
+	pf_ops->power_down = cnss_sdio_power_down;
+	pf_ops->device_crashed = cnss_sdio_device_crashed;
+	pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_sdio_device_self_recovery;
+	pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address;
+	pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work;
+	pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth;
+	pf_ops->register_tsf_captured_handler =
+		cnss_sdio_register_tsf_captured_handler;
+	pf_ops->unregister_tsf_captured_handler =
+		cnss_sdio_unregister_tsf_captured_handler;
+	dev->platform_data = pf_ops;
+}
+
+static int cnss_sdio_wlan_inserted(struct sdio_func *func,
+				   const struct sdio_device_id *id)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->func = func;
+	info->card = func->card;
+	info->host = func->card->host;
+	info->id = id;
+	info->dev = &func->dev;
+	cnss_sdio_set_platform_ops(info->dev);
+
+	cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev);
+
+	pr_info("SDIO Device is Probed\n");
+	return 0;
+}
+
+static void cnss_sdio_wlan_removed(struct sdio_func *func)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->host = NULL;
+	info->card = NULL;
+	info->func = NULL;
+	info->id = NULL;
+}
+
+#if defined(CONFIG_PM)
+static int cnss_sdio_wlan_suspend(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct sdio_func *func;
+
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	func = cnss_pdata->cnss_sdio_info.func;
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->suspend) {
+		error = wdrv->suspend(dev);
+		if (error)
+			pr_err("wlan suspend failed error=%d\n", error);
+	}
+
+	return error;
+}
+
+static int cnss_sdio_wlan_resume(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client,
+			bus_bandwidth->current_bandwidth_vote);
+	}
+
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->resume) {
+		error = wdrv->resume(dev);
+		if (error)
+			pr_err("wlan resume failed error=%d\n", error);
+	}
+	return error;
+}
+#endif
+
+#if defined(CONFIG_PM)
+static const struct dev_pm_ops cnss_ar6k_device_pm_ops = {
+	.suspend = cnss_sdio_wlan_suspend,
+	.resume = cnss_sdio_wlan_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct sdio_driver cnss_ar6k_driver = {
+	.name = "cnss_ar6k_wlan",
+	.id_table = ar6k_id_table,
+	.probe = cnss_sdio_wlan_inserted,
+	.remove = cnss_sdio_wlan_removed,
+#if defined(CONFIG_PM)
+	.drv = {
+		.pm = &cnss_ar6k_device_pm_ops,
+	}
+#endif
+};
+
+static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state)
+{
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!info->is_antenna_shared)
+		return 0;
+
+	if (!info->pinctrl)
+		return -EIO;
+
+	return state ? pinctrl_select_state(info->pinctrl, info->active) :
+		pinctrl_select_state(info->pinctrl, info->sleep);
+}
+
+int cnss_sdio_configure_spdt(bool state)
+{
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	return cnss_set_pinctrl_state(cnss_pdata, state);
+}
+EXPORT_SYMBOL(cnss_sdio_configure_spdt);
+
+/**
+ * cnss_sdio_wlan_register_driver() - cnss wlan register API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to register callback
+ * functions to cnss_sido platform driver. The callback will
+ * be invoked by corresponding wrapper function of this cnss
+ * platform driver.
+ */
+int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct device *dev;
+	int error = -EINVAL;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	dev = cnss_info->dev;
+
+	if (cnss_info->wdrv) {
+		pr_debug("wdrv already existed\n");
+		return error;
+	}
+
+	if (!driver)
+		return error;
+
+	error = cnss_get_hw_resources(dev);
+	if (error) {
+		pr_err("Failed to restore power err:%d\n", error);
+		return error;
+	}
+
+	error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE);
+	if (error) {
+		pr_err("Fail to set pinctrl to active state\n");
+		cnss_put_hw_resources(dev);
+		goto put_hw;
+	}
+
+	/* The HW resources are released in unregister logic if probe fails */
+	error = driver->probe ? driver->probe(cnss_info->func,
+					      cnss_info->id) : error;
+	if (error) {
+		pr_err("wlan probe failed error=%d\n", error);
+		/**
+		 * Check memory leak in skb pre-alloc memory pool
+		 * Reset the skb memory pool
+		 */
+		goto pinctrl_sleep;
+	}
+
+	cnss_info->wdrv = driver;
+
+	return error;
+
+pinctrl_sleep:
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+put_hw:
+	return error;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);
+
+/**
+ * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to detach it from cnss_sido
+ * platform driver.
+ */
+void
+cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	if (!cnss_info->wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (!driver)
+		return;
+
+	if (!driver->remove)
+		return;
+
+	driver->remove(cnss_info->func);
+
+	cnss_info->wdrv = NULL;
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+	cnss_put_hw_resources(cnss_info->dev);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);
+
+/**
+ * cnss_wlan_query_oob_status() - cnss wlan query oob status API
+ *
+ * Wlan sdio function driver uses this API to check whether oob is
+ * supported in platform driver.
+ *
+ * Return: 0 means oob is supported, others means unsupported.
+ */
+int cnss_wlan_query_oob_status(void)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_query_oob_status);
+
+/**
+ * cnss_wlan_register_oob_irq_handler() - cnss wlan register oob callback API
+ * @handler: oob callback function pointer which registered to platform driver.
+ * @pm_oob : parameter which registered to platform driver.
+ *
+ * Wlan sdio function driver uses this API to register oob callback
+ * function to platform driver.
+ *
+ * Return: 0 means register successfully, others means failure.
+ */
+int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_register_oob_irq_handler);
+
+/**
+ * cnss_wlan_unregister_oob_irq_handler() - unregister oob callback API
+ * @pm_oob: parameter which unregistered from platform driver.
+ *
+ * Wlan sdio function driver uses this API to unregister oob callback
+ * function from platform driver.
+ *
+ * Return: 0 means unregister successfully, others means failure.
+ */
+int cnss_wlan_unregister_oob_irq_handler(void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler);
+
+static void cnss_sdio_reset_platform_ops(void)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+	struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	if (sdio_info->dev)
+		sdio_info->dev->platform_data = NULL;
+}
+
+static int cnss_sdio_wlan_init(void)
+{
+	int error = 0;
+
+	error = sdio_register_driver(&cnss_ar6k_driver);
+	if (error) {
+		cnss_sdio_reset_platform_ops();
+		pr_err("registered fail error=%d\n", error);
+	} else {
+		pr_debug("registered success\n");
+	}
+
+	return error;
+}
+
+static void cnss_sdio_wlan_exit(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	cnss_sdio_reset_platform_ops();
+	sdio_unregister_driver(&cnss_ar6k_driver);
+}
+
+static void cnss_sdio_deinit_bus_bandwidth(void)
+{
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(bus_bandwidth->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+		msm_bus_scale_unregister_client(bus_bandwidth->bus_client);
+	}
+}
+
+static int cnss_sdio_configure_wlan_enable_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg);
+			dev_err(dev, "VDD-VREG get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+		if (error) {
+			dev_err(dev, "VDD-VREG enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg);
+
+	return error;
+}
+
+static int cnss_sdio_configure_wlan_enable_dsrc_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg_dsrc = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_DSRC_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg_dsrc)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg_dsrc);
+			dev_err(dev, "VDD-VREG-DSRC get failed error=%d\n",
+				error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg_dsrc);
+		if (error) {
+			dev_err(dev, "VDD-VREG-DSRC enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_dsrc_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_dsrc_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+
+	return error;
+}
+
+static int cnss_sdio_configure_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_IO_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_io = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_IO_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_io)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_io);
+			dev_err(dev, "VDD-IO get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_io,
+			WLAN_VREG_IO_MIN, WLAN_VREG_IO_MAX);
+		if (error) {
+			dev_err(dev, "VDD-IO set failed error=%d\n", error);
+			goto err_vdd_io_regulator;
+		} else {
+			error = regulator_enable(cnss_pdata->regulator.wlan_io);
+			if (error) {
+				dev_err(dev, "VDD-IO enable failed error=%d\n",
+					error);
+				goto err_vdd_io_regulator;
+			}
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_XTAL_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_xtal = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_XTAL_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_xtal)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_xtal);
+			dev_err(dev, "VDD-XTAL get failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_xtal,
+			WLAN_VREG_XTAL_MIN, WLAN_VREG_XTAL_MAX);
+		if (error) {
+			dev_err(dev, "VDD-XTAL set failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		} else {
+			error = regulator_enable(
+				cnss_pdata->regulator.wlan_xtal);
+			if (error) {
+				dev_err(dev, "VDD-XTAL enable failed err=%d\n",
+					error);
+				goto err_vdd_xtal_regulator;
+			}
+		}
+	}
+
+	return 0;
+
+err_vdd_xtal_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+err_vdd_io_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	return error;
+}
+
+static void cnss_sdio_release_resource(void)
+{
+	if (cnss_pdata->regulator.wlan_xtal)
+		regulator_put(cnss_pdata->regulator.wlan_xtal);
+	if (cnss_pdata->regulator.wlan_vreg)
+		regulator_put(cnss_pdata->regulator.wlan_vreg);
+	if (cnss_pdata->regulator.wlan_io)
+		regulator_put(cnss_pdata->regulator.wlan_io);
+	if (cnss_pdata->regulator.wlan_vreg_dsrc)
+		regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+}
+
+static int cnss_sdio_pinctrl_init(struct cnss_sdio_data *pdata,
+				  struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!of_find_property(dev->of_node, "qcom,is-antenna-shared", NULL))
+		return 0;
+
+	info->is_antenna_shared = true;
+	info->pinctrl = devm_pinctrl_get(dev);
+	if ((IS_ERR_OR_NULL(info->pinctrl))) {
+		dev_err(dev, "%s: Failed to get pinctrl\n", __func__);
+		return PTR_ERR(info->pinctrl);
+	}
+
+	info->sleep = pinctrl_lookup_state(info->pinctrl,
+						   CNSS_PINCTRL_SLEEP_STATE);
+	if (IS_ERR_OR_NULL(info->sleep)) {
+		dev_err(dev, "%s: Fail to get sleep state for pin\n", __func__);
+		ret = PTR_ERR(info->sleep);
+		goto release_pinctrl;
+	}
+
+	info->active = pinctrl_lookup_state(info->pinctrl,
+					    CNSS_PINCTRL_ACTIVE_STATE);
+	if (IS_ERR_OR_NULL(info->active)) {
+		dev_err(dev, "%s: Fail to get active state for pin\n",
+			__func__);
+		ret = PTR_ERR(info->active);
+		goto release_pinctrl;
+	}
+
+	ret = cnss_set_pinctrl_state(pdata, PINCTRL_SLEEP);
+
+	if (ret) {
+		dev_err(dev, "%s: Fail to set pin in sleep state\n", __func__);
+		goto release_pinctrl;
+	}
+
+	return ret;
+
+release_pinctrl:
+	devm_pinctrl_put(info->pinctrl);
+	info->is_antenna_shared = false;
+	return ret;
+}
+
+static int cnss_sdio_init_bus_bandwidth(void)
+{
+	int ret = 0;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	bus_bandwidth->bus_scale_table = msm_bus_cl_get_pdata(cnss_pdata->pdev);
+	if (!bus_bandwidth->bus_scale_table) {
+		dev_err(dev, "Failed to get the bus scale platform data\n");
+		ret = -EINVAL;
+	}
+
+	bus_bandwidth->bus_client = msm_bus_scale_register_client(
+			bus_bandwidth->bus_scale_table);
+	if (!bus_bandwidth->bus_client) {
+		dev_err(dev, "Failed to register with bus_scale client\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cnss_sdio_probe(struct platform_device *pdev)
+{
+	int error;
+	struct device *dev = &pdev->dev;
+	struct cnss_sdio_info *info;
+
+	if (pdev->dev.of_node) {
+		cnss_pdata = devm_kzalloc(
+			&pdev->dev, sizeof(*cnss_pdata), GFP_KERNEL);
+		if (!cnss_pdata)
+			return -ENOMEM;
+	} else {
+		cnss_pdata = pdev->dev.platform_data;
+	}
+
+	if (!cnss_pdata)
+		return -EINVAL;
+
+	cnss_pdata->pdev = pdev;
+	info = &cnss_pdata->cnss_sdio_info;
+
+	error = cnss_sdio_pinctrl_init(cnss_pdata, pdev);
+	if (error) {
+		dev_err(&pdev->dev, "Fail to configure pinctrl err:%d\n",
+			error);
+		return error;
+	}
+
+	error = cnss_sdio_configure_regulator();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n",
+			error);
+		return error;
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan enable regulator error=%d\n",
+				error);
+			goto err_wlan_enable_regulator;
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_dsrc_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan dsrc enable regulator\n");
+			goto err_wlan_dsrc_enable_regulator;
+		}
+	}
+
+	info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node,
+							  "qcom,skip-wlan-en-toggle");
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+
+	cnss_sdio_tsf_init(dev, &info->cap_tsf_info);
+
+	error = cnss_sdio_wlan_init();
+	if (error) {
+		dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error);
+		goto err_wlan_dsrc_enable_regulator;
+	}
+
+	error = cnss_configure_ramdump();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n",
+			error);
+		goto err_ramdump_create;
+	}
+
+	error = cnss_subsys_init();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n",
+			error);
+		goto err_subsys_init;
+	}
+
+	if (of_property_read_bool(
+		pdev->dev.of_node, "qcom,cnss-enable-bus-bandwidth")) {
+		error = cnss_sdio_init_bus_bandwidth();
+		if (error) {
+			dev_err(&pdev->dev, "Failed to init bus bandwidth\n");
+			goto err_bus_bandwidth_init;
+		}
+	}
+
+	dev_info(&pdev->dev, "CNSS SDIO Driver registered");
+	return 0;
+
+err_bus_bandwidth_init:
+	cnss_subsys_exit();
+err_subsys_init:
+	cnss_ramdump_cleanup();
+err_ramdump_create:
+	cnss_sdio_wlan_exit();
+err_wlan_dsrc_enable_regulator:
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+err_wlan_enable_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	cnss_pdata = NULL;
+	return error;
+}
+
+static int cnss_sdio_remove(struct platform_device *pdev)
+{
+	struct cnss_sdio_info *info;
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+	tsf_info = &info->cap_tsf_info;
+
+	cnss_sdio_tsf_deinit(tsf_info);
+	cnss_sdio_deinit_bus_bandwidth();
+	cnss_sdio_wlan_exit();
+	cnss_subsys_exit();
+	cnss_ramdump_cleanup();
+	cnss_put_hw_resources(info->dev);
+	cnss_sdio_release_resource();
+	cnss_pdata = NULL;
+	return 0;
+}
+
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	return 0;
+}
+
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num)
+{
+	*num = 0;
+	return NULL;
+}
+
+int cnss_sdio_power_down(struct device *dev)
+{
+	return 0;
+}
+
+int cnss_sdio_power_up(struct device *dev)
+{
+	return 0;
+}
+
+static const struct of_device_id cnss_sdio_dt_match[] = {
+	{.compatible = "qcom,cnss_sdio"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cnss_sdio_dt_match);
+
+static struct platform_driver cnss_sdio_driver = {
+	.probe  = cnss_sdio_probe,
+	.remove = cnss_sdio_remove,
+	.driver = {
+		.name = "cnss_sdio",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_sdio_dt_match,
+	},
+};
+
+static int __init cnss_sdio_init(void)
+{
+	return platform_driver_register(&cnss_sdio_driver);
+}
+
+static void __exit cnss_sdio_exit(void)
+{
+	platform_driver_unregister(&cnss_sdio_driver);
+}
+
+module_init(cnss_sdio_init);
+module_exit(cnss_sdio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS SDIO Driver");
diff --git a/drivers/net/wireless/cnss/logger/Kconfig b/drivers/net/wireless/cnss/logger/Kconfig
new file mode 100644
index 0000000..85b6992
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Kconfig
@@ -0,0 +1,6 @@
+config CNSS_LOGGER
+	tristate "CNSS Logging Service Driver"
+	---help---
+	  This module adds support for the CNSS Logging Service for CLD
+	  driver, including the netlink socket service registration, transmit,
+	  event receive.
diff --git a/drivers/net/wireless/cnss/logger/Makefile b/drivers/net/wireless/cnss/logger/Makefile
new file mode 100644
index 0000000..1e296a3
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CNSS_LOGGER) += logger.o
+
+logger-y += main.o	\
+	    nl_service.o
+
+logger-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/wireless/cnss/logger/debugfs.c b/drivers/net/wireless/cnss/logger/debugfs.c
new file mode 100644
index 0000000..027d630
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/debugfs.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include "logger.h"
+
+#define CNSS_LOGGER_STATE_DUMP_BUFFER	(2 * 1024) /* 2KB */
+
+static int logger_state_dump_device(struct logger_device *dev, char *buf,
+				    int buf_len)
+{
+	int len = 0;
+	struct logger_event_handler *cur;
+
+	len += scnprintf(buf + len, buf_len - len,
+			"==============================================\n");
+
+	len += scnprintf(buf + len, buf_len - len,
+			"driver [%s] is registered with radio index: %d\n",
+			dev->name, dev->radio_idx);
+
+	if (list_empty(&dev->event_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "No event registered\n");
+		return len;
+	}
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		len += scnprintf(buf + len, buf_len - len,
+				"\t event %d\n", cur->event);
+	}
+	len += scnprintf(buf + len, buf_len - len, "\n");
+
+	return len;
+}
+
+static int logger_state_dump(struct logger_context *ctx, char *buf, int buf_len)
+{
+	int len = 0;
+	struct logger_device *cur;
+
+	if (list_empty(&ctx->dev_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "=======================\n");
+		len += scnprintf(buf + len, buf_len - len,
+				 "No driver registered\n");
+		return 0;
+	}
+
+	list_for_each_entry(cur, &ctx->dev_list, list)
+		len += logger_state_dump_device(cur, (buf + len), buf_len);
+
+	return 0;
+}
+
+static int logger_state_open(struct inode *inode, struct file *file)
+{
+	struct logger_context *ctx = inode->i_private;
+	void *buf;
+	int ret;
+
+	mutex_lock(&ctx->con_mutex);
+
+	buf = kmalloc(CNSS_LOGGER_STATE_DUMP_BUFFER, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto error_unlock;
+	}
+
+	ret = logger_state_dump(ctx, buf, CNSS_LOGGER_STATE_DUMP_BUFFER);
+	if (ret)
+		goto error_free;
+
+	file->private_data = buf;
+	mutex_unlock(&ctx->con_mutex);
+	return 0;
+
+error_free:
+	kfree(buf);
+
+error_unlock:
+	mutex_unlock(&ctx->con_mutex);
+
+	return ret;
+}
+
+static int logger_state_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static ssize_t logger_state_read(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	unsigned int len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_logger_state = {
+	.open = logger_state_open,
+	.release = logger_state_release,
+	.read = logger_state_read,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+void logger_debugfs_init(struct logger_context *ctx)
+{
+	if (!ctx->debugfs_entry)
+		ctx->debugfs_entry = debugfs_create_dir("cnss_logger", NULL);
+
+	debugfs_create_file("state", 0400, ctx->debugfs_entry, ctx,
+			    &fops_logger_state);
+}
+
+void logger_debugfs_remove(struct logger_context *ctx)
+{
+	debugfs_remove(ctx->debugfs_entry);
+}
+
diff --git a/drivers/net/wireless/cnss/logger/logger.h b/drivers/net/wireless/cnss/logger/logger.h
new file mode 100644
index 0000000..6531ac6
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/logger.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LOGGER_H_
+#define _LOGGER_H_
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+
+#define CNSS_LOGGER_NL_MCAST_GRP_ID	0x01
+#define CNSS_LOGGER_NL_MAX_PAYLOAD	256
+#define CNSS_LOGGER_BROADCAST_ID	255
+
+/**
+ * struct aninlmsg - the wireless service message header
+ * @nlh:	the netlink message header
+ * @radio:	the radio index of this message
+ * @wmsg:	the pointer to the wireless message data
+ */
+struct aninlmsg {
+	struct  nlmsghdr *nlh;
+	int radio;
+	void *wmsg;
+};
+
+/**
+ * struct logger_event_handler - the logger event handler structure
+ * @list:	the event list associated to the same device
+ * @event:	the event number
+ * @radio_idx:	the callback handler
+ */
+struct logger_event_handler {
+	struct list_head list;
+
+	int event;
+	int (*cb)(struct sk_buff *skb);
+};
+
+/**
+ * struct logger_device - the logger device structure
+ * @list:	the device list registered to logger module
+ * @event_list:	the event list registered to this device
+ * @ctx:	the pointer to the logger context
+ * @wiphy:	the wiphy that associated to the device
+ * @name:	the name of the device driver module
+ * @radio_idx:	the radio index assigned to this device
+ */
+struct logger_device {
+	struct list_head list;
+	struct list_head event_list;
+
+	struct logger_context *ctx;
+	struct wiphy *wiphy;
+	char name[MODULE_NAME_LEN];
+	int radio_idx;
+};
+
+/**
+ * struct logger_context - the main context block for logger module
+ * @dev_list:	this is the list to maintain the devices that registered
+ *		to use the logger module feature
+ * @nl_sock:	the netlink socket to share accros the module
+ * @con_mutex:	the mutex to protect concurrent access
+ * @data_lock:	the lock to protect shared data
+ * @radio_mask: this mask would maintain the radio index assign and release
+ */
+struct logger_context {
+	struct list_head dev_list;
+
+	struct sock *nl_sock;
+	struct mutex con_mutex; /* concurrent access mutex */
+	spinlock_t data_lock;
+	unsigned long radio_mask; /* support up to 4 drivers registration? */
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_entry;
+#endif
+};
+
+int logger_netlink_init(struct logger_context *ctx);
+int logger_netlink_deinit(struct logger_context *ctx);
+struct logger_context *logger_get_ctx(void);
+
+#ifdef CONFIG_DEBUG_FS
+void logger_debugfs_init(struct logger_context *ctx);
+void logger_debugfs_remove(struct logger_context *ctx);
+#else
+static inline void logger_debugfs_init(struct logger_context *ctx) {}
+static inline void logger_debugfs_remove(struct logger_context *ctx) {}
+#endif
+
+#endif /* _LOGGER_H_ */
diff --git a/drivers/net/wireless/cnss/logger/main.c b/drivers/net/wireless/cnss/logger/main.c
new file mode 100644
index 0000000..4013e69
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/main.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static struct logger_context *ctx;
+
+struct logger_context *logger_get_ctx(void)
+{
+	return ctx;
+}
+
+static int __init logger_module_init(void)
+{
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ret = logger_netlink_init(ctx);
+
+	mutex_init(&ctx->con_mutex);
+	spin_lock_init(&ctx->data_lock);
+	logger_debugfs_init(ctx);
+
+	return ret;
+}
+
+static void __exit logger_module_exit(void)
+{
+	logger_debugfs_remove(ctx);
+	logger_netlink_deinit(ctx);
+
+	kfree(ctx);
+}
+
+module_init(logger_module_init);
+module_exit(logger_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Logging Service Driver");
diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c
new file mode 100644
index 0000000..4ea76ae
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/nl_service.c
@@ -0,0 +1,476 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "cnss_logger: %s: "fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static DEFINE_MUTEX(logger_sem);
+
+/**
+ * logger_get_radio_idx() - to get the radio index
+ * @ctx: the logger context pointer
+ *
+ * Return: the first available radio index, otherwise failure code
+ */
+static int logger_get_radio_idx(struct logger_context *ctx)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ctx->radio_mask); i++) {
+		if (!test_and_set_bit(i, &ctx->radio_mask))
+			return i;
+	}
+	return -EINVAL;
+}
+
+/**
+ * logger_put_radio_idx() - to release the radio index
+ * @radio: the radio index to release
+ *
+ * Return: None
+ */
+static void logger_put_radio_idx(struct logger_context *ctx, int radio)
+{
+	clear_bit(radio, &ctx->radio_mask);
+}
+
+/**
+ * logger_get_device() - to get the logger device per radio index
+ * @radio: the radio index
+ *
+ * Return: the logger_device pointer, otherwise return NULL.
+ */
+static struct logger_device *logger_get_device(int radio)
+{
+	struct logger_device *dev;
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return NULL;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->radio_idx == radio)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_device_is_registered() - to check if device has been registered
+ * @dev: pointer to logger device
+ * @wiphy: the wiphy pointer of the device to register
+ *
+ * This helper function is to check if this device has been registered.
+ *
+ * Return: NULL if it has not, otherwise return the logger_device pointer.
+ */
+static struct logger_device *logger_device_is_registered(
+						 struct logger_context *ctx,
+						 struct wiphy *wiphy)
+{
+	struct logger_device *dev;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->wiphy == wiphy)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_dispatch_skb() - to dispatch the skb to devices
+ * @skb: the socket buffer received and to dispatch
+ *
+ * The function will look up the header of the skb, and dispatch the skb
+ * to the associated event and device that registered.
+ *
+ * Return: 0 if successfully dispatch, otherwise failure code
+ */
+static int logger_dispatch_skb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct logger_event_handler *evt;
+	int handled = 0;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	pr_info("skb_len: %d, skb_data_len: %d\n",
+		skb->len, skb->data_len);
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return 0;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	list_for_each_entry(cur, &ctx->dev_list, list) {
+		list_for_each_entry(evt, &cur->event_list, list) {
+			if (nlh->nlmsg_type == evt->event) {
+				if (evt->cb) {
+					handled = 1;
+					evt->cb(skb);
+				}
+				/* Break inside loop, next dev */
+				break;
+			}
+		}
+	}
+
+	if (!handled)
+		pr_info("Not handled msg type: %d\n", nlh->nlmsg_type);
+
+	return 0;
+}
+
+/**
+ * logger_flush_event_handle() - to flush the event handle associate to device
+ * @dev: pointer to logger device
+ *
+ * The function will clean up all the event handle's resource, take it out
+ * from the list, and free the memory allocated.
+ *
+ * Return: None
+ */
+static void logger_flush_event_handle(struct logger_device *dev)
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		pr_info("radio: %d, event: %d unregistered\n",
+			dev->radio_idx, cur->event);
+		list_del(&cur->list);
+		kfree(cur);
+	}
+}
+
+/**
+ * logger_flush_devices() - to flush the devices infomration
+ * @dev: pointer to logger device
+ *
+ * The helper function to flush the device information, all the device clean
+ * up prcoess should be starting from here.
+ *
+ * Return: None
+ */
+static void logger_flush_devices(struct logger_device *dev)
+{
+	pr_info("driver: [%s] and radio-%d is unregistered\n",
+		dev->name, dev->radio_idx);
+	logger_flush_event_handle(dev);
+	logger_put_radio_idx(dev->ctx, dev->radio_idx);
+	list_del(&dev->list);
+	kfree(dev);
+}
+
+/**
+ * logger_register_device_event() - register the evet to device
+ * @dev: pointer to logger device
+ * @event: the event to register
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if register successfully, otherwise the failure code
+ */
+static int logger_register_device_event(struct logger_device *dev, int event,
+					int (*cb)(struct sk_buff *skb))
+{
+	struct logger_event_handler *cur;
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		if (cur->event == event) {
+			pr_info("event %d, is already added\n", event);
+			return 0;
+		}
+	}
+
+	cur = kmalloc(sizeof(*cur), GFP_KERNEL);
+	if (!cur)
+		return -ENOMEM;
+
+	cur->event = event;
+	cur->cb = cb;
+
+	pr_info("radio: %d, event: %d\n", dev->radio_idx, cur->event);
+	list_add_tail(&cur->list, &dev->event_list);
+
+	return 0;
+}
+
+/**
+ * logger_unregister_device_event() - unregister the evet from device
+ * @dev: pointer to logger device
+ * @event: the event to unregister
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if unregister successfully, otherwise the failure code
+ */
+static int logger_unregister_device_event(struct logger_device *dev, int event,
+					  int (*cb)(struct sk_buff *skb))
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		if (cur->event == event && cur->cb == cb) {
+			pr_info("radio: %d, event: %d\n",
+				dev->radio_idx, cur->event);
+			list_del(&cur->list);
+			kfree(cur);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * logger_skb_input() - the callback to receive the skb
+ * @skb: the receive socket buffer
+ *
+ * Return: None
+ */
+static void logger_skb_input(struct sk_buff *skb)
+{
+	mutex_lock(&logger_sem);
+	logger_dispatch_skb(skb);
+	mutex_unlock(&logger_sem);
+}
+
+/**
+ * cnss_logger_event_register() - register the event
+ * @radio: the radio index to register
+ * @event: the event to register
+ * @cb: the callback
+ *
+ * This function is used to register event associated to the radio index.
+ *
+ * Return: 0 if register success, otherwise failure code
+ */
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_register_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_register);
+
+/**
+ * cnss_logger_event_unregister() - unregister the event
+ * @radio: the radio index to unregister
+ * @event: the event to unregister
+ * @cb: the callback
+ *
+ * This function is used to unregister the event from cnss logger module.
+ *
+ * Return: 0 if unregister success, otherwise failure code
+ */
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_unregister_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_unregister);
+
+/**
+ * cnss_logger_device_register() - register the driver
+ * @wiphy: the wiphy device to unregister
+ * @name: the module name of the driver
+ *
+ * This function is used to register the driver to cnss logger module,
+ * this will indicate the existence of the driver, and also assign the
+ * radio index for further operation.
+ *
+ * Return: the radio index if register successful, otherwise failure code
+ */
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name)
+{
+	int radio;
+	struct logger_context *ctx;
+	struct logger_device *new;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	/* sanity check, already registered? */
+	new = logger_device_is_registered(ctx, wiphy);
+	if (new)
+		return new->radio_idx;
+
+	radio = logger_get_radio_idx(ctx);
+	if (radio < 0) {
+		pr_err("driver registration is full\n");
+		return -ENOMEM;
+	}
+
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (!new) {
+		logger_put_radio_idx(ctx, radio);
+		return -ENOMEM;
+	}
+
+	new->radio_idx = radio;
+	new->wiphy = wiphy;
+	new->ctx = ctx;
+	strlcpy(new->name, name, sizeof(new->name));
+	INIT_LIST_HEAD(&new->event_list);
+
+	list_add(&new->list, &ctx->dev_list);
+
+	pr_info("driver: [%s] is registered as radio-%d\n",
+		new->name, new->radio_idx);
+
+	return new->radio_idx;
+}
+EXPORT_SYMBOL(cnss_logger_device_register);
+
+/**
+ * cnss_logger_device_unregister() - unregister the driver
+ * @radio: the radio to unregister
+ * @wiphy: the wiphy device to unregister
+ *
+ * This function is used to unregister the driver from cnss logger module.
+ * This will disable the driver to access the interface in cnss logger,
+ * and also all the related events that registered will be reset.
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct list_head *pos, *temp;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		cur = list_entry(pos, struct logger_device, list);
+		if (cur->radio_idx == radio && cur->wiphy == wiphy) {
+			logger_flush_devices(cur);
+			break;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_logger_device_unregister);
+
+/**
+ * cnss_logger_nl_ucast() - nl interface to unicast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the flag to indicate if this is a nonblock call
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_unicast(ctx->nl_sock, skb, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_ucast);
+
+/**
+ * cnss_logger_nl_bcast() - nl interface to broadcast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the gfp_t flag
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_broadcast(ctx->nl_sock, skb, 0, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_bcast);
+
+/**
+ * logger_netlink_init() - initialize the netlink socket
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: the netlink handle if success, otherwise failure code
+ */
+int logger_netlink_init(struct logger_context *ctx)
+{
+	struct netlink_kernel_cfg cfg = {
+		.groups	= CNSS_LOGGER_NL_MCAST_GRP_ID,
+		.input	= logger_skb_input,
+	};
+
+	ctx->nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
+	if (!ctx->nl_sock) {
+		pr_err("cnss_logger: Cannot create netlink socket");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&ctx->dev_list);
+
+	return 0;
+}
+
+/**
+ * logger_netlink_deinit() - release the netlink socket and other resource
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int logger_netlink_deinit(struct logger_context *ctx)
+{
+	struct list_head *pos, *temp;
+	struct logger_device *dev;
+
+	netlink_kernel_release(ctx->nl_sock);
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		dev = container_of(pos, struct logger_device, list);
+		logger_flush_devices(dev);
+	}
+	return 0;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index d04babd..ff5ce1e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1040,6 +1040,8 @@
 		return le32_to_cpu(txq_timer->p2p_go);
 	case NL80211_IFTYPE_P2P_DEVICE:
 		return le32_to_cpu(txq_timer->p2p_device);
+	case NL80211_IFTYPE_MONITOR:
+		return default_timeout;
 	default:
 		WARN_ON(1);
 		return mvm->cfg->base_params->wd_timeout;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8d498a9..1a9dadf 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -86,6 +86,8 @@
 /* IRQ name is queue name with "-tx" or "-rx" appended */
 #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)
 
+static DECLARE_WAIT_QUEUE_HEAD(module_unload_q);
+
 struct netfront_stats {
 	u64			packets;
 	u64			bytes;
@@ -2051,10 +2053,12 @@
 		break;
 
 	case XenbusStateClosed:
+		wake_up_all(&module_unload_q);
 		if (dev->state == XenbusStateClosed)
 			break;
 		/* Missed the backend's CLOSING state -- fallthrough */
 	case XenbusStateClosing:
+		wake_up_all(&module_unload_q);
 		xenbus_frontend_closed(dev);
 		break;
 	}
@@ -2160,6 +2164,20 @@
 
 	dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
+	if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) {
+		xenbus_switch_state(dev, XenbusStateClosing);
+		wait_event(module_unload_q,
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateClosing);
+
+		xenbus_switch_state(dev, XenbusStateClosed);
+		wait_event(module_unload_q,
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateClosed ||
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateUnknown);
+	}
+
 	xennet_disconnect_backend(info);
 
 	unregister_netdev(info->netdev);
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index ea4bedf..0280d42 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -36,6 +36,8 @@
 	unsigned int firm_gpio;
 	unsigned int ese_gpio;
 	const char *clk_src_name;
+	/* NFC_CLK pin voting state */
+	bool clk_pin_voting;
 };
 
 static const struct of_device_id msm_match_table[] = {
@@ -469,39 +471,47 @@
 		dev_dbg(&nqx_dev->client->dev,
 			"gpio_set_value disable: %s: info: %p\n",
 			__func__, nqx_dev);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 0);
+			usleep_range(10000, 10100);
+		}
 
 		if (gpio_is_valid(nqx_dev->ese_gpio)) {
 			if (!gpio_get_value(nqx_dev->ese_gpio)) {
 				dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n");
 				gpio_set_value(nqx_dev->en_gpio, 0);
+				usleep_range(10000, 10100);
 			} else {
 				dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n");
 			}
 		} else {
 			dev_dbg(&nqx_dev->client->dev, "ese_gpio invalid, set en_gpio to low\n");
 			gpio_set_value(nqx_dev->en_gpio, 0);
+			usleep_range(10000, 10100);
 		}
-		r = nqx_clock_deselect(nqx_dev);
-		if (r < 0)
-			dev_err(&nqx_dev->client->dev, "unable to disable clock\n");
+		if (nqx_dev->pdata->clk_pin_voting) {
+			r = nqx_clock_deselect(nqx_dev);
+			if (r < 0)
+				dev_err(&nqx_dev->client->dev, "unable to disable clock\n");
+		}
 		nqx_dev->nfc_ven_enabled = false;
-		/* hardware dependent delay */
-		msleep(100);
 	} else if (arg == 1) {
 		nqx_enable_irq(nqx_dev);
 		dev_dbg(&nqx_dev->client->dev,
 			"gpio_set_value enable: %s: info: %p\n",
 			__func__, nqx_dev);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 0);
+			usleep_range(10000, 10100);
+		}
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		r = nqx_clock_select(nqx_dev);
-		if (r < 0)
-			dev_err(&nqx_dev->client->dev, "unable to enable clock\n");
+		usleep_range(10000, 10100);
+		if (nqx_dev->pdata->clk_pin_voting) {
+			r = nqx_clock_select(nqx_dev);
+			if (r < 0)
+				dev_err(&nqx_dev->client->dev, "unable to enable clock\n");
+		}
 		nqx_dev->nfc_ven_enabled = true;
-		msleep(20);
 	} else if (arg == 2) {
 		/*
 		 * We are switching to Dowload Mode, toggle the enable pin
@@ -515,14 +525,15 @@
 			}
 		}
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		msleep(20);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		usleep_range(10000, 10100);
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 1);
-		msleep(20);
+			usleep_range(10000, 10100);
+		}
 		gpio_set_value(nqx_dev->en_gpio, 0);
-		msleep(100);
+		usleep_range(10000, 10100);
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		msleep(20);
+		usleep_range(10000, 10100);
 	} else {
 		r = -ENOIOCTLCMD;
 	}
@@ -648,13 +659,14 @@
 	unsigned char nci_reset_rsp[6];
 	unsigned char init_rsp_len = 0;
 	unsigned int enable_gpio = nqx_dev->en_gpio;
+
 	/* making sure that the NFCC starts in a clean state. */
 	gpio_set_value(enable_gpio, 0);/* ULPM: Disable */
 	/* hardware dependent delay */
-	msleep(20);
+	usleep_range(10000, 10100);
 	gpio_set_value(enable_gpio, 1);/* HPD : Enable*/
 	/* hardware dependent delay */
-	msleep(20);
+	usleep_range(10000, 10100);
 
 	/* send NCI CORE RESET CMD with Keep Config parameters */
 	ret = i2c_master_send(client, raw_nci_reset_cmd,
@@ -670,21 +682,17 @@
 	/* Read Response of RESET command */
 	ret = i2c_master_recv(client, nci_reset_rsp,
 		sizeof(nci_reset_rsp));
-	dev_err(&client->dev,
-	"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
-	__func__, nci_reset_rsp[0],
-	nci_reset_rsp[1], nci_reset_rsp[2]);
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_recv Error\n", __func__);
 		goto err_nfcc_hw_check;
 	}
-	ret = i2c_master_send(client, raw_nci_init_cmd,
-		sizeof(raw_nci_init_cmd));
+	ret = nqx_standby_write(nqx_dev, raw_nci_init_cmd,
+				sizeof(raw_nci_init_cmd));
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_send Error\n", __func__);
-		goto err_nfcc_hw_check;
+		goto err_nfcc_core_init_fail;
 	}
 	/* hardware dependent delay */
 	msleep(30);
@@ -694,7 +702,7 @@
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_recv Error\n", __func__);
-		goto err_nfcc_hw_check;
+		goto err_nfcc_core_init_fail;
 	}
 	init_rsp_len = 2 + nci_init_rsp[2]; /*payload + len*/
 	if (init_rsp_len > PAYLOAD_HEADER_LENGTH) {
@@ -707,6 +715,11 @@
 		nqx_dev->nqx_info.info.fw_minor =
 				nci_init_rsp[init_rsp_len];
 	}
+	dev_dbg(&client->dev,
+		"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
+		__func__, nci_reset_rsp[0],
+		nci_reset_rsp[1], nci_reset_rsp[2]);
+
 	dev_dbg(&nqx_dev->client->dev, "NQ NFCC chip_type = %x\n",
 		nqx_dev->nqx_info.info.chip_type);
 	dev_dbg(&nqx_dev->client->dev, "NQ fw version = %x.%x.%x\n",
@@ -746,6 +759,12 @@
 	ret = 0;
 	goto done;
 
+err_nfcc_core_init_fail:
+	dev_err(&client->dev,
+	"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
+	__func__, nci_reset_rsp[0],
+	nci_reset_rsp[1], nci_reset_rsp[2]);
+
 err_nfcc_hw_check:
 	ret = -ENXIO;
 	dev_err(&client->dev,
@@ -828,12 +847,13 @@
 		pdata->ese_gpio = -EINVAL;
 	}
 
-	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name);
+	if (of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name))
+		pdata->clk_pin_voting = false;
+	else
+		pdata->clk_pin_voting = true;
 
 	pdata->clkreq_gpio = of_get_named_gpio(np, "qcom,nq-clkreq", 0);
 
-	if (r)
-		return -EINVAL;
 	return r;
 }
 
@@ -1213,6 +1233,7 @@
 		.owner = THIS_MODULE,
 		.name = "nq-nci",
 		.of_match_table = msm_match_table,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm = &nfc_pm_ops,
 	},
 };
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 94733f7..7121453 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -183,13 +183,13 @@
 	return ret;
 }
 
-static int btt_log_read_pair(struct arena_info *arena, u32 lane,
-			struct log_entry *ent)
+static int btt_log_group_read(struct arena_info *arena, u32 lane,
+			struct log_group *log)
 {
-	WARN_ON(!ent);
+	WARN_ON(!log);
 	return arena_read_bytes(arena,
-			arena->logoff + (2 * lane * LOG_ENT_SIZE), ent,
-			2 * LOG_ENT_SIZE);
+			arena->logoff + (lane * LOG_GRP_SIZE), log,
+			LOG_GRP_SIZE);
 }
 
 static struct dentry *debugfs_root;
@@ -229,6 +229,8 @@
 	debugfs_create_x64("logoff", S_IRUGO, d, &a->logoff);
 	debugfs_create_x64("info2off", S_IRUGO, d, &a->info2off);
 	debugfs_create_x32("flags", S_IRUGO, d, &a->flags);
+	debugfs_create_u32("log_index_0", S_IRUGO, d, &a->log_index[0]);
+	debugfs_create_u32("log_index_1", S_IRUGO, d, &a->log_index[1]);
 }
 
 static void btt_debugfs_init(struct btt *btt)
@@ -247,6 +249,11 @@
 	}
 }
 
+static u32 log_seq(struct log_group *log, int log_idx)
+{
+	return le32_to_cpu(log->ent[log_idx].seq);
+}
+
 /*
  * This function accepts two log entries, and uses the
  * sequence number to find the 'older' entry.
@@ -256,8 +263,10 @@
  *
  * TODO The logic feels a bit kludge-y. make it better..
  */
-static int btt_log_get_old(struct log_entry *ent)
+static int btt_log_get_old(struct arena_info *a, struct log_group *log)
 {
+	int idx0 = a->log_index[0];
+	int idx1 = a->log_index[1];
 	int old;
 
 	/*
@@ -265,23 +274,23 @@
 	 * the next time, the following logic works out to put this
 	 * (next) entry into [1]
 	 */
-	if (ent[0].seq == 0) {
-		ent[0].seq = cpu_to_le32(1);
+	if (log_seq(log, idx0) == 0) {
+		log->ent[idx0].seq = cpu_to_le32(1);
 		return 0;
 	}
 
-	if (ent[0].seq == ent[1].seq)
+	if (log_seq(log, idx0) == log_seq(log, idx1))
 		return -EINVAL;
-	if (le32_to_cpu(ent[0].seq) + le32_to_cpu(ent[1].seq) > 5)
+	if (log_seq(log, idx0) + log_seq(log, idx1) > 5)
 		return -EINVAL;
 
-	if (le32_to_cpu(ent[0].seq) < le32_to_cpu(ent[1].seq)) {
-		if (le32_to_cpu(ent[1].seq) - le32_to_cpu(ent[0].seq) == 1)
+	if (log_seq(log, idx0) < log_seq(log, idx1)) {
+		if ((log_seq(log, idx1) - log_seq(log, idx0)) == 1)
 			old = 0;
 		else
 			old = 1;
 	} else {
-		if (le32_to_cpu(ent[0].seq) - le32_to_cpu(ent[1].seq) == 1)
+		if ((log_seq(log, idx0) - log_seq(log, idx1)) == 1)
 			old = 1;
 		else
 			old = 0;
@@ -306,17 +315,18 @@
 {
 	int ret;
 	int old_ent, ret_ent;
-	struct log_entry log[2];
+	struct log_group log;
 
-	ret = btt_log_read_pair(arena, lane, log);
+	ret = btt_log_group_read(arena, lane, &log);
 	if (ret)
 		return -EIO;
 
-	old_ent = btt_log_get_old(log);
+	old_ent = btt_log_get_old(arena, &log);
 	if (old_ent < 0 || old_ent > 1) {
 		dev_info(to_dev(arena),
 				"log corruption (%d): lane %d seq [%d, %d]\n",
-			old_ent, lane, log[0].seq, log[1].seq);
+				old_ent, lane, log.ent[arena->log_index[0]].seq,
+				log.ent[arena->log_index[1]].seq);
 		/* TODO set error state? */
 		return -EIO;
 	}
@@ -324,7 +334,7 @@
 	ret_ent = (old_flag ? old_ent : (1 - old_ent));
 
 	if (ent != NULL)
-		memcpy(ent, &log[ret_ent], LOG_ENT_SIZE);
+		memcpy(ent, &log.ent[arena->log_index[ret_ent]], LOG_ENT_SIZE);
 
 	return ret_ent;
 }
@@ -338,17 +348,13 @@
 			u32 sub, struct log_entry *ent)
 {
 	int ret;
-	/*
-	 * Ignore the padding in log_entry for calculating log_half.
-	 * The entry is 'committed' when we write the sequence number,
-	 * and we want to ensure that that is the last thing written.
-	 * We don't bother writing the padding as that would be extra
-	 * media wear and write amplification
-	 */
-	unsigned int log_half = (LOG_ENT_SIZE - 2 * sizeof(u64)) / 2;
-	u64 ns_off = arena->logoff + (((2 * lane) + sub) * LOG_ENT_SIZE);
+	u32 group_slot = arena->log_index[sub];
+	unsigned int log_half = LOG_ENT_SIZE / 2;
 	void *src = ent;
+	u64 ns_off;
 
+	ns_off = arena->logoff + (lane * LOG_GRP_SIZE) +
+		(group_slot * LOG_ENT_SIZE);
 	/* split the 16B write into atomic, durable halves */
 	ret = arena_write_bytes(arena, ns_off, src, log_half);
 	if (ret)
@@ -419,16 +425,16 @@
 {
 	int ret;
 	u32 i;
-	struct log_entry log, zerolog;
+	struct log_entry ent, zerolog;
 
 	memset(&zerolog, 0, sizeof(zerolog));
 
 	for (i = 0; i < arena->nfree; i++) {
-		log.lba = cpu_to_le32(i);
-		log.old_map = cpu_to_le32(arena->external_nlba + i);
-		log.new_map = cpu_to_le32(arena->external_nlba + i);
-		log.seq = cpu_to_le32(LOG_SEQ_INIT);
-		ret = __btt_log_write(arena, i, 0, &log);
+		ent.lba = cpu_to_le32(i);
+		ent.old_map = cpu_to_le32(arena->external_nlba + i);
+		ent.new_map = cpu_to_le32(arena->external_nlba + i);
+		ent.seq = cpu_to_le32(LOG_SEQ_INIT);
+		ret = __btt_log_write(arena, i, 0, &ent);
 		if (ret)
 			return ret;
 		ret = __btt_log_write(arena, i, 1, &zerolog);
@@ -490,6 +496,123 @@
 	return 0;
 }
 
+static bool ent_is_padding(struct log_entry *ent)
+{
+	return (ent->lba == 0) && (ent->old_map == 0) && (ent->new_map == 0)
+		&& (ent->seq == 0);
+}
+
+/*
+ * Detecting valid log indices: We read a log group (see the comments in btt.h
+ * for a description of a 'log_group' and its 'slots'), and iterate over its
+ * four slots. We expect that a padding slot will be all-zeroes, and use this
+ * to detect a padding slot vs. an actual entry.
+ *
+ * If a log_group is in the initial state, i.e. hasn't been used since the
+ * creation of this BTT layout, it will have three of the four slots with
+ * zeroes. We skip over these log_groups for the detection of log_index. If
+ * all log_groups are in the initial state (i.e. the BTT has never been
+ * written to), it is safe to assume the 'new format' of log entries in slots
+ * (0, 1).
+ */
+static int log_set_indices(struct arena_info *arena)
+{
+	bool idx_set = false, initial_state = true;
+	int ret, log_index[2] = {-1, -1};
+	u32 i, j, next_idx = 0;
+	struct log_group log;
+	u32 pad_count = 0;
+
+	for (i = 0; i < arena->nfree; i++) {
+		ret = btt_log_group_read(arena, i, &log);
+		if (ret < 0)
+			return ret;
+
+		for (j = 0; j < 4; j++) {
+			if (!idx_set) {
+				if (ent_is_padding(&log.ent[j])) {
+					pad_count++;
+					continue;
+				} else {
+					/* Skip if index has been recorded */
+					if ((next_idx == 1) &&
+						(j == log_index[0]))
+						continue;
+					/* valid entry, record index */
+					log_index[next_idx] = j;
+					next_idx++;
+				}
+				if (next_idx == 2) {
+					/* two valid entries found */
+					idx_set = true;
+				} else if (next_idx > 2) {
+					/* too many valid indices */
+					return -ENXIO;
+				}
+			} else {
+				/*
+				 * once the indices have been set, just verify
+				 * that all subsequent log groups are either in
+				 * their initial state or follow the same
+				 * indices.
+				 */
+				if (j == log_index[0]) {
+					/* entry must be 'valid' */
+					if (ent_is_padding(&log.ent[j]))
+						return -ENXIO;
+				} else if (j == log_index[1]) {
+					;
+					/*
+					 * log_index[1] can be padding if the
+					 * lane never got used and it is still
+					 * in the initial state (three 'padding'
+					 * entries)
+					 */
+				} else {
+					/* entry must be invalid (padding) */
+					if (!ent_is_padding(&log.ent[j]))
+						return -ENXIO;
+				}
+			}
+		}
+		/*
+		 * If any of the log_groups have more than one valid,
+		 * non-padding entry, then the we are no longer in the
+		 * initial_state
+		 */
+		if (pad_count < 3)
+			initial_state = false;
+		pad_count = 0;
+	}
+
+	if (!initial_state && !idx_set)
+		return -ENXIO;
+
+	/*
+	 * If all the entries in the log were in the initial state,
+	 * assume new padding scheme
+	 */
+	if (initial_state)
+		log_index[1] = 1;
+
+	/*
+	 * Only allow the known permutations of log/padding indices,
+	 * i.e. (0, 1), and (0, 2)
+	 */
+	if ((log_index[0] == 0) && ((log_index[1] == 1) || (log_index[1] == 2)))
+		; /* known index possibilities */
+	else {
+		dev_err(to_dev(arena), "Found an unknown padding scheme\n");
+		return -ENXIO;
+	}
+
+	arena->log_index[0] = log_index[0];
+	arena->log_index[1] = log_index[1];
+	dev_dbg(to_dev(arena), "log_index_0 = %d\n", log_index[0]);
+	dev_dbg(to_dev(arena), "log_index_1 = %d\n", log_index[1]);
+	return 0;
+}
+
 static int btt_rtt_init(struct arena_info *arena)
 {
 	arena->rtt = kcalloc(arena->nfree, sizeof(u32), GFP_KERNEL);
@@ -545,8 +668,7 @@
 	available -= 2 * BTT_PG_SIZE;
 
 	/* The log takes a fixed amount of space based on nfree */
-	logsize = roundup(2 * arena->nfree * sizeof(struct log_entry),
-				BTT_PG_SIZE);
+	logsize = roundup(arena->nfree * LOG_GRP_SIZE, BTT_PG_SIZE);
 	available -= logsize;
 
 	/* Calculate optimal split between map and data area */
@@ -563,6 +685,10 @@
 	arena->mapoff = arena->dataoff + datasize;
 	arena->logoff = arena->mapoff + mapsize;
 	arena->info2off = arena->logoff + logsize;
+
+	/* Default log indices are (0,1) */
+	arena->log_index[0] = 0;
+	arena->log_index[1] = 1;
 	return arena;
 }
 
@@ -653,6 +779,13 @@
 		arena->external_lba_start = cur_nlba;
 		parse_arena_meta(arena, super, cur_off);
 
+		ret = log_set_indices(arena);
+		if (ret) {
+			dev_err(to_dev(arena),
+				"Unable to deduce log/padding indices\n");
+			goto out;
+		}
+
 		ret = btt_freelist_init(arena);
 		if (ret)
 			goto out;
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index b2f8651..0f80b6b 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -26,6 +26,7 @@
 #define MAP_ERR_MASK (1 << MAP_ERR_SHIFT)
 #define MAP_LBA_MASK (~((1 << MAP_TRIM_SHIFT) | (1 << MAP_ERR_SHIFT)))
 #define MAP_ENT_NORMAL 0xC0000000
+#define LOG_GRP_SIZE sizeof(struct log_group)
 #define LOG_ENT_SIZE sizeof(struct log_entry)
 #define ARENA_MIN_SIZE (1UL << 24)	/* 16 MB */
 #define ARENA_MAX_SIZE (1ULL << 39)	/* 512 GB */
@@ -44,12 +45,52 @@
 	INIT_READY
 };
 
+/*
+ * A log group represents one log 'lane', and consists of four log entries.
+ * Two of the four entries are valid entries, and the remaining two are
+ * padding. Due to an old bug in the padding location, we need to perform a
+ * test to determine the padding scheme being used, and use that scheme
+ * thereafter.
+ *
+ * In kernels prior to 4.15, 'log group' would have actual log entries at
+ * indices (0, 2) and padding at indices (1, 3), where as the correct/updated
+ * format has log entries at indices (0, 1) and padding at indices (2, 3).
+ *
+ * Old (pre 4.15) format:
+ * +-----------------+-----------------+
+ * |      ent[0]     |      ent[1]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq |       pad       |
+ * +-----------------------------------+
+ * |      ent[2]     |      ent[3]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq |       pad       |
+ * +-----------------+-----------------+
+ *
+ * New format:
+ * +-----------------+-----------------+
+ * |      ent[0]     |      ent[1]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq | lba/old/new/seq |
+ * +-----------------------------------+
+ * |      ent[2]     |      ent[3]     |
+ * |       16B       |       16B       |
+ * |       pad       |       pad       |
+ * +-----------------+-----------------+
+ *
+ * We detect during start-up which format is in use, and set
+ * arena->log_index[(0, 1)] with the detected format.
+ */
+
 struct log_entry {
 	__le32 lba;
 	__le32 old_map;
 	__le32 new_map;
 	__le32 seq;
-	__le64 padding[2];
+};
+
+struct log_group {
+	struct log_entry ent[4];
 };
 
 struct btt_sb {
@@ -117,6 +158,7 @@
  * @list:		List head for list of arenas
  * @debugfs_dir:	Debugfs dentry
  * @flags:		Arena flags - may signify error states.
+ * @log_index:		Indices of the valid log entries in a log_group
  *
  * arena_info is a per-arena handle. Once an arena is narrowed down for an
  * IO, this struct is passed around for the duration of the IO.
@@ -147,6 +189,7 @@
 	struct dentry *debugfs_dir;
 	/* Arena flags */
 	u32 flags;
+	int log_index[2];
 };
 
 /**
diff --git a/drivers/of/base.c b/drivers/of/base.c
index a0bccb5..23a6d36 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -20,9 +20,11 @@
 
 #define pr_fmt(fmt)	"OF: " fmt
 
+#include <linux/bootmem.h>
 #include <linux/console.h>
 #include <linux/ctype.h>
 #include <linux/cpu.h>
+#include <linux/memblock.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_graph.h>
@@ -198,9 +200,100 @@
 	return 0;
 }
 
+static struct device_node **phandle_cache;
+static u32 phandle_cache_mask;
+
+/*
+ * Assumptions behind phandle_cache implementation:
+ *   - phandle property values are in a contiguous range of 1..n
+ *
+ * If the assumptions do not hold, then
+ *   - the phandle lookup overhead reduction provided by the cache
+ *     will likely be less
+ */
+static void of_populate_phandle_cache(void)
+{
+	unsigned long flags;
+	u32 cache_entries;
+	struct device_node *np;
+	u32 phandles = 0;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+
+	kfree(phandle_cache);
+	phandle_cache = NULL;
+
+	for_each_of_allnodes(np)
+		if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+			phandles++;
+
+	cache_entries = roundup_pow_of_two(phandles);
+	phandle_cache_mask = cache_entries - 1;
+
+	phandle_cache = kcalloc(cache_entries, sizeof(*phandle_cache),
+				GFP_ATOMIC);
+
+	if (phandle_cache)
+		for_each_of_allnodes(np)
+			if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+				phandle_cache[np->phandle & phandle_cache_mask] = np;
+
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+}
+
+void __init of_populate_phandle_cache_early(void)
+{
+	u32 cache_entries;
+	struct device_node *np;
+	u32 phandles = 0;
+	size_t size;
+
+	for_each_of_allnodes(np)
+		if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+			phandles++;
+
+	cache_entries = roundup_pow_of_two(phandles);
+	phandle_cache_mask = cache_entries - 1;
+
+	size = cache_entries * sizeof(*phandle_cache);
+	phandle_cache = memblock_virt_alloc(size, 4);
+	memset(phandle_cache, 0, size);
+
+	for_each_of_allnodes(np)
+		if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
+			phandle_cache[np->phandle & phandle_cache_mask] = np;
+}
+
+#ifndef CONFIG_MODULES
+static int __init of_free_phandle_cache(void)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+
+	kfree(phandle_cache);
+	phandle_cache = NULL;
+
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+	return 0;
+}
+late_initcall_sync(of_free_phandle_cache);
+#endif
+
 void __init of_core_init(void)
 {
+	unsigned long flags;
 	struct device_node *np;
+	phys_addr_t size;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+	size = (phandle_cache_mask + 1) * sizeof(*phandle_cache);
+	memblock_free(__pa(phandle_cache), size);
+	phandle_cache = NULL;
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+	of_populate_phandle_cache();
 
 	/* Create the kset, and register existing nodes */
 	mutex_lock(&of_mutex);
@@ -1093,16 +1186,32 @@
  */
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
-	struct device_node *np;
+	struct device_node *np = NULL;
 	unsigned long flags;
+	phandle masked_handle;
 
 	if (!handle)
 		return NULL;
 
 	raw_spin_lock_irqsave(&devtree_lock, flags);
-	for_each_of_allnodes(np)
-		if (np->phandle == handle)
-			break;
+
+	masked_handle = handle & phandle_cache_mask;
+
+	if (phandle_cache) {
+		if (phandle_cache[masked_handle] &&
+		    handle == phandle_cache[masked_handle]->phandle)
+			np = phandle_cache[masked_handle];
+	}
+
+	if (!np) {
+		for_each_of_allnodes(np)
+			if (np->phandle == handle) {
+				if (phandle_cache)
+					phandle_cache[masked_handle] = np;
+				break;
+			}
+	}
+
 	of_node_get(np);
 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c0914fb..755b386 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -31,6 +31,8 @@
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #include <asm/page.h>
 
+#include "of_private.h"
+
 /*
  * of_fdt_limit_memory - limit the number of regions in the /memory node
  * @limit: maximum entries
@@ -1269,6 +1271,8 @@
 
 	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
 	of_alias_scan(early_init_dt_alloc_memory_arch);
+
+	of_populate_phandle_cache_early();
 }
 
 /**
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 18bbb451..c4d7fdc 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -86,6 +86,11 @@
 extern void __of_sysfs_remove_bin_file(struct device_node *np,
 				       struct property *prop);
 
+/* illegal phandle value (set when unresolved) */
+#define OF_PHANDLE_ILLEGAL	0xdeadbeef
+
+extern void __init of_populate_phandle_cache_early(void);
+
 /* iterators for transactions, used for overlays */
 /* forward iterator */
 #define for_each_transaction_entry(_oft, _te) \
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index 46325d6..67b1d72 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -21,9 +21,6 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
-/* illegal phandle value (set when unresolved) */
-#define OF_PHANDLE_ILLEGAL	0xdeadbeef
-
 /**
  * Find a node with the give full name by recursively following any of
  * the child node links.
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index b897813..20d48a0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -5094,20 +5094,6 @@
 		return arch_setup_msi_irq_default(pdev, desc, 1);
 }
 
-static int msm_pcie_get_msi_multiple(int nvec)
-{
-	int msi_multiple = 0;
-
-	while (nvec) {
-		nvec = nvec >> 1;
-		msi_multiple++;
-	}
-	PCIE_GEN_DBG("log2 number of MSI multiple:%d\n",
-		msi_multiple - 1);
-
-	return msi_multiple - 1;
-}
-
 int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
 	struct msi_desc *entry;
@@ -5123,7 +5109,7 @@
 
 	list_for_each_entry(entry, &dev->dev.msi_list, list) {
 		entry->msi_attrib.multiple =
-				msm_pcie_get_msi_multiple(nvec);
+			__ilog2_u32(__roundup_pow_of_two(nvec));
 
 		if (pcie_dev->msi_gicm_addr)
 			ret = arch_setup_msi_irq_qgic(dev, entry, nvec);
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index a268f4d..48a365e 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -395,6 +395,10 @@
 	if (ret)
 		return ERR_PTR(-ENODEV);
 
+	/* This phy type handled by the usb-phy subsystem for now */
+	if (of_device_is_compatible(args.np, "usb-nop-xceiv"))
+		return ERR_PTR(-ENODEV);
+
 	mutex_lock(&phy_provider_mutex);
 	phy_provider = of_phy_provider_lookup(args.np);
 	if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index b40a074..df63b7d 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -368,6 +368,18 @@
 	writel(value, padcfg0);
 }
 
+static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
+{
+	u32 value;
+
+	/* Put the pad into GPIO mode */
+	value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
+	/* Disable SCI/SMI/NMI generation */
+	value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
+	value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
+	writel(value, padcfg0);
+}
+
 static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
 				     struct pinctrl_gpio_range *range,
 				     unsigned pin)
@@ -375,7 +387,6 @@
 	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 	void __iomem *padcfg0;
 	unsigned long flags;
-	u32 value;
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -385,13 +396,7 @@
 	}
 
 	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
-	/* Put the pad into GPIO mode */
-	value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
-	/* Disable SCI/SMI/NMI generation */
-	value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
-	value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
-	writel(value, padcfg0);
-
+	intel_gpio_set_gpio_mode(padcfg0);
 	/* Disable TX buffer and enable RX (this will be input) */
 	__intel_gpio_set_direction(padcfg0, true);
 
@@ -770,6 +775,8 @@
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
 
+	intel_gpio_set_gpio_mode(reg);
+
 	value = readl(reg);
 
 	value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
index 866aa3c..6cf0006 100644
--- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
+++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
@@ -436,3 +436,7 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pxa2xx_pinctrl_exit);
+
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
+MODULE_DESCRIPTION("Marvell PXA2xx pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index d39a17f..207ed06 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -89,6 +89,36 @@
 	  Technologies Inc MSM8953 platform.
 	  If unsure say N.
 
+config PINCTRL_MSM8909
+       tristate "Qualcomm Technologies Inc MSM8909 pin controller driver"
+       depends on GPIOLIB && OF && (ARCH_MSM8909 || COMPILE_TEST)
+       select PINCTRL_MSM
+       help
+	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+	  Qualcomm Technologies Inc TLMM block found on the Qualcomm
+	  Technologies Inc MSM8909 platform.
+	  If unsure say N.
+
+config PINCTRL_MSM8937
+	tristate "Qualcomm Technologies Inc MSM8937 pin controller driver"
+	depends on GPIOLIB && OF
+	select PINCTRL_MSM
+	help
+	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+	  Qualcomm Technologies Inc TLMM block found on the Qualcomm
+	  Technologies Inc MSM8937 platform.
+	  If unsure say N.
+
+config PINCTRL_MSM8917
+	tristate "Qualcomm Technologies Inc MSM8917 pin controller driver"
+	depends on GPIOLIB && OF
+	select PINCTRL_MSM
+	help
+	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+	  Qualcomm Technologies Inc TLMM block found on the Qualcomm
+	  Technologies Inc MSM8917 platform.
+	  If unsure say N.
+
 config PINCTRL_SDM845
 	tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
 	depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index d92db11..e5c3b34 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -12,6 +12,9 @@
 obj-$(CONFIG_PINCTRL_QDF2XXX)	+= pinctrl-qdf2xxx.o
 obj-$(CONFIG_PINCTRL_MDM9615)	+= pinctrl-mdm9615.o
 obj-$(CONFIG_PINCTRL_MSM8953)   += pinctrl-msm8953.o
+obj-$(CONFIG_PINCTRL_MSM8909)   += pinctrl-msm8909.o
+obj-$(CONFIG_PINCTRL_MSM8937)   += pinctrl-msm8937.o
+obj-$(CONFIG_PINCTRL_MSM8917)   += pinctrl-msm8917.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index bf95849..9e1c8d2 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013, Sony Mobile Communications AB.
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 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
@@ -25,6 +25,7 @@
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/of_irq.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -70,6 +71,7 @@
 
 	const struct msm_pinctrl_soc_data *soc;
 	void __iomem *regs;
+	void __iomem *pdc_regs;
 };
 
 static int msm_get_groups_count(struct pinctrl_dev *pctldev)
@@ -582,6 +584,9 @@
 	clear_bit(d->hwirq, pctrl->enabled_irqs);
 
 	spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	if (d->parent_data)
+		irq_chip_mask_parent(d);
 }
 
 static void msm_gpio_irq_enable(struct irq_data *d)
@@ -610,6 +615,9 @@
 	set_bit(d->hwirq, pctrl->enabled_irqs);
 
 	spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	if (d->parent_data)
+		irq_chip_enable_parent(d);
 }
 
 static void msm_gpio_irq_unmask(struct irq_data *d)
@@ -631,6 +639,9 @@
 	set_bit(d->hwirq, pctrl->enabled_irqs);
 
 	spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	if (d->parent_data)
+		irq_chip_unmask_parent(d);
 }
 
 static void msm_gpio_irq_ack(struct irq_data *d)
@@ -744,6 +755,9 @@
 
 	spin_unlock_irqrestore(&pctrl->lock, flags);
 
+	if (d->parent_data)
+		irq_chip_set_type_parent(d, type);
+
 	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
 		irq_set_handler_locked(d, handle_level_irq);
 	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -764,9 +778,35 @@
 
 	spin_unlock_irqrestore(&pctrl->lock, flags);
 
+	if (d->parent_data)
+		irq_chip_set_wake_parent(d, on);
+
 	return 0;
 }
 
+static int msm_gpiochip_irq_reqres(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+	if (!try_module_get(chip->owner))
+		return -ENODEV;
+
+	if (gpiochip_lock_as_irq(chip, d->hwirq)) {
+		pr_err("unable to lock HW IRQ %lu for IRQ\n", d->hwirq);
+		module_put(chip->owner);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_gpiochip_irq_relres(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+	gpiochip_unlock_as_irq(chip, d->hwirq);
+	module_put(chip->owner);
+}
+
 static struct irq_chip msm_gpio_irq_chip = {
 	.name           = "msmgpio",
 	.irq_enable     = msm_gpio_irq_enable,
@@ -775,8 +815,163 @@
 	.irq_ack        = msm_gpio_irq_ack,
 	.irq_set_type   = msm_gpio_irq_set_type,
 	.irq_set_wake   = msm_gpio_irq_set_wake,
+	.irq_request_resources    = msm_gpiochip_irq_reqres,
+	.irq_release_resources	  = msm_gpiochip_irq_relres,
+	.flags                    = IRQCHIP_MASK_ON_SUSPEND |
+					IRQCHIP_SKIP_SET_WAKE,
 };
 
+static void msm_gpio_domain_set_info(struct irq_domain *d, unsigned int irq,
+							irq_hw_number_t hwirq)
+{
+	struct gpio_chip *gc = d->host_data;
+
+	irq_domain_set_info(d, irq, hwirq, gc->irqchip, d->host_data,
+		gc->irq_handler, NULL, NULL);
+
+	if (gc->can_sleep && !gc->irq_not_threaded)
+		irq_set_nested_thread(irq, 1);
+
+	irq_set_noprobe(irq);
+}
+
+static int msm_gpio_domain_translate(struct irq_domain *d,
+	struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
+{
+	if (is_of_node(fwspec->fwnode)) {
+		if (fwspec->param_count < 2)
+			return -EINVAL;
+		if (hwirq)
+			*hwirq = fwspec->param[0];
+		if (type)
+			*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
+					unsigned int nr_irqs, void *arg)
+{
+	int ret = 0;
+	irq_hw_number_t hwirq;
+	struct irq_fwspec *fwspec = arg, parent_fwspec;
+
+	ret = msm_gpio_domain_translate(domain, fwspec, &hwirq, NULL);
+	if (ret)
+		return ret;
+
+	msm_gpio_domain_set_info(domain, virq, hwirq);
+
+	parent_fwspec = *fwspec;
+	parent_fwspec.fwnode = domain->parent->fwnode;
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+						&parent_fwspec);
+}
+
+static const struct irq_domain_ops msm_gpio_domain_ops = {
+	.translate	= msm_gpio_domain_translate,
+	.alloc		= msm_gpio_domain_alloc,
+	.free		= irq_domain_free_irqs_top,
+};
+
+static struct irq_chip msm_dirconn_irq_chip;
+
+static void msm_gpio_dirconn_handler(struct irq_desc *desc)
+{
+	struct irq_data *irqd = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
+	generic_handle_irq(irqd->irq);
+	chained_irq_exit(chip, desc);
+}
+
+static void setup_pdc_gpio(struct irq_domain *domain,
+			unsigned int parent_irq, unsigned int gpio)
+{
+	int irq;
+
+	if (gpio != 0) {
+		irq = irq_find_mapping(domain, gpio);
+		irq_set_parent(irq, parent_irq);
+		irq_set_chip(irq, &msm_dirconn_irq_chip);
+		irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
+	}
+
+	__irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL);
+}
+
+static void request_dc_interrupt(struct irq_domain *domain,
+			struct irq_domain *parent, irq_hw_number_t hwirq,
+			unsigned int gpio)
+{
+	struct irq_fwspec fwspec;
+	unsigned int parent_irq;
+
+	fwspec.fwnode = parent->fwnode;
+	fwspec.param[0] = 0; /* SPI */
+	fwspec.param[1] = hwirq;
+	fwspec.param[2] = IRQ_TYPE_NONE;
+	fwspec.param_count = 3;
+
+	parent_irq = irq_create_fwspec_mapping(&fwspec);
+
+	setup_pdc_gpio(domain, parent_irq, gpio);
+}
+
+/**
+ * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ
+ *
+ * @pdc_domain: the PDC's domain
+ * @d: the GPIO's IRQ data
+ *
+ * Find a free PDC port for the GPIO and map the GPIO's mux information to the
+ * PDC registers; so the GPIO can be used a wakeup source.
+ */
+static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d)
+{
+	int i, j;
+	unsigned int mux;
+	struct irq_desc *desc = irq_data_to_desc(d);
+	struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = d->hwirq;
+	struct msm_pinctrl *pctrl;
+	unsigned int irq;
+
+	if (!gc || !parent_data)
+		return;
+
+	pctrl = gpiochip_get_data(gc);
+
+	for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) {
+		if (gpio != pctrl->soc->gpio_mux_in[i].gpio)
+			continue;
+		mux = pctrl->soc->gpio_mux_in[i].mux;
+		for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) {
+			struct msm_pdc_mux_output *pdc_out =
+						&pctrl->soc->pdc_mux_out[j];
+
+			if (pdc_out->mux == mux)
+				break;
+			if (pdc_out->mux)
+				continue;
+			pdc_out->mux = gpio;
+			irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32);
+			/* setup the IRQ parent for the GPIO */
+			setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio);
+			/* program pdc select grp register */
+			writel_relaxed((mux & 0x3F), pctrl->pdc_regs +
+				(0x14 * j));
+			break;
+		}
+		/* We have no more PDC port available */
+		WARN_ON(j == pctrl->soc->n_pdc_mux_out);
+	}
+}
+
 static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq)
 {
 	struct irq_desc *desc = irq_data_to_desc(d);
@@ -797,6 +992,17 @@
 			return true;
 		}
 	}
+
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		struct msm_pdc_mux_output *dir_conn =
+					&pctrl->soc->pdc_mux_out[i];
+
+		if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32)
+				!= parent_data->hwirq) {
+			*dir_conn_irq = dir_conn->hwirq + 32;
+			return true;
+		}
+	}
 	return false;
 }
 
@@ -814,13 +1020,48 @@
 			irq_get_irq_data(irq_find_mapping(parent_data->domain,
 						dir_conn_irq));
 
-		if (dir_conn_data && dir_conn_data->chip->irq_mask)
+		if (!dir_conn_data)
+			return;
+		if (dir_conn_data->chip->irq_mask)
 			dir_conn_data->chip->irq_mask(dir_conn_data);
 	}
+
 	if (parent_data->chip->irq_mask)
 		parent_data->chip->irq_mask(parent_data);
 }
 
+static void msm_dirconn_irq_enable(struct irq_data *d)
+{
+	struct irq_desc *desc = irq_data_to_desc(d);
+	struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+	irq_hw_number_t dir_conn_irq = 0;
+
+	if (!parent_data)
+		return;
+
+	if (is_gpio_dual_edge(d, &dir_conn_irq)) {
+		struct irq_data *dir_conn_data =
+			irq_get_irq_data(irq_find_mapping(parent_data->domain,
+						dir_conn_irq));
+
+		if (dir_conn_data &&
+				dir_conn_data->chip->irq_set_irqchip_state)
+			dir_conn_data->chip->irq_set_irqchip_state(
+					dir_conn_data,
+					IRQCHIP_STATE_PENDING, 0);
+
+		if (dir_conn_data && dir_conn_data->chip->irq_unmask)
+			dir_conn_data->chip->irq_unmask(dir_conn_data);
+	}
+
+	if (parent_data->chip->irq_set_irqchip_state)
+		parent_data->chip->irq_set_irqchip_state(parent_data,
+						IRQCHIP_STATE_PENDING, 0);
+
+	if (parent_data->chip->irq_unmask)
+		parent_data->chip->irq_unmask(parent_data);
+}
+
 static void msm_dirconn_irq_unmask(struct irq_data *d)
 {
 	struct irq_desc *desc = irq_data_to_desc(d);
@@ -835,7 +1076,9 @@
 			irq_get_irq_data(irq_find_mapping(parent_data->domain,
 						dir_conn_irq));
 
-		if (dir_conn_data && dir_conn_data->chip->irq_unmask)
+		if (!dir_conn_data)
+			return;
+		if (dir_conn_data->chip->irq_unmask)
 			dir_conn_data->chip->irq_unmask(dir_conn_data);
 	}
 	if (parent_data->chip->irq_unmask)
@@ -1058,6 +1301,7 @@
 static struct irq_chip msm_dirconn_irq_chip = {
 	.name			= "msmgpio-dc",
 	.irq_mask		= msm_dirconn_irq_mask,
+	.irq_enable		= msm_dirconn_irq_enable,
 	.irq_unmask		= msm_dirconn_irq_unmask,
 	.irq_eoi		= msm_dirconn_irq_eoi,
 	.irq_ack		= msm_dirconn_irq_ack,
@@ -1103,58 +1347,66 @@
 	chained_irq_exit(chip, desc);
 }
 
-static void msm_gpio_dirconn_handler(struct irq_desc *desc)
-{
-	struct irq_data *irqd = irq_desc_get_handler_data(desc);
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-
-	chained_irq_enter(chip, desc);
-	generic_handle_irq(irqd->irq);
-	chained_irq_exit(chip, desc);
-}
-
 static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl)
 {
 	struct device_node *parent_node;
-	struct irq_domain *parent_domain;
-	struct irq_fwspec fwspec;
+	struct irq_domain *pdc_domain;
 	unsigned int i;
 
 	parent_node = of_irq_find_parent(pctrl->dev->of_node);
-
 	if (!parent_node)
 		return;
 
-	parent_domain = irq_find_host(parent_node);
-	if (!parent_domain)
+	pdc_domain = irq_find_host(parent_node);
+	if (!pdc_domain)
 		return;
 
-	fwspec.fwnode = parent_domain->fwnode;
 	for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
 		const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i];
-		unsigned int parent_irq;
-		int irq;
 
-		fwspec.param[0] = 0; /* SPI */
-		fwspec.param[1] = dirconn->hwirq;
-		fwspec.param[2] = IRQ_TYPE_NONE;
-		fwspec.param_count = 3;
-		parent_irq = irq_create_fwspec_mapping(&fwspec);
-
-		if (dirconn->gpio != 0) {
-			irq = irq_find_mapping(pctrl->chip.irqdomain,
-					dirconn->gpio);
-
-			irq_set_parent(irq, parent_irq);
-			irq_set_chip(irq, &msm_dirconn_irq_chip);
-			__irq_set_handler(parent_irq, msm_gpio_dirconn_handler,
-				false, NULL);
-			irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
-		} else {
-			__irq_set_handler(parent_irq, msm_gpio_dirconn_handler,
-				false, NULL);
-		}
+		request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
+					dirconn->hwirq, dirconn->gpio);
 	}
+
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		struct msm_pdc_mux_output *pdc_out =
+					&pctrl->soc->pdc_mux_out[i];
+
+		request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
+					pdc_out->hwirq, 0);
+	}
+
+	/*
+	 * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping
+	 * is very difficult.
+	 */
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		unsigned int irq;
+		struct irq_data *d;
+		struct msm_gpio_mux_input *gpio_in =
+					&pctrl->soc->gpio_mux_in[i];
+		if (!gpio_in->init)
+			continue;
+
+		irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio);
+		d = irq_get_irq_data(irq);
+		if (!d)
+			continue;
+
+		gpio_muxed_to_pdc(pdc_domain, d);
+	}
+}
+
+static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+	struct irq_fwspec fwspec;
+
+	fwspec.fwnode = of_node_to_fwnode(chip->of_node);
+	fwspec.param[0] = offset;
+	fwspec.param[1] = IRQ_TYPE_NONE;
+	fwspec.param_count = 2;
+
+	return irq_create_fwspec_mapping(&fwspec);
 }
 
 static int msm_gpio_init(struct msm_pinctrl *pctrl)
@@ -1162,6 +1414,8 @@
 	struct gpio_chip *chip;
 	int ret;
 	unsigned ngpio = pctrl->soc->ngpios;
+	struct device_node *irq_parent = NULL;
+	struct irq_domain *domain_parent;
 
 	if (WARN_ON(ngpio > MAX_NR_GPIO))
 		return -EINVAL;
@@ -1187,19 +1441,45 @@
 		return ret;
 	}
 
-	ret = gpiochip_irqchip_add(chip,
-				   &msm_gpio_irq_chip,
-				   0,
-				   handle_fasteoi_irq,
-				   IRQ_TYPE_NONE);
-	if (ret) {
-		dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
-		gpiochip_remove(&pctrl->chip);
-		return -ENOSYS;
-	}
+	irq_parent = of_irq_find_parent(chip->of_node);
+	if (of_device_is_compatible(irq_parent, "qcom,mpm-gpio")) {
+		chip->irqchip = &msm_gpio_irq_chip;
+		chip->irq_handler = handle_fasteoi_irq;
+		chip->irq_default_type = IRQ_TYPE_NONE;
+		chip->to_irq = msm_gpiochip_to_irq;
+		chip->lock_key = NULL;
+		domain_parent = irq_find_host(irq_parent);
+		if (!domain_parent) {
+			pr_err("unable to find parent domain\n");
+			gpiochip_remove(&pctrl->chip);
+			return -ENXIO;
+		}
 
-	gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq,
-				     msm_gpio_irq_handler);
+		chip->irqdomain = irq_domain_add_hierarchy(domain_parent, 0,
+							chip->ngpio,
+							chip->of_node,
+							&msm_gpio_domain_ops,
+							chip);
+		if (!chip->irqdomain) {
+			dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
+			chip->irqchip = NULL;
+			gpiochip_remove(&pctrl->chip);
+			return -ENXIO;
+		}
+	} else {
+		ret = gpiochip_irqchip_add(chip,
+					&msm_gpio_irq_chip,
+					0,
+					handle_fasteoi_irq,
+					IRQ_TYPE_NONE);
+		if (ret) {
+			dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
+			gpiochip_remove(&pctrl->chip);
+			return ret;
+		}
+	}
+	gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip,
+				pctrl->irq, msm_gpio_irq_handler);
 
 	msm_gpio_setup_dir_connects(pctrl);
 	return 0;
@@ -1263,6 +1543,9 @@
 	if (IS_ERR(pctrl->regs))
 		return PTR_ERR(pctrl->regs);
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res);
+
 	msm_pinctrl_setup_pm_reset(pctrl);
 
 	pctrl->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 1c6df2f..9fc6660 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013, Sony Mobile Communications AB.
+ * Copyright (c) 2018, 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
@@ -99,13 +100,35 @@
 	unsigned intr_detection_bit:5;
 	unsigned intr_detection_width:5;
 	unsigned dir_conn_en_bit:8;
-}
+};
+
+/**
+ * struct msm_gpio_mux_input - Map GPIO to Mux pin
+ * @mux::	The mux pin to which the GPIO is connected to
+ * @gpio:	GPIO pin number
+ * @init:	Setup PDC connection at probe
+ */
+struct msm_gpio_mux_input {
+	unsigned int mux;
+	unsigned int gpio;
+	bool init;
+};
+
+/**
+ * struct msm_pdc_mux_output - GPIO mux pin to PDC port
+ * @mux:	GPIO mux pin number
+ * @hwirq:	The PDC port (hwirq) that GPIO is connected to
+ */
+struct msm_pdc_mux_output {
+	unsigned int mux;
+	irq_hw_number_t hwirq;
+};
 
 /**
  * struct msm_dir_conn - Direct GPIO connect configuration
  * @gpio:	GPIO pin number
  * @hwirq:	The GIC interrupt that the pin is connected to
- */;
+ */
 struct msm_dir_conn {
 	unsigned int gpio;
 	irq_hw_number_t hwirq;
@@ -122,8 +145,12 @@
  * @ngpio:      The number of pingroups the driver should expose as GPIOs.
  * @dir_conn:   An array describing all the pins directly connected to GIC.
  * @ndirconns:  The number of pins directly connected to GIC
- * @dir_conn_offsets:   Direct connect register offsets for each tile.
  * @dir_conn_irq_base:  Direct connect interrupt base register for kpss.
+ * @gpio_mux_in:	Map of GPIO pin to the hwirq.
+ * @n_gpioc_mux_in:	The number of entries in @pdc_mux_in.
+ * @pdc_mux_out:	Map of GPIO mux to PDC port.
+ * @n_pdc_mux_out:	The number of entries in @pdc_mux_out.
+ * @n_pdc_offset:	The offset for the PDC mux pins
  */
 struct msm_pinctrl_soc_data {
 	const struct pinctrl_pin_desc *pins;
@@ -136,6 +163,11 @@
 	const struct msm_dir_conn *dir_conn;
 	unsigned int n_dir_conns;
 	unsigned int dir_conn_irq_base;
+	struct msm_pdc_mux_output *pdc_mux_out;
+	unsigned int n_pdc_mux_out;
+	struct msm_gpio_mux_input *gpio_mux_in;
+	unsigned int n_gpio_mux_in;
+	unsigned int n_pdc_mux_offset;
 };
 
 int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c
new file mode 100644
index 0000000..c8c3de7
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)			                \
+	[msm_mux_##fname] = {		                \
+		.name = #fname,				\
+		.groups = fname##_groups,               \
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)	\
+	{					        \
+		.name = "gpio" #id,			\
+		.pins = gpio##id##_pins,		\
+		.npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),	\
+		.funcs = (int[]){			\
+			msm_mux_gpio, /* gpio mode */	\
+			msm_mux_##f1,			\
+			msm_mux_##f2,			\
+			msm_mux_##f3,			\
+			msm_mux_##f4,			\
+			msm_mux_##f5,			\
+			msm_mux_##f6,			\
+			msm_mux_##f7,			\
+			msm_mux_##f8,			\
+			msm_mux_##f9			\
+		},				        \
+		.nfuncs = 10,				\
+		.ctl_reg = REG_BASE + REG_SIZE * id,			\
+		.io_reg = REG_BASE + 0x4 + REG_SIZE * id,		\
+		.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,		\
+		.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,	\
+		.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,	\
+		.mux_bit = 2,			\
+		.pull_bit = 0,			\
+		.drv_bit = 6,			\
+		.oe_bit = 9,			\
+		.in_bit = 0,			\
+		.out_bit = 1,			\
+		.intr_enable_bit = 0,		\
+		.intr_status_bit = 0,		\
+		.intr_target_bit = 5,		\
+		.intr_target_kpss_val = 4,       \
+		.intr_raw_status_bit = 4,	\
+		.intr_polarity_bit = 1,		\
+		.intr_detection_bit = 2,	\
+		.intr_detection_width = 2,	\
+	}
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+static const struct pinctrl_pin_desc msm8909_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "SDC1_CLK"),
+	PINCTRL_PIN(114, "SDC1_CMD"),
+	PINCTRL_PIN(115, "SDC1_DATA"),
+	PINCTRL_PIN(116, "SDC2_CLK"),
+	PINCTRL_PIN(117, "SDC2_CMD"),
+	PINCTRL_PIN(118, "SDC2_DATA"),
+	PINCTRL_PIN(119, "QDSD_CLK"),
+	PINCTRL_PIN(120, "QDSD_CMD"),
+	PINCTRL_PIN(121, "QDSD_DATA0"),
+	PINCTRL_PIN(122, "QDSD_DATA1"),
+	PINCTRL_PIN(123, "QDSD_DATA2"),
+	PINCTRL_PIN(124, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+
+static const unsigned int sdc1_clk_pins[] = { 113 };
+static const unsigned int sdc1_cmd_pins[] = { 114 };
+static const unsigned int sdc1_data_pins[] = { 115 };
+static const unsigned int sdc2_clk_pins[] = { 116 };
+static const unsigned int sdc2_cmd_pins[] = { 117 };
+static const unsigned int sdc2_data_pins[] = { 118 };
+static const unsigned int qdsd_clk_pins[] = { 119 };
+static const unsigned int qdsd_cmd_pins[] = { 120 };
+static const unsigned int qdsd_data0_pins[] = { 121 };
+static const unsigned int qdsd_data1_pins[] = { 122 };
+static const unsigned int qdsd_data2_pins[] = { 123 };
+static const unsigned int qdsd_data3_pins[] = { 124 };
+
+enum msm8909_functions {
+	msm_mux_blsp_spi3,
+	msm_mux_gpio,
+	msm_mux_sec_mi2s,
+	msm_mux_blsp_spi1,
+	msm_mux_blsp_uart1,
+	msm_mux_blsp_uim1,
+	msm_mux_blsp3_spi,
+	msm_mux_dmic0_clk,
+	msm_mux_qdss_tracectl_b,
+	msm_mux_blsp2_spi,
+	msm_mux_dmic0_data,
+	msm_mux_qdss_traceclk_b,
+	msm_mux_blsp_i2c1,
+	msm_mux_qdss_tracedata_a,
+	msm_mux_bimc_dte0,
+	msm_mux_bimc_dte1,
+	msm_mux_blsp_spi6,
+	msm_mux_m_voc,
+	msm_mux_blsp_i2c6,
+	msm_mux_dbg_out,
+	msm_mux_blsp_spi4,
+	msm_mux_gcc_gp2_clk_b,
+	msm_mux_gcc_gp3_clk_b,
+	msm_mux_blsp_i2c4,
+	msm_mux_gcc_gp1_clk_b,
+	msm_mux_qdss_tracedata_b,
+	msm_mux_blsp_spi5,
+	msm_mux_blsp_i2c5,
+	msm_mux_uim3_clk,
+	msm_mux_qdss_cti_trig_out_a0,
+	msm_mux_mdp_vsync,
+	msm_mux_ebi2_lcd,
+	msm_mux_dsi_rst,
+	msm_mux_cam_mclk,
+	msm_mux_uim3_data,
+	msm_mux_blsp_spi2,
+	msm_mux_blsp_uart2,
+	msm_mux_blsp_uim2,
+	msm_mux_qdss_cti_trig_in_a0,
+	msm_mux_uim3_present,
+	msm_mux_qdss_cti_trig_in_b0,
+	msm_mux_uim3_reset,
+	msm_mux_qdss_cti_trig_out_b0,
+	msm_mux_webcam1_rst,
+	msm_mux_pwr_modem_enabled_a,
+	msm_mux_blsp_i2c3,
+	msm_mux_flash_strobe,
+	msm_mux_cci_timer0,
+	msm_mux_cci_timer1,
+	msm_mux_atest_combodac_to_gpio_native,
+	msm_mux_cci_async,
+	msm_mux_cam1_standby,
+	msm_mux_pwr_nav_enabled_a,
+	msm_mux_cam1_rst,
+	msm_mux_pwr_crypto_enabled_a,
+	msm_mux_atest_bbrx1,
+	msm_mux_backlight_en,
+	msm_mux_blsp1_spi,
+	msm_mux_atest_bbrx0,
+	msm_mux_sd_card,
+	msm_mux_cci_timer2,
+	msm_mux_adsp_ext,
+	msm_mux_wcss_bt,
+	msm_mux_wcss_wlan2,
+	msm_mux_wcss_wlan1,
+	msm_mux_wcss_wlan0,
+	msm_mux_wcss_wlan,
+	msm_mux_prng_rosc,
+	msm_mux_wcss_fm,
+	msm_mux_ext_lpass,
+	msm_mux_qdss_tracectl_a,
+	msm_mux_qdss_traceclk_a,
+	msm_mux_uim2_data,
+	msm_mux_gcc_gp1_clk_a,
+	msm_mux_qdss_cti_trig_in_a1,
+	msm_mux_uim2_clk,
+	msm_mux_gcc_gp2_clk_a,
+	msm_mux_qdss_cti_trig_in_b1,
+	msm_mux_uim2_reset,
+	msm_mux_gcc_gp3_clk_a,
+	msm_mux_qdss_cti_trig_out_b1,
+	msm_mux_uim2_present,
+	msm_mux_qdss_cti_trig_out_a1,
+	msm_mux_uim1_data,
+	msm_mux_uim1_clk,
+	msm_mux_uim1_reset,
+	msm_mux_uim1_present,
+	msm_mux_uim_batt,
+	msm_mux_smb_int,
+	msm_mux_cdc_pdm0,
+	msm_mux_pri_mi2s_mclk_a,
+	msm_mux_atest_char3,
+	msm_mux_pri_mi2s_sck_a,
+	msm_mux_atest_char2,
+	msm_mux_pri_mi2s_ws_a,
+	msm_mux_atest_char1,
+	msm_mux_pri_mi2s_data0_a,
+	msm_mux_atest_char0,
+	msm_mux_atest_gpsadc_dtest0_native,
+	msm_mux_gcc_plltest,
+	msm_mux_pri_mi2s_data1_a,
+	msm_mux_atest_char,
+	msm_mux_atest_tsens,
+	msm_mux_ebi0_wrcdc,
+	msm_mux_mag_int,
+	msm_mux_atest_gpsadc_dtest1_native,
+	msm_mux_pa_indicator,
+	msm_mux_modem_tsync,
+	msm_mux_nav_tsync,
+	msm_mux_nav_pps,
+	msm_mux_gsm0_tx,
+	msm_mux_ssbi0,
+	msm_mux_ssbi1,
+	msm_mux_kpsns0,
+	msm_mux_pbs0,
+	msm_mux_kpsns1,
+	msm_mux_pbs1,
+	msm_mux_kpsns2,
+	msm_mux_pbs2,
+	msm_mux_ext_buck,
+	msm_mux_alsp_int,
+	msm_mux_pri_mi2s_sck_b,
+	msm_mux_pwr_modem_enabled_b,
+	msm_mux_pri_mi2s_data0_b,
+	msm_mux_pwr_nav_enabled_b,
+	msm_mux_gyro_accl,
+	msm_mux_pri_mi2s_data1_b,
+	msm_mux_pwr_crypto_enabled_b,
+	msm_mux_atest_wlan0,
+	msm_mux_euro_us,
+	msm_mux_atest_wlan1,
+	msm_mux_pri_mi2s_mclk_b,
+	msm_mux_ldo_update,
+	msm_mux_gcc_tlmm,
+	msm_mux_ebi2_a,
+	msm_mux_sd_write,
+	msm_mux_ldo_en,
+	msm_mux_msim_int,
+	msm_mux_pri_mi2s_ws_b,
+	msm_mux_blsp_i2c2,
+	msm_mux_NA,
+};
+
+static const char * const blsp_spi3_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+	"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+	"gpio50",  "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64",  "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+	"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+	"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+	"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+	"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+	"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+	"gpio111", "gpio112",
+};
+static const char * const sec_mi2s_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio98",
+};
+static const char * const blsp_spi1_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart1_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uim1_groups[] = {
+	"gpio4", "gpio5",
+};
+static const char * const blsp3_spi_groups[] = {
+	"gpio4", "gpio65", "gpio95",
+};
+static const char * const dmic0_clk_groups[] = {
+	"gpio4",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+	"gpio4",
+};
+static const char * const blsp2_spi_groups[] = {
+	"gpio5", "gpio17", "gpio98",
+};
+static const char * const dmic0_data_groups[] = {
+	"gpio5",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+	"gpio5",
+};
+static const char * const blsp_i2c1_groups[] = {
+	"gpio6", "gpio7",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+	"gpio6", "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41",
+	"gpio42", "gpio43", "gpio47", "gpio48", "gpio58", "gpio65", "gpio94",
+	"gpio96", "gpio97",
+};
+static const char * const bimc_dte0_groups[] = {
+	"gpio6", "gpio59",
+};
+static const char * const bimc_dte1_groups[] = {
+	"gpio7", "gpio60",
+};
+static const char * const blsp_spi6_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const m_voc_groups[] = {
+	"gpio8", "gpio95",
+};
+static const char * const blsp_i2c6_groups[] = {
+	"gpio10", "gpio11",
+};
+static const char * const dbg_out_groups[] = {
+	"gpio10",
+};
+static const char * const blsp_spi4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+	"gpio12",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+	"gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+	"gpio14", "gpio15",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+	"gpio14",
+};
+static const char * const qdss_tracedata_b_groups[] = {
+	"gpio14", "gpio16", "gpio17", "gpio26", "gpio27", "gpio28", "gpio29",
+	"gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
+	"gpio37", "gpio93",
+};
+static const char * const blsp_spi5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_i2c5_groups[] = {
+	"gpio18", "gpio19",
+};
+static const char * const uim3_clk_groups[] = {
+	"gpio23",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+	"gpio23",
+};
+static const char * const mdp_vsync_groups[] = {
+	"gpio24", "gpio25",
+};
+static const char * const ebi2_lcd_groups[] = {
+	"gpio24", "gpio24", "gpio25", "gpio95",
+};
+static const char * const dsi_rst_groups[] = {
+	"gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+	"gpio26", "gpio27",
+};
+static const char * const uim3_data_groups[] = {
+	"gpio20",
+};
+static const char * const blsp_spi2_groups[] = {
+	"gpio20", "gpio21", "gpio111", "gpio112",
+};
+static const char * const blsp_uart2_groups[] = {
+	"gpio20", "gpio21", "gpio111", "gpio112",
+};
+static const char * const blsp_uim2_groups[] = {
+	"gpio20", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+	"gpio20",
+};
+static const char * const uim3_present_groups[] = {
+	"gpio21",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+	"gpio21",
+};
+static const char * const uim3_reset_groups[] = {
+	"gpio22",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+	"gpio22",
+};
+static const char * const webcam1_rst_groups[] = {
+	"gpio28",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+	"gpio28",
+};
+static const char * const blsp_i2c3_groups[] = {
+	"gpio29", "gpio30",
+};
+static const char * const flash_strobe_groups[] = {
+	"gpio31", "gpio32",
+};
+static const char * const cci_timer0_groups[] = {
+	"gpio31",
+};
+static const char * const cci_timer1_groups[] = {
+	"gpio32",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+	"gpio32", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+	"gpio44", "gpio45", "gpio47", "gpio48", "gpio66", "gpio81", "gpio83",
+	"gpio84", "gpio85", "gpio86", "gpio94", "gpio95", "gpio110",
+};
+static const char * const cci_async_groups[] = {
+	"gpio33",
+};
+static const char * const cam1_standby_groups[] = {
+	"gpio34",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+	"gpio34",
+};
+static const char * const cam1_rst_groups[] = {
+	"gpio35",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+	"gpio35",
+};
+static const char * const atest_bbrx1_groups[] = {
+	"gpio36",
+};
+static const char * const backlight_en_groups[] = {
+	"gpio37",
+};
+static const char * const blsp1_spi_groups[] = {
+	"gpio37", "gpio65", "gpio97",
+};
+static const char * const atest_bbrx0_groups[] = {
+	"gpio37",
+};
+static const char * const sd_card_groups[] = {
+	"gpio38",
+};
+static const char * const cci_timer2_groups[] = {
+	"gpio38",
+};
+static const char * const adsp_ext_groups[] = {
+	"gpio38",
+};
+static const char * const wcss_bt_groups[] = {
+	"gpio39", "gpio47", "gpio48",
+};
+static const char * const wcss_wlan2_groups[] = {
+	"gpio40",
+};
+static const char * const wcss_wlan1_groups[] = {
+	"gpio41",
+};
+static const char * const wcss_wlan0_groups[] = {
+	"gpio42",
+};
+static const char * const wcss_wlan_groups[] = {
+	"gpio43", "gpio44",
+};
+static const char * const prng_rosc_groups[] = {
+	"gpio43",
+};
+static const char * const wcss_fm_groups[] = {
+	"gpio45", "gpio46",
+};
+static const char * const ext_lpass_groups[] = {
+	"gpio45",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+	"gpio45",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+	"gpio46",
+};
+static const char * const uim2_data_groups[] = {
+	"gpio49",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+	"gpio49",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+	"gpio49",
+};
+static const char * const uim2_clk_groups[] = {
+	"gpio50",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+	"gpio50",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+	"gpio50",
+};
+static const char * const uim2_reset_groups[] = {
+	"gpio51",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+	"gpio51",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+	"gpio51",
+};
+static const char * const uim2_present_groups[] = {
+	"gpio52",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+	"gpio52",
+};
+static const char * const uim1_data_groups[] = {
+	"gpio53",
+};
+static const char * const uim1_clk_groups[] = {
+	"gpio54",
+};
+static const char * const uim1_reset_groups[] = {
+	"gpio55",
+};
+static const char * const uim1_present_groups[] = {
+	"gpio56",
+};
+static const char * const uim_batt_groups[] = {
+	"gpio57",
+};
+static const char * const smb_int_groups[] = {
+	"gpio58",
+};
+static const char * const cdc_pdm0_groups[] = {
+	"gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+	"gpio59",
+};
+static const char * const atest_char3_groups[] = {
+	"gpio59",
+};
+static const char * const pri_mi2s_sck_a_groups[] = {
+	"gpio60",
+};
+static const char * const atest_char2_groups[] = {
+	"gpio60",
+};
+static const char * const pri_mi2s_ws_a_groups[] = {
+	"gpio61",
+};
+static const char * const atest_char1_groups[] = {
+	"gpio61",
+};
+static const char * const pri_mi2s_data0_a_groups[] = {
+	"gpio62",
+};
+static const char * const atest_char0_groups[] = {
+	"gpio62",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+	"gpio65",
+};
+static const char * const gcc_plltest_groups[] = {
+	"gpio66", "gpio67",
+};
+static const char * const pri_mi2s_data1_a_groups[] = {
+	"gpio63",
+};
+static const char * const atest_char_groups[] = {
+	"gpio63",
+};
+static const char * const atest_tsens_groups[] = {
+	"gpio63",
+};
+static const char * const ebi0_wrcdc_groups[] = {
+	"gpio64",
+};
+static const char * const mag_int_groups[] = {
+	"gpio65",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+	"gpio79",
+};
+static const char * const pa_indicator_groups[] = {
+	"gpio82",
+};
+static const char * const modem_tsync_groups[] = {
+	"gpio83",
+};
+static const char * const nav_tsync_groups[] = {
+	"gpio83",
+};
+static const char * const nav_pps_groups[] = {
+	"gpio83",
+};
+static const char * const gsm0_tx_groups[] = {
+	"gpio85",
+};
+static const char * const ssbi0_groups[] = {
+	"gpio88",
+};
+static const char * const ssbi1_groups[] = {
+	"gpio89",
+};
+static const char * const kpsns0_groups[] = {
+	"gpio90",
+};
+static const char * const pbs0_groups[] = {
+	"gpio90",
+};
+static const char * const kpsns1_groups[] = {
+	"gpio91",
+};
+static const char * const pbs1_groups[] = {
+	"gpio91",
+};
+static const char * const kpsns2_groups[] = {
+	"gpio92",
+};
+static const char * const pbs2_groups[] = {
+	"gpio92",
+};
+static const char * const ext_buck_groups[] = {
+	"gpio93",
+};
+static const char * const alsp_int_groups[] = {
+	"gpio94",
+};
+static const char * const pri_mi2s_sck_b_groups[] = {
+	"gpio94",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+	"gpio94",
+};
+static const char * const pri_mi2s_data0_b_groups[] = {
+	"gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+	"gpio95",
+};
+static const char * const gyro_accl_groups[] = {
+	"gpio96",
+};
+static const char * const pri_mi2s_data1_b_groups[] = {
+	"gpio96",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+	"gpio96",
+};
+static const char * const atest_wlan0_groups[] = {
+	"gpio96",
+};
+static const char * const euro_us_groups[] = {
+	"gpio97",
+};
+static const char * const atest_wlan1_groups[] = {
+	"gpio97",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+	"gpio98",
+};
+static const char * const ldo_update_groups[] = {
+	"gpio98",
+};
+static const char * const gcc_tlmm_groups[] = {
+	"gpio98",
+};
+static const char * const ebi2_a_groups[] = {
+	"gpio99",
+};
+static const char * const sd_write_groups[] = {
+	"gpio99",
+};
+static const char * const ldo_en_groups[] = {
+	"gpio99",
+};
+static const char * const msim_int_groups[] = {
+	"gpio110",
+};
+static const char * const pri_mi2s_ws_b_groups[] = {
+	"gpio110",
+};
+static const char * const blsp_i2c2_groups[] = {
+	"gpio111", "gpio112",
+};
+
+static const struct msm_function msm8909_functions[] = {
+	FUNCTION(blsp_spi3),
+	FUNCTION(gpio),
+	FUNCTION(sec_mi2s),
+	FUNCTION(blsp_spi1),
+	FUNCTION(blsp_uart1),
+	FUNCTION(blsp_uim1),
+	FUNCTION(blsp3_spi),
+	FUNCTION(dmic0_clk),
+	FUNCTION(qdss_tracectl_b),
+	FUNCTION(blsp2_spi),
+	FUNCTION(dmic0_data),
+	FUNCTION(qdss_traceclk_b),
+	FUNCTION(blsp_i2c1),
+	FUNCTION(qdss_tracedata_a),
+	FUNCTION(bimc_dte0),
+	FUNCTION(bimc_dte1),
+	FUNCTION(blsp_spi6),
+	FUNCTION(m_voc),
+	FUNCTION(blsp_i2c6),
+	FUNCTION(dbg_out),
+	FUNCTION(blsp_spi4),
+	FUNCTION(gcc_gp2_clk_b),
+	FUNCTION(gcc_gp3_clk_b),
+	FUNCTION(blsp_i2c4),
+	FUNCTION(gcc_gp1_clk_b),
+	FUNCTION(qdss_tracedata_b),
+	FUNCTION(blsp_spi5),
+	FUNCTION(blsp_i2c5),
+	FUNCTION(uim3_clk),
+	FUNCTION(qdss_cti_trig_out_a0),
+	FUNCTION(mdp_vsync),
+	FUNCTION(ebi2_lcd),
+	FUNCTION(dsi_rst),
+	FUNCTION(cam_mclk),
+	FUNCTION(uim3_data),
+	FUNCTION(blsp_spi2),
+	FUNCTION(blsp_uart2),
+	FUNCTION(blsp_uim2),
+	FUNCTION(qdss_cti_trig_in_a0),
+	FUNCTION(uim3_present),
+	FUNCTION(qdss_cti_trig_in_b0),
+	FUNCTION(uim3_reset),
+	FUNCTION(qdss_cti_trig_out_b0),
+	FUNCTION(webcam1_rst),
+	FUNCTION(pwr_modem_enabled_a),
+	FUNCTION(blsp_i2c3),
+	FUNCTION(flash_strobe),
+	FUNCTION(cci_timer0),
+	FUNCTION(cci_timer1),
+	FUNCTION(atest_combodac_to_gpio_native),
+	FUNCTION(cci_async),
+	FUNCTION(cam1_standby),
+	FUNCTION(pwr_nav_enabled_a),
+	FUNCTION(cam1_rst),
+	FUNCTION(pwr_crypto_enabled_a),
+	FUNCTION(atest_bbrx1),
+	FUNCTION(backlight_en),
+	FUNCTION(blsp1_spi),
+	FUNCTION(atest_bbrx0),
+	FUNCTION(sd_card),
+	FUNCTION(cci_timer2),
+	FUNCTION(adsp_ext),
+	FUNCTION(wcss_bt),
+	FUNCTION(wcss_wlan2),
+	FUNCTION(wcss_wlan1),
+	FUNCTION(wcss_wlan0),
+	FUNCTION(wcss_wlan),
+	FUNCTION(prng_rosc),
+	FUNCTION(wcss_fm),
+	FUNCTION(ext_lpass),
+	FUNCTION(qdss_tracectl_a),
+	FUNCTION(qdss_traceclk_a),
+	FUNCTION(uim2_data),
+	FUNCTION(gcc_gp1_clk_a),
+	FUNCTION(qdss_cti_trig_in_a1),
+	FUNCTION(uim2_clk),
+	FUNCTION(gcc_gp2_clk_a),
+	FUNCTION(qdss_cti_trig_in_b1),
+	FUNCTION(uim2_reset),
+	FUNCTION(gcc_gp3_clk_a),
+	FUNCTION(qdss_cti_trig_out_b1),
+	FUNCTION(uim2_present),
+	FUNCTION(qdss_cti_trig_out_a1),
+	FUNCTION(uim1_data),
+	FUNCTION(uim1_clk),
+	FUNCTION(uim1_reset),
+	FUNCTION(uim1_present),
+	FUNCTION(uim_batt),
+	FUNCTION(smb_int),
+	FUNCTION(cdc_pdm0),
+	FUNCTION(pri_mi2s_mclk_a),
+	FUNCTION(atest_char3),
+	FUNCTION(pri_mi2s_sck_a),
+	FUNCTION(atest_char2),
+	FUNCTION(pri_mi2s_ws_a),
+	FUNCTION(atest_char1),
+	FUNCTION(pri_mi2s_data0_a),
+	FUNCTION(atest_char0),
+	FUNCTION(atest_gpsadc_dtest0_native),
+	FUNCTION(gcc_plltest),
+	FUNCTION(pri_mi2s_data1_a),
+	FUNCTION(atest_char),
+	FUNCTION(atest_tsens),
+	FUNCTION(ebi0_wrcdc),
+	FUNCTION(mag_int),
+	FUNCTION(atest_gpsadc_dtest1_native),
+	FUNCTION(pa_indicator),
+	FUNCTION(modem_tsync),
+	FUNCTION(nav_tsync),
+	FUNCTION(nav_pps),
+	FUNCTION(gsm0_tx),
+	FUNCTION(ssbi0),
+	FUNCTION(ssbi1),
+	FUNCTION(kpsns0),
+	FUNCTION(pbs0),
+	FUNCTION(kpsns1),
+	FUNCTION(pbs1),
+	FUNCTION(kpsns2),
+	FUNCTION(pbs2),
+	FUNCTION(ext_buck),
+	FUNCTION(alsp_int),
+	FUNCTION(pri_mi2s_sck_b),
+	FUNCTION(pwr_modem_enabled_b),
+	FUNCTION(pri_mi2s_data0_b),
+	FUNCTION(pwr_nav_enabled_b),
+	FUNCTION(gyro_accl),
+	FUNCTION(pri_mi2s_data1_b),
+	FUNCTION(pwr_crypto_enabled_b),
+	FUNCTION(atest_wlan0),
+	FUNCTION(euro_us),
+	FUNCTION(atest_wlan1),
+	FUNCTION(pri_mi2s_mclk_b),
+	FUNCTION(ldo_update),
+	FUNCTION(gcc_tlmm),
+	FUNCTION(ebi2_a),
+	FUNCTION(sd_write),
+	FUNCTION(ldo_en),
+	FUNCTION(msim_int),
+	FUNCTION(pri_mi2s_ws_b),
+	FUNCTION(blsp_i2c2),
+};
+
+static const struct msm_pingroup msm8909_groups[] = {
+	PINGROUP(0, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(1, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(2, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(3, blsp_spi3, sec_mi2s, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(4, blsp_spi1, blsp_uart1, blsp_uim1, blsp3_spi, dmic0_clk, NA,
+		 NA, NA, NA),
+	PINGROUP(5, blsp_spi1, blsp_uart1, blsp_uim1, blsp2_spi, dmic0_data,
+		 NA, NA, NA, NA),
+	PINGROUP(6, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+	PINGROUP(7, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA,
+		 bimc_dte1),
+	PINGROUP(8, blsp_spi6, m_voc, NA, NA, NA, NA, NA, qdss_tracedata_a, NA),
+	PINGROUP(9, blsp_spi6, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+	PINGROUP(10, blsp_spi6, blsp_i2c6, dbg_out, qdss_tracedata_a, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(11, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(14, blsp_spi4, blsp_i2c4, gcc_gp1_clk_b, NA, NA, NA, NA, NA,
+		 qdss_tracedata_b),
+	PINGROUP(15, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(16, blsp_spi5, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+	PINGROUP(17, blsp_spi5, blsp2_spi, NA, NA, NA, NA, NA,
+		 qdss_tracedata_b, NA),
+	PINGROUP(18, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(19, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(20, uim3_data, blsp_spi2, blsp_uart2, blsp_uim2, NA,
+		 qdss_cti_trig_in_a0, NA, NA, NA),
+	PINGROUP(21, uim3_present, blsp_spi2, blsp_uart2, blsp_uim2, NA,
+		 qdss_cti_trig_in_b0, NA, NA, NA),
+	PINGROUP(22, uim3_reset, NA, qdss_cti_trig_out_b0, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(23, uim3_clk, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(24, mdp_vsync, ebi2_lcd, ebi2_lcd, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, mdp_vsync, ebi2_lcd, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(28, NA, pwr_modem_enabled_a, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(29, blsp_i2c3, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+	PINGROUP(30, blsp_i2c3, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+	PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, qdss_tracedata_b, NA),
+	PINGROUP(32, cci_timer1, NA, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(33, cci_async, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(34, pwr_nav_enabled_a, qdss_tracedata_b, NA, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(35, pwr_crypto_enabled_a, qdss_tracedata_b, NA, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(36, qdss_tracedata_b, NA, atest_bbrx1, NA, NA, NA, NA, NA, NA),
+	PINGROUP(37, blsp1_spi, qdss_tracedata_b, NA, atest_bbrx0, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(38, cci_timer2, adsp_ext, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA, NA),
+	PINGROUP(39, wcss_bt, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(40, wcss_wlan2, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(41, wcss_wlan1, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(42, wcss_wlan0, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(44, wcss_wlan, NA, atest_combodac_to_gpio_native, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(46, wcss_fm, qdss_traceclk_a, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(47, wcss_bt, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(48, wcss_bt, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(49, uim2_data, gcc_gp1_clk_a, qdss_cti_trig_in_a1, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(50, uim2_clk, gcc_gp2_clk_a, qdss_cti_trig_in_b1, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(51, uim2_reset, gcc_gp3_clk_a, qdss_cti_trig_out_b1, NA, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(52, uim2_present, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(53, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, qdss_tracedata_a, smb_int, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, cdc_pdm0, pri_mi2s_mclk_a, atest_char3, NA, NA, NA, NA,
+		 NA, bimc_dte0),
+	PINGROUP(60, cdc_pdm0, pri_mi2s_sck_a, atest_char2, NA, NA, NA, NA, NA,
+		 bimc_dte1),
+	PINGROUP(61, cdc_pdm0, pri_mi2s_ws_a, atest_char1, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(62, cdc_pdm0, pri_mi2s_data0_a, atest_char0, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(63, cdc_pdm0, pri_mi2s_data1_a, atest_char, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(64, cdc_pdm0, NA, NA, NA, NA, NA, ebi0_wrcdc, NA, NA),
+	PINGROUP(65, blsp3_spi, blsp1_spi, qdss_tracedata_a, NA,
+		 atest_gpsadc_dtest0_native, NA, NA, NA, NA),
+	PINGROUP(66, NA, gcc_plltest, NA, atest_combodac_to_gpio_native, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(67, NA, gcc_plltest, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(68, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(69, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(79, NA, NA, atest_gpsadc_dtest1_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(81, NA, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(82, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(83, NA, modem_tsync, nav_tsync, nav_pps, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA),
+	PINGROUP(84, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(85, gsm0_tx, NA, NA, atest_combodac_to_gpio_native, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(86, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(88, NA, ssbi0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(89, NA, ssbi1, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(90, pbs0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(91, pbs1, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(92, pbs2, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(93, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(94, pri_mi2s_sck_b, pwr_modem_enabled_b, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(95, blsp3_spi, pri_mi2s_data0_b, ebi2_lcd, m_voc,
+		 pwr_nav_enabled_b, NA, atest_combodac_to_gpio_native, NA, NA),
+	PINGROUP(96, pri_mi2s_data1_b, NA, pwr_crypto_enabled_b,
+		 qdss_tracedata_a, NA, atest_wlan0, NA, NA, NA),
+	PINGROUP(97, blsp1_spi, qdss_tracedata_a, NA, atest_wlan1, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(98, sec_mi2s, pri_mi2s_mclk_b, blsp2_spi, ldo_update, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(99, ebi2_a, sd_write, ldo_en, NA, NA, NA, NA, NA, NA),
+	PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(110, pri_mi2s_ws_b, NA, atest_combodac_to_gpio_native, NA, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(111, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+	PINGROUP(112, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+	SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+	SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+	SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+	SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+	SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+	SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+	SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+	SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8909_pinctrl = {
+	.pins = msm8909_pins,
+	.npins = ARRAY_SIZE(msm8909_pins),
+	.functions = msm8909_functions,
+	.nfunctions = ARRAY_SIZE(msm8909_functions),
+	.groups = msm8909_groups,
+	.ngroups = ARRAY_SIZE(msm8909_groups),
+	.ngpios = 113,
+};
+
+static int msm8909_pinctrl_probe(struct platform_device *pdev)
+{
+	return msm_pinctrl_probe(pdev, &msm8909_pinctrl);
+}
+
+static const struct of_device_id msm8909_pinctrl_of_match[] = {
+	{ .compatible = "qcom,msm8909-pinctrl", },
+	{ },
+};
+
+static struct platform_driver msm8909_pinctrl_driver = {
+	.driver = {
+		.name = "msm8909-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = msm8909_pinctrl_of_match,
+	},
+	.probe = msm8909_pinctrl_probe,
+	.remove = msm_pinctrl_remove,
+};
+
+static int __init msm8909_pinctrl_init(void)
+{
+	return platform_driver_register(&msm8909_pinctrl_driver);
+}
+arch_initcall(msm8909_pinctrl_init);
+
+static void __exit msm8909_pinctrl_exit(void)
+{
+	platform_driver_unregister(&msm8909_pinctrl_driver);
+}
+module_exit(msm8909_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8909 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8909_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8917.c b/drivers/pinctrl/qcom/pinctrl-msm8917.c
new file mode 100644
index 0000000..1c0c64c
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8917.c
@@ -0,0 +1,1474 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)			                \
+	[msm_mux_##fname] = {		                \
+		.name = #fname,				\
+		.groups = fname##_groups,               \
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)	\
+	{					        \
+		.name = "gpio" #id,			\
+		.pins = gpio##id##_pins,		\
+		.npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),	\
+		.funcs = (int[]){			\
+			msm_mux_gpio, /* gpio mode */	\
+			msm_mux_##f1,			\
+			msm_mux_##f2,			\
+			msm_mux_##f3,			\
+			msm_mux_##f4,			\
+			msm_mux_##f5,			\
+			msm_mux_##f6,			\
+			msm_mux_##f7,			\
+			msm_mux_##f8,			\
+			msm_mux_##f9			\
+		},				        \
+		.nfuncs = 10,				\
+		.ctl_reg = REG_BASE + REG_SIZE * id,			\
+		.io_reg = REG_BASE + 0x4 + REG_SIZE * id,		\
+		.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,		\
+		.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,	\
+		.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,	\
+		.mux_bit = 2,			\
+		.pull_bit = 0,			\
+		.drv_bit = 6,			\
+		.oe_bit = 9,			\
+		.in_bit = 0,			\
+		.out_bit = 1,			\
+		.intr_enable_bit = 0,		\
+		.intr_status_bit = 0,		\
+		.intr_target_bit = 5,		\
+		.intr_target_kpss_val = 4,	\
+		.intr_raw_status_bit = 4,	\
+		.intr_polarity_bit = 1,		\
+		.intr_detection_bit = 2,	\
+		.intr_detection_width = 2,	\
+	}
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+static const struct pinctrl_pin_desc msm8917_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "GPIO_113"),
+	PINCTRL_PIN(114, "GPIO_114"),
+	PINCTRL_PIN(115, "GPIO_115"),
+	PINCTRL_PIN(116, "GPIO_116"),
+	PINCTRL_PIN(117, "GPIO_117"),
+	PINCTRL_PIN(118, "GPIO_118"),
+	PINCTRL_PIN(119, "GPIO_119"),
+	PINCTRL_PIN(120, "GPIO_120"),
+	PINCTRL_PIN(121, "GPIO_121"),
+	PINCTRL_PIN(122, "GPIO_122"),
+	PINCTRL_PIN(123, "GPIO_123"),
+	PINCTRL_PIN(124, "GPIO_124"),
+	PINCTRL_PIN(125, "GPIO_125"),
+	PINCTRL_PIN(126, "GPIO_126"),
+	PINCTRL_PIN(127, "GPIO_127"),
+	PINCTRL_PIN(128, "GPIO_128"),
+	PINCTRL_PIN(129, "GPIO_129"),
+	PINCTRL_PIN(130, "GPIO_130"),
+	PINCTRL_PIN(131, "GPIO_131"),
+	PINCTRL_PIN(132, "GPIO_132"),
+	PINCTRL_PIN(133, "GPIO_133"),
+	PINCTRL_PIN(134, "SDC1_CLK"),
+	PINCTRL_PIN(135, "SDC1_CMD"),
+	PINCTRL_PIN(136, "SDC1_DATA"),
+	PINCTRL_PIN(137, "SDC1_RCLK"),
+	PINCTRL_PIN(138, "SDC2_CLK"),
+	PINCTRL_PIN(139, "SDC2_CMD"),
+	PINCTRL_PIN(140, "SDC2_DATA"),
+	PINCTRL_PIN(141, "QDSD_CLK"),
+	PINCTRL_PIN(142, "QDSD_CMD"),
+	PINCTRL_PIN(143, "QDSD_DATA0"),
+	PINCTRL_PIN(144, "QDSD_DATA1"),
+	PINCTRL_PIN(145, "QDSD_DATA2"),
+	PINCTRL_PIN(146, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+
+static const unsigned int sdc1_clk_pins[] = { 134 };
+static const unsigned int sdc1_cmd_pins[] = { 135 };
+static const unsigned int sdc1_data_pins[] = { 136 };
+static const unsigned int sdc1_rclk_pins[] = { 137 };
+static const unsigned int sdc2_clk_pins[] = { 138 };
+static const unsigned int sdc2_cmd_pins[] = { 139 };
+static const unsigned int sdc2_data_pins[] = { 140 };
+static const unsigned int qdsd_clk_pins[] = { 141 };
+static const unsigned int qdsd_cmd_pins[] = { 142 };
+static const unsigned int qdsd_data0_pins[] = { 143 };
+static const unsigned int qdsd_data1_pins[] = { 144 };
+static const unsigned int qdsd_data2_pins[] = { 145 };
+static const unsigned int qdsd_data3_pins[] = { 146 };
+
+enum msm8917_functions {
+	msm_mux_qdss_tracedata_b,
+	msm_mux_blsp_uart1,
+	msm_mux_gpio,
+	msm_mux_blsp_spi1,
+	msm_mux_adsp_ext,
+	msm_mux_blsp_i2c1,
+	msm_mux_prng_rosc,
+	msm_mux_qdss_cti_trig_out_b0,
+	msm_mux_blsp_spi2,
+	msm_mux_blsp_uart2,
+	msm_mux_blsp_uart3,
+	msm_mux_pbs0,
+	msm_mux_pbs1,
+	msm_mux_pwr_modem_enabled_b,
+	msm_mux_blsp_i2c3,
+	msm_mux_gcc_gp2_clk_b,
+	msm_mux_ldo_update,
+	msm_mux_atest_combodac_to_gpio_native,
+	msm_mux_ldo_en,
+	msm_mux_blsp_i2c2,
+	msm_mux_gcc_gp1_clk_b,
+	msm_mux_pbs2,
+	msm_mux_atest_gpsadc_dtest0_native,
+	msm_mux_blsp_spi3,
+	msm_mux_gcc_gp3_clk_b,
+	msm_mux_blsp_spi4,
+	msm_mux_blsp_uart4,
+	msm_mux_sec_mi2s,
+	msm_mux_pwr_nav_enabled_b,
+	msm_mux_codec_mad,
+	msm_mux_pwr_crypto_enabled_b,
+	msm_mux_blsp_i2c4,
+	msm_mux_blsp_spi5,
+	msm_mux_blsp_uart5,
+	msm_mux_qdss_traceclk_a,
+	msm_mux_atest_bbrx1,
+	msm_mux_m_voc,
+	msm_mux_qdss_cti_trig_in_a0,
+	msm_mux_qdss_cti_trig_in_b0,
+	msm_mux_blsp_i2c6,
+	msm_mux_qdss_traceclk_b,
+	msm_mux_atest_wlan0,
+	msm_mux_atest_bbrx0,
+	msm_mux_blsp_i2c5,
+	msm_mux_qdss_tracectl_a,
+	msm_mux_atest_gpsadc_dtest1_native,
+	msm_mux_qdss_tracedata_a,
+	msm_mux_blsp_spi6,
+	msm_mux_blsp_uart6,
+	msm_mux_qdss_tracectl_b,
+	msm_mux_atest_wlan1,
+	msm_mux_mdp_vsync,
+	msm_mux_pri_mi2s_mclk_a,
+	msm_mux_sec_mi2s_mclk_a,
+	msm_mux_cam_mclk,
+	msm_mux_cci_i2c,
+	msm_mux_pwr_modem_enabled_a,
+	msm_mux_cci_timer0,
+	msm_mux_cci_timer1,
+	msm_mux_cam1_standby,
+	msm_mux_pwr_nav_enabled_a,
+	msm_mux_cam1_rst,
+	msm_mux_pwr_crypto_enabled_a,
+	msm_mux_forced_usb,
+	msm_mux_qdss_cti_trig_out_b1,
+	msm_mux_cam2_rst,
+	msm_mux_webcam_standby,
+	msm_mux_cci_async,
+	msm_mux_webcam_rst,
+	msm_mux_ov_ldo,
+	msm_mux_sd_write,
+	msm_mux_accel_int,
+	msm_mux_gcc_gp1_clk_a,
+	msm_mux_alsp_int,
+	msm_mux_gcc_gp2_clk_a,
+	msm_mux_mag_int,
+	msm_mux_gcc_gp3_clk_a,
+	msm_mux_blsp6_spi,
+	msm_mux_fp_int,
+	msm_mux_qdss_cti_trig_in_b1,
+	msm_mux_uim_batt,
+	msm_mux_cam2_standby,
+	msm_mux_uim1_data,
+	msm_mux_uim1_clk,
+	msm_mux_uim1_reset,
+	msm_mux_uim1_present,
+	msm_mux_uim2_data,
+	msm_mux_uim2_clk,
+	msm_mux_uim2_reset,
+	msm_mux_uim2_present,
+	msm_mux_sensor_rst,
+	msm_mux_mipi_dsi0,
+	msm_mux_smb_int,
+	msm_mux_cam0_ldo,
+	msm_mux_us_euro,
+	msm_mux_atest_char3,
+	msm_mux_dbg_out,
+	msm_mux_bimc_dte0,
+	msm_mux_ts_resout,
+	msm_mux_ts_sample,
+	msm_mux_sec_mi2s_mclk_b,
+	msm_mux_pri_mi2s,
+	msm_mux_sdcard_det,
+	msm_mux_atest_char1,
+	msm_mux_ebi_cdc,
+	msm_mux_audio_reset,
+	msm_mux_atest_char0,
+	msm_mux_audio_ref,
+	msm_mux_cdc_pdm0,
+	msm_mux_pri_mi2s_mclk_b,
+	msm_mux_lpass_slimbus,
+	msm_mux_lpass_slimbus0,
+	msm_mux_lpass_slimbus1,
+	msm_mux_codec_int1,
+	msm_mux_codec_int2,
+	msm_mux_wcss_bt,
+	msm_mux_atest_char2,
+	msm_mux_ebi_ch0,
+	msm_mux_wcss_wlan2,
+	msm_mux_wcss_wlan1,
+	msm_mux_wcss_wlan0,
+	msm_mux_wcss_wlan,
+	msm_mux_wcss_fm,
+	msm_mux_ext_lpass,
+	msm_mux_cri_trng,
+	msm_mux_cri_trng1,
+	msm_mux_cri_trng0,
+	msm_mux_blsp_spi7,
+	msm_mux_blsp_uart7,
+	msm_mux_pri_mi2s_ws,
+	msm_mux_blsp_i2c7,
+	msm_mux_gcc_tlmm,
+	msm_mux_dmic0_clk,
+	msm_mux_dmic0_data,
+	msm_mux_key_volp,
+	msm_mux_qdss_cti_trig_in_a1,
+	msm_mux_us_emitter,
+	msm_mux_wsa_irq,
+	msm_mux_wsa_io,
+	msm_mux_blsp_spi8,
+	msm_mux_blsp_uart8,
+	msm_mux_blsp_i2c8,
+	msm_mux_gcc_plltest,
+	msm_mux_nav_pps_in_a,
+	msm_mux_pa_indicator,
+	msm_mux_modem_tsync,
+	msm_mux_nav_tsync,
+	msm_mux_nav_pps_in_b,
+	msm_mux_nav_pps,
+	msm_mux_gsm0_tx,
+	msm_mux_atest_char,
+	msm_mux_atest_tsens,
+	msm_mux_bimc_dte1,
+	msm_mux_ssbi_wtr1,
+	msm_mux_fp_gpio,
+	msm_mux_coex_uart,
+	msm_mux_key_snapshot,
+	msm_mux_key_focus,
+	msm_mux_nfc_pwr,
+	msm_mux_blsp8_spi,
+	msm_mux_qdss_cti_trig_out_a0,
+	msm_mux_qdss_cti_trig_out_a1,
+	msm_mux_NA,
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+	"gpio0", "gpio1", "gpio6", "gpio7", "gpio12", "gpio13", "gpio23",
+	"gpio42", "gpio43", "gpio44", "gpio47", "gpio66", "gpio86", "gpio87",
+	"gpio88", "gpio92",
+};
+static const char * const blsp_uart1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+	"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+	"gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+	"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+	"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+	"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+	"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+	"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+	"gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+	"gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+	"gpio129", "gpio130", "gpio131", "gpio132", "gpio133",
+};
+static const char * const blsp_spi1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const adsp_ext_groups[] = {
+	"gpio1",
+};
+static const char * const blsp_i2c1_groups[] = {
+	"gpio2", "gpio3",
+};
+static const char * const prng_rosc_groups[] = {
+	"gpio2",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+	"gpio2",
+};
+static const char * const blsp_spi2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const pbs0_groups[] = {
+	"gpio8",
+};
+static const char * const pbs1_groups[] = {
+	"gpio9",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+	"gpio9",
+};
+static const char * const blsp_i2c3_groups[] = {
+	"gpio10", "gpio11",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+	"gpio10",
+};
+static const char * const ldo_update_groups[] = {
+	"gpio4",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+	"gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29",
+	"gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44",
+	"gpio45", "gpio46", "gpio47", "gpio48", "gpio67", "gpio115",
+};
+static const char * const ldo_en_groups[] = {
+	"gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+	"gpio6", "gpio7",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+	"gpio6",
+};
+static const char * const pbs2_groups[] = {
+	"gpio7",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+	"gpio7",
+};
+static const char * const blsp_spi3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+	"gpio11",
+};
+static const char * const blsp_spi4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_uart4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const sec_mi2s_groups[] = {
+	"gpio12", "gpio13", "gpio94", "gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+	"gpio12",
+};
+static const char * const codec_mad_groups[] = {
+	"gpio13",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+	"gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+	"gpio14", "gpio15",
+};
+static const char * const blsp_spi5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+	"gpio16",
+};
+static const char * const atest_bbrx1_groups[] = {
+	"gpio16",
+};
+static const char * const m_voc_groups[] = {
+	"gpio17", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+	"gpio17",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+	"gpio21",
+};
+static const char * const blsp_i2c6_groups[] = {
+	"gpio22", "gpio23",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+	"gpio22",
+};
+static const char * const atest_wlan0_groups[] = {
+	"gpio22",
+};
+static const char * const atest_bbrx0_groups[] = {
+	"gpio17",
+};
+static const char * const blsp_i2c5_groups[] = {
+	"gpio18", "gpio19",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+	"gpio18",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+	"gpio18",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+	"gpio19", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+	"gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio38", "gpio39",
+	"gpio40", "gpio50",
+};
+static const char * const blsp_spi6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const blsp_uart6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+	"gpio20",
+};
+static const char * const atest_wlan1_groups[] = {
+	"gpio23",
+};
+static const char * const mdp_vsync_groups[] = {
+	"gpio24", "gpio25",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const sec_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+	"gpio26", "gpio27", "gpio28",
+};
+static const char * const cci_i2c_groups[] = {
+	"gpio29", "gpio30", "gpio31", "gpio32",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+	"gpio29",
+};
+static const char * const cci_timer0_groups[] = {
+	"gpio33",
+};
+static const char * const cci_timer1_groups[] = {
+	"gpio34",
+};
+static const char * const cam1_standby_groups[] = {
+	"gpio35",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+	"gpio35",
+};
+static const char * const cam1_rst_groups[] = {
+	"gpio36",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+	"gpio36",
+};
+static const char * const forced_usb_groups[] = {
+	"gpio37",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+	"gpio37",
+};
+static const char * const cam2_rst_groups[] = {
+	"gpio38",
+};
+static const char * const webcam_standby_groups[] = {
+	"gpio39",
+};
+static const char * const cci_async_groups[] = {
+	"gpio39",
+};
+static const char * const webcam_rst_groups[] = {
+	"gpio40",
+};
+static const char * const ov_ldo_groups[] = {
+	"gpio41",
+};
+static const char * const sd_write_groups[] = {
+	"gpio41",
+};
+static const char * const accel_int_groups[] = {
+	"gpio42",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+	"gpio42",
+};
+static const char * const alsp_int_groups[] = {
+	"gpio43",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+	"gpio43",
+};
+static const char * const mag_int_groups[] = {
+	"gpio44",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+	"gpio44",
+};
+static const char * const blsp6_spi_groups[] = {
+	"gpio47",
+};
+static const char * const fp_int_groups[] = {
+	"gpio48",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+	"gpio48",
+};
+static const char * const uim_batt_groups[] = {
+	"gpio49",
+};
+static const char * const cam2_standby_groups[] = {
+	"gpio50",
+};
+static const char * const uim1_data_groups[] = {
+	"gpio51",
+};
+static const char * const uim1_clk_groups[] = {
+	"gpio52",
+};
+static const char * const uim1_reset_groups[] = {
+	"gpio53",
+};
+static const char * const uim1_present_groups[] = {
+	"gpio54",
+};
+static const char * const uim2_data_groups[] = {
+	"gpio55",
+};
+static const char * const uim2_clk_groups[] = {
+	"gpio56",
+};
+static const char * const uim2_reset_groups[] = {
+	"gpio57",
+};
+static const char * const uim2_present_groups[] = {
+	"gpio58",
+};
+static const char * const sensor_rst_groups[] = {
+	"gpio59",
+};
+static const char * const mipi_dsi0_groups[] = {
+	"gpio60",
+};
+static const char * const smb_int_groups[] = {
+	"gpio61",
+};
+static const char * const cam0_ldo_groups[] = {
+	"gpio62",
+};
+static const char * const us_euro_groups[] = {
+	"gpio63",
+};
+static const char * const atest_char3_groups[] = {
+	"gpio63",
+};
+static const char * const dbg_out_groups[] = {
+	"gpio63",
+};
+static const char * const bimc_dte0_groups[] = {
+	"gpio63", "gpio65",
+};
+static const char * const ts_resout_groups[] = {
+	"gpio64",
+};
+static const char * const ts_sample_groups[] = {
+	"gpio65",
+};
+static const char * const sec_mi2s_mclk_b_groups[] = {
+	"gpio66",
+};
+static const char * const pri_mi2s_groups[] = {
+	"gpio66", "gpio85", "gpio86", "gpio88", "gpio94", "gpio95",
+};
+static const char * const sdcard_det_groups[] = {
+	"gpio67",
+};
+static const char * const atest_char1_groups[] = {
+	"gpio67",
+};
+static const char * const ebi_cdc_groups[] = {
+	"gpio67", "gpio69", "gpio118", "gpio119", "gpio120", "gpio123",
+};
+static const char * const audio_reset_groups[] = {
+	"gpio68",
+};
+static const char * const atest_char0_groups[] = {
+	"gpio68",
+};
+static const char * const audio_ref_groups[] = {
+	"gpio69",
+};
+static const char * const cdc_pdm0_groups[] = {
+	"gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+	"gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+	"gpio70",
+};
+static const char * const lpass_slimbus0_groups[] = {
+	"gpio71",
+};
+static const char * const lpass_slimbus1_groups[] = {
+	"gpio72",
+};
+static const char * const codec_int1_groups[] = {
+	"gpio73",
+};
+static const char * const codec_int2_groups[] = {
+	"gpio74",
+};
+static const char * const wcss_bt_groups[] = {
+	"gpio75", "gpio83", "gpio84",
+};
+static const char * const atest_char2_groups[] = {
+	"gpio75",
+};
+static const char * const ebi_ch0_groups[] = {
+	"gpio75",
+};
+static const char * const wcss_wlan2_groups[] = {
+	"gpio76",
+};
+static const char * const wcss_wlan1_groups[] = {
+	"gpio77",
+};
+static const char * const wcss_wlan0_groups[] = {
+	"gpio78",
+};
+static const char * const wcss_wlan_groups[] = {
+	"gpio79", "gpio80",
+};
+static const char * const wcss_fm_groups[] = {
+	"gpio81", "gpio82",
+};
+static const char * const ext_lpass_groups[] = {
+	"gpio81",
+};
+static const char * const cri_trng_groups[] = {
+	"gpio82",
+};
+static const char * const cri_trng1_groups[] = {
+	"gpio83",
+};
+static const char * const cri_trng0_groups[] = {
+	"gpio84",
+};
+static const char * const blsp_spi7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+	"gpio87",
+};
+static const char * const blsp_i2c7_groups[] = {
+	"gpio87", "gpio88",
+};
+static const char * const gcc_tlmm_groups[] = {
+	"gpio87",
+};
+static const char * const dmic0_clk_groups[] = {
+	"gpio89",
+};
+static const char * const dmic0_data_groups[] = {
+	"gpio90",
+};
+static const char * const key_volp_groups[] = {
+	"gpio91",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+	"gpio91",
+};
+static const char * const us_emitter_groups[] = {
+	"gpio92",
+};
+static const char * const wsa_irq_groups[] = {
+	"gpio93",
+};
+static const char * const wsa_io_groups[] = {
+	"gpio94", "gpio95",
+};
+static const char * const blsp_spi8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_uart8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_i2c8_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const gcc_plltest_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const nav_pps_in_a_groups[] = {
+	"gpio115",
+};
+static const char * const pa_indicator_groups[] = {
+	"gpio116",
+};
+static const char * const modem_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_in_b_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_groups[] = {
+	"gpio117",
+};
+static const char * const gsm0_tx_groups[] = {
+	"gpio119",
+};
+static const char * const atest_char_groups[] = {
+	"gpio120",
+};
+static const char * const atest_tsens_groups[] = {
+	"gpio120",
+};
+static const char * const bimc_dte1_groups[] = {
+	"gpio121", "gpio122",
+};
+static const char * const ssbi_wtr1_groups[] = {
+	"gpio122", "gpio123",
+};
+static const char * const fp_gpio_groups[] = {
+	"gpio124",
+};
+static const char * const coex_uart_groups[] = {
+	"gpio124", "gpio127",
+};
+static const char * const key_snapshot_groups[] = {
+	"gpio127",
+};
+static const char * const key_focus_groups[] = {
+	"gpio128",
+};
+static const char * const nfc_pwr_groups[] = {
+	"gpio129",
+};
+static const char * const blsp8_spi_groups[] = {
+	"gpio130",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+	"gpio132",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+	"gpio133",
+};
+
+static const struct msm_function msm8917_functions[] = {
+	FUNCTION(qdss_tracedata_b),
+	FUNCTION(blsp_uart1),
+	FUNCTION(gpio),
+	FUNCTION(blsp_spi1),
+	FUNCTION(adsp_ext),
+	FUNCTION(blsp_i2c1),
+	FUNCTION(prng_rosc),
+	FUNCTION(qdss_cti_trig_out_b0),
+	FUNCTION(blsp_spi2),
+	FUNCTION(blsp_uart2),
+	FUNCTION(blsp_uart3),
+	FUNCTION(pbs0),
+	FUNCTION(pbs1),
+	FUNCTION(pwr_modem_enabled_b),
+	FUNCTION(blsp_i2c3),
+	FUNCTION(gcc_gp2_clk_b),
+	FUNCTION(ldo_update),
+	FUNCTION(atest_combodac_to_gpio_native),
+	FUNCTION(ldo_en),
+	FUNCTION(blsp_i2c2),
+	FUNCTION(gcc_gp1_clk_b),
+	FUNCTION(pbs2),
+	FUNCTION(atest_gpsadc_dtest0_native),
+	FUNCTION(blsp_spi3),
+	FUNCTION(gcc_gp3_clk_b),
+	FUNCTION(blsp_spi4),
+	FUNCTION(blsp_uart4),
+	FUNCTION(sec_mi2s),
+	FUNCTION(pwr_nav_enabled_b),
+	FUNCTION(codec_mad),
+	FUNCTION(pwr_crypto_enabled_b),
+	FUNCTION(blsp_i2c4),
+	FUNCTION(blsp_spi5),
+	FUNCTION(blsp_uart5),
+	FUNCTION(qdss_traceclk_a),
+	FUNCTION(atest_bbrx1),
+	FUNCTION(m_voc),
+	FUNCTION(qdss_cti_trig_in_a0),
+	FUNCTION(qdss_cti_trig_in_b0),
+	FUNCTION(blsp_i2c6),
+	FUNCTION(qdss_traceclk_b),
+	FUNCTION(atest_wlan0),
+	FUNCTION(atest_bbrx0),
+	FUNCTION(blsp_i2c5),
+	FUNCTION(qdss_tracectl_a),
+	FUNCTION(atest_gpsadc_dtest1_native),
+	FUNCTION(qdss_tracedata_a),
+	FUNCTION(blsp_spi6),
+	FUNCTION(blsp_uart6),
+	FUNCTION(qdss_tracectl_b),
+	FUNCTION(atest_wlan1),
+	FUNCTION(mdp_vsync),
+	FUNCTION(pri_mi2s_mclk_a),
+	FUNCTION(sec_mi2s_mclk_a),
+	FUNCTION(cam_mclk),
+	FUNCTION(cci_i2c),
+	FUNCTION(pwr_modem_enabled_a),
+	FUNCTION(cci_timer0),
+	FUNCTION(cci_timer1),
+	FUNCTION(cam1_standby),
+	FUNCTION(pwr_nav_enabled_a),
+	FUNCTION(cam1_rst),
+	FUNCTION(pwr_crypto_enabled_a),
+	FUNCTION(forced_usb),
+	FUNCTION(qdss_cti_trig_out_b1),
+	FUNCTION(cam2_rst),
+	FUNCTION(webcam_standby),
+	FUNCTION(cci_async),
+	FUNCTION(webcam_rst),
+	FUNCTION(ov_ldo),
+	FUNCTION(sd_write),
+	FUNCTION(accel_int),
+	FUNCTION(gcc_gp1_clk_a),
+	FUNCTION(alsp_int),
+	FUNCTION(gcc_gp2_clk_a),
+	FUNCTION(mag_int),
+	FUNCTION(gcc_gp3_clk_a),
+	FUNCTION(blsp6_spi),
+	FUNCTION(fp_int),
+	FUNCTION(qdss_cti_trig_in_b1),
+	FUNCTION(uim_batt),
+	FUNCTION(cam2_standby),
+	FUNCTION(uim1_data),
+	FUNCTION(uim1_clk),
+	FUNCTION(uim1_reset),
+	FUNCTION(uim1_present),
+	FUNCTION(uim2_data),
+	FUNCTION(uim2_clk),
+	FUNCTION(uim2_reset),
+	FUNCTION(uim2_present),
+	FUNCTION(sensor_rst),
+	FUNCTION(mipi_dsi0),
+	FUNCTION(smb_int),
+	FUNCTION(cam0_ldo),
+	FUNCTION(us_euro),
+	FUNCTION(atest_char3),
+	FUNCTION(dbg_out),
+	FUNCTION(bimc_dte0),
+	FUNCTION(ts_resout),
+	FUNCTION(ts_sample),
+	FUNCTION(sec_mi2s_mclk_b),
+	FUNCTION(pri_mi2s),
+	FUNCTION(sdcard_det),
+	FUNCTION(atest_char1),
+	FUNCTION(ebi_cdc),
+	FUNCTION(audio_reset),
+	FUNCTION(atest_char0),
+	FUNCTION(audio_ref),
+	FUNCTION(cdc_pdm0),
+	FUNCTION(pri_mi2s_mclk_b),
+	FUNCTION(lpass_slimbus),
+	FUNCTION(lpass_slimbus0),
+	FUNCTION(lpass_slimbus1),
+	FUNCTION(codec_int1),
+	FUNCTION(codec_int2),
+	FUNCTION(wcss_bt),
+	FUNCTION(atest_char2),
+	FUNCTION(ebi_ch0),
+	FUNCTION(wcss_wlan2),
+	FUNCTION(wcss_wlan1),
+	FUNCTION(wcss_wlan0),
+	FUNCTION(wcss_wlan),
+	FUNCTION(wcss_fm),
+	FUNCTION(ext_lpass),
+	FUNCTION(cri_trng),
+	FUNCTION(cri_trng1),
+	FUNCTION(cri_trng0),
+	FUNCTION(blsp_spi7),
+	FUNCTION(blsp_uart7),
+	FUNCTION(pri_mi2s_ws),
+	FUNCTION(blsp_i2c7),
+	FUNCTION(gcc_tlmm),
+	FUNCTION(dmic0_clk),
+	FUNCTION(dmic0_data),
+	FUNCTION(key_volp),
+	FUNCTION(qdss_cti_trig_in_a1),
+	FUNCTION(us_emitter),
+	FUNCTION(wsa_irq),
+	FUNCTION(wsa_io),
+	FUNCTION(blsp_spi8),
+	FUNCTION(blsp_uart8),
+	FUNCTION(blsp_i2c8),
+	FUNCTION(gcc_plltest),
+	FUNCTION(nav_pps_in_a),
+	FUNCTION(pa_indicator),
+	FUNCTION(modem_tsync),
+	FUNCTION(nav_tsync),
+	FUNCTION(nav_pps_in_b),
+	FUNCTION(nav_pps),
+	FUNCTION(gsm0_tx),
+	FUNCTION(atest_char),
+	FUNCTION(atest_tsens),
+	FUNCTION(bimc_dte1),
+	FUNCTION(ssbi_wtr1),
+	FUNCTION(fp_gpio),
+	FUNCTION(coex_uart),
+	FUNCTION(key_snapshot),
+	FUNCTION(key_focus),
+	FUNCTION(nfc_pwr),
+	FUNCTION(blsp8_spi),
+	FUNCTION(qdss_cti_trig_out_a0),
+	FUNCTION(qdss_cti_trig_out_a1),
+};
+
+static const struct msm_pingroup msm8917_groups[] = {
+	PINGROUP(0, blsp_spi1, blsp_uart1, qdss_tracedata_b, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(1, blsp_spi1, blsp_uart1, adsp_ext, NA, NA, NA, NA, NA,
+		 qdss_tracedata_b),
+	PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, prng_rosc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+	PINGROUP(4, blsp_spi2, blsp_uart2, ldo_update, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(5, blsp_spi2, blsp_uart2, ldo_en, NA, NA, NA, NA, NA, NA),
+	PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, gcc_gp1_clk_b,
+		 qdss_tracedata_b, NA, NA, NA, NA),
+	PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, pbs2, NA,
+		 qdss_tracedata_b, NA, atest_gpsadc_dtest0_native, NA),
+	PINGROUP(8, blsp_spi3, blsp_uart3, pbs0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(9, blsp_spi3, blsp_uart3, pbs1, pwr_modem_enabled_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(10, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp2_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(11, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp3_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(12, blsp_spi4, blsp_uart4, sec_mi2s, pwr_nav_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(13, blsp_spi4, blsp_uart4, sec_mi2s, pwr_crypto_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(14, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(15, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(16, blsp_spi5, blsp_uart5, NA, NA, NA, NA, qdss_traceclk_a,
+		 NA, atest_bbrx1),
+	PINGROUP(17, blsp_spi5, blsp_uart5, m_voc, qdss_cti_trig_in_a0, NA,
+		 atest_bbrx0, NA, NA, NA),
+	PINGROUP(18, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracectl_a, NA,
+		 atest_gpsadc_dtest1_native, NA, NA, NA),
+	PINGROUP(19, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracedata_a, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(20, blsp_spi6, blsp_uart6, NA, NA, NA, NA, NA, NA,
+		 qdss_tracectl_b),
+	PINGROUP(21, blsp_spi6, blsp_uart6, m_voc, NA, NA, NA, NA, NA,
+		 qdss_cti_trig_in_b0),
+	PINGROUP(22, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_traceclk_b, NA,
+		 atest_wlan0, NA, NA, NA),
+	PINGROUP(23, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_tracedata_b, NA,
+		 atest_wlan1, NA, NA, NA),
+	PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+	PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(28, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(29, cci_i2c, pwr_modem_enabled_a, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a, NA),
+	PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(31, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(32, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(33, cci_timer0, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(34, cci_timer1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(35, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(36, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(37, NA, NA, NA, NA, NA, qdss_cti_trig_out_b1, NA, NA, NA),
+	PINGROUP(38, NA, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(39, cci_async, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(40, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA),
+	PINGROUP(41, sd_write, NA, NA, NA, NA, NA, NA, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(42, gcc_gp1_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(43, gcc_gp2_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(44, gcc_gp3_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(45, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(46, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(47, blsp6_spi, NA, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(48, NA, qdss_cti_trig_in_b1, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(49, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(50, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(51, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(52, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(53, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, uim2_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(63, atest_char3, dbg_out, bimc_dte0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(65, bimc_dte0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(66, sec_mi2s_mclk_b, pri_mi2s, NA, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(67, atest_char1, ebi_cdc, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA, NA),
+	PINGROUP(68, atest_char0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(69, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, ebi_cdc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(70, lpass_slimbus, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(71, lpass_slimbus0, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(72, lpass_slimbus1, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(73, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(74, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(75, wcss_bt, atest_char2, NA, ebi_ch0, NA, NA, NA, NA, NA),
+	PINGROUP(76, wcss_wlan2, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(77, wcss_wlan1, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(78, wcss_wlan0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(79, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(80, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(81, wcss_fm, ext_lpass, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(82, wcss_fm, cri_trng, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(83, wcss_bt, cri_trng1, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(84, wcss_bt, cri_trng0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(85, pri_mi2s, blsp_spi7, blsp_uart7, NA, NA, NA, NA, NA, NA),
+	PINGROUP(86, pri_mi2s, blsp_spi7, blsp_uart7, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(87, pri_mi2s_ws, blsp_spi7, blsp_uart7, blsp_i2c7,
+		 qdss_tracedata_b, gcc_tlmm, NA, NA, NA),
+	PINGROUP(88, pri_mi2s, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(89, dmic0_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(90, dmic0_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(91, NA, NA, NA, NA, NA, qdss_cti_trig_in_a1, NA, NA, NA),
+	PINGROUP(92, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA, NA),
+	PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(94, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(95, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(96, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(97, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(98, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(99, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(110, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(111, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(112, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(113, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(114, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(115, NA, NA, nav_pps_in_a, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA),
+	PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(117, NA, modem_tsync, nav_tsync, nav_pps_in_b, nav_pps, NA,
+		 NA, NA, NA),
+	PINGROUP(118, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(119, gsm0_tx, NA, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(120, NA, atest_char, ebi_cdc, NA, atest_tsens, NA, NA, NA, NA),
+	PINGROUP(121, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+	PINGROUP(122, NA, ssbi_wtr1, NA, NA, bimc_dte1, NA, NA, NA, NA),
+	PINGROUP(123, NA, ssbi_wtr1, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(124, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(127, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(128, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(130, blsp8_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(131, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(132, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(133, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA, NA, NA, NA),
+	SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+	SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+	SDC_QDSD_PINGROUP(sdc1_rclk, 0x10a000, 15, 0),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+	SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+	SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+	SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+	SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+	SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+	SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8917_pinctrl = {
+	.pins = msm8917_pins,
+	.npins = ARRAY_SIZE(msm8917_pins),
+	.functions = msm8917_functions,
+	.nfunctions = ARRAY_SIZE(msm8917_functions),
+	.groups = msm8917_groups,
+	.ngroups = ARRAY_SIZE(msm8917_groups),
+	.ngpios = 134,
+};
+
+static int msm8917_pinctrl_probe(struct platform_device *pdev)
+{
+	return msm_pinctrl_probe(pdev, &msm8917_pinctrl);
+}
+
+static const struct of_device_id msm8917_pinctrl_of_match[] = {
+	{ .compatible = "qcom,msm8917-pinctrl", },
+	{ },
+};
+
+static struct platform_driver msm8917_pinctrl_driver = {
+	.driver = {
+		.name = "msm8917-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = msm8917_pinctrl_of_match,
+	},
+	.probe = msm8917_pinctrl_probe,
+	.remove = msm_pinctrl_remove,
+};
+
+static int __init msm8917_pinctrl_init(void)
+{
+	return platform_driver_register(&msm8917_pinctrl_driver);
+}
+arch_initcall(msm8917_pinctrl_init);
+
+static void __exit msm8917_pinctrl_exit(void)
+{
+	platform_driver_unregister(&msm8917_pinctrl_driver);
+}
+module_exit(msm8917_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8917 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8917_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8937.c b/drivers/pinctrl/qcom/pinctrl-msm8937.c
new file mode 100644
index 0000000..2b72c54
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8937.c
@@ -0,0 +1,1479 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)			                \
+	[msm_mux_##fname] = {		                \
+		.name = #fname,				\
+		.groups = fname##_groups,               \
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)	\
+	{					        \
+		.name = "gpio" #id,			\
+		.pins = gpio##id##_pins,		\
+		.npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),	\
+		.funcs = (int[]){			\
+			msm_mux_gpio, /* gpio mode */	\
+			msm_mux_##f1,			\
+			msm_mux_##f2,			\
+			msm_mux_##f3,			\
+			msm_mux_##f4,			\
+			msm_mux_##f5,			\
+			msm_mux_##f6,			\
+			msm_mux_##f7,			\
+			msm_mux_##f8,			\
+			msm_mux_##f9			\
+		},				        \
+		.nfuncs = 10,				\
+		.ctl_reg = REG_BASE + REG_SIZE * id,			\
+		.io_reg = REG_BASE + 0x4 + REG_SIZE * id,		\
+		.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,		\
+		.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,	\
+		.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,	\
+		.mux_bit = 2,			\
+		.pull_bit = 0,			\
+		.drv_bit = 6,			\
+		.oe_bit = 9,			\
+		.in_bit = 0,			\
+		.out_bit = 1,			\
+		.intr_enable_bit = 0,		\
+		.intr_status_bit = 0,		\
+		.intr_target_bit = 5,		\
+		.intr_target_kpss_val = 4,	\
+		.intr_raw_status_bit = 4,	\
+		.intr_polarity_bit = 1,		\
+		.intr_detection_bit = 2,	\
+		.intr_detection_width = 2,	\
+	}
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+static const struct pinctrl_pin_desc msm8937_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "GPIO_113"),
+	PINCTRL_PIN(114, "GPIO_114"),
+	PINCTRL_PIN(115, "GPIO_115"),
+	PINCTRL_PIN(116, "GPIO_116"),
+	PINCTRL_PIN(117, "GPIO_117"),
+	PINCTRL_PIN(118, "GPIO_118"),
+	PINCTRL_PIN(119, "GPIO_119"),
+	PINCTRL_PIN(120, "GPIO_120"),
+	PINCTRL_PIN(121, "GPIO_121"),
+	PINCTRL_PIN(122, "GPIO_122"),
+	PINCTRL_PIN(123, "GPIO_123"),
+	PINCTRL_PIN(124, "GPIO_124"),
+	PINCTRL_PIN(125, "GPIO_125"),
+	PINCTRL_PIN(126, "GPIO_126"),
+	PINCTRL_PIN(127, "GPIO_127"),
+	PINCTRL_PIN(128, "GPIO_128"),
+	PINCTRL_PIN(129, "GPIO_129"),
+	PINCTRL_PIN(130, "GPIO_130"),
+	PINCTRL_PIN(131, "GPIO_131"),
+	PINCTRL_PIN(132, "GPIO_132"),
+	PINCTRL_PIN(133, "GPIO_133"),
+	PINCTRL_PIN(134, "SDC1_CLK"),
+	PINCTRL_PIN(135, "SDC1_CMD"),
+	PINCTRL_PIN(136, "SDC1_DATA"),
+	PINCTRL_PIN(137, "SDC1_RCLK"),
+	PINCTRL_PIN(138, "SDC2_CLK"),
+	PINCTRL_PIN(139, "SDC2_CMD"),
+	PINCTRL_PIN(140, "SDC2_DATA"),
+	PINCTRL_PIN(141, "QDSD_CLK"),
+	PINCTRL_PIN(142, "QDSD_CMD"),
+	PINCTRL_PIN(143, "QDSD_DATA0"),
+	PINCTRL_PIN(144, "QDSD_DATA1"),
+	PINCTRL_PIN(145, "QDSD_DATA2"),
+	PINCTRL_PIN(146, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+
+static const unsigned int sdc1_clk_pins[] = { 134 };
+static const unsigned int sdc1_cmd_pins[] = { 135 };
+static const unsigned int sdc1_data_pins[] = { 136 };
+static const unsigned int sdc1_rclk_pins[] = { 137 };
+static const unsigned int sdc2_clk_pins[] = { 138 };
+static const unsigned int sdc2_cmd_pins[] = { 139 };
+static const unsigned int sdc2_data_pins[] = { 140 };
+static const unsigned int qdsd_clk_pins[] = { 141 };
+static const unsigned int qdsd_cmd_pins[] = { 142 };
+static const unsigned int qdsd_data0_pins[] = { 143 };
+static const unsigned int qdsd_data1_pins[] = { 144 };
+static const unsigned int qdsd_data2_pins[] = { 145 };
+static const unsigned int qdsd_data3_pins[] = { 146 };
+
+enum msm8937_functions {
+	msm_mux_qdss_tracedata_b,
+	msm_mux_blsp_uart1,
+	msm_mux_gpio,
+	msm_mux_blsp_spi1,
+	msm_mux_adsp_ext,
+	msm_mux_blsp_i2c1,
+	msm_mux_prng_rosc,
+	msm_mux_qdss_cti_trig_out_b0,
+	msm_mux_blsp_spi2,
+	msm_mux_blsp_uart2,
+	msm_mux_blsp_uart3,
+	msm_mux_pbs0,
+	msm_mux_pbs1,
+	msm_mux_pwr_modem_enabled_b,
+	msm_mux_blsp_i2c3,
+	msm_mux_gcc_gp2_clk_b,
+	msm_mux_ldo_update,
+	msm_mux_atest_combodac_to_gpio_native,
+	msm_mux_ldo_en,
+	msm_mux_blsp_i2c2,
+	msm_mux_gcc_gp1_clk_b,
+	msm_mux_pbs2,
+	msm_mux_atest_gpsadc_dtest0_native,
+	msm_mux_blsp_spi3,
+	msm_mux_gcc_gp3_clk_b,
+	msm_mux_blsp_spi4,
+	msm_mux_blsp_uart4,
+	msm_mux_sec_mi2s,
+	msm_mux_pwr_nav_enabled_b,
+	msm_mux_codec_mad,
+	msm_mux_pwr_crypto_enabled_b,
+	msm_mux_blsp_i2c4,
+	msm_mux_blsp_spi5,
+	msm_mux_blsp_uart5,
+	msm_mux_qdss_traceclk_a,
+	msm_mux_atest_bbrx1,
+	msm_mux_m_voc,
+	msm_mux_qdss_cti_trig_in_a0,
+	msm_mux_qdss_cti_trig_in_b0,
+	msm_mux_blsp_i2c6,
+	msm_mux_qdss_traceclk_b,
+	msm_mux_atest_wlan0,
+	msm_mux_atest_wlan1,
+	msm_mux_atest_bbrx0,
+	msm_mux_blsp_i2c5,
+	msm_mux_qdss_tracectl_a,
+	msm_mux_atest_gpsadc_dtest1_native,
+	msm_mux_qdss_tracedata_a,
+	msm_mux_blsp_spi6,
+	msm_mux_blsp_uart6,
+	msm_mux_qdss_tracectl_b,
+	msm_mux_mdp_vsync,
+	msm_mux_pri_mi2s_mclk_a,
+	msm_mux_sec_mi2s_mclk_a,
+	msm_mux_cam_mclk,
+	msm_mux_cci_i2c,
+	msm_mux_pwr_modem_enabled_a,
+	msm_mux_cci_timer0,
+	msm_mux_cci_timer1,
+	msm_mux_cam1_standby,
+	msm_mux_pwr_nav_enabled_a,
+	msm_mux_cam1_rst,
+	msm_mux_pwr_crypto_enabled_a,
+	msm_mux_forced_usb,
+	msm_mux_qdss_cti_trig_out_b1,
+	msm_mux_cam2_rst,
+	msm_mux_webcam_standby,
+	msm_mux_cci_async,
+	msm_mux_webcam_rst,
+	msm_mux_ov_ldo,
+	msm_mux_sd_write,
+	msm_mux_accel_int,
+	msm_mux_gcc_gp1_clk_a,
+	msm_mux_alsp_int,
+	msm_mux_gcc_gp2_clk_a,
+	msm_mux_mag_int,
+	msm_mux_gcc_gp3_clk_a,
+	msm_mux_blsp6_spi,
+	msm_mux_fp_int,
+	msm_mux_qdss_cti_trig_in_b1,
+	msm_mux_uim_batt,
+	msm_mux_cam2_standby,
+	msm_mux_uim1_data,
+	msm_mux_uim1_clk,
+	msm_mux_uim1_reset,
+	msm_mux_uim1_present,
+	msm_mux_uim2_data,
+	msm_mux_uim2_clk,
+	msm_mux_uim2_reset,
+	msm_mux_uim2_present,
+	msm_mux_sensor_rst,
+	msm_mux_mipi_dsi0,
+	msm_mux_smb_int,
+	msm_mux_cam0_ldo,
+	msm_mux_us_euro,
+	msm_mux_atest_char3,
+	msm_mux_dbg_out,
+	msm_mux_bimc_dte0,
+	msm_mux_ts_resout,
+	msm_mux_ts_sample,
+	msm_mux_sec_mi2s_mclk_b,
+	msm_mux_pri_mi2s,
+	msm_mux_sdcard_det,
+	msm_mux_atest_char1,
+	msm_mux_ebi_cdc,
+	msm_mux_audio_reset,
+	msm_mux_atest_char0,
+	msm_mux_audio_ref,
+	msm_mux_cdc_pdm0,
+	msm_mux_pri_mi2s_mclk_b,
+	msm_mux_lpass_slimbus,
+	msm_mux_lpass_slimbus0,
+	msm_mux_lpass_slimbus1,
+	msm_mux_codec_int1,
+	msm_mux_codec_int2,
+	msm_mux_wcss_bt,
+	msm_mux_atest_char2,
+	msm_mux_ebi_ch0,
+	msm_mux_wcss_wlan2,
+	msm_mux_wcss_wlan1,
+	msm_mux_wcss_wlan0,
+	msm_mux_wcss_wlan,
+	msm_mux_wcss_fm,
+	msm_mux_ext_lpass,
+	msm_mux_cri_trng,
+	msm_mux_cri_trng1,
+	msm_mux_cri_trng0,
+	msm_mux_blsp_spi7,
+	msm_mux_blsp_uart7,
+	msm_mux_pri_mi2s_ws,
+	msm_mux_blsp_i2c7,
+	msm_mux_gcc_tlmm,
+	msm_mux_dmic0_clk,
+	msm_mux_dmic0_data,
+	msm_mux_key_volp,
+	msm_mux_qdss_cti_trig_in_a1,
+	msm_mux_us_emitter,
+	msm_mux_wsa_irq,
+	msm_mux_wsa_io,
+	msm_mux_wsa_reset,
+	msm_mux_blsp_spi8,
+	msm_mux_blsp_uart8,
+	msm_mux_blsp_i2c8,
+	msm_mux_gcc_plltest,
+	msm_mux_nav_pps_in_a,
+	msm_mux_pa_indicator,
+	msm_mux_modem_tsync,
+	msm_mux_nav_tsync,
+	msm_mux_nav_pps_in_b,
+	msm_mux_nav_pps,
+	msm_mux_gsm0_tx,
+	msm_mux_atest_char,
+	msm_mux_atest_tsens,
+	msm_mux_bimc_dte1,
+	msm_mux_ssbi_wtr1,
+	msm_mux_fp_gpio,
+	msm_mux_coex_uart,
+	msm_mux_key_snapshot,
+	msm_mux_key_focus,
+	msm_mux_nfc_pwr,
+	msm_mux_blsp8_spi,
+	msm_mux_qdss_cti_trig_out_a0,
+	msm_mux_qdss_cti_trig_out_a1,
+	msm_mux_NA,
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+	"gpio0", "gpio1", "gpio6", "gpio7", "gpio12", "gpio13", "gpio23",
+	"gpio42", "gpio43", "gpio44", "gpio47", "gpio66", "gpio86", "gpio87",
+	"gpio88", "gpio92",
+};
+static const char * const blsp_uart1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+	"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+	"gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+	"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+	"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+	"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+	"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+	"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+	"gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+	"gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+	"gpio129", "gpio130", "gpio131", "gpio132", "gpio133",
+};
+static const char * const blsp_spi1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const adsp_ext_groups[] = {
+	"gpio1",
+};
+static const char * const blsp_i2c1_groups[] = {
+	"gpio2", "gpio3",
+};
+static const char * const prng_rosc_groups[] = {
+	"gpio2",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+	"gpio2",
+};
+static const char * const blsp_spi2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const pbs0_groups[] = {
+	"gpio8",
+};
+static const char * const pbs1_groups[] = {
+	"gpio9",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+	"gpio9",
+};
+static const char * const blsp_i2c3_groups[] = {
+	"gpio10", "gpio11",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+	"gpio10",
+};
+static const char * const ldo_update_groups[] = {
+	"gpio4",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+	"gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29",
+	"gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44",
+	"gpio45", "gpio46", "gpio47", "gpio48", "gpio67", "gpio115",
+};
+static const char * const ldo_en_groups[] = {
+	"gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+	"gpio6", "gpio7",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+	"gpio6",
+};
+static const char * const pbs2_groups[] = {
+	"gpio7",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+	"gpio7",
+};
+static const char * const blsp_spi3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+	"gpio11",
+};
+static const char * const blsp_spi4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_uart4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const sec_mi2s_groups[] = {
+	"gpio12", "gpio13", "gpio94", "gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+	"gpio12",
+};
+static const char * const codec_mad_groups[] = {
+	"gpio13",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+	"gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+	"gpio14", "gpio15",
+};
+static const char * const blsp_spi5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+	"gpio16",
+};
+static const char * const atest_bbrx1_groups[] = {
+	"gpio16",
+};
+static const char * const m_voc_groups[] = {
+	"gpio17", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+	"gpio17",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+	"gpio21",
+};
+static const char * const blsp_i2c6_groups[] = {
+	"gpio22", "gpio23",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+	"gpio22",
+};
+static const char * const atest_wlan0_groups[] = {
+	"gpio22",
+};
+static const char * const atest_wlan1_groups[] = {
+	"gpio23",
+};
+static const char * const atest_bbrx0_groups[] = {
+	"gpio17",
+};
+static const char * const blsp_i2c5_groups[] = {
+	"gpio18", "gpio19",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+	"gpio18",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+	"gpio18",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+	"gpio19", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+	"gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio38", "gpio39",
+	"gpio40", "gpio50",
+};
+static const char * const blsp_spi6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const blsp_uart6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+	"gpio20",
+};
+static const char * const mdp_vsync_groups[] = {
+	"gpio24", "gpio25",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const sec_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+	"gpio26", "gpio27", "gpio28",
+};
+static const char * const cci_i2c_groups[] = {
+	"gpio29", "gpio30", "gpio31", "gpio32",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+	"gpio29",
+};
+static const char * const cci_timer0_groups[] = {
+	"gpio33",
+};
+static const char * const cci_timer1_groups[] = {
+	"gpio34",
+};
+static const char * const cam1_standby_groups[] = {
+	"gpio35",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+	"gpio35",
+};
+static const char * const cam1_rst_groups[] = {
+	"gpio36",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+	"gpio36",
+};
+static const char * const forced_usb_groups[] = {
+	"gpio37",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+	"gpio37",
+};
+static const char * const cam2_rst_groups[] = {
+	"gpio38",
+};
+static const char * const webcam_standby_groups[] = {
+	"gpio39",
+};
+static const char * const cci_async_groups[] = {
+	"gpio39",
+};
+static const char * const webcam_rst_groups[] = {
+	"gpio40",
+};
+static const char * const ov_ldo_groups[] = {
+	"gpio41",
+};
+static const char * const sd_write_groups[] = {
+	"gpio41",
+};
+static const char * const accel_int_groups[] = {
+	"gpio42",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+	"gpio42",
+};
+static const char * const alsp_int_groups[] = {
+	"gpio43",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+	"gpio43",
+};
+static const char * const mag_int_groups[] = {
+	"gpio44",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+	"gpio44",
+};
+static const char * const blsp6_spi_groups[] = {
+	"gpio47",
+};
+static const char * const fp_int_groups[] = {
+	"gpio48",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+	"gpio48",
+};
+static const char * const uim_batt_groups[] = {
+	"gpio49",
+};
+static const char * const cam2_standby_groups[] = {
+	"gpio50",
+};
+static const char * const uim1_data_groups[] = {
+	"gpio51",
+};
+static const char * const uim1_clk_groups[] = {
+	"gpio52",
+};
+static const char * const uim1_reset_groups[] = {
+	"gpio53",
+};
+static const char * const uim1_present_groups[] = {
+	"gpio54",
+};
+static const char * const uim2_data_groups[] = {
+	"gpio55",
+};
+static const char * const uim2_clk_groups[] = {
+	"gpio56",
+};
+static const char * const uim2_reset_groups[] = {
+	"gpio57",
+};
+static const char * const uim2_present_groups[] = {
+	"gpio58",
+};
+static const char * const sensor_rst_groups[] = {
+	"gpio59",
+};
+static const char * const mipi_dsi0_groups[] = {
+	"gpio60",
+};
+static const char * const smb_int_groups[] = {
+	"gpio61",
+};
+static const char * const cam0_ldo_groups[] = {
+	"gpio62",
+};
+static const char * const us_euro_groups[] = {
+	"gpio63",
+};
+static const char * const atest_char3_groups[] = {
+	"gpio63",
+};
+static const char * const dbg_out_groups[] = {
+	"gpio63",
+};
+static const char * const bimc_dte0_groups[] = {
+	"gpio63", "gpio65",
+};
+static const char * const ts_resout_groups[] = {
+	"gpio64",
+};
+static const char * const ts_sample_groups[] = {
+	"gpio65",
+};
+static const char * const sec_mi2s_mclk_b_groups[] = {
+	"gpio66",
+};
+static const char * const pri_mi2s_groups[] = {
+	"gpio66", "gpio85", "gpio86", "gpio88", "gpio94", "gpio95",
+};
+static const char * const sdcard_det_groups[] = {
+	"gpio67",
+};
+static const char * const atest_char1_groups[] = {
+	"gpio67",
+};
+static const char * const ebi_cdc_groups[] = {
+	"gpio67", "gpio69", "gpio118", "gpio119", "gpio120", "gpio123",
+};
+static const char * const audio_reset_groups[] = {
+	"gpio68",
+};
+static const char * const atest_char0_groups[] = {
+	"gpio68",
+};
+static const char * const audio_ref_groups[] = {
+	"gpio69",
+};
+static const char * const cdc_pdm0_groups[] = {
+	"gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+	"gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+	"gpio70",
+};
+static const char * const lpass_slimbus0_groups[] = {
+	"gpio71",
+};
+static const char * const lpass_slimbus1_groups[] = {
+	"gpio72",
+};
+static const char * const codec_int1_groups[] = {
+	"gpio73",
+};
+static const char * const codec_int2_groups[] = {
+	"gpio74",
+};
+static const char * const wcss_bt_groups[] = {
+	"gpio75", "gpio83", "gpio84",
+};
+static const char * const atest_char2_groups[] = {
+	"gpio75",
+};
+static const char * const ebi_ch0_groups[] = {
+	"gpio75",
+};
+static const char * const wcss_wlan2_groups[] = {
+	"gpio76",
+};
+static const char * const wcss_wlan1_groups[] = {
+	"gpio77",
+};
+static const char * const wcss_wlan0_groups[] = {
+	"gpio78",
+};
+static const char * const wcss_wlan_groups[] = {
+	"gpio79", "gpio80",
+};
+static const char * const wcss_fm_groups[] = {
+	"gpio81", "gpio82",
+};
+static const char * const ext_lpass_groups[] = {
+	"gpio81",
+};
+static const char * const cri_trng_groups[] = {
+	"gpio82",
+};
+static const char * const cri_trng1_groups[] = {
+	"gpio83",
+};
+static const char * const cri_trng0_groups[] = {
+	"gpio84",
+};
+static const char * const blsp_spi7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+	"gpio87",
+};
+static const char * const blsp_i2c7_groups[] = {
+	"gpio87", "gpio88",
+};
+static const char * const gcc_tlmm_groups[] = {
+	"gpio87",
+};
+static const char * const dmic0_clk_groups[] = {
+	"gpio89",
+};
+static const char * const dmic0_data_groups[] = {
+	"gpio90",
+};
+static const char * const key_volp_groups[] = {
+	"gpio91",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+	"gpio91",
+};
+static const char * const us_emitter_groups[] = {
+	"gpio92",
+};
+static const char * const wsa_irq_groups[] = {
+	"gpio93",
+};
+static const char * const wsa_io_groups[] = {
+	"gpio94", "gpio95",
+};
+static const char * const wsa_reset_groups[] = {
+	"gpio96",
+};
+static const char * const blsp_spi8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_uart8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_i2c8_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const gcc_plltest_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const nav_pps_in_a_groups[] = {
+	"gpio115",
+};
+static const char * const pa_indicator_groups[] = {
+	"gpio116",
+};
+static const char * const modem_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_in_b_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_groups[] = {
+	"gpio117",
+};
+static const char * const gsm0_tx_groups[] = {
+	"gpio119",
+};
+static const char * const atest_char_groups[] = {
+	"gpio120",
+};
+static const char * const atest_tsens_groups[] = {
+	"gpio120",
+};
+static const char * const bimc_dte1_groups[] = {
+	"gpio121", "gpio122",
+};
+static const char * const ssbi_wtr1_groups[] = {
+	"gpio122", "gpio123",
+};
+static const char * const fp_gpio_groups[] = {
+	"gpio124",
+};
+static const char * const coex_uart_groups[] = {
+	"gpio124", "gpio127",
+};
+static const char * const key_snapshot_groups[] = {
+	"gpio127",
+};
+static const char * const key_focus_groups[] = {
+	"gpio128",
+};
+static const char * const nfc_pwr_groups[] = {
+	"gpio129",
+};
+static const char * const blsp8_spi_groups[] = {
+	"gpio130",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+	"gpio132",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+	"gpio133",
+};
+
+static const struct msm_function msm8937_functions[] = {
+	FUNCTION(qdss_tracedata_b),
+	FUNCTION(blsp_uart1),
+	FUNCTION(gpio),
+	FUNCTION(blsp_spi1),
+	FUNCTION(adsp_ext),
+	FUNCTION(blsp_i2c1),
+	FUNCTION(prng_rosc),
+	FUNCTION(qdss_cti_trig_out_b0),
+	FUNCTION(blsp_spi2),
+	FUNCTION(blsp_uart2),
+	FUNCTION(blsp_uart3),
+	FUNCTION(pbs0),
+	FUNCTION(pbs1),
+	FUNCTION(pwr_modem_enabled_b),
+	FUNCTION(blsp_i2c3),
+	FUNCTION(gcc_gp2_clk_b),
+	FUNCTION(ldo_update),
+	FUNCTION(atest_combodac_to_gpio_native),
+	FUNCTION(ldo_en),
+	FUNCTION(blsp_i2c2),
+	FUNCTION(gcc_gp1_clk_b),
+	FUNCTION(pbs2),
+	FUNCTION(atest_gpsadc_dtest0_native),
+	FUNCTION(blsp_spi3),
+	FUNCTION(gcc_gp3_clk_b),
+	FUNCTION(blsp_spi4),
+	FUNCTION(blsp_uart4),
+	FUNCTION(sec_mi2s),
+	FUNCTION(pwr_nav_enabled_b),
+	FUNCTION(codec_mad),
+	FUNCTION(pwr_crypto_enabled_b),
+	FUNCTION(blsp_i2c4),
+	FUNCTION(blsp_spi5),
+	FUNCTION(blsp_uart5),
+	FUNCTION(qdss_traceclk_a),
+	FUNCTION(atest_bbrx1),
+	FUNCTION(m_voc),
+	FUNCTION(qdss_cti_trig_in_a0),
+	FUNCTION(qdss_cti_trig_in_b0),
+	FUNCTION(blsp_i2c6),
+	FUNCTION(qdss_traceclk_b),
+	FUNCTION(atest_wlan0),
+	FUNCTION(atest_wlan1),
+	FUNCTION(atest_bbrx0),
+	FUNCTION(blsp_i2c5),
+	FUNCTION(qdss_tracectl_a),
+	FUNCTION(atest_gpsadc_dtest1_native),
+	FUNCTION(qdss_tracedata_a),
+	FUNCTION(blsp_spi6),
+	FUNCTION(blsp_uart6),
+	FUNCTION(qdss_tracectl_b),
+	FUNCTION(mdp_vsync),
+	FUNCTION(pri_mi2s_mclk_a),
+	FUNCTION(sec_mi2s_mclk_a),
+	FUNCTION(cam_mclk),
+	FUNCTION(cci_i2c),
+	FUNCTION(pwr_modem_enabled_a),
+	FUNCTION(cci_timer0),
+	FUNCTION(cci_timer1),
+	FUNCTION(cam1_standby),
+	FUNCTION(pwr_nav_enabled_a),
+	FUNCTION(cam1_rst),
+	FUNCTION(pwr_crypto_enabled_a),
+	FUNCTION(forced_usb),
+	FUNCTION(qdss_cti_trig_out_b1),
+	FUNCTION(cam2_rst),
+	FUNCTION(webcam_standby),
+	FUNCTION(cci_async),
+	FUNCTION(webcam_rst),
+	FUNCTION(ov_ldo),
+	FUNCTION(sd_write),
+	FUNCTION(accel_int),
+	FUNCTION(gcc_gp1_clk_a),
+	FUNCTION(alsp_int),
+	FUNCTION(gcc_gp2_clk_a),
+	FUNCTION(mag_int),
+	FUNCTION(gcc_gp3_clk_a),
+	FUNCTION(blsp6_spi),
+	FUNCTION(fp_int),
+	FUNCTION(qdss_cti_trig_in_b1),
+	FUNCTION(uim_batt),
+	FUNCTION(cam2_standby),
+	FUNCTION(uim1_data),
+	FUNCTION(uim1_clk),
+	FUNCTION(uim1_reset),
+	FUNCTION(uim1_present),
+	FUNCTION(uim2_data),
+	FUNCTION(uim2_clk),
+	FUNCTION(uim2_reset),
+	FUNCTION(uim2_present),
+	FUNCTION(sensor_rst),
+	FUNCTION(mipi_dsi0),
+	FUNCTION(smb_int),
+	FUNCTION(cam0_ldo),
+	FUNCTION(us_euro),
+	FUNCTION(atest_char3),
+	FUNCTION(dbg_out),
+	FUNCTION(bimc_dte0),
+	FUNCTION(ts_resout),
+	FUNCTION(ts_sample),
+	FUNCTION(sec_mi2s_mclk_b),
+	FUNCTION(pri_mi2s),
+	FUNCTION(sdcard_det),
+	FUNCTION(atest_char1),
+	FUNCTION(ebi_cdc),
+	FUNCTION(audio_reset),
+	FUNCTION(atest_char0),
+	FUNCTION(audio_ref),
+	FUNCTION(cdc_pdm0),
+	FUNCTION(pri_mi2s_mclk_b),
+	FUNCTION(lpass_slimbus),
+	FUNCTION(lpass_slimbus0),
+	FUNCTION(lpass_slimbus1),
+	FUNCTION(codec_int1),
+	FUNCTION(codec_int2),
+	FUNCTION(wcss_bt),
+	FUNCTION(atest_char2),
+	FUNCTION(ebi_ch0),
+	FUNCTION(wcss_wlan2),
+	FUNCTION(wcss_wlan1),
+	FUNCTION(wcss_wlan0),
+	FUNCTION(wcss_wlan),
+	FUNCTION(wcss_fm),
+	FUNCTION(ext_lpass),
+	FUNCTION(cri_trng),
+	FUNCTION(cri_trng1),
+	FUNCTION(cri_trng0),
+	FUNCTION(blsp_spi7),
+	FUNCTION(blsp_uart7),
+	FUNCTION(pri_mi2s_ws),
+	FUNCTION(blsp_i2c7),
+	FUNCTION(gcc_tlmm),
+	FUNCTION(dmic0_clk),
+	FUNCTION(dmic0_data),
+	FUNCTION(key_volp),
+	FUNCTION(qdss_cti_trig_in_a1),
+	FUNCTION(us_emitter),
+	FUNCTION(wsa_irq),
+	FUNCTION(wsa_io),
+	FUNCTION(wsa_reset),
+	FUNCTION(blsp_spi8),
+	FUNCTION(blsp_uart8),
+	FUNCTION(blsp_i2c8),
+	FUNCTION(gcc_plltest),
+	FUNCTION(nav_pps_in_a),
+	FUNCTION(pa_indicator),
+	FUNCTION(modem_tsync),
+	FUNCTION(nav_tsync),
+	FUNCTION(nav_pps_in_b),
+	FUNCTION(nav_pps),
+	FUNCTION(gsm0_tx),
+	FUNCTION(atest_char),
+	FUNCTION(atest_tsens),
+	FUNCTION(bimc_dte1),
+	FUNCTION(ssbi_wtr1),
+	FUNCTION(fp_gpio),
+	FUNCTION(coex_uart),
+	FUNCTION(key_snapshot),
+	FUNCTION(key_focus),
+	FUNCTION(nfc_pwr),
+	FUNCTION(blsp8_spi),
+	FUNCTION(qdss_cti_trig_out_a0),
+	FUNCTION(qdss_cti_trig_out_a1),
+};
+
+static const struct msm_pingroup msm8937_groups[] = {
+	PINGROUP(0, blsp_spi1, blsp_uart1, qdss_tracedata_b, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(1, blsp_spi1, blsp_uart1, adsp_ext, NA, NA, NA, NA, NA,
+		 qdss_tracedata_b),
+	PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, prng_rosc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+	PINGROUP(4, blsp_spi2, blsp_uart2, ldo_update, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(5, blsp_spi2, blsp_uart2, ldo_en, NA, NA, NA, NA, NA, NA),
+	PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, gcc_gp1_clk_b,
+		 qdss_tracedata_b, NA, NA, NA, NA),
+	PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, pbs2, NA,
+		 qdss_tracedata_b, NA, atest_gpsadc_dtest0_native, NA),
+	PINGROUP(8, blsp_spi3, blsp_uart3, pbs0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(9, blsp_spi3, blsp_uart3, pbs1, pwr_modem_enabled_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(10, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp2_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(11, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp3_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(12, blsp_spi4, blsp_uart4, sec_mi2s, pwr_nav_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(13, blsp_spi4, blsp_uart4, sec_mi2s, pwr_crypto_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(14, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(15, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(16, blsp_spi5, blsp_uart5, NA, NA, NA, NA, qdss_traceclk_a,
+		 NA, atest_bbrx1),
+	PINGROUP(17, blsp_spi5, blsp_uart5, m_voc, qdss_cti_trig_in_a0, NA,
+		 atest_bbrx0, NA, NA, NA),
+	PINGROUP(18, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracectl_a, NA,
+		 atest_gpsadc_dtest1_native, NA, NA, NA),
+	PINGROUP(19, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracedata_a, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(20, blsp_spi6, blsp_uart6, NA, NA, NA, NA, NA, NA,
+		 qdss_tracectl_b),
+	PINGROUP(21, blsp_spi6, blsp_uart6, m_voc, NA, NA, NA, NA, NA,
+		 qdss_cti_trig_in_b0),
+	PINGROUP(22, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_traceclk_b, NA,
+		 atest_wlan0, NA, NA, NA),
+	PINGROUP(23, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_tracedata_b, NA,
+		 atest_wlan1, NA, NA, NA),
+	PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+	PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(28, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(29, cci_i2c, pwr_modem_enabled_a, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a, NA),
+	PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(31, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(32, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(33, cci_timer0, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(34, cci_timer1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(35, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(36, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(37, NA, NA, NA, NA, NA, qdss_cti_trig_out_b1, NA, NA, NA),
+	PINGROUP(38, NA, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(39, cci_async, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(40, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA),
+	PINGROUP(41, sd_write, NA, NA, NA, NA, NA, NA, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(42, gcc_gp1_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(43, gcc_gp2_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(44, gcc_gp3_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(45, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(46, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(47, blsp6_spi, NA, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(48, NA, qdss_cti_trig_in_b1, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(49, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(50, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(51, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(52, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(53, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, uim2_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(63, atest_char3, dbg_out, bimc_dte0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(65, bimc_dte0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(66, sec_mi2s_mclk_b, pri_mi2s, NA, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(67, atest_char1, ebi_cdc, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA, NA),
+	PINGROUP(68, atest_char0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(69, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, ebi_cdc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(70, lpass_slimbus, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(71, lpass_slimbus0, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(72, lpass_slimbus1, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(73, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(74, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(75, wcss_bt, atest_char2, NA, ebi_ch0, NA, NA, NA, NA, NA),
+	PINGROUP(76, wcss_wlan2, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(77, wcss_wlan1, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(78, wcss_wlan0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(79, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(80, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(81, wcss_fm, ext_lpass, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(82, wcss_fm, cri_trng, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(83, wcss_bt, cri_trng1, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(84, wcss_bt, cri_trng0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(85, pri_mi2s, blsp_spi7, blsp_uart7, NA, NA, NA, NA, NA, NA),
+	PINGROUP(86, pri_mi2s, blsp_spi7, blsp_uart7, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(87, pri_mi2s_ws, blsp_spi7, blsp_uart7, blsp_i2c7,
+		 qdss_tracedata_b, gcc_tlmm, NA, NA, NA),
+	PINGROUP(88, pri_mi2s, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(89, dmic0_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(90, dmic0_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(91, NA, NA, NA, NA, NA, qdss_cti_trig_in_a1, NA, NA, NA),
+	PINGROUP(92, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA, NA),
+	PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(94, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(95, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(96, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(97, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(98, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(99, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(110, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(111, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(112, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(113, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(114, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(115, NA, NA, nav_pps_in_a, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA),
+	PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(117, NA, modem_tsync, nav_tsync, nav_pps_in_b, nav_pps, NA,
+		 NA, NA, NA),
+	PINGROUP(118, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(119, gsm0_tx, NA, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(120, NA, atest_char, ebi_cdc, NA, atest_tsens, NA, NA, NA, NA),
+	PINGROUP(121, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+	PINGROUP(122, NA, ssbi_wtr1, NA, NA, bimc_dte1, NA, NA, NA, NA),
+	PINGROUP(123, NA, ssbi_wtr1, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(124, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(127, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(128, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(130, blsp8_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(131, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(132, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(133, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA, NA, NA, NA),
+	SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+	SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+	SDC_QDSD_PINGROUP(sdc1_rclk, 0x10a000, 15, 0),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+	SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+	SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+	SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+	SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+	SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+	SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8937_pinctrl = {
+	.pins = msm8937_pins,
+	.npins = ARRAY_SIZE(msm8937_pins),
+	.functions = msm8937_functions,
+	.nfunctions = ARRAY_SIZE(msm8937_functions),
+	.groups = msm8937_groups,
+	.ngroups = ARRAY_SIZE(msm8937_groups),
+	.ngpios = 134,
+};
+
+static int msm8937_pinctrl_probe(struct platform_device *pdev)
+{
+	return msm_pinctrl_probe(pdev, &msm8937_pinctrl);
+}
+
+static const struct of_device_id msm8937_pinctrl_of_match[] = {
+	{ .compatible = "qcom,msm8937-pinctrl", },
+	{ },
+};
+
+static struct platform_driver msm8937_pinctrl_driver = {
+	.driver = {
+		.name = "msm8937-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = msm8937_pinctrl_of_match,
+	},
+	.probe = msm8937_pinctrl_probe,
+	.remove = msm_pinctrl_remove,
+};
+
+static int __init msm8937_pinctrl_init(void)
+{
+	return platform_driver_register(&msm8937_pinctrl_driver);
+}
+arch_initcall(msm8937_pinctrl_init);
+
+static void __exit msm8937_pinctrl_exit(void)
+{
+	platform_driver_unregister(&msm8937_pinctrl_driver);
+}
+module_exit(msm8937_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8937 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8937_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
index f7af6da..37a6199 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm670.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -1588,7 +1588,7 @@
 	[156] = SDC_QDSD_PINGROUP(sdc2_data, 0x9a000, 9, 0),
 	[157] = UFS_RESET(ufs_reset, 0x9f000),
 };
-static const struct msm_dir_conn sdm670_dir_conn[] = {
+static struct msm_dir_conn sdm670_dir_conn[] = {
 	{1, 510},
 	{3, 511},
 	{5, 512},
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
index e77dcd9..72b730d 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -1681,7 +1681,7 @@
 	[153] = UFS_RESET(ufs_reset, 0x99f000),
 };
 
-static const struct msm_dir_conn sdm845_dir_conn[] = {
+static struct msm_dir_conn sdm845_dir_conn[] = {
 	{1, 510},
 	{3, 511},
 	{5, 512},
diff --git a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
index 6ceb39a..c5f1307 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -1105,6 +1105,97 @@
 	[106] = SDC_QDSD_PINGROUP(sdc2_data, 0x0, 9, 0),
 };
 
+static struct msm_gpio_mux_input sdxpoorwills_mux_in[] = {
+	{0, 1},
+	{1, 2},
+	{2, 5},
+	{3, 6},
+	{4, 9},
+	{5, 10},
+	{6, 11},
+	{7, 12},
+	{8, 13},
+	{9, 14},
+	{10, 15},
+	{11, 16},
+	{12, 17},
+	{13, 18},
+	{14, 19},
+	{15, 21},
+	{16, 22},
+	{17, 24},
+	{18, 25},
+	{19, 35},
+	{20, 42, 1},
+	{21, 43},
+	{22, 45},
+	{23, 46},
+	{24, 48},
+	{25, 50},
+	{26, 52},
+	{27, 53},
+	{28, 54},
+	{29, 55},
+	{30, 56},
+	{31, 57},
+	{32, 60},
+	{33, 61},
+	{34, 64},
+	{35, 65},
+	{36, 68},
+	{37, 71},
+	{38, 75},
+	{39, 76},
+	{40, 78},
+	{41, 79},
+	{42, 80},
+	{43, 82},
+	{44, 83},
+	{45, 84},
+	{46, 86},
+	{47, 87},
+	{48, 88},
+	{49, 89},
+	{50, 90},
+	{51, 93},
+	{52, 94},
+	{53, 95},
+	{54, 97},
+	{55, 98},
+};
+
+static struct msm_pdc_mux_output sdxpoorwills_mux_out[] = {
+	{0, 167},
+	{0, 168},
+	{0, 169},
+	{0, 170},
+	{0, 171},
+	{0, 172},
+	{0, 173},
+	{0, 174},
+	{0, 175},
+	{0, 176},
+	{0, 177},
+	{0, 178},
+	{0, 179},
+	{0, 180},
+	{0, 181},
+	{0, 182},
+	{0, 183},
+	{0, 184},
+	{0, 185},
+	{0, 186},
+	{0, 187},
+	{0, 188},
+	{0, 189},
+	{0, 190},
+	{0, 191},
+	{0, 192},
+	{0, 193},
+	{0, 194},
+	{0, 195},
+};
+
 static const struct msm_pinctrl_soc_data sdxpoorwills_pinctrl = {
 	.pins = sdxpoorwills_pins,
 	.npins = ARRAY_SIZE(sdxpoorwills_pins),
@@ -1112,6 +1203,11 @@
 	.nfunctions = ARRAY_SIZE(sdxpoorwills_functions),
 	.groups = sdxpoorwills_groups,
 	.ngroups = ARRAY_SIZE(sdxpoorwills_groups),
+	.gpio_mux_in = sdxpoorwills_mux_in,
+	.n_gpio_mux_in = ARRAY_SIZE(sdxpoorwills_mux_in),
+	.pdc_mux_out = sdxpoorwills_mux_out,
+	.n_pdc_mux_out = ARRAY_SIZE(sdxpoorwills_mux_out),
+	.n_pdc_mux_offset = 20,
 	.ngpios = 100,
 };
 
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 4abd8f1..782ce62 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -163,7 +163,7 @@
 
 config MSM_MHI_DEV
         tristate "Modem Device Interface Driver"
-	depends on EP_PCIE && IPA
+	depends on EP_PCIE && IPA3
         help
           This kernel module is used to interact with PCIe Root complex
           supporting MHI protocol. MHI is a data transmission protocol
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index c02aabf..00ca8dc4 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,8 @@
 #define PCIE20_PARF_DBI_BASE_ADDR_HI   0x354
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE        0x358
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI     0x35C
+#define PCIE20_PARF_ATU_BASE_ADDR      0x634
+#define PCIE20_PARF_ATU_BASE_ADDR_HI   0x638
 #define PCIE20_PARF_DEVICE_TYPE        0x1000
 
 #define PCIE20_ELBI_VERSION            0x00
@@ -98,6 +100,24 @@
 #define PCIE20_PLR_IATU_LTAR           0x918
 #define PCIE20_PLR_IATU_UTAR           0x91c
 
+#define PCIE20_IATU_BASE(n)            (n * 0x200)
+
+#define PCIE20_IATU_O_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x00)
+#define PCIE20_IATU_O_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x04)
+#define PCIE20_IATU_O_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x08)
+#define PCIE20_IATU_O_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x0c)
+#define PCIE20_IATU_O_LAR(n)           (PCIE20_IATU_BASE(n) + 0x10)
+#define PCIE20_IATU_O_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x14)
+#define PCIE20_IATU_O_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x18)
+
+#define PCIE20_IATU_I_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x100)
+#define PCIE20_IATU_I_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x104)
+#define PCIE20_IATU_I_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x108)
+#define PCIE20_IATU_I_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x10c)
+#define PCIE20_IATU_I_LAR(n)           (PCIE20_IATU_BASE(n) + 0x110)
+#define PCIE20_IATU_I_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x114)
+#define PCIE20_IATU_I_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x118)
+
 #define PCIE20_MHICFG                  0x110
 #define PCIE20_BHI_EXECENV             0x228
 
@@ -129,7 +149,7 @@
 
 #define EP_PCIE_LOG_PAGES 50
 #define EP_PCIE_MAX_VREG 2
-#define EP_PCIE_MAX_CLK 5
+#define EP_PCIE_MAX_CLK 7
 #define EP_PCIE_MAX_PIPE_CLK 1
 #define EP_PCIE_MAX_RESET 2
 
@@ -202,6 +222,7 @@
 	EP_PCIE_RES_MSI,
 	EP_PCIE_RES_DM_CORE,
 	EP_PCIE_RES_ELBI,
+	EP_PCIE_RES_IATU,
 	EP_PCIE_MAX_RES,
 };
 
@@ -292,6 +313,7 @@
 	void __iomem                 *msi;
 	void __iomem                 *dm_core;
 	void __iomem                 *elbi;
+	void __iomem                 *iatu;
 
 	struct msm_bus_scale_pdata   *bus_scale_table;
 	u32                          bus_client;
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index e48409b..055f026 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -68,6 +68,8 @@
 	{NULL, "pcie_0_slv_axi_clk", 0, true},
 	{NULL, "pcie_0_aux_clk", 1000000, true},
 	{NULL, "pcie_0_ldo", 0, true},
+	{NULL, "pcie_0_sleep_clk", 0, false},
+	{NULL, "pcie_0_slv_q2a_axi_clk", 0, false},
 };
 
 static struct ep_pcie_clk_info_t
@@ -82,12 +84,13 @@
 };
 
 static const struct ep_pcie_res_info_t ep_pcie_res_info[EP_PCIE_MAX_RES] = {
-	{"parf",	0, 0},
-	{"phy",		0, 0},
-	{"mmio",	0, 0},
-	{"msi",		0, 0},
-	{"dm_core",	0, 0},
-	{"elbi",	0, 0}
+	{"parf",	NULL, NULL},
+	{"phy",		NULL, NULL},
+	{"mmio",	NULL, NULL},
+	{"msi",		NULL, NULL},
+	{"dm_core",	NULL, NULL},
+	{"elbi",	NULL, NULL},
+	{"iatu",	NULL, NULL},
 };
 
 static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
@@ -318,8 +321,8 @@
 				break;
 			}
 			EP_PCIE_DBG(dev,
-				"PCIe V%d: set rate for clk %s.\n",
-				dev->rev, info->name);
+				"PCIe V%d: set rate %d for clk %s.\n",
+				dev->rev, info->freq, info->name);
 		}
 
 		rc = clk_prepare_enable(info->hdl);
@@ -528,6 +531,47 @@
 				0xf, dev->link_speed);
 	}
 
+	if (dev->active_config) {
+		struct resource *dbi = dev->res[EP_PCIE_RES_DM_CORE].resource;
+		u32 dbi_lo = dbi->start;
+
+		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
+
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
+					0, BIT(0));
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
+					0x200);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
+					0x0);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
+					0x100);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
+					dbi_lo);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: DBI base:0x%x.\n", dev->rev,
+			readl_relaxed(dev->parf + PCIE20_PARF_DBI_BASE_ADDR));
+
+		if (dev->phy_rev >= 6) {
+			struct resource *atu =
+					dev->res[EP_PCIE_RES_IATU].resource;
+			u32 atu_lo = atu->start;
+
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: configure MSB of ATU base for flipping and LSB as 0x%x.\n",
+				dev->rev, atu_lo);
+			ep_pcie_write_reg(dev->parf,
+					PCIE20_PARF_ATU_BASE_ADDR_HI, 0x100);
+			ep_pcie_write_reg(dev->parf, PCIE20_PARF_ATU_BASE_ADDR,
+					atu_lo);
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: LSB of ATU base:0x%x.\n",
+				dev->rev, readl_relaxed(dev->parf
+						+ PCIE20_PARF_ATU_BASE_ADDR));
+		}
+	}
+
 	/* Read halts write */
 	ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES,
 			0, BIT(0));
@@ -646,13 +690,6 @@
 			dev->rev,
 			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
 	}
-
-	if (dev->active_config) {
-		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
-
-		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
-	}
 }
 
 static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
@@ -671,6 +708,26 @@
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_LOWER, lower);
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_UPPER, 0x0);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL1(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_LTAR(0), lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_UTAR(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL2(0),
+					0xc0000000);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Inbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL1(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL1(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_LTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_LTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_UTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_UTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL2(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL2(0)));
+		return;
+	}
+
 	/* program inbound address translation using region 0 */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, 0x80000000);
 	/* set region to mem type */
@@ -701,6 +758,49 @@
 		"PCIe V%d: region:%d; lower:0x%x; limit:0x%x; target_lower:0x%x; target_upper:0x%x\n",
 		dev->rev, region, lower, limit, tgt_lower, tgt_upper);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_CTRL1(region),
+					0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LBAR(region),
+					lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UBAR(region),
+					upper);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LAR(region),
+					limit);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LTAR(region),
+					tgt_lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UTAR(region),
+					tgt_upper);
+		ep_pcie_write_mask(dev->iatu + PCIE20_IATU_O_CTRL2(region),
+					0, BIT(31));
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Outbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL1:0x%x\n",
+			readl_relaxed(dev->iatu
+					+ PCIE20_IATU_O_CTRL1(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL2:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_CTRL2(region)));
+
+		return;
+	}
+
 	/* program outbound address translation using an input region */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, region);
 	/* set region to mem type */
@@ -813,12 +913,10 @@
 		ret = of_property_read_u32_array(
 			(&pdev->dev)->of_node,
 			"max-clock-frequency-hz", clkfreq, cnt);
-		if (ret) {
-			EP_PCIE_ERR(dev,
-				"PCIe V%d: invalid max-clock-frequency-hz property:%d\n",
+		if (ret)
+			EP_PCIE_DBG2(dev,
+				"PCIe V%d: cannot get max-clock-frequency-hz property from DT:%d\n",
 				dev->rev, ret);
-			goto out;
-		}
 	}
 
 	for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
@@ -1037,6 +1135,7 @@
 	dev->msi = dev->res[EP_PCIE_RES_MSI].base;
 	dev->dm_core = dev->res[EP_PCIE_RES_DM_CORE].base;
 	dev->elbi = dev->res[EP_PCIE_RES_ELBI].base;
+	dev->iatu = dev->res[EP_PCIE_RES_IATU].base;
 
 out:
 	kfree(clkfreq);
@@ -1051,6 +1150,7 @@
 	dev->phy = NULL;
 	dev->mmio = NULL;
 	dev->msi = NULL;
+	dev->iatu = NULL;
 
 	if (dev->bus_client) {
 		msm_bus_scale_unregister_client(dev->bus_client);
@@ -1319,18 +1419,8 @@
 	}
 
 checkbme:
-	if (dev->active_config) {
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
-					0, BIT(0));
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
-					0x200);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
-					0x0);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
-					0x100);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
-					0x7FFFE000);
-	}
+	if (dev->active_config)
+		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
 
 	if (!(opt & EP_PCIE_OPT_ENUM_ASYNC)) {
 		/* Wait for up to 1000ms for BME to be set */
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
index 776ef08..f813bb9 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,11 @@
 			"PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n",
 			dev->rev, dev->phy_rev);
 		break;
+	case 6:
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: PHY V%d: Initializing 7nm QMP phy - 100MHz\n",
+			dev->rev, dev->phy_rev);
+		break;
 	default:
 		EP_PCIE_ERR(dev,
 			"PCIe V%d: Unexpected phy version %d is caught!\n",
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index e20ddba..b99435d 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -3167,52 +3167,53 @@
 EXPORT_SYMBOL(ipa_get_smmu_params);
 
 /**
- * ipa_conn_wdi3_pipes() - connect wdi3 pipes
+ * ipa_conn_wdi_pipes() - connect wdi pipes
  */
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_conn_wdi3_pipes, in, out);
+	IPA_API_DISPATCH_RETURN(ipa_conn_wdi_pipes, in, out, wdi_notify);
 
 	return ret;
 }
 
 /**
- * ipa_disconn_wdi3_pipes() - disconnect wdi3 pipes
+ * ipa_disconn_wdi_pipes() - disconnect wdi pipes
  */
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_disconn_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_disconn_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
 }
 
 /**
- * ipa_enable_wdi3_pipes() - enable wdi3 pipes
+ * ipa_enable_wdi_pipes() - enable wdi pipes
  */
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_enable_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_enable_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
 }
 
 /**
- * ipa_disable_wdi3_pipes() - disable wdi3 pipes
+ * ipa_disable_wdi_pipes() - disable wdi pipes
  */
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_disable_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_disable_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
@@ -3230,6 +3231,18 @@
 	return ret;
 }
 
+/**
+ * ipa_pm_is_used() - Returns if IPA PM framework is used
+ */
+bool ipa_pm_is_used(void)
+{
+	bool ret;
+
+	IPA_API_DISPATCH_RETURN(ipa_pm_is_used);
+
+	return ret;
+}
+
 static const struct dev_pm_ops ipa_pm_ops = {
 	.suspend_noirq = ipa_ap_suspend,
 	.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index f3e62b8..fc4362f 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -403,16 +403,17 @@
 
 	void (*ipa_ntn_uc_dereg_rdyCB)(void);
 
-	int (*ipa_conn_wdi3_pipes)(struct ipa_wdi3_conn_in_params *in,
-		struct ipa_wdi3_conn_out_params *out);
+	int (*ipa_conn_wdi_pipes)(struct ipa_wdi_conn_in_params *in,
+		struct ipa_wdi_conn_out_params *out,
+		ipa_wdi_meter_notifier_cb wdi_notify);
 
-	int (*ipa_disconn_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_disconn_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
-	int (*ipa_enable_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_enable_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
-	int (*ipa_disable_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_disable_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
 	int (*ipa_tz_unlock_reg)(struct ipa_tz_unlock_reg_info *reg_info,
@@ -421,6 +422,8 @@
 	int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
 		struct ipa_smmu_out_params *out);
 	int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
+
+	bool (*ipa_pm_is_used)(void);
 };
 
 #ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index eadd58b..9f8bfbe 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -619,8 +619,10 @@
 	}
 
 	if (ecm_ipa_ctx->is_vlan_mode)
-		if (unlikely(skb->protocol != ETH_P_8021Q))
-			ECM_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+		if (unlikely(skb->protocol != htons(ETH_P_8021Q)))
+			ECM_IPA_DEBUG(
+				"ether_type != ETH_P_8021Q && vlan, prot = 0x%X\n"
+				, skb->protocol);
 
 	ret = ipa_tx_dp(ecm_ipa_ctx->ipa_to_usb_client, skb, NULL);
 	if (ret) {
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index a8946bf..e23541c 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -747,6 +747,10 @@
 		&ipa3_usb_ctx->ttype_ctx[ttype];
 	int result;
 
+	/* there is one PM resource for teth and one for DPL */
+	if (!IPA3_USB_IS_TTYPE_DPL(ttype) && ipa3_usb_ctx->num_init_prot > 0)
+		return 0;
+
 	memset(&ttype_ctx->pm_ctx.reg_params, 0,
 		sizeof(ttype_ctx->pm_ctx.reg_params));
 	ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
@@ -1026,11 +1030,11 @@
 	return 0;
 
 teth_prot_init_fail:
-	if (ipa_pm_is_used()) {
-		ipa3_usb_deregister_pm(ttype);
-	} else {
-		if ((IPA3_USB_IS_TTYPE_DPL(ttype))
-			|| (ipa3_usb_ctx->num_init_prot == 0)) {
+	if ((IPA3_USB_IS_TTYPE_DPL(ttype))
+		|| (ipa3_usb_ctx->num_init_prot == 0)) {
+		if (ipa_pm_is_used()) {
+			ipa3_usb_deregister_pm(ttype);
+		} else {
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
 				false;
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
@@ -2539,14 +2543,15 @@
 		goto bad_params;
 	}
 
-	if (ipa_pm_is_used()) {
-		ipa3_usb_deregister_pm(ttype);
-	} else {
-		if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
-			(ipa3_usb_ctx->num_init_prot == 0)) {
-			if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
-				IPA_USB_ERR(
-					"failed to change state to invalid\n");
+	if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
+		(ipa3_usb_ctx->num_init_prot == 0)) {
+		if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
+			IPA_USB_ERR(
+				"failed to change state to invalid\n");
+		if (ipa_pm_is_used()) {
+			ipa3_usb_deregister_pm(ttype);
+			ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+		} else {
 			ipa_rm_delete_resource(
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
index f4c8763..b2e454a 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,9 +14,10 @@
 #include <linux/msm_ipa.h>
 #include <linux/string.h>
 #include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
 
-#define OFFLOAD_DRV_NAME "ipa_wdi3"
-#define IPA_WDI3_DBG(fmt, args...) \
+#define OFFLOAD_DRV_NAME "ipa_wdi"
+#define IPA_WDI_DBG(fmt, args...) \
 	do { \
 		pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -26,7 +27,7 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-#define IPA_WDI3_DBG_LOW(fmt, args...) \
+#define IPA_WDI_DBG_LOW(fmt, args...) \
 	do { \
 		pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -34,7 +35,7 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-#define IPA_WDI3_ERR(fmt, args...) \
+#define IPA_WDI_ERR(fmt, args...) \
 	do { \
 		pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -44,32 +45,107 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-struct ipa_wdi3_intf_info {
+struct ipa_wdi_intf_info {
 	char netdev_name[IPA_RESOURCE_NAME_MAX];
 	u8 hdr_len;
 	u32 partial_hdr_hdl[IPA_IP_MAX];
 	struct list_head link;
 };
 
-struct ipa_wdi3_context {
+struct ipa_wdi_context {
 	struct list_head head_intf_list;
-	ipa_notify_cb notify;
-	void *priv;
-	struct completion wdi3_completion;
+	struct completion wdi_completion;
 	struct mutex lock;
+	enum ipa_wdi_version wdi_version;
+	u8 is_smmu_enabled;
+	u32 tx_pipe_hdl;
+	u32 rx_pipe_hdl;
+	u8 num_sys_pipe_needed;
+	u32 sys_pipe_hdl[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+	u32 ipa_pm_hdl;
+	ipa_wdi_meter_notifier_cb wdi_notify;
 };
 
-static struct ipa_wdi3_context *ipa_wdi3_ctx;
+static struct ipa_wdi_context *ipa_wdi_ctx;
 
-static int ipa_wdi3_commit_partial_hdr(
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out)
+{
+	struct ipa_wdi_uc_ready_params uc_ready_params;
+	struct ipa_smmu_in_params smmu_in;
+	struct ipa_smmu_out_params smmu_out;
+
+	if (ipa_wdi_ctx) {
+		IPA_WDI_ERR("ipa_wdi_ctx was initialized before\n");
+		return -EFAULT;
+	}
+
+	if (in->wdi_version > IPA_WDI_3 || in->wdi_version < IPA_WDI_1) {
+		IPA_WDI_ERR("wrong wdi version: %d\n", in->wdi_version);
+		return -EFAULT;
+	}
+
+	ipa_wdi_ctx = kzalloc(sizeof(*ipa_wdi_ctx), GFP_KERNEL);
+	if (ipa_wdi_ctx == NULL)
+		return -ENOMEM;
+
+	mutex_init(&ipa_wdi_ctx->lock);
+	init_completion(&ipa_wdi_ctx->wdi_completion);
+	INIT_LIST_HEAD(&ipa_wdi_ctx->head_intf_list);
+
+	ipa_wdi_ctx->wdi_version = in->wdi_version;
+	uc_ready_params.notify = in->notify;
+	uc_ready_params.priv = in->priv;
+	ipa_wdi_ctx->wdi_notify = in->wdi_notify;
+
+	if (ipa_uc_reg_rdyCB(&uc_ready_params) != 0) {
+		mutex_destroy(&ipa_wdi_ctx->lock);
+		kfree(ipa_wdi_ctx);
+		ipa_wdi_ctx = NULL;
+		return -EFAULT;
+	}
+
+	out->is_uC_ready = uc_ready_params.is_uC_ready;
+
+	smmu_in.smmu_client = IPA_SMMU_WLAN_CLIENT;
+	if (ipa_get_smmu_params(&smmu_in, &smmu_out))
+		out->is_smmu_enabled = false;
+	else
+		out->is_smmu_enabled = smmu_out.smmu_enable;
+
+	ipa_wdi_ctx->is_smmu_enabled = out->is_smmu_enabled;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_init);
+
+int ipa_wdi_cleanup(void)
+{
+	struct ipa_wdi_intf_info *entry;
+	struct ipa_wdi_intf_info *next;
+
+	/* clear interface list */
+	list_for_each_entry_safe(entry, next,
+		&ipa_wdi_ctx->head_intf_list, link) {
+		list_del(&entry->link);
+		kfree(entry);
+	}
+	mutex_destroy(&ipa_wdi_ctx->lock);
+	kfree(ipa_wdi_ctx);
+	ipa_wdi_ctx = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_cleanup);
+
+static int ipa_wdi_commit_partial_hdr(
 	struct ipa_ioc_add_hdr *hdr,
 	const char *netdev_name,
-	struct ipa_wdi3_hdr_info *hdr_info)
+	struct ipa_wdi_hdr_info *hdr_info)
 {
 	int i;
 
 	if (!hdr || !hdr_info || !netdev_name) {
-		IPA_WDI3_ERR("Invalid input\n");
+		IPA_WDI_ERR("Invalid input\n");
 		return -EINVAL;
 	}
 
@@ -90,18 +166,18 @@
 	}
 
 	if (ipa_add_hdr(hdr)) {
-		IPA_WDI3_ERR("fail to add partial headers\n");
+		IPA_WDI_ERR("fail to add partial headers\n");
 		return -EFAULT;
 	}
 
 	return 0;
 }
 
-int ipa_wdi3_reg_intf(struct ipa_wdi3_reg_intf_in_params *in)
+int ipa_wdi_reg_intf(struct ipa_wdi_reg_intf_in_params *in)
 {
 	struct ipa_ioc_add_hdr *hdr;
-	struct ipa_wdi3_intf_info *new_intf;
-	struct ipa_wdi3_intf_info *entry;
+	struct ipa_wdi_intf_info *new_intf;
+	struct ipa_wdi_intf_info *entry;
 	struct ipa_tx_intf tx;
 	struct ipa_rx_intf rx;
 	struct ipa_ioc_tx_intf_prop tx_prop[2];
@@ -110,36 +186,30 @@
 	int ret = 0;
 
 	if (in == NULL) {
-		IPA_WDI3_ERR("invalid params in=%pK\n", in);
+		IPA_WDI_ERR("invalid params in=NULL\n");
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
-		if (ipa_wdi3_ctx == NULL) {
-			IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
-			return -ENOMEM;
-		}
-		mutex_init(&ipa_wdi3_ctx->lock);
-		INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
 	}
 
-	IPA_WDI3_DBG("register interface for netdev %s\n",
+	IPA_WDI_DBG("register interface for netdev %s\n",
 		in->netdev_name);
 
-	mutex_lock(&ipa_wdi3_ctx->lock);
-	list_for_each_entry(entry, &ipa_wdi3_ctx->head_intf_list, link)
+	mutex_lock(&ipa_wdi_ctx->lock);
+	list_for_each_entry(entry, &ipa_wdi_ctx->head_intf_list, link)
 		if (strcmp(entry->netdev_name, in->netdev_name) == 0) {
-			IPA_WDI3_DBG("intf was added before.\n");
-			mutex_unlock(&ipa_wdi3_ctx->lock);
+			IPA_WDI_DBG("intf was added before\n");
+			mutex_unlock(&ipa_wdi_ctx->lock);
 			return 0;
 		}
 
-	IPA_WDI3_DBG("intf was not added before, proceed.\n");
+	IPA_WDI_DBG("intf was not added before, proceed\n");
 	new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL);
 	if (new_intf == NULL) {
-		IPA_WDI3_ERR("fail to alloc new intf\n");
-		mutex_unlock(&ipa_wdi3_ctx->lock);
+		mutex_unlock(&ipa_wdi_ctx->lock);
 		return -ENOMEM;
 	}
 
@@ -152,20 +222,19 @@
 	len = sizeof(struct ipa_ioc_add_hdr) + 2 * sizeof(struct ipa_hdr_add);
 	hdr = kzalloc(len, GFP_KERNEL);
 	if (hdr == NULL) {
-		IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
 		ret = -EFAULT;
 		goto fail_alloc_hdr;
 	}
 
-	if (ipa_wdi3_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
-		IPA_WDI3_ERR("fail to commit partial headers\n");
+	if (ipa_wdi_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
+		IPA_WDI_ERR("fail to commit partial headers\n");
 		ret = -EFAULT;
 		goto fail_commit_hdr;
 	}
 
 	new_intf->partial_hdr_hdl[IPA_IP_v4] = hdr->hdr[IPA_IP_v4].hdr_hdl;
 	new_intf->partial_hdr_hdl[IPA_IP_v6] = hdr->hdr[IPA_IP_v6].hdr_hdl;
-	IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+	IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
 		hdr->hdr[IPA_IP_v4].hdr_hdl, hdr->hdr[IPA_IP_v6].hdr_hdl);
 
 	/* populate tx prop */
@@ -175,12 +244,14 @@
 	memset(tx_prop, 0, sizeof(tx_prop));
 	tx_prop[0].ip = IPA_IP_v4;
 	tx_prop[0].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+	tx_prop[0].alt_dst_pipe = in->alt_dst_pipe;
 	tx_prop[0].hdr_l2_type = in->hdr_info[0].hdr_type;
 	strlcpy(tx_prop[0].hdr_name, hdr->hdr[IPA_IP_v4].name,
 		sizeof(tx_prop[0].hdr_name));
 
 	tx_prop[1].ip = IPA_IP_v6;
 	tx_prop[1].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+	tx_prop[1].alt_dst_pipe = in->alt_dst_pipe;
 	tx_prop[1].hdr_l2_type = in->hdr_info[1].hdr_type;
 	strlcpy(tx_prop[1].hdr_name, hdr->hdr[IPA_IP_v6].name,
 		sizeof(tx_prop[1].hdr_name));
@@ -209,54 +280,53 @@
 	}
 
 	if (ipa_register_intf(in->netdev_name, &tx, &rx)) {
-		IPA_WDI3_ERR("fail to add interface prop\n");
+		IPA_WDI_ERR("fail to add interface prop\n");
 		ret = -EFAULT;
 		goto fail_commit_hdr;
 	}
 
-	list_add(&new_intf->link, &ipa_wdi3_ctx->head_intf_list);
-	init_completion(&ipa_wdi3_ctx->wdi3_completion);
+	list_add(&new_intf->link, &ipa_wdi_ctx->head_intf_list);
+	init_completion(&ipa_wdi_ctx->wdi_completion);
 
 	kfree(hdr);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return 0;
 
 fail_commit_hdr:
 	kfree(hdr);
 fail_alloc_hdr:
 	kfree(new_intf);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_reg_intf);
+EXPORT_SYMBOL(ipa_wdi_reg_intf);
 
-int ipa_wdi3_dereg_intf(const char *netdev_name)
+int ipa_wdi_dereg_intf(const char *netdev_name)
 {
 	int len, ret = 0;
 	struct ipa_ioc_del_hdr *hdr = NULL;
-	struct ipa_wdi3_intf_info *entry;
-	struct ipa_wdi3_intf_info *next;
+	struct ipa_wdi_intf_info *entry;
+	struct ipa_wdi_intf_info *next;
 
 	if (!netdev_name) {
-		IPA_WDI3_ERR("no netdev name.\n");
+		IPA_WDI_ERR("no netdev name\n");
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		return -EPERM;
 	}
 
-	mutex_lock(&ipa_wdi3_ctx->lock);
-	list_for_each_entry_safe(entry, next, &ipa_wdi3_ctx->head_intf_list,
+	mutex_lock(&ipa_wdi_ctx->lock);
+	list_for_each_entry_safe(entry, next, &ipa_wdi_ctx->head_intf_list,
 		link)
 		if (strcmp(entry->netdev_name, netdev_name) == 0) {
 			len = sizeof(struct ipa_ioc_del_hdr) +
 				2 * sizeof(struct ipa_hdr_del);
 			hdr = kzalloc(len, GFP_KERNEL);
 			if (hdr == NULL) {
-				IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
-				mutex_unlock(&ipa_wdi3_ctx->lock);
+				mutex_unlock(&ipa_wdi_ctx->lock);
 				return -ENOMEM;
 			}
 
@@ -264,20 +334,21 @@
 			hdr->num_hdls = 2;
 			hdr->hdl[0].hdl = entry->partial_hdr_hdl[0];
 			hdr->hdl[1].hdl = entry->partial_hdr_hdl[1];
-			IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+			IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
 				hdr->hdl[0].hdl, hdr->hdl[1].hdl);
 
 			if (ipa_del_hdr(hdr)) {
-				IPA_WDI3_ERR("fail to delete partial header\n");
+				IPA_WDI_ERR("fail to delete partial header\n");
 				ret = -EFAULT;
 				goto fail;
 			}
 
 			if (ipa_deregister_intf(entry->netdev_name)) {
-				IPA_WDI3_ERR("fail to del interface props\n");
+				IPA_WDI_ERR("fail to del interface props\n");
 				ret = -EFAULT;
 				goto fail;
 			}
+
 			list_del(&entry->link);
 			kfree(entry);
 
@@ -286,241 +357,512 @@
 
 fail:
 	kfree(hdr);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_dereg_intf);
+EXPORT_SYMBOL(ipa_wdi_dereg_intf);
 
-static void ipa_wdi3_rm_notify(void *user_data, enum ipa_rm_event event,
+static void ipa_wdi_rm_notify(void *user_data, enum ipa_rm_event event,
 		unsigned long data)
 {
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("Invalid context\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("Invalid context\n");
 		return;
 	}
 
 	switch (event) {
 	case IPA_RM_RESOURCE_GRANTED:
-		complete_all(&ipa_wdi3_ctx->wdi3_completion);
+		complete_all(&ipa_wdi_ctx->wdi_completion);
 		break;
 
 	case IPA_RM_RESOURCE_RELEASED:
 		break;
 
 	default:
-		IPA_WDI3_ERR("Invalid RM Evt: %d", event);
+		IPA_WDI_ERR("Invalid RM Evt: %d", event);
 		break;
 	}
 }
 
-static int ipa_wdi3_cons_release(void)
+static int ipa_wdi_cons_release(void)
 {
 	return 0;
 }
 
-static int ipa_wdi3_cons_request(void)
+static int ipa_wdi_cons_request(void)
 {
 	int ret = 0;
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		ret = -EFAULT;
 	}
 
 	return ret;
 }
 
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out)
+static void ipa_wdi_pm_cb(void *p, enum ipa_pm_cb_event event)
 {
-	int ret = 0;
+	IPA_WDI_DBG("received pm event %d\n", event);
+}
+
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+			struct ipa_wdi_conn_out_params *out)
+{
+	int i, j, ret = 0;
 	struct ipa_rm_create_params param;
+	struct ipa_pm_register_params pm_params;
+	struct ipa_wdi_in_params in_tx;
+	struct ipa_wdi_in_params in_rx;
+	struct ipa_wdi_out_params out_tx;
+	struct ipa_wdi_out_params out_rx;
 
 	if (!(in && out)) {
-		IPA_WDI3_ERR("empty parameters. in=%pK out=%pK\n", in, out);
+		IPA_WDI_ERR("empty parameters. in=%pK out=%pK\n", in, out);
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
-		if (ipa_wdi3_ctx == NULL) {
-			IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
-			return -EFAULT;
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
+	}
+
+	if (in->num_sys_pipe_needed > IPA_WDI_MAX_SUPPORTED_SYS_PIPE) {
+		IPA_WDI_ERR("ipa can only support up to %d sys pipe\n",
+			IPA_WDI_MAX_SUPPORTED_SYS_PIPE);
+		return -EINVAL;
+	}
+	ipa_wdi_ctx->num_sys_pipe_needed = in->num_sys_pipe_needed;
+	IPA_WDI_DBG("number of sys pipe %d\n", in->num_sys_pipe_needed);
+
+	/* setup sys pipe when needed */
+	for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+		ret = ipa_setup_sys_pipe(&in->sys_in[i],
+			&ipa_wdi_ctx->sys_pipe_hdl[i]);
+		if (ret) {
+			IPA_WDI_ERR("fail to setup sys pipe %d\n", i);
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
 		}
-		mutex_init(&ipa_wdi3_ctx->lock);
-		INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
-	}
-	ipa_wdi3_ctx->notify = in->notify;
-	ipa_wdi3_ctx->priv = in->priv;
-
-	memset(&param, 0, sizeof(param));
-	param.name = IPA_RM_RESOURCE_WLAN_PROD;
-	param.reg_params.user_data = ipa_wdi3_ctx;
-	param.reg_params.notify_cb = ipa_wdi3_rm_notify;
-	param.floor_voltage = IPA_VOLTAGE_SVS;
-	ret = ipa_rm_create_resource(&param);
-	if (ret) {
-		IPA_WDI3_ERR("fail to create WLAN_PROD resource\n");
-		return -EFAULT;
 	}
 
-	memset(&param, 0, sizeof(param));
-	param.name = IPA_RM_RESOURCE_WLAN_CONS;
-	param.request_resource = ipa_wdi3_cons_request;
-	param.release_resource = ipa_wdi3_cons_release;
-	ret = ipa_rm_create_resource(&param);
-	if (ret) {
-		IPA_WDI3_ERR("fail to create WLAN_CONS resource\n");
-		goto fail_create_rm_cons;
+	if (!ipa_pm_is_used()) {
+		memset(&param, 0, sizeof(param));
+		param.name = IPA_RM_RESOURCE_WLAN_PROD;
+		param.reg_params.user_data = ipa_wdi_ctx;
+		param.reg_params.notify_cb = ipa_wdi_rm_notify;
+		param.floor_voltage = IPA_VOLTAGE_SVS;
+		ret = ipa_rm_create_resource(&param);
+		if (ret) {
+			IPA_WDI_ERR("fail to create WLAN_PROD resource\n");
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
+		}
+
+		memset(&param, 0, sizeof(param));
+		param.name = IPA_RM_RESOURCE_WLAN_CONS;
+		param.request_resource = ipa_wdi_cons_request;
+		param.release_resource = ipa_wdi_cons_release;
+		ret = ipa_rm_create_resource(&param);
+		if (ret) {
+			IPA_WDI_ERR("fail to create WLAN_CONS resource\n");
+			goto fail_create_rm_cons;
+		}
+
+		if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+			IPA_RM_RESOURCE_APPS_CONS)) {
+			IPA_WDI_ERR("fail to add rm dependency\n");
+			ret = -EFAULT;
+			goto fail_add_dependency;
+		}
+	} else {
+		pm_params.name = "wdi";
+		pm_params.callback = ipa_wdi_pm_cb;
+		pm_params.user_data = NULL;
+		pm_params.group = IPA_PM_GROUP_DEFAULT;
+		if (ipa_pm_register(&pm_params, &ipa_wdi_ctx->ipa_pm_hdl)) {
+			IPA_WDI_ERR("fail to register ipa pm\n");
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
+		}
 	}
 
-	if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
-		IPA_RM_RESOURCE_APPS_CONS)) {
-		IPA_WDI3_ERR("fail to add rm dependency\n");
-		ret = -EFAULT;
-		goto fail;
-	}
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_conn_wdi_pipes(in, out, ipa_wdi_ctx->wdi_notify)) {
+			IPA_WDI_ERR("fail to setup wdi pipes\n");
+			ret = -EFAULT;
+			goto fail_connect_pipe;
+		}
+	} else {
+		memset(&in_tx, 0, sizeof(in_tx));
+		memset(&in_rx, 0, sizeof(in_rx));
+		memset(&out_tx, 0, sizeof(out_tx));
+		memset(&out_rx, 0, sizeof(out_rx));
+		in_rx.wdi_notify = ipa_wdi_ctx->wdi_notify;
+		if (in->is_smmu_enabled == false) {
+			/* firsr setup rx pipe */
+			in_rx.sys.ipa_ep_cfg = in->u_rx.rx.ipa_ep_cfg;
+			in_rx.sys.client = in->u_rx.rx.client;
+			in_rx.sys.notify = in->notify;
+			in_rx.sys.priv = in->priv;
+			in_rx.smmu_enabled = in->is_smmu_enabled;
+			in_rx.u.ul.rdy_ring_base_pa =
+				in->u_rx.rx.transfer_ring_base_pa;
+			in_rx.u.ul.rdy_ring_size =
+				in->u_rx.rx.transfer_ring_size;
+			in_rx.u.ul.rdy_ring_rp_pa =
+				in->u_rx.rx.transfer_ring_doorbell_pa;
+			in_rx.u.ul.rdy_comp_ring_base_pa =
+				in->u_rx.rx.event_ring_base_pa;
+			in_rx.u.ul.rdy_comp_ring_wp_pa =
+				in->u_rx.rx.event_ring_doorbell_pa;
+			in_rx.u.ul.rdy_comp_ring_size =
+				in->u_rx.rx.event_ring_size;
+			if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+				IPA_WDI_ERR("fail to setup rx pipe\n");
+				ret = -EFAULT;
+				goto fail_connect_pipe;
+			}
+			ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+			out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+			IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
 
-	if (ipa_conn_wdi3_pipes(in, out)) {
-		IPA_WDI3_ERR("fail to setup wdi3 pipes\n");
-		ret = -EFAULT;
-		goto fail;
+			/* then setup tx pipe */
+			in_tx.sys.ipa_ep_cfg = in->u_tx.tx.ipa_ep_cfg;
+			in_tx.sys.client = in->u_tx.tx.client;
+			in_tx.smmu_enabled = in->is_smmu_enabled;
+			in_tx.u.dl.comp_ring_base_pa =
+				in->u_tx.tx.transfer_ring_base_pa;
+			in_tx.u.dl.comp_ring_size =
+				in->u_tx.tx.transfer_ring_size;
+			in_tx.u.dl.ce_ring_base_pa =
+				in->u_tx.tx.event_ring_base_pa;
+			in_tx.u.dl.ce_door_bell_pa =
+				in->u_tx.tx.event_ring_doorbell_pa;
+			in_tx.u.dl.ce_ring_size =
+				in->u_tx.tx.event_ring_size;
+			in_tx.u.dl.num_tx_buffers =
+				in->u_tx.tx.num_pkt_buffers;
+			if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+				IPA_WDI_ERR("fail to setup tx pipe\n");
+				ret = -EFAULT;
+				goto fail;
+			}
+			ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+			out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+			IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+		} else { /* smmu is enabled */
+			/* firsr setup rx pipe */
+			in_rx.sys.ipa_ep_cfg = in->u_rx.rx_smmu.ipa_ep_cfg;
+			in_rx.sys.client = in->u_rx.rx_smmu.client;
+			in_rx.sys.notify = in->notify;
+			in_rx.sys.priv = in->priv;
+			in_rx.smmu_enabled = in->is_smmu_enabled;
+			in_rx.u.ul_smmu.rdy_ring =
+				in->u_rx.rx_smmu.transfer_ring_base;
+			in_rx.u.ul_smmu.rdy_ring_size =
+				in->u_rx.rx_smmu.transfer_ring_size;
+			in_rx.u.ul_smmu.rdy_ring_rp_pa =
+				in->u_rx.rx_smmu.transfer_ring_doorbell_pa;
+			in_rx.u.ul_smmu.rdy_comp_ring =
+				in->u_rx.rx_smmu.event_ring_base;
+			in_rx.u.ul_smmu.rdy_comp_ring_wp_pa =
+				in->u_rx.rx_smmu.event_ring_doorbell_pa;
+			in_rx.u.ul_smmu.rdy_comp_ring_size =
+				in->u_rx.rx_smmu.event_ring_size;
+			if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+				IPA_WDI_ERR("fail to setup rx pipe\n");
+				ret = -EFAULT;
+				goto fail_connect_pipe;
+			}
+			ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+			out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+			IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
+
+			/* then setup tx pipe */
+			in_tx.sys.ipa_ep_cfg = in->u_tx.tx_smmu.ipa_ep_cfg;
+			in_tx.sys.client = in->u_tx.tx_smmu.client;
+			in_tx.smmu_enabled = in->is_smmu_enabled;
+			in_tx.u.dl_smmu.comp_ring =
+				in->u_tx.tx_smmu.transfer_ring_base;
+			in_tx.u.dl_smmu.comp_ring_size =
+				in->u_tx.tx_smmu.transfer_ring_size;
+			in_tx.u.dl_smmu.ce_ring =
+				in->u_tx.tx_smmu.event_ring_base;
+			in_tx.u.dl_smmu.ce_door_bell_pa =
+				in->u_tx.tx_smmu.event_ring_doorbell_pa;
+			in_tx.u.dl_smmu.ce_ring_size =
+				in->u_tx.tx_smmu.event_ring_size;
+			in_tx.u.dl_smmu.num_tx_buffers =
+				in->u_tx.tx_smmu.num_pkt_buffers;
+			if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+				IPA_WDI_ERR("fail to setup tx pipe\n");
+				ret = -EFAULT;
+				goto fail;
+			}
+			ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+			out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+			IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+		}
 	}
 
 	return 0;
 
 fail:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
+	ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl);
+fail_connect_pipe:
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+			IPA_RM_RESOURCE_APPS_CONS);
+	else
+		ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl);
+fail_add_dependency:
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
 fail_create_rm_cons:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
-
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
+fail_setup_sys_pipe:
+	for (j = 0; j < i; j++)
+		ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[j]);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_conn_pipes);
+EXPORT_SYMBOL(ipa_wdi_conn_pipes);
 
-int ipa_wdi3_disconn_pipes(void)
+int ipa_wdi_disconn_pipes(void)
 {
-	int ipa_ep_idx_rx, ipa_ep_idx_tx;
+	int i, ipa_ep_idx_rx, ipa_ep_idx_tx;
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		return -EPERM;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_disconn_wdi3_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
-		IPA_WDI3_ERR("fail to tear down wdi3 pipes\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
-				IPA_RM_RESOURCE_APPS_CONS)) {
-		IPA_WDI3_ERR("fail to delete rm dependency\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
-		IPA_WDI3_ERR("fail to delete WLAN_PROD resource\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
-		IPA_WDI3_ERR("fail to delete WLAN_CONS resource\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_disconn_pipes);
-
-int ipa_wdi3_enable_pipes(void)
-{
-	int ret;
-	int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
-		return -EPERM;
-	}
-
-	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_enable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
-		IPA_WDI3_ERR("fail to enable wdi3 pipes\n");
-		return -EFAULT;
-	}
-
-	ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
-	if (ret == -EINPROGRESS) {
-		if (wait_for_completion_timeout(&ipa_wdi3_ctx->wdi3_completion,
-			10*HZ) == 0) {
-			IPA_WDI3_ERR("WLAN_PROD resource req time out\n");
+	/* tear down sys pipe if needed */
+	for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+		if (ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[i])) {
+			IPA_WDI_ERR("fail to tear down sys pipe %d\n", i);
 			return -EFAULT;
 		}
-	} else if (ret != 0) {
-		IPA_WDI3_ERR("fail to request resource\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_enable_pipes);
-
-int ipa_wdi3_disable_pipes(void)
-{
-	int ret;
-	int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
-		return -EPERM;
-	}
-
-	ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
-	if (ret != 0) {
-		IPA_WDI3_ERR("fail to release resource\n");
-		return -EFAULT;
 	}
 
 	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
 	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_disable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
-		IPA_WDI3_ERR("fail to disable wdi3 pipes\n");
-		return -EFAULT;
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_disconn_wdi_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
+			IPA_WDI_ERR("fail to tear down wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to tear down wdi tx pipes\n");
+			return -EFAULT;
+		}
+		if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to tear down wdi rx pipes\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+					IPA_RM_RESOURCE_APPS_CONS)) {
+			IPA_WDI_ERR("fail to delete rm dependency\n");
+			return -EFAULT;
+		}
+
+		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
+			IPA_WDI_ERR("fail to delete WLAN_PROD resource\n");
+			return -EFAULT;
+		}
+
+		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
+			IPA_WDI_ERR("fail to delete WLAN_CONS resource\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl)) {
+			IPA_WDI_ERR("fail to deregister ipa pm\n");
+			return -EFAULT;
+		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(ipa_wdi3_disable_pipes);
+EXPORT_SYMBOL(ipa_wdi_disconn_pipes);
 
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile)
+int ipa_wdi_enable_pipes(void)
+{
+	int ret;
+	int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_enable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+			IPA_WDI_ERR("fail to enable wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_enable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to enable wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_resume_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to resume wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_enable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to enable wdi rx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_resume_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to resume wdi rx pipe\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
+		if (ret == -EINPROGRESS) {
+			if (wait_for_completion_timeout(
+				&ipa_wdi_ctx->wdi_completion, 10*HZ) == 0) {
+				IPA_WDI_ERR("WLAN_PROD res req time out\n");
+				return -EFAULT;
+			}
+		} else if (ret != 0) {
+			IPA_WDI_ERR("fail to request resource\n");
+			return -EFAULT;
+		}
+	} else {
+		ret = ipa_pm_activate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+		if (ret) {
+			IPA_WDI_ERR("fail to activate ipa pm\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_enable_pipes);
+
+int ipa_wdi_disable_pipes(void)
+{
+	int ret;
+	int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized.\n");
+		return -EPERM;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_disable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+			IPA_WDI_ERR("fail to disable wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to suspend wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_disable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to disable wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to suspend wdi rx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_disable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to disable wdi rx pipe\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
+		if (ret != 0) {
+			IPA_WDI_ERR("fail to release resource\n");
+			return -EFAULT;
+		}
+	} else {
+		ret = ipa_pm_deactivate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+		if (ret) {
+			IPA_WDI_ERR("fail to deactivate ipa pm\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_disable_pipes);
+
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile)
 {
 	struct ipa_rm_perf_profile rm_profile;
 	enum ipa_rm_resource_name resource_name;
 
 	if (profile == NULL) {
-		IPA_WDI3_ERR("Invalid input\n");
+		IPA_WDI_ERR("Invalid input\n");
 		return -EINVAL;
 	}
 
-	rm_profile.max_supported_bandwidth_mbps =
-		profile->max_supported_bw_mbps;
+	if (!ipa_pm_is_used()) {
+		rm_profile.max_supported_bandwidth_mbps =
+			profile->max_supported_bw_mbps;
 
-	if (profile->client == IPA_CLIENT_WLAN1_PROD) {
-		resource_name = IPA_RM_RESOURCE_WLAN_PROD;
-	} else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
-		resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+		if (profile->client == IPA_CLIENT_WLAN1_PROD) {
+			resource_name = IPA_RM_RESOURCE_WLAN_PROD;
+		} else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
+			resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+		} else {
+			IPA_WDI_ERR("not supported\n");
+			return -EINVAL;
+		}
+
+		if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
+			IPA_WDI_ERR("fail to setup rm perf profile\n");
+			return -EFAULT;
+		}
 	} else {
-		IPA_WDI3_ERR("not supported\n");
-		return -EINVAL;
-	}
-
-	if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
-		IPA_WDI3_ERR("fail to setup rm perf profile\n");
-		return -EFAULT;
+		if (ipa_pm_set_perf_profile(ipa_wdi_ctx->ipa_pm_hdl,
+			profile->max_supported_bw_mbps)) {
+			IPA_WDI_ERR("fail to setup pm perf profile\n");
+			return -EFAULT;
+		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(ipa_wdi3_set_perf_profile);
+EXPORT_SYMBOL(ipa_wdi_set_perf_profile);
+
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return ipa_create_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_create_smmu_mapping);
+
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return ipa_release_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping);
+
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
+{
+	return ipa_get_wdi_stats(stats);
+}
+EXPORT_SYMBOL(ipa_wdi_get_stats);
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index 4f60896..4980167 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -574,13 +574,15 @@
 		goto fail_set_device_ethernet;
 	}
 	RNDIS_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);
-
+#ifdef CONFIG_IPA3
 	if (ipa_is_vlan_mode(IPA_VLAN_IF_RNDIS,
 		&rndis_ipa_ctx->is_vlan_mode)) {
 		RNDIS_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
-		goto fail_get_vlan_mode;
+		goto fail_hdrs_cfg;
 	}
-
+#else
+	rndis_ipa_ctx->is_vlan_mode = 0;
+#endif
 	RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);
 
 	result = rndis_ipa_hdrs_cfg
@@ -631,7 +633,6 @@
 fail_register_tx:
 	rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
 fail_hdrs_cfg:
-fail_get_vlan_mode:
 fail_set_device_ethernet:
 	rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
 fail_netdev_priv:
@@ -2025,8 +2026,10 @@
 	}
 
 	if (rndis_ipa_ctx->is_vlan_mode)
-		if (unlikely(skb->protocol != ETH_P_8021Q))
-			RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+		if (unlikely(skb->protocol != htons(ETH_P_8021Q)))
+			RNDIS_IPA_DEBUG(
+				"ether_type != ETH_P_8021Q && vlan, prot = 0x%X\n"
+				, skb->protocol);
 
 	/* make room at the head of the SKB to put the RNDIS header */
 	rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 98a1cf9..b37a127 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -419,14 +419,15 @@
 			      void *user_data);
 void ipa_ntn_uc_dereg_rdyCB(void);
 
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
 const char *ipa_get_version_string(enum ipa_hw_type ver);
 int ipa_start_gsi_channel(u32 clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index f19e9d6..e43a201 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -3591,8 +3591,8 @@
 		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	} else {
 		IPADBG_LOW("clocks are gated, not setting rate\n");
+		ipa_active_clients_unlock();
 	}
-	ipa_active_clients_unlock();
 	IPADBG_LOW("Done\n");
 	return 0;
 }
@@ -3925,7 +3925,6 @@
 	ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
 	ipa_ctx->use_dma_zone = resource_p->use_dma_zone;
 	ipa_ctx->tethered_flow_control = resource_p->tethered_flow_control;
-	ipa_ctx->use_ipa_pm = resource_p->use_ipa_pm;
 
 	/* Setting up IPA RX Polling Timeout Seconds */
 	ipa_rx_timeout_min_max_calc(&ipa_ctx->ipa_rx_min_timeout_usec,
@@ -4359,7 +4358,7 @@
 	else
 		IPADBG(":ipa Uc interface init ok\n");
 
-	result = ipa_wdi_init();
+	result = ipa2_wdi_init();
 	if (result)
 		IPAERR(":wdi init failed (%d)\n", -result);
 	else
@@ -4451,20 +4450,12 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa_ctx) ? ipa_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_configuration(struct platform_device *pdev,
 		struct ipa_plat_drv_res *ipa_drv_res)
 {
 	int result;
 	struct resource *resource;
 
-	ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
-		"qcom,use-ipa-pm");
-	IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
 	/* initialize ipa_res */
 	ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
 	ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index ec4942f..bd7f600 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -67,6 +67,16 @@
 #define IPA_MAX_NUM_REQ_CACHE 10
 #define IPA_IPC_LOG_PAGES 50
 
+#define IPA_WDI_RX_RING_RES 0
+#define IPA_WDI_RX_RING_RP_RES 1
+#define IPA_WDI_RX_COMP_RING_RES 2
+#define IPA_WDI_RX_COMP_RING_WP_RES 3
+#define IPA_WDI_TX_RING_RES 4
+#define IPA_WDI_CE_RING_RES 5
+#define IPA_WDI_CE_DB_RES 6
+#define IPA_WDI_TX_DB_RES 7
+#define IPA_WDI_MAX_RES 8
+
 #define IPADBG(fmt, args...) \
 	do { \
 		pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
@@ -1206,7 +1216,6 @@
 	int num_ipa_cne_evt_req;
 	struct mutex ipa_cne_evt_lock;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 /**
@@ -1263,7 +1272,6 @@
 	u32 ipa_rx_polling_sleep_msec;
 	u32 ipa_polling_iteration;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 struct ipa_mem_partition {
@@ -1580,8 +1588,9 @@
 int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
 void ipa2_ntn_uc_dereg_rdyCB(void);
 
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1603,6 +1612,9 @@
  */
 int ipa2_uc_dereg_rdyCB(void);
 
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+		unsigned long *iova);
 /*
  * Tethering bridge (Rmnet / MBIM)
  */
@@ -1866,7 +1878,7 @@
 int ipa_active_clients_trylock(unsigned long *flags);
 void ipa_active_clients_unlock(void);
 void ipa_active_clients_trylock_unlock(unsigned long *flags);
-int ipa_wdi_init(void);
+int ipa2_wdi_init(void);
 int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id);
 int ipa_tag_process(struct ipa_desc *desc, int num_descs,
 		    unsigned long timeout);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 227a12a..66a8d0b 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -51,6 +51,7 @@
 	u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
 	u8 *start;
 	int pipe_idx;
+	struct ipa_hdr_entry *hdr_entry;
 
 	if (buf == NULL) {
 		memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4));
@@ -74,6 +75,18 @@
 	}
 	rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
 	rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
+
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EPERM;
+		}
+	}
 	if (entry->hdr) {
 		if (entry->hdr->cookie == IPA_HDR_COOKIE) {
 			rule_hdr->u.hdr.hdr_offset =
@@ -103,7 +116,7 @@
 		entry->hw_len = buf - start;
 	} else if (entry->hw_len != (buf - start)) {
 		IPAERR(
-		"hw_len differs b/w passes passed=0x%x calc=0x%lxtd\n",
+		"hw_len differs b/w passes passed=0x%x calc=0x%zxtd\n",
 		entry->hw_len,
 		(buf - start));
 		return -EPERM;
@@ -140,6 +153,8 @@
 	u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
 	u8 *start;
 	int pipe_idx;
+	struct ipa_hdr_entry *hdr_entry;
+	struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
 
 	if (buf == NULL) {
 		memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE);
@@ -162,6 +177,24 @@
 		return -EPERM;
 	}
 	rule_hdr->u.hdr_v2_5.pipe_dest_idx = pipe_idx;
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EPERM;
+		}
+	} else if (entry->proc_ctx) {
+		hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+		if (!hdr_proc_entry ||
+			hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+			IPAERR_RL("Proc header entry already deleted\n");
+			return -EPERM;
+		}
+	}
 	if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
 		struct ipa_hdr_proc_ctx_entry *proc_ctx;
 
@@ -197,7 +230,7 @@
 	if (entry->hw_len == 0) {
 		entry->hw_len = buf - start;
 	} else if (entry->hw_len != (buf - start)) {
-		IPAERR("hw_len differs b/w passes passed=0x%x calc=0x%lxtd\n",
+		IPAERR("hw_len differs b/w passes passed=0x%x calc=0x%zxtd\n",
 			entry->hw_len, (buf - start));
 		return -EPERM;
 	}
@@ -1132,6 +1165,8 @@
 {
 	struct ipa_rt_entry *entry;
 	int id;
+	struct ipa_hdr_entry *hdr_entry;
+	struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
 
 	entry = ipa_id_find(rule_hdl);
 
@@ -1145,6 +1180,33 @@
 		return -EINVAL;
 	}
 
+	if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+		IPADBG("Deleting rule from default rt table idx=%u\n",
+			entry->tbl->idx);
+		if (entry->tbl->rule_cnt == 1) {
+			IPAERR_RL("Default tbl last rule cannot be deleted\n");
+			return -EINVAL;
+		}
+	}
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EINVAL;
+		}
+	} else if (entry->proc_ctx) {
+		hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+		if (!hdr_proc_entry ||
+			hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+			IPAERR_RL("Proc header entry already deleted\n");
+			return -EINVAL;
+		}
+	}
+
 	if (entry->hdr)
 		__ipa_release_hdr(entry->hdr->id);
 	else if (entry->proc_ctx)
@@ -1457,6 +1519,7 @@
 {
 	struct ipa_rt_entry *entry;
 	struct ipa_hdr_entry *hdr = NULL;
+	struct ipa_hdr_entry *hdr_entry;
 
 	if (rtrule->rule.hdr_hdl) {
 		hdr = ipa_id_find(rtrule->rule.hdr_hdl);
@@ -1477,6 +1540,17 @@
 		goto error;
 	}
 
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EPERM;
+		}
+	}
 	if (entry->hdr)
 		entry->hdr->ref_cnt--;
 
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
index a454382..459c207 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -26,15 +26,6 @@
 #define IPA_WDI_RESUMED BIT(2)
 #define IPA_UC_POLL_SLEEP_USEC 100
 
-#define IPA_WDI_RX_RING_RES 0
-#define IPA_WDI_RX_RING_RP_RES 1
-#define IPA_WDI_RX_COMP_RING_RES 2
-#define IPA_WDI_RX_COMP_RING_WP_RES 3
-#define IPA_WDI_TX_RING_RES 4
-#define IPA_WDI_CE_RING_RES 5
-#define IPA_WDI_CE_DB_RES 6
-#define IPA_WDI_MAX_RES 7
-
 struct ipa_wdi_res {
 	struct ipa_wdi_buffer_info *res;
 	unsigned int nents;
@@ -448,7 +439,7 @@
 	return 0;
 }
 
-int ipa_wdi_init(void)
+int ipa2_wdi_init(void)
 {
 	struct ipa_uc_hdlrs uc_wdi_cbs = { 0 };
 
@@ -583,7 +574,8 @@
 {
 	IPADBG("--res_idx=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", res_idx,
 			&pa, iova, len);
-	wdi_res[res_idx].res = kzalloc(sizeof(struct ipa_wdi_res), GFP_KERNEL);
+	wdi_res[res_idx].res = kzalloc(sizeof(*wdi_res[res_idx].res),
+					GFP_KERNEL);
 	if (!wdi_res[res_idx].res)
 		BUG();
 	wdi_res[res_idx].nents = 1;
@@ -609,8 +601,8 @@
 		return;
 	}
 
-	wdi_res[res_idx].res = kcalloc(sgt->nents, sizeof(struct ipa_wdi_res),
-			GFP_KERNEL);
+	wdi_res[res_idx].res = kcalloc(sgt->nents,
+		sizeof(*wdi_res[res_idx].res), GFP_KERNEL);
 	if (!wdi_res[res_idx].res)
 		BUG();
 	wdi_res[res_idx].nents = sgt->nents;
@@ -628,7 +620,7 @@
 	}
 }
 
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
 		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
 		unsigned long *iova)
 {
@@ -844,7 +836,7 @@
 				in->smmu_enabled,
 				in->u.dl_smmu.comp_ring_size,
 				in->u.dl.comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
 					in->smmu_enabled,
 					in->u.dl.comp_ring_base_pa,
 					&in->u.dl_smmu.comp_ring,
@@ -869,7 +861,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.ce_ring_size,
 					in->u.dl.ce_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.ce_ring_base_pa,
 						&in->u.dl_smmu.ce_ring,
@@ -890,7 +882,7 @@
 
 			pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
 				in->u.dl.ce_door_bell_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -918,7 +910,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.comp_ring_size,
 					in->u.dl.comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.comp_ring_base_pa,
 						&in->u.dl_smmu.comp_ring,
@@ -938,7 +930,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.ce_ring_size,
 					in->u.dl.ce_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.ce_ring_base_pa,
 						&in->u.dl_smmu.ce_ring,
@@ -953,7 +945,7 @@
 			tx->ce_ring_size = len;
 			pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
 				in->u.dl.ce_door_bell_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -994,7 +986,7 @@
 				in->smmu_enabled,
 				in->u.ul_smmu.rdy_ring_size,
 				in->u.ul.rdy_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_ring_base_pa,
 						&in->u.ul_smmu.rdy_ring,
@@ -1015,7 +1007,7 @@
 
 			pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
 				in->u.ul.rdy_ring_rp_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -1039,7 +1031,8 @@
 					in->smmu_enabled,
 					in->u.ul_smmu.rdy_comp_ring_size,
 					in->u.ul.rdy_comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_COMP_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(
+						IPA_WDI_RX_COMP_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_comp_ring_base_pa,
 						&in->u.ul_smmu.rdy_comp_ring,
@@ -1061,7 +1054,7 @@
 			pa = in->smmu_enabled ?
 				in->u.ul_smmu.rdy_comp_ring_wp_pa :
 				in->u.ul.rdy_comp_ring_wp_pa;
-			if (ipa_create_uc_smmu_mapping(
+			if (ipa2_create_uc_smmu_mapping(
 						IPA_WDI_RX_COMP_RING_WP_RES,
 						in->smmu_enabled,
 						pa,
@@ -1089,7 +1082,7 @@
 					in->smmu_enabled,
 					in->u.ul_smmu.rdy_ring_size,
 					in->u.ul.rdy_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_ring_base_pa,
 						&in->u.ul_smmu.rdy_ring,
@@ -1105,7 +1098,7 @@
 
 			pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
 				in->u.ul.rdy_ring_rp_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 8a3fbd4..c9273ec 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -161,6 +161,7 @@
 	[IPA_2_0][IPA_CLIENT_TEST4_CONS]         = {true, 15},
 
 
+	[IPA_2_6L][IPA_CLIENT_USB_PROD]          =  {true,  1},
 	[IPA_2_6L][IPA_CLIENT_APPS_LAN_WAN_PROD]  = {true,  4},
 	[IPA_2_6L][IPA_CLIENT_APPS_CMD_PROD]      = {true,  3},
 	[IPA_2_6L][IPA_CLIENT_Q6_LAN_PROD]        = {true,  6},
@@ -4983,6 +4984,11 @@
 	ipa_ctx->tag_process_before_gating = val;
 }
 
+static bool ipa2_pm_is_used(void)
+{
+	return false;
+}
+
 int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -5154,10 +5160,11 @@
 	api_ctrl->ipa_get_pdev = ipa2_get_pdev;
 	api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB;
 	api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB;
-	api_ctrl->ipa_conn_wdi3_pipes = ipa2_conn_wdi3_pipes;
-	api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
-	api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
-	api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+	api_ctrl->ipa_conn_wdi_pipes = ipa2_conn_wdi3_pipes;
+	api_ctrl->ipa_disconn_wdi_pipes = ipa2_disconn_wdi3_pipes;
+	api_ctrl->ipa_enable_wdi_pipes = ipa2_enable_wdi3_pipes;
+	api_ctrl->ipa_disable_wdi_pipes = ipa2_disable_wdi3_pipes;
+	api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
index a2c33a1..62748b2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,43 +10,27 @@
  * GNU General Public License for more details.
  */
 #include "ipa_i.h"
-#include "ipa_uc_offload_i.h"
 #include <linux/ipa_wdi3.h>
 
 #define IPA_HW_WDI3_RX_MBOX_START_INDEX 48
 #define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
 
 static int ipa_send_wdi3_setup_pipe_cmd(
-	struct ipa_wdi3_setup_info *info, u8 dir)
+	u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+	struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
 {
 	int ipa_ep_idx;
-	int result = 0;
+	int result = 0, len;
+	unsigned long va;
 	struct ipa_mem_buffer cmd;
 	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
 	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
 
-	if (info == NULL) {
+	if (info == NULL || info_smmu == NULL) {
 		IPAERR("invalid input\n");
 		return -EINVAL;
 	}
 
-	ipa_ep_idx = ipa_get_ep_mapping(info->client);
-	IPAERR("ep number: %d\n", ipa_ep_idx);
-	if (ipa_ep_idx == -1) {
-		IPAERR("fail to get ep idx.\n");
-		return -EFAULT;
-	}
-
-	IPAERR("client=%d ep=%d\n", info->client, ipa_ep_idx);
-	IPAERR("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
-	IPAERR("ring_size = %hu\n", info->transfer_ring_size);
-	IPAERR("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
-	IPAERR("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
-	IPAERR("evt_ring_size = %hu\n", info->event_ring_size);
-	IPAERR("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
-	IPAERR("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
-	IPAERR("pkt_offset = %d.\n", info->pkt_offset);
-
 	cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size,
 			&cmd.phys_base, GFP_KERNEL);
@@ -54,35 +38,181 @@
 		IPAERR("fail to get DMA memory.\n");
 		return -ENOMEM;
 	}
-	IPAERR("suceeded in allocating memory.\n");
 
 	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
 	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
 
-	wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
-	wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
-	wdi3_params->transfer_ring_base_pa_hi =
-		(u32)((u64)info->transfer_ring_base_pa >> 32);
-	wdi3_params->transfer_ring_size = info->transfer_ring_size;
-	wdi3_params->transfer_ring_doorbell_pa =
-		(u32)info->transfer_ring_doorbell_pa;
-	wdi3_params->transfer_ring_doorbell_pa_hi =
-		(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
-	wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
-	wdi3_params->event_ring_base_pa_hi =
-		(u32)((u64)info->event_ring_base_pa >> 32);
-	wdi3_params->event_ring_size = info->event_ring_size;
-	wdi3_params->event_ring_doorbell_pa =
-		(u32)info->event_ring_doorbell_pa;
-	wdi3_params->event_ring_doorbell_pa_hi =
-		(u32)((u64)info->event_ring_doorbell_pa >> 32);
-	wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
-	wdi3_params->ipa_pipe_number = ipa_ep_idx;
-	wdi3_params->dir = dir;
-	wdi3_params->pkt_offset = info->pkt_offset;
-	memcpy(wdi3_params->desc_format_template, info->desc_format_template,
-		sizeof(wdi3_params->desc_format_template));
-	IPAERR("suceeded in populating the command memory.\n");
+	if (!is_smmu_enabled) {
+		ipa_ep_idx = ipa_get_ep_mapping(info->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx.\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+		IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+		IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_base_pa = 0x%pad\n",
+			&info->event_ring_base_pa);
+		IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+		wdi3_params->transfer_ring_base_pa =
+			(u32)info->transfer_ring_base_pa;
+		wdi3_params->transfer_ring_base_pa_hi =
+			(u32)((u64)info->transfer_ring_base_pa >> 32);
+		wdi3_params->transfer_ring_size = info->transfer_ring_size;
+		wdi3_params->transfer_ring_doorbell_pa =
+			(u32)info->transfer_ring_doorbell_pa;
+		wdi3_params->transfer_ring_doorbell_pa_hi =
+			(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+		wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+		wdi3_params->event_ring_base_pa_hi =
+			(u32)((u64)info->event_ring_base_pa >> 32);
+		wdi3_params->event_ring_size = info->event_ring_size;
+		wdi3_params->event_ring_doorbell_pa =
+			(u32)info->event_ring_doorbell_pa;
+		wdi3_params->event_ring_doorbell_pa_hi =
+			(u32)((u64)info->event_ring_doorbell_pa >> 32);
+		wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	} else {
+		ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+		IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info_smmu->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info_smmu->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+		if (dir == IPA_WDI3_TX_DIR) {
+			len = info_smmu->transfer_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+				true, info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+				true, info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		} else {
+			len = info_smmu->transfer_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa2_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_RES, true,
+				info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_WP_RES, true,
+				info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		}
+		wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info_smmu->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info_smmu->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	}
 
 	result = ipa_uc_send_cmd((u32)(cmd.phys_base),
 				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -94,13 +224,15 @@
 	}
 
 	dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
-	IPAERR("suceeded in freeing memory.\n");
 	return result;
 }
 
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
+	enum ipa_client_type rx_client;
+	enum ipa_client_type tx_client;
 	struct ipa_ep_context *ep_rx;
 	struct ipa_ep_context *ep_tx;
 	int ipa_ep_idx_rx;
@@ -112,12 +244,26 @@
 		return -EINVAL;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+	if (in->is_smmu_enabled == false) {
+		rx_client = in->u_rx.rx.client;
+		tx_client = in->u_tx.tx.client;
+	} else {
+		rx_client = in->u_rx.rx_smmu.client;
+		tx_client = in->u_tx.tx_smmu.client;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
 	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
 		IPAERR("fail to alloc EP.\n");
 		return -EFAULT;
 	}
+	if (ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES ||
+		ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES) {
+		IPAERR("ep out of range.\n");
+		return -EFAULT;
+	}
 
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
@@ -132,9 +278,14 @@
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
+	if (wdi_notify)
+		ipa_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+	else
+		IPADBG("wdi_notify is null\n");
+
 	/* setup rx ep cfg */
 	ep_rx->valid = 1;
-	ep_rx->client = in->rx.client;
+	ep_rx->client = rx_client;
 	result = ipa_disable_data_path(ipa_ep_idx_rx);
 	if (result) {
 		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,65 +296,71 @@
 	ep_rx->client_notify = in->notify;
 	ep_rx->priv = in->priv;
 
-	memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
+	else
+		memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
 
 	if (ipa_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
 		IPAERR("fail to setup rx pipe cfg\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("configured RX EP.\n");
 
-	if (ipa_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+	if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
 		IPAERR("fail to send cmd to uc for rx pipe\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("rx pipe was setup.\n");
-
 	ipa_install_dflt_flt_rules(ipa_ep_idx_rx);
 	out->rx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
 		IPA_REG_BASE_OFST_v2_5 +
 		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
 		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
-	IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+
+	IPADBG("client %d (ep: %d) connected\n", rx_client,
 		ipa_ep_idx_rx);
 
-	/* setup dl ep cfg */
+	/* setup tx ep cfg */
 	ep_tx->valid = 1;
-	ep_tx->client = in->tx.client;
+	ep_tx->client = tx_client;
 	result = ipa_disable_data_path(ipa_ep_idx_tx);
 	if (result) {
-		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+		IPAERR("disable data path failed res=%d ep=%d.\n", result,
 			ipa_ep_idx_tx);
 		result = -EFAULT;
 		goto fail;
 	}
 
-	memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
+	else
+		memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
 
 	if (ipa_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
 		IPAERR("fail to setup tx pipe cfg\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("configured TX EP in DMA mode.\n");
 
-	if (ipa_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+	if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
 		IPAERR("fail to send cmd to uc for tx pipe\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("tx pipe was setup.\n");
-
 	out->tx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
 		IPA_REG_BASE_OFST_v2_5 +
 		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
 		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
-	out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
-	IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+	IPADBG("client %d (ep: %d) connected\n", tx_client,
 		ipa_ep_idx_tx);
 
 fail:
@@ -233,7 +390,6 @@
 
 	wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params;
 	wdi3->params.ipa_pipe_number = ipa_ep_idx;
-	IPAERR("cmd: %d ep_idx: %d\n", command, ipa_ep_idx);
 	result = ipa_uc_send_cmd((u32)(cmd.phys_base), command,
 				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
 				false, 10*HZ);
@@ -256,6 +412,12 @@
 	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
 	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
 
+	if (ipa_ep_idx_tx < 0 || ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES ||
+		ipa_ep_idx_rx < 0 || ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES) {
+		IPAERR("invalid ipa ep index\n");
+		return -EINVAL;
+	}
+
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
 
@@ -291,8 +453,8 @@
 	struct ipa_ep_context *ep_tx, *ep_rx;
 	int result = 0;
 
-	IPAERR("ep_tx = %d\n", ipa_ep_idx_tx);
-	IPAERR("ep_rx = %d\n", ipa_ep_idx_rx);
+	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
+	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
 
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
@@ -301,7 +463,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
 		IPAERR("fail to enable tx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -310,7 +471,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
 		IPAERR("fail to resume tx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -319,7 +479,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
 		IPAERR("fail to enable rx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -328,7 +487,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
 		IPAERR("fail to resume rx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 068c6c5..c86b0df 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -773,7 +773,7 @@
 {
 	int i;
 
-	for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++) {
+	for (i = 0; i < rmnet_index; i++) {
 		if (strcmp(mux_channel[i].vchannel_name, vchannel_name) == 0)
 			return i;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ae24675..6307137 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2140,7 +2140,7 @@
 	}
 }
 
-static void ipa3_halt_q6_cons_gsi_channels(void)
+static void ipa3_halt_q6_gsi_channels(bool prod)
 {
 	int ep_idx;
 	int client_idx;
@@ -2149,8 +2149,10 @@
 	int ret;
 	int code = 0;
 
+	/* if prod flag is true, then we halt the producer channels also */
 	for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++) {
-		if (IPA_CLIENT_IS_Q6_CONS(client_idx)) {
+		if (IPA_CLIENT_IS_Q6_CONS(client_idx)
+			|| (IPA_CLIENT_IS_Q6_PROD(client_idx) && prod)) {
 			ep_idx = ipa3_get_ep_mapping(client_idx);
 			if (ep_idx == -1)
 				continue;
@@ -2192,7 +2194,6 @@
 	}
 }
 
-
 static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
 	enum ipa_rule_type rlt)
 {
@@ -2607,6 +2608,7 @@
 {
 	int client_idx;
 	int ep_idx;
+	bool prod = false;
 
 	IPADBG_LOW("ENTER\n");
 
@@ -2619,7 +2621,17 @@
 
 	/* Handle the issue where SUSPEND was removed for some reason */
 	ipa3_q6_avoid_holb();
-	ipa3_halt_q6_cons_gsi_channels();
+
+	/* halt both prod and cons channels starting at IPAv4 */
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		prod = true;
+		ipa3_halt_q6_gsi_channels(prod);
+		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+		IPADBG("Exit without consumer check\n");
+		return;
+	}
+
+	ipa3_halt_q6_gsi_channels(prod);
 
 	for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
 		if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
@@ -4395,6 +4407,12 @@
 	if (ipa3_ctx->ipa_initialization_complete)
 		return 0;
 
+	IPADBG("active clients = %d\n",
+			atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
+	/* move proxy vote for modem on ipa3_post_init */
+	if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
+		ipa3_proxy_clk_vote();
+
 	/*
 	 * indication whether working in MHI config or non MHI config is given
 	 * in ipa3_write which is launched before ipa3_post_init. i.e. from
@@ -4530,9 +4548,6 @@
 
 	ipa3_register_panic_hdlr();
 
-	ipa3_ctx->q6_proxy_clk_vote_valid = true;
-	ipa3_ctx->q6_proxy_clk_vote_cnt++;
-
 	mutex_lock(&ipa3_ctx->lock);
 	ipa3_ctx->ipa_initialization_complete = true;
 	mutex_unlock(&ipa3_ctx->lock);
@@ -4549,6 +4564,7 @@
 	gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
 fail_register_device:
 	ipa3_destroy_flt_tbl_idrs();
+	ipa3_proxy_clk_unvote();
 	return result;
 }
 
@@ -5049,8 +5065,13 @@
 	}
 
 	mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
+
 	IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
 	ipa3_active_clients_log_inc(&log_info, false);
+	ipa3_ctx->q6_proxy_clk_vote_valid = true;
+	ipa3_ctx->q6_proxy_clk_vote_cnt = 1;
+
+	/*Updating the proxy vote cnt 1 */
 	atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
 
 	/* Create workqueues for power management */
@@ -5181,7 +5202,6 @@
 	mutex_init(&ipa3_ctx->lock);
 	mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
 	mutex_init(&ipa3_ctx->ipa_cne_evt_lock);
-	ipa3_ctx->q6_proxy_clk_vote_cnt = 0;
 
 	idr_init(&ipa3_ctx->ipa_idr);
 	spin_lock_init(&ipa3_ctx->idr_lock);
@@ -5296,6 +5316,14 @@
 	IPADBG("ipa cdev added successful. major:%d minor:%d\n",
 			MAJOR(ipa3_ctx->dev_num),
 			MINOR(ipa3_ctx->dev_num));
+	/*
+	 * for IPA 4.0 offline charge is not needed and we need to prevent
+	 * power collapse until IPA uC is loaded.
+	 */
+
+	/* proxy vote for modem is added in ipa3_post_init() phase */
+	if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
+		ipa3_proxy_clk_unvote();
 	return 0;
 
 fail_cdev_add:
@@ -5379,11 +5407,6 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_pm_info(struct platform_device *pdev,
 	struct ipa3_plat_drv_res *ipa_drv_res)
 {
@@ -5971,6 +5994,7 @@
 	int bypass = 1;
 	u32 iova_ap_mapping[2];
 	u32 add_map_size;
+	u32 q6_smem_size;
 	const u32 *add_map;
 	void *smem_addr;
 	int i;
@@ -6087,9 +6111,18 @@
 		}
 	}
 
-	/* map SMEM memory for IPA table accesses */
-	smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
-		SMEM_MODEM, 0);
+	result = of_property_read_u32_array(dev->of_node,
+			"qcom,ipa-q6-smem-size", &q6_smem_size, 1);
+	if (result) {
+		IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
+		/* map SMEM memory for IPA table accesses */
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
+				SMEM_MODEM, 0);
+	} else {
+		IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
+				SMEM_MODEM, 0);
+	}
 	if (smem_addr) {
 		phys_addr_t iova = smem_virt_to_phys(smem_addr);
 		phys_addr_t pa = iova;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 90edd2b..6aa15c1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -952,11 +952,13 @@
 				goto fail_pm;
 			}
 
-			result = ipa_pm_associate_ipa_cons_to_client(
-				ep->sys->pm_hdl, sys_in->client);
-			if (result) {
-				IPAERR("failed to associate IPA PM client\n");
-				goto fail_gen2;
+			if (IPA_CLIENT_IS_APPS_CONS(sys_in->client)) {
+				result = ipa_pm_associate_ipa_cons_to_client(
+					ep->sys->pm_hdl, sys_in->client);
+				if (result) {
+					IPAERR("failed to associate\n");
+					goto fail_gen2;
+				}
 			}
 
 			result = ipa_pm_set_perf_profile(ep->sys->pm_hdl,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 7bd1731..4a8e7c7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -185,6 +185,16 @@
 #define IPA3_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50
 #define IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN 40
 
+#define IPA_WDI_RX_RING_RES			0
+#define IPA_WDI_RX_RING_RP_RES		1
+#define IPA_WDI_RX_COMP_RING_RES	2
+#define IPA_WDI_RX_COMP_RING_WP_RES	3
+#define IPA_WDI_TX_RING_RES			4
+#define IPA_WDI_CE_RING_RES			5
+#define IPA_WDI_CE_DB_RES			6
+#define IPA_WDI_TX_DB_RES			7
+#define IPA_WDI_MAX_RES				8
+
 struct ipa3_active_client_htable_entry {
 	struct hlist_node list;
 	char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
@@ -1898,8 +1908,9 @@
 int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
 int ipa3_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
 void ipa3_ntn_uc_dereg_rdyCB(void);
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1921,6 +1932,10 @@
  */
 int ipa3_uc_dereg_rdyCB(void);
 
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+		unsigned long *iova);
+
 /*
  * Tethering bridge (Rmnet / MBIM)
  */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index 80a39b5..140afa8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -156,6 +156,7 @@
  * @activate_work: work for activate (blocking case)
  * @deactivate work: delayed work for deferred_deactivate function
  * @complete: generic wait-for-completion handler
+ * @wlock: wake source to prevent AP suspend
  */
 struct ipa_pm_client {
 	char name[IPA_PM_MAX_EX_CL];
@@ -170,6 +171,7 @@
 	struct work_struct activate_work;
 	struct delayed_work deactivate_work;
 	struct completion complete;
+	struct wakeup_source wlock;
 };
 
 /*
@@ -395,8 +397,11 @@
 	unsigned long flags;
 
 	client = container_of(work, struct ipa_pm_client, activate_work);
-	if (!client->skip_clk_vote)
+	if (!client->skip_clk_vote) {
 		IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_stay_awake(&client->wlock);
+	}
 
 	spin_lock_irqsave(&client->state_lock, flags);
 	IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
@@ -414,8 +419,11 @@
 	complete_all(&client->complete);
 
 	if (dec_clk) {
-		if (!client->skip_clk_vote)
+		if (!client->skip_clk_vote) {
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+			if (client->group == IPA_PM_GROUP_APPS)
+				__pm_relax(&client->wlock);
+		}
 
 		IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
 		return;
@@ -464,8 +472,11 @@
 		client->state = IPA_PM_DEACTIVATED;
 		IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
 		spin_unlock_irqrestore(&client->state_lock, flags);
-		if (!client->skip_clk_vote)
+		if (!client->skip_clk_vote) {
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+			if (client->group == IPA_PM_GROUP_APPS)
+				__pm_relax(&client->wlock);
+		}
 
 		deactivate_client(client->hdl);
 		do_clk_scaling();
@@ -669,7 +680,7 @@
 }
 
 /**
- * ipa_rm_delete_register() - register an IPA PM client with the PM
+ * ipa_pm_register() - register an IPA PM client with the PM
  * @register_params: params for a client like throughput, callback, etc.
  * @hdl: int pointer that will be used as an index to access the client
  *
@@ -681,6 +692,7 @@
 int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl)
 {
 	struct ipa_pm_client *client;
+	struct wakeup_source *wlock;
 
 	if (ipa_pm_ctx == NULL) {
 		IPA_PM_ERR("PM_ctx is null\n");
@@ -729,6 +741,8 @@
 	client->group = params->group;
 	client->hdl = *hdl;
 	client->skip_clk_vote = params->skip_clk_vote;
+	wlock = &client->wlock;
+	wakeup_source_init(wlock, client->name);
 
 	/* add client to exception list */
 	if (add_client_to_exception_list(*hdl)) {
@@ -792,6 +806,7 @@
 		if (ipa_pm_ctx->clients_by_pipe[i] == ipa_pm_ctx->clients[hdl])
 			ipa_pm_ctx->clients_by_pipe[i] = NULL;
 	}
+	wakeup_source_trash(&client->wlock);
 	kfree(client);
 	ipa_pm_ctx->clients[hdl] = NULL;
 
@@ -909,6 +924,8 @@
 	/* we got the clocks */
 	if (result == 0) {
 		client->state = IPA_PM_ACTIVATED;
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_stay_awake(&client->wlock);
 		spin_unlock_irqrestore(&client->state_lock, flags);
 		activate_client(client->hdl);
 		if (sync)
@@ -1072,8 +1089,11 @@
 			IPA_PM_DBG_STATE(client->hdl, client->name,
 				client->state);
 			spin_unlock_irqrestore(&client->state_lock, flags);
-			if (!client->skip_clk_vote)
+			if (!client->skip_clk_vote) {
 				IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+				if (client->group == IPA_PM_GROUP_APPS)
+					__pm_relax(&client->wlock);
+			}
 			deactivate_client(client->hdl);
 		} else /* if activated or deactivated, we do nothing */
 			spin_unlock_irqrestore(&client->state_lock, flags);
@@ -1124,8 +1144,11 @@
 	spin_unlock_irqrestore(&client->state_lock, flags);
 
 	/* else case (Deactivates all Activated cases)*/
-	if (!client->skip_clk_vote)
+	if (!client->skip_clk_vote) {
 		IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_relax(&client->wlock);
+	}
 
 	spin_lock_irqsave(&client->state_lock, flags);
 	client->state = IPA_PM_DEACTIVATED;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index 205e7a5..ce9c684 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -90,6 +90,8 @@
 	bool skip_clk_vote;
 };
 
+#ifdef CONFIG_IPA3
+
 int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl);
 int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer);
 int ipa_pm_activate(u32 hdl);
@@ -107,4 +109,80 @@
 int ipa_pm_stat(char *buf, int size);
 int ipa_pm_exceptions_stat(char *buf, int size);
 
+#else
+
+static inline int ipa_pm_register(
+	struct ipa_pm_register_params *params, u32 *hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_associate_ipa_cons_to_client(
+	u32 hdl, enum ipa_client_type consumer)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_activate(u32 hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_activate_sync(u32 hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_deferred_deactivate(u32 hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_deactivate_sync(u32 hdl)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_set_perf_profile(u32 hdl, int throughput)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_deregister(u32 hdl)
+{
+	return -EPERM;
+}
+
+/* IPA Internal Functions */
+static inline int ipa_pm_init(struct ipa_pm_init_params *params)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_destroy(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_handle_suspend(u32 pipe_bitmask)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_deactivate_all_deferred(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_stat(char *buf, int size)
+{
+	return -EPERM;
+}
+
+static inline int ipa_pm_exceptions_stat(char *buf, int size)
+{
+	return -EPERM;
+}
+#endif
+
 #endif /* _IPA_PM_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index c158c94..88de06e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -708,7 +708,7 @@
 		return -EINVAL;
 	}
 
-	for (i = 0; i < req->filter_spec_ex_list_len-1; i++) {
+	for (i = 0; i < req->filter_spec_ex_list_len; i++) {
 		if ((req->filter_spec_ex_list[i].ip_type !=
 			QMI_IPA_IP_TYPE_V4_V01) &&
 			(req->filter_spec_ex_list[i].ip_type !=
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index fc76604..a0f1f54 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -52,6 +52,8 @@
 	struct ipa3_rt_entry *entry, u8 *buf)
 {
 	struct ipahal_rt_rule_gen_params gen_params;
+	struct ipa3_hdr_entry *hdr_entry;
+	struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
 	int res = 0;
 
 	memset(&gen_params, 0, sizeof(gen_params));
@@ -71,6 +73,25 @@
 		return -EPERM;
 	}
 
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EPERM;
+		}
+	} else if (entry->proc_ctx) {
+		hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+		if (!hdr_proc_entry ||
+			hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+			IPAERR_RL("Proc header entry already deleted\n");
+			return -EPERM;
+		}
+	}
+
 	if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
 		struct ipa3_hdr_proc_ctx_entry *proc_ctx;
 
@@ -1269,6 +1290,8 @@
 {
 	struct ipa3_rt_entry *entry;
 	int id;
+	struct ipa3_hdr_entry *hdr_entry;
+	struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
 
 	entry = ipa3_id_find(rule_hdl);
 
@@ -1282,6 +1305,34 @@
 		return -EINVAL;
 	}
 
+	if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+		IPADBG("Deleting rule from default rt table idx=%u\n",
+			entry->tbl->idx);
+		if (entry->tbl->rule_cnt == 1) {
+			IPAERR_RL("Default tbl last rule cannot be deleted\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EINVAL;
+		}
+	} else if (entry->proc_ctx) {
+		hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+		if (!hdr_proc_entry ||
+			hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+			IPAERR_RL("Proc header entry already deleted\n");
+			return -EINVAL;
+		}
+	}
+
 	if (entry->hdr)
 		__ipa3_release_hdr(entry->hdr->id);
 	else if (entry->proc_ctx)
@@ -1602,7 +1653,8 @@
 	struct ipa3_rt_entry *entry;
 	struct ipa3_hdr_entry *hdr = NULL;
 	struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
-
+	struct ipa3_hdr_entry *hdr_entry;
+	struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
 	if (rtrule->rule.hdr_hdl) {
 		hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
 		if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
@@ -1629,6 +1681,25 @@
 		goto error;
 	}
 
+	/* Adding check to confirm still
+	 * header entry present in header table or not
+	 */
+
+	if (entry->hdr) {
+		hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+		if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+			IPAERR_RL("Header entry already deleted\n");
+			return -EPERM;
+		}
+	} else if (entry->proc_ctx) {
+		hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+		if (!hdr_proc_entry ||
+			hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+			IPAERR_RL("Proc header entry already deleted\n");
+			return -EPERM;
+		}
+	}
+
 	if (entry->hdr)
 		entry->hdr->ref_cnt--;
 	if (entry->proc_ctx)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 941e489..ec777bc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -16,6 +16,7 @@
 #include "ipa_qmi_service.h"
 
 #define IPA_HOLB_TMR_DIS 0x0
+#define IPA_HOLB_TMR_EN 0x1
 
 #define IPA_HW_INTERFACE_WDI_VERSION 0x0001
 #define IPA_HW_WDI_RX_MBOX_START_INDEX 48
@@ -27,15 +28,6 @@
 #define IPA_WDI_RESUMED BIT(2)
 #define IPA_UC_POLL_SLEEP_USEC 100
 
-#define IPA_WDI_RX_RING_RES			0
-#define IPA_WDI_RX_RING_RP_RES		1
-#define IPA_WDI_RX_COMP_RING_RES	2
-#define IPA_WDI_RX_COMP_RING_WP_RES	3
-#define IPA_WDI_TX_RING_RES			4
-#define IPA_WDI_CE_RING_RES			5
-#define IPA_WDI_CE_DB_RES			6
-#define IPA_WDI_MAX_RES				7
-
 struct ipa_wdi_res {
 	struct ipa_wdi_buffer_info *res;
 	unsigned int nents;
@@ -669,7 +661,7 @@
 	}
 }
 
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
 		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
 		unsigned long *iova)
 {
@@ -702,6 +694,7 @@
 		case IPA_WDI_RX_RING_RP_RES:
 		case IPA_WDI_RX_COMP_RING_WP_RES:
 		case IPA_WDI_CE_DB_RES:
+		case IPA_WDI_TX_DB_RES:
 			if (ipa_create_uc_smmu_mapping_pa(pa, len,
 				(res_idx == IPA_WDI_CE_DB_RES) ? true : false,
 				iova)) {
@@ -839,35 +832,6 @@
 			in->u.ul.rdy_comp_ring_wp_pa;
 		ipa3_ctx->uc_ctx.rdy_comp_ring_size =
 			in->u.ul.rdy_comp_ring_size;
-
-		/* check if the VA is empty */
-		if (ipa3_ctx->ipa_wdi2) {
-			if (in->smmu_enabled) {
-				if (!in->u.ul_smmu.rdy_ring_rp_va ||
-					!in->u.ul_smmu.rdy_comp_ring_wp_va)
-					goto dma_alloc_fail;
-			} else {
-				if (!in->u.ul.rdy_ring_rp_va ||
-					!in->u.ul.rdy_comp_ring_wp_va)
-					goto dma_alloc_fail;
-			}
-			IPADBG("rdy_ring_rp value =%d\n",
-				in->smmu_enabled ?
-				*in->u.ul_smmu.rdy_ring_rp_va :
-				*in->u.ul.rdy_ring_rp_va);
-			IPADBG("rx_comp_ring_wp value=%d\n",
-				in->smmu_enabled ?
-				*in->u.ul_smmu.rdy_comp_ring_wp_va :
-				*in->u.ul.rdy_comp_ring_wp_va);
-				ipa3_ctx->uc_ctx.rdy_ring_rp_va =
-					in->smmu_enabled ?
-					in->u.ul_smmu.rdy_ring_rp_va :
-					in->u.ul.rdy_ring_rp_va;
-				ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va =
-					in->smmu_enabled ?
-					in->u.ul_smmu.rdy_comp_ring_wp_va :
-					in->u.ul.rdy_comp_ring_wp_va;
-		}
 	}
 
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
@@ -1209,8 +1173,6 @@
 		IPADBG("Skipping endpoint configuration.\n");
 	}
 
-	ipa3_enable_data_path(ipa_ep_idx);
-
 	out->clnt_hdl = ipa_ep_idx;
 
 	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
@@ -1316,6 +1278,7 @@
 	struct ipa3_ep_context *ep;
 	union IpaHwWdiCommonChCmdData_t enable;
 	struct ipa_ep_cfg_holb holb_cfg;
+	struct ipahal_reg_endp_init_rsrc_grp rsrc_grp;
 
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 	    ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1348,6 +1311,20 @@
 		goto uc_timeout;
 	}
 
+	/* Assign the resource group for pipe */
+	memset(&rsrc_grp, 0, sizeof(rsrc_grp));
+	rsrc_grp.rsrc_grp = ipa_get_ep_group(ep->client);
+	if (rsrc_grp.rsrc_grp == -1) {
+		IPAERR("invalid group for client %d\n", ep->client);
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	IPADBG("Setting group %d for pipe %d\n",
+		rsrc_grp.rsrc_grp, clnt_hdl);
+	ipahal_write_reg_n_fields(IPA_ENDP_INIT_RSRC_GRP_n, clnt_hdl,
+		&rsrc_grp);
+
 	if (IPA_CLIENT_IS_CONS(ep->client)) {
 		memset(&holb_cfg, 0, sizeof(holb_cfg));
 		holb_cfg.en = IPA_HOLB_TMR_DIS;
@@ -1521,6 +1498,24 @@
 	return result;
 }
 
+static void ipa3_cfg_holb_wdi_consumer(bool is_enable)
+{
+	u32 clnt_hdl;
+	struct ipa_ep_cfg_holb holb_cfg;
+
+	clnt_hdl = ipa3_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+	if (clnt_hdl < ipa3_ctx->ipa_num_pipes &&
+		ipa3_ctx->ep[clnt_hdl].valid == 1) {
+		memset(&holb_cfg, 0, sizeof(holb_cfg));
+		if (is_enable)
+			holb_cfg.en = IPA_HOLB_TMR_EN;
+		else
+			holb_cfg.en = IPA_HOLB_TMR_DIS;
+		holb_cfg.tmr_val = 0;
+		ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
+	}
+}
+
 /**
  * ipa3_suspend_wdi_pipe() - WDI client suspend
  * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
@@ -1587,6 +1582,9 @@
 			}
 		}
 
+		/* Enabling HOLB on WDI consumer pipe */
+		ipa3_cfg_holb_wdi_consumer(true);
+
 		IPADBG("Post suspend event first for IPA Producer\n");
 		IPADBG("Client: %d clnt_hdl: %d\n", ep->client, clnt_hdl);
 		result = ipa3_uc_send_cmd(suspend.raw32b,
@@ -1596,8 +1594,12 @@
 
 		if (result) {
 			result = -EFAULT;
+			/* Disabling HOLB on WDI consumer pipe */
+			ipa3_cfg_holb_wdi_consumer(false);
 			goto uc_timeout;
 		}
+		/* Disabling HOLB on WDI consumer pipe */
+		ipa3_cfg_holb_wdi_consumer(false);
 	}
 
 	memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 9974b87..d2b3b4e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4168,9 +4168,8 @@
  */
 void ipa3_proxy_clk_unvote(void)
 {
-	if (!ipa3_is_ready())
+	if (ipa3_ctx == NULL)
 		return;
-
 	mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
 	if (ipa3_ctx->q6_proxy_clk_vote_valid) {
 		IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PROXY_CLK_VOTE");
@@ -4188,9 +4187,8 @@
  */
 void ipa3_proxy_clk_vote(void)
 {
-	if (!ipa3_is_ready())
+	if (ipa3_ctx == NULL)
 		return;
-
 	mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
 	if (!ipa3_ctx->q6_proxy_clk_vote_valid ||
 		(ipa3_ctx->q6_proxy_clk_vote_cnt > 0)) {
@@ -4336,6 +4334,11 @@
 	return 0;
 }
 
+static bool ipa3_pm_is_used(void)
+{
+	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
 int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -4516,13 +4519,14 @@
 	api_ctrl->ipa_get_pdev = ipa3_get_pdev;
 	api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa3_ntn_uc_reg_rdyCB;
 	api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa3_ntn_uc_dereg_rdyCB;
-	api_ctrl->ipa_conn_wdi3_pipes = ipa3_conn_wdi3_pipes;
-	api_ctrl->ipa_disconn_wdi3_pipes = ipa3_disconn_wdi3_pipes;
-	api_ctrl->ipa_enable_wdi3_pipes = ipa3_enable_wdi3_pipes;
-	api_ctrl->ipa_disable_wdi3_pipes = ipa3_disable_wdi3_pipes;
+	api_ctrl->ipa_conn_wdi_pipes = ipa3_conn_wdi3_pipes;
+	api_ctrl->ipa_disconn_wdi_pipes = ipa3_disconn_wdi3_pipes;
+	api_ctrl->ipa_enable_wdi_pipes = ipa3_enable_wdi3_pipes;
+	api_ctrl->ipa_disable_wdi_pipes = ipa3_disable_wdi3_pipes;
 	api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
 	api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
 	api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
+	api_ctrl->ipa_pm_is_used = ipa3_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
index 7801745..6c019b9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,35 +16,21 @@
 #define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
 
 static int ipa3_send_wdi3_setup_pipe_cmd(
-	struct ipa_wdi3_setup_info *info, u8 dir)
+	u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+	struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
 {
 	int ipa_ep_idx;
-	int result = 0;
+	int result = 0, len;
+	unsigned long va;
 	struct ipa_mem_buffer cmd;
 	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
 	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
 
-	if (info == NULL) {
+	if (info == NULL || info_smmu == NULL) {
 		IPAERR("invalid input\n");
 		return -EINVAL;
 	}
 
-	ipa_ep_idx = ipa_get_ep_mapping(info->client);
-	if (ipa_ep_idx == -1) {
-		IPAERR("fail to get ep idx.\n");
-		return -EFAULT;
-	}
-
-	IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
-	IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
-	IPADBG("ring_size = %hu\n", info->transfer_ring_size);
-	IPADBG("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
-	IPADBG("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
-	IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
-	IPADBG("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
-	IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
-	IPADBG("pkt_offset = %d\n", info->pkt_offset);
-
 	cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
 			&cmd.phys_base, GFP_KERNEL);
@@ -56,29 +42,177 @@
 	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
 	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
 
-	wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
-	wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
-	wdi3_params->transfer_ring_base_pa_hi =
-		(u32)((u64)info->transfer_ring_base_pa >> 32);
-	wdi3_params->transfer_ring_size = info->transfer_ring_size;
-	wdi3_params->transfer_ring_doorbell_pa =
-		(u32)info->transfer_ring_doorbell_pa;
-	wdi3_params->transfer_ring_doorbell_pa_hi =
-		(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
-	wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
-	wdi3_params->event_ring_base_pa_hi =
-		(u32)((u64)info->event_ring_base_pa >> 32);
-	wdi3_params->event_ring_size = info->event_ring_size;
-	wdi3_params->event_ring_doorbell_pa =
-		(u32)info->event_ring_doorbell_pa;
-	wdi3_params->event_ring_doorbell_pa_hi =
-		(u32)((u64)info->event_ring_doorbell_pa >> 32);
-	wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
-	wdi3_params->ipa_pipe_number = ipa_ep_idx;
-	wdi3_params->dir = dir;
-	wdi3_params->pkt_offset = info->pkt_offset;
-	memcpy(wdi3_params->desc_format_template, info->desc_format_template,
-		sizeof(wdi3_params->desc_format_template));
+	if (!is_smmu_enabled) {
+		ipa_ep_idx = ipa_get_ep_mapping(info->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx.\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+		IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+		IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_base_pa = 0x%pad\n",
+			&info->event_ring_base_pa);
+		IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+		wdi3_params->transfer_ring_base_pa =
+			(u32)info->transfer_ring_base_pa;
+		wdi3_params->transfer_ring_base_pa_hi =
+			(u32)((u64)info->transfer_ring_base_pa >> 32);
+		wdi3_params->transfer_ring_size = info->transfer_ring_size;
+		wdi3_params->transfer_ring_doorbell_pa =
+			(u32)info->transfer_ring_doorbell_pa;
+		wdi3_params->transfer_ring_doorbell_pa_hi =
+			(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+		wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+		wdi3_params->event_ring_base_pa_hi =
+			(u32)((u64)info->event_ring_base_pa >> 32);
+		wdi3_params->event_ring_size = info->event_ring_size;
+		wdi3_params->event_ring_doorbell_pa =
+			(u32)info->event_ring_doorbell_pa;
+		wdi3_params->event_ring_doorbell_pa_hi =
+			(u32)((u64)info->event_ring_doorbell_pa >> 32);
+		wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	} else {
+		ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+		IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info_smmu->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info_smmu->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+		if (dir == IPA_WDI3_TX_DIR) {
+			len = info_smmu->transfer_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+				true, info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+				true, info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		} else {
+			len = info_smmu->transfer_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_RES, true,
+				info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_WP_RES, true,
+				info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		}
+		wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info_smmu->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info_smmu->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	}
 
 	result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
 				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -93,9 +227,12 @@
 	return result;
 }
 
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
+	enum ipa_client_type rx_client;
+	enum ipa_client_type tx_client;
 	struct ipa3_ep_context *ep_rx;
 	struct ipa3_ep_context *ep_tx;
 	int ipa_ep_idx_rx;
@@ -107,8 +244,17 @@
 		return -EINVAL;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+	if (in->is_smmu_enabled == false) {
+		rx_client = in->u_rx.rx.client;
+		tx_client = in->u_tx.tx.client;
+	} else {
+		rx_client = in->u_rx.rx_smmu.client;
+		tx_client = in->u_tx.tx_smmu.client;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
 	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
 		IPAERR("fail to alloc EP.\n");
 		return -EFAULT;
@@ -132,9 +278,14 @@
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
+	if (wdi_notify)
+		ipa3_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+	else
+		IPADBG("wdi_notify is null\n");
+
 	/* setup rx ep cfg */
 	ep_rx->valid = 1;
-	ep_rx->client = in->rx.client;
+	ep_rx->client = rx_client;
 	result = ipa3_disable_data_path(ipa_ep_idx_rx);
 	if (result) {
 		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,7 +296,12 @@
 	ep_rx->client_notify = in->notify;
 	ep_rx->priv = in->priv;
 
-	memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
+	else
+		memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
 
 	if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
 		IPAERR("fail to setup rx pipe cfg\n");
@@ -153,7 +309,8 @@
 		goto fail;
 	}
 
-	if (ipa3_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
 		IPAERR("fail to send cmd to uc for rx pipe\n");
 		result = -EFAULT;
 		goto fail;
@@ -165,12 +322,12 @@
 		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
 
-	IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+	IPADBG("client %d (ep: %d) connected\n", rx_client,
 		ipa_ep_idx_rx);
 
-	/* setup dl ep cfg */
+	/* setup tx ep cfg */
 	ep_tx->valid = 1;
-	ep_tx->client = in->tx.client;
+	ep_tx->client = tx_client;
 	result = ipa3_disable_data_path(ipa_ep_idx_tx);
 	if (result) {
 		IPAERR("disable data path failed res=%d ep=%d.\n", result,
@@ -179,7 +336,12 @@
 		goto fail;
 	}
 
-	memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
+	else
+		memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
 
 	if (ipa3_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
 		IPAERR("fail to setup tx pipe cfg\n");
@@ -187,7 +349,8 @@
 		goto fail;
 	}
 
-	if (ipa3_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
 		IPAERR("fail to send cmd to uc for tx pipe\n");
 		result = -EFAULT;
 		goto fail;
@@ -197,13 +360,7 @@
 		ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
-	out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
-	if (!out->tx_uc_db_va) {
-		IPAERR("fail to ioremap tx uc db\n");
-		result = -EFAULT;
-		goto fail;
-	}
-	IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+	IPADBG("client %d (ep: %d) connected\n", tx_client,
 		ipa_ep_idx_tx);
 
 fail:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 48e7d7c..c3422d1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -2129,11 +2129,11 @@
 		return;
 	}
 
-	valmask->val = (1 << IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_SHFT) &&
+	valmask->val = (1 << IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_SHFT) &
 		IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_BMSK;
 	valmask->mask = IPA_ENDP_INIT_AGGR_n_AGGR_FORCE_CLOSE_BMSK;
 
-	valmask->val |= ((0 << IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT) &&
+	valmask->val |= ((0 << IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT) &
 		IPA_ENDP_INIT_AGGR_n_AGGR_EN_BMSK);
 	valmask->mask |= IPA_ENDP_INIT_AGGR_n_AGGR_EN_BMSK;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 512dddd..833520c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -802,7 +802,7 @@
 {
 	int i;
 
-	for (i = 0; i < MAX_NUM_OF_MUX_CHANNEL; i++) {
+	for (i = 0; i < rmnet_ipa3_ctx->rmnet_index; i++) {
 		if (strcmp(rmnet_ipa3_ctx->mux_channel[i].vchannel_name,
 					vchannel_name) == 0)
 			return i;
@@ -2699,11 +2699,16 @@
 		ipa_stop_polling_stats();
 		if (atomic_read(&rmnet_ipa3_ctx->is_initialized))
 			platform_driver_unregister(&rmnet_ipa_driver);
+
+		if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
+			ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+			ipa3_q6_post_shutdown_cleanup();
 		IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
 		break;
 	case SUBSYS_AFTER_SHUTDOWN:
 		IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n");
-		if (atomic_read(&rmnet_ipa3_ctx->is_ssr))
+		if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
+			ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
 			ipa3_q6_post_shutdown_cleanup();
 		IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
 		break;
@@ -4026,10 +4031,6 @@
 	ipa3_qmi_init();
 
 	/* Register for Modem SSR */
-	/* SSR is not supported yet on IPA 4.0 */
-	if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_0)
-		return platform_driver_register(&rmnet_ipa_driver);
-
 	rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
 			SUBSYS_MODEM,
 			&ipa3_ssr_notifier);
diff --git a/drivers/platform/msm/mhi_dev/Makefile b/drivers/platform/msm/mhi_dev/Makefile
index c1969e2..53ef716 100644
--- a/drivers/platform/msm/mhi_dev/Makefile
+++ b/drivers/platform/msm/mhi_dev/Makefile
@@ -4,3 +4,4 @@
 obj-y += mhi_ring.o
 obj-y += mhi_uci.o
 obj-y += mhi_sm.o
+obj-y += mhi_dev_net.o
diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c
index 7179fcd..c2187c6 100644
--- a/drivers/platform/msm/mhi_dev/mhi.c
+++ b/drivers/platform/msm/mhi_dev/mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -34,13 +34,10 @@
 #include "mhi_sm.h"
 
 /* Wait time on the device for Host to set M0 state */
-#define MHI_M0_WAIT_MIN_USLEEP		20000000
-#define MHI_M0_WAIT_MAX_USLEEP		25000000
 #define MHI_DEV_M0_MAX_CNT		30
 /* Wait time before suspend/resume is complete */
-#define MHI_SUSPEND_WAIT_MIN		3100
-#define MHI_SUSPEND_WAIT_MAX		3200
-#define MHI_SUSPEND_WAIT_TIMEOUT	500
+#define MHI_SUSPEND_MIN			100
+#define MHI_SUSPEND_TIMEOUT		600
 #define MHI_MASK_CH_EV_LEN		32
 #define MHI_RING_CMD_ID			0
 #define MHI_RING_PRIMARY_EVT_ID		1
@@ -59,6 +56,13 @@
 #define HOST_ADDR_MSB(addr)		((addr >> 32) & 0xFFFFFFFF)
 
 #define MHI_IPC_LOG_PAGES		(100)
+#define MHI_REGLEN			0x100
+#define MHI_INIT			0
+#define MHI_REINIT			1
+
+#define TR_RING_ELEMENT_SZ	sizeof(struct mhi_dev_transfer_ring_element)
+#define RING_ELEMENT_TYPE_SZ	sizeof(union mhi_dev_ring_element_type)
+
 enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR;
 enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE;
 void *mhi_ipc_log;
@@ -67,106 +71,213 @@
 static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event,
 	unsigned long data);
 static void mhi_ring_init_cb(void *user_data);
+static void mhi_update_state_info(uint32_t info);
+static int mhi_deinit(struct mhi_dev *mhi);
+static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify);
+static int mhi_dev_pcie_notify_event;
+static void mhi_dev_transfer_completion_cb(void *mreq);
 
-void mhi_dev_read_from_host(struct mhi_addr *host, dma_addr_t dev, size_t size)
+/*
+ * mhi_dev_ring_cache_completion_cb () - Call back function called
+ * by IPA driver when ring element cache is done
+ *
+ * @req : ring cache request
+ */
+static void  mhi_dev_ring_cache_completion_cb(void *req)
 {
-	int rc = 0;
-	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+	struct ring_cache_req *ring_req = NULL;
 
-	host_addr_pa = ((u64) host->host_pa) | bit_40;
-
-	mhi_log(MHI_MSG_ERROR, "device 0x%x <<-- host 0x%llx, size %d\n",
-		dev, host_addr_pa, size);
-
-	rc = ipa_dma_sync_memcpy((u64) dev, host_addr_pa, (int) size);
-	if (rc)
-		pr_err("error while reading from host:%d\n", rc);
+	if (req)
+		ring_req = (struct ring_cache_req *)req;
+	else {
+		pr_err("%s():ring cache req data is NULL\n", __func__);
+		return;
+	}
+	complete(ring_req->done);
 }
-EXPORT_SYMBOL(mhi_dev_read_from_host);
 
-void mhi_dev_write_to_host(struct mhi_addr *host, void *dev, size_t size,
-						struct mhi_dev *mhi)
+void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer)
 {
 	int rc = 0;
-	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+	struct ring_cache_req ring_req;
+
+	DECLARE_COMPLETION(done);
+
+	ring_req.done = &done;
 
 	if (!mhi) {
 		pr_err("invalid MHI ctx\n");
 		return;
 	}
 
-	host_addr_pa = ((u64) host->host_pa) | bit_40;
-	/* Copy the device content to a local device physical address */
-	memcpy(mhi->dma_cache, dev, size);
-	mhi_log(MHI_MSG_ERROR, "device 0x%llx --> host 0x%llx, size %d\n",
-		(uint64_t) mhi->cache_dma_handle, host_addr_pa, (int) size);
+	if (mhi->config_iatu) {
+		offset = (uint64_t) transfer->host_pa - mhi->ctrl_base.host_pa;
+		/* Mapping the translated physical address on the device */
+		host_addr_pa = (uint64_t) mhi->ctrl_base.device_pa + offset;
+	} else {
+		host_addr_pa = transfer->host_pa | bit_40;
+	}
 
-	rc = ipa_dma_sync_memcpy(host_addr_pa, (u64) mhi->cache_dma_handle,
-								(int) size);
+	mhi_log(MHI_MSG_VERBOSE,
+		"device 0x%x <<-- host 0x%llx, size %d\n",
+		transfer->phy_addr, host_addr_pa,
+		(int) transfer->size);
+	rc = ipa_dma_async_memcpy((u64)transfer->phy_addr, host_addr_pa,
+			(int)transfer->size,
+			mhi_dev_ring_cache_completion_cb, &ring_req);
 	if (rc)
 		pr_err("error while reading from host:%d\n", rc);
+
+	wait_for_completion(&done);
+}
+EXPORT_SYMBOL(mhi_dev_read_from_host);
+
+void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *transfer,
+		struct event_req *ereq, enum mhi_dev_transfer_type tr_type)
+{
+	int rc = 0;
+	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+	dma_addr_t dma;
+
+	if (!mhi) {
+		pr_err("invalid MHI ctx\n");
+		return;
+	}
+	if (mhi->config_iatu) {
+		offset = (uint64_t) transfer->host_pa - mhi->ctrl_base.host_pa;
+		/* Mapping the translated physical address on the device */
+		host_addr_pa = (uint64_t) mhi->ctrl_base.device_pa + offset;
+	} else {
+		host_addr_pa = transfer->host_pa | bit_40;
+	}
+
+	mhi_log(MHI_MSG_VERBOSE,
+		"device 0x%llx --> host 0x%llx, size %d\n",
+		(uint64_t) mhi->cache_dma_handle, host_addr_pa,
+		(int) transfer->size);
+	if (tr_type == MHI_DEV_DMA_ASYNC) {
+		dma = dma_map_single(&mhi->pdev->dev,
+				transfer->virt_addr, transfer->size,
+				DMA_TO_DEVICE);
+		if (ereq->event_type == SEND_EVENT_BUFFER) {
+			ereq->dma = dma;
+			ereq->dma_len = transfer->size;
+		} else if (ereq->event_type == SEND_EVENT_RD_OFFSET) {
+			ereq->event_rd_dma = dma;
+		}
+		rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t) dma,
+				(int)transfer->size,
+				ereq->client_cb, ereq);
+		if (rc)
+			pr_err("error while writing to host:%d\n", rc);
+	} else if (tr_type == MHI_DEV_DMA_SYNC) {
+		/* Copy the device content to a local device
+		 * physical address.
+		 */
+		memcpy(mhi->dma_cache, transfer->virt_addr,
+				transfer->size);
+		rc = ipa_dma_sync_memcpy(host_addr_pa,
+				(u64) mhi->cache_dma_handle,
+				(int) transfer->size);
+		if (rc)
+			pr_err("error while writing to host:%d\n", rc);
+	}
 }
 EXPORT_SYMBOL(mhi_dev_write_to_host);
 
 int mhi_transfer_host_to_device(void *dev, uint64_t host_pa, uint32_t len,
-							struct mhi_dev *mhi)
+		struct mhi_dev *mhi, struct mhi_req *mreq)
 {
 	int rc = 0;
-	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+	struct mhi_dev_ring *ring = NULL;
 
-	if (!mhi) {
-		pr_err("Invalid mhi device\n");
+
+	if (!mhi || !dev || !host_pa || !mreq) {
+		pr_err("%s():Invalid parameters\n", __func__);
 		return -EINVAL;
 	}
 
-	if (!dev) {
-		pr_err("Invalid virt device\n");
-		return -EINVAL;
+	if (mhi->config_iatu) {
+		offset = (uint64_t)host_pa - mhi->data_base.host_pa;
+		/* Mapping the translated physical address on the device */
+		host_addr_pa = (uint64_t) mhi->data_base.device_pa + offset;
+	} else {
+		host_addr_pa = host_pa | bit_40;
 	}
 
-	if (!host_pa) {
-		pr_err("Invalid host pa device\n");
-		return -EINVAL;
-	}
-
-	host_addr_pa = host_pa | bit_40;
-	mhi_log(MHI_MSG_ERROR, "device 0x%llx <-- host 0x%llx, size %d\n",
+	mhi_log(MHI_MSG_VERBOSE, "device 0x%llx <-- host 0x%llx, size %d\n",
 		(uint64_t) mhi->read_dma_handle, host_addr_pa, (int) len);
-	rc = ipa_dma_sync_memcpy((u64) mhi->read_dma_handle,
-			host_addr_pa, (int) len);
-	if (rc) {
-		pr_err("error while reading from host:%d\n", rc);
-		return rc;
+
+	if (mreq->mode == IPA_DMA_SYNC) {
+		rc = ipa_dma_sync_memcpy((u64) mhi->read_dma_handle,
+				host_addr_pa, (int) len);
+		if (rc) {
+			pr_err("error while reading chan using sync:%d\n", rc);
+			return rc;
+		}
+		memcpy(dev, mhi->read_handle, len);
+	} else if (mreq->mode == IPA_DMA_ASYNC) {
+		ring = mreq->client->channel->ring;
+		mreq->dma = dma_map_single(&mhi->pdev->dev, dev, len,
+				DMA_FROM_DEVICE);
+		mhi_dev_ring_inc_index(ring, ring->rd_offset);
+
+		if (ring->rd_offset == ring->wr_offset)
+			mreq->snd_cmpl = 1;
+		else
+			mreq->snd_cmpl = 0;
+		rc = ipa_dma_async_memcpy(mreq->dma, host_addr_pa,
+				(int) len, mhi_dev_transfer_completion_cb,
+				mreq);
+		if (rc) {
+			pr_err("error while reading chan using async:%d\n", rc);
+			return rc;
+		}
 	}
-
-	memcpy(dev, mhi->read_handle, len);
-
 	return rc;
 }
 EXPORT_SYMBOL(mhi_transfer_host_to_device);
 
 int mhi_transfer_device_to_host(uint64_t host_addr, void *dev, uint32_t len,
-						struct mhi_dev *mhi)
+		struct mhi_dev *mhi, struct mhi_req *req)
 {
 	int rc = 0;
-	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0;
+	uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
+	struct mhi_dev_ring *ring = NULL;
 
-	if (!mhi || !dev || !host_addr) {
+	if (!mhi || !dev || !req  || !host_addr) {
 		pr_err("%sInvalid parameters\n", __func__);
 		return -EINVAL;
 	}
 
-	host_addr_pa = host_addr | bit_40;
-	memcpy(mhi->write_handle, dev, len);
+	if (mhi->config_iatu) {
+		offset = (uint64_t)host_addr - mhi->data_base.host_pa;
+		/* Mapping the translated physical address on the device */
+		host_addr_pa = (uint64_t) mhi->data_base.device_pa + offset;
+	} else {
+		host_addr_pa = host_addr | bit_40;
+	}
+	mhi_log(MHI_MSG_VERBOSE, "device 0x%llx ---> host 0x%llx, size %d\n",
+				(uint64_t) mhi->write_dma_handle,
+				host_addr_pa, (int) len);
 
-	mhi_log(MHI_MSG_ERROR, "device 0x%llx ---> host 0x%llx, size %d\n",
-		(uint64_t) mhi->write_dma_handle, host_addr_pa, (int) len);
-	rc = ipa_dma_sync_memcpy(host_addr_pa,
-			(u64) mhi->write_dma_handle,
-			(int) len);
-	if (rc)
-		pr_err("error while reading from host:%d\n", rc);
-
+	if (req->mode == IPA_DMA_SYNC) {
+		memcpy(mhi->write_handle, dev, len);
+		rc = ipa_dma_sync_memcpy(host_addr_pa,
+				(u64) mhi->write_dma_handle, (int) len);
+	} else if (req->mode == IPA_DMA_ASYNC) {
+		req->dma = dma_map_single(&mhi->pdev->dev, req->buf,
+				req->len, DMA_TO_DEVICE);
+		ring = req->client->channel->ring;
+		mhi_dev_ring_inc_index(ring, ring->rd_offset);
+		if (ring->rd_offset == ring->wr_offset)
+			req->snd_cmpl = 1;
+		rc = ipa_dma_async_memcpy(host_addr_pa,
+				(uint64_t) req->dma, (int) len,
+				mhi_dev_transfer_completion_cb, req);
+	}
 	return rc;
 }
 EXPORT_SYMBOL(mhi_transfer_device_to_host);
@@ -216,7 +327,7 @@
 
 	mhi_dev_get_erdb_db_cfg(mhi, &erdb_cfg);
 
-	mhi_log(MHI_MSG_ERROR,
+	mhi_log(MHI_MSG_VERBOSE,
 		"Event rings 0x%x => er_base 0x%x, er_end %d\n",
 		mhi->cfg.event_rings, erdb_cfg.base, erdb_cfg.end);
 	erdb_cfg.tgt_addr = (uint32_t) mhi->ipa_uc_mbox_erdb;
@@ -247,7 +358,7 @@
 	}
 
 	mhi_dev_get_erdb_db_cfg(mhi, &erdb_cfg);
-	mhi_log(MHI_MSG_ERROR,
+	mhi_log(MHI_MSG_VERBOSE,
 		"Event rings 0x%x => er_base 0x%x, er_end %d\n",
 		mhi->cfg.event_rings, erdb_cfg.base, erdb_cfg.end);
 
@@ -259,10 +370,18 @@
 	ipa_init_params.msi.mask = ((1 << cfg.msg_num) - 1);
 	ipa_init_params.first_er_idx = erdb_cfg.base;
 	ipa_init_params.first_ch_idx = HW_CHANNEL_BASE;
-	ipa_init_params.mmio_addr = ((uint32_t) mhi_ctx->mmio_base_pa_addr);
-	ipa_init_params.assert_bit40 = true;
 
-	mhi_log(MHI_MSG_ERROR,
+	if (mhi_ctx->config_iatu)
+		ipa_init_params.mmio_addr =
+			((uint32_t) mhi_ctx->mmio_base_pa_addr) + MHI_REGLEN;
+	else
+		ipa_init_params.mmio_addr =
+			((uint32_t) mhi_ctx->mmio_base_pa_addr);
+
+	if (!mhi_ctx->config_iatu)
+		ipa_init_params.assert_bit40 = true;
+
+	mhi_log(MHI_MSG_VERBOSE,
 		"MMIO Addr 0x%x, MSI config: U:0x%x L: 0x%x D: 0x%x\n",
 		ipa_init_params.mmio_addr, cfg.upper, cfg.lower, cfg.data);
 	ipa_init_params.notify = mhi_hwc_cb;
@@ -284,10 +403,15 @@
 
 	memset(&ipa_start_params, 0, sizeof(ipa_start_params));
 
-	ipa_start_params.channel_context_array_addr =
+	if (mhi->config_iatu) {
+		ipa_start_params.host_ctrl_addr = mhi->ctrl_base.device_pa;
+		ipa_start_params.host_data_addr = mhi->data_base.device_pa;
+	} else {
+		ipa_start_params.channel_context_array_addr =
 				mhi->ch_ctx_shadow.host_pa;
-	ipa_start_params.event_context_array_addr =
+		ipa_start_params.event_context_array_addr =
 				mhi->ev_ctx_shadow.host_pa;
+	}
 
 	rc = ipa_mhi_start(&ipa_start_params);
 	if (rc)
@@ -303,7 +427,7 @@
 
 	switch (event) {
 	case IPA_MHI_EVENT_READY:
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_INFO,
 			"HW Channel uC is ready event=0x%X\n", event);
 		rc = mhi_hwc_start(mhi_ctx);
 		if (rc) {
@@ -329,6 +453,11 @@
 			pr_err("Failed to enable command db\n");
 			return;
 		}
+
+		mhi_update_state_info(MHI_STATE_CONNECTED);
+
+		ep_pcie_mask_irq_event(mhi_ctx->phandle,
+				EP_PCIE_INT_EVT_MHI_A7, true);
 		break;
 	case IPA_MHI_EVENT_DATA_AVAILABLE:
 		rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP);
@@ -352,6 +481,7 @@
 	memset(&connect_params, 0, sizeof(connect_params));
 
 	switch (type) {
+	case MHI_DEV_RING_EL_RESET:
 	case MHI_DEV_RING_EL_STOP:
 		rc = ipa_mhi_disconnect_pipe(
 			mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]);
@@ -402,15 +532,18 @@
 
 static void mhi_dev_fetch_ch_ctx(struct mhi_dev *mhi, uint32_t ch_id)
 {
-	struct mhi_addr addr;
+	struct mhi_addr data_transfer;
 
-	addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+	if (mhi->use_ipa) {
+		data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
 					sizeof(struct mhi_dev_ch_ctx) * ch_id;
-	addr.size  = sizeof(struct mhi_dev_ch_ctx);
+		data_transfer.phy_addr = mhi->ch_ctx_cache_dma_handle +
+					sizeof(struct mhi_dev_ch_ctx) * ch_id;
+	}
+
+	data_transfer.size  = sizeof(struct mhi_dev_ch_ctx);
 	/* Fetch the channel ctx (*dst, *src, size) */
-	mhi_dev_read_from_host(&addr, mhi->ch_ctx_cache_dma_handle +
-					(sizeof(struct mhi_dev_ch_ctx) * ch_id),
-				sizeof(struct mhi_dev_ch_ctx));
+	mhi_dev_read_from_host(mhi, &data_transfer);
 }
 
 int mhi_dev_syserr(struct mhi_dev *mhi)
@@ -436,24 +569,21 @@
 	struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
 	union mhi_dev_ring_ctx *ctx;
 	struct ep_pcie_msi_config cfg;
-	struct mhi_addr msi_addr;
-	uint32_t msi = 0;
-	struct mhi_addr host_rp_addr;
+	struct mhi_addr transfer_addr;
 
-	rc = ep_pcie_get_msi_config(mhi->phandle,
-			&cfg);
-		if (rc) {
-			pr_err("Error retrieving pcie msi logic\n");
-			return rc;
-		}
+	rc = ep_pcie_get_msi_config(mhi->phandle, &cfg);
+	if (rc) {
+		pr_err("Error retrieving pcie msi logic\n");
+		return rc;
+	}
 
 	if (evnt_ring_idx > mhi->cfg.event_rings) {
 		pr_err("Invalid event ring idx: %lld\n", evnt_ring_idx);
 		return -EINVAL;
 	}
 
+	ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
 	if (mhi_ring_get_state(ring) == RING_STATE_UINT) {
-		ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
 		rc = mhi_ring_start(ring, ctx, mhi);
 		if (rc) {
 			mhi_log(MHI_MSG_ERROR,
@@ -464,23 +594,30 @@
 
 	mutex_lock(&mhi->mhi_event_lock);
 	/* add the ring element */
-	mhi_dev_add_element(ring, el);
+	mhi_dev_add_element(ring, el, NULL, 0);
 
 	ring->ring_ctx_shadow->ev.rp =  (ring->rd_offset *
 				sizeof(union mhi_dev_ring_element_type)) +
 				ring->ring_ctx->generic.rbase;
 
-	mhi_log(MHI_MSG_ERROR, "ev.rp = %llx for %lld\n",
+	mhi_log(MHI_MSG_VERBOSE, "ev.rp = %llx for %lld\n",
 				ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);
 
-	host_rp_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
+	if (mhi->use_ipa)
+		transfer_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
 			sizeof(struct mhi_dev_ev_ctx) *
 			evnt_ring) + (uint32_t) &ring->ring_ctx->ev.rp -
 			(uint32_t) ring->ring_ctx;
-	mhi_dev_write_to_host(&host_rp_addr, &ring->ring_ctx_shadow->ev.rp,
-						sizeof(uint64_t),
-						mhi);
+	else
+		transfer_addr.device_va = (mhi->ev_ctx_shadow.device_va +
+			sizeof(struct mhi_dev_ev_ctx) *
+			evnt_ring) + (uint32_t) &ring->ring_ctx->ev.rp -
+			(uint32_t) ring->ring_ctx;
 
+	transfer_addr.virt_addr = &ring->ring_ctx_shadow->ev.rp;
+	transfer_addr.size = sizeof(uint64_t);
+
+	mhi_dev_write_to_host(mhi, &transfer_addr, NULL, MHI_DEV_DMA_SYNC);
 	/*
 	 * rp update in host memory should be flushed
 	 * before sending a MSI to the host
@@ -488,20 +625,141 @@
 	wmb();
 
 	mutex_unlock(&mhi->mhi_event_lock);
-	mhi_log(MHI_MSG_ERROR, "event sent:\n");
-	mhi_log(MHI_MSG_ERROR, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr);
-	mhi_log(MHI_MSG_ERROR, "evnt len : 0x%x\n", el->evt_tr_comp.len);
-	mhi_log(MHI_MSG_ERROR, "evnt code :0x%x\n", el->evt_tr_comp.code);
-	mhi_log(MHI_MSG_ERROR, "evnt type :0x%x\n", el->evt_tr_comp.type);
-	mhi_log(MHI_MSG_ERROR, "evnt chid :0x%x\n", el->evt_tr_comp.chid);
+	mhi_log(MHI_MSG_VERBOSE, "event sent:\n");
+	mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr);
+	mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n", el->evt_tr_comp.len);
+	mhi_log(MHI_MSG_VERBOSE, "evnt code :0x%x\n", el->evt_tr_comp.code);
+	mhi_log(MHI_MSG_VERBOSE, "evnt type :0x%x\n", el->evt_tr_comp.type);
+	mhi_log(MHI_MSG_VERBOSE, "evnt chid :0x%x\n", el->evt_tr_comp.chid);
+	rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
+	if (rc) {
+		pr_err("%s: error sending msi\n", __func__);
+		return rc;
+	}
+	return rc;
+}
 
-	msi_addr.host_pa = (uint64_t)((uint64_t)cfg.upper << 32) |
-						(uint64_t)cfg.lower;
-	msi = cfg.data + mhi_ctx->mhi_ep_msi_num;
-	mhi_log(MHI_MSG_ERROR, "Sending MSI %d to 0x%llx as data = 0x%x\n",
-			mhi_ctx->mhi_ep_msi_num, msi_addr.host_pa, msi);
-	mhi_dev_write_to_host(&msi_addr, &msi, 4, mhi);
+/*
+ * mhi_dev_event_buf_completion_cb() -Cb function called by IPA driver
+ * when transfer completion event buffer copy is done.
+ *
+ * @req -  event_req structure
+ */
 
+static void mhi_dev_event_buf_completion_cb(void *req)
+{
+	struct event_req *ereq = NULL;
+
+	if (req) {
+		ereq = (struct event_req *)req;
+	} else {
+		pr_err("%s():event req data is invalid\n", __func__);
+		return;
+	}
+	dma_unmap_single(&mhi_ctx->pdev->dev, ereq->dma,
+			ereq->dma_len, DMA_TO_DEVICE);
+}
+
+/**
+ * mhi_dev_event_rd_offset_completion_cb() -CB function called by IPA driver
+ * when event rd_offset transfer is done.
+ *
+ * @req -  event_req structure
+ */
+
+static void mhi_dev_event_rd_offset_completion_cb(void *req)
+{
+	union mhi_dev_ring_ctx *ctx;
+	int rc = 0;
+	struct event_req *ereq = (struct event_req *)req;
+	struct mhi_dev_channel *ch = ereq->context;
+	struct mhi_dev *mhi = ch->ring->mhi_dev;
+	unsigned long flags;
+
+	dma_unmap_single(&mhi_ctx->pdev->dev, ereq->event_rd_dma,
+			sizeof(uint64_t), DMA_TO_DEVICE);
+	ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[ereq->event_ring];
+	rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
+	if (rc)
+		pr_err("%s: error sending in msi\n", __func__);
+
+	/* return the event req to pre allocated pooled list */
+	spin_lock_irqsave(&mhi->lock, flags);
+	list_add_tail(&ereq->list, &ch->event_req_buffers);
+	spin_unlock_irqrestore(&mhi->lock, flags);
+}
+
+static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
+		struct event_req *ereq, uint32_t evt_len)
+{
+	int rc = 0;
+	uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
+	struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
+	union mhi_dev_ring_ctx *ctx;
+	struct mhi_addr transfer_addr;
+	static int count;
+
+	if (!ereq) {
+		pr_err("%s(): invalid event req\n", __func__);
+		return -EINVAL;
+	}
+
+	if (count == 0) {
+		rc = ep_pcie_get_msi_config(mhi->phandle, &mhi->msi_cfg);
+		if (rc) {
+			pr_err("Error retrieving pcie msi logic\n");
+			return rc;
+		}
+		count++;
+	}
+
+	if (evnt_ring_idx > mhi->cfg.event_rings) {
+		pr_err("Invalid event ring idx: %lld\n", evnt_ring_idx);
+		return -EINVAL;
+	}
+
+	ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[evnt_ring];
+	if (mhi_ring_get_state(ring) == RING_STATE_UINT) {
+		rc = mhi_ring_start(ring, ctx, mhi);
+		if (rc) {
+			mhi_log(MHI_MSG_ERROR,
+				"error starting event ring %d\n", evnt_ring);
+			return rc;
+		}
+	}
+
+	/* add the ring element */
+	ereq->client_cb = mhi_dev_event_buf_completion_cb;
+	ereq->event_type = SEND_EVENT_BUFFER;
+	rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
+	if (rc) {
+		pr_err("%s(): error in adding element rc %d\n", __func__, rc);
+		return rc;
+	}
+	ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
+		sizeof(union mhi_dev_ring_element_type)) +
+		ring->ring_ctx->generic.rbase;
+
+	mhi_log(MHI_MSG_VERBOSE, "ev.rp = %llx for %lld\n",
+		ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);
+
+	if (mhi->use_ipa)
+		transfer_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
+		sizeof(struct mhi_dev_ev_ctx) *
+		evnt_ring) + (uint32_t)&ring->ring_ctx->ev.rp -
+		(uint32_t)ring->ring_ctx;
+	else
+		transfer_addr.device_va = (mhi->ev_ctx_shadow.device_va +
+		sizeof(struct mhi_dev_ev_ctx) *
+		evnt_ring) + (uint32_t)&ring->ring_ctx->ev.rp -
+		(uint32_t)ring->ring_ctx;
+
+	transfer_addr.virt_addr = &ring->ring_ctx_shadow->ev.rp;
+	transfer_addr.size = sizeof(uint64_t);
+	ereq->event_type = SEND_EVENT_RD_OFFSET;
+	ereq->client_cb = mhi_dev_event_rd_offset_completion_cb;
+	ereq->event_ring = evnt_ring;
+	mhi_dev_write_to_host(mhi, &transfer_addr, ereq, MHI_DEV_DMA_ASYNC);
 	return rc;
 }
 
@@ -564,6 +822,21 @@
 }
 EXPORT_SYMBOL(mhi_dev_send_ee_event);
 
+static void mhi_dev_trigger_cb(void)
+{
+	struct mhi_dev_ready_cb_info *info;
+	uint32_t state_data;
+
+	mutex_lock(&mhi_ctx->mhi_lock);
+	list_for_each_entry(info, &mhi_ctx->client_cb_list, list)
+		if (info->cb) {
+			mhi_ctrl_state_info(&state_data);
+			info->cb_data.ctrl_info = state_data;
+			info->cb(&info->cb_data);
+		}
+	mutex_unlock(&mhi_ctx->mhi_lock);
+}
+
 int mhi_dev_trigger_hw_acc_wakeup(struct mhi_dev *mhi)
 {
 	int rc = 0;
@@ -591,7 +864,7 @@
 	event.evt_cmd_comp.ptr = mhi->cmd_ctx_cache->rbase
 			+ (mhi->ring[MHI_RING_CMD_ID].rd_offset *
 			(sizeof(union mhi_dev_ring_element_type)));
-	mhi_log(MHI_MSG_ERROR, "evt cmd comp ptr :%d\n",
+	mhi_log(MHI_MSG_VERBOSE, "evt cmd comp ptr :%d\n",
 			(uint32_t) event.evt_cmd_comp.ptr);
 	event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
 	event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_SUCCESS;
@@ -607,27 +880,38 @@
 							struct mhi_dev *mhi)
 {
 	int rc = 0;
-	struct mhi_addr host_addr;
+	struct mhi_addr data_transfer;
 
 	if (ring->rd_offset != ring->wr_offset &&
 		mhi->ch_ctx_cache[ch_id].ch_type ==
 				MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL) {
-		mhi_log(MHI_MSG_INFO, "Pending transaction to be processed\n");
+		mhi_log(MHI_MSG_INFO, "Pending outbound transaction\n");
 		return 0;
 	} else if (mhi->ch_ctx_cache[ch_id].ch_type ==
 			MHI_DEV_CH_TYPE_INBOUND_CHANNEL &&
 			mhi->ch[ch_id].wr_request_active) {
+		mhi_log(MHI_MSG_INFO, "Pending inbound transaction\n");
 		return 0;
 	}
 
 	/* set the channel to stop */
 	mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_STOP;
+	mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
 
-	host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+	if (mhi->use_ipa) {
+		data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
 				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+	} else {
+		data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+		data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+	}
+	data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+	data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
+
 	/* update the channel state in the host */
-	mhi_dev_write_to_host(&host_addr, &mhi->ch_ctx_cache[ch_id].ch_state,
-				sizeof(enum mhi_dev_ch_ctx_state), mhi);
+	mhi_dev_write_to_host(mhi, &data_transfer, NULL, MHI_DEV_DMA_SYNC);
 
 	/* send the completion event to the host */
 	rc = mhi_dev_send_cmd_comp_event(mhi);
@@ -644,14 +928,16 @@
 	uint32_t ch_id = 0;
 	union mhi_dev_ring_element_type event;
 	struct mhi_addr host_addr;
+	struct mhi_dev_channel *ch;
+	struct mhi_dev_ring *ring;
 
-	mhi_log(MHI_MSG_ERROR, "for channel:%d and cmd:%d\n",
-		ch_id, el->generic.type);
 	ch_id = el->generic.chid;
+	mhi_log(MHI_MSG_VERBOSE, "for channel:%d and cmd:%d\n",
+		ch_id, el->generic.type);
 
 	switch (el->generic.type) {
 	case MHI_DEV_RING_EL_START:
-		mhi_log(MHI_MSG_ERROR, "recived start cmd for channel %d\n",
+		mhi_log(MHI_MSG_VERBOSE, "recived start cmd for channel %d\n",
 								ch_id);
 		if (ch_id >= (HW_CHANNEL_BASE)) {
 			rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type);
@@ -680,6 +966,7 @@
 
 		/* set the channel to running */
 		mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_RUNNING;
+		mhi->ch[ch_id].state = MHI_DEV_CH_STARTED;
 		mhi->ch[ch_id].ch_id = ch_id;
 		mhi->ch[ch_id].ring = &mhi->ring[mhi->ch_ring_start + ch_id];
 		mhi->ch[ch_id].ch_type = mhi->ch_ctx_cache[ch_id].ch_type;
@@ -691,17 +978,26 @@
 			return;
 		}
 
-		host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+		if (mhi->use_ipa)
+			host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
 					sizeof(struct mhi_dev_ch_ctx) * ch_id;
-		mhi_dev_write_to_host(&host_addr,
-					&mhi->ch_ctx_cache[ch_id].ch_state,
-					sizeof(enum mhi_dev_ch_ctx_state), mhi);
+		else
+			host_addr.device_va = mhi->ch_ctx_shadow.device_va +
+					sizeof(struct mhi_dev_ch_ctx) * ch_id;
+
+		host_addr.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
+		host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
+
+		mhi_dev_write_to_host(mhi, &host_addr, NULL, MHI_DEV_DMA_SYNC);
 
 send_start_completion_event:
 		rc = mhi_dev_send_cmd_comp_event(mhi);
 		if (rc)
 			pr_err("Error sending command completion event\n");
 
+		/* Trigger callback to clients */
+		mhi_dev_trigger_cb();
+
 		break;
 	case MHI_DEV_RING_EL_STOP:
 		if (ch_id >= HW_CHANNEL_BASE) {
@@ -738,32 +1034,99 @@
 			 * channel command to check if one can suspend the
 			 * command.
 			 */
+			ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+			if (ring->state == RING_STATE_UINT) {
+				pr_err("Channel not opened for %d\n", ch_id);
+				return;
+			}
+
+			ch = &mhi->ch[ch_id];
+
+			mutex_lock(&ch->ch_lock);
+
 			mhi->ch[ch_id].state = MHI_DEV_CH_PENDING_STOP;
 			rc = mhi_dev_process_stop_cmd(
 				&mhi->ring[mhi->ch_ring_start + ch_id],
 				ch_id, mhi);
+			if (rc)
+				pr_err("stop event send failed\n");
+
+			mutex_unlock(&ch->ch_lock);
+		}
+		break;
+	case MHI_DEV_RING_EL_RESET:
+		mhi_log(MHI_MSG_VERBOSE,
+			"received reset cmd for channel %d\n", ch_id);
+		if (ch_id >= HW_CHANNEL_BASE) {
+			rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type);
+			if (rc) {
+				mhi_log(MHI_MSG_ERROR,
+					"send channel stop cmd event failed\n");
+				return;
+			}
+
+			/* send the completion event to the host */
+			event.evt_cmd_comp.ptr = mhi->cmd_ctx_cache->rbase +
+				(mhi->ring[MHI_RING_CMD_ID].rd_offset *
+				(sizeof(union mhi_dev_ring_element_type)));
+			event.evt_cmd_comp.type =
+					MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
+			if (rc == 0)
+				event.evt_cmd_comp.code =
+					MHI_CMD_COMPL_CODE_SUCCESS;
+			else
+				event.evt_cmd_comp.code =
+					MHI_CMD_COMPL_CODE_UNDEFINED;
+
+			rc = mhi_dev_send_event(mhi, 0, &event);
 			if (rc) {
 				pr_err("stop event send failed\n");
 				return;
 			}
+		} else {
+
+			mhi_log(MHI_MSG_VERBOSE,
+					"received reset cmd for channel %d\n",
+					ch_id);
+
+			ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+			if (ring->state == RING_STATE_UINT) {
+				pr_err("Channel not opened for %d\n", ch_id);
+				return;
+			}
+
+			ch = &mhi->ch[ch_id];
+
+			mutex_lock(&ch->ch_lock);
+
+			/* hard stop and set the channel to stop */
+			mhi->ch_ctx_cache[ch_id].ch_state =
+						MHI_DEV_CH_STATE_DISABLED;
+			mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
+			if (mhi->use_ipa)
+				host_addr.host_pa =
+					mhi->ch_ctx_shadow.host_pa +
+					(sizeof(struct mhi_dev_ch_ctx) * ch_id);
+			else
+				host_addr.device_va =
+					mhi->ch_ctx_shadow.device_va +
+					(sizeof(struct mhi_dev_ch_ctx) * ch_id);
+
+			host_addr.virt_addr =
+					&mhi->ch_ctx_cache[ch_id].ch_state;
+			host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
+
+			/* update the channel state in the host */
+			mhi_dev_write_to_host(mhi, &host_addr, NULL,
+					MHI_DEV_DMA_SYNC);
+
+			/* send the completion event to the host */
+			rc = mhi_dev_send_cmd_comp_event(mhi);
+			if (rc)
+				pr_err("Error sending command completion event\n");
+			mutex_unlock(&ch->ch_lock);
 		}
 		break;
-	case MHI_DEV_RING_EL_RESET:
-		/* hard stop and set the channel to stop */
-		mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_STOP;
-		host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
-				sizeof(struct mhi_dev_ch_ctx) * ch_id;
-
-		/* update the channel state in the host */
-		mhi_dev_write_to_host(&host_addr,
-				&mhi->ch_ctx_cache[ch_id].ch_state,
-				sizeof(enum mhi_dev_ch_ctx_state), mhi);
-
-		/* send the completion event to the host */
-		rc = mhi_dev_send_cmd_comp_event(mhi);
-		if (rc)
-			pr_err("Error sending command completion event\n");
-		break;
 	default:
 		pr_err("%s: Invalid command:%d\n", __func__, el->generic.type);
 		break;
@@ -778,7 +1141,7 @@
 	struct mhi_dev_client_cb_reason reason;
 
 	if (ring->id < mhi->ch_ring_start) {
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"invalid channel ring id (%d), should be < %d\n",
 			ring->id, mhi->ch_ring_start);
 		return;
@@ -816,7 +1179,7 @@
 	list_for_each_safe(cp, q, &mhi->process_ring_list) {
 		ring = list_entry(cp, struct mhi_dev_ring, list);
 		list_del(cp);
-		mhi_log(MHI_MSG_ERROR, "processing ring %d\n", ring->id);
+		mhi_log(MHI_MSG_VERBOSE, "processing ring %d\n", ring->id);
 		rc = mhi_dev_process_ring(ring);
 		if (rc) {
 			mhi_log(MHI_MSG_ERROR,
@@ -879,7 +1242,7 @@
 		if (chintr_value & 1) {
 			ring = &mhi->ring[ch_num + mhi->ch_ring_start];
 			if (ring->state == RING_STATE_UINT) {
-				pr_err("Channel not opened for %d\n", ch_num);
+				pr_debug("Channel not opened for %d\n", ch_num);
 				break;
 			}
 			mhi_ring_set_state(ring, RING_STATE_PENDING);
@@ -907,9 +1270,10 @@
 
 	for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) {
 		ch_num = i * MHI_MASK_CH_EV_LEN;
-		chintr_value = mhi->chdb[i].status;
+		/* Process channel status whose mask is enabled */
+		chintr_value = (mhi->chdb[i].status & mhi->chdb[i].mask);
 		if (chintr_value) {
-			mhi_log(MHI_MSG_ERROR,
+			mhi_log(MHI_MSG_VERBOSE,
 				"processing id: %d, ch interrupt 0x%x\n",
 							i, chintr_value);
 			mhi_dev_queue_channel_db(mhi, chintr_value, ch_num);
@@ -923,6 +1287,153 @@
 	}
 }
 
+static int mhi_dev_abort(struct mhi_dev *mhi)
+{
+	struct mhi_dev_channel *ch;
+	struct mhi_dev_ring *ring;
+	int ch_id = 0, rc = 0;
+
+	/* Hard stop all the channels */
+	for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) {
+		ring = &mhi->ring[ch_id + mhi->ch_ring_start];
+		if (ring->state == RING_STATE_UINT)
+			continue;
+
+		ch = &mhi->ch[ch_id];
+		mutex_lock(&ch->ch_lock);
+		mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
+		mutex_unlock(&ch->ch_lock);
+	}
+
+	/* Update ctrl node */
+	mhi_update_state_info(MHI_STATE_DISCONNECTED);
+
+	flush_workqueue(mhi->ring_init_wq);
+	flush_workqueue(mhi->pending_ring_wq);
+
+	/* Initiate MHI IPA reset */
+	ipa_mhi_destroy();
+
+	/* Clean up initialized channels */
+	rc = mhi_deinit(mhi);
+	if (rc) {
+		pr_err("Error during mhi_deinit with %d\n", rc);
+		return rc;
+	}
+
+	rc = mhi_dev_mmio_mask_chdb_interrupts(mhi_ctx);
+	if (rc) {
+		pr_err("Failed to enable channel db\n");
+		return rc;
+	}
+
+	rc = mhi_dev_mmio_disable_ctrl_interrupt(mhi_ctx);
+	if (rc) {
+		pr_err("Failed to enable control interrupt\n");
+		return rc;
+	}
+
+	rc = mhi_dev_mmio_disable_cmdb_interrupt(mhi_ctx);
+	if (rc) {
+		pr_err("Failed to enable command db\n");
+		return rc;
+	}
+
+
+	atomic_set(&mhi_ctx->re_init_done, 0);
+
+	mhi_log(MHI_MSG_INFO,
+			"Register a PCIe callback during re-init\n");
+	mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP;
+	mhi_ctx->event_reg.user = mhi_ctx;
+	mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+	mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up;
+	mhi_ctx->event_reg.options = MHI_REINIT;
+
+	rc = ep_pcie_register_event(mhi_ctx->phandle,
+					&mhi_ctx->event_reg);
+	if (rc) {
+		pr_err("Failed to register for events from PCIe\n");
+		return rc;
+	}
+
+	/* Set RESET field to 0 */
+	mhi_dev_mmio_reset(mhi_ctx);
+
+	return rc;
+}
+
+static void mhi_dev_transfer_completion_cb(void *mreq)
+{
+	struct mhi_dev_channel *ch;
+	struct mhi_dev_client *client;
+	union mhi_dev_ring_element_type *el;
+	int rc = 0;
+	struct mhi_req *req = (struct mhi_req *)mreq;
+	struct mhi_req *local_req = NULL;
+	union mhi_dev_ring_element_type *compl_ev = NULL;
+	struct mhi_dev *mhi = NULL;
+	unsigned long flags;
+
+	client = req->client;
+	ch = client->channel;
+	mhi = ch->ring->mhi_dev;
+	el = req->el;
+	local_req = req;
+	ch->curr_ereq->context = ch;
+
+	dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
+			req->len, DMA_FROM_DEVICE);
+
+	/* Trigger client call back */
+	req->client_cb(req);
+
+	if (el->tre.ieot) {
+		compl_ev = ch->curr_ereq->tr_events + ch->curr_ereq->num_events;
+		compl_ev->evt_tr_comp.chid = ch->ch_id;
+		compl_ev->evt_tr_comp.type =
+				MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT;
+		compl_ev->evt_tr_comp.len = el->tre.len;
+		compl_ev->evt_tr_comp.code = MHI_CMD_COMPL_CODE_EOT;
+		compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase +
+				local_req->rd_offset * TR_RING_ELEMENT_SZ;
+		ch->curr_ereq->num_events++;
+
+		if (ch->curr_ereq->num_events >= MAX_TR_EVENTS ||
+				local_req->snd_cmpl){
+			mhi_log(MHI_MSG_VERBOSE,
+					"num of tr events %d for ch %d\n",
+					ch->curr_ereq->num_events, ch->ch_id);
+			rc = mhi_dev_send_multiple_tr_events(mhi,
+				mhi->ch_ctx_cache[ch->ch_id].err_indx,
+				ch->curr_ereq, (ch->curr_ereq->num_events*
+				sizeof(union mhi_dev_ring_element_type)));
+			if (rc)
+				mhi_log(MHI_MSG_ERROR,
+						"failed to send compl evts\n");
+			if (!list_empty(&ch->event_req_buffers)) {
+				ch->curr_ereq =
+					container_of(ch->event_req_buffers.next,
+							struct event_req, list);
+				spin_lock_irqsave(&mhi->lock, flags);
+				list_del_init(&ch->curr_ereq->list);
+				spin_unlock_irqrestore(&mhi->lock, flags);
+				ch->curr_ereq->num_events = 0;
+			} else
+				pr_err("%s evt req buffers empty\n", __func__);
+		}
+	} else
+		mhi_log(MHI_MSG_ERROR, "ieot is not valid\n");
+
+	if (ch->state == MHI_DEV_CH_PENDING_STOP) {
+		ch->state = MHI_DEV_CH_STOPPED;
+		rc = mhi_dev_process_stop_cmd(ch->ring, ch->ch_id, mhi_ctx);
+		if (rc)
+			mhi_log(MHI_MSG_ERROR,
+			"Error while stopping channel (%d)\n", ch->ch_id);
+	}
+}
+
 static void mhi_dev_scheduler(struct work_struct *work)
 {
 	struct mhi_dev *mhi = container_of(work,
@@ -932,38 +1443,48 @@
 	struct mhi_dev_ring *ring;
 	enum mhi_dev_state state;
 	enum mhi_dev_event event = 0;
+	bool mhi_reset = false;
 
 	mutex_lock(&mhi_ctx->mhi_lock);
 	/* Check for interrupts */
 	mhi_dev_core_ack_ctrl_interrupts(mhi, &int_value);
 
 	if (int_value & MHI_MMIO_CTRL_INT_STATUS_A7_MSK) {
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"processing ctrl interrupt with %d\n", int_value);
-		rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+		rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
 		if (rc) {
 			pr_err("%s: get mhi state failed\n", __func__);
 			mutex_unlock(&mhi_ctx->mhi_lock);
 			return;
 		}
 
+		if (mhi_reset) {
+			mhi_log(MHI_MSG_VERBOSE,
+				"processing mhi device reset\n");
+			rc = mhi_dev_abort(mhi);
+			if (rc)
+				pr_err("device reset failed:%d\n", rc);
+			mutex_unlock(&mhi_ctx->mhi_lock);
+			queue_work(mhi->ring_init_wq, &mhi->re_init);
+			return;
+		}
+
 		rc = mhi_dev_get_event_notify(state, &event);
 		if (rc) {
 			pr_err("unsupported state :%d\n", state);
-			mutex_unlock(&mhi_ctx->mhi_lock);
-			return;
+			goto fail;
 		}
 
 		rc = mhi_dev_notify_sm_event(event);
 		if (rc) {
 			pr_err("error sending SM event\n");
-			mutex_unlock(&mhi_ctx->mhi_lock);
-			return;
+			goto fail;
 		}
 	}
 
 	if (int_value & MHI_MMIO_CTRL_CRDB_STATUS_MSK) {
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"processing cmd db interrupt with %d\n", int_value);
 		ring = &mhi->ring[MHI_RING_CMD_ID];
 		ring->state = RING_STATE_PENDING;
@@ -973,20 +1494,67 @@
 	/* get the specific channel interrupts */
 	mhi_dev_check_channel_interrupt(mhi);
 
+fail:
 	mutex_unlock(&mhi_ctx->mhi_lock);
-	ep_pcie_mask_irq_event(mhi->phandle,
+
+	if (mhi->config_iatu || mhi->mhi_int)
+		enable_irq(mhi->mhi_irq);
+	else
+		ep_pcie_mask_irq_event(mhi->phandle,
 				EP_PCIE_INT_EVT_MHI_A7, true);
 }
 
 void mhi_dev_notify_a7_event(struct mhi_dev *mhi)
 {
+
+	if (!atomic_read(&mhi->mhi_dev_wake)) {
+		pm_stay_awake(mhi->dev);
+		atomic_set(&mhi->mhi_dev_wake, 1);
+	}
+	mhi_log(MHI_MSG_VERBOSE, "acquiring mhi wakelock\n");
+
 	schedule_work(&mhi->chdb_ctrl_work);
-	mhi_log(MHI_MSG_ERROR, "mhi irq triggered\n");
+	mhi_log(MHI_MSG_VERBOSE, "mhi irq triggered\n");
 }
 EXPORT_SYMBOL(mhi_dev_notify_a7_event);
 
+static irqreturn_t mhi_dev_isr(int irq, void *dev_id)
+{
+	struct mhi_dev *mhi = dev_id;
+
+	disable_irq_nosync(mhi->mhi_irq);
+	schedule_work(&mhi->chdb_ctrl_work);
+	mhi_log(MHI_MSG_VERBOSE, "mhi irq triggered\n");
+
+	return IRQ_HANDLED;
+}
+
 int mhi_dev_config_outbound_iatu(struct mhi_dev *mhi)
 {
+	struct ep_pcie_iatu control, data;
+	int rc = 0;
+	struct ep_pcie_iatu entries[MHI_HOST_REGION_NUM];
+
+	data.start = mhi->data_base.device_pa;
+	data.end = mhi->data_base.device_pa + mhi->data_base.size - 1;
+	data.tgt_lower = HOST_ADDR_LSB(mhi->data_base.host_pa);
+	data.tgt_upper = HOST_ADDR_MSB(mhi->data_base.host_pa);
+
+	control.start = mhi->ctrl_base.device_pa;
+	control.end = mhi->ctrl_base.device_pa + mhi->ctrl_base.size - 1;
+	control.tgt_lower = HOST_ADDR_LSB(mhi->ctrl_base.host_pa);
+	control.tgt_upper = HOST_ADDR_MSB(mhi->ctrl_base.host_pa);
+
+	entries[0] = data;
+	entries[1] = control;
+
+	rc = ep_pcie_config_outbound_iatu(mhi_ctx->phandle, entries,
+					MHI_HOST_REGION_NUM);
+	if (rc) {
+		pr_err("error configure iATU\n");
+		return rc;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(mhi_dev_config_outbound_iatu);
@@ -996,6 +1564,7 @@
 	int rc = 0;
 	struct platform_device *pdev;
 	uint64_t addr1 = 0;
+	struct mhi_addr data_transfer;
 
 	pdev = mhi->pdev;
 
@@ -1014,6 +1583,37 @@
 					mhi->host_addr.data_limit_msb);
 	mhi->data_base.size = addr1 - mhi->data_base.host_pa;
 
+	if (mhi->config_iatu) {
+		if (mhi->ctrl_base.host_pa > mhi->data_base.host_pa) {
+			mhi->data_base.device_pa = mhi->device_local_pa_base;
+			mhi->ctrl_base.device_pa = mhi->device_local_pa_base +
+				mhi->ctrl_base.host_pa - mhi->data_base.host_pa;
+		} else {
+			mhi->ctrl_base.device_pa = mhi->device_local_pa_base;
+			mhi->data_base.device_pa = mhi->device_local_pa_base +
+				mhi->data_base.host_pa - mhi->ctrl_base.host_pa;
+		}
+
+		if (!mhi->use_ipa) {
+			mhi->ctrl_base.device_va =
+				(uintptr_t) devm_ioremap_nocache(&pdev->dev,
+				mhi->ctrl_base.device_pa,
+				mhi->ctrl_base.size);
+			if (!mhi->ctrl_base.device_va) {
+				pr_err("io remap failed for mhi address\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	if (mhi->config_iatu) {
+		rc = mhi_dev_config_outbound_iatu(mhi);
+		if (rc) {
+			pr_err("Configuring iATU failed\n");
+			return rc;
+		}
+	}
+
 	/* Get Channel, event and command context base pointer */
 	rc = mhi_dev_mmio_get_chc_base(mhi);
 	if (rc) {
@@ -1062,30 +1662,44 @@
 				GFP_KERNEL);
 	if (!mhi->ev_ctx_cache)
 		return -ENOMEM;
+	memset(mhi->ev_ctx_cache, 0, sizeof(struct mhi_dev_ev_ctx) *
+						mhi->cfg.event_rings);
 
 	mhi->ch_ctx_cache = dma_alloc_coherent(&pdev->dev,
 				sizeof(struct mhi_dev_ch_ctx) *
 				mhi->cfg.channels,
 				&mhi->ch_ctx_cache_dma_handle,
 				GFP_KERNEL);
-	if (!mhi_ctx->ch_ctx_cache)
+	if (!mhi->ch_ctx_cache)
 		return -ENOMEM;
+	memset(mhi->ch_ctx_cache, 0, sizeof(struct mhi_dev_ch_ctx) *
+						mhi->cfg.channels);
+
+	if (mhi->use_ipa) {
+		data_transfer.phy_addr = mhi->cmd_ctx_cache_dma_handle;
+		data_transfer.host_pa = mhi->cmd_ctx_shadow.host_pa;
+	}
+
+	data_transfer.size = mhi->cmd_ctx_shadow.size;
 
 	/* Cache the command and event context */
-	mhi_dev_read_from_host(&mhi->cmd_ctx_shadow,
-				mhi->cmd_ctx_cache_dma_handle,
-				mhi->cmd_ctx_shadow.size);
+	mhi_dev_read_from_host(mhi, &data_transfer);
 
-	mhi_dev_read_from_host(&mhi->ev_ctx_shadow,
-				mhi->ev_ctx_cache_dma_handle,
-				mhi->ev_ctx_shadow.size);
+	if (mhi->use_ipa) {
+		data_transfer.phy_addr = mhi->ev_ctx_cache_dma_handle;
+		data_transfer.host_pa = mhi->ev_ctx_shadow.host_pa;
+	}
 
-	mhi_log(MHI_MSG_ERROR,
+	data_transfer.size = mhi->ev_ctx_shadow.size;
+
+	mhi_dev_read_from_host(mhi, &data_transfer);
+
+	mhi_log(MHI_MSG_VERBOSE,
 			"cmd ring_base:0x%llx, rp:0x%llx, wp:0x%llx\n",
 					mhi->cmd_ctx_cache->rbase,
 					mhi->cmd_ctx_cache->rp,
 					mhi->cmd_ctx_cache->wp);
-	mhi_log(MHI_MSG_ERROR,
+	mhi_log(MHI_MSG_VERBOSE,
 			"ev ring_base:0x%llx, rp:0x%llx, wp:0x%llx\n",
 					mhi_ctx->ev_ctx_cache->rbase,
 					mhi->ev_ctx_cache->rp,
@@ -1104,7 +1718,7 @@
 int mhi_dev_suspend(struct mhi_dev *mhi)
 {
 	int ch_id = 0, rc = 0;
-	struct mhi_addr host_addr;
+	struct mhi_addr data_transfer;
 
 	mutex_lock(&mhi_ctx->mhi_write_test);
 	atomic_set(&mhi->is_suspended, 1);
@@ -1116,19 +1730,28 @@
 
 		mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_SUSPENDED;
 
-		host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+		if (mhi->use_ipa) {
+			data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
 				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+		} else {
+			data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+			data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+		}
+
+		data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+		data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
 
 		/* update the channel state in the host */
-		mhi_dev_write_to_host(&host_addr,
-			&mhi->ch_ctx_cache[ch_id].ch_state,
-			sizeof(enum mhi_dev_ch_ctx_state), mhi);
+		mhi_dev_write_to_host(mhi, &data_transfer, NULL,
+				MHI_DEV_DMA_SYNC);
 
 	}
 
-	rc = ipa_dma_disable();
-	if (rc)
-		pr_err("Disable IPA failed\n");
+	atomic_set(&mhi->mhi_dev_wake, 0);
+	pm_relax(mhi->dev);
+	mhi_log(MHI_MSG_VERBOSE, "releasing mhi wakelock\n");
 
 	mutex_unlock(&mhi_ctx->mhi_write_test);
 
@@ -1139,13 +1762,7 @@
 int mhi_dev_resume(struct mhi_dev *mhi)
 {
 	int ch_id = 0, rc = 0;
-	struct mhi_addr host_addr;
-
-	rc = ipa_dma_enable();
-	if (rc) {
-		pr_err("IPA enable failed\n");
-		return rc;
-	}
+	struct mhi_addr data_transfer;
 
 	for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) {
 		if (mhi->ch_ctx_cache[ch_id].ch_state !=
@@ -1153,14 +1770,24 @@
 			continue;
 
 		mhi->ch_ctx_cache[ch_id].ch_state = MHI_DEV_CH_STATE_RUNNING;
-		host_addr.host_pa = mhi->ch_ctx_shadow.host_pa +
+		if (mhi->use_ipa) {
+			data_transfer.host_pa = mhi->ch_ctx_shadow.host_pa +
 				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+		} else {
+			data_transfer.device_va = mhi->ch_ctx_shadow.device_va +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+			data_transfer.device_pa = mhi->ch_ctx_shadow.device_pa +
+				sizeof(struct mhi_dev_ch_ctx) * ch_id;
+		}
+
+		data_transfer.size = sizeof(enum mhi_dev_ch_ctx_state);
+		data_transfer.virt_addr = &mhi->ch_ctx_cache[ch_id].ch_state;
 
 		/* update the channel state in the host */
-		mhi_dev_write_to_host(&host_addr,
-				&mhi->ch_ctx_cache[ch_id].ch_state,
-				sizeof(enum mhi_dev_ch_ctx_state), mhi);
+		mhi_dev_write_to_host(mhi, &data_transfer, NULL,
+				MHI_DEV_DMA_SYNC);
 	}
+	mhi_update_state_info(MHI_STATE_CONNECTED);
 
 	atomic_set(&mhi->is_suspended, 0);
 
@@ -1312,14 +1939,14 @@
 				mhi_dev_send_completion_event(ch,
 					ring->rd_offset, el->tre.len,
 					MHI_CMD_COMPL_CODE_EOB);
-				*chain = 1;
+			*chain = 1;
 		} else {
 			if (el->tre.ieot)
 				mhi_dev_send_completion_event(
 					ch, ring->rd_offset, el->tre.len,
 					MHI_CMD_COMPL_CODE_EOT);
-				td_done = 1;
-				*chain = 0;
+			td_done = 1;
+			*chain = 0;
 		}
 		mhi_dev_ring_inc_index(ring, ring->rd_offset);
 		ch->tre_bytes_left = 0;
@@ -1329,53 +1956,67 @@
 	return td_done;
 }
 
-int mhi_dev_read_channel(struct mhi_dev_client *handle_client,
-				void *buf, uint32_t buf_size, uint32_t *chain)
+int mhi_dev_read_channel(struct mhi_req *mreq)
 {
 	struct mhi_dev_channel *ch;
 	struct mhi_dev_ring *ring;
 	union mhi_dev_ring_element_type *el;
-	uint32_t ch_id;
 	size_t bytes_to_read, addr_offset;
 	uint64_t read_from_loc;
 	ssize_t bytes_read = 0;
 	uint32_t write_to_loc = 0;
-	size_t usr_buf_remaining = buf_size;
+	size_t usr_buf_remaining;
 	int td_done = 0, rc = 0;
+	struct mhi_dev_client *handle_client;
 
-	if (!handle_client) {
-		mhi_log(MHI_MSG_ERROR, "invalid client handle\n");
+	if (!mreq) {
+		mhi_log(MHI_MSG_ERROR, "invalid mhi request\n");
 		return -ENXIO;
 	}
 
+	if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) {
+		pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info);
+		return -ENODEV;
+	}
+
+	if (!mreq->client) {
+		mhi_log(MHI_MSG_ERROR, "invalid mhi request\n");
+		return -ENXIO;
+	}
+	handle_client = mreq->client;
 	ch = handle_client->channel;
+	usr_buf_remaining = mreq->len;
 	ring = ch->ring;
-	ch_id = ch->ch_id;
-	*chain = 0;
+	mreq->chain = 0;
 
 	mutex_lock(&ch->ch_lock);
 
 	do {
 		el = &ring->ring_cache[ring->rd_offset];
+		mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n",
+						el->tre.data_buf_ptr);
+		mhi_log(MHI_MSG_VERBOSE, "evntlen : 0x%x, offset:%d\n",
+						el->tre.len, ring->rd_offset);
+
 		if (ch->tre_loc) {
 			bytes_to_read = min(usr_buf_remaining,
 						ch->tre_bytes_left);
-			*chain = 1;
-			mhi_log(MHI_MSG_ERROR,
+			mreq->chain = 1;
+			mhi_log(MHI_MSG_VERBOSE,
 				"remaining buffered data size %d\n",
 				(int) ch->tre_bytes_left);
 		} else {
 			if (ring->rd_offset == ring->wr_offset) {
-				mhi_log(MHI_MSG_ERROR,
+				mhi_log(MHI_MSG_VERBOSE,
 					"nothing to read, returning\n");
 				bytes_read = 0;
 				goto exit;
 			}
 
 			if (ch->state == MHI_DEV_CH_STOPPED) {
-				mhi_log(MHI_MSG_ERROR,
+				mhi_log(MHI_MSG_VERBOSE,
 					"channel (%d) already stopped\n",
-					ch_id);
+					mreq->chan);
 				bytes_read = -1;
 				goto exit;
 			}
@@ -1384,35 +2025,51 @@
 			ch->tre_size = el->tre.len;
 			ch->tre_bytes_left = ch->tre_size;
 
-			mhi_log(MHI_MSG_ERROR,
+			mhi_log(MHI_MSG_VERBOSE,
 			"user_buf_remaining %d, ch->tre_size %d\n",
 			usr_buf_remaining, ch->tre_size);
 			bytes_to_read = min(usr_buf_remaining, ch->tre_size);
 		}
 
+		bytes_read += bytes_to_read;
 		addr_offset = ch->tre_size - ch->tre_bytes_left;
 		read_from_loc = ch->tre_loc + addr_offset;
-		write_to_loc = (uint32_t) buf + (buf_size - usr_buf_remaining);
-
-		mhi_log(MHI_MSG_ERROR, "reading %d bytes from chan %d\n",
-				bytes_to_read, ch_id);
-
-		mhi_transfer_host_to_device((void *) write_to_loc,
-			read_from_loc, bytes_to_read, mhi_ctx);
-
-		bytes_read += bytes_to_read;
+		write_to_loc = (uint32_t) mreq->buf +
+			(mreq->len - usr_buf_remaining);
 		ch->tre_bytes_left -= bytes_to_read;
-		usr_buf_remaining -= bytes_to_read;
-		td_done = mhi_dev_check_tre_bytes_left(ch, ring, el, chain);
-	} while (usr_buf_remaining  && !td_done);
-
-	if (td_done && ch->state == MHI_DEV_CH_PENDING_STOP) {
-		ch->state = MHI_DEV_CH_STOPPED;
-		rc = mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx);
+		mreq->el = el;
+		mreq->actual_len = bytes_read;
+		mreq->rd_offset = ring->rd_offset;
+		mhi_log(MHI_MSG_VERBOSE, "reading %d bytes from chan %d\n",
+				bytes_to_read, mreq->chan);
+		rc = mhi_transfer_host_to_device((void *) write_to_loc,
+				read_from_loc, bytes_to_read, mhi_ctx, mreq);
 		if (rc) {
 			mhi_log(MHI_MSG_ERROR,
-				"Error while stopping channel (%d)\n", ch_id);
-			bytes_read = -1;
+					"Error while reading chan (%d) rc %d\n",
+					mreq->chan, rc);
+			mutex_unlock(&ch->ch_lock);
+			return rc;
+		}
+		usr_buf_remaining -= bytes_to_read;
+
+		if (mreq->mode == IPA_DMA_ASYNC) {
+			ch->tre_bytes_left = 0;
+			ch->tre_loc = 0;
+			goto exit;
+		} else {
+			td_done = mhi_dev_check_tre_bytes_left(ch, ring,
+					el, &mreq->chain);
+		}
+	} while (usr_buf_remaining  && !td_done);
+	if (td_done && ch->state == MHI_DEV_CH_PENDING_STOP) {
+		ch->state = MHI_DEV_CH_STOPPED;
+		rc = mhi_dev_process_stop_cmd(ring, mreq->chan, mhi_ctx);
+		if (rc) {
+			mhi_log(MHI_MSG_ERROR,
+					"Error while stopping channel (%d)\n",
+					mreq->chan);
+			bytes_read = -EIO;
 		}
 	}
 exit:
@@ -1441,32 +2098,33 @@
 	}
 }
 
-int mhi_dev_write_channel(struct mhi_dev_client *handle_client,
-						void *buf, size_t buf_size)
+int mhi_dev_write_channel(struct mhi_req *wreq)
 {
 	struct mhi_dev_channel *ch;
 	struct mhi_dev_ring *ring;
+	struct mhi_dev_client *handle_client;
 	union mhi_dev_ring_element_type *el;
 	enum mhi_dev_cmd_completion_code code = MHI_CMD_COMPL_CODE_INVALID;
 	int rc = 0;
-	uint64_t ch_id, skip_tres = 0, write_to_loc;
+	uint64_t skip_tres = 0, write_to_loc;
 	uint32_t read_from_loc;
-	size_t usr_buf_remaining = buf_size;
+	size_t usr_buf_remaining;
 	size_t usr_buf_offset = 0;
 	size_t bytes_to_write = 0;
 	size_t bytes_written = 0;
 	uint32_t tre_len = 0, suspend_wait_timeout = 0;
 
-	if (!handle_client) {
-		pr_err("%s: invalid client handle\n", __func__);
+	if (!wreq || !wreq->client || !wreq->buf) {
+		pr_err("%s: invalid parameters\n", __func__);
 		return -ENXIO;
 	}
 
-	if (!buf) {
-		pr_err("%s: invalid buffer to write data\n", __func__);
-		return -ENXIO;
+	if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) {
+		pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info);
+		return -ENODEV;
 	}
 
+	usr_buf_remaining =  wreq->len;
 	mutex_lock(&mhi_ctx->mhi_write_test);
 
 	if (atomic_read(&mhi_ctx->is_suspended)) {
@@ -1482,31 +2140,29 @@
 		}
 	}
 
-	atomic_inc(&mhi_ctx->write_active);
 	while (atomic_read(&mhi_ctx->is_suspended) &&
-			suspend_wait_timeout < MHI_SUSPEND_WAIT_TIMEOUT) {
+			suspend_wait_timeout < MHI_SUSPEND_TIMEOUT) {
 		/* wait for the suspend to finish */
-		usleep_range(MHI_SUSPEND_WAIT_MIN, MHI_SUSPEND_WAIT_MAX);
+		msleep(MHI_SUSPEND_MIN);
 		suspend_wait_timeout++;
 	}
-
+	handle_client = wreq->client;
 	ch = handle_client->channel;
 	ch->wr_request_active = true;
 
 	ring = ch->ring;
-	ch_id = ch->ch_id;
 
 	mutex_lock(&ch->ch_lock);
 
 	if (ch->state == MHI_DEV_CH_STOPPED) {
 		mhi_log(MHI_MSG_ERROR,
-			"channel (%lld) already stopped\n", ch_id);
+			"channel %d already stopped\n", wreq->chan);
 		bytes_written = -1;
 		goto exit;
 	}
 
 	if (ch->state == MHI_DEV_CH_PENDING_STOP) {
-		if (mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx) < 0)
+		if (mhi_dev_process_stop_cmd(ring, wreq->chan, mhi_ctx) < 0)
 			bytes_written = -1;
 		goto exit;
 	}
@@ -1516,20 +2172,38 @@
 
 	do {
 		if (ring->rd_offset == ring->wr_offset) {
+			mhi_log(MHI_MSG_ERROR,
+					"%s():rd & wr offsets are equal\n",
+					__func__);
 			mhi_log(MHI_MSG_INFO, "No TREs available\n");
 			break;
 		}
 
 		el = &ring->ring_cache[ring->rd_offset];
 		tre_len = el->tre.len;
+		if (wreq->len > tre_len) {
+			pr_err("%s(): rlen = %d, tlen = %d: client buf > tre len\n",
+					__func__, wreq->len, tre_len);
+			bytes_written = -ENOMEM;
+			goto exit;
+		}
 
 		bytes_to_write = min(usr_buf_remaining, tre_len);
-		usr_buf_offset = buf_size - bytes_to_write;
-		read_from_loc = (uint32_t) buf + usr_buf_offset;
+		usr_buf_offset = wreq->len - bytes_to_write;
+		read_from_loc = (uint32_t) wreq->buf + usr_buf_offset;
 		write_to_loc = el->tre.data_buf_ptr;
-		mhi_transfer_device_to_host(write_to_loc,
+		wreq->rd_offset = ring->rd_offset;
+		wreq->el = el;
+		rc = mhi_transfer_device_to_host(write_to_loc,
 						(void *) read_from_loc,
-						bytes_to_write, mhi_ctx);
+						bytes_to_write,
+						mhi_ctx, wreq);
+		if (rc) {
+			mhi_log(MHI_MSG_ERROR,
+					"Error while writing chan (%d) rc %d\n",
+					wreq->chan, rc);
+			goto exit;
+		}
 		bytes_written += bytes_to_write;
 		usr_buf_remaining -= bytes_to_write;
 
@@ -1543,33 +2217,34 @@
 				skip_tres = 1;
 			code = MHI_CMD_COMPL_CODE_EOT;
 		}
-
-		if (mhi_dev_send_completion_event(ch,
-				ring->rd_offset, bytes_to_write, code) < 0) {
-			mhi_log(MHI_MSG_ERROR,
-				"error sending completion event ch_id:%lld\n",
-				ch_id);
+		if (wreq->mode == IPA_DMA_SYNC) {
+			rc = mhi_dev_send_completion_event(ch,
+					ring->rd_offset, bytes_to_write, code);
+			if (rc)
+				mhi_log(MHI_MSG_VERBOSE,
+						"err in snding cmpl evt ch:%d\n",
+						wreq->chan);
+			 mhi_dev_ring_inc_index(ring, ring->rd_offset);
 		}
 
 		if (ch->state == MHI_DEV_CH_PENDING_STOP)
 			break;
 
-		mhi_dev_ring_inc_index(ring, ring->rd_offset);
 	} while (!skip_tres && usr_buf_remaining);
 
 	if (skip_tres)
 		skip_to_next_td(ch);
 
 	if (ch->state == MHI_DEV_CH_PENDING_STOP) {
-		rc = mhi_dev_process_stop_cmd(ring, ch_id, mhi_ctx);
+		rc = mhi_dev_process_stop_cmd(ring, wreq->chan, mhi_ctx);
 		if (rc) {
 			mhi_log(MHI_MSG_ERROR,
-				"channel (%lld) stop failed\n", ch_id);
+				"channel %d stop failed\n", wreq->chan);
 		}
 	}
 exit:
+	ch->wr_request_active = false;
 	mutex_unlock(&ch->ch_lock);
-	atomic_dec(&mhi_ctx->write_active);
 	mutex_unlock(&mhi_ctx->mhi_write_test);
 	return bytes_written;
 }
@@ -1581,21 +2256,22 @@
 	struct ep_pcie_msi_config msi_cfg;
 	struct mhi_dev *mhi = container_of(work,
 				struct mhi_dev, ring_init_cb_work);
-
+	bool mhi_reset;
 	enum mhi_dev_state state;
-	uint32_t max_cnt = 0;
+	uint32_t max_cnt = 0, bhi_intvec = 0;
 
+	if (mhi->use_ipa) {
+		rc = ipa_dma_init();
+		if (rc) {
+			pr_err("ipa dma init failed\n");
+			return;
+		}
 
-	rc = ipa_dma_init();
-	if (rc) {
-		pr_err("ipa dma init failed\n");
-		return;
-	}
-
-	rc = ipa_dma_enable();
-	if (rc) {
-		pr_err("ipa enable failed\n");
-		return;
+		rc = ipa_dma_enable();
+		if (rc) {
+			pr_err("ipa enable failed\n");
+			return;
+		}
 	}
 
 	rc = mhi_dev_ring_init(mhi);
@@ -1604,34 +2280,39 @@
 		return;
 	}
 
-	/* Invoke MHI SM when device is in RESET state */
-	mhi_dev_sm_init(mhi);
-
-	/* set the env before setting the ready bit */
-	rc = mhi_dev_mmio_set_env(mhi, MHI_ENV_VALUE);
-	if (rc) {
-		pr_err("%s: env setting failed\n", __func__);
-		return;
-	}
-	mhi_uci_init();
-
-	/* All set...let's notify the host */
-	mhi_dev_sm_set_ready();
-
-	rc = ep_pcie_get_msi_config(mhi->phandle, &msi_cfg);
+	/*Enable MHI dev network stack Interface*/
+	rc = mhi_dev_net_interface_init();
 	if (rc)
-		pr_warn("MHI: error geting msi configs\n");
+		pr_err("%s Failed to initialize mhi_dev_net iface\n", __func__);
 
-	rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+	rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec);
+	if (rc)
+		return;
+
+	if (bhi_intvec != 0xffffffff) {
+		/* Indicate the host that the device is ready */
+		rc = ep_pcie_get_msi_config(mhi->phandle, &msi_cfg);
+		if (!rc) {
+			rc = ep_pcie_trigger_msi(mhi_ctx->phandle, bhi_intvec);
+			if (rc) {
+				pr_err("%s: error sending msi\n", __func__);
+				return;
+			}
+		} else {
+			pr_err("MHI: error geting msi configs\n");
+		}
+	}
+
+	rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
 	if (rc) {
 		pr_err("%s: get mhi state failed\n", __func__);
 		return;
 	}
 
-	while (state != MHI_DEV_M0_STATE && max_cnt < MHI_DEV_M0_MAX_CNT) {
+	while (state != MHI_DEV_M0_STATE && max_cnt < MHI_SUSPEND_TIMEOUT) {
 		/* Wait for Host to set the M0 state */
-		usleep_range(MHI_M0_WAIT_MIN_USLEEP, MHI_M0_WAIT_MAX_USLEEP);
-		rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
+		msleep(MHI_SUSPEND_MIN);
+		rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
 		if (rc) {
 			pr_err("%s: get mhi state failed\n", __func__);
 			return;
@@ -1663,6 +2344,11 @@
 		pr_err("error during hwc_init\n");
 		return;
 	}
+
+	if (mhi_ctx->config_iatu || mhi_ctx->mhi_int)
+		enable_irq(mhi_ctx->mhi_irq);
+
+	mhi_update_state_info(MHI_STATE_CONNECTED);
 }
 
 static void mhi_ring_init_cb(void *data)
@@ -1677,6 +2363,78 @@
 	queue_work(mhi->ring_init_wq, &mhi->ring_init_cb_work);
 }
 
+int mhi_register_state_cb(void (*mhi_state_cb)
+				(struct mhi_dev_client_cb_data *cb_data),
+				void *data, enum mhi_client_channel channel)
+{
+	struct mhi_dev_ready_cb_info *cb_info = NULL;
+
+	if (!mhi_ctx) {
+		pr_err("MHI device not ready\n");
+		return -ENXIO;
+	}
+
+	if (channel > MHI_MAX_CHANNELS) {
+		pr_err("Invalid channel :%d\n", channel);
+		return -EINVAL;
+	}
+
+	mutex_lock(&mhi_ctx->mhi_lock);
+	cb_info = kmalloc(sizeof(struct mhi_dev_ready_cb_info), GFP_KERNEL);
+	if (!cb_info) {
+		mutex_unlock(&mhi_ctx->mhi_lock);
+		return -ENOMEM;
+	}
+
+	cb_info->cb = mhi_state_cb;
+	cb_info->cb_data.user_data = data;
+	cb_info->cb_data.channel = channel;
+
+	list_add_tail(&cb_info->list, &mhi_ctx->client_cb_list);
+
+	/**
+	 * If channel is open during registration, no callback is issued.
+	 * Instead return -EEXIST to notify the client. Clients request
+	 * is added to the list to notify future state change notification.
+	 */
+	if (mhi_ctx->ch[channel].state == MHI_DEV_CH_STARTED) {
+		mutex_unlock(&mhi_ctx->mhi_lock);
+		return -EEXIST;
+	}
+
+	mutex_unlock(&mhi_ctx->mhi_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(mhi_register_state_cb);
+
+static void mhi_update_state_info(uint32_t info)
+{
+	struct mhi_dev_client_cb_reason reason;
+
+	mhi_ctx->ctrl_info = info;
+
+	if (info == MHI_STATE_CONNECTED)
+		return;
+
+	reason.reason = MHI_DEV_CTRL_UPDATE;
+	uci_ctrl_update(&reason);
+}
+
+int mhi_ctrl_state_info(uint32_t *info)
+{
+	if (!info) {
+		pr_err("Invalid info\n");
+		return -EINVAL;
+	}
+
+	*info = mhi_ctx->ctrl_info;
+	mhi_log(MHI_MSG_VERBOSE, "ctrl:%d", mhi_ctx->ctrl_info);
+
+	return 0;
+}
+EXPORT_SYMBOL(mhi_ctrl_state_info);
+
 static int get_device_tree_data(struct platform_device *pdev)
 {
 	struct mhi_dev *mhi;
@@ -1725,13 +2483,11 @@
 	}
 
 	mhi->ipa_uc_mbox_erdb = res_mem->start;
-
 	mhi_ctx = mhi;
 
 	rc = of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,mhi-ifc-id",
 				&mhi_ctx->ifc_id);
-
 	if (rc) {
 		pr_err("qcom,mhi-ifc-id does not exist.\n");
 		return rc;
@@ -1753,22 +2509,90 @@
 		return rc;
 	}
 
+	mhi_ctx->use_ipa = of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-ipa-software-channel");
+
+	mhi_ctx->config_iatu = of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,mhi-config-iatu");
+
+	if (mhi_ctx->config_iatu) {
+		rc = of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,mhi-local-pa-base",
+				&mhi_ctx->device_local_pa_base);
+		if (rc) {
+			pr_err("qcom,mhi-local-pa-base does not exist\n");
+			return rc;
+		}
+	}
+
+	mhi_ctx->mhi_int = of_property_read_bool((&pdev->dev)->of_node,
+					"qcom,mhi-interrupt");
+
+	if (mhi->config_iatu || mhi_ctx->mhi_int) {
+		mhi->mhi_irq = platform_get_irq_byname(pdev, "mhi-device-inta");
+		if (mhi->mhi_irq < 0) {
+			pr_err("Invalid MHI device interrupt\n");
+			rc = mhi->mhi_irq;
+			return rc;
+		}
+	}
+
+	device_init_wakeup(mhi->dev, true);
+	/* MHI device will be woken up from PCIe event */
+	device_set_wakeup_capable(mhi->dev, false);
+	/* Hold a wakelock until completion of M0 */
+	pm_stay_awake(mhi->dev);
+	atomic_set(&mhi->mhi_dev_wake, 1);
+
+	mhi_log(MHI_MSG_VERBOSE, "acquiring wakelock\n");
+
 	return 0;
 }
 
+static int mhi_deinit(struct mhi_dev *mhi)
+{
+	int rc = 0, i = 0, ring_id = 0;
+	struct mhi_dev_ring *ring;
+	struct platform_device *pdev = mhi->pdev;
+
+	ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1;
+
+	for (i = 0; i < ring_id; i++) {
+		ring = &mhi->ring[i];
+		if (ring->state == RING_STATE_UINT)
+			continue;
+
+		dma_free_coherent(mhi->dev, ring->ring_size *
+			sizeof(union mhi_dev_ring_element_type),
+			ring->ring_cache,
+			ring->ring_cache_dma_handle);
+	}
+
+	for (i = 0; i < mhi->cfg.channels; i++)
+		mutex_destroy(&mhi->ch[i].ch_lock);
+
+	devm_kfree(&pdev->dev, mhi->mmio_backup);
+	devm_kfree(&pdev->dev, mhi->ch);
+	devm_kfree(&pdev->dev, mhi->ring);
+
+	mhi_dev_sm_exit(mhi);
+
+	mhi->mmio_initialized = false;
+
+	return rc;
+}
+
 static int mhi_init(struct mhi_dev *mhi)
 {
 	int rc = 0, i = 0;
 	struct platform_device *pdev = mhi->pdev;
 
-
 	rc = mhi_dev_mmio_init(mhi);
 	if (rc) {
 		pr_err("Failed to update the MMIO init\n");
 		return rc;
 	}
 
-
 	mhi->ring = devm_kzalloc(&pdev->dev,
 			(sizeof(struct mhi_dev_ring) *
 			(mhi->cfg.channels + mhi->cfg.event_rings + 1)),
@@ -1782,46 +2606,148 @@
 	if (!mhi->ch)
 		return -ENOMEM;
 
-	for (i = 0; i < mhi->cfg.channels; i++)
-		mutex_init(&mhi->ch[i].ch_lock);
 
-	mhi->mmio_backup = devm_kzalloc(&pdev->dev, MHI_DEV_MMIO_RANGE,
-								GFP_KERNEL);
+	for (i = 0; i < mhi->cfg.channels; i++) {
+		mutex_init(&mhi->ch[i].ch_lock);
+		if (i == MHI_CLIENT_IP_SW_4_OUT || i == MHI_CLIENT_IP_SW_4_IN) {
+			int nreq = 0;
+
+			INIT_LIST_HEAD(&mhi->ch[i].event_req_buffers);
+			while (nreq < MHI_MAX_EVT_REQ) {
+				struct event_req *ereq;
+				/* Pre allocate event requests */
+				ereq = kzalloc(sizeof(struct event_req),
+						GFP_KERNEL);
+				if (!ereq)
+					return -ENOMEM;
+
+				/* pre allocate buffers to queue
+				 * transfer completion events
+				 */
+				ereq->tr_events = kzalloc(RING_ELEMENT_TYPE_SZ*
+						MAX_TR_EVENTS, GFP_KERNEL);
+				if (!ereq->tr_events) {
+					kfree(ereq);
+					return -ENOMEM;
+				}
+				list_add_tail(&ereq->list,
+						&mhi->ch[i].event_req_buffers);
+				nreq++;
+			}
+			mhi->ch[i].curr_ereq =
+				container_of(mhi->ch[i].event_req_buffers.next,
+						struct event_req, list);
+			list_del_init(&mhi->ch[i].curr_ereq->list);
+		}
+	}
+
+	spin_lock_init(&mhi->lock);
+	mhi->mmio_backup = devm_kzalloc(&pdev->dev,
+			MHI_DEV_MMIO_RANGE, GFP_KERNEL);
 	if (!mhi->mmio_backup)
 		return -ENOMEM;
 
-	mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0);
-	if (mhi_ipc_log == NULL) {
-		dev_err(&pdev->dev,
-				"Failed to create IPC logging context\n");
-	}
-
 	return 0;
 }
 
-static int mhi_dev_probe(struct platform_device *pdev)
+static int mhi_dev_resume_mmio_mhi_reinit(struct mhi_dev *mhi_ctx)
 {
 	int rc = 0;
 
-	if (pdev->dev.of_node) {
-		rc = get_device_tree_data(pdev);
-		if (rc) {
-			pr_err("Error reading MHI Dev DT\n");
-			return rc;
+	mutex_lock(&mhi_ctx->mhi_lock);
+	if (atomic_read(&mhi_ctx->re_init_done)) {
+		mhi_log(MHI_MSG_INFO, "Re_init done, return\n");
+		mutex_unlock(&mhi_ctx->mhi_lock);
+		return 0;
+	}
+
+	rc = mhi_init(mhi_ctx);
+	if (rc) {
+		pr_err("Error initializing MHI MMIO with %d\n", rc);
+		goto fail;
+	}
+
+	mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
+		EP_PCIE_EVENT_PM_D3_COLD |
+		EP_PCIE_EVENT_PM_D0 |
+		EP_PCIE_EVENT_PM_RST_DEAST |
+		EP_PCIE_EVENT_MHI_A7 |
+		EP_PCIE_EVENT_LINKDOWN;
+	mhi_ctx->event_reg.user = mhi_ctx;
+	mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+	mhi_ctx->event_reg.callback = mhi_dev_sm_pcie_handler;
+
+	rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg);
+	if (rc) {
+		pr_err("Failed to register for events from PCIe\n");
+		goto fail;
+	}
+
+	rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx);
+	if (rc < 0) {
+		if (rc == -EEXIST) {
+			mhi_ring_init_cb(mhi_ctx);
+		} else {
+			pr_err("Error calling IPA cb with %d\n", rc);
+			goto fail;
 		}
 	}
 
-	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
-	if (!mhi_ctx->phandle) {
-		pr_err("PCIe driver is not ready yet.\n");
-		return -EPROBE_DEFER;
+	/* Invoke MHI SM when device is in RESET state */
+	rc = mhi_dev_sm_init(mhi_ctx);
+	if (rc) {
+		pr_err("%s: Error during SM init\n", __func__);
+		goto fail;
 	}
 
-	if (ep_pcie_get_linkstatus(mhi_ctx->phandle) != EP_PCIE_LINK_ENABLED) {
-		pr_err("PCIe link is not ready to use.\n");
-		return -EPROBE_DEFER;
+	/* set the env before setting the ready bit */
+	rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE);
+	if (rc) {
+		pr_err("%s: env setting failed\n", __func__);
+		goto fail;
 	}
 
+	/* All set, notify the host */
+	rc = mhi_dev_sm_set_ready();
+	if (rc) {
+		pr_err("%s: unable to set ready bit\n", __func__);
+		goto fail;
+	}
+
+	atomic_set(&mhi_ctx->is_suspended, 0);
+fail:
+	atomic_set(&mhi_ctx->re_init_done, 1);
+	mutex_unlock(&mhi_ctx->mhi_lock);
+	return rc;
+}
+
+static void mhi_dev_reinit(struct work_struct *work)
+{
+	struct mhi_dev *mhi_ctx = container_of(work,
+				struct mhi_dev, re_init);
+	enum ep_pcie_link_status link_state;
+	int rc = 0;
+
+	link_state = ep_pcie_get_linkstatus(mhi_ctx->phandle);
+	if (link_state == EP_PCIE_LINK_ENABLED) {
+		/* PCIe link is up with BME set */
+		rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx);
+		if (rc) {
+			pr_err("Failed to register for events from PCIe\n");
+			return;
+		}
+	}
+
+	mhi_log(MHI_MSG_VERBOSE, "Wait for PCIe linkup\n");
+}
+
+static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx)
+{
+	struct platform_device *pdev;
+	int rc = 0;
+
+	pdev = mhi_ctx->pdev;
+
 	INIT_WORK(&mhi_ctx->chdb_ctrl_work, mhi_dev_scheduler);
 
 	mhi_ctx->pending_ring_wq = alloc_workqueue("mhi_pending_wq",
@@ -1835,6 +2761,8 @@
 
 	INIT_WORK(&mhi_ctx->ring_init_cb_work, mhi_dev_enable);
 
+	INIT_WORK(&mhi_ctx->re_init, mhi_dev_reinit);
+
 	mhi_ctx->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq",
 							WQ_HIGHPRI, 0);
 	if (!mhi_ctx->ring_init_wq) {
@@ -1844,6 +2772,7 @@
 
 	INIT_LIST_HEAD(&mhi_ctx->event_ring_list);
 	INIT_LIST_HEAD(&mhi_ctx->process_ring_list);
+	INIT_LIST_HEAD(&mhi_ctx->client_cb_list);
 	mutex_init(&mhi_ctx->mhi_lock);
 	mutex_init(&mhi_ctx->mhi_event_lock);
 	mutex_init(&mhi_ctx->mhi_write_test);
@@ -1878,6 +2807,12 @@
 		return rc;
 	}
 
+	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
+	if (!mhi_ctx->phandle) {
+		pr_err("PCIe driver get handle failed.\n");
+		return -EINVAL;
+	}
+
 	mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
 		EP_PCIE_EVENT_PM_D3_COLD |
 		EP_PCIE_EVENT_PM_D0 |
@@ -1906,6 +2841,125 @@
 		}
 	}
 
+	/* Invoke MHI SM when device is in RESET state */
+	rc = mhi_dev_sm_init(mhi_ctx);
+	if (rc) {
+		pr_err("%s: Error during SM init\n", __func__);
+		return rc;
+	}
+
+	/* set the env before setting the ready bit */
+	rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE);
+	if (rc) {
+		pr_err("%s: env setting failed\n", __func__);
+		return rc;
+	}
+
+	/* All set, notify the host */
+	mhi_dev_sm_set_ready();
+
+	if (mhi_ctx->config_iatu || mhi_ctx->mhi_int) {
+		rc = devm_request_irq(&pdev->dev, mhi_ctx->mhi_irq, mhi_dev_isr,
+			IRQF_TRIGGER_HIGH, "mhi_isr", mhi_ctx);
+		if (rc) {
+			dev_err(&pdev->dev, "request mhi irq failed %d\n", rc);
+			return -EINVAL;
+		}
+
+		disable_irq(mhi_ctx->mhi_irq);
+	}
+
+	return 0;
+}
+
+static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify)
+{
+	if (!notify || !notify->user) {
+		pr_err("Null argument for notify\n");
+		return;
+	}
+
+	mhi_ctx = notify->user;
+	mhi_dev_pcie_notify_event = notify->options;
+	mhi_log(MHI_MSG_INFO,
+			"PCIe event=0x%x\n", notify->options);
+	queue_work(mhi_ctx->pcie_event_wq, &mhi_ctx->pcie_event);
+}
+
+static void mhi_dev_pcie_handle_event(struct work_struct *work)
+{
+	struct mhi_dev *mhi_ctx = container_of(work, struct mhi_dev,
+								pcie_event);
+	int rc = 0;
+
+	if (mhi_dev_pcie_notify_event == MHI_INIT) {
+		rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx);
+		if (rc) {
+			pr_err("Error during MHI device initialization\n");
+			return;
+		}
+	} else if (mhi_dev_pcie_notify_event == MHI_REINIT) {
+		rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx);
+		if (rc) {
+			pr_err("Error during MHI device re-initialization\n");
+			return;
+		}
+	}
+}
+
+static int mhi_dev_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	if (pdev->dev.of_node) {
+		rc = get_device_tree_data(pdev);
+		if (rc) {
+			pr_err("Error reading MHI Dev DT\n");
+			return rc;
+		}
+		mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES,
+								"mhi", 0);
+		if (mhi_ipc_log == NULL) {
+			dev_err(&pdev->dev,
+				"Failed to create IPC logging context\n");
+		}
+		mhi_uci_init();
+		mhi_update_state_info(MHI_STATE_CONFIGURED);
+	}
+
+	INIT_WORK(&mhi_ctx->pcie_event, mhi_dev_pcie_handle_event);
+	mhi_ctx->pcie_event_wq = alloc_workqueue("mhi_dev_pcie_event_wq",
+							WQ_HIGHPRI, 0);
+	if (!mhi_ctx->pcie_event_wq) {
+		pr_err("no memory\n");
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
+	if (mhi_ctx->phandle) {
+		/* PCIe link is already up */
+		rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx);
+		if (rc) {
+			pr_err("Error during MHI device initialization\n");
+			return rc;
+		}
+	} else {
+		pr_debug("Register a PCIe callback\n");
+		mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP;
+		mhi_ctx->event_reg.user = mhi_ctx;
+		mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
+		mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up;
+		mhi_ctx->event_reg.options = MHI_INIT;
+
+		rc = ep_pcie_register_event(mhi_ctx->phandle,
+							&mhi_ctx->event_reg);
+		if (rc) {
+			pr_err("Failed to register for events from PCIe\n");
+			return rc;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h
index 1a73d92..38e52e2 100644
--- a/drivers/platform/msm/mhi_dev/mhi.h
+++ b/drivers/platform/msm/mhi_dev/mhi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -274,7 +274,15 @@
 #define HW_CHANNEL_END			107
 #define MHI_ENV_VALUE			2
 #define MHI_MASK_ROWS_CH_EV_DB		4
-#define TRB_MAX_DATA_SIZE		4096
+#define TRB_MAX_DATA_SIZE		8192
+#define MHI_CTRL_STATE			25
+#define IPA_DMA_SYNC                    1
+#define IPA_DMA_ASYNC                   0
+
+/*maximum trasnfer completion events buffer*/
+#define MAX_TR_EVENTS			50
+/*maximum event requests */
+#define MHI_MAX_EVT_REQ			50
 
 /* Possible ring element types */
 union mhi_dev_ring_element_type {
@@ -324,7 +332,10 @@
 	uint64_t	host_pa;
 	uintptr_t	device_pa;
 	uintptr_t	device_va;
-	uint32_t	size;
+	size_t		size;
+	dma_addr_t	phy_addr;
+	void		*virt_addr;
+	bool		use_ipa_dma;
 };
 
 struct mhi_interrupt_state {
@@ -349,6 +360,23 @@
 	MHI_DEV_POLL,
 };
 
+enum mhi_ctrl_info {
+	MHI_STATE_CONFIGURED = 0,
+	MHI_STATE_CONNECTED = 1,
+	MHI_STATE_DISCONNECTED = 2,
+	MHI_STATE_INVAL,
+};
+
+enum mhi_dev_tr_compl_evt_type {
+	SEND_EVENT_BUFFER,
+	SEND_EVENT_RD_OFFSET,
+};
+
+enum mhi_dev_transfer_type {
+	MHI_DEV_DMA_SYNC,
+	MHI_DEV_DMA_ASYNC,
+};
+
 struct mhi_dev_channel;
 
 struct mhi_dev_ring {
@@ -394,6 +422,7 @@
 
 enum cb_reason {
 	MHI_DEV_TRE_AVAILABLE = 0,
+	MHI_DEV_CTRL_UPDATE,
 };
 
 struct mhi_dev_client_cb_reason {
@@ -423,14 +452,30 @@
 	uint32_t			nr_iov;
 };
 
+struct ring_cache_req {
+	struct completion	*done;
+	void			*context;
+};
+
+struct event_req {
+	union mhi_dev_ring_element_type *tr_events;
+	u32			num_events;
+	dma_addr_t		dma;
+	u32			dma_len;
+	dma_addr_t		event_rd_dma;
+	void			*context;
+	enum mhi_dev_tr_compl_evt_type event_type;
+	u32			event_ring;
+	void			(*client_cb)(void *req);
+	struct list_head	list;
+};
+
 struct mhi_dev_channel {
 	struct list_head		list;
 	struct list_head		clients;
 	/* synchronization for changing channel state,
 	 * adding/removing clients, mhi_dev callbacks, etc
 	 */
-	spinlock_t			lock;
-
 	struct mhi_dev_ring		*ring;
 
 	enum mhi_dev_channel_state	state;
@@ -440,6 +485,9 @@
 	/* client which the current inbound/outbound message is for */
 	struct mhi_dev_client		*active_client;
 
+	struct list_head		event_req_buffers;
+	struct event_req		*curr_ereq;
+
 	/* current TRE being processed */
 	uint64_t			tre_loc;
 	/* current TRE size */
@@ -466,6 +514,7 @@
 	struct mhi_config		cfg;
 	bool				mmio_initialized;
 
+	spinlock_t			lock;
 	/* Host control base information */
 	struct mhi_host_addr		host_addr;
 	struct mhi_addr			ctrl_base;
@@ -481,6 +530,7 @@
 	struct mhi_dev_ch_ctx		*cmd_ctx_cache;
 	dma_addr_t			cmd_ctx_cache_dma_handle;
 	struct mhi_dev_ring		*ring;
+	int				mhi_irq;
 	struct mhi_dev_channel		*ch;
 
 	int				ctrl_int;
@@ -491,6 +541,7 @@
 
 	/* Scheduler work */
 	struct work_struct		chdb_ctrl_work;
+
 	struct mutex			mhi_lock;
 	struct mutex			mhi_event_lock;
 
@@ -509,15 +560,22 @@
 	u32				ipa_clnt_hndl[4];
 	struct workqueue_struct		*ring_init_wq;
 	struct work_struct		ring_init_cb_work;
+	struct work_struct		re_init;
 
 	/* EP PCIe registration */
+	struct workqueue_struct		*pcie_event_wq;
 	struct ep_pcie_register_event	event_reg;
 	u32                             ifc_id;
 	struct ep_pcie_hw               *phandle;
+	struct work_struct		pcie_event;
+	struct ep_pcie_msi_config	msi_cfg;
 
 	atomic_t			write_active;
 	atomic_t			is_suspended;
+	atomic_t			mhi_dev_wake;
+	atomic_t			re_init_done;
 	struct mutex			mhi_write_test;
+	u32				device_local_pa_base;
 	u32				mhi_ep_msi_num;
 	u32				mhi_version;
 	void				*dma_cache;
@@ -535,6 +593,37 @@
 	 * region from device used in mhi_write()
 	 */
 	dma_addr_t			write_dma_handle;
+
+	/* Use IPA DMA for Software channel data transfer */
+	bool				use_ipa;
+
+	/* iATU is required to map control and data region */
+	bool				config_iatu;
+
+	/* MHI state info */
+	enum mhi_ctrl_info		ctrl_info;
+
+	/*Register for interrupt */
+	bool				mhi_int;
+	/* Registered client callback list */
+	struct list_head		client_cb_list;
+};
+
+struct mhi_req {
+	u32                             chan;
+	u32                             mode;
+	u32				chain;
+	void                            *buf;
+	dma_addr_t                      dma;
+	u32                             snd_cmpl;
+	void                            *context;
+	size_t                          len;
+	size_t                          actual_len;
+	uint32_t                        rd_offset;
+	struct mhi_dev_client           *client;
+	struct list_head                list;
+	union mhi_dev_ring_element_type *el;
+	void (*client_cb)(void *req);
 };
 
 enum mhi_msg_level {
@@ -609,7 +698,9 @@
 	MHI_CLIENT_CSVT_IN = 43,
 	MHI_CLIENT_SMCT_OUT = 44,
 	MHI_CLIENT_SMCT_IN = 45,
-	MHI_MAX_SOFTWARE_CHANNELS = 46,
+	MHI_CLIENT_IP_SW_4_OUT  = 46,
+	MHI_CLIENT_IP_SW_4_IN  = 47,
+	MHI_MAX_SOFTWARE_CHANNELS = 48,
 	MHI_CLIENT_TEST_OUT = 60,
 	MHI_CLIENT_TEST_IN = 61,
 	MHI_CLIENT_RESERVED_1_LOWER = 62,
@@ -626,6 +717,20 @@
 	uint32_t	buf_size;
 };
 
+struct mhi_dev_client_cb_data {
+	void			*user_data;
+	enum mhi_client_channel	channel;
+	enum mhi_ctrl_info	ctrl_info;
+};
+
+typedef void (*mhi_state_cb)(struct mhi_dev_client_cb_data *cb_dat);
+
+struct mhi_dev_ready_cb_info {
+	struct list_head		list;
+	mhi_state_cb			cb;
+	struct mhi_dev_client_cb_data	cb_data;
+};
+
 /**
  * mhi_dev_open_channel() - Channel open for a given client done prior
  *		to read/write.
@@ -643,24 +748,21 @@
 
 /**
  * mhi_dev_read_channel() - Channel read for a given client
- * @handle_client:	Client Handle issued during mhi_dev_open_channel
- * @buf: Pointer to the buffer used by the MHI core to copy the data received
- *	 from the Host.
- * @buf_size: Size of the buffer pointer.
- * @chain : Indicate if the received data is part of chained packet.
+ * @mreq:       mreq is the client argument which includes meta info
+ *              like write data location, buffer len, read offset, mode,
+ *              chain and client call back function which will be invoked
+ *              when data read is completed.
  */
-int mhi_dev_read_channel(struct mhi_dev_client *handle_client,
-				void *buf, uint32_t buf_size, uint32_t *chain);
+int mhi_dev_read_channel(struct mhi_req *mreq);
 
 /**
  * mhi_dev_write_channel() - Channel write for a given software client.
- * @handle_client:	Client Handle issued during mhi_dev_open_channel
- * @buf: Pointer to the buffer used by the MHI core to copy the data from the
- *	 device to the host.
- * @buf_size: Size of the buffer pointer.
+ * @wreq	wreq is the client argument which includes meta info like
+ *              client handle, read data location, buffer length, mode,
+ *              and client call back function which will free the packet.
+ *              when data write is completed.
  */
-int mhi_dev_write_channel(struct mhi_dev_client *handle_client, void *buf,
-							uint32_t buf_size);
+int mhi_dev_write_channel(struct mhi_req *wreq);
 
 /**
  * mhi_dev_channel_isempty() - Checks if there is any pending TRE's to process.
@@ -733,8 +835,8 @@
  * @element:	Transfer ring element to be copied to the host memory.
  */
 int mhi_dev_add_element(struct mhi_dev_ring *ring,
-				union mhi_dev_ring_element_type *element);
-
+				union mhi_dev_ring_element_type *element,
+				struct event_req *ereq, int evt_offset);
 /**
  * mhi_transfer_device_to_host() - memcpy equivalent API to transfer data
  *		from device to the host.
@@ -742,9 +844,10 @@
  * @src:	Source virtual address.
  * @len:	Numer of bytes to be transferred.
  * @mhi:	MHI dev structure.
+ * @req:        mhi_req structure
  */
 int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len,
-				struct mhi_dev *mhi);
+				struct mhi_dev *mhi, struct mhi_req *req);
 
 /**
  * mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data
@@ -753,19 +856,29 @@
  * @src_pa:	Source physical address.
  * @len:	Numer of bytes to be transferred.
  * @mhi:	MHI dev structure.
+ * @req:        mhi_req structure
  */
 int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len,
-				struct mhi_dev *mhi);
+				struct mhi_dev *mhi, struct mhi_req *mreq);
 
 /**
- * mhi_dev_write_to_host() - memcpy equivalent API to transfer data
- *		from device to host.
+ * mhi_dev_write_to_host() - Transfer data from device to host.
+ *		Based on support available, either IPA DMA or memcpy is used.
  * @host:	Host and device address details.
  * @buf:	Data buffer that needs to be written to the host.
  * @size:	Data buffer size.
  */
-void mhi_dev_write_to_host(struct mhi_addr *host, void *buf, size_t size,
-				struct mhi_dev *mhi);
+void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer,
+		struct event_req *ereq, enum mhi_dev_transfer_type type);
+/**
+ * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
+ *		from host to device.
+ * @host:	Host and device address details.
+ * @buf:	Data buffer that needs to be read from the host.
+ * @size:	Data buffer size.
+ */
+void mhi_dev_read_from_host(struct mhi_dev *mhi,
+				struct mhi_addr *mhi_transfer);
 
 /**
  * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
@@ -774,15 +887,7 @@
  * @buf:	Data buffer that needs to be read from the host.
  * @size:	Data buffer size.
  */
-void mhi_dev_read_from_host(struct mhi_addr *dst, dma_addr_t buf, size_t size);
 
-/**
- * mhi_dev_read_from_host() - memcpy equivalent API to transfer data
- *		from host to device.
- * @host:	Host and device address details.
- * @buf:	Data buffer that needs to be read from the host.
- * @size:	Data buffer size.
- */
 void mhi_ring_set_cb(struct mhi_dev_ring *ring,
 			void (*ring_cb)(struct mhi_dev *dev,
 			union mhi_dev_ring_element_type *el, void *ctx));
@@ -848,6 +953,7 @@
  * mhi_dev_mmio_enable_ctrl_interrupt() - Enable Control interrupt.
  * @dev:	MHI device structure.
  */
+
 int mhi_dev_mmio_enable_ctrl_interrupt(struct mhi_dev *dev);
 
 /**
@@ -1021,8 +1127,10 @@
  * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3.
  * @dev:	MHI device structure.
  * @state:	Pointer of type mhi_dev_state
+ * @mhi_reset:	MHI device reset from host.
  */
-int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state);
+int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state,
+						bool *mhi_reset);
 
 /**
  * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event
@@ -1121,6 +1229,48 @@
  */
 int mhi_uci_init(void);
 
+/**
+ * mhi_dev_net_interface_init() - Initializes the mhi device network interface
+ *		which exposes the virtual network interface (mhi_dev_net0).
+ *		data packets will transfer between MHI host interface (mhi_swip)
+ *		and mhi_dev_net interface using software path
+ */
+int mhi_dev_net_interface_init(void);
+
+/**
+ * mhi_dev_net_exit() - Clean up and close MHI Network interface module.
+ */
+void mhi_dev_net_exit(void);
+
+/**
+ * mhi_dev_notify_a7_event() - Used by PCIe driver to notify A7 MHI device
+ *	interrupt after doorbell is received. Used by PCIe driver when MHI
+ *	A7 interrupts are routed to PCIe instead of MHI device.
+ */
 void mhi_dev_notify_a7_event(struct mhi_dev *mhi);
 
+/**
+ * mhi_ctrl_state_info() - Provide MHI state info
+ *		MHI_STATE=CONFIGURED - MHI device is present but not ready
+ *					for data traffic.
+ *		MHI_STATE=CONNECTED - MHI device is ready for data transfer.
+ *		MHI_STATE=DISCONNECTED - MHI device has its pipes suspended.
+ *		exposes device nodes for the supported MHI software
+ *		channels.
+ */
+int mhi_ctrl_state_info(uint32_t *info);
+
+/**
+ * uci_ctrl_update() - Update UCI once TRE's are available for clients to
+ *			consume.
+ */
+void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason);
+
+/**
+ * mhi_register_state_cb() - Clients can register and receive callback after
+ *		MHI channel is connected or disconnected.
+ */
+int mhi_register_state_cb(void (*mhi_state_cb)
+			(struct mhi_dev_client_cb_data *cb_data), void *data,
+			enum mhi_client_channel channel);
 #endif /* _MHI_H_ */
diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c
new file mode 100644
index 0000000..d8dc85f
--- /dev/null
+++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c
@@ -0,0 +1,667 @@
+/* Copyright (c) 2017-2018, 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.
+ */
+/*
+ * MHI Device Network interface
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/ipc_logging.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/ktime.h>
+
+#include "mhi.h"
+
+#define MHI_NET_DRIVER_NAME  "mhi_dev_net_drv"
+#define MHI_NET_DEV_NAME     "mhi_dev_net%d"
+#define MHI_NET_DEFAULT_MTU   8192
+#define MHI_NET_IPC_PAGES     (100)
+#define MHI_MAX_RX_REQ        (128)
+#define MHI_MAX_TX_REQ        (128)
+
+enum mhi_dev_net_dbg_lvl {
+	MHI_VERBOSE = 0x1,
+	MHI_INFO = 0x2,
+	MHI_DBG = 0x3,
+	MHI_WARNING = 0x4,
+	MHI_ERROR = 0x5,
+	MHI_CRITICAL = 0x6,
+	MSG_NET_reserved = 0x80000000
+};
+
+static enum mhi_dev_net_dbg_lvl mhi_net_msg_lvl = MHI_CRITICAL;
+static enum mhi_dev_net_dbg_lvl mhi_net_ipc_log_lvl = MHI_VERBOSE;
+static void *mhi_net_ipc_log;
+
+enum mhi_chan_dir {
+	MHI_DIR_INVALID = 0x0,
+	MHI_DIR_OUT = 0x1,
+	MHI_DIR_IN = 0x2,
+	MHI_DIR__reserved = 0x80000000
+};
+
+struct mhi_dev_net_chan_attr {
+	/* SW maintained channel id */
+	enum mhi_client_channel chan_id;
+	/* maximum buffer size for this channel */
+	size_t max_packet_size;
+	/* direction of the channel, see enum mhi_chan_dir */
+	enum mhi_chan_dir dir;
+};
+
+#define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2)
+
+#define mhi_dev_net_log(_msg_lvl, _msg, ...) do { \
+	if (_msg_lvl >= mhi_net_msg_lvl) { \
+		pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \
+	} \
+	if (mhi_net_ipc_log && (_msg_lvl >= mhi_net_ipc_log_lvl)) { \
+		ipc_log_string(mhi_net_ipc_log,                     \
+			"[%s] " _msg, __func__, ##__VA_ARGS__);     \
+	} \
+} while (0)
+
+module_param(mhi_net_msg_lvl, uint, 0644);
+MODULE_PARM_DESC(mhi_net_msg_lvl, "mhi dev net dbg lvl");
+
+module_param(mhi_net_ipc_log_lvl, uint, 0644);
+MODULE_PARM_DESC(mhi_net_ipc_log_lvl, "mhi dev net dbg lvl");
+
+struct mhi_dev_net_client {
+	/* write channel - always even*/
+	u32 out_chan;
+	/* read channel - always odd */
+	u32 in_chan;
+	struct mhi_dev_client *out_handle;
+	struct mhi_dev_client *in_handle;
+	/*process pendig packets */
+	struct workqueue_struct *pending_pckt_wq;
+	struct work_struct       xmit_work;
+	/*Read data from host work queue*/
+	atomic_t  rx_enabled;
+	atomic_t  tx_enabled;
+	struct net_device *dev;
+	struct sk_buff_head tx_buffers;
+	struct list_head rx_buffers;
+	struct list_head wr_req_buffers;
+	struct mhi_dev_net_ctxt *net_ctxt;
+	/*To check write channel is empty or not*/
+	spinlock_t wrt_lock;
+	spinlock_t rd_lock;
+	struct mutex in_chan_lock;
+	struct mutex out_chan_lock;
+};
+
+struct mhi_dev_net_ctxt {
+	struct mhi_dev_net_chan_attr chan_attr[MHI_MAX_SOFTWARE_CHANNELS];
+	struct mhi_dev_net_client *client_handle;
+	void (*net_event_notifier)(struct mhi_dev_client_cb_reason *cb);
+};
+
+static struct mhi_dev_net_ctxt mhi_net_ctxt;
+static ssize_t mhi_dev_net_client_read(struct mhi_dev_net_client *);
+
+static int mhi_dev_net_init_ch_attributes(struct mhi_dev_net_ctxt *mhi_ctxt)
+{
+	u32 channel = 0;
+	struct mhi_dev_net_chan_attr *chan_attrib = NULL;
+
+	channel = MHI_CLIENT_IP_SW_4_OUT;
+	chan_attrib = &mhi_ctxt->chan_attr[channel];
+	chan_attrib->dir = MHI_DIR_OUT;
+	chan_attrib->chan_id = channel;
+	chan_attrib->max_packet_size = TRB_MAX_DATA_SIZE;
+	mhi_dev_net_log(MHI_INFO, "Write chan attributes dir %d chan_id %d\n",
+			chan_attrib->dir, chan_attrib->chan_id);
+
+	channel = MHI_CLIENT_IP_SW_4_IN;
+	chan_attrib = &mhi_ctxt->chan_attr[channel];
+	chan_attrib->dir = MHI_DIR_IN;
+	chan_attrib->chan_id = channel;
+	chan_attrib->max_packet_size = TRB_MAX_DATA_SIZE;
+	mhi_dev_net_log(MHI_INFO, "Read chan attributes dir %d chan_id %d\n",
+			chan_attrib->dir, chan_attrib->chan_id);
+	return 0;
+}
+
+static void mhi_dev_net_process_queue_packets(struct work_struct *work)
+{
+	struct mhi_dev_net_client *client = container_of(work,
+			struct mhi_dev_net_client, xmit_work);
+	unsigned long flags = 0;
+	int xfer_data = 0;
+	struct sk_buff *skb = NULL;
+	struct mhi_req *wreq = NULL;
+
+	if (mhi_dev_channel_isempty(client->in_handle)) {
+		mhi_dev_net_log(MHI_INFO, "%s stop network xmmit\n", __func__);
+		netif_stop_queue(client->dev);
+		return;
+	}
+	while (!((skb_queue_empty(&client->tx_buffers)) ||
+			(list_empty(&client->wr_req_buffers)))) {
+		spin_lock_irqsave(&client->wrt_lock, flags);
+		skb = skb_dequeue(&(client->tx_buffers));
+		if (!skb) {
+			mhi_dev_net_log(MHI_INFO,
+					"SKB is NULL from dequeue\n");
+			spin_unlock_irqrestore(&client->wrt_lock, flags);
+			return;
+		}
+		wreq = container_of(client->wr_req_buffers.next,
+				struct mhi_req, list);
+		list_del_init(&wreq->list);
+
+		wreq->client = client->in_handle;
+		wreq->context = skb;
+		wreq->buf = skb->data;
+		wreq->len = skb->len;
+		wreq->chan = client->in_chan;
+		wreq->mode = IPA_DMA_ASYNC;
+		if (skb_queue_empty(&client->tx_buffers) ||
+				list_empty(&client->wr_req_buffers)) {
+			wreq->snd_cmpl = 1;
+		} else
+			wreq->snd_cmpl = 0;
+		spin_unlock_irqrestore(&client->wrt_lock, flags);
+		xfer_data = mhi_dev_write_channel(wreq);
+		if (xfer_data <= 0) {
+			pr_err("%s(): Failed to write skb len %d\n",
+					__func__, skb->len);
+			kfree_skb(skb);
+			return;
+		}
+		client->dev->stats.tx_packets++;
+
+		/* Check if free buffers are available*/
+		if (mhi_dev_channel_isempty(client->in_handle)) {
+			mhi_dev_net_log(MHI_INFO,
+					"%s buffers are full stop xmit\n",
+					__func__);
+			netif_stop_queue(client->dev);
+			break;
+		}
+	} /* While TX queue is not empty */
+}
+
+static void mhi_dev_net_event_notifier(struct mhi_dev_client_cb_reason *reason)
+{
+	struct mhi_dev_net_client *client_handle = mhi_net_ctxt.client_handle;
+
+	if (reason->reason == MHI_DEV_TRE_AVAILABLE) {
+		if (reason->ch_id % 2) {
+			if (netif_queue_stopped(client_handle->dev)) {
+				netif_wake_queue(client_handle->dev);
+				queue_work(client_handle->pending_pckt_wq,
+						&client_handle->xmit_work);
+			}
+		} else
+			mhi_dev_net_client_read(client_handle);
+	}
+}
+
+static __be16 mhi_dev_net_eth_type_trans(struct sk_buff *skb)
+{
+	__be16 protocol = 0;
+	/* Determine L3 protocol */
+	switch (skb->data[0] & 0xf0) {
+	case 0x40:
+		protocol = htons(ETH_P_IP);
+		break;
+	case 0x60:
+		protocol = htons(ETH_P_IPV6);
+		break;
+	default:
+		/* Default is QMAP */
+		protocol = htons(ETH_P_MAP);
+		break;
+	}
+	return protocol;
+}
+
+static void mhi_dev_net_read_completion_cb(void *req)
+{
+	struct mhi_dev_net_client *net_handle =
+		mhi_net_ctxt.client_handle;
+	struct mhi_req *mreq =
+		(struct mhi_req *)req;
+	struct sk_buff *skb = mreq->context;
+	unsigned long   flags;
+
+	skb->len = mreq->actual_len;
+	skb->protocol =
+		mhi_dev_net_eth_type_trans(skb);
+	skb_put(skb, mreq->actual_len);
+	net_handle->dev->stats.rx_packets++;
+	skb->dev = net_handle->dev;
+	netif_rx(skb);
+	spin_lock_irqsave(&net_handle->rd_lock, flags);
+	list_add_tail(&mreq->list, &net_handle->rx_buffers);
+	spin_unlock_irqrestore(&net_handle->rd_lock, flags);
+}
+
+static ssize_t mhi_dev_net_client_read(struct mhi_dev_net_client *mhi_handle)
+{
+	int bytes_avail = 0;
+	int ret_val = 0;
+	u32 chan = 0;
+	struct mhi_dev_client *client_handle = NULL;
+	struct mhi_req *req;
+	struct sk_buff *skb;
+	unsigned long   flags;
+
+	client_handle = mhi_handle->out_handle;
+	chan = mhi_handle->out_chan;
+	if (!atomic_read(&mhi_handle->rx_enabled))
+		return -EPERM;
+	while (1) {
+		spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+		if (list_empty(&mhi_handle->rx_buffers)) {
+			spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+			break;
+		}
+
+		req = container_of(mhi_handle->rx_buffers.next,
+				struct mhi_req, list);
+		list_del_init(&req->list);
+		spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+		skb = alloc_skb(MHI_NET_DEFAULT_MTU, GFP_ATOMIC);
+		if (skb == NULL) {
+			pr_err("%s(): skb alloc failed\n", __func__);
+			spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+			list_add_tail(&req->list, &mhi_handle->rx_buffers);
+			spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+			ret_val = -ENOMEM;
+			return ret_val;
+		}
+
+		req->client = client_handle;
+		req->chan = chan;
+		req->buf = skb->data;
+		req->len = MHI_NET_DEFAULT_MTU;
+		req->context = skb;
+		req->mode = IPA_DMA_ASYNC;
+		bytes_avail = mhi_dev_read_channel(req);
+
+		if (bytes_avail < 0) {
+			pr_err("Failed to read chan %d bytes_avail = %d\n",
+					chan, bytes_avail);
+			spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+			kfree_skb(skb);
+			list_add_tail(&req->list, &mhi_handle->rx_buffers);
+			spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+			ret_val = -EIO;
+			return 0;
+		}
+		/* no data to send to network stack, break */
+		if (!bytes_avail) {
+			spin_lock_irqsave(&mhi_handle->rd_lock, flags);
+			kfree_skb(skb);
+			list_add_tail(&req->list, &mhi_handle->rx_buffers);
+			spin_unlock_irqrestore(&mhi_handle->rd_lock, flags);
+			return 0;
+		}
+	}
+	/* coming out while only in case of no data or error */
+	return ret_val;
+
+}
+
+static void mhi_dev_net_write_completion_cb(void *req)
+{
+	struct mhi_dev_net_client *client_handle = mhi_net_ctxt.client_handle;
+	struct mhi_req *wreq = (struct mhi_req *)req;
+	struct sk_buff *skb = wreq->context;
+	unsigned long   flags;
+
+	kfree_skb(skb);
+	spin_lock_irqsave(&client_handle->wrt_lock, flags);
+	list_add_tail(&wreq->list, &client_handle->wr_req_buffers);
+	spin_unlock_irqrestore(&client_handle->wrt_lock, flags);
+}
+
+static int mhi_dev_net_alloc_write_reqs(struct mhi_dev_net_client *client)
+{
+	int nreq = 0, rc = 0;
+	struct mhi_req *wreq;
+
+	while (nreq < MHI_MAX_TX_REQ) {
+		wreq = kzalloc(sizeof(struct mhi_req), GFP_ATOMIC);
+		if (!wreq)
+			return -ENOMEM;
+		wreq->client_cb =  mhi_dev_net_write_completion_cb;
+		list_add_tail(&wreq->list, &client->wr_req_buffers);
+		nreq++;
+	}
+	mhi_dev_net_log(MHI_INFO,
+			"mhi write reqs allocation success\n");
+	return rc;
+
+}
+
+static int mhi_dev_net_alloc_read_reqs(struct mhi_dev_net_client *client)
+{
+	int nreq = 0, rc = 0;
+	struct mhi_req *mreq;
+
+	while (nreq < MHI_MAX_RX_REQ) {
+		mreq = kzalloc(sizeof(struct mhi_req), GFP_ATOMIC);
+		if (!mreq)
+			return -ENOMEM;
+		mreq->len =  TRB_MAX_DATA_SIZE;
+		mreq->client_cb =  mhi_dev_net_read_completion_cb;
+		list_add_tail(&mreq->list, &client->rx_buffers);
+		nreq++;
+	}
+	mhi_dev_net_log(MHI_INFO,
+			"mhi read reqs allocation success\n");
+	return rc;
+
+}
+
+static int mhi_dev_net_open(struct net_device *dev)
+{
+	struct mhi_dev_net_client *mhi_dev_net_ptr =
+		*(struct mhi_dev_net_client **)netdev_priv(dev);
+	mhi_dev_net_log(MHI_INFO,
+			"mhi_net_dev interface is up for IN %d OUT %d\n",
+			mhi_dev_net_ptr->out_chan,
+			mhi_dev_net_ptr->in_chan);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static netdev_tx_t mhi_dev_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mhi_dev_net_client *mhi_dev_net_ptr =
+			*(struct mhi_dev_net_client **)netdev_priv(dev);
+	unsigned long flags;
+
+	if (skb->len <= 0) {
+		mhi_dev_net_log(MHI_ERROR,
+				"Invalid skb received freeing skb\n");
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+	spin_lock_irqsave(&mhi_dev_net_ptr->wrt_lock, flags);
+	skb_queue_tail(&(mhi_dev_net_ptr->tx_buffers), skb);
+	spin_unlock_irqrestore(&mhi_dev_net_ptr->wrt_lock, flags);
+
+	queue_work(mhi_dev_net_ptr->pending_pckt_wq,
+			&mhi_dev_net_ptr->xmit_work);
+
+	return NETDEV_TX_OK;
+}
+
+static int mhi_dev_net_stop(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	mhi_dev_net_log(MHI_VERBOSE, "mhi_dev_net interface is down\n");
+	return 0;
+}
+
+static int mhi_dev_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (0 > new_mtu || MHI_NET_DEFAULT_MTU < new_mtu)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static const struct net_device_ops mhi_dev_net_ops_ip = {
+	.ndo_open = mhi_dev_net_open,
+	.ndo_stop = mhi_dev_net_stop,
+	.ndo_start_xmit = mhi_dev_net_xmit,
+	.ndo_change_mtu = mhi_dev_net_change_mtu,
+};
+
+static void mhi_dev_net_setup(struct net_device *dev)
+{
+	dev->netdev_ops = &mhi_dev_net_ops_ip;
+	ether_setup(dev);
+
+	/* set this after calling ether_setup */
+	dev->type = ARPHRD_RAWIP;
+	dev->hard_header_len = 0;
+	dev->mtu = MHI_NET_DEFAULT_MTU;
+	dev->addr_len = 0;
+	dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+}
+
+static int mhi_dev_net_enable_iface(struct mhi_dev_net_client *mhi_dev_net_ptr)
+{
+	int ret = 0;
+	struct mhi_dev_net_client **mhi_dev_net_ctxt = NULL;
+	struct net_device *netdev;
+
+	if (!mhi_dev_net_ptr)
+		return -EINVAL;
+
+	/* Initialize skb list head to queue the packets for mhi dev client */
+	skb_queue_head_init(&(mhi_dev_net_ptr->tx_buffers));
+
+	mhi_dev_net_log(MHI_INFO,
+			"mhi_dev_net interface registration\n");
+	netdev = alloc_netdev(sizeof(struct mhi_dev_net_client),
+			MHI_NET_DEV_NAME, NET_NAME_PREDICTABLE,
+			mhi_dev_net_setup);
+	if (!netdev) {
+		pr_err("Failed to allocate netdev for mhi_dev_net\n");
+		goto net_dev_alloc_fail;
+	}
+
+	mhi_dev_net_ctxt = netdev_priv(netdev);
+	mhi_dev_net_ptr->dev = netdev;
+	*mhi_dev_net_ctxt = mhi_dev_net_ptr;
+	ret = register_netdev(mhi_dev_net_ptr->dev);
+	if (ret) {
+		pr_err("Failed to register mhi_dev_net device\n");
+		goto net_dev_reg_fail;
+	}
+	mhi_dev_net_log(MHI_INFO, "Successfully registred mhi_dev_net\n");
+	return 0;
+
+net_dev_reg_fail:
+	free_netdev(mhi_dev_net_ptr->dev);
+net_dev_alloc_fail:
+	mhi_dev_close_channel(mhi_dev_net_ptr->in_handle);
+	mhi_dev_close_channel(mhi_dev_net_ptr->out_handle);
+	mhi_dev_net_ptr->dev = NULL;
+	return -ENOMEM;
+}
+
+static int mhi_dev_net_open_channels(struct mhi_dev_net_client *client)
+{
+	int rc = 0;
+	int ret = 0;
+	struct list_head *cp, *q;
+	struct mhi_req *mreq;
+
+	mhi_dev_net_log(MHI_DBG, "opening OUT %d IN %d channels\n",
+			client->out_chan,
+			client->in_chan);
+	mutex_lock(&client->out_chan_lock);
+	mutex_lock(&client->in_chan_lock);
+	mhi_dev_net_log(MHI_DBG,
+			"Initializing inbound chan %d.\n",
+			client->in_chan);
+
+	rc = mhi_dev_open_channel(client->out_chan, &client->out_handle,
+			mhi_net_ctxt.net_event_notifier);
+	if (rc < 0) {
+		mhi_dev_net_log(MHI_ERROR,
+				"Failed to open chan %d, ret 0x%x\n",
+				client->out_chan, rc);
+		goto handle_not_rdy_err;
+	} else
+		atomic_set(&client->rx_enabled, 1);
+
+	rc = mhi_dev_open_channel(client->in_chan, &client->in_handle,
+			mhi_net_ctxt.net_event_notifier);
+	if (rc < 0) {
+		mhi_dev_net_log(MHI_ERROR,
+				"Failed to open chan %d, ret 0x%x\n",
+				client->in_chan, rc);
+		goto handle_in_err;
+	} else
+		atomic_set(&client->tx_enabled, 1);
+
+	mutex_unlock(&client->in_chan_lock);
+	mutex_unlock(&client->out_chan_lock);
+	mhi_dev_net_log(MHI_INFO, "IN %d, OUT %d channels are opened",
+			client->in_chan, client->out_chan);
+
+	INIT_LIST_HEAD(&client->rx_buffers);
+	INIT_LIST_HEAD(&client->wr_req_buffers);
+	/* pre allocate read request buffer */
+
+	ret = mhi_dev_net_alloc_read_reqs(client);
+	if (ret) {
+		pr_err("failed to allocate rx req buffers\n");
+		goto rx_req_failed;
+	}
+	ret = mhi_dev_net_alloc_write_reqs(client);
+	if (ret) {
+		pr_err("failed to allocate write req buffers\n");
+		goto tx_req_failed;
+	}
+	if (atomic_read(&client->tx_enabled)) {
+		ret = mhi_dev_net_enable_iface(client);
+		if (ret < 0)
+			mhi_dev_net_log(MHI_ERROR,
+					"failed to enable mhi_dev_net iface\n");
+	}
+	return ret;
+tx_req_failed:
+	list_for_each_safe(cp, q, &client->rx_buffers);
+	mreq = list_entry(cp, struct mhi_req, list);
+	list_del(cp);
+	kfree(mreq);
+rx_req_failed:
+	mhi_dev_close_channel(client->in_handle);
+handle_in_err:
+	mhi_dev_close_channel(client->out_handle);
+handle_not_rdy_err:
+	mutex_unlock(&client->in_chan_lock);
+	mutex_unlock(&client->out_chan_lock);
+	return rc;
+}
+
+static int mhi_dev_net_close(void)
+{
+	struct mhi_dev_net_client *client;
+
+	mhi_dev_net_log(MHI_INFO,
+			"mhi_dev_net module is removed\n");
+	client = mhi_net_ctxt.client_handle;
+	mhi_dev_close_channel(client->out_handle);
+	mhi_dev_close_channel(client->in_handle);
+	atomic_set(&client->tx_enabled, 0);
+	atomic_set(&client->rx_enabled, 0);
+	if (client->dev != NULL) {
+		netif_stop_queue(client->dev);
+		unregister_netdev(client->dev);
+		free_netdev(client->dev);
+		client->dev = NULL;
+	}
+	/* freeing mhi client and IPC context */
+	kfree(client);
+	kfree(mhi_net_ipc_log);
+	return 0;
+}
+
+static int mhi_dev_net_rgstr_client(struct mhi_dev_net_client *client, int idx)
+{
+	client->out_chan = idx;
+	client->in_chan = idx + 1;
+	mutex_init(&client->in_chan_lock);
+	mutex_init(&client->out_chan_lock);
+	spin_lock_init(&client->wrt_lock);
+	spin_lock_init(&client->rd_lock);
+	mhi_dev_net_log(MHI_INFO, "Registering out %d, In %d channels\n",
+			client->out_chan, client->in_chan);
+
+	/* Open IN and OUT channels for Network client*/
+	mhi_dev_net_open_channels(client);
+	return 0;
+}
+
+int mhi_dev_net_interface_init(void)
+{
+	int ret_val = 0;
+	int index = 0;
+	struct mhi_dev_net_client *mhi_net_client = NULL;
+
+	mhi_net_client = kzalloc(sizeof(struct mhi_dev_net_client), GFP_KERNEL);
+	if (!mhi_net_client)
+		return -ENOMEM;
+
+	mhi_net_ipc_log = ipc_log_context_create(MHI_NET_IPC_PAGES,
+						"mhi-net", 0);
+	if (mhi_net_ipc_log == NULL)
+		mhi_dev_net_log(MHI_DBG,
+				"Failed to create IPC logging for mhi_dev_net\n");
+	mhi_net_ctxt.client_handle = mhi_net_client;
+
+	/*Process pending packet work queue*/
+	mhi_net_client->pending_pckt_wq =
+		create_singlethread_workqueue("pending_xmit_pckt_wq");
+	INIT_WORK(&mhi_net_client->xmit_work,
+			mhi_dev_net_process_queue_packets);
+
+	mhi_dev_net_log(MHI_INFO,
+			"Registering for MHI transfer events from host\n");
+	mhi_net_ctxt.net_event_notifier = mhi_dev_net_event_notifier;
+
+	ret_val = mhi_dev_net_init_ch_attributes(&mhi_net_ctxt);
+	if (ret_val < 0) {
+		mhi_dev_net_log(MHI_ERROR,
+				"Failed to init client attributes\n");
+		goto channel_init_fail;
+	}
+	mhi_dev_net_log(MHI_DBG, "Initializing client\n");
+	index = MHI_CLIENT_IP_SW_4_OUT;
+	ret_val = mhi_dev_net_rgstr_client(mhi_net_client, index);
+	if (ret_val) {
+		mhi_dev_net_log(MHI_CRITICAL,
+				"Failed to reg client %d ret 0\n", ret_val);
+		goto client_register_fail;
+	}
+	return ret_val;
+
+channel_init_fail:
+	kfree(mhi_net_client);
+	kfree(mhi_net_ipc_log);
+	return ret_val;
+client_register_fail:
+	kfree(mhi_net_client);
+	kfree(mhi_net_ipc_log);
+	return ret_val;
+}
+EXPORT_SYMBOL(mhi_dev_net_interface_init);
+
+void __exit mhi_dev_net_exit(void)
+{
+	mhi_dev_net_log(MHI_INFO,
+			"MHI Network Interface Module exited ");
+	mhi_dev_net_close();
+}
+EXPORT_SYMBOL(mhi_dev_net_exit);
diff --git a/drivers/platform/msm/mhi_dev/mhi_hwio.h b/drivers/platform/msm/mhi_dev/mhi_hwio.h
index 197713b..09a0118 100644
--- a/drivers/platform/msm/mhi_dev/mhi_hwio.h
+++ b/drivers/platform/msm/mhi_dev/mhi_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017-2018 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
@@ -184,6 +184,10 @@
 #define ERDB_HIGHER_n_ERDB_HIGHER_MASK			0xffffffff
 #define ERDB_HIGHER_n_ERDB_HIGHER_SHIFT			0x0
 
+#define BHI_INTVEC					(0x220)
+#define BHI_INTVEC_MASK					0xFFFFFFFF
+#define BHI_INTVEC_SHIFT				0
+
 #define BHI_EXECENV					(0x228)
 #define BHI_EXECENV_MASK				0xFFFFFFFF
 #define BHI_EXECENV_SHIFT				0
diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c
index 4043e0b..559fa84 100644
--- a/drivers/platform/msm/mhi_dev/mhi_mmio.c
+++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017-2018, 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
@@ -133,6 +133,11 @@
 	chid_mask = (1 << chid_shft);
 	chid_idx = chdb_id/32;
 
+	if (chid_idx >= MHI_MASK_ROWS_CH_EV_DB) {
+		pr_err("Invalid channel id:%d\n", chid_idx);
+		return -EINVAL;
+	}
+
 	if (enable)
 		val = 1;
 
@@ -143,6 +148,13 @@
 		return rc;
 	}
 
+	rc = mhi_dev_mmio_read(dev, MHI_CHDB_INT_MASK_A7_n(chid_idx),
+						&dev->chdb[chid_idx].mask);
+	if (rc) {
+		pr_err("Read channel db INT on row:%d failed\n", chid_idx);
+		return rc;
+	}
+
 	return rc;
 }
 
@@ -246,7 +258,8 @@
 }
 EXPORT_SYMBOL(mhi_dev_mmio_disable_erdb_a7);
 
-int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state)
+int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state,
+						bool *mhi_reset)
 {
 	uint32_t reg_value = 0;
 	int rc = 0;
@@ -265,6 +278,9 @@
 	if (rc)
 		return rc;
 
+	if (reg_value & MHICTRL_RESET_MASK)
+		*mhi_reset = true;
+
 	pr_debug("MHICTRL is 0x%x\n", reg_value);
 
 	return 0;
@@ -286,6 +302,7 @@
 			pr_err("Set channel db on row:%d failed\n", i);
 			return rc;
 		}
+		dev->chdb[i].mask = mask;
 	}
 
 	return rc;
@@ -850,6 +867,9 @@
 	mhi_dev_mmio_clear_interrupts(dev);
 	mhi_dev_mmio_enable_ctrl_interrupt(dev);
 
+	/*Enable chdb interrupt*/
+	mhi_dev_mmio_enable_chdb_interrupts(dev);
+
 	/* Mask and enable control interrupt */
 	mb();
 
diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c
index 3007b5a..d6791ea 100644
--- a/drivers/platform/msm/mhi_dev/mhi_ring.c
+++ b/drivers/platform/msm/mhi_dev/mhi_ring.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -47,38 +47,36 @@
 {
 	struct mhi_addr host_addr;
 
-	host_addr.device_pa = ring->ring_shadow.device_pa
+	if (ring->mhi_dev->use_ipa) {
+		host_addr.host_pa = ring->ring_shadow.host_pa
 			+ sizeof(union mhi_dev_ring_element_type) * start;
-	host_addr.device_va = ring->ring_shadow.device_va
+		host_addr.phy_addr = ring->ring_cache_dma_handle +
+			(sizeof(union mhi_dev_ring_element_type) * start);
+	} else {
+		host_addr.device_va = ring->ring_shadow.device_va
 			+ sizeof(union mhi_dev_ring_element_type) * start;
-	host_addr.host_pa = ring->ring_shadow.host_pa
-			+ sizeof(union mhi_dev_ring_element_type) * start;
+		host_addr.virt_addr = &ring->ring_cache[start];
+	}
+	host_addr.size = (end-start) * sizeof(union mhi_dev_ring_element_type);
 	if (start < end) {
-		mhi_dev_read_from_host(&host_addr,
-			(ring->ring_cache_dma_handle +
-			sizeof(union mhi_dev_ring_element_type) * start),
-			(end-start) *
-			sizeof(union mhi_dev_ring_element_type));
+		mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
 	} else if (start > end) {
 		/* copy from 'start' to ring end, then ring start to 'end'*/
-		mhi_dev_read_from_host(&host_addr,
-			(ring->ring_cache_dma_handle +
-			sizeof(union mhi_dev_ring_element_type) * start),
-			(ring->ring_size-start) *
-			sizeof(union mhi_dev_ring_element_type));
+		host_addr.size = (ring->ring_size-start) *
+					sizeof(union mhi_dev_ring_element_type);
+		mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
 		if (end) {
 			/* wrapped around */
 			host_addr.device_pa = ring->ring_shadow.device_pa;
 			host_addr.device_va = ring->ring_shadow.device_va;
 			host_addr.host_pa = ring->ring_shadow.host_pa;
-			mhi_dev_read_from_host(&host_addr,
-				(ring->ring_cache_dma_handle +
-				sizeof(union mhi_dev_ring_element_type) *
-				start),
-				end * sizeof(union mhi_dev_ring_element_type));
+			host_addr.virt_addr = &ring->ring_cache[0];
+			host_addr.phy_addr = ring->ring_cache_dma_handle;
+			host_addr.size = (end *
+				sizeof(union mhi_dev_ring_element_type));
+			mhi_dev_read_from_host(ring->mhi_dev, &host_addr);
 		}
 	}
-
 	return 0;
 }
 
@@ -95,21 +93,16 @@
 	mhi_ctx = ring->mhi_dev;
 
 	if (ring->wr_offset == wr_offset) {
-		mhi_log(MHI_MSG_INFO,
+		mhi_log(MHI_MSG_VERBOSE,
 			"nothing to cache for ring %d, local wr_ofst %d\n",
 			ring->id, ring->wr_offset);
-		mhi_log(MHI_MSG_INFO,
+		mhi_log(MHI_MSG_VERBOSE,
 			"new wr_offset %d\n", wr_offset);
 		return 0;
 	}
 
 	old_offset = ring->wr_offset;
 
-	mhi_log(MHI_MSG_ERROR,
-			"caching - rng size :%d local ofst:%d new ofst: %d\n",
-			(uint32_t) ring->ring_size, old_offset,
-			ring->wr_offset);
-
 	/*
 	 * copy the elements starting from old_offset to wr_offset
 	 * take in to account wrap around case event rings are not
@@ -118,12 +111,12 @@
 	if (ring->id >= mhi_ctx->ev_ring_start &&
 		ring->id < (mhi_ctx->ev_ring_start +
 				mhi_ctx->cfg.event_rings)) {
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 				"not caching event ring %d\n", ring->id);
 		return 0;
 	}
 
-	mhi_log(MHI_MSG_ERROR, "caching ring %d, start %d, end %d\n",
+	mhi_log(MHI_MSG_VERBOSE, "caching ring %d, start %d, end %d\n",
 			ring->id, old_offset, wr_offset);
 
 	if (mhi_dev_fetch_ring_elements(ring, old_offset, wr_offset)) {
@@ -155,7 +148,7 @@
 			pr_err("%s: CMD DB read failed\n", __func__);
 			return rc;
 		}
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"ring %d wr_offset from db 0x%x\n",
 			ring->id, (uint32_t) wr_offset);
 		break;
@@ -172,7 +165,7 @@
 			pr_err("%s: CH DB read failed\n", __func__);
 			return rc;
 		}
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"ring %d wr_offset from db 0x%x\n",
 			ring->id, (uint32_t) wr_offset);
 		break;
@@ -203,10 +196,14 @@
 	/* get the element and invoke the respective callback */
 	el = &ring->ring_cache[offset];
 
+	mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->tre.data_buf_ptr);
+	mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x, offset:%d\n",
+						el->tre.len, offset);
+
 	if (ring->ring_cb)
 		ring->ring_cb(ring->mhi_dev, el, (void *)ring);
 	else
-		mhi_log(MHI_MSG_INFO, "No callback registered for ring %d\n",
+		mhi_log(MHI_MSG_ERROR, "No callback registered for ring %d\n",
 				ring->id);
 
 	return 0;
@@ -216,12 +213,17 @@
 int mhi_dev_process_ring(struct mhi_dev_ring *ring)
 {
 	int rc = 0;
+	union mhi_dev_ring_element_type *el;
 
 	if (!ring) {
 		pr_err("%s: Invalid ring context\n", __func__);
 		return -EINVAL;
 	}
 
+	mhi_log(MHI_MSG_VERBOSE,
+			"Before wr update ring_id (%d) element (%d) with wr:%d\n",
+			ring->id, ring->rd_offset, ring->wr_offset);
+
 	rc = mhi_dev_update_wr_offset(ring);
 	if (rc) {
 		mhi_log(MHI_MSG_ERROR,
@@ -230,6 +232,13 @@
 		return rc;
 	}
 
+	/* get the element and invoke the respective callback */
+	el = &ring->ring_cache[ring->wr_offset];
+
+	mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->tre.data_buf_ptr);
+	mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x, wr_offset:%d\n",
+						el->tre.len, ring->wr_offset);
+
 	if (ring->type == RING_TYPE_CH) {
 		/* notify the clients that there are elements in the ring */
 		rc = mhi_dev_process_ring_element(ring, ring->rd_offset);
@@ -237,6 +246,9 @@
 			pr_err("Error fetching elements\n");
 		return rc;
 	}
+	mhi_log(MHI_MSG_VERBOSE,
+			"After ring update ring_id (%d) element (%d) with wr:%d\n",
+			ring->id, ring->rd_offset, ring->wr_offset);
 
 	while (ring->rd_offset != ring->wr_offset) {
 		rc = mhi_dev_process_ring_element(ring, ring->rd_offset);
@@ -247,7 +259,7 @@
 			return rc;
 		}
 
-		mhi_log(MHI_MSG_ERROR,
+		mhi_log(MHI_MSG_VERBOSE,
 			"Processing ring (%d) rd_offset:%d, wr_offset:%d\n",
 			ring->id, ring->rd_offset, ring->wr_offset);
 
@@ -265,10 +277,12 @@
 EXPORT_SYMBOL(mhi_dev_process_ring);
 
 int mhi_dev_add_element(struct mhi_dev_ring *ring,
-				union mhi_dev_ring_element_type *element)
+				union mhi_dev_ring_element_type *element,
+				struct event_req *ereq, int evt_offset)
 {
 	uint32_t old_offset = 0;
 	struct mhi_addr host_addr;
+	uint32_t num_elem = 0;
 
 	if (!ring || !element) {
 		pr_err("%s: Invalid context\n", __func__);
@@ -278,33 +292,53 @@
 	mhi_dev_update_wr_offset(ring);
 
 	if ((ring->rd_offset + 1) % ring->ring_size == ring->wr_offset) {
-		mhi_log(MHI_MSG_INFO, "ring full to insert element\n");
+		mhi_log(MHI_MSG_VERBOSE, "ring full to insert element\n");
 		return -EINVAL;
 	}
 
 	old_offset = ring->rd_offset;
 
-	mhi_dev_ring_inc_index(ring, ring->rd_offset);
+	if (evt_offset) {
+		num_elem = evt_offset /
+			(sizeof(union mhi_dev_ring_element_type));
+		ring->rd_offset += num_elem;
+		if (ring->rd_offset >= ring->ring_size)
+			ring->rd_offset -= ring->ring_size;
+	} else
+		mhi_dev_ring_inc_index(ring, ring->rd_offset);
 
 	ring->ring_ctx->generic.rp = (ring->rd_offset *
-				sizeof(union mhi_dev_ring_element_type)) +
-				ring->ring_ctx->generic.rbase;
+		sizeof(union mhi_dev_ring_element_type)) +
+		ring->ring_ctx->generic.rbase;
 	/*
 	 * Write the element, ring_base has to be the
 	 * iomap of the ring_base for memcpy
 	 */
-	host_addr.host_pa = ring->ring_shadow.host_pa +
+
+	if (ring->mhi_dev->use_ipa)
+		host_addr.host_pa = ring->ring_shadow.host_pa +
 			sizeof(union mhi_dev_ring_element_type) * old_offset;
-	host_addr.device_va = ring->ring_shadow.device_va +
+	else
+		host_addr.device_va = ring->ring_shadow.device_va +
 			sizeof(union mhi_dev_ring_element_type) * old_offset;
 
-	mhi_log(MHI_MSG_ERROR, "adding element to ring (%d)\n", ring->id);
-	mhi_log(MHI_MSG_ERROR, "rd_ofset %d\n", ring->rd_offset);
-	mhi_log(MHI_MSG_ERROR, "type %d\n", element->generic.type);
+	host_addr.virt_addr = element;
 
-	mhi_dev_write_to_host(&host_addr, element,
-			sizeof(union mhi_dev_ring_element_type), ring->mhi_dev);
+	if (evt_offset)
+		host_addr.size = evt_offset;
+	else
+		host_addr.size = sizeof(union mhi_dev_ring_element_type);
 
+	mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", ring->id);
+	mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset);
+	mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type);
+
+	if (ereq)
+		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
+				ereq, MHI_DEV_DMA_ASYNC);
+	else
+		mhi_dev_write_to_host(ring->mhi_dev, &host_addr,
+				NULL, MHI_DEV_DMA_SYNC);
 	return 0;
 }
 EXPORT_SYMBOL(mhi_dev_add_element);
@@ -362,16 +396,15 @@
 		(union mhi_dev_ring_ctx *) (mhi->ch_ctx_shadow.device_va +
 		(ring->id - mhi->ch_ring_start)*sizeof(union mhi_dev_ring_ctx));
 
-
 	ring->ring_ctx_shadow = ring->ring_ctx;
 
-	if (ring->type != RING_TYPE_ER) {
+	if (ring->type != RING_TYPE_ER || ring->type != RING_TYPE_CH) {
 		rc = mhi_dev_cache_ring(ring, wr_offset);
 		if (rc)
 			return rc;
 	}
 
-	mhi_log(MHI_MSG_ERROR, "ctx ring_base:0x%x, rp:0x%x, wp:0x%x\n",
+	mhi_log(MHI_MSG_VERBOSE, "ctx ring_base:0x%x, rp:0x%x, wp:0x%x\n",
 			(uint32_t)ring->ring_ctx->generic.rbase,
 			(uint32_t)ring->ring_ctx->generic.rp,
 			(uint32_t)ring->ring_ctx->generic.wp);
diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c
index 8179fad..1200a36 100644
--- a/drivers/platform/msm/mhi_dev/mhi_sm.c
+++ b/drivers/platform/msm/mhi_dev/mhi_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -396,7 +396,8 @@
 		res = true;
 		break;
 	case EP_PCIE_EVENT_PM_D3_HOT:
-		res = (curr_mstate == MHI_DEV_M3_STATE &&
+		res = ((curr_mstate == MHI_DEV_M3_STATE ||
+			curr_mstate == MHI_DEV_READY_STATE) &&
 			curr_dstate != MHI_SM_EP_PCIE_LINK_DISABLE);
 		break;
 	case EP_PCIE_EVENT_PM_D3_COLD:
@@ -437,7 +438,7 @@
 {
 	enum mhi_dev_state old_state;
 	struct ep_pcie_msi_config cfg;
-	int res;
+	int res = -EINVAL;
 
 	MHI_SM_FUNC_ENTRY();
 
@@ -476,6 +477,30 @@
 	mhi_sm_mmio_set_mhistatus(MHI_DEV_M0_STATE);
 
 	/* Tell the host, device move to M0 */
+	if (old_state == MHI_DEV_M3_STATE) {
+		if (mhi_sm_ctx->mhi_dev->use_ipa) {
+			res = ipa_dma_enable();
+			if (res) {
+				MHI_SM_ERR("IPA enable failed\n");
+				return res;
+			}
+		}
+
+		res = mhi_dev_resume(mhi_sm_ctx->mhi_dev);
+		if (res) {
+			MHI_SM_ERR("Failed resuming mhi core, returned %d",
+				res);
+			goto exit;
+		}
+
+		res = ipa_mhi_resume();
+		if (res) {
+			MHI_SM_ERR("Failed resuming ipa_mhi, returned %d",
+				res);
+			goto exit;
+		}
+	}
+
 	res = mhi_dev_send_state_change_event(mhi_sm_ctx->mhi_dev,
 				MHI_DEV_M0_STATE);
 	if (res) {
@@ -491,20 +516,6 @@
 			MHI_SM_ERR("failed sending EE event to host\n");
 			goto exit;
 		}
-	} else if (old_state == MHI_DEV_M3_STATE) {
-		/*Resuming MHI operation*/
-		res = mhi_dev_resume(mhi_sm_ctx->mhi_dev);
-		if (res) {
-			MHI_SM_ERR("Failed resuming mhi core, returned %d",
-				res);
-			goto exit;
-		}
-		res = ipa_mhi_resume();
-		if (res) {
-			MHI_SM_ERR("Failed resuming ipa_mhi, returned %d",
-				res);
-			goto exit;
-		}
 	}
 	res  = 0;
 
@@ -557,6 +568,14 @@
 		goto exit;
 	}
 
+	if (mhi_sm_ctx->mhi_dev->use_ipa) {
+		res = ipa_dma_disable();
+		if (res) {
+			MHI_SM_ERR("IPA disable failed\n");
+			return res;
+		}
+	}
+
 exit:
 	MHI_SM_FUNC_EXIT();
 	return res;
@@ -579,9 +598,9 @@
 
 	if (mhi_sm_ctx->mhi_state == MHI_DEV_M3_STATE) {
 		/*
-		 * ep_pcie driver is responsible to send the right wakeup
-		 * event, assert WAKE#, according to Link state
-		 */
+		  * ep_pcie driver is responsible to send the right wakeup
+		  * event, assert WAKE#, according to Link state
+		  */
 		res = ep_pcie_wakeup_host(mhi_sm_ctx->mhi_dev->phandle);
 		if (res) {
 			MHI_SM_ERR("Failed to wakeup MHI host, returned %d\n",
@@ -661,8 +680,8 @@
 		MHI_SM_ERR("EP-PCIE Link is disable cannot set MMIO to %s\n",
 			mhi_sm_mstate_str(MHI_DEV_SYSERR_STATE));
 
-	MHI_SM_ERR("/n/n/nASSERT ON DEVICE !!!!/n/n/n");
-	WARN_ON();
+	MHI_SM_ERR("/n/n/nError ON DEVICE !!!!/n/n/n");
+	WARN_ON(1);
 
 	MHI_SM_FUNC_EXIT();
 	return res;
@@ -918,6 +937,24 @@
 }
 EXPORT_SYMBOL(mhi_dev_sm_init);
 
+int mhi_dev_sm_exit(struct mhi_dev *mhi_dev)
+{
+	MHI_SM_FUNC_ENTRY();
+
+	atomic_set(&mhi_sm_ctx->pending_device_events, 0);
+	atomic_set(&mhi_sm_ctx->pending_pcie_events, 0);
+	mhi_sm_debugfs_destroy();
+	flush_workqueue(mhi_sm_ctx->mhi_sm_wq);
+	destroy_workqueue(mhi_sm_ctx->mhi_sm_wq);
+	ipa_dma_destroy();
+	mutex_destroy(&mhi_sm_ctx->mhi_state_lock);
+	devm_kfree(mhi_dev->dev, mhi_sm_ctx);
+	mhi_sm_ctx = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(mhi_dev_sm_exit);
+
 /**
  * mhi_dev_sm_get_mhi_state() -Get current MHI state.
  * @state: return param
@@ -964,7 +1001,7 @@
  */
 int mhi_dev_sm_set_ready(void)
 {
-	int res;
+	int res = 0;
 	int is_ready;
 	enum mhi_dev_state state;
 
@@ -1011,6 +1048,7 @@
 		goto unlock_and_exit;
 	}
 	mhi_sm_mmio_set_mhistatus(MHI_DEV_READY_STATE);
+	res = 0;
 
 unlock_and_exit:
 	mutex_unlock(&mhi_sm_ctx->mhi_state_lock);
@@ -1153,6 +1191,7 @@
 		ep_pcie_mask_irq_event(mhi_sm_ctx->mhi_dev->phandle,
 				EP_PCIE_INT_EVT_MHI_A7, false);
 		mhi_dev_notify_a7_event(mhi_sm_ctx->mhi_dev);
+		kfree(dstate_change_evt);
 		goto exit;
 	default:
 		MHI_SM_ERR("Invalid ep_pcie event, received 0x%x event\n",
diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h
index d477880..01e127b 100644
--- a/drivers/platform/msm/mhi_dev/mhi_sm.h
+++ b/drivers/platform/msm/mhi_dev/mhi_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015,2017-2018 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
@@ -41,6 +41,7 @@
 };
 
 int mhi_dev_sm_init(struct mhi_dev *dev);
+int mhi_dev_sm_exit(struct mhi_dev *dev);
 int mhi_dev_sm_set_ready(void);
 int mhi_dev_notify_sm_event(enum mhi_dev_event event);
 int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state);
diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c
index 3279fa8..244cf04 100644
--- a/drivers/platform/msm/mhi_dev/mhi_uci.c
+++ b/drivers/platform/msm/mhi_dev/mhi_uci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015,2017-2018, 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
@@ -73,6 +73,12 @@
 	u32 uci_ownership;
 };
 
+struct uci_ctrl {
+	wait_queue_head_t	ctrl_wq;
+	struct mhi_uci_ctxt_t	*uci_ctxt;
+	atomic_t		ctrl_data_update;
+};
+
 struct uci_client {
 	u32 client_index;
 	/* write channel - always odd*/
@@ -100,9 +106,13 @@
 struct mhi_uci_ctxt_t {
 	struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS];
 	struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
+	struct uci_ctrl ctrl_handle;
 	void (*event_notifier)(struct mhi_dev_client_cb_reason *cb);
 	dev_t start_ctrl_nr;
 	struct cdev cdev[MHI_MAX_SOFTWARE_CHANNELS];
+	dev_t ctrl_nr;
+	struct cdev *cdev_ctrl;
+	struct device *dev;
 	struct class *mhi_uci_class;
 	atomic_t mhi_disabled;
 	atomic_t mhi_enable_notif_wq_active;
@@ -129,12 +139,16 @@
 
 static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
 		size_t count, loff_t *offp);
+static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf,
+		size_t count, loff_t *offp);
 static ssize_t mhi_uci_client_write(struct file *file,
 		const char __user *buf, size_t count, loff_t *offp);
 static int mhi_uci_client_open(struct inode *mhi_inode, struct file*);
+static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*);
 static int mhi_uci_client_release(struct inode *mhi_inode,
 		struct file *file_handle);
 static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
+static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait);
 static struct mhi_uci_ctxt_t uci_ctxt;
 
 static int mhi_init_read_chan(struct uci_client *client_handle,
@@ -184,6 +198,8 @@
 	uintptr_t memcpy_result = 0;
 	u32 data_inserted_so_far = 0;
 	struct uci_client *uci_handle;
+	struct mhi_req ureq;
+
 
 	uci_handle = container_of(client_handle, struct uci_client,
 					out_handle);
@@ -206,15 +222,43 @@
 	} else {
 		data_loc = buf;
 	}
+	ureq.client = *client_handle;
+	ureq.buf = data_loc;
+	ureq.len = size;
+	ureq.chan = uci_handle->out_chan;
+	ureq.mode = IPA_DMA_SYNC;
 
-	data_inserted_so_far = mhi_dev_write_channel(*client_handle, data_loc,
-							size);
+	data_inserted_so_far = mhi_dev_write_channel(&ureq);
 
 error_memcpy:
 	kfree(data_loc);
 	return data_inserted_so_far;
 }
 
+static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	struct uci_ctrl *uci_ctrl_handle;
+
+	uci_ctrl_handle = file->private_data;
+
+	if (!uci_ctrl_handle)
+		return -ENODEV;
+
+	poll_wait(file, &uci_ctrl_handle->ctrl_wq, wait);
+	if (!atomic_read(&uci_ctxt.mhi_disabled) &&
+		atomic_read(&uci_ctrl_handle->ctrl_data_update)) {
+		uci_log(UCI_DBG_VERBOSE, "Client can read ctrl_state");
+		mask |= POLLIN | POLLRDNORM;
+	}
+
+	uci_log(UCI_DBG_VERBOSE,
+		"Client attempted to poll ctrl returning mask 0x%x\n",
+		mask);
+
+	return mask;
+}
+
 static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
 {
 	unsigned int mask = 0;
@@ -297,6 +341,22 @@
 	return rc;
 }
 
+static int mhi_uci_ctrl_open(struct inode *inode,
+			struct file *file_handle)
+{
+	struct uci_ctrl *uci_ctrl_handle;
+
+	uci_log(UCI_DBG_DBG, "Client opened ctrl file device node\n");
+
+	uci_ctrl_handle = &uci_ctxt.ctrl_handle;
+	if (!uci_ctrl_handle)
+		return -EINVAL;
+
+	file_handle->private_data = uci_ctrl_handle;
+
+	return 0;
+}
+
 static int mhi_uci_client_open(struct inode *mhi_inode,
 				struct file *file_handle)
 {
@@ -337,18 +397,20 @@
 		struct file *file_handle)
 {
 	struct uci_client *uci_handle = file_handle->private_data;
-	struct mhi_uci_ctxt_t *uci_ctxt = uci_handle->uci_ctxt;
+	struct mhi_uci_ctxt_t *uci_ctxt;
 	u32 nr_in_bufs = 0;
 	int rc = 0;
 	int in_chan = 0;
 	u32 buf_size = 0;
 
+	if (!uci_handle)
+		return -EINVAL;
+
+	uci_ctxt = uci_handle->uci_ctxt;
 	in_chan = iminor(mhi_inode) + 1;
 	nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs;
 	buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size;
 
-	if (!uci_handle)
-		return -EINVAL;
 	if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
 		uci_log(UCI_DBG_DBG,
 				"Last client left, closing channel 0x%x\n",
@@ -379,7 +441,54 @@
 	return rc;
 }
 
-static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
+static ssize_t mhi_uci_ctrl_client_read(struct file *file,
+		char __user *user_buf,
+		size_t count, loff_t *offp)
+{
+	uint32_t rc = 0, info;
+	int nbytes, size;
+	char buf[MHI_CTRL_STATE];
+	struct uci_ctrl *uci_ctrl_handle = NULL;
+
+	if (!file || !user_buf || !count ||
+		(count < MHI_CTRL_STATE) || !file->private_data)
+		return -EINVAL;
+
+	uci_ctrl_handle = file->private_data;
+	rc = mhi_ctrl_state_info(&info);
+	if (rc)
+		return -EINVAL;
+
+	switch (info) {
+	case MHI_STATE_CONFIGURED:
+		nbytes = scnprintf(buf, sizeof(buf),
+			"MHI_STATE=CONFIGURED");
+		break;
+	case MHI_STATE_CONNECTED:
+		nbytes = scnprintf(buf, sizeof(buf),
+			"MHI_STATE=CONNECTED");
+		break;
+	case MHI_STATE_DISCONNECTED:
+		nbytes = scnprintf(buf, sizeof(buf),
+			"MHI_STATE=DISCONNECTED");
+		break;
+	default:
+		pr_err("invalid info:%d\n", info);
+		return -EINVAL;
+	}
+
+
+	size = simple_read_from_buffer(user_buf, count, offp, buf, nbytes);
+
+	atomic_set(&uci_ctrl_handle->ctrl_data_update, 0);
+
+	if (size == 0)
+		*offp = 0;
+
+	return size;
+}
+
+static ssize_t mhi_uci_client_read(struct file *file, char __user *ubuf,
 		size_t uspace_buf_size, loff_t *bytes_pending)
 {
 	struct uci_client *uci_handle = NULL;
@@ -387,39 +496,40 @@
 	int bytes_avail = 0;
 	int ret_val = 0;
 	struct mutex *mutex;
-	u32 chan = 0;
 	ssize_t bytes_copied = 0;
 	u32 addr_offset = 0;
-	uint32_t buf_size;
-	uint32_t chained = 0;
 	void *local_buf = NULL;
+	struct mhi_req ureq;
 
-	if (!file || !buf || !uspace_buf_size ||
+	if (!file || !ubuf || !uspace_buf_size ||
 			!file->private_data)
 		return -EINVAL;
 
 	uci_handle = file->private_data;
 	client_handle = uci_handle->in_handle;
 	mutex = &uci_handle->in_chan_lock;
-	chan = uci_handle->in_chan;
+	ureq.chan = uci_handle->in_chan;
 
 	mutex_lock(mutex);
+	ureq.client = client_handle;
+	ureq.buf = uci_handle->in_buf_list[0].addr;
+	ureq.len = uci_handle->in_buf_list[0].buf_size;
+	ureq.mode = IPA_DMA_SYNC;
 
-	local_buf = uci_handle->in_buf_list[0].addr;
-	buf_size = uci_handle->in_buf_list[0].buf_size;
-
-
-	uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n", chan);
+	uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n",
+			ureq.chan);
 	do {
 		if (!uci_handle->pkt_loc &&
 				!atomic_read(&uci_ctxt.mhi_disabled)) {
 
-			bytes_avail = mhi_dev_read_channel(client_handle,
-					local_buf, buf_size, &chained);
+			bytes_avail = mhi_dev_read_channel(&ureq);
 
 			uci_log(UCI_DBG_VERBOSE,
-				"reading from mhi_core local_buf = %p,buf_size = 0x%x bytes_read = 0x%x\n",
-				local_buf, buf_size, bytes_avail);
+				"reading from mhi_core local_buf = %p",
+				local_buf);
+			uci_log(UCI_DBG_VERBOSE,
+					"buf_size = 0x%x bytes_read = 0x%x\n",
+					 ureq.len, bytes_avail);
 
 			if (bytes_avail < 0) {
 				uci_log(UCI_DBG_ERROR,
@@ -430,13 +540,14 @@
 			}
 
 			if (bytes_avail > 0) {
-				uci_handle->pkt_loc = (void *)local_buf;
-				uci_handle->pkt_size = bytes_avail;
+				uci_handle->pkt_loc = (void *) ureq.buf;
+				uci_handle->pkt_size = ureq.actual_len;
 
 				*bytes_pending = (loff_t)uci_handle->pkt_size;
 				uci_log(UCI_DBG_VERBOSE,
-					"Got pkt of size 0x%x at addr %p, chan %d\n",
-					uci_handle->pkt_size, local_buf, chan);
+					"Got pkt of sz 0x%x at adr %p, ch %d\n",
+					uci_handle->pkt_size,
+					ureq.buf, ureq.chan);
 			} else {
 				uci_handle->pkt_loc = 0;
 				uci_handle->pkt_size = 0;
@@ -448,7 +559,7 @@
 			uci_log(UCI_DBG_VERBOSE,
 				"No data read_data_ready %d, chan %d\n",
 				atomic_read(&uci_handle->read_data_ready),
-				chan);
+				ureq.chan);
 
 			ret_val = wait_event_interruptible(uci_handle->read_wq,
 				(!mhi_dev_channel_isempty(client_handle)));
@@ -458,17 +569,17 @@
 				goto error;
 			}
 			uci_log(UCI_DBG_VERBOSE,
-				"Thread woke up. Got data on chan %d read_data_ready %d\n",
-				chan,
+				"wk up Got data on ch %d read_data_ready %d\n",
+				ureq.chan,
 				atomic_read(&uci_handle->read_data_ready));
 
 			/* A valid packet was returned from MHI */
 		} else if (bytes_avail > 0) {
 			uci_log(UCI_DBG_VERBOSE,
-				"Got packet: avail pkts %d phy_adr %p, chan %d\n",
+				"Got packet: avail pkts %d phy_adr %p, ch %d\n",
 				atomic_read(&uci_handle->read_data_ready),
-				local_buf,
-				chan);
+				ureq.buf,
+				ureq.chan);
 			break;
 			/*
 			 * MHI did not return a valid packet, but we have one
@@ -477,16 +588,16 @@
 		} else {
 			uci_log(UCI_DBG_CRITICAL,
 				"chan %d err: avail pkts %d phy_adr %p",
-				chan,
+				ureq.chan,
 				atomic_read(&uci_handle->read_data_ready),
-				local_buf);
+				ureq.buf);
 			return -EIO;
 		}
 	} while (!uci_handle->pkt_loc);
 
 	if (uspace_buf_size >= *bytes_pending) {
 		addr_offset = uci_handle->pkt_size - *bytes_pending;
-		if (copy_to_user(buf, uci_handle->pkt_loc + addr_offset,
+		if (copy_to_user(ubuf, uci_handle->pkt_loc + addr_offset,
 							*bytes_pending)) {
 			ret_val = -EIO;
 			goto error;
@@ -495,10 +606,10 @@
 		bytes_copied = *bytes_pending;
 		*bytes_pending = 0;
 		uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x, chan %d\n",
-				bytes_copied, (u32)*bytes_pending, chan);
+				bytes_copied, (u32)*bytes_pending, ureq.chan);
 	} else {
 		addr_offset = uci_handle->pkt_size - *bytes_pending;
-		if (copy_to_user(buf, (void *) (uintptr_t)uci_handle->pkt_loc +
+		if (copy_to_user(ubuf, (void *) (uintptr_t)uci_handle->pkt_loc +
 					addr_offset, uspace_buf_size)) {
 			ret_val = -EIO;
 			goto error;
@@ -508,13 +619,13 @@
 		uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x,chan %d\n",
 				bytes_copied,
 				(u32)*bytes_pending,
-				chan);
+				ureq.chan);
 	}
 	/* We finished with this buffer, map it back */
 	if (*bytes_pending == 0) {
 		uci_log(UCI_DBG_VERBOSE,
 				"All data consumed. Pkt loc %p ,chan %d\n",
-				uci_handle->pkt_loc, chan);
+				uci_handle->pkt_loc, ureq.chan);
 		uci_handle->pkt_loc = 0;
 		uci_handle->pkt_size = 0;
 	}
@@ -599,6 +710,8 @@
 		case MHI_CLIENT_SAHARA_IN:
 		case MHI_CLIENT_EFS_OUT:
 		case MHI_CLIENT_EFS_IN:
+		case MHI_CLIENT_MBIM_OUT:
+		case MHI_CLIENT_MBIM_IN:
 		case MHI_CLIENT_QMI_OUT:
 		case MHI_CLIENT_QMI_IN:
 		case MHI_CLIENT_IP_CTRL_0_OUT:
@@ -634,6 +747,23 @@
 	return 0;
 }
 
+void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason)
+{
+	struct uci_ctrl *uci_ctrl_handle = NULL;
+
+	if (reason->reason == MHI_DEV_CTRL_UPDATE) {
+		uci_ctrl_handle = &uci_ctxt.ctrl_handle;
+		if (!uci_ctrl_handle) {
+			pr_err("Invalid uci ctrl handle\n");
+			return;
+		}
+
+		uci_log(UCI_DBG_DBG, "received state change update\n");
+		wake_up(&uci_ctrl_handle->ctrl_wq);
+		atomic_set(&uci_ctrl_handle->ctrl_data_update, 1);
+	}
+}
+EXPORT_SYMBOL(uci_ctrl_update);
 
 static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason)
 {
@@ -718,6 +848,12 @@
 	return rc;
 }
 
+static const struct file_operations mhi_uci_ctrl_client_fops = {
+	.open = mhi_uci_ctrl_open,
+	.read = mhi_uci_ctrl_client_read,
+	.poll = mhi_uci_ctrl_poll,
+};
+
 static const struct file_operations mhi_uci_client_fops = {
 	.read = mhi_uci_client_read,
 	.write = mhi_uci_client_write,
@@ -770,16 +906,25 @@
 			}
 		}
 	}
+
+	init_waitqueue_head(&uci_ctxt.ctrl_handle.ctrl_wq);
 	uci_log(UCI_DBG_INFO, "Allocating char devices.\n");
 	r = alloc_chrdev_region(&uci_ctxt.start_ctrl_nr,
 			0, MHI_MAX_SOFTWARE_CHANNELS,
 			DEVICE_NAME);
-
 	if (IS_ERR_VALUE(r)) {
 		uci_log(UCI_DBG_ERROR,
 				"Failed to alloc char devs, ret 0x%x\n", r);
 		goto failed_char_alloc;
 	}
+
+	r = alloc_chrdev_region(&uci_ctxt.ctrl_nr, 0, 1, DEVICE_NAME);
+	if (IS_ERR_VALUE(r)) {
+		uci_log(UCI_DBG_ERROR,
+				"Failed to alloc char ctrl devs, 0x%x\n", r);
+		goto failed_char_alloc;
+	}
+
 	uci_log(UCI_DBG_INFO, "Creating class\n");
 	uci_ctxt.mhi_uci_class = class_create(THIS_MODULE,
 						DEVICE_NAME);
@@ -803,12 +948,12 @@
 					i, r);
 				goto failed_char_add;
 			}
+
 			uci_ctxt.client_handles[i].dev =
 				device_create(uci_ctxt.mhi_uci_class, NULL,
 						uci_ctxt.start_ctrl_nr + i,
 						NULL, DEVICE_NAME "_pipe_%d",
 						i * 2);
-
 			if (IS_ERR(uci_ctxt.client_handles[i].dev)) {
 				uci_log(UCI_DBG_ERROR,
 						"Failed to add cdev %d\n", i);
@@ -817,6 +962,37 @@
 			}
 		}
 	}
+
+	/* Control node */
+	uci_ctxt.cdev_ctrl = cdev_alloc();
+	if (uci_ctxt.cdev_ctrl == NULL) {
+		pr_err("%s: ctrl cdev alloc failed\n", __func__);
+		return 0;
+	}
+
+	cdev_init(uci_ctxt.cdev_ctrl, &mhi_uci_ctrl_client_fops);
+	uci_ctxt.cdev_ctrl->owner = THIS_MODULE;
+	r = cdev_add(uci_ctxt.cdev_ctrl, uci_ctxt.ctrl_nr, 1);
+	if (IS_ERR_VALUE(r)) {
+		uci_log(UCI_DBG_ERROR,
+		"Failed to add ctrl cdev %d, ret 0x%x\n", i, r);
+		kfree(uci_ctxt.cdev_ctrl);
+		uci_ctxt.cdev_ctrl = NULL;
+		return 0;
+	}
+
+	uci_ctxt.dev =
+		device_create(uci_ctxt.mhi_uci_class, NULL,
+				uci_ctxt.ctrl_nr,
+				NULL, DEVICE_NAME "_ctrl");
+	if (IS_ERR(uci_ctxt.dev)) {
+		uci_log(UCI_DBG_ERROR,
+				"Failed to add ctrl cdev %d\n", i);
+		cdev_del(uci_ctxt.cdev_ctrl);
+		kfree(uci_ctxt.cdev_ctrl);
+		uci_ctxt.cdev_ctrl = NULL;
+	}
+
 	return 0;
 
 failed_char_add:
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 5d094d2..348b287 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -31,6 +31,14 @@
 #define GENI_SE_IOMMU_VA_START	(0x40000000)
 #define GENI_SE_IOMMU_VA_SIZE	(0xC0000000)
 
+#ifdef CONFIG_ARM64
+#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
+#define GENI_SE_DMA_PTR_H(ptr) ((u32)(ptr >> 32))
+#else
+#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
+#define GENI_SE_DMA_PTR_H(ptr) 0
+#endif
+
 #define NUM_LOG_PAGES 2
 #define MAX_CLK_PERF_LEVEL 32
 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000};
@@ -999,8 +1007,8 @@
 		return ret;
 
 	geni_write_reg(7, base, SE_DMA_TX_IRQ_EN_SET);
-	geni_write_reg((u32)(*tx_dma), base, SE_DMA_TX_PTR_L);
-	geni_write_reg((u32)((*tx_dma) >> 32), base, SE_DMA_TX_PTR_H);
+	geni_write_reg(GENI_SE_DMA_PTR_L(*tx_dma), base, SE_DMA_TX_PTR_L);
+	geni_write_reg(GENI_SE_DMA_PTR_H(*tx_dma), base, SE_DMA_TX_PTR_H);
 	geni_write_reg(1, base, SE_DMA_TX_ATTR);
 	geni_write_reg(tx_len, base, SE_DMA_TX_LEN);
 	return 0;
@@ -1033,8 +1041,8 @@
 		return ret;
 
 	geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET);
-	geni_write_reg((u32)(*rx_dma), base, SE_DMA_RX_PTR_L);
-	geni_write_reg((u32)((*rx_dma) >> 32), base, SE_DMA_RX_PTR_H);
+	geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L);
+	geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H);
 	/* RX does not have EOT bit */
 	geni_write_reg(0, base, SE_DMA_RX_ATTR);
 	geni_write_reg(rx_len, base, SE_DMA_RX_LEN);
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 684aec8..99c5f27 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -50,6 +50,7 @@
 	[PM2433_SUBTYPE] = "PM2433",
 	[PMD9655_SUBTYPE] = "PMD9655",
 	[PM8950_SUBTYPE] = "PM8950",
+	[PM8953_SUBTYPE] = "PM8953",
 	[PMI8950_SUBTYPE] = "PMI8950",
 	[PMK8001_SUBTYPE] = "PMK8001",
 	[PMI8996_SUBTYPE] = "PMI8996",
@@ -61,6 +62,9 @@
 	[PM660_SUBTYPE] = "PM660",
 	[PMI632_SUBTYPE] = "PMI632",
 	[PMI8937_SUBTYPE] = "PMI8937",
+	[PM855_SUBTYPE] = "PM855",
+	[PM855B_SUBTYPE] = "PM855B",
+	[PM855L_SUBTYPE] = "PM855L",
 };
 
 struct revid_chip {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 95e3782..6314270 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -3139,7 +3139,8 @@
 	}
 
 	dev = &ctx->usb_bam_pdev->dev;
-	if (dev && dev->parent && !device_property_present(dev->parent,
+	if (dev && dev->parent && device_property_present(dev->parent, "iommus")
+		&& !device_property_present(dev->parent,
 						"qcom,smmu-s1-bypass")) {
 		pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n",
 						__func__, dev_name(dev));
@@ -3312,7 +3313,7 @@
 	return ret;
 }
 
-bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx)
+bool usb_bam_get_prod_granted(enum usb_ctrl bam_type)
 {
 	return (info[bam_type].cur_prod_state == IPA_RM_RESOURCE_GRANTED);
 }
diff --git a/drivers/power/qcom/apm.c b/drivers/power/qcom/apm.c
index 3dfb439..ed3df00 100644
--- a/drivers/power/qcom/apm.c
+++ b/drivers/power/qcom/apm.c
@@ -638,9 +638,15 @@
 #define MSM8953_APCC_APM_MODE              0x000002a8
 #define MSM8953_APCC_APM_CTL_STS           0x000002b0
 
+/* 8953 constants */
+#define MSM8953_APM_SWITCH_TIMEOUT_US      500
+
+/* Register bit mask definitions */
+#define MSM8953_APM_CTL_STS_MASK           0x1f
+
 static int msm8953_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
 {
-	int timeout = MSM_APM_SWITCH_TIMEOUT_US;
+	int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
 	u32 regval;
 	int ret = 0;
 	unsigned long flags;
@@ -657,7 +663,7 @@
 	while (timeout > 0) {
 		regval = readl_relaxed(ctrl_dev->reg_base +
 					MSM8953_APCC_APM_CTL_STS);
-		if ((regval & MSM_APM_CTL_STS_MASK) ==
+		if ((regval & MSM8953_APM_CTL_STS_MASK) ==
 				MSM8953_APM_MX_DONE_VAL)
 			break;
 
@@ -681,7 +687,7 @@
 
 static int msm8953_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
 {
-	int timeout = MSM_APM_SWITCH_TIMEOUT_US;
+	int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
 	u32 regval;
 	int ret = 0;
 	unsigned long flags;
@@ -698,7 +704,7 @@
 	while (timeout > 0) {
 		regval = readl_relaxed(ctrl_dev->reg_base +
 					MSM8953_APCC_APM_CTL_STS);
-		if ((regval & MSM_APM_CTL_STS_MASK) ==
+		if ((regval & MSM8953_APM_CTL_STS_MASK) ==
 				MSM8953_APM_APCC_DONE_VAL)
 			break;
 
diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c
index b0b1eb3..76153ac 100644
--- a/drivers/power/reset/zx-reboot.c
+++ b/drivers/power/reset/zx-reboot.c
@@ -81,3 +81,7 @@
 	},
 };
 module_platform_driver(zx_reboot_driver);
+
+MODULE_DESCRIPTION("ZTE SoCs reset driver");
+MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 819fbf0..f4a36a3 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -321,8 +321,12 @@
 	POWER_SUPPLY_ATTR(sdp_current_max),
 	POWER_SUPPLY_ATTR(connector_type),
 	POWER_SUPPLY_ATTR(parallel_batfet_mode),
+	POWER_SUPPLY_ATTR(parallel_fcc_max),
 	POWER_SUPPLY_ATTR(min_icl),
 	POWER_SUPPLY_ATTR(moisture_detected),
+	POWER_SUPPLY_ATTR(batt_profile_version),
+	POWER_SUPPLY_ATTR(batt_full_current),
+	POWER_SUPPLY_ATTR(recharge_soc),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig
index 35aa6cc..e653475 100644
--- a/drivers/power/supply/qcom/Kconfig
+++ b/drivers/power/supply/qcom/Kconfig
@@ -62,6 +62,19 @@
 	  VBUS and VCONN regulators are registered for supporting OTG,
 	  and powered Type-C cables respectively.
 
+config QPNP_SMB5
+	tristate "SMB5 Battery Charger"
+	depends on MFD_SPMI_PMIC
+	help
+	  Say Y to enables support for the SMB5 charging peripheral.
+	  The QPNP SMB5 charger driver supports the charger peripheral
+	  present in the chip.
+	  The power supply framework is used to communicate battery and
+	  usb properties to userspace and other driver consumers such
+	  as fuel gauge, USB, and USB-PD.
+	  VBUS and VCONN regulators are registered for supporting OTG,
+	  and powered Type-C cables respectively.
+
 config SMB138X_CHARGER
 	tristate "SMB138X Battery Charger"
 	depends on MFD_I2C_PMIC
@@ -102,4 +115,13 @@
 	  USB power-delivery. The driver adds support to report these type-C
 	  parameters via the power-supply framework.
 
+config QPNP_QG
+	bool "QPNP Qgauge driver"
+	depends on MFD_SPMI_PMIC
+	help
+	  Say Y here to enable the Qualcomm Technologies, Inc. QGauge driver
+	  which uses the periodic sampling of the battery voltage and current
+	  to determine the battery state-of-charge (SOC) and supports other
+	  battery management features.
+
 endmenu
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index 7350c30..662f18d 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -6,5 +6,7 @@
 obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
 obj-$(CONFIG_QPNP_SMB2)		+= step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
 obj-$(CONFIG_SMB138X_CHARGER)	+= step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
+obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
 obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
 obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
+obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 3f8c727..223af14 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018 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
@@ -73,6 +73,7 @@
 	int			charge_type;
 	int			total_settled_ua;
 	int			pl_settled_ua;
+	int			pl_fcc_max;
 	struct class		qcom_batt_class;
 	struct wakeup_source	*pl_ws;
 	struct notifier_block	nb;
@@ -418,6 +419,7 @@
 	effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
 	slave_limited_ua = min(effective_total_ua, bcl_ua);
 	*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
+	*slave_ua = min(*slave_ua, chip->pl_fcc_max);
 
 	/*
 	 * In stacked BATFET configuration charger's current goes
@@ -935,6 +937,12 @@
 					&pval);
 	chip->pl_min_icl_ua = pval.intval;
 
+	chip->pl_fcc_max = INT_MAX;
+	rc = power_supply_get_property(chip->pl_psy,
+			POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval);
+	if (!rc)
+		chip->pl_fcc_max = pval.intval;
+
 	vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
 
 	return true;
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 99120f4..e77cf35 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -86,6 +86,13 @@
 
 #define MAX_CC_STEPS			20
 
+enum prof_load_status {
+	PROFILE_MISSING,
+	PROFILE_LOADED,
+	PROFILE_SKIPPED,
+	PROFILE_NOT_LOADED,
+};
+
 /* Debug flag definitions */
 enum fg_debug_flag {
 	FG_IRQ			= BIT(0), /* Show interrupts */
@@ -170,6 +177,7 @@
 	FG_SRAM_SYS_TERM_CURR,
 	FG_SRAM_CHG_TERM_CURR,
 	FG_SRAM_CHG_TERM_BASE_CURR,
+	FG_SRAM_CUTOFF_CURR,
 	FG_SRAM_DELTA_MSOC_THR,
 	FG_SRAM_DELTA_BSOC_THR,
 	FG_SRAM_RECHARGE_SOC_THR,
@@ -262,6 +270,7 @@
 	int	chg_term_curr_ma;
 	int	chg_term_base_curr_ma;
 	int	sys_term_curr_ma;
+	int	cutoff_curr_ma;
 	int	delta_soc_thr;
 	int	recharge_soc_thr;
 	int	recharge_volt_thr_mv;
@@ -444,6 +453,7 @@
 	enum slope_limit_status	slope_limit_sts;
 	bool			profile_available;
 	bool			profile_loaded;
+	enum prof_load_status	profile_load_status;
 	bool			battery_missing;
 	bool			fg_restarting;
 	bool			charge_full;
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
new file mode 100644
index 0000000..441c759
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/qg-profile.h>
+#include "qg-profile-lib.h"
+#include "qg-defs.h"
+
+struct qg_battery_data {
+	/* battery-data class node */
+	dev_t				dev_no;
+	struct class			*battery_class;
+	struct device			*battery_device;
+	struct cdev			battery_cdev;
+
+	/* profile */
+	struct device_node		*profile_node;
+	struct profile_table_data	profile[TABLE_MAX];
+};
+
+struct tables {
+	int table_index;
+	char *table_name;
+};
+
+static struct tables table[] = {
+	{TABLE_SOC_OCV1, "qcom,pc-temp-v1-lut"},
+	{TABLE_SOC_OCV2, "qcom,pc-temp-v2-lut"},
+	{TABLE_FCC1, "qcom,fcc1-temp-lut"},
+	{TABLE_FCC2, "qcom,fcc2-temp-lut"},
+	{TABLE_Z1, "qcom,pc-temp-z1-lut"},
+	{TABLE_Z2, "qcom,pc-temp-z2-lut"},
+	{TABLE_Z3, "qcom,pc-temp-z3-lut"},
+	{TABLE_Z4, "qcom,pc-temp-z4-lut"},
+	{TABLE_Z5, "qcom,pc-temp-z5-lut"},
+	{TABLE_Z6, "qcom,pc-temp-z6-lut"},
+	{TABLE_Y1, "qcom,pc-temp-y1-lut"},
+	{TABLE_Y2, "qcom,pc-temp-y2-lut"},
+	{TABLE_Y3, "qcom,pc-temp-y3-lut"},
+	{TABLE_Y4, "qcom,pc-temp-y4-lut"},
+	{TABLE_Y5, "qcom,pc-temp-y5-lut"},
+	{TABLE_Y6, "qcom,pc-temp-y6-lut"},
+};
+
+static struct qg_battery_data *the_battery;
+
+static int qg_battery_data_open(struct inode *inode, struct file *file)
+{
+	struct qg_battery_data *battery = container_of(inode->i_cdev,
+				struct qg_battery_data, battery_cdev);
+
+	file->private_data = battery;
+
+	return 0;
+}
+
+static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
+						unsigned long arg)
+{
+	struct qg_battery_data *battery = file->private_data;
+	struct battery_params __user *bp_user =
+				(struct battery_params __user *)arg;
+	struct battery_params bp;
+	int rc = 0, soc, ocv_uv, fcc_mah, var, slope;
+
+	if (!battery->profile_node) {
+		pr_err("Battery data not set!\n");
+		return -EINVAL;
+	}
+
+	if (!bp_user) {
+		pr_err("Invalid battery-params user pointer\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&bp, bp_user, sizeof(bp))) {
+		pr_err("Failed in copy_from_user\n");
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case BPIOCXSOC:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for SOC-OCV lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			/* OCV is passed as deci-uV  - 10^-4 V */
+			soc = interpolate_soc(&battery->profile[bp.table_index],
+					bp.batt_temp, UV_TO_DECIUV(bp.ocv_uv));
+			soc = CAP(QG_MIN_SOC, QG_MAX_SOC, soc);
+			rc = put_user(soc, &bp_user->soc);
+			if (rc < 0) {
+				pr_err("BPIOCXSOC: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXSOC: lut=%s ocv=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.ocv_uv, bp.batt_temp, soc);
+		}
+		break;
+	case BPIOCXOCV:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for SOC-OCV lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			ocv_uv = interpolate_var(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			ocv_uv = DECIUV_TO_UV(ocv_uv);
+			ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv);
+			rc = put_user(ocv_uv, &bp_user->ocv_uv);
+			if (rc < 0) {
+				pr_err("BPIOCXOCV: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXOCV: lut=%s ocv=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					ocv_uv, bp.batt_temp, bp.soc);
+		}
+		break;
+	case BPIOCXFCC:
+		if (bp.table_index != TABLE_FCC1 &&
+				bp.table_index != TABLE_FCC2) {
+			pr_err("Invalid table index %d for FCC lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			fcc_mah = interpolate_single_row_lut(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, DEGC_SCALE);
+			fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
+			rc = put_user(fcc_mah, &bp_user->fcc_mah);
+			if (rc) {
+				pr_err("BPIOCXFCC: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXFCC: lut=%s batt_temp=%d fcc_mah=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.batt_temp, fcc_mah);
+		}
+		break;
+	case BPIOCXVAR:
+		if (bp.table_index < TABLE_Z1 || bp.table_index >= TABLE_MAX) {
+			pr_err("Invalid table index %d for VAR lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			var = interpolate_var(&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			var = CAP(QG_MIN_VAR, QG_MAX_VAR, var);
+			rc = put_user(var, &bp_user->var);
+			if (rc < 0) {
+				pr_err("BPIOCXVAR: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXVAR: lut=%s var=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					var, bp.batt_temp, bp.soc);
+		}
+		break;
+	case BPIOCXSLOPE:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for Slope lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			slope = interpolate_slope(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			slope = CAP(QG_MIN_SLOPE, QG_MAX_SLOPE, slope);
+			rc = put_user(slope, &bp_user->slope);
+			if (rc) {
+				pr_err("BPIOCXSLOPE: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXSLOPE: lut=%s soc=%d batt_temp=%d slope=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.soc, bp.batt_temp, slope);
+		}
+		break;
+	default:
+		pr_err("IOCTL %d not supported\n", cmd);
+		rc = -EINVAL;
+	}
+ret_err:
+	return rc;
+}
+
+static int qg_battery_data_release(struct inode *inode, struct file *file)
+{
+	pr_debug("battery_data device closed\n");
+
+	return 0;
+}
+
+static const struct file_operations qg_battery_data_fops = {
+	.owner = THIS_MODULE,
+	.open = qg_battery_data_open,
+	.unlocked_ioctl = qg_battery_data_ioctl,
+	.compat_ioctl = qg_battery_data_ioctl,
+	.release = qg_battery_data_release,
+};
+
+static int get_length(struct device_node *node,
+			int *length, char *prop_name, bool ignore_null)
+{
+	struct property *prop;
+
+	prop = of_find_property(node, prop_name, NULL);
+	if (!prop) {
+		if (ignore_null) {
+			*length = 1;
+			return 0;
+		}
+		pr_err("Failed to find %s property\n", prop_name);
+		return -ENODATA;
+	} else if (!prop->value) {
+		pr_err("Failed to find value for %s property\n", prop_name);
+		return -ENODATA;
+	}
+
+	*length = prop->length / sizeof(u32);
+
+	return 0;
+}
+
+static int qg_parse_battery_profile(struct qg_battery_data *battery)
+{
+	int i, j, k, rows = 0, cols = 0, lut_length = 0, rc = 0;
+	struct device_node *node;
+	struct property *prop;
+	const __be32 *data;
+
+	for (i = 0; i < TABLE_MAX; i++) {
+		node = of_find_node_by_name(battery->profile_node,
+						table[i].table_name);
+		if (!node) {
+			pr_err("%s table not found\n", table[i].table_name);
+			rc = -ENODEV;
+			goto cleanup;
+		}
+
+		rc = get_length(node, &cols, "qcom,lut-col-legend", false);
+		if (rc < 0) {
+			pr_err("Failed to get col-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		rc = get_length(node, &rows, "qcom,lut-row-legend", true);
+		if (rc < 0) {
+			pr_err("Failed to get row-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		rc = get_length(node, &lut_length, "qcom,lut-data", false);
+		if (rc < 0) {
+			pr_err("Failed to get lut-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		if (lut_length != cols * rows) {
+			pr_err("Invalid lut-length for %s table\n",
+					table[i].table_name);
+			rc = -EINVAL;
+			goto cleanup;
+		}
+
+		battery->profile[i].name = kzalloc(strlen(table[i].table_name)
+						+ 1, GFP_KERNEL);
+		if (!battery->profile[i].name) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		strlcpy(battery->profile[i].name, table[i].table_name,
+						strlen(table[i].table_name));
+		battery->profile[i].rows = rows;
+		battery->profile[i].cols = cols;
+
+		if (rows != 1) {
+			battery->profile[i].row_entries = kcalloc(rows,
+				sizeof(*battery->profile[i].row_entries),
+				GFP_KERNEL);
+			if (!battery->profile[i].row_entries) {
+				rc = -ENOMEM;
+				goto cleanup;
+			}
+		}
+
+		battery->profile[i].col_entries = kcalloc(cols,
+				sizeof(*battery->profile[i].col_entries),
+				GFP_KERNEL);
+		if (!battery->profile[i].col_entries) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		battery->profile[i].data = kcalloc(rows,
+				sizeof(*battery->profile[i].data), GFP_KERNEL);
+		if (!battery->profile[i].data) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		for (j = 0; j < rows; j++) {
+			battery->profile[i].data[j] = kcalloc(cols,
+				sizeof(**battery->profile[i].data),
+				GFP_KERNEL);
+			if (!battery->profile[i].data[j]) {
+				rc = -ENOMEM;
+				goto cleanup;
+			}
+		}
+
+		/* read profile data */
+		rc = of_property_read_u32_array(node, "qcom,lut-col-legend",
+					battery->profile[i].col_entries, cols);
+		if (rc < 0) {
+			pr_err("Failed to read cols values for table %s rc=%d\n",
+					table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		if (rows != 1) {
+			rc = of_property_read_u32_array(node,
+					"qcom,lut-row-legend",
+					battery->profile[i].row_entries, rows);
+			if (rc < 0) {
+				pr_err("Failed to read row values for table %s rc=%d\n",
+						table[i].table_name, rc);
+				goto cleanup;
+			}
+		}
+
+		prop = of_find_property(node, "qcom,lut-data", NULL);
+		if (!prop) {
+			pr_err("Failed to find lut-data\n");
+			rc = -EINVAL;
+			goto cleanup;
+		}
+		data = prop->value;
+		for (j = 0; j < rows; j++) {
+			for (k = 0; k < cols; k++)
+				battery->profile[i].data[j][k] =
+						be32_to_cpup(data++);
+		}
+
+		pr_debug("Profile table %s parsed rows=%d cols=%d\n",
+			battery->profile[i].name, battery->profile[i].rows,
+			battery->profile[i].cols);
+	}
+
+	return 0;
+
+cleanup:
+	for (; i >= 0; i++) {
+		kfree(battery->profile[i].name);
+		kfree(battery->profile[i].row_entries);
+		kfree(battery->profile[i].col_entries);
+		for (j = 0; j < battery->profile[i].rows; j++) {
+			if (battery->profile[i].data)
+				kfree(battery->profile[i].data[j]);
+		}
+		kfree(battery->profile[i].data);
+	}
+	return rc;
+}
+
+int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging)
+{
+	u8 table_index = charging ? TABLE_SOC_OCV1 : TABLE_SOC_OCV2;
+
+	if (!the_battery || !the_battery->profile) {
+		pr_err("Battery profile not loaded\n");
+		return -ENODEV;
+	}
+
+	*soc = interpolate_soc(&the_battery->profile[table_index],
+				batt_temp, UV_TO_DECIUV(ocv_uv));
+
+	*soc = CAP(0, 100, DIV_ROUND_CLOSEST(*soc, 100));
+
+	return 0;
+}
+
+int qg_batterydata_init(struct device_node *profile_node)
+{
+	int rc = 0;
+	struct qg_battery_data *battery;
+
+	battery = kzalloc(sizeof(*battery), GFP_KERNEL);
+	if (!battery)
+		return -ENOMEM;
+
+	battery->profile_node = profile_node;
+
+	/* char device to access battery-profile data */
+	rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qg_battery");
+	if (rc < 0) {
+		pr_err("Failed to allocate chrdev rc=%d\n", rc);
+		goto free_battery;
+	}
+
+	cdev_init(&battery->battery_cdev, &qg_battery_data_fops);
+	rc = cdev_add(&battery->battery_cdev, battery->dev_no, 1);
+	if (rc) {
+		pr_err("Failed to add battery_cdev rc=%d\n", rc);
+		goto unregister_chrdev;
+	}
+
+	battery->battery_class = class_create(THIS_MODULE, "qg_battery");
+	if (IS_ERR_OR_NULL(battery->battery_class)) {
+		pr_err("Failed to create qg-battery class\n");
+		rc = -ENODEV;
+		goto delete_cdev;
+	}
+
+	battery->battery_device = device_create(battery->battery_class,
+					NULL, battery->dev_no,
+					NULL, "qg_battery");
+	if (IS_ERR_OR_NULL(battery->battery_device)) {
+		pr_err("Failed to create battery_device device\n");
+		rc = -ENODEV;
+		goto delete_cdev;
+	}
+
+	/* parse the battery profile */
+	rc = qg_parse_battery_profile(battery);
+	if (rc < 0) {
+		pr_err("Failed to parse battery profile rc=%d\n", rc);
+		goto destroy_device;
+	}
+
+	the_battery = battery;
+
+	pr_info("QG Battery-profile loaded, '/dev/qg_battery' created!\n");
+
+	return 0;
+
+destroy_device:
+	device_destroy(battery->battery_class, battery->dev_no);
+delete_cdev:
+	cdev_del(&battery->battery_cdev);
+unregister_chrdev:
+	unregister_chrdev_region(battery->dev_no, 1);
+free_battery:
+	kfree(battery);
+	return rc;
+}
+
+void qg_batterydata_exit(void)
+{
+	int i, j;
+
+	if (the_battery) {
+		/* unregister the device node */
+		device_destroy(the_battery->battery_class, the_battery->dev_no);
+		cdev_del(&the_battery->battery_cdev);
+		unregister_chrdev_region(the_battery->dev_no, 1);
+
+		/* delete all the battery profile memory */
+		for (i = 0; i < TABLE_MAX; i++) {
+			kfree(the_battery->profile[i].name);
+			kfree(the_battery->profile[i].row_entries);
+			kfree(the_battery->profile[i].col_entries);
+			for (j = 0; j < the_battery->profile[i].rows; j++) {
+				if (the_battery->profile[i].data)
+					kfree(the_battery->profile[i].data[j]);
+			}
+			kfree(the_battery->profile[i].data);
+		}
+	}
+
+	kfree(the_battery);
+	the_battery = NULL;
+}
diff --git a/drivers/power/supply/qcom/qg-battery-profile.h b/drivers/power/supply/qcom/qg-battery-profile.h
new file mode 100644
index 0000000..143a4f2
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-battery-profile.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_BATTERY_PROFILE_H__
+#define __QG_BATTERY_PROFILE_H__
+
+int qg_batterydata_init(struct device_node *node);
+void qg_batterydata_exit(void);
+int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging);
+
+#endif /* __QG_BATTERY_PROFILE_H__ */
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
new file mode 100644
index 0000000..5ea9b78
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -0,0 +1,151 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_CORE_H__
+#define __QG_CORE_H__
+
+struct qg_batt_props {
+	const char		*batt_type_str;
+	int			float_volt_uv;
+	int			vbatt_full_mv;
+	int			fastchg_curr_ma;
+	int			qg_profile_version;
+};
+
+struct qg_irq_info {
+	const char		*name;
+	const irq_handler_t	handler;
+	const bool		wake;
+	int			irq;
+};
+
+struct qg_dt {
+	int			vbatt_empty_mv;
+	int			vbatt_low_mv;
+	int			vbatt_cutoff_mv;
+	int			iterm_ma;
+	int			s2_fifo_length;
+	int			s2_vbat_low_fifo_length;
+	int			s2_acc_length;
+	int			s2_acc_intvl_ms;
+	int			ocv_timer_expiry_min;
+	int			ocv_tol_threshold_uv;
+	int			s3_entry_fifo_length;
+	int			s3_entry_ibat_ua;
+	int			s3_exit_ibat_ua;
+	int			delta_soc;
+	int			rbat_conn_mohm;
+	int			ignore_shutdown_soc_secs;
+	bool			hold_soc_while_full;
+	bool			linearize_soc;
+};
+
+struct qpnp_qg {
+	struct device		*dev;
+	struct pmic_revid_data	*pmic_rev_id;
+	struct regmap		*regmap;
+	struct qpnp_vadc_chip	*vadc_dev;
+	struct power_supply	*qg_psy;
+	struct class		*qg_class;
+	struct device		*qg_device;
+	struct cdev		qg_cdev;
+	dev_t			dev_no;
+	struct work_struct	udata_work;
+	struct work_struct	scale_soc_work;
+	struct work_struct	qg_status_change_work;
+	struct notifier_block	nb;
+	struct mutex		bus_lock;
+	struct mutex		data_lock;
+	struct mutex		soc_lock;
+	wait_queue_head_t	qg_wait_q;
+	struct votable		*awake_votable;
+	struct votable		*vbatt_irq_disable_votable;
+	struct votable		*fifo_irq_disable_votable;
+	struct votable		*good_ocv_irq_disable_votable;
+	u32			qg_base;
+
+	/* local data variables */
+	u32			batt_id_ohm;
+	struct qg_kernel_data	kdata;
+	struct qg_user_data	udata;
+	struct power_supply	*batt_psy;
+	struct power_supply	*usb_psy;
+	struct power_supply	*parallel_psy;
+
+	/* status variable */
+	u32			*debug_mask;
+	bool			qg_device_open;
+	bool			profile_loaded;
+	bool			battery_missing;
+	bool			data_ready;
+	bool			suspend_data;
+	bool			vbat_low;
+	bool			charge_done;
+	bool			parallel_enabled;
+	bool			usb_present;
+	bool			charge_full;
+	int			charge_status;
+	int			charge_type;
+	int			next_wakeup_ms;
+	u32			wa_flags;
+	u32			seq_no;
+	u32			charge_counter_uah;
+	ktime_t			last_user_update_time;
+	ktime_t			last_fifo_update_time;
+
+	/* soc params */
+	int			catch_up_soc;
+	int			maint_soc;
+	int			msoc;
+	int			pon_soc;
+	struct alarm		alarm_timer;
+	u32			sdam_data[SDAM_MAX];
+
+	/* DT */
+	struct qg_dt		dt;
+	struct qg_batt_props	bp;
+};
+
+enum ocv_type {
+	PON_OCV,
+	GOOD_OCV,
+};
+
+enum debug_mask {
+	QG_DEBUG_PON		= BIT(0),
+	QG_DEBUG_PROFILE	= BIT(1),
+	QG_DEBUG_DEVICE		= BIT(2),
+	QG_DEBUG_STATUS		= BIT(3),
+	QG_DEBUG_FIFO		= BIT(4),
+	QG_DEBUG_IRQ		= BIT(5),
+	QG_DEBUG_SOC		= BIT(6),
+	QG_DEBUG_PM		= BIT(7),
+	QG_DEBUG_BUS_READ	= BIT(8),
+	QG_DEBUG_BUS_WRITE	= BIT(9),
+};
+
+enum qg_irq {
+	QG_BATT_MISSING_IRQ,
+	QG_VBATT_LOW_IRQ,
+	QG_VBATT_EMPTY_IRQ,
+	QG_FIFO_UPDATE_DONE_IRQ,
+	QG_GOOD_OCV_IRQ,
+	QG_FSM_STAT_CHG_IRQ,
+	QG_EVENT_IRQ,
+	QG_MAX_IRQ,
+};
+
+enum qg_wa_flags {
+	QG_VBAT_LOW_WA = BIT(0),
+};
+
+
+#endif /* __QG_CORE_H__ */
diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h
new file mode 100644
index 0000000..bbbc7ee
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-defs.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_DEFS_H__
+#define __QG_DEFS_H__
+
+#define qg_dbg(chip, reason, fmt, ...)			\
+	do {							\
+		if (*chip->debug_mask & (reason))		\
+			pr_info(fmt, ##__VA_ARGS__);	\
+		else						\
+			pr_debug(fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#define is_between(left, right, value) \
+		(((left) >= (right) && (left) >= (value) \
+			&& (value) >= (right)) \
+		|| ((left) <= (right) && (left) <= (value) \
+			&& (value) <= (right)))
+
+#define UDATA_READY_VOTER		"UDATA_READY_VOTER"
+#define FIFO_DONE_VOTER			"FIFO_DONE_VOTER"
+#define FIFO_RT_DONE_VOTER		"FIFO_RT_DONE_VOTER"
+#define SUSPEND_DATA_VOTER		"SUSPEND_DATA_VOTER"
+#define GOOD_OCV_VOTER			"GOOD_OCV_VOTER"
+#define PROFILE_IRQ_DISABLE		"NO_PROFILE_IRQ_DISABLE"
+#define QG_INIT_STATE_IRQ_DISABLE	"QG_INIT_STATE_IRQ_DISABLE"
+
+#define V_RAW_TO_UV(V_RAW)		div_u64(194637ULL * (u64)V_RAW, 1000)
+#define I_RAW_TO_UA(I_RAW)		div_s64(152588LL * (s64)I_RAW, 1000)
+
+#define DEGC_SCALE			10
+#define UV_TO_DECIUV(a)			(a / 100)
+#define DECIUV_TO_UV(a)			(a * 100)
+
+#define CAP(min, max, value)			\
+		((min > value) ? min : ((value > max) ? max : value))
+
+#endif /* __QG_DEFS_H__ */
diff --git a/drivers/power/supply/qcom/qg-profile-lib.c b/drivers/power/supply/qcom/qg-profile-lib.c
new file mode 100644
index 0000000..2af997e
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-profile-lib.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include "qg-profile-lib.h"
+#include "qg-defs.h"
+
+static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+int interpolate_single_row_lut(struct profile_table_data *lut,
+						int x, int scale)
+{
+	int i, result;
+	int cols = lut->cols;
+
+	if (x < lut->col_entries[0] * scale) {
+		pr_debug("x %d less than known range return y = %d lut = %s\n",
+					x, lut->data[0][0], lut->name);
+		return lut->data[0][0];
+	}
+
+	if (x > lut->col_entries[cols-1] * scale) {
+		pr_debug("x %d more than known range return y = %d lut = %s\n",
+					x, lut->data[0][cols-1], lut->name);
+		return lut->data[0][cols-1];
+	}
+
+	for (i = 0; i < cols; i++) {
+		if (x <= lut->col_entries[i] * scale)
+			break;
+	}
+
+	if (x == lut->col_entries[i] * scale) {
+		result = lut->data[0][i];
+	} else {
+		result = linear_interpolate(
+			lut->data[0][i-1],
+			lut->col_entries[i-1] * scale,
+			lut->data[0][i],
+			lut->col_entries[i] * scale,
+			x);
+	}
+
+	return result;
+}
+
+int interpolate_soc(struct profile_table_data *lut,
+				int batt_temp, int ocv)
+{
+	int i, j, soc_high, soc_low, soc;
+	int rows = lut->rows;
+	int cols = lut->cols;
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp);
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	}
+
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp);
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+	}
+
+	for (j = 0; j < cols; j++)
+		if (batt_temp <= lut->col_entries[j] * DEGC_SCALE)
+			break;
+
+	if (batt_temp == lut->col_entries[j] * DEGC_SCALE) {
+		/* found an exact match for temp in the table */
+		if (ocv >= lut->data[0][j])
+			return lut->row_entries[0];
+		if (ocv <= lut->data[rows - 1][j])
+			return lut->row_entries[rows - 1];
+		for (i = 0; i < rows; i++) {
+			if (ocv >= lut->data[i][j]) {
+				if (ocv == lut->data[i][j])
+					return lut->row_entries[i];
+				soc = linear_interpolate(
+					lut->row_entries[i],
+					lut->data[i][j],
+					lut->row_entries[i - 1],
+					lut->data[i - 1][j],
+					ocv);
+				return soc;
+			}
+		}
+	}
+
+	/* batt_temp is within temperature for column j-1 and j */
+	if (ocv >= lut->data[0][j])
+		return lut->row_entries[0];
+	if (ocv <= lut->data[rows - 1][j - 1])
+		return lut->row_entries[rows - 1];
+
+	soc_low = soc_high = 0;
+	for (i = 0; i < rows-1; i++) {
+		if (soc_high == 0 && is_between(lut->data[i][j],
+				lut->data[i+1][j], ocv)) {
+			soc_high = linear_interpolate(
+				lut->row_entries[i],
+				lut->data[i][j],
+				lut->row_entries[i + 1],
+				lut->data[i+1][j],
+				ocv);
+		}
+
+		if (soc_low == 0 && is_between(lut->data[i][j-1],
+				lut->data[i+1][j-1], ocv)) {
+			soc_low = linear_interpolate(
+				lut->row_entries[i],
+				lut->data[i][j-1],
+				lut->row_entries[i + 1],
+				lut->data[i+1][j-1],
+				ocv);
+		}
+
+		if (soc_high && soc_low) {
+			soc = linear_interpolate(
+				soc_low,
+				lut->col_entries[j-1] * DEGC_SCALE,
+				soc_high,
+				lut->col_entries[j] * DEGC_SCALE,
+				batt_temp);
+			return soc;
+		}
+	}
+
+	if (soc_high)
+		return soc_high;
+
+	if (soc_low)
+		return soc_low;
+
+	pr_debug("%d ocv wasn't found for temp %d in the LUT %s returning 100%%\n",
+						ocv, batt_temp, lut->name);
+	return 10000;
+}
+
+int interpolate_var(struct profile_table_data *lut,
+				int batt_temp, int soc)
+{
+	int i, var1, var2, var, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = lut->rows;
+	cols = lut->cols;
+	if (soc > lut->row_entries[0]) {
+		pr_debug("soc %d greater than known soc ranges for %s lut\n",
+							soc, lut->name);
+		row1 = 0;
+		row2 = 0;
+	} else if (soc < lut->row_entries[rows - 1]) {
+		pr_debug("soc %d less than known soc ranges for %s lut\n",
+							soc, lut->name);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (soc == lut->row_entries[i]) {
+				row1 = i;
+				row2 = i;
+				break;
+			}
+			if (soc > lut->row_entries[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
+		}
+	}
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
+			break;
+
+	if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
+		var = linear_interpolate(
+				lut->data[row1][i],
+				lut->row_entries[row1],
+				lut->data[row2][i],
+				lut->row_entries[row2],
+				soc);
+		return var;
+	}
+
+	var1 = linear_interpolate(
+				lut->data[row1][i - 1],
+				lut->col_entries[i - 1] * DEGC_SCALE,
+				lut->data[row1][i],
+				lut->col_entries[i] * DEGC_SCALE,
+				batt_temp);
+
+	var2 = linear_interpolate(
+				lut->data[row2][i - 1],
+				lut->col_entries[i - 1] * DEGC_SCALE,
+				lut->data[row2][i],
+				lut->col_entries[i] * DEGC_SCALE,
+				batt_temp);
+
+	var = linear_interpolate(
+				var1,
+				lut->row_entries[row1],
+				var2,
+				lut->row_entries[row2],
+				soc);
+
+	return var;
+}
+
+int interpolate_slope(struct profile_table_data *lut,
+					int batt_temp, int soc)
+{
+	int i, ocvrow1, ocvrow2, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+	int slope;
+
+	rows = lut->rows;
+	cols = lut->cols;
+	if (soc >= lut->row_entries[0]) {
+		pr_debug("soc %d >= max soc range - use the slope at soc=%d for lut %s\n",
+					soc, lut->row_entries[0], lut->name);
+		row1 = 0;
+		row2 = 1;
+	} else if (soc <= lut->row_entries[rows - 1]) {
+		pr_debug("soc %d is <= min soc range - use the slope at soc=%d for lut %s\n",
+				soc, lut->row_entries[rows - 1], lut->name);
+		row1 = rows - 2;
+		row2 = rows - 1;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (soc >= lut->row_entries[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
+		}
+	}
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+
+	for (i = 0; i < cols; i++) {
+		if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
+			break;
+	}
+
+	if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
+		slope = (lut->data[row1][i] - lut->data[row2][i]);
+		if (slope <= 0) {
+			pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
+							slope, soc);
+			slope = 1;
+		}
+		slope *= 10000;
+		slope /= (lut->row_entries[row1] -
+			lut->row_entries[row2]);
+		return slope;
+	}
+	ocvrow1 = linear_interpolate(
+			lut->data[row1][i - 1],
+			lut->col_entries[i - 1] * DEGC_SCALE,
+			lut->data[row1][i],
+			lut->col_entries[i] * DEGC_SCALE,
+			batt_temp);
+
+	ocvrow2 = linear_interpolate(
+			lut->data[row2][i - 1],
+			lut->col_entries[i - 1] * DEGC_SCALE,
+			lut->data[row2][i],
+			lut->col_entries[i] * DEGC_SCALE,
+			batt_temp);
+
+	slope = (ocvrow1 - ocvrow2);
+	if (slope <= 0) {
+		pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
+							slope, soc);
+		slope = 1;
+	}
+	slope *= 10000;
+	slope /= (lut->row_entries[row1] - lut->row_entries[row2]);
+
+	return slope;
+}
diff --git a/drivers/power/supply/qcom/qg-profile-lib.h b/drivers/power/supply/qcom/qg-profile-lib.h
new file mode 100644
index 0000000..eb7263d
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-profile-lib.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_PROFILE_LIB_H__
+#define __QG_PROFILE_LIB_H__
+
+struct profile_table_data {
+	char		*name;
+	int		rows;
+	int		cols;
+	int		*row_entries;
+	int		*col_entries;
+	int		**data;
+};
+
+int interpolate_single_row_lut(struct profile_table_data *lut,
+						int x, int scale);
+int interpolate_soc(struct profile_table_data *lut,
+				int batt_temp, int ocv);
+int interpolate_var(struct profile_table_data *lut,
+				int batt_temp, int soc);
+int interpolate_slope(struct profile_table_data *lut,
+				int batt_temp, int soc);
+
+#endif /*__QG_PROFILE_LIB_H__ */
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
new file mode 100644
index 0000000..1f42a8c
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_REG_H__
+#define __QG_REG_H__
+
+#define PERPH_TYPE_REG				0x04
+#define QG_TYPE					0x0D
+
+#define QG_STATUS1_REG				0x08
+#define BATTERY_PRESENT_BIT			BIT(0)
+
+#define QG_STATUS2_REG				0x09
+#define GOOD_OCV_BIT				BIT(1)
+
+#define QG_STATUS3_REG				0x0A
+#define COUNT_FIFO_RT_MASK			GENMASK(3, 0)
+
+#define QG_INT_RT_STS_REG			0x10
+#define FIFO_UPDATE_DONE_RT_STS_BIT		BIT(3)
+#define VBAT_LOW_INT_RT_STS_BIT			BIT(1)
+
+#define QG_INT_LATCHED_STS_REG			0x18
+#define FIFO_UPDATE_DONE_INT_LAT_STS_BIT	BIT(3)
+
+#define QG_DATA_CTL1_REG			0x41
+#define MASTER_HOLD_OR_CLR_BIT			BIT(0)
+
+#define QG_MODE_CTL1_REG			0x43
+#define PARALLEL_IBAT_SENSE_EN_BIT		BIT(7)
+
+#define QG_VBAT_EMPTY_THRESHOLD_REG		0x4B
+#define QG_VBAT_LOW_THRESHOLD_REG		0x4C
+
+#define QG_S2_NORMAL_MEAS_CTL2_REG		0x51
+#define FIFO_LENGTH_MASK			GENMASK(5, 3)
+#define FIFO_LENGTH_SHIFT			3
+#define NUM_OF_ACCUM_MASK			GENMASK(2, 0)
+
+#define QG_S2_NORMAL_MEAS_CTL3_REG		0x52
+
+#define QG_S3_SLEEP_OCV_MEAS_CTL4_REG		0x59
+#define S3_SLEEP_OCV_TIMER_MASK			GENMASK(2, 0)
+
+#define QG_S3_SLEEP_OCV_TREND_CTL2_REG		0x5C
+#define TREND_TOL_MASK				GENMASK(5, 0)
+
+#define QG_S3_SLEEP_OCV_IBAT_CTL1_REG		0x5D
+#define SLEEP_IBAT_QUALIFIED_LENGTH_MASK	GENMASK(2, 0)
+
+#define QG_S3_ENTRY_IBAT_THRESHOLD_REG		0x5E
+#define QG_S3_EXIT_IBAT_THRESHOLD_REG		0x5F
+
+#define QG_S7_PON_OCV_V_DATA0_REG		0x70
+#define QG_S7_PON_OCV_I_DATA0_REG		0x72
+#define QG_S3_GOOD_OCV_V_DATA0_REG		0x74
+#define QG_S3_GOOD_OCV_I_DATA0_REG		0x76
+
+#define QG_V_ACCUM_DATA0_RT_REG			0x88
+#define QG_I_ACCUM_DATA0_RT_REG			0x8B
+#define QG_ACCUM_CNT_RT_REG			0x8E
+
+#define QG_V_FIFO0_DATA0_REG			0x90
+#define QG_I_FIFO0_DATA0_REG			0xA0
+
+#define QG_SOC_MONOTONIC_REG			0xBF
+
+#define QG_LAST_ADC_V_DATA0_REG			0xC0
+#define QG_LAST_ADC_I_DATA0_REG			0xC2
+
+/* SDAM offsets */
+#define QG_SDAM_VALID_OFFSET			0x46
+#define QG_SDAM_SOC_OFFSET			0x47
+#define QG_SDAM_TEMP_OFFSET			0x48
+#define QG_SDAM_RBAT_OFFSET			0x4A
+#define QG_SDAM_OCV_OFFSET			0x4C
+#define QG_SDAM_IBAT_OFFSET			0x50
+#define QG_SDAM_TIME_OFFSET			0x54
+
+#endif
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
new file mode 100644
index 0000000..65bebab
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -0,0 +1,219 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include "qg-sdam.h"
+#include "qg-reg.h"
+
+static struct qg_sdam *the_chip;
+
+struct qg_sdam_info {
+	char		*name;
+	u32		offset;
+	u32		length;
+};
+
+static struct qg_sdam_info sdam_info[] = {
+	[SDAM_VALID] = {
+		.name	= "VALID",
+		.offset = QG_SDAM_VALID_OFFSET,
+		.length = 1,
+	},
+	[SDAM_SOC] = {
+		.name	= "SOC",
+		.offset = QG_SDAM_SOC_OFFSET,
+		.length = 1,
+	},
+	[SDAM_TEMP] = {
+		.name	= "BATT_TEMP",
+		.offset = QG_SDAM_TEMP_OFFSET,
+		.length = 2,
+	},
+	[SDAM_RBAT_MOHM] = {
+		.name	= "RBAT_MOHM",
+		.offset = QG_SDAM_RBAT_OFFSET,
+		.length = 2,
+	},
+	[SDAM_OCV_UV] = {
+		.name	= "OCV_UV",
+		.offset = QG_SDAM_OCV_OFFSET,
+		.length = 4,
+	},
+	[SDAM_IBAT_UA] = {
+		.name	= "IBAT_UA",
+		.offset = QG_SDAM_IBAT_OFFSET,
+		.length = 4,
+	},
+	[SDAM_TIME_SEC] = {
+		.name	= "TIME_SEC",
+		.offset = QG_SDAM_TIME_OFFSET,
+		.length = 4,
+	},
+};
+
+int qg_sdam_write(u8 param, u32 data)
+{
+	int rc;
+	struct qg_sdam *chip = the_chip;
+	u32 offset;
+	size_t length;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	if (param >= SDAM_MAX) {
+		pr_err("Invalid SDAM param %d\n", param);
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + sdam_info[param].offset;
+	length = sdam_info[param].length;
+	rc = regmap_bulk_write(chip->regmap, offset, (u8 *)&data, length);
+	if (rc < 0)
+		pr_err("Failed to write offset=%0x4x param=%d value=%d\n",
+					offset, param, data);
+	else
+		pr_debug("QG SDAM write param=%s value=%d\n",
+					sdam_info[param].name, data);
+
+	return rc;
+}
+
+int qg_sdam_read(u8 param, u32 *data)
+{
+	int rc;
+	struct qg_sdam *chip = the_chip;
+	u32 offset;
+	size_t length;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	if (param >= SDAM_MAX) {
+		pr_err("Invalid SDAM param %d\n", param);
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + sdam_info[param].offset;
+	length = sdam_info[param].length;
+	rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, length);
+	if (rc < 0)
+		pr_err("Failed to read offset=%0x4x param=%d\n",
+					offset, param);
+	else
+		pr_debug("QG SDAM read param=%s value=%d\n",
+				sdam_info[param].name, *data);
+
+	return rc;
+}
+
+int qg_sdam_read_all(u32 *sdam_data)
+{
+	int i, rc;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SDAM_MAX; i++) {
+		rc = qg_sdam_read(i, &sdam_data[i]);
+		if (rc < 0) {
+			pr_err("Failed to read SDAM param=%s rc=%d\n",
+					sdam_info[i].name, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int qg_sdam_write_all(u32 *sdam_data)
+{
+	int i, rc;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SDAM_MAX; i++) {
+		rc = qg_sdam_write(i, sdam_data[i]);
+		if (rc < 0) {
+			pr_err("Failed to write SDAM param=%s rc=%d\n",
+					sdam_info[i].name, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int qg_sdam_init(struct device *dev)
+{
+	int rc;
+	u32 base = 0, type = 0;
+	struct qg_sdam *chip;
+	struct device_node *child, *node = dev->of_node;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return 0;
+
+	chip->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!chip->regmap) {
+		pr_err("Parent regmap is unavailable\n");
+		return -ENXIO;
+	}
+
+	/* get the SDAM base address */
+	for_each_available_child_of_node(node, child) {
+		rc = of_property_read_u32(child, "reg", &base);
+		if (rc < 0) {
+			pr_err("Failed to read base address rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = regmap_read(chip->regmap, base + PERPH_TYPE_REG, &type);
+		if (rc < 0) {
+			pr_err("Failed to read type rc=%d\n", rc);
+			return rc;
+		}
+
+		switch (type) {
+		case SDAM_TYPE:
+			chip->sdam_base = base;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!chip->sdam_base) {
+		pr_err("QG SDAM node not defined\n");
+		return -EINVAL;
+	}
+
+	the_chip = chip;
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
new file mode 100644
index 0000000..a75ead9
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_SDAM_H__
+#define __QG_SDAM_H__
+
+#define SDAM_TYPE			0x2E
+
+enum qg_sdam_param {
+	SDAM_VALID,
+	SDAM_SOC,
+	SDAM_TEMP,
+	SDAM_RBAT_MOHM,
+	SDAM_OCV_UV,
+	SDAM_IBAT_UA,
+	SDAM_TIME_SEC,
+	SDAM_MAX,
+};
+
+struct qg_sdam {
+	struct regmap		*regmap;
+	u16			sdam_base;
+};
+
+int qg_sdam_init(struct device *dev);
+int qg_sdam_write(u8 param, u32 data);
+int qg_sdam_read(u8 param, u32 *data);
+int qg_sdam_write_all(u32 *sdam_data);
+int qg_sdam_read_all(u32 *sdam_data);
+
+#endif
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
new file mode 100644
index 0000000..660f6f1
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/alarmtimer.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-util.h"
+#include "qg-defs.h"
+
+#define DEFAULT_UPDATE_TIME_MS			64000
+#define SOC_SCALE_HYST_MS			2000
+#define SOC_SCALE_LOW_TEMP_THRESHOLD		100
+
+static int qg_delta_soc_interval_ms = 20000;
+module_param_named(
+	delta_soc_interval_ms, qg_delta_soc_interval_ms, int, 0600
+);
+
+static void get_next_update_time(struct qpnp_qg *chip)
+{
+	int soc_points = 0, batt_temp = 0;
+	int min_delta_soc_interval_ms = qg_delta_soc_interval_ms;
+	int rc = 0, rt_time_ms = 0, full_time_ms = DEFAULT_UPDATE_TIME_MS;
+
+	get_fifo_done_time(chip, false, &full_time_ms);
+	get_fifo_done_time(chip, true, &rt_time_ms);
+
+	full_time_ms = CAP(0, DEFAULT_UPDATE_TIME_MS,
+				full_time_ms - rt_time_ms);
+
+	soc_points = abs(chip->msoc - chip->catch_up_soc);
+	if (chip->maint_soc > 0)
+		soc_points = max(abs(chip->msoc - chip->maint_soc), soc_points);
+	soc_points /= chip->dt.delta_soc;
+
+	/* Lower the delta soc interval by half at cold */
+	rc = qg_get_battery_temp(chip, &batt_temp);
+	if (rc < 0)
+		pr_err("Failed to read battery temperature rc=%d\n", rc);
+
+	if (batt_temp < SOC_SCALE_LOW_TEMP_THRESHOLD)
+		min_delta_soc_interval_ms = min_delta_soc_interval_ms / 2;
+
+	chip->next_wakeup_ms = (full_time_ms / (soc_points + 1))
+					- SOC_SCALE_HYST_MS;
+	chip->next_wakeup_ms = max(chip->next_wakeup_ms,
+				min_delta_soc_interval_ms);
+
+	qg_dbg(chip, QG_DEBUG_SOC, "fifo_full_time=%d secs fifo_real_time=%d secs soc_scale_points=%d\n",
+			full_time_ms / 1000, rt_time_ms / 1000, soc_points);
+}
+
+static bool is_scaling_required(struct qpnp_qg *chip)
+{
+	if (!chip->profile_loaded)
+		return false;
+
+	if (chip->maint_soc > 0 &&
+		(abs(chip->maint_soc - chip->msoc) >= chip->dt.delta_soc))
+		return true;
+
+	if ((abs(chip->catch_up_soc - chip->msoc) < chip->dt.delta_soc) &&
+		chip->catch_up_soc != 0 && chip->catch_up_soc != 100)
+		return false;
+
+	if (chip->catch_up_soc == chip->msoc)
+		/* SOC has not changed */
+		return false;
+
+
+	if (chip->catch_up_soc > chip->msoc && !is_usb_present(chip))
+		/* USB is not present and SOC has increased */
+		return false;
+
+	return true;
+}
+
+static void update_msoc(struct qpnp_qg *chip)
+{
+	int rc;
+
+	if (chip->catch_up_soc > chip->msoc) {
+		/* SOC increased */
+		if (is_usb_present(chip)) /* Increment if USB is present */
+			chip->msoc += chip->dt.delta_soc;
+	} else if (chip->catch_up_soc < chip->msoc) {
+		/* SOC dropped */
+		chip->msoc -= chip->dt.delta_soc;
+	}
+	chip->msoc = CAP(0, 100, chip->msoc);
+
+	if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc) {
+		chip->maint_soc -= chip->dt.delta_soc;
+		chip->maint_soc = CAP(0, 100, chip->maint_soc);
+	}
+
+	/* maint_soc dropped below msoc, skip using it */
+	if (chip->maint_soc <= chip->msoc)
+		chip->maint_soc = -EINVAL;
+
+	/* update the SOC register */
+	rc = qg_write_monotonic_soc(chip, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+	/* update SDAM with the new MSOC */
+	chip->sdam_data[SDAM_SOC] = chip->msoc;
+	rc = qg_sdam_write(SDAM_SOC, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update SDAM with MSOC rc=%d\n", rc);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: Update maint_soc=%d msoc=%d catch_up_soc=%d delta_soc=%d\n",
+				chip->maint_soc, chip->msoc,
+				chip->catch_up_soc, chip->dt.delta_soc);
+}
+
+static void scale_soc_stop(struct qpnp_qg *chip)
+{
+	chip->next_wakeup_ms = 0;
+	alarm_cancel(&chip->alarm_timer);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale stopped: msoc=%d catch_up_soc=%d\n",
+			chip->msoc, chip->catch_up_soc);
+}
+
+static void scale_soc_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, scale_soc_work);
+
+	mutex_lock(&chip->soc_lock);
+
+	if (!is_scaling_required(chip)) {
+		scale_soc_stop(chip);
+		goto done;
+	}
+
+	update_msoc(chip);
+
+	if (is_scaling_required(chip)) {
+		alarm_start_relative(&chip->alarm_timer,
+				ms_to_ktime(chip->next_wakeup_ms));
+	} else {
+		scale_soc_stop(chip);
+		goto done_psy;
+	}
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: Work msoc=%d catch_up_soc=%d delta_soc=%d next_wakeup=%d sec\n",
+			chip->msoc, chip->catch_up_soc, chip->dt.delta_soc,
+			chip->next_wakeup_ms / 1000);
+
+done_psy:
+	power_supply_changed(chip->qg_psy);
+done:
+	pm_relax(chip->dev);
+	mutex_unlock(&chip->soc_lock);
+}
+
+static enum alarmtimer_restart
+	qpnp_msoc_timer(struct alarm *alarm, ktime_t now)
+{
+	struct qpnp_qg *chip = container_of(alarm,
+				struct qpnp_qg, alarm_timer);
+
+	/* timer callback runs in atomic context, cannot use voter */
+	pm_stay_awake(chip->dev);
+	schedule_work(&chip->scale_soc_work);
+
+	return ALARMTIMER_NORESTART;
+}
+
+int qg_scale_soc(struct qpnp_qg *chip, bool force_soc)
+{
+	int rc = 0;
+
+	mutex_lock(&chip->soc_lock);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale: Start msoc=%d catch_up_soc=%d delta_soc=%d\n",
+			chip->msoc, chip->catch_up_soc, chip->dt.delta_soc);
+
+	if (force_soc) {
+		chip->msoc = chip->catch_up_soc;
+		rc = qg_write_monotonic_soc(chip, chip->msoc);
+		if (rc < 0)
+			pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+		qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale: Forced msoc=%d\n", chip->msoc);
+		goto done_psy;
+	}
+
+	if (!is_scaling_required(chip)) {
+		scale_soc_stop(chip);
+		goto done;
+	}
+
+	update_msoc(chip);
+
+	if (is_scaling_required(chip)) {
+		get_next_update_time(chip);
+		alarm_start_relative(&chip->alarm_timer,
+					ms_to_ktime(chip->next_wakeup_ms));
+	} else {
+		scale_soc_stop(chip);
+		goto done_psy;
+	}
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: msoc=%d catch_up_soc=%d delta_soc=%d next_wakeup=%d sec\n",
+			chip->msoc, chip->catch_up_soc, chip->dt.delta_soc,
+			chip->next_wakeup_ms / 1000);
+
+done_psy:
+	power_supply_changed(chip->qg_psy);
+done:
+	mutex_unlock(&chip->soc_lock);
+	return rc;
+}
+
+int qg_soc_init(struct qpnp_qg *chip)
+{
+	if (alarmtimer_get_rtcdev()) {
+		alarm_init(&chip->alarm_timer, ALARM_BOOTTIME,
+			qpnp_msoc_timer);
+	} else {
+		pr_err("Failed to get soc alarm-timer\n");
+		return -EINVAL;
+	}
+	INIT_WORK(&chip->scale_soc_work, scale_soc_work);
+
+	return 0;
+}
+
+void qg_soc_exit(struct qpnp_qg *chip)
+{
+	alarm_cancel(&chip->alarm_timer);
+}
diff --git a/drivers/power/supply/qcom/qg-soc.h b/drivers/power/supply/qcom/qg-soc.h
new file mode 100644
index 0000000..3b4eb60
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-soc.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_SOC_H__
+#define __QG_SOC_H__
+
+int qg_scale_soc(struct qpnp_qg *chip, bool force_soc);
+int qg_soc_init(struct qpnp_qg *chip);
+void qg_soc_exit(struct qpnp_qg *chip);
+
+#endif /* __QG_SOC_H__ */
diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c
new file mode 100644
index 0000000..d354799
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -0,0 +1,318 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/alarmtimer.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/power_supply.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-defs.h"
+#include "qg-util.h"
+
+static inline bool is_sticky_register(u32 addr)
+{
+	if ((addr & 0xFF) == QG_STATUS2_REG)
+		return true;
+
+	return false;
+}
+
+int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
+{
+	int rc, i;
+	u32 dummy = 0;
+
+	rc = regmap_bulk_read(chip->regmap, addr, val, len);
+	if (rc < 0) {
+		pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
+		return rc;
+	}
+
+	if (is_sticky_register(addr)) {
+		/* write to the sticky register to clear it */
+		rc = regmap_write(chip->regmap, addr, dummy);
+		if (rc < 0) {
+			pr_err("Failed regmap_write for %04x rc=%d\n",
+						addr, rc);
+			return rc;
+		}
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_READ) {
+		pr_info("length %d addr=%04x\n", len, addr);
+		for (i = 0; i < len; i++)
+			pr_info("val[%d]: %02x\n", i, val[i]);
+	}
+
+	return 0;
+}
+
+int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
+{
+	int rc, i;
+
+	mutex_lock(&chip->bus_lock);
+
+	if (len > 1)
+		rc = regmap_bulk_write(chip->regmap, addr, val, len);
+	else
+		rc = regmap_write(chip->regmap, addr, *val);
+
+	if (rc < 0) {
+		pr_err("Failed regmap_write for address %04x rc=%d\n",
+				addr, rc);
+		goto out;
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_WRITE) {
+		pr_info("length %d addr=%04x\n", len, addr);
+		for (i = 0; i < len; i++)
+			pr_info("val[%d]: %02x\n", i, val[i]);
+	}
+out:
+	mutex_unlock(&chip->bus_lock);
+	return rc;
+}
+
+int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val)
+{
+	int rc;
+
+	mutex_lock(&chip->bus_lock);
+
+	rc = regmap_update_bits(chip->regmap, addr, mask, val);
+	if (rc < 0) {
+		pr_err("Failed regmap_update_bits for address %04x rc=%d\n",
+				addr, rc);
+		goto out;
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_WRITE)
+		pr_info("addr=%04x mask: %02x val: %02x\n", addr, mask, val);
+
+out:
+	mutex_unlock(&chip->bus_lock);
+	return rc;
+}
+
+int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt)
+{
+	int rc;
+	u8 reg = 0;
+	u32 addr;
+
+	addr = rt ? QG_STATUS3_REG : QG_S2_NORMAL_MEAS_CTL2_REG;
+	rc = qg_read(chip, chip->qg_base + addr, &reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO length rc=%d\n", rc);
+		return rc;
+	}
+
+	if (rt) {
+		*fifo_length = reg & COUNT_FIFO_RT_MASK;
+	} else {
+		*fifo_length = (reg & FIFO_LENGTH_MASK) >> FIFO_LENGTH_SHIFT;
+		*fifo_length += 1;
+	}
+
+	return rc;
+}
+
+int get_sample_count(struct qpnp_qg *chip, u32 *sample_count)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO sample count rc=%d\n", rc);
+		return rc;
+	}
+
+	*sample_count = 1 << ((reg & NUM_OF_ACCUM_MASK) + 1);
+
+	return rc;
+}
+
+int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO sample interval rc=%d\n", rc);
+		return rc;
+	}
+
+	*sample_interval = reg * 10;
+
+	return rc;
+}
+
+int get_rtc_time(unsigned long *rtc_time)
+{
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	int rc;
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc == NULL) {
+		pr_err("Failed to open rtc device (%s)\n",
+				CONFIG_RTC_HCTOSYS_DEVICE);
+		return -EINVAL;
+	}
+
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Failed to read rtc time (%s) : %d\n",
+				CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto close_time;
+	}
+
+	rc = rtc_valid_tm(&tm);
+	if (rc) {
+		pr_err("Invalid RTC time (%s): %d\n",
+				CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto close_time;
+	}
+	rtc_tm_to_time(&tm, rtc_time);
+
+close_time:
+	rtc_class_close(rtc);
+	return rc;
+}
+
+int get_fifo_done_time(struct qpnp_qg *chip, bool rt, int *time_ms)
+{
+	int rc, length = 0;
+	u32 sample_count = 0, sample_interval = 0, acc_count = 0;
+
+	rc = get_fifo_length(chip, &length, rt ? true : false);
+	if (rc < 0)
+		return rc;
+
+	rc = get_sample_count(chip, &sample_count);
+	if (rc < 0)
+		return rc;
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0)
+		return rc;
+
+	*time_ms = length * sample_count * sample_interval;
+
+	if (rt) {
+		rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG,
+					(u8 *)&acc_count, 1);
+		if (rc < 0)
+			return rc;
+
+		*time_ms += ((sample_count - acc_count) * sample_interval);
+	}
+
+	return 0;
+}
+
+static bool is_usb_available(struct qpnp_qg *chip)
+{
+	if (chip->usb_psy)
+		return true;
+
+	chip->usb_psy = power_supply_get_by_name("usb");
+	if (!chip->usb_psy)
+		return false;
+
+	return true;
+}
+
+bool is_usb_present(struct qpnp_qg *chip)
+{
+	union power_supply_propval pval = {0, };
+
+	if (is_usb_available(chip))
+		power_supply_get_property(chip->usb_psy,
+			POWER_SUPPLY_PROP_PRESENT, &pval);
+
+	return pval.intval ? true : false;
+}
+
+static bool is_parallel_available(struct qpnp_qg *chip)
+{
+	if (chip->parallel_psy)
+		return true;
+
+	chip->parallel_psy = power_supply_get_by_name("parallel");
+	if (!chip->parallel_psy)
+		return false;
+
+	return true;
+}
+
+bool is_parallel_enabled(struct qpnp_qg *chip)
+{
+	union power_supply_propval pval = {0, };
+
+	if (is_parallel_available(chip)) {
+		power_supply_get_property(chip->parallel_psy,
+			POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval);
+	}
+
+	return pval.intval ? true : false;
+}
+
+int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc)
+{
+	u8 reg = 0;
+	int rc;
+
+	reg = (msoc * 255) / 100;
+	rc = qg_write(chip, chip->qg_base + QG_SOC_MONOTONIC_REG,
+				&reg, 1);
+	if (rc < 0)
+		pr_err("Failed to update QG_SOC_MONOTINIC reg rc=%d\n", rc);
+
+	return rc;
+}
+
+int qg_get_battery_temp(struct qpnp_qg *chip, int *temp)
+{
+	int rc = 0;
+	struct qpnp_vadc_result result;
+
+	if (chip->battery_missing) {
+		*temp = 250;
+		return 0;
+	}
+
+	rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_THERM_PU2, &result);
+	if (rc) {
+		pr_err("Failed reading adc channel=%d, rc=%d\n",
+					VADC_BAT_THERM_PU2, rc);
+		return rc;
+	}
+	pr_debug("batt_temp = %lld meas = 0x%llx\n",
+			result.physical, result.measurement);
+
+	*temp = (int)result.physical;
+
+	return rc;
+}
diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h
new file mode 100644
index 0000000..385c9e0
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-util.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_UTIL_H__
+#define __QG_UTIL_H__
+
+int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
+int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
+int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val);
+int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt);
+int get_sample_count(struct qpnp_qg *chip, u32 *sample_count);
+int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval);
+int get_fifo_done_time(struct qpnp_qg *chip, bool rt, int *time_ms);
+int get_rtc_time(unsigned long *rtc_time);
+bool is_usb_present(struct qpnp_qg *chip);
+bool is_parallel_enabled(struct qpnp_qg *chip);
+int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc);
+int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp);
+
+#endif
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 2c62218..18732c0 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -35,6 +35,8 @@
 #define ESR_PULSE_THRESH_OFFSET		3
 #define SLOPE_LIMIT_WORD		3
 #define SLOPE_LIMIT_OFFSET		0
+#define CUTOFF_CURR_WORD		4
+#define CUTOFF_CURR_OFFSET		0
 #define CUTOFF_VOLT_WORD		5
 #define CUTOFF_VOLT_OFFSET		0
 #define SYS_TERM_CURR_WORD		6
@@ -208,6 +210,8 @@
 		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
 		100000, 390625, 0, fg_encode_current, NULL),
+	PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
+		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
 		2048, 100, 0, fg_encode_default, NULL),
 	PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
@@ -284,6 +288,8 @@
 	PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
 		CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
 		fg_encode_current, NULL),
+	PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
+		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
 		1, 2048, 100, 0, fg_encode_default, NULL),
 	PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
@@ -910,11 +916,16 @@
 #define DEFAULT_BATT_TYPE	"Unknown Battery"
 #define MISSING_BATT_TYPE	"Missing Battery"
 #define LOADING_BATT_TYPE	"Loading Battery"
+#define SKIP_BATT_TYPE		"Skipped loading battery"
 static const char *fg_get_battery_type(struct fg_chip *chip)
 {
-	if (chip->battery_missing)
+	if (chip->battery_missing ||
+		chip->profile_load_status == PROFILE_MISSING)
 		return MISSING_BATT_TYPE;
 
+	if (chip->profile_load_status == PROFILE_SKIPPED)
+		return SKIP_BATT_TYPE;
+
 	if (chip->bp.batt_type_str) {
 		if (chip->profile_loaded)
 			return chip->bp.batt_type_str;
@@ -1397,16 +1408,16 @@
 			QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
 		chip->cl.final_cc_uah = chip->cl.final_cc_uah *
 						(1000 + QNOVO_CL_SKEW_DECIPCT);
-		do_div(chip->cl.final_cc_uah, 1000);
+		div64_s64(chip->cl.final_cc_uah, 1000);
 	}
 
 	max_inc_val = chip->cl.learned_cc_uah
 			* (1000 + chip->dt.cl_max_cap_inc);
-	do_div(max_inc_val, 1000);
+	div64_s64(max_inc_val, 1000);
 
 	min_dec_val = chip->cl.learned_cc_uah
 			* (1000 - chip->dt.cl_max_cap_dec);
-	do_div(min_dec_val, 1000);
+	div64_s64(min_dec_val, 1000);
 
 	old_cap = chip->cl.learned_cc_uah;
 	if (chip->cl.final_cc_uah > max_inc_val)
@@ -1420,7 +1431,7 @@
 	if (chip->dt.cl_max_cap_limit) {
 		max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 +
 				chip->dt.cl_max_cap_limit);
-		do_div(max_inc_val, 1000);
+		div64_s64(max_inc_val, 1000);
 		if (chip->cl.final_cc_uah > max_inc_val) {
 			fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n",
 				chip->cl.final_cc_uah, max_inc_val);
@@ -1431,7 +1442,7 @@
 	if (chip->dt.cl_min_cap_limit) {
 		min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 -
 				chip->dt.cl_min_cap_limit);
-		do_div(min_dec_val, 1000);
+		div64_s64(min_dec_val, 1000);
 		if (chip->cl.final_cc_uah < min_dec_val) {
 			fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n",
 				chip->cl.final_cc_uah, min_dec_val);
@@ -1935,7 +1946,7 @@
 	}
 
 	val *= scaling_factor;
-	do_div(val, 1000);
+	div64_s64(val, 1000);
 	rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
 			ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
 	if (rc < 0) {
@@ -1952,7 +1963,7 @@
 	}
 
 	val *= scaling_factor;
-	do_div(val, 1000);
+	div64_s64(val, 1000);
 	rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
 			ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
 	if (rc < 0) {
@@ -2708,12 +2719,14 @@
 				buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
 		if (rc < 0) {
 			pr_err("Error in reading battery profile, rc:%d\n", rc);
+			chip->profile_load_status = PROFILE_SKIPPED;
 			return false;
 		}
 		profiles_same = memcmp(chip->batt_profile, buf,
 					PROFILE_COMP_LEN) == 0;
 		if (profiles_same) {
 			fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n");
+			chip->profile_load_status = PROFILE_LOADED;
 			return false;
 		}
 
@@ -2727,6 +2740,7 @@
 				dump_sram(chip->batt_profile, PROFILE_LOAD_WORD,
 					PROFILE_LEN);
 			}
+			chip->profile_load_status = PROFILE_SKIPPED;
 			return false;
 		}
 
@@ -2870,6 +2884,7 @@
 
 	rc = fg_get_batt_profile(chip);
 	if (rc < 0) {
+		chip->profile_load_status = PROFILE_MISSING;
 		pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
 			chip->batt_id_ohms / 1000, rc);
 		goto out;
@@ -2921,6 +2936,7 @@
 	}
 
 	fg_dbg(chip, FG_STATUS, "SOC is ready\n");
+	chip->profile_load_status = PROFILE_LOADED;
 done:
 	rc = fg_bp_params_config(chip);
 	if (rc < 0)
@@ -2946,7 +2962,10 @@
 
 	batt_psy_initialized(chip);
 	fg_notify_charger(chip);
-	chip->profile_loaded = true;
+
+	if (chip->profile_load_status == PROFILE_LOADED)
+		chip->profile_loaded = true;
+
 	fg_dbg(chip, FG_STATUS, "profile loaded successfully");
 out:
 	chip->soc_reporting_ready = true;
@@ -3974,6 +3993,16 @@
 		return rc;
 	}
 
+	fg_encode(chip->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma,
+		buf);
+	rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_CURR].addr_word,
+			chip->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf,
+			chip->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT);
+	if (rc < 0) {
+		pr_err("Error in writing cutoff_curr, rc=%d\n", rc);
+		return rc;
+	}
+
 	if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
 		fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
 			chip->dt.chg_term_base_curr_ma, buf);
@@ -4296,6 +4325,7 @@
 	if (chip->battery_missing) {
 		chip->profile_available = false;
 		chip->profile_loaded = false;
+		chip->profile_load_status = PROFILE_NOT_LOADED;
 		chip->soc_reporting_ready = false;
 		chip->batt_id_ohms = -EINVAL;
 		cancel_delayed_work_sync(&chip->pl_enable_work);
@@ -4697,6 +4727,7 @@
 #define DEFAULT_CHG_TERM_CURR_MA	100
 #define DEFAULT_CHG_TERM_BASE_CURR_MA	75
 #define DEFAULT_SYS_TERM_CURR_MA	-125
+#define DEFAULT_CUTOFF_CURR_MA		500
 #define DEFAULT_DELTA_SOC_THR		1
 #define DEFAULT_RECHARGE_SOC_THR	95
 #define DEFAULT_BATT_TEMP_COLD		0
@@ -4860,6 +4891,12 @@
 	else
 		chip->dt.chg_term_base_curr_ma = temp;
 
+	rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp);
+	if (rc < 0)
+		chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA;
+	else
+		chip->dt.cutoff_curr_ma = temp;
+
 	rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
 	if (rc < 0)
 		chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
new file mode 100644
index 0000000..3f05a53
--- /dev/null
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -0,0 +1,2482 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/alarmtimer.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_batterydata.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/uaccess.h>
+#include <linux/pmic-voter.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-util.h"
+#include "qg-soc.h"
+#include "qg-battery-profile.h"
+#include "qg-defs.h"
+
+static int qg_debug_mask;
+module_param_named(
+	debug_mask, qg_debug_mask, int, 0600
+);
+
+static bool is_battery_present(struct qpnp_qg *chip)
+{
+	u8 reg = 0;
+	int rc;
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, &reg, 1);
+	if (rc < 0)
+		pr_err("Failed to read battery presence, rc=%d\n", rc);
+
+	return !!(reg & BATTERY_PRESENT_BIT);
+}
+
+#define DEBUG_BATT_ID_LOW	6000
+#define DEBUG_BATT_ID_HIGH	8500
+static bool is_debug_batt_id(struct qpnp_qg *chip)
+{
+	if (is_between(DEBUG_BATT_ID_LOW, DEBUG_BATT_ID_HIGH,
+					chip->batt_id_ohm))
+		return true;
+
+	return false;
+}
+
+static int qg_read_ocv(struct qpnp_qg *chip, u32 *ocv_uv, u8 type)
+{
+	int rc, addr;
+	u64 temp = 0;
+
+	switch (type) {
+	case GOOD_OCV:
+		addr = QG_S3_GOOD_OCV_V_DATA0_REG;
+		break;
+	case PON_OCV:
+		addr = QG_S7_PON_OCV_V_DATA0_REG;
+		break;
+	default:
+		pr_err("Invalid OCV type %d\n", type);
+		return -EINVAL;
+	}
+
+	rc = qg_read(chip, chip->qg_base + addr, (u8 *)&temp, 2);
+	if (rc < 0) {
+		pr_err("Failed to read ocv, rc=%d\n", rc);
+		return rc;
+	}
+
+	*ocv_uv = V_RAW_TO_UV(temp);
+
+	pr_debug("%s: OCV=%duV\n",
+		type == GOOD_OCV ? "GOOD_OCV" : "PON_OCV", *ocv_uv);
+
+	return rc;
+}
+
+static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length)
+{
+	int rc;
+
+	if (!length || length > 8) {
+		pr_err("Invalid FIFO length %d\n", length);
+		return -EINVAL;
+	}
+
+	rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
+			FIFO_LENGTH_MASK, (length - 1) << FIFO_LENGTH_SHIFT);
+	if (rc < 0)
+		pr_err("Failed to write S2 FIFO length, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int qg_master_hold(struct qpnp_qg *chip, bool hold)
+{
+	int rc;
+
+	/* clear the master */
+	rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
+					MASTER_HOLD_OR_CLR_BIT, 0);
+	if (rc < 0)
+		return rc;
+
+	if (hold) {
+		/* 0 -> 1, hold the master */
+		rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
+					MASTER_HOLD_OR_CLR_BIT,
+					MASTER_HOLD_OR_CLR_BIT);
+		if (rc < 0)
+			return rc;
+	}
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "Master hold = %d\n", hold);
+
+	return rc;
+}
+
+static void qg_notify_charger(struct qpnp_qg *chip)
+{
+	union power_supply_propval prop = {0, };
+	int rc;
+
+	if (!chip->batt_psy)
+		return;
+
+	if (is_debug_batt_id(chip)) {
+		prop.intval = 1;
+		power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_DEBUG_BATTERY, &prop);
+		return;
+	}
+
+	if (!chip->profile_loaded)
+		return;
+
+	prop.intval = chip->bp.float_volt_uv;
+	rc = power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
+	if (rc < 0) {
+		pr_err("Failed to set voltage_max property on batt_psy, rc=%d\n",
+			rc);
+		return;
+	}
+
+	prop.intval = chip->bp.fastchg_curr_ma * 1000;
+	rc = power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
+	if (rc < 0) {
+		pr_err("Failed to set constant_charge_current_max property on batt_psy, rc=%d\n",
+			rc);
+		return;
+	}
+
+	pr_debug("Notified charger on float voltage and FCC\n");
+}
+
+static bool is_batt_available(struct qpnp_qg *chip)
+{
+	if (chip->batt_psy)
+		return true;
+
+	chip->batt_psy = power_supply_get_by_name("battery");
+	if (!chip->batt_psy)
+		return false;
+
+	/* batt_psy is initialized, set the fcc and fv */
+	qg_notify_charger(chip);
+
+	return true;
+}
+
+static int qg_update_sdam_params(struct qpnp_qg *chip)
+{
+	int rc, batt_temp = 0, i;
+	unsigned long rtc_sec = 0;
+
+	rc = get_rtc_time(&rtc_sec);
+	if (rc < 0)
+		pr_err("Failed to get RTC time, rc=%d\n", rc);
+	else
+		chip->sdam_data[SDAM_TIME_SEC] = rtc_sec;
+
+	rc = qg_get_battery_temp(chip, &batt_temp);
+	if (rc < 0)
+		pr_err("Failed to get battery-temp, rc = %d\n", rc);
+	else
+		chip->sdam_data[SDAM_TEMP] = (u32)batt_temp;
+
+	rc = qg_sdam_write_all(chip->sdam_data);
+	if (rc < 0)
+		pr_err("Failed to write to SDAM rc=%d\n", rc);
+
+	for (i = 0; i < SDAM_MAX; i++)
+		qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n",
+					i, chip->sdam_data[i]);
+
+	return rc;
+}
+
+static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
+{
+	int rc = 0, i, j = 0, temp;
+	u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
+	u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
+
+	chip->kdata.fifo_time = (u32)ktime_get_seconds();
+
+	if (!fifo_length) {
+		pr_debug("No FIFO data\n");
+		return 0;
+	}
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "FIFO length=%d\n", fifo_length);
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO sample interval, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = get_sample_count(chip, &sample_count);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO sample count, rc=%d\n", rc);
+		return rc;
+	}
+
+	/*
+	 * If there is pending data from suspend, append the new FIFO
+	 * data to it.
+	 */
+	if (chip->suspend_data) {
+		j = chip->kdata.fifo_length; /* append the data */
+		chip->suspend_data = false;
+		qg_dbg(chip, QG_DEBUG_FIFO,
+			"Pending suspend-data FIFO length=%d\n", j);
+	} else {
+		/* clear any old pending data */
+		chip->kdata.fifo_length = 0;
+	}
+
+	for (i = 0; i < fifo_length * 2; i = i + 2, j++) {
+		rc = qg_read(chip, chip->qg_base + QG_V_FIFO0_DATA0_REG + i,
+					&v_fifo[i], 2);
+		if (rc < 0) {
+			pr_err("Failed to read QG_V_FIFO, rc=%d\n", rc);
+			return rc;
+		}
+		rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG + i,
+					&i_fifo[i], 2);
+		if (rc < 0) {
+			pr_err("Failed to read QG_I_FIFO, rc=%d\n", rc);
+			return rc;
+		}
+
+		fifo_v = v_fifo[i] | (v_fifo[i + 1] << 8);
+		fifo_i = i_fifo[i] | (i_fifo[i + 1] << 8);
+
+		temp = sign_extend32(fifo_i, 15);
+
+		chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v);
+		chip->kdata.fifo[j].i = I_RAW_TO_UA(temp);
+		chip->kdata.fifo[j].interval = sample_interval;
+		chip->kdata.fifo[j].count = sample_count;
+
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
+					j, fifo_v,
+					chip->kdata.fifo[j].v,
+					fifo_i,
+					(int)chip->kdata.fifo[j].i,
+					chip->kdata.fifo[j].interval,
+					chip->kdata.fifo[j].count);
+	}
+
+	chip->kdata.fifo_length += fifo_length;
+	chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
+
+	return rc;
+}
+
+static int qg_process_accumulator(struct qpnp_qg *chip)
+{
+	int rc, sample_interval = 0;
+	u8 count, index = chip->kdata.fifo_length;
+	u64 acc_v = 0, acc_i = 0;
+	s64 temp = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG,
+			&count, 1);
+	if (rc < 0) {
+		pr_err("Failed to read ACC count, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (!count) {
+		pr_debug("No ACCUMULATOR data!\n");
+		return 0;
+	}
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0) {
+		pr_err("Failed to get ACC sample interval, rc=%d\n", rc);
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_V_ACCUM_DATA0_RT_REG,
+			(u8 *)&acc_v, 3);
+	if (rc < 0) {
+		pr_err("Failed to read ACC RT V data, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_I_ACCUM_DATA0_RT_REG,
+			(u8 *)&acc_i, 3);
+	if (rc < 0) {
+		pr_err("Failed to read ACC RT I data, rc=%d\n", rc);
+		return rc;
+	}
+
+	temp = sign_extend64(acc_i, 23);
+
+	chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count));
+	chip->kdata.fifo[index].i = I_RAW_TO_UA(div_s64(temp, count));
+	chip->kdata.fifo[index].interval = sample_interval;
+	chip->kdata.fifo[index].count = count;
+	chip->kdata.fifo_length++;
+
+	if (chip->kdata.fifo_length == 1)	/* Only accumulator data */
+		chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "ACC v_avg=%duV i_avg=%duA interval=%d count=%d\n",
+			chip->kdata.fifo[index].v,
+			(int)chip->kdata.fifo[index].i,
+			chip->kdata.fifo[index].interval,
+			chip->kdata.fifo[index].count);
+
+	return rc;
+}
+
+static int qg_process_rt_fifo(struct qpnp_qg *chip)
+{
+	int rc;
+	u32 fifo_length = 0;
+
+	/* Get the real-time FIFO length */
+	rc = get_fifo_length(chip, &fifo_length, true);
+	if (rc < 0) {
+		pr_err("Failed to read RT FIFO length, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_process_fifo(chip, fifo_length);
+	if (rc < 0) {
+		pr_err("Failed to process FIFO data, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_process_accumulator(chip);
+	if (rc < 0) {
+		pr_err("Failed to process ACC data, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#define VBAT_LOW_HYST_UV		50000 /* 50mV */
+static int qg_vbat_low_wa(struct qpnp_qg *chip)
+{
+	int rc, i;
+	u32 vbat_low_uv = chip->dt.vbatt_low_mv * 1000 + VBAT_LOW_HYST_UV;
+
+	if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low)
+		return 0;
+
+	/*
+	 * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
+	 * To exit from VBAT_LOW config, check if any of the FIFO
+	 * averages is > vbat_low threshold and reconfigure the
+	 * FIFO length to normal.
+	 */
+	for (i = 0; i < chip->kdata.fifo_length; i++) {
+		if (chip->kdata.fifo[i].v > vbat_low_uv) {
+			rc = qg_master_hold(chip, true);
+			if (rc < 0) {
+				pr_err("Failed to hold master, rc=%d\n", rc);
+				goto done;
+			}
+			rc = qg_update_fifo_length(chip,
+					chip->dt.s2_fifo_length);
+			if (rc < 0)
+				goto done;
+
+			rc = qg_master_hold(chip, false);
+			if (rc < 0) {
+				pr_err("Failed to release master, rc=%d\n", rc);
+				goto done;
+			}
+			/* FIFOs restarted */
+			chip->last_fifo_update_time = ktime_get();
+
+			chip->vbat_low = false;
+			pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
+					chip->kdata.fifo[i].v, vbat_low_uv,
+					chip->dt.s2_fifo_length);
+			break;
+		}
+	}
+
+	return 0;
+
+done:
+	qg_master_hold(chip, false);
+	return rc;
+}
+
+#define MIN_FIFO_FULL_TIME_MS			12000
+static int process_rt_fifo_data(struct qpnp_qg *chip,
+				bool vbat_low, bool update_smb)
+{
+	int rc = 0;
+	ktime_t now = ktime_get();
+	s64 time_delta;
+
+	/*
+	 * Reject the FIFO read event if there are back-to-back requests
+	 * This is done to gaurantee that there is always a minimum FIFO
+	 * data to be processed, ignore this if vbat_low is set.
+	 */
+	time_delta = ktime_ms_delta(now, chip->last_user_update_time);
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n",
+				time_delta, vbat_low);
+
+	if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) {
+		rc = qg_master_hold(chip, true);
+		if (rc < 0) {
+			pr_err("Failed to hold master, rc=%d\n", rc);
+			goto done;
+		}
+
+		rc = qg_process_rt_fifo(chip);
+		if (rc < 0) {
+			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+			goto done;
+		}
+
+		if (vbat_low) {
+			/* change FIFO length */
+			rc = qg_update_fifo_length(chip,
+					chip->dt.s2_vbat_low_fifo_length);
+			if (rc < 0)
+				goto done;
+
+			qg_dbg(chip, QG_DEBUG_STATUS,
+				"FIFO length updated to %d vbat_low=%d\n",
+					chip->dt.s2_vbat_low_fifo_length,
+					vbat_low);
+		}
+
+		if (update_smb) {
+			rc = qg_masked_write(chip, chip->qg_base +
+				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
+				chip->parallel_enabled ?
+					PARALLEL_IBAT_SENSE_EN_BIT : 0);
+			if (rc < 0) {
+				pr_err("Failed to update SMB_EN, rc=%d\n", rc);
+				goto done;
+			}
+			qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n",
+						chip->parallel_enabled);
+		}
+
+		rc = qg_master_hold(chip, false);
+		if (rc < 0) {
+			pr_err("Failed to release master, rc=%d\n", rc);
+			goto done;
+		}
+		/* FIFOs restarted */
+		chip->last_fifo_update_time = ktime_get();
+
+		/* signal the read thread */
+		chip->data_ready = true;
+		wake_up_interruptible(&chip->qg_wait_q);
+		chip->last_user_update_time = now;
+
+		/* vote to stay awake until userspace reads data */
+		vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0);
+	} else {
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n",
+							time_delta);
+	}
+done:
+	qg_master_hold(chip, false);
+	return rc;
+}
+
+static void process_udata_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, udata_work);
+	int rc;
+
+	if (chip->udata.param[QG_SOC].valid) {
+		qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n",
+			chip->udata.param[QG_SOC].data, chip->catch_up_soc);
+
+		chip->catch_up_soc = chip->udata.param[QG_SOC].data;
+		qg_scale_soc(chip, false);
+
+		/* update parameters to SDAM */
+		chip->sdam_data[SDAM_SOC] = chip->msoc;
+		chip->sdam_data[SDAM_OCV_UV] =
+				chip->udata.param[QG_OCV_UV].data;
+		chip->sdam_data[SDAM_RBAT_MOHM] =
+				chip->udata.param[QG_RBAT_MOHM].data;
+		chip->sdam_data[SDAM_VALID] = 1;
+
+		rc = qg_update_sdam_params(chip);
+		if (rc < 0)
+			pr_err("Failed to update SDAM params, rc=%d\n", rc);
+	}
+
+	if (chip->udata.param[QG_CHARGE_COUNTER].valid)
+		chip->charge_counter_uah =
+			chip->udata.param[QG_CHARGE_COUNTER].data;
+
+	vote(chip->awake_votable, UDATA_READY_VOTER, false, 0);
+}
+
+static irqreturn_t qg_default_irq_handler(int irq, void *data)
+{
+	struct qpnp_qg *chip = data;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+
+	return IRQ_HANDLED;
+}
+
+#define MAX_FIFO_DELTA_PERCENT		10
+static irqreturn_t qg_fifo_update_done_handler(int irq, void *data)
+{
+	ktime_t now = ktime_get();
+	int rc, hw_delta_ms = 0, margin_ms = 0;
+	u32 fifo_length = 0;
+	s64 time_delta_ms = 0;
+	struct qpnp_qg *chip = data;
+
+	time_delta_ms = ktime_ms_delta(now, chip->last_fifo_update_time);
+	chip->last_fifo_update_time = now;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	mutex_lock(&chip->data_lock);
+
+	rc = get_fifo_length(chip, &fifo_length, false);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO length, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = qg_process_fifo(chip, fifo_length);
+	if (rc < 0) {
+		pr_err("Failed to process QG FIFO, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = qg_vbat_low_wa(chip);
+	if (rc < 0) {
+		pr_err("Failed to apply VBAT LOW WA, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = get_fifo_done_time(chip, false, &hw_delta_ms);
+	if (rc < 0)
+		hw_delta_ms = 0;
+	else
+		margin_ms = (hw_delta_ms * MAX_FIFO_DELTA_PERCENT) / 100;
+
+	if (abs(hw_delta_ms - time_delta_ms) < margin_ms) {
+		chip->kdata.param[QG_FIFO_TIME_DELTA].data = time_delta_ms;
+		chip->kdata.param[QG_FIFO_TIME_DELTA].valid = true;
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO_done time_delta_ms=%lld\n",
+							time_delta_ms);
+	}
+
+	/* signal the read thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+
+	/* vote to stay awake until userspace reads data */
+	vote(chip->awake_votable, FIFO_DONE_VOTER, true, 0);
+
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_vbat_low_handler(int irq, void *data)
+{
+	int rc;
+	struct qpnp_qg *chip = data;
+	u8 status = 0;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	mutex_lock(&chip->data_lock);
+
+	rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read RT status, rc=%d\n", rc);
+		goto done;
+	}
+	chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT);
+
+	rc = process_rt_fifo_data(chip, chip->vbat_low, false);
+	if (rc < 0)
+		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low);
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_vbat_empty_handler(int irq, void *data)
+{
+	struct qpnp_qg *chip = data;
+	u32 ocv_uv = 0;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	pr_warn("VBATT EMPTY SOC = 0\n");
+
+	chip->catch_up_soc = 0;
+	qg_scale_soc(chip, true);
+
+	qg_sdam_read(SDAM_OCV_UV, &ocv_uv);
+	chip->sdam_data[SDAM_SOC] = 0;
+	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
+	chip->sdam_data[SDAM_VALID] = 1;
+
+	qg_update_sdam_params(chip);
+
+	if (chip->qg_psy)
+		power_supply_changed(chip->qg_psy);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_good_ocv_handler(int irq, void *data)
+{
+	int rc;
+	u8 status = 0;
+	u32 ocv_uv;
+	struct qpnp_qg *chip = data;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+
+	mutex_lock(&chip->data_lock);
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read status2 register rc=%d\n", rc);
+		goto done;
+	}
+
+	if (!(status & GOOD_OCV_BIT))
+		goto done;
+
+	rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
+	if (rc < 0) {
+		pr_err("Failed to read good_ocv, rc=%d\n", rc);
+		goto done;
+	}
+
+	chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+	chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
+
+	vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0);
+
+	/* signal the readd thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static struct qg_irq_info qg_irqs[] = {
+	[QG_BATT_MISSING_IRQ] = {
+		.name		= "qg-batt-missing",
+		.handler	= qg_default_irq_handler,
+	},
+	[QG_VBATT_LOW_IRQ] = {
+		.name		= "qg-vbat-low",
+		.handler	= qg_vbat_low_handler,
+		.wake		= true,
+	},
+	[QG_VBATT_EMPTY_IRQ] = {
+		.name		= "qg-vbat-empty",
+		.handler	= qg_vbat_empty_handler,
+		.wake		= true,
+	},
+	[QG_FIFO_UPDATE_DONE_IRQ] = {
+		.name		= "qg-fifo-done",
+		.handler	= qg_fifo_update_done_handler,
+		.wake		= true,
+	},
+	[QG_GOOD_OCV_IRQ] = {
+		.name		= "qg-good-ocv",
+		.handler	= qg_good_ocv_handler,
+		.wake		= true,
+	},
+	[QG_FSM_STAT_CHG_IRQ] = {
+		.name		= "qg-fsm-state-chg",
+		.handler	= qg_default_irq_handler,
+	},
+	[QG_EVENT_IRQ] = {
+		.name		= "qg-event",
+		.handler	= qg_default_irq_handler,
+	},
+};
+
+static int qg_awake_cb(struct votable *votable, void *data, int awake,
+			const char *client)
+{
+	struct qpnp_qg *chip = data;
+
+	/* ignore if the QG device is not open */
+	if (!chip->qg_device_open)
+		return 0;
+
+	if (awake)
+		pm_stay_awake(chip->dev);
+	else
+		pm_relax(chip->dev);
+
+	pr_debug("client: %s awake: %d\n", client, awake);
+	return 0;
+}
+
+static int qg_fifo_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
+			disable_irq_wake(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
+			disable_irq_nosync(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
+			enable_irq(qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
+			enable_irq_wake(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+	}
+
+	return 0;
+}
+
+static int qg_vbatt_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
+			enable_irq(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
+			enable_irq(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+	}
+
+	return 0;
+}
+
+static int qg_good_ocv_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
+			enable_irq(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+	}
+
+	return 0;
+}
+
+#define DEFAULT_BATT_TYPE	"Unknown Battery"
+#define MISSING_BATT_TYPE	"Missing Battery"
+#define DEBUG_BATT_TYPE		"Debug Board"
+static const char *qg_get_battery_type(struct qpnp_qg *chip)
+{
+	if (chip->battery_missing)
+		return MISSING_BATT_TYPE;
+
+	if (is_debug_batt_id(chip))
+		return DEBUG_BATT_TYPE;
+
+	if (chip->bp.batt_type_str) {
+		if (chip->profile_loaded)
+			return chip->bp.batt_type_str;
+	}
+
+	return DEFAULT_BATT_TYPE;
+}
+
+static int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua)
+{
+	int rc = 0, last_ibat = 0;
+
+	if (chip->battery_missing) {
+		*ibat_ua = 0;
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
+				(u8 *)&last_ibat, 2);
+	if (rc < 0) {
+		pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	last_ibat = sign_extend32(last_ibat, 15);
+	*ibat_ua = I_RAW_TO_UA(last_ibat);
+
+	return rc;
+}
+
+static int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv)
+{
+	int rc = 0;
+	u64 last_vbat = 0;
+
+	if (chip->battery_missing) {
+		*vbat_uv = 3700000;
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG,
+				(u8 *)&last_vbat, 2);
+	if (rc < 0) {
+		pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	*vbat_uv = V_RAW_TO_UV(last_vbat);
+
+	return rc;
+}
+
+#define DEBUG_BATT_SOC		67
+#define BATT_MISSING_SOC	50
+#define EMPTY_SOC		0
+#define FULL_SOC		100
+static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc)
+{
+	if (is_debug_batt_id(chip)) {
+		*soc = DEBUG_BATT_SOC;
+		return 0;
+	}
+
+	if (chip->battery_missing || !chip->profile_loaded) {
+		*soc = BATT_MISSING_SOC;
+		return 0;
+	}
+
+	if (chip->charge_full) {
+		*soc = FULL_SOC;
+		return 0;
+	}
+
+	mutex_lock(&chip->soc_lock);
+
+	if (chip->dt.linearize_soc && chip->maint_soc > 0)
+		*soc = chip->maint_soc;
+	else
+		*soc = chip->msoc;
+
+	mutex_unlock(&chip->soc_lock);
+
+	return 0;
+}
+
+static int qg_psy_set_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       const union power_supply_propval *pval)
+{
+	return 0;
+}
+
+static int qg_psy_get_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       union power_supply_propval *pval)
+{
+	struct qpnp_qg *chip = power_supply_get_drvdata(psy);
+	int rc = 0;
+
+	pval->intval = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = qg_get_battery_capacity(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		rc = qg_get_battery_voltage(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		rc = qg_get_battery_current(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		rc = qg_sdam_read(SDAM_OCV_UV, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		rc = qg_get_battery_temp(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE_ID:
+		pval->intval = chip->batt_id_ohm;
+		break;
+	case POWER_SUPPLY_PROP_DEBUG_BATTERY:
+		pval->intval = is_debug_batt_id(chip);
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE:
+		rc = qg_sdam_read(SDAM_RBAT_MOHM, &pval->intval);
+		if (!rc)
+			pval->intval *= 1000;
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE:
+		pval->intval = chip->dt.rbat_conn_mohm;
+		break;
+	case POWER_SUPPLY_PROP_BATTERY_TYPE:
+		pval->strval = qg_get_battery_type(chip);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+		pval->intval = chip->dt.vbatt_cutoff_mv * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		pval->intval = chip->bp.float_volt_uv;
+		break;
+	case POWER_SUPPLY_PROP_BATT_FULL_CURRENT:
+		pval->intval = chip->dt.iterm_ma * 1000;
+		break;
+	case POWER_SUPPLY_PROP_BATT_PROFILE_VERSION:
+		pval->intval = chip->bp.qg_profile_version;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		pval->intval = chip->charge_counter_uah;
+		break;
+	default:
+		pr_debug("Unsupported property %d\n", psp);
+		break;
+	}
+
+	return rc;
+}
+
+static int qg_property_is_writeable(struct power_supply *psy,
+				enum power_supply_property psp)
+{
+	return 0;
+}
+
+static enum power_supply_property qg_psy_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_RESISTANCE,
+	POWER_SUPPLY_PROP_RESISTANCE_ID,
+	POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
+	POWER_SUPPLY_PROP_DEBUG_BATTERY,
+	POWER_SUPPLY_PROP_BATTERY_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+};
+
+static const struct power_supply_desc qg_psy_desc = {
+	.name = "bms",
+	.type = POWER_SUPPLY_TYPE_BMS,
+	.properties = qg_psy_props,
+	.num_properties = ARRAY_SIZE(qg_psy_props),
+	.get_property = qg_psy_get_property,
+	.set_property = qg_psy_set_property,
+	.property_is_writeable = qg_property_is_writeable,
+};
+
+#define DEFAULT_RECHARGE_SOC 95
+static int qg_charge_full_update(struct qpnp_qg *chip)
+{
+	union power_supply_propval prop = {0, };
+	int rc, recharge_soc, health;
+
+	vote(chip->good_ocv_irq_disable_votable,
+		QG_INIT_STATE_IRQ_DISABLE, !chip->charge_done, 0);
+
+	if (!chip->dt.hold_soc_while_full)
+		goto out;
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_HEALTH, &prop);
+	if (rc < 0) {
+		pr_err("Failed to get battery health, rc=%d\n", rc);
+		goto out;
+	}
+	health = prop.intval;
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_RECHARGE_SOC, &prop);
+	if (rc < 0 || prop.intval < 0) {
+		pr_debug("Failed to get recharge-soc\n");
+		recharge_soc = DEFAULT_RECHARGE_SOC;
+	}
+	recharge_soc = prop.intval;
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d\n",
+				chip->msoc, health, chip->charge_full);
+	if (chip->charge_done && !chip->charge_full) {
+		if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) {
+			chip->charge_full = true;
+			qg_dbg(chip, QG_DEBUG_STATUS, "Setting charge_full (0->1) @ msoc=%d\n",
+					chip->msoc);
+		} else {
+			qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n",
+					chip->msoc);
+		}
+	} else if ((!chip->charge_done || chip->msoc < recharge_soc)
+				&& chip->charge_full) {
+		/*
+		 * If recharge or discharge has started and
+		 * if linearize soc dtsi property defined
+		 * scale msoc from 100% for better UX.
+		 */
+		if (chip->dt.linearize_soc && chip->msoc < 99) {
+			chip->maint_soc = FULL_SOC;
+			qg_scale_soc(chip, false);
+		}
+
+		qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n",
+					chip->msoc, recharge_soc);
+		chip->charge_full = false;
+	}
+out:
+	return 0;
+}
+
+static int qg_parallel_status_update(struct qpnp_qg *chip)
+{
+	int rc;
+	bool parallel_enabled = is_parallel_enabled(chip);
+
+	if (parallel_enabled == chip->parallel_enabled)
+		return 0;
+
+	chip->parallel_enabled = parallel_enabled;
+	qg_dbg(chip, QG_DEBUG_STATUS,
+		"Parallel status changed Enabled=%d\n", parallel_enabled);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_rt_fifo_data(chip, false, true);
+	if (rc < 0)
+		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static int qg_usb_status_update(struct qpnp_qg *chip)
+{
+	bool usb_present = is_usb_present(chip);
+
+	if (chip->usb_present != usb_present) {
+		qg_dbg(chip, QG_DEBUG_STATUS,
+			"USB status changed Present=%d\n",
+							usb_present);
+		qg_scale_soc(chip, false);
+	}
+
+	chip->usb_present = usb_present;
+
+	return 0;
+}
+
+static void qg_status_change_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, qg_status_change_work);
+	union power_supply_propval prop = {0, };
+	int rc = 0;
+
+	if (!is_batt_available(chip)) {
+		pr_debug("batt-psy not available\n");
+		goto out;
+	}
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_STATUS, &prop);
+	if (rc < 0)
+		pr_err("Failed to get charger status, rc=%d\n", rc);
+	else
+		chip->charge_status = prop.intval;
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
+	if (rc < 0)
+		pr_err("Failed to get charge done status, rc=%d\n", rc);
+	else
+		chip->charge_done = prop.intval;
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "charge_status=%d charge_done=%d\n",
+			chip->charge_status, chip->charge_done);
+
+	rc = qg_parallel_status_update(chip);
+	if (rc < 0)
+		pr_err("Failed to update parallel-status, rc=%d\n", rc);
+
+	rc = qg_usb_status_update(chip);
+	if (rc < 0)
+		pr_err("Failed to update usb status, rc=%d\n", rc);
+
+	rc = qg_charge_full_update(chip);
+	if (rc < 0)
+		pr_err("Failed in charge_full_update, rc=%d\n", rc);
+out:
+	pm_relax(chip->dev);
+}
+
+static int qg_notifier_cb(struct notifier_block *nb,
+			unsigned long event, void *data)
+{
+	struct power_supply *psy = data;
+	struct qpnp_qg *chip = container_of(nb, struct qpnp_qg, nb);
+
+	if (event != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	if (work_pending(&chip->qg_status_change_work))
+		return NOTIFY_OK;
+
+	if ((strcmp(psy->desc->name, "battery") == 0)
+		|| (strcmp(psy->desc->name, "parallel") == 0)
+		|| (strcmp(psy->desc->name, "usb") == 0)) {
+		/*
+		 * We cannot vote for awake votable here as that takes
+		 * a mutex lock and this is executed in an atomic context.
+		 */
+		pm_stay_awake(chip->dev);
+		schedule_work(&chip->qg_status_change_work);
+	}
+
+	return NOTIFY_OK;
+}
+
+static int qg_init_psy(struct qpnp_qg *chip)
+{
+	struct power_supply_config qg_psy_cfg;
+	int rc;
+
+	qg_psy_cfg.drv_data = chip;
+	qg_psy_cfg.of_node = NULL;
+	qg_psy_cfg.supplied_to = NULL;
+	qg_psy_cfg.num_supplicants = 0;
+	chip->qg_psy = devm_power_supply_register(chip->dev,
+				&qg_psy_desc, &qg_psy_cfg);
+	if (IS_ERR_OR_NULL(chip->qg_psy)) {
+		pr_err("Failed to register qg_psy rc = %ld\n",
+				PTR_ERR(chip->qg_psy));
+		return -ENODEV;
+	}
+
+	chip->nb.notifier_call = qg_notifier_cb;
+	rc = power_supply_reg_notifier(&chip->nb);
+	if (rc < 0)
+		pr_err("Failed register psy notifier rc = %d\n", rc);
+
+	return rc;
+}
+
+static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *ppos)
+{
+	int rc;
+	struct qpnp_qg *chip = file->private_data;
+	unsigned long data_size = sizeof(chip->kdata);
+
+	/* non-blocking access, return */
+	if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
+		return 0;
+
+	/* blocking access wait on data_ready */
+	if (!(file->f_flags & O_NONBLOCK)) {
+		rc = wait_event_interruptible(chip->qg_wait_q,
+					chip->data_ready);
+		if (rc < 0) {
+			pr_debug("Failed wait! rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	mutex_lock(&chip->data_lock);
+
+	if (!chip->data_ready) {
+		pr_debug("No Data, false wakeup\n");
+		rc = -EFAULT;
+		goto fail_read;
+	}
+
+
+	if (copy_to_user(buf, &chip->kdata, data_size)) {
+		pr_err("Failed in copy_to_user\n");
+		rc = -EFAULT;
+		goto fail_read;
+	}
+	chip->data_ready = false;
+
+	/* release all wake sources */
+	vote(chip->awake_votable, GOOD_OCV_VOTER, false, 0);
+	vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0);
+	vote(chip->awake_votable, FIFO_RT_DONE_VOTER, false, 0);
+	vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0);
+
+	qg_dbg(chip, QG_DEBUG_DEVICE,
+		"QG device read complete Seq_no=%u Size=%ld\n",
+				chip->kdata.seq_no, data_size);
+
+	/* clear data */
+	memset(&chip->kdata, 0, sizeof(chip->kdata));
+
+	mutex_unlock(&chip->data_lock);
+
+	return data_size;
+
+fail_read:
+	mutex_unlock(&chip->data_lock);
+	return rc;
+}
+
+static ssize_t qg_device_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	int rc = -EINVAL;
+	struct qpnp_qg *chip = file->private_data;
+	unsigned long data_size = sizeof(chip->udata);
+
+	mutex_lock(&chip->data_lock);
+	if (count == 0) {
+		pr_err("No data!\n");
+		goto fail;
+	}
+
+	if (count != 0 && count < data_size) {
+		pr_err("Invalid datasize %zu expected %lu\n", count, data_size);
+		goto fail;
+	}
+
+	if (copy_from_user(&chip->udata, buf, data_size)) {
+		pr_err("Failed in copy_from_user\n");
+		rc = -EFAULT;
+		goto fail;
+	}
+
+	rc = data_size;
+	vote(chip->awake_votable, UDATA_READY_VOTER, true, 0);
+	schedule_work(&chip->udata_work);
+	qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc);
+fail:
+	mutex_unlock(&chip->data_lock);
+	return rc;
+}
+
+static unsigned int qg_device_poll(struct file *file, poll_table *wait)
+{
+	struct qpnp_qg *chip = file->private_data;
+	unsigned int mask = 0;
+
+	poll_wait(file, &chip->qg_wait_q, wait);
+
+	if (chip->data_ready)
+		mask = POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+static int qg_device_open(struct inode *inode, struct file *file)
+{
+	struct qpnp_qg *chip = container_of(inode->i_cdev,
+				struct qpnp_qg, qg_cdev);
+
+	file->private_data = chip;
+	chip->qg_device_open = true;
+	qg_dbg(chip, QG_DEBUG_DEVICE, "QG device opened!\n");
+
+	return 0;
+}
+
+static int qg_device_release(struct inode *inode, struct file *file)
+{
+	struct qpnp_qg *chip = container_of(inode->i_cdev,
+				struct qpnp_qg, qg_cdev);
+
+	file->private_data = chip;
+	chip->qg_device_open = false;
+	qg_dbg(chip, QG_DEBUG_DEVICE, "QG device closed!\n");
+
+	return 0;
+}
+
+static const struct file_operations qg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= qg_device_open,
+	.release	= qg_device_release,
+	.read		= qg_device_read,
+	.write		= qg_device_write,
+	.poll		= qg_device_poll,
+};
+
+static int qg_register_device(struct qpnp_qg *chip)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&chip->dev_no, 0, 1, "qg");
+	if (rc < 0) {
+		pr_err("Failed to allocate chardev rc=%d\n", rc);
+		return rc;
+	}
+
+	cdev_init(&chip->qg_cdev, &qg_fops);
+	rc = cdev_add(&chip->qg_cdev, chip->dev_no, 1);
+	if (rc < 0) {
+		pr_err("Failed to cdev_add rc=%d\n", rc);
+		goto unregister_chrdev;
+	}
+
+	chip->qg_class = class_create(THIS_MODULE, "qg");
+	if (IS_ERR_OR_NULL(chip->qg_class)) {
+		pr_err("Failed to create qg class\n");
+		rc = -EINVAL;
+		goto delete_cdev;
+	}
+	chip->qg_device = device_create(chip->qg_class, NULL, chip->dev_no,
+					NULL, "qg");
+	if (IS_ERR(chip->qg_device)) {
+		pr_err("Failed to create qg_device\n");
+		rc = -EINVAL;
+		goto destroy_class;
+	}
+
+	qg_dbg(chip, QG_DEBUG_DEVICE, "'/dev/qg' successfully created\n");
+
+	return 0;
+
+destroy_class:
+	class_destroy(chip->qg_class);
+delete_cdev:
+	cdev_del(&chip->qg_cdev);
+unregister_chrdev:
+	unregister_chrdev_region(chip->dev_no, 1);
+	return rc;
+}
+
+#define BID_RPULL_OHM		100000
+#define BID_VREF_MV		1875
+static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm)
+{
+	int rc, batt_id_mv;
+	int64_t denom;
+	struct qpnp_vadc_result result;
+
+	/* Read battery-id */
+	rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_ID_PU2, &result);
+	if (rc) {
+		pr_err("Failed to read BATT_ID over vadc, rc=%d\n", rc);
+		return rc;
+	}
+
+	batt_id_mv = div_s64(result.physical, 1000);
+	if (batt_id_mv == 0) {
+		pr_debug("batt_id_mv = 0 from ADC\n");
+		return 0;
+	}
+
+	denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000;
+	if (denom <= 0) {
+		/* batt id connector might be open, return 0 kohms */
+		return 0;
+	}
+
+	*batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom);
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n",
+					batt_id_mv, *batt_id_ohm);
+
+	return 0;
+}
+
+static int qg_load_battery_profile(struct qpnp_qg *chip)
+{
+	struct device_node *node = chip->dev->of_node;
+	struct device_node *batt_node, *profile_node;
+	int rc;
+
+	batt_node = of_find_node_by_name(node, "qcom,battery-data");
+	if (!batt_node) {
+		pr_err("Batterydata not available\n");
+		return -ENXIO;
+	}
+
+	profile_node = of_batterydata_get_best_profile(batt_node,
+				chip->batt_id_ohm / 1000, NULL);
+	if (IS_ERR(profile_node)) {
+		rc = PTR_ERR(profile_node);
+		pr_err("Failed to detect valid QG battery profile %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_string(profile_node, "qcom,battery-type",
+				&chip->bp.batt_type_str);
+	if (rc < 0) {
+		pr_err("Failed to detect battery type rc:%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_batterydata_init(profile_node);
+	if (rc < 0) {
+		pr_err("Failed to initialize battery-profile rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
+				&chip->bp.float_volt_uv);
+	if (rc < 0) {
+		pr_err("Failed to read battery float-voltage rc:%d\n", rc);
+		chip->bp.float_volt_uv = -EINVAL;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
+				&chip->bp.fastchg_curr_ma);
+	if (rc < 0) {
+		pr_err("Failed to read battery fastcharge current rc:%d\n", rc);
+		chip->bp.fastchg_curr_ma = -EINVAL;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,qg-batt-profile-ver",
+				&chip->bp.qg_profile_version);
+	if (rc < 0) {
+		pr_err("Failed to read QG profile version rc:%d\n", rc);
+		chip->bp.qg_profile_version = -EINVAL;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "profile=%s FV=%duV FCC=%dma\n",
+			chip->bp.batt_type_str, chip->bp.float_volt_uv,
+			chip->bp.fastchg_curr_ma);
+
+	return 0;
+}
+
+static int qg_setup_battery(struct qpnp_qg *chip)
+{
+	int rc;
+
+	if (!is_battery_present(chip)) {
+		qg_dbg(chip, QG_DEBUG_PROFILE, "Battery Missing!\n");
+		chip->battery_missing = true;
+		chip->profile_loaded = false;
+	} else {
+		/* battery present */
+		rc = get_batt_id_ohm(chip, &chip->batt_id_ohm);
+		if (rc < 0) {
+			pr_err("Failed to detect batt_id rc=%d\n", rc);
+			chip->profile_loaded = false;
+		} else {
+			rc = qg_load_battery_profile(chip);
+			if (rc < 0)
+				pr_err("Failed to load battery-profile rc=%d\n",
+								rc);
+			else
+				chip->profile_loaded = true;
+		}
+	}
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "battery_missing=%d batt_id_ohm=%d Ohm profile_loaded=%d profile=%s\n",
+			chip->battery_missing, chip->batt_id_ohm,
+			chip->profile_loaded, chip->bp.batt_type_str);
+
+	return 0;
+}
+
+static int qg_determine_pon_soc(struct qpnp_qg *chip)
+{
+	u8 status = 0, ocv_type = 0;
+	int rc = 0, batt_temp = 0;
+	bool use_pon_ocv = true, use_shutdown_ocv = false;
+	unsigned long rtc_sec = 0;
+	u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0};
+
+	if (!chip->profile_loaded) {
+		qg_dbg(chip, QG_DEBUG_PON, "No Profile, skipping PON soc\n");
+		return 0;
+	}
+
+	rc = get_rtc_time(&rtc_sec);
+	if (rc < 0) {
+		pr_err("Failed to read RTC time rc=%d\n", rc);
+		goto use_pon_ocv;
+	}
+
+	rc = qg_sdam_read_all(shutdown);
+	if (rc < 0) {
+		pr_err("Failed to read shutdown params rc=%d\n", rc);
+		goto use_pon_ocv;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
+			shutdown[SDAM_VALID],
+			shutdown[SDAM_SOC],
+			shutdown[SDAM_OCV_UV],
+			shutdown[SDAM_TIME_SEC],
+			rtc_sec);
+	/*
+	 * Use the shutdown SOC if
+	 * 1. The device was powered off for < ignore_shutdown_time
+	 * 2. SDAM read is a success & SDAM data is valid
+	 */
+	if (shutdown[SDAM_VALID] && is_between(0,
+			chip->dt.ignore_shutdown_soc_secs,
+			(rtc_sec - shutdown[SDAM_TIME_SEC]))) {
+		use_pon_ocv = false;
+		use_shutdown_ocv = true;
+		ocv_uv = shutdown[SDAM_OCV_UV];
+		soc = shutdown[SDAM_SOC];
+		qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
+	}
+
+use_pon_ocv:
+	if (use_pon_ocv == true) {
+		rc = qg_get_battery_temp(chip, &batt_temp);
+		if (rc) {
+			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
+			goto done;
+		}
+
+		rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+		if (rc < 0) {
+			pr_err("Failed to read status2 register rc=%d\n", rc);
+			goto done;
+		}
+
+		if (status & GOOD_OCV_BIT)
+			ocv_type = GOOD_OCV;
+		else
+			ocv_type = PON_OCV;
+
+		qg_dbg(chip, QG_DEBUG_PON, "Using %s @ PON\n",
+				ocv_type == GOOD_OCV ? "GOOD_OCV" : "PON_OCV");
+
+		rc = qg_read_ocv(chip, &ocv_uv, ocv_type);
+		if (rc < 0) {
+			pr_err("Failed to read ocv rc=%d\n", rc);
+			goto done;
+		}
+
+		rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
+		if (rc < 0) {
+			pr_err("Failed to lookup SOC@PON rc=%d\n", rc);
+			goto done;
+		}
+	}
+done:
+	if (rc < 0) {
+		pr_err("Failed to get SOC @ PON, rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->pon_soc = chip->catch_up_soc = chip->msoc = soc;
+	chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv;
+	chip->kdata.param[QG_PON_OCV_UV].valid = true;
+
+	/* write back to SDAM */
+	chip->sdam_data[SDAM_SOC] = soc;
+	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
+	chip->sdam_data[SDAM_VALID] = 1;
+
+	rc = qg_write_monotonic_soc(chip, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+	rc = qg_update_sdam_params(chip);
+	if (rc < 0)
+		pr_err("Failed to update sdam params rc=%d\n", rc);
+
+	pr_info("use_pon_ocv=%d use_good_ocv=%d use_shutdown_ocv=%d ocv_uv=%duV soc=%d\n",
+			use_pon_ocv, !!(status & GOOD_OCV_BIT),
+			use_shutdown_ocv, ocv_uv, chip->msoc);
+	return 0;
+}
+
+static int qg_set_wa_flags(struct qpnp_qg *chip)
+{
+	switch (chip->pmic_rev_id->pmic_subtype) {
+	case PMI632_SUBTYPE:
+		if (chip->pmic_rev_id->rev4 == PMI632_V1P0_REV4)
+			chip->wa_flags |= QG_VBAT_LOW_WA;
+		break;
+	default:
+		pr_err("Unsupported PMIC subtype %d\n",
+			chip->pmic_rev_id->pmic_subtype);
+		return -EINVAL;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "wa_flags = %x\n", chip->wa_flags);
+
+	return 0;
+}
+
+static int qg_hw_init(struct qpnp_qg *chip)
+{
+	int rc, temp;
+	u8 reg;
+
+	rc = qg_set_wa_flags(chip);
+	if (rc < 0) {
+		pr_err("Failed to update PMIC type flags, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_master_hold(chip, true);
+	if (rc < 0) {
+		pr_err("Failed to hold master, rc=%d\n", rc);
+		goto done_fifo;
+	}
+
+	rc = qg_process_rt_fifo(chip);
+	if (rc < 0) {
+		pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+		goto done_fifo;
+	}
+
+	/* update the changed S2 fifo DT parameters */
+	if (chip->dt.s2_fifo_length > 0) {
+		rc = qg_update_fifo_length(chip, chip->dt.s2_fifo_length);
+		if (rc < 0)
+			goto done_fifo;
+	}
+
+	if (chip->dt.s2_acc_length > 0) {
+		reg = ilog2(chip->dt.s2_acc_length) - 1;
+		rc = qg_masked_write(chip, chip->qg_base +
+				QG_S2_NORMAL_MEAS_CTL2_REG,
+				NUM_OF_ACCUM_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write S2 ACC length, rc=%d\n", rc);
+			goto done_fifo;
+		}
+	}
+
+	if (chip->dt.s2_acc_intvl_ms > 0) {
+		reg = chip->dt.s2_acc_intvl_ms / 10;
+		rc = qg_write(chip, chip->qg_base +
+				QG_S2_NORMAL_MEAS_CTL3_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S2 ACC intrvl, rc=%d\n", rc);
+			goto done_fifo;
+		}
+	}
+
+	/* signal the read thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+
+done_fifo:
+	rc = qg_master_hold(chip, false);
+	if (rc < 0) {
+		pr_err("Failed to release master, rc=%d\n", rc);
+		return rc;
+	}
+	chip->last_fifo_update_time = ktime_get();
+
+	if (chip->dt.ocv_timer_expiry_min != -EINVAL) {
+		if (chip->dt.ocv_timer_expiry_min < 2)
+			chip->dt.ocv_timer_expiry_min = 2;
+		else if (chip->dt.ocv_timer_expiry_min > 30)
+			chip->dt.ocv_timer_expiry_min = 30;
+
+		reg = (chip->dt.ocv_timer_expiry_min - 2) / 4;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_MEAS_CTL4_REG,
+			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write OCV timer, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.ocv_tol_threshold_uv != -EINVAL) {
+		if (chip->dt.ocv_tol_threshold_uv < 0)
+			chip->dt.ocv_tol_threshold_uv = 0;
+		else if (chip->dt.ocv_tol_threshold_uv > 12262)
+			chip->dt.ocv_tol_threshold_uv = 12262;
+
+		reg = chip->dt.ocv_tol_threshold_uv / 195;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_TREND_CTL2_REG,
+			TREND_TOL_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write OCV tol-thresh, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_entry_fifo_length != -EINVAL) {
+		if (chip->dt.s3_entry_fifo_length < 1)
+			chip->dt.s3_entry_fifo_length = 1;
+		else if (chip->dt.s3_entry_fifo_length > 8)
+			chip->dt.s3_entry_fifo_length = 8;
+
+		reg = chip->dt.s3_entry_fifo_length - 1;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
+			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry fifo-length, rc=%d\n",
+							rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_entry_ibat_ua != -EINVAL) {
+		if (chip->dt.s3_entry_ibat_ua < 0)
+			chip->dt.s3_entry_ibat_ua = 0;
+		else if (chip->dt.s3_entry_ibat_ua > 155550)
+			chip->dt.s3_entry_ibat_ua = 155550;
+
+		reg = chip->dt.s3_entry_ibat_ua / 610;
+		rc = qg_write(chip, chip->qg_base +
+				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_exit_ibat_ua != -EINVAL) {
+		if (chip->dt.s3_exit_ibat_ua < 0)
+			chip->dt.s3_exit_ibat_ua = 0;
+		else if (chip->dt.s3_exit_ibat_ua > 155550)
+			chip->dt.s3_exit_ibat_ua = 155550;
+
+		rc = qg_read(chip, chip->qg_base +
+				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to read S3-entry ibat-uA, rc=%d", rc);
+			return rc;
+		}
+		temp = reg * 610;
+		if (chip->dt.s3_exit_ibat_ua < temp)
+			chip->dt.s3_exit_ibat_ua = temp;
+		else
+			chip->dt.s3_exit_ibat_ua -= temp;
+
+		reg = chip->dt.s3_exit_ibat_ua / 610;
+		rc = qg_write(chip,
+			chip->qg_base + QG_S3_EXIT_IBAT_THRESHOLD_REG,
+			&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	/* vbat low */
+	if (chip->dt.vbatt_low_mv < 0)
+		chip->dt.vbatt_low_mv = 0;
+	else if (chip->dt.vbatt_low_mv > 12750)
+		chip->dt.vbatt_low_mv = 12750;
+
+	reg = chip->dt.vbatt_low_mv / 50;
+	rc = qg_write(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to write vbat-low, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* vbat empty */
+	if (chip->dt.vbatt_empty_mv < 0)
+		chip->dt.vbatt_empty_mv = 0;
+	else if (chip->dt.vbatt_empty_mv > 12750)
+		chip->dt.vbatt_empty_mv = 12750;
+
+	reg = chip->dt.vbatt_empty_mv / 50;
+	rc = qg_write(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to write vbat-empty, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int qg_post_init(struct qpnp_qg *chip)
+{
+	/* disable all IRQs if profile is not loaded */
+	if (!chip->profile_loaded) {
+		vote(chip->vbatt_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+		vote(chip->fifo_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+		vote(chip->good_ocv_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+	} else {
+		/* disable GOOD_OCV IRQ at init */
+		vote(chip->good_ocv_irq_disable_votable,
+				QG_INIT_STATE_IRQ_DISABLE, true, 0);
+	}
+
+	return 0;
+}
+
+static int qg_get_irq_index_byname(const char *irq_name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(qg_irqs); i++) {
+		if (strcmp(qg_irqs[i].name, irq_name) == 0)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+static int qg_request_interrupt(struct qpnp_qg *chip,
+		struct device_node *node, const char *irq_name)
+{
+	int rc, irq, irq_index;
+
+	irq = of_irq_get_byname(node, irq_name);
+	if (irq < 0) {
+		pr_err("Failed to get irq %s byname\n", irq_name);
+		return irq;
+	}
+
+	irq_index = qg_get_irq_index_byname(irq_name);
+	if (irq_index < 0) {
+		pr_err("%s is not a defined irq\n", irq_name);
+		return irq_index;
+	}
+
+	if (!qg_irqs[irq_index].handler)
+		return 0;
+
+	rc = devm_request_threaded_irq(chip->dev, irq, NULL,
+				qg_irqs[irq_index].handler,
+				IRQF_ONESHOT, irq_name, chip);
+	if (rc < 0) {
+		pr_err("Failed to request irq %d\n", irq);
+		return rc;
+	}
+
+	qg_irqs[irq_index].irq = irq;
+	if (qg_irqs[irq_index].wake)
+		enable_irq_wake(irq);
+
+	qg_dbg(chip, QG_DEBUG_PON, "IRQ %s registered wakeable=%d\n",
+			qg_irqs[irq_index].name, qg_irqs[irq_index].wake);
+
+	return 0;
+}
+
+static int qg_request_irqs(struct qpnp_qg *chip)
+{
+	struct device_node *node = chip->dev->of_node;
+	struct device_node *child;
+	const char *name;
+	struct property *prop;
+	int rc = 0;
+
+	for_each_available_child_of_node(node, child) {
+		of_property_for_each_string(child, "interrupt-names",
+					    prop, name) {
+			rc = qg_request_interrupt(chip, child, name);
+			if (rc < 0)
+				return rc;
+		}
+	}
+
+
+	return 0;
+}
+
+#define DEFAULT_VBATT_EMPTY_MV		3200
+#define DEFAULT_VBATT_CUTOFF_MV		3400
+#define DEFAULT_VBATT_LOW_MV		3500
+#define DEFAULT_ITERM_MA		100
+#define DEFAULT_S2_FIFO_LENGTH		5
+#define DEFAULT_S2_VBAT_LOW_LENGTH	2
+#define DEFAULT_S2_ACC_LENGTH		128
+#define DEFAULT_S2_ACC_INTVL_MS		100
+#define DEFAULT_DELTA_SOC		1
+#define DEFAULT_SHUTDOWN_SOC_SECS	360
+static int qg_parse_dt(struct qpnp_qg *chip)
+{
+	int rc = 0;
+	struct device_node *revid_node, *child, *node = chip->dev->of_node;
+	u32 base, temp;
+	u8 type;
+
+	if (!node)  {
+		pr_err("Failed to find device-tree node\n");
+		return -ENXIO;
+	}
+
+	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;
+	}
+
+	chip->pmic_rev_id = get_revid_data(revid_node);
+	of_node_put(revid_node);
+	if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+		pr_err("Failed to get pmic_revid, rc=%ld\n",
+			PTR_ERR(chip->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;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "PMIC subtype %d Digital major %d\n",
+		chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
+
+	for_each_available_child_of_node(node, child) {
+		rc = of_property_read_u32(child, "reg", &base);
+		if (rc < 0) {
+			pr_err("Failed to read base address, rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = qg_read(chip, base + PERPH_TYPE_REG, &type, 1);
+		if (rc < 0) {
+			pr_err("Failed to read type, rc=%d\n", rc);
+			return rc;
+		}
+
+		switch (type) {
+		case QG_TYPE:
+			chip->qg_base = base;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!chip->qg_base) {
+		pr_err("QG device node missing\n");
+		return -EINVAL;
+	}
+
+	/* S2 state params */
+	rc = of_property_read_u32(node, "qcom,s2-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_fifo_length = DEFAULT_S2_FIFO_LENGTH;
+	else
+		chip->dt.s2_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH;
+	else
+		chip->dt.s2_vbat_low_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-acc-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_acc_length = DEFAULT_S2_ACC_LENGTH;
+	else
+		chip->dt.s2_acc_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-acc-interval-ms", &temp);
+	if (rc < 0)
+		chip->dt.s2_acc_intvl_ms = DEFAULT_S2_ACC_INTVL_MS;
+	else
+		chip->dt.s2_acc_intvl_ms = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: S2 FIFO length=%d low_vbat_length=%d acc_length=%d acc_interval=%d\n",
+		chip->dt.s2_fifo_length, chip->dt.s2_vbat_low_fifo_length,
+		chip->dt.s2_acc_length, chip->dt.s2_acc_intvl_ms);
+
+	/* OCV params */
+	rc = of_property_read_u32(node, "qcom,ocv-timer-expiry-min", &temp);
+	if (rc < 0)
+		chip->dt.ocv_timer_expiry_min = -EINVAL;
+	else
+		chip->dt.ocv_timer_expiry_min = temp;
+
+	rc = of_property_read_u32(node, "qcom,ocv-tol-threshold-uv", &temp);
+	if (rc < 0)
+		chip->dt.ocv_tol_threshold_uv = -EINVAL;
+	else
+		chip->dt.ocv_tol_threshold_uv = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: OCV timer_expiry =%dmin ocv_tol_threshold=%duV\n",
+		chip->dt.ocv_timer_expiry_min, chip->dt.ocv_tol_threshold_uv);
+
+	/* S3 sleep configuration */
+	rc = of_property_read_u32(node, "qcom,s3-entry-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s3_entry_fifo_length = -EINVAL;
+	else
+		chip->dt.s3_entry_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp);
+	if (rc < 0)
+		chip->dt.s3_entry_ibat_ua = -EINVAL;
+	else
+		chip->dt.s3_entry_ibat_ua = temp;
+
+	rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp);
+	if (rc < 0)
+		chip->dt.s3_exit_ibat_ua = -EINVAL;
+	else
+		chip->dt.s3_exit_ibat_ua = temp;
+
+	/* VBAT thresholds */
+	rc = of_property_read_u32(node, "qcom,vbatt-empty-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_empty_mv = DEFAULT_VBATT_EMPTY_MV;
+	else
+		chip->dt.vbatt_empty_mv = temp;
+
+	rc = of_property_read_u32(node, "qcom,vbatt-low-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_low_mv = DEFAULT_VBATT_LOW_MV;
+	else
+		chip->dt.vbatt_low_mv = temp;
+
+	rc = of_property_read_u32(node, "qcom,vbatt-cutoff-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_cutoff_mv = DEFAULT_VBATT_CUTOFF_MV;
+	else
+		chip->dt.vbatt_cutoff_mv = temp;
+
+	/* IBAT thresholds */
+	rc = of_property_read_u32(node, "qcom,qg-iterm-ma", &temp);
+	if (rc < 0)
+		chip->dt.iterm_ma = DEFAULT_ITERM_MA;
+	else
+		chip->dt.iterm_ma = temp;
+
+	rc = of_property_read_u32(node, "qcom,delta-soc", &temp);
+	if (rc < 0)
+		chip->dt.delta_soc = DEFAULT_DELTA_SOC;
+	else
+		chip->dt.delta_soc = temp;
+
+	rc = of_property_read_u32(node, "qcom,ignore-shutdown-soc-secs", &temp);
+	if (rc < 0)
+		chip->dt.ignore_shutdown_soc_secs = DEFAULT_SHUTDOWN_SOC_SECS;
+	else
+		chip->dt.ignore_shutdown_soc_secs = temp;
+
+	chip->dt.hold_soc_while_full = of_property_read_bool(node,
+					"qcom,hold-soc-while-full");
+
+	chip->dt.linearize_soc = of_property_read_bool(node,
+					"qcom,linearize-soc");
+
+	rc = of_property_read_u32(node, "qcom,rbat-conn-mohm", &temp);
+	if (rc < 0)
+		chip->dt.rbat_conn_mohm = 0;
+	else
+		chip->dt.rbat_conn_mohm = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n",
+			chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
+			chip->dt.delta_soc);
+
+	return 0;
+}
+
+static int process_suspend(struct qpnp_qg *chip)
+{
+	u8 status = 0;
+	int rc;
+	u32 fifo_rt_length = 0, sleep_fifo_length = 0;
+
+	/* skip if profile is not loaded */
+	if (!chip->profile_loaded)
+		return 0;
+
+	chip->suspend_data = false;
+
+	/* ignore any suspend processing if we are charging */
+	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+		qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n");
+		return 0;
+	}
+
+	rc = get_fifo_length(chip, &fifo_rt_length, true);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO RT count, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
+			(u8 *)&sleep_fifo_length, 1);
+	if (rc < 0) {
+		pr_err("Failed to read sleep FIFO count, rc=%d\n", rc);
+		return rc;
+	}
+	sleep_fifo_length &= SLEEP_IBAT_QUALIFIED_LENGTH_MASK;
+	/*
+	 * If the real-time FIFO count is greater than
+	 * the the #fifo to enter sleep, save the FIFO data
+	 * and reset the fifo count.
+	 */
+	if (fifo_rt_length >= (chip->dt.s2_fifo_length - sleep_fifo_length)) {
+		rc = qg_master_hold(chip, true);
+		if (rc < 0) {
+			pr_err("Failed to hold master, rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = qg_process_rt_fifo(chip);
+		if (rc < 0) {
+			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+			qg_master_hold(chip, false);
+			return rc;
+		}
+
+		rc = qg_master_hold(chip, false);
+		if (rc < 0) {
+			pr_err("Failed to release master, rc=%d\n", rc);
+			return rc;
+		}
+		/* FIFOs restarted */
+		chip->last_fifo_update_time = ktime_get();
+
+		chip->suspend_data = true;
+	}
+
+	/* read STATUS2 register to clear its last state */
+	qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+
+	qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n",
+			fifo_rt_length, sleep_fifo_length,
+			chip->dt.s2_fifo_length, chip->suspend_data);
+
+	return rc;
+}
+
+static int process_resume(struct qpnp_qg *chip)
+{
+	u8 status2 = 0, rt_status = 0;
+	u32 ocv_uv = 0;
+	int rc, batt_temp = 0;
+
+	/* skip if profile is not loaded */
+	if (!chip->profile_loaded)
+		return 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1);
+	if (rc < 0) {
+		pr_err("Failed to read status2 register, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (status2 & GOOD_OCV_BIT) {
+		rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
+		if (rc < 0) {
+			pr_err("Failed to read good_ocv, rc=%d\n", rc);
+			return rc;
+		}
+		rc = qg_get_battery_temp(chip, &batt_temp);
+		if (rc < 0) {
+			pr_err("Failed to read BATT_TEMP, rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
+		 /* Clear suspend data as there has been a GOOD OCV */
+		chip->suspend_data = false;
+		qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
+				ocv_uv);
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_INT_LATCHED_STS_REG,
+						&rt_status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read latched status register, rc=%d\n", rc);
+		return rc;
+	}
+	rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT;
+
+	qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d\n",
+				!!rt_status, chip->suspend_data,
+				chip->kdata.param[QG_GOOD_OCV_UV].valid);
+	/*
+	 * If this is not a wakeup from FIFO-done,
+	 * process the data immediately if - we have data from
+	 * suspend or there is a good OCV.
+	 */
+	if (!rt_status && (chip->suspend_data ||
+			chip->kdata.param[QG_GOOD_OCV_UV].valid)) {
+		vote(chip->awake_votable, SUSPEND_DATA_VOTER, true, 0);
+		/* signal the read thread */
+		chip->data_ready = true;
+		wake_up_interruptible(&chip->qg_wait_q);
+		chip->suspend_data = false;
+	}
+
+	return rc;
+}
+
+static int qpnp_qg_suspend_noirq(struct device *dev)
+{
+	int rc;
+	struct qpnp_qg *chip = dev_get_drvdata(dev);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_suspend(chip);
+	if (rc < 0)
+		pr_err("Failed to process QG suspend, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static int qpnp_qg_resume_noirq(struct device *dev)
+{
+	int rc;
+	struct qpnp_qg *chip = dev_get_drvdata(dev);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_resume(chip);
+	if (rc < 0)
+		pr_err("Failed to process QG resume, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops qpnp_qg_pm_ops = {
+	.suspend_noirq	= qpnp_qg_suspend_noirq,
+	.resume_noirq	= qpnp_qg_resume_noirq,
+};
+
+static int qpnp_qg_probe(struct platform_device *pdev)
+{
+	int rc = 0, soc = 0;
+	struct qpnp_qg *chip;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!chip->regmap) {
+		pr_err("Parent regmap is unavailable\n");
+		return -ENXIO;
+	}
+
+	/* VADC for BID */
+	chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "qg");
+	if (IS_ERR(chip->vadc_dev)) {
+		rc = PTR_ERR(chip->vadc_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("Failed to find VADC node, rc=%d\n", rc);
+
+		return rc;
+	}
+
+	chip->dev = &pdev->dev;
+	chip->debug_mask = &qg_debug_mask;
+	platform_set_drvdata(pdev, chip);
+	INIT_WORK(&chip->udata_work, process_udata_work);
+	INIT_WORK(&chip->qg_status_change_work, qg_status_change_work);
+	mutex_init(&chip->bus_lock);
+	mutex_init(&chip->soc_lock);
+	mutex_init(&chip->data_lock);
+	init_waitqueue_head(&chip->qg_wait_q);
+	chip->maint_soc = -EINVAL;
+
+	rc = qg_parse_dt(chip);
+	if (rc < 0) {
+		pr_err("Failed to parse DT, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_hw_init(chip);
+	if (rc < 0) {
+		pr_err("Failed to hw_init, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_setup_battery(chip);
+	if (rc < 0) {
+		pr_err("Failed to setup battery, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_register_device(chip);
+	if (rc < 0) {
+		pr_err("Failed to register QG char device, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_sdam_init(chip->dev);
+	if (rc < 0) {
+		pr_err("Failed to initialize QG SDAM, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_soc_init(chip);
+	if (rc < 0) {
+		pr_err("Failed to initialize SOC scaling init rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_determine_pon_soc(chip);
+	if (rc < 0) {
+		pr_err("Failed to determine initial state, rc=%d\n", rc);
+		goto fail_device;
+	}
+
+	chip->awake_votable = create_votable("QG_WS", VOTE_SET_ANY,
+					 qg_awake_cb, chip);
+	if (IS_ERR(chip->awake_votable)) {
+		rc = PTR_ERR(chip->awake_votable);
+		chip->awake_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->vbatt_irq_disable_votable = create_votable("QG_VBATT_IRQ_DISABLE",
+				VOTE_SET_ANY, qg_vbatt_irq_disable_cb, chip);
+	if (IS_ERR(chip->vbatt_irq_disable_votable)) {
+		rc = PTR_ERR(chip->vbatt_irq_disable_votable);
+		chip->vbatt_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->fifo_irq_disable_votable = create_votable("QG_FIFO_IRQ_DISABLE",
+				VOTE_SET_ANY, qg_fifo_irq_disable_cb, chip);
+	if (IS_ERR(chip->fifo_irq_disable_votable)) {
+		rc = PTR_ERR(chip->fifo_irq_disable_votable);
+		chip->fifo_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->good_ocv_irq_disable_votable =
+			create_votable("QG_GOOD_IRQ_DISABLE",
+			VOTE_SET_ANY, qg_good_ocv_irq_disable_cb, chip);
+	if (IS_ERR(chip->good_ocv_irq_disable_votable)) {
+		rc = PTR_ERR(chip->good_ocv_irq_disable_votable);
+		chip->good_ocv_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	rc = qg_init_psy(chip);
+	if (rc < 0) {
+		pr_err("Failed to initialize QG psy, rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	rc = qg_request_irqs(chip);
+	if (rc < 0) {
+		pr_err("Failed to register QG interrupts, rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	rc = qg_post_init(chip);
+	if (rc < 0) {
+		pr_err("Failed in qg_post_init rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	qg_get_battery_capacity(chip, &soc);
+	pr_info("QG initialized! battery_profile=%s SOC=%d\n",
+				qg_get_battery_type(chip), soc);
+
+	return rc;
+
+fail_votable:
+	destroy_votable(chip->awake_votable);
+fail_device:
+	device_destroy(chip->qg_class, chip->dev_no);
+	cdev_del(&chip->qg_cdev);
+	unregister_chrdev_region(chip->dev_no, 1);
+	return rc;
+}
+
+static int qpnp_qg_remove(struct platform_device *pdev)
+{
+	struct qpnp_qg *chip = platform_get_drvdata(pdev);
+
+	qg_batterydata_exit();
+	qg_soc_exit(chip);
+
+	cancel_work_sync(&chip->udata_work);
+	cancel_work_sync(&chip->qg_status_change_work);
+	device_destroy(chip->qg_class, chip->dev_no);
+	cdev_del(&chip->qg_cdev);
+	unregister_chrdev_region(chip->dev_no, 1);
+	mutex_destroy(&chip->bus_lock);
+	mutex_destroy(&chip->data_lock);
+	mutex_destroy(&chip->soc_lock);
+	if (chip->awake_votable)
+		destroy_votable(chip->awake_votable);
+
+	return 0;
+}
+
+static const struct of_device_id match_table[] = {
+	{ .compatible = "qcom,qpnp-qg", },
+	{ },
+};
+
+static struct platform_driver qpnp_qg_driver = {
+	.driver		= {
+		.name		= "qcom,qpnp-qg",
+		.owner		= THIS_MODULE,
+		.of_match_table	= match_table,
+		.pm		= &qpnp_qg_pm_ops,
+	},
+	.probe		= qpnp_qg_probe,
+	.remove		= qpnp_qg_remove,
+};
+module_platform_driver(qpnp_qg_driver);
+
+MODULE_DESCRIPTION("QPNP QG Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
new file mode 100644
index 0000000..b91850d
--- /dev/null
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -0,0 +1,2370 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/log2.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/pmic-voter.h>
+#include "smb5-reg.h"
+#include "smb5-lib.h"
+#include "schgm-flash.h"
+
+static struct smb_params smb5_pmi632_params = {
+	.fcc			= {
+		.name   = "fast charge current",
+		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.fv			= {
+		.name   = "float voltage",
+		.reg    = CHGR_FLOAT_VOLTAGE_CFG_REG,
+		.min_u  = 3600000,
+		.max_u  = 4800000,
+		.step_u = 10000,
+	},
+	.usb_icl		= {
+		.name   = "usb input current limit",
+		.reg    = USBIN_CURRENT_LIMIT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.icl_stat		= {
+		.name   = "input current limit status",
+		.reg    = AICL_ICL_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.otg_cl			= {
+		.name	= "usb otg current limit",
+		.reg	= DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+		.min_u	= 500000,
+		.max_u	= 1000000,
+		.step_u	= 250000,
+	},
+	.jeita_cc_comp_hot	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_HOT_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.jeita_cc_comp_cold	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_COLD_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.freq_switcher		= {
+		.name	= "switching frequency",
+		.reg	= DCDC_FSW_SEL_REG,
+		.min_u	= 600,
+		.max_u	= 1200,
+		.step_u	= 400,
+		.set_proc = smblib_set_chg_freq,
+	},
+};
+
+static struct smb_params smb5_pmi855_params = {
+	.fcc			= {
+		.name   = "fast charge current",
+		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 8000000,
+		.step_u = 25000,
+	},
+	.fv			= {
+		.name   = "float voltage",
+		.reg    = CHGR_FLOAT_VOLTAGE_CFG_REG,
+		.min_u  = 3600000,
+		.max_u  = 4790000,
+		.step_u = 10000,
+	},
+	.usb_icl		= {
+		.name   = "usb input current limit",
+		.reg    = USBIN_CURRENT_LIMIT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 5000000,
+		.step_u = 50000,
+	},
+	.icl_stat		= {
+		.name   = "input current limit status",
+		.reg    = AICL_ICL_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 5000000,
+		.step_u = 50000,
+	},
+	.otg_cl			= {
+		.name	= "usb otg current limit",
+		.reg	= DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+		.min_u	= 500000,
+		.max_u	= 3000000,
+		.step_u	= 500000,
+	},
+	.jeita_cc_comp_hot	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_HOT_REG,
+		.min_u	= 0,
+		.max_u	= 8000000,
+		.step_u	= 25000,
+		.set_proc = NULL,
+	},
+	.jeita_cc_comp_cold	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_COLD_REG,
+		.min_u	= 0,
+		.max_u	= 8000000,
+		.step_u	= 25000,
+		.set_proc = NULL,
+	},
+	.freq_switcher		= {
+		.name	= "switching frequency",
+		.reg	= DCDC_FSW_SEL_REG,
+		.min_u	= 1200,
+		.max_u	= 2400,
+		.step_u	= 400,
+		.set_proc = NULL,
+	},
+};
+
+struct smb_dt_props {
+	int			usb_icl_ua;
+	struct device_node	*revid_dev_node;
+	enum float_options	float_option;
+	int			chg_inhibit_thr_mv;
+	bool			no_battery;
+	bool			hvdcp_disable;
+	int			auto_recharge_soc;
+	int			auto_recharge_vbat_mv;
+	int			wd_bark_time;
+	int			batt_profile_fcc_ua;
+	int			batt_profile_fv_uv;
+};
+
+struct smb5 {
+	struct smb_charger	chg;
+	struct dentry		*dfs_root;
+	struct smb_dt_props	dt;
+};
+
+static int __debug_mask;
+module_param_named(
+	debug_mask, __debug_mask, int, 0600
+);
+
+static int __weak_chg_icl_ua = 500000;
+module_param_named(
+	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
+);
+
+#define PMI632_MAX_ICL_UA	3000000
+static int smb5_chg_config_init(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct pmic_revid_data *pmic_rev_id;
+	struct device_node *revid_dev_node;
+	int rc = 0;
+
+	revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+					  "qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_err("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR_OR_NULL(pmic_rev_id)) {
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		rc =  -EPROBE_DEFER;
+		goto out;
+	}
+
+	switch (pmic_rev_id->pmic_subtype) {
+	case PM855B_SUBTYPE:
+		chip->chg.smb_version = PM855B_SUBTYPE;
+		chg->param = smb5_pmi855_params;
+		chg->name = "pm855b_charger";
+		break;
+	case PMI632_SUBTYPE:
+		chip->chg.smb_version = PMI632_SUBTYPE;
+		chg->param = smb5_pmi632_params;
+		chg->use_extcon = true;
+		chg->name = "pmi632_charger";
+		chg->hw_max_icl_ua =
+			(chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
+						: PMI632_MAX_ICL_UA;
+		chg->chg_freq.freq_5V			= 600;
+		chg->chg_freq.freq_6V_8V		= 800;
+		chg->chg_freq.freq_9V			= 1050;
+		chg->chg_freq.freq_removal		= 1050;
+		chg->chg_freq.freq_below_otg_threshold	= 800;
+		chg->chg_freq.freq_above_otg_threshold	= 800;
+		break;
+	default:
+		pr_err("PMIC subtype %d not supported\n",
+				pmic_rev_id->pmic_subtype);
+		rc = -EINVAL;
+	}
+
+out:
+	of_node_put(revid_dev_node);
+	return rc;
+}
+
+#define MICRO_1P5A		1500000
+#define MICRO_P1A		100000
+#define OTG_DEFAULT_DEGLITCH_TIME_MS	50
+#define MIN_WD_BARK_TIME		16
+#define DEFAULT_WD_BARK_TIME		64
+#define BITE_WDOG_TIMEOUT_8S		0x3
+#define BARK_WDOG_TIMEOUT_MASK		GENMASK(3, 2)
+#define BARK_WDOG_TIMEOUT_SHIFT		2
+static int smb5_parse_dt(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct device_node *node = chg->dev->of_node;
+	int rc, byte_len;
+
+	if (!node) {
+		pr_err("device tree node missing\n");
+		return -EINVAL;
+	}
+
+	chg->step_chg_enabled = of_property_read_bool(node,
+				"qcom,step-charging-enable");
+
+	chg->sw_jeita_enabled = of_property_read_bool(node,
+				"qcom,sw-jeita-enable");
+
+	rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
+					&chip->dt.wd_bark_time);
+	if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
+		chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;
+
+	chip->dt.no_battery = of_property_read_bool(node,
+						"qcom,batteryless-platform");
+
+	rc = of_property_read_u32(node,
+			"qcom,fcc-max-ua", &chip->dt.batt_profile_fcc_ua);
+	if (rc < 0)
+		chip->dt.batt_profile_fcc_ua = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,fv-max-uv", &chip->dt.batt_profile_fv_uv);
+	if (rc < 0)
+		chip->dt.batt_profile_fv_uv = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
+	if (rc < 0)
+		chip->dt.usb_icl_ua = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,otg-cl-ua", &chg->otg_cl_ua);
+	if (rc < 0)
+		chg->otg_cl_ua = MICRO_1P5A;
+
+	if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) {
+		chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len,
+			GFP_KERNEL);
+
+		if (chg->thermal_mitigation == NULL)
+			return -ENOMEM;
+
+		chg->thermal_levels = byte_len / sizeof(u32);
+		rc = of_property_read_u32_array(node,
+				"qcom,thermal-mitigation",
+				chg->thermal_mitigation,
+				chg->thermal_levels);
+		if (rc < 0) {
+			dev_err(chg->dev,
+				"Couldn't read threm limits rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	rc = of_property_read_u32(node, "qcom,float-option",
+						&chip->dt.float_option);
+	if (!rc && (chip->dt.float_option < 0 || chip->dt.float_option > 4)) {
+		pr_err("qcom,float-option is out of range [0, 4]\n");
+		return -EINVAL;
+	}
+
+	chip->dt.hvdcp_disable = of_property_read_bool(node,
+						"qcom,hvdcp-disable");
+
+
+	rc = of_property_read_u32(node, "qcom,chg-inhibit-threshold-mv",
+				&chip->dt.chg_inhibit_thr_mv);
+	if (!rc && (chip->dt.chg_inhibit_thr_mv < 0 ||
+				chip->dt.chg_inhibit_thr_mv > 300)) {
+		pr_err("qcom,chg-inhibit-threshold-mv is incorrect\n");
+		return -EINVAL;
+	}
+
+	chip->dt.auto_recharge_soc = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,auto-recharge-soc",
+				&chip->dt.auto_recharge_soc);
+	if (!rc && (chip->dt.auto_recharge_soc < 0 ||
+			chip->dt.auto_recharge_soc > 100)) {
+		pr_err("qcom,auto-recharge-soc is incorrect\n");
+		return -EINVAL;
+	}
+	chg->auto_recharge_soc = chip->dt.auto_recharge_soc;
+
+	chip->dt.auto_recharge_vbat_mv = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,auto-recharge-vbat-mv",
+				&chip->dt.auto_recharge_vbat_mv);
+	if (!rc && (chip->dt.auto_recharge_vbat_mv < 0)) {
+		pr_err("qcom,auto-recharge-vbat-mv is incorrect\n");
+		return -EINVAL;
+	}
+
+	chg->dcp_icl_ua = chip->dt.usb_icl_ua;
+
+	chg->suspend_input_on_debug_batt = of_property_read_bool(node,
+					"qcom,suspend-input-on-debug-batt");
+
+	rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms",
+					&chg->otg_delay_ms);
+	if (rc < 0)
+		chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
+
+	return 0;
+}
+
+/************************
+ * USB PSY REGISTRATION *
+ ************************/
+static enum power_supply_property smb5_usb_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PD_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_TYPEC_MODE,
+	POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
+	POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
+	POWER_SUPPLY_PROP_PD_ALLOWED,
+	POWER_SUPPLY_PROP_PD_ACTIVE,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
+	POWER_SUPPLY_PROP_BOOST_CURRENT,
+	POWER_SUPPLY_PROP_PE_START,
+	POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
+	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+	POWER_SUPPLY_PROP_REAL_TYPE,
+	POWER_SUPPLY_PROP_PR_SWAP,
+	POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_SCOPE,
+};
+
+static int smb5_usb_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval pval;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_usb_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_usb_online(chg, val);
+		if (!val->intval)
+			break;
+
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			val->intval = 0;
+		else
+			val->intval = 1;
+
+		if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_get_prop_usb_voltage_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB_PD;
+		break;
+	case POWER_SUPPLY_PROP_REAL_TYPE:
+		val->intval = chg->real_charger_type;
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_MODE:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = POWER_SUPPLY_TYPEC_NONE;
+		else
+			val->intval = chg->typec_mode;
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		else
+			rc = smblib_get_prop_typec_power_role(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = 0;
+		else
+			rc = smblib_get_prop_typec_cc_orientation(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ALLOWED:
+		rc = smblib_get_prop_pd_allowed(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ACTIVE:
+		val->intval = chg->pd_active;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_BOOST_CURRENT:
+		val->intval = chg->boost_current_ua;
+		break;
+	case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+		rc = smblib_get_prop_pd_in_hard_reset(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+		val->intval = chg->system_suspend_supported;
+		break;
+	case POWER_SUPPLY_PROP_PE_START:
+		rc = smblib_get_pe_start(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
+		rc = smblib_get_charge_current(chg, &val->intval);
+		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_get_prop_pr_swap_in_progress(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
+		val->intval = chg->voltage_max_uv;
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
+		val->intval = chg->voltage_min_uv;
+		break;
+	case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable,
+					      USB_PSY_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
+		val->intval = chg->connector_type;
+		break;
+	case POWER_SUPPLY_PROP_SCOPE:
+		val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
+		rc = smblib_get_prop_usb_present(chg, &pval);
+		if (rc < 0)
+			break;
+		val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
+				: chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
+						: POWER_SUPPLY_SCOPE_UNKNOWN;
+		break;
+	default:
+		pr_err("get prop %d is not supported in usb\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	mutex_lock(&chg->lock);
+	if (!chg->typec_present) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+		rc = smblib_set_prop_pd_current_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+		rc = smblib_set_prop_typec_power_role(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ACTIVE:
+		rc = smblib_set_prop_pd_active(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+		rc = smblib_set_prop_pd_in_hard_reset(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+		chg->system_suspend_supported = val->intval;
+		break;
+	case POWER_SUPPLY_PROP_BOOST_CURRENT:
+		rc = smblib_set_prop_boost_current(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		rc = vote(chg->usb_icl_votable, CTM_VOTER,
+						val->intval >= 0, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_set_prop_pr_swap_in_progress(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
+		rc = smblib_set_prop_pd_voltage_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
+		rc = smblib_set_prop_pd_voltage_min(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
+		rc = smblib_set_prop_sdp_current_max(chg, val);
+		break;
+	default:
+		pr_err("set prop %d is not supported\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+unlock:
+	mutex_unlock(&chg->lock);
+	return rc;
+}
+
+static int smb5_usb_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct power_supply_desc usb_psy_desc = {
+	.name = "usb",
+	.type = POWER_SUPPLY_TYPE_USB_PD,
+	.properties = smb5_usb_props,
+	.num_properties = ARRAY_SIZE(smb5_usb_props),
+	.get_property = smb5_usb_get_prop,
+	.set_property = smb5_usb_set_prop,
+	.property_is_writeable = smb5_usb_prop_is_writeable,
+};
+
+static int smb5_init_usb_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_cfg.drv_data = chip;
+	usb_cfg.of_node = chg->dev->of_node;
+	chg->usb_psy = devm_power_supply_register(chg->dev,
+						  &usb_psy_desc,
+						  &usb_cfg);
+	if (IS_ERR(chg->usb_psy)) {
+		pr_err("Couldn't register USB power supply\n");
+		return PTR_ERR(chg->usb_psy);
+	}
+
+	return 0;
+}
+
+/********************************
+ * USB PC_PORT PSY REGISTRATION *
+ ********************************/
+static enum power_supply_property smb5_usb_port_props[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static int smb5_usb_port_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_usb_online(chg, val);
+		if (!val->intval)
+			break;
+
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			val->intval = 1;
+		else
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		val->intval = 5000000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	default:
+		pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
+				psp);
+		return -EINVAL;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_port_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	switch (psp) {
+	default:
+		pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
+				psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc usb_port_psy_desc = {
+	.name		= "pc_port",
+	.type		= POWER_SUPPLY_TYPE_USB,
+	.properties	= smb5_usb_port_props,
+	.num_properties	= ARRAY_SIZE(smb5_usb_port_props),
+	.get_property	= smb5_usb_port_get_prop,
+	.set_property	= smb5_usb_port_set_prop,
+};
+
+static int smb5_init_usb_port_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_port_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_port_cfg.drv_data = chip;
+	usb_port_cfg.of_node = chg->dev->of_node;
+	chg->usb_port_psy = devm_power_supply_register(chg->dev,
+						  &usb_port_psy_desc,
+						  &usb_port_cfg);
+	if (IS_ERR(chg->usb_port_psy)) {
+		pr_err("Couldn't register USB pc_port power supply\n");
+		return PTR_ERR(chg->usb_port_psy);
+	}
+
+	return 0;
+}
+
+/*****************************
+ * USB MAIN PSY REGISTRATION *
+ *****************************/
+
+static enum power_supply_property smb5_usb_main_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
+	POWER_SUPPLY_PROP_FCC_DELTA,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_FLASH_ACTIVE,
+	POWER_SUPPLY_PROP_FLASH_TRIGGER,
+};
+
+static int smb5_usb_main_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		rc = smblib_get_charge_param(chg, &chg->param.fcc,
+							&val->intval);
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_MAIN;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
+		rc = smblib_get_prop_input_voltage_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_FCC_DELTA:
+		rc = smblib_get_prop_fcc_delta(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_icl_current(chg, &val->intval);
+		break;
+	case POWER_SUPPLY_PROP_FLASH_ACTIVE:
+		val->intval = chg->flash_active;
+		break;
+	case POWER_SUPPLY_PROP_FLASH_TRIGGER:
+		rc = schgm_flash_get_vreg_ok(chg, &val->intval);
+		break;
+	default:
+		pr_debug("get prop %d is not supported in usb-main\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_main_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_set_icl_current(chg, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_FLASH_ACTIVE:
+		chg->flash_active = val->intval;
+		break;
+	default:
+		pr_err("set prop %d is not supported\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc usb_main_psy_desc = {
+	.name		= "main",
+	.type		= POWER_SUPPLY_TYPE_MAIN,
+	.properties	= smb5_usb_main_props,
+	.num_properties	= ARRAY_SIZE(smb5_usb_main_props),
+	.get_property	= smb5_usb_main_get_prop,
+	.set_property	= smb5_usb_main_set_prop,
+};
+
+static int smb5_init_usb_main_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_main_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_main_cfg.drv_data = chip;
+	usb_main_cfg.of_node = chg->dev->of_node;
+	chg->usb_main_psy = devm_power_supply_register(chg->dev,
+						  &usb_main_psy_desc,
+						  &usb_main_cfg);
+	if (IS_ERR(chg->usb_main_psy)) {
+		pr_err("Couldn't register USB main power supply\n");
+		return PTR_ERR(chg->usb_main_psy);
+	}
+
+	return 0;
+}
+
+/*************************
+ * DC PSY REGISTRATION   *
+ *************************/
+
+static enum power_supply_property smb5_dc_props[] = {
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_REAL_TYPE,
+};
+
+static int smb5_dc_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		val->intval = get_effective_result(chg->dc_suspend_votable);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_dc_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_dc_online(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_REAL_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_WIPOWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+	return 0;
+}
+
+static int smb5_dc_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = vote(chg->dc_suspend_votable, WBC_VOTER,
+				(bool)val->intval, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int smb5_dc_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	int rc;
+
+	switch (psp) {
+	default:
+		rc = 0;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc dc_psy_desc = {
+	.name = "dc",
+	.type = POWER_SUPPLY_TYPE_WIRELESS,
+	.properties = smb5_dc_props,
+	.num_properties = ARRAY_SIZE(smb5_dc_props),
+	.get_property = smb5_dc_get_prop,
+	.set_property = smb5_dc_set_prop,
+	.property_is_writeable = smb5_dc_prop_is_writeable,
+};
+
+static int smb5_init_dc_psy(struct smb5 *chip)
+{
+	struct power_supply_config dc_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	dc_cfg.drv_data = chip;
+	dc_cfg.of_node = chg->dev->of_node;
+	chg->dc_psy = devm_power_supply_register(chg->dev,
+						  &dc_psy_desc,
+						  &dc_cfg);
+	if (IS_ERR(chg->dc_psy)) {
+		pr_err("Couldn't register USB power supply\n");
+		return PTR_ERR(chg->dc_psy);
+	}
+
+	return 0;
+}
+
+/*************************
+ * BATT PSY REGISTRATION *
+ *************************/
+static enum power_supply_property smb5_batt_props[] = {
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
+	POWER_SUPPLY_PROP_CHARGE_DONE,
+	POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+	POWER_SUPPLY_PROP_SET_SHIP_MODE,
+	POWER_SUPPLY_PROP_DIE_HEALTH,
+	POWER_SUPPLY_PROP_RERUN_AICL,
+	POWER_SUPPLY_PROP_DP_DM,
+	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
+	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_RECHARGE_SOC,
+};
+
+static int smb5_batt_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb_charger *chg = power_supply_get_drvdata(psy);
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		rc = smblib_get_prop_batt_status(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		rc = smblib_get_prop_batt_health(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_batt_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = smblib_get_prop_input_suspend(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		rc = smblib_get_prop_batt_charge_type(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = smblib_get_prop_batt_capacity(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+		rc = smblib_get_prop_system_temp_level(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
+		rc = smblib_get_prop_system_temp_level_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+		rc = smblib_get_prop_input_current_limited(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+		val->intval = chg->step_chg_enabled;
+		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		val->intval = chg->sw_jeita_enabled;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		rc = smblib_get_prop_batt_voltage_now(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		val->intval = get_client_vote(chg->fv_votable,
+				BATT_PROFILE_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		rc = smblib_get_prop_batt_current_now(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		val->intval = get_client_vote(chg->fcc_votable,
+					      BATT_PROFILE_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		rc = smblib_get_prop_batt_temp(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_DONE:
+		rc = smblib_get_prop_batt_charge_done(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+		val->intval = get_client_vote(chg->pl_disable_votable,
+					      USER_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		/* Not in ship mode as long as device is active */
+		val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		if (chg->die_health == -EINVAL)
+			rc = smblib_get_prop_die_health(chg, val);
+		else
+			val->intval = chg->die_health;
+		break;
+	case POWER_SUPPLY_PROP_DP_DM:
+		val->intval = chg->pulse_cnt;
+		break;
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+		val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		rc = smblib_get_prop_batt_charge_counter(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_RECHARGE_SOC:
+		val->intval = chg->auto_recharge_soc;
+		break;
+	default:
+		pr_err("batt power supply prop %d not supported\n", psp);
+		return -EINVAL;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_batt_set_prop(struct power_supply *psy,
+		enum power_supply_property prop,
+		const union power_supply_propval *val)
+{
+	int rc = 0;
+	struct smb_charger *chg = power_supply_get_drvdata(psy);
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_STATUS:
+		rc = smblib_set_prop_batt_status(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = smblib_set_prop_input_suspend(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+		rc = smblib_set_prop_system_temp_level(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = smblib_set_prop_batt_capacity(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+		vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		chg->batt_profile_fv_uv = val->intval;
+		vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+		chg->step_chg_enabled = !!val->intval;
+		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		if (chg->sw_jeita_enabled != (!!val->intval)) {
+			rc = smblib_disable_hw_jeita(chg, !!val->intval);
+			if (rc == 0)
+				chg->sw_jeita_enabled = !!val->intval;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		chg->batt_profile_fcc_ua = val->intval;
+		vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		/* Not in ship mode as long as the device is active */
+		if (!val->intval)
+			break;
+		if (chg->pl.psy)
+			power_supply_set_property(chg->pl.psy,
+				POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
+		rc = smblib_set_prop_ship_mode(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+		rc = smblib_rerun_aicl(chg);
+		break;
+	case POWER_SUPPLY_PROP_DP_DM:
+		rc = smblib_dp_dm(chg, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+		rc = smblib_set_prop_input_current_limited(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		chg->die_health = val->intval;
+		power_supply_changed(chg->batt_psy);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int smb5_batt_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
+	case POWER_SUPPLY_PROP_CAPACITY:
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+	case POWER_SUPPLY_PROP_DP_DM:
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct power_supply_desc batt_psy_desc = {
+	.name = "battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = smb5_batt_props,
+	.num_properties = ARRAY_SIZE(smb5_batt_props),
+	.get_property = smb5_batt_get_prop,
+	.set_property = smb5_batt_set_prop,
+	.property_is_writeable = smb5_batt_prop_is_writeable,
+};
+
+static int smb5_init_batt_psy(struct smb5 *chip)
+{
+	struct power_supply_config batt_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	batt_cfg.drv_data = chg;
+	batt_cfg.of_node = chg->dev->of_node;
+	chg->batt_psy = devm_power_supply_register(chg->dev,
+					   &batt_psy_desc,
+					   &batt_cfg);
+	if (IS_ERR(chg->batt_psy)) {
+		pr_err("Couldn't register battery power supply\n");
+		return PTR_ERR(chg->batt_psy);
+	}
+
+	return rc;
+}
+
+/******************************
+ * VBUS REGULATOR REGISTRATION *
+ ******************************/
+
+static struct regulator_ops smb5_vbus_reg_ops = {
+	.enable = smblib_vbus_regulator_enable,
+	.disable = smblib_vbus_regulator_disable,
+	.is_enabled = smblib_vbus_regulator_is_enabled,
+};
+
+static int smb5_init_vbus_regulator(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct regulator_config cfg = {};
+	int rc = 0;
+
+	chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
+				      GFP_KERNEL);
+	if (!chg->vbus_vreg)
+		return -ENOMEM;
+
+	cfg.dev = chg->dev;
+	cfg.driver_data = chip;
+
+	chg->vbus_vreg->rdesc.owner = THIS_MODULE;
+	chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
+	chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
+	chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
+	chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
+
+	chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
+						&chg->vbus_vreg->rdesc, &cfg);
+	if (IS_ERR(chg->vbus_vreg->rdev)) {
+		rc = PTR_ERR(chg->vbus_vreg->rdev);
+		chg->vbus_vreg->rdev = NULL;
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/******************************
+ * VCONN REGULATOR REGISTRATION *
+ ******************************/
+
+static struct regulator_ops smb5_vconn_reg_ops = {
+	.enable = smblib_vconn_regulator_enable,
+	.disable = smblib_vconn_regulator_disable,
+	.is_enabled = smblib_vconn_regulator_is_enabled,
+};
+
+static int smb5_init_vconn_regulator(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct regulator_config cfg = {};
+	int rc = 0;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		return 0;
+
+	chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
+				      GFP_KERNEL);
+	if (!chg->vconn_vreg)
+		return -ENOMEM;
+
+	cfg.dev = chg->dev;
+	cfg.driver_data = chip;
+
+	chg->vconn_vreg->rdesc.owner = THIS_MODULE;
+	chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
+	chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
+	chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
+	chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
+
+	chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
+						&chg->vconn_vreg->rdesc, &cfg);
+	if (IS_ERR(chg->vconn_vreg->rdev)) {
+		rc = PTR_ERR(chg->vconn_vreg->rdev);
+		chg->vconn_vreg->rdev = NULL;
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/***************************
+ * HARDWARE INITIALIZATION *
+ ***************************/
+static int smb5_configure_typec(struct smb_charger *chg)
+{
+	int rc;
+
+	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
+				TYPEC_CCOUT_DETACH_INT_EN_BIT |
+				TYPEC_CCOUT_ATTACH_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+				TYPEC_WATER_DETECTION_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure VCONN for software control */
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
+				 VCONN_EN_SRC_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure VCONN for SW control rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int smb5_configure_micro_usb(struct smb_charger *chg)
+{
+	int rc;
+
+	/* configure micro USB mode */
+	rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
+			EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int smb5_init_hw(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc, type = 0;
+	u8 val = 0;
+
+	if (chip->dt.no_battery)
+		chg->fake_capacity = 50;
+
+	if (chip->dt.batt_profile_fcc_ua < 0)
+		smblib_get_charge_param(chg, &chg->param.fcc,
+				&chg->batt_profile_fcc_ua);
+
+	if (chip->dt.batt_profile_fv_uv < 0)
+		smblib_get_charge_param(chg, &chg->param.fv,
+				&chg->batt_profile_fv_uv);
+
+	smblib_get_charge_param(chg, &chg->param.usb_icl,
+				&chg->default_icl_ua);
+
+	/* Use SW based VBUS control, disable HW autonomous mode */
+	/* TODO: auth can be enabled through vote based on APSD flow */
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
+		HVDCP_AUTH_ALG_EN_CFG_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
+		return rc;
+	}
+
+	/*
+	 * PMI632 can have the connector type defined by a dedicated register
+	 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
+	 */
+	if (chg->smb_version == PMI632_SUBTYPE) {
+		rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
+			return rc;
+		}
+		type = !!(val & MICRO_USB_MODE_ONLY_BIT);
+	}
+
+	/*
+	 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
+	 * check the connector type using TYPEC_U_USB_CFG_REG.
+	 */
+	if (!type) {
+		rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		type = !!(val & EN_MICRO_USB_MODE_BIT);
+	}
+
+	chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
+					: POWER_SUPPLY_CONNECTOR_TYPEC;
+	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+
+	/*
+	 * PMI632 based hw init:
+	 * - Initialize flash module for PMI632
+	 */
+	if (chg->smb_version == PMI632_SUBTYPE)
+		schgm_flash_init(chg);
+
+	smblib_rerun_apsd_if_required(chg);
+
+	/* vote 0mA on usb_icl for non battery platforms */
+	vote(chg->usb_icl_votable,
+		DEFAULT_VOTER, chip->dt.no_battery, 0);
+	vote(chg->dc_suspend_votable,
+		DEFAULT_VOTER, chip->dt.no_battery, 0);
+	vote(chg->fcc_votable, HW_LIMIT_VOTER,
+		chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
+	vote(chg->fv_votable, HW_LIMIT_VOTER,
+		chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
+	vote(chg->fcc_votable,
+		BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
+		chg->batt_profile_fcc_ua);
+	vote(chg->fv_votable,
+		BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
+		chg->batt_profile_fv_uv);
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
+			true, 0);
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+			true, 0);
+	vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
+		chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
+
+	/* Some h/w limit maximum supported ICL */
+	vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
+			chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
+
+	/*
+	 * AICL configuration:
+	 * start from min and AICL ADC disable
+	 */
+	rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
+				USBIN_AICL_ADC_EN_BIT, 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
+		return rc;
+	}
+
+	/* enable the charging path */
+	rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
+		return rc;
+	}
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		rc = smb5_configure_micro_usb(chg);
+	else
+		rc = smb5_configure_typec(chg);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure VBUS for software control */
+	rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure VBUS for SW control rc=%d\n", rc);
+		return rc;
+	}
+
+	val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
+			& BARK_WDOG_TIMEOUT_MASK;
+	val |= BITE_WDOG_TIMEOUT_8S;
+	rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
+			BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
+			BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
+			val);
+	if (rc < 0) {
+		pr_err("Couldn't configue WD config rc=%d\n", rc);
+		return rc;
+	}
+
+	/* enable WD BARK and enable it on plugin */
+	rc = smblib_masked_write(chg, WD_CFG_REG,
+			WATCHDOG_TRIGGER_AFP_EN_BIT |
+			WDOG_TIMER_EN_ON_PLUGIN_BIT |
+			BARK_WDOG_INT_EN_BIT,
+			WDOG_TIMER_EN_ON_PLUGIN_BIT |
+			BARK_WDOG_INT_EN_BIT);
+	if (rc < 0) {
+		pr_err("Couldn't configue WD config rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure float charger options */
+	switch (chip->dt.float_option) {
+	case FLOAT_DCP:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, 0);
+		break;
+	case FLOAT_SDP:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
+		break;
+	case DISABLE_CHARGING:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
+		break;
+	case SUSPEND_INPUT:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
+		break;
+	default:
+		rc = 0;
+		break;
+	}
+
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	switch (chip->dt.chg_inhibit_thr_mv) {
+	case 50:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_50MV);
+		break;
+	case 100:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_100MV);
+		break;
+	case 200:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_200MV);
+		break;
+	case 300:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_300MV);
+		break;
+	case 0:
+		rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+				CHARGER_INHIBIT_BIT, 0);
+	default:
+		break;
+	}
+
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+				(chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
+				VBAT_BASED_RECHG_BIT : 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	/* program the auto-recharge VBAT threshold */
+	if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
+		u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
+
+		temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
+		rc = smblib_batch_write(chg,
+			CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
+				rc);
+			return rc;
+		}
+		/* Program the sample count for VBAT based recharge to 3 */
+		rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+					NO_OF_SAMPLE_FOR_RCHG,
+					2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+				(chip->dt.auto_recharge_soc != -EINVAL) ?
+				SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	/* program the auto-recharge threshold */
+	if (chip->dt.auto_recharge_soc != -EINVAL) {
+		rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
+				(chip->dt.auto_recharge_soc * 255) / 100);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
+				rc);
+			return rc;
+		}
+		/* Program the sample count for SOC based recharge to 1 */
+		rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+						NO_OF_SAMPLE_FOR_RCHG, 0);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	if (chg->sw_jeita_enabled) {
+		rc = smblib_disable_hw_jeita(chg, true);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int smb5_post_init(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval pval;
+	int rc;
+
+	/*
+	 * In case the usb path is suspended, we would have missed disabling
+	 * the icl change interrupt because the interrupt could have been
+	 * not requested
+	 */
+	rerun_election(chg->usb_icl_votable);
+
+	/* configure power role for dual-role */
+	pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+	rc = smblib_set_prop_typec_power_role(chg, &pval);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	rerun_election(chg->usb_irq_enable_votable);
+
+	return 0;
+}
+
+/****************************
+ * DETERMINE INITIAL STATUS *
+ ****************************/
+
+static int smb5_determine_initial_status(struct smb5 *chip)
+{
+	struct smb_irq_data irq_data = {chip, "determine-initial-status"};
+	struct smb_charger *chg = &chip->chg;
+
+	if (chg->bms_psy)
+		smblib_suspend_on_debug_battery(chg);
+
+	usb_plugin_irq_handler(0, &irq_data);
+	typec_state_change_irq_handler(0, &irq_data);
+	usb_source_change_irq_handler(0, &irq_data);
+	chg_state_change_irq_handler(0, &irq_data);
+	icl_change_irq_handler(0, &irq_data);
+	batt_temp_changed_irq_handler(0, &irq_data);
+	wdog_bark_irq_handler(0, &irq_data);
+	typec_or_rid_detection_change_irq_handler(0, &irq_data);
+
+	return 0;
+}
+
+/**************************
+ * INTERRUPT REGISTRATION *
+ **************************/
+
+static struct smb_irq_info smb5_irqs[] = {
+	/* CHARGER IRQs */
+	[CHGR_ERROR_IRQ] = {
+		.name		= "chgr-error",
+		.handler	= default_irq_handler,
+	},
+	[CHG_STATE_CHANGE_IRQ] = {
+		.name		= "chg-state-change",
+		.handler	= chg_state_change_irq_handler,
+		.wake		= true,
+	},
+	[STEP_CHG_STATE_CHANGE_IRQ] = {
+		.name		= "step-chg-state-change",
+	},
+	[STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
+		.name		= "step-chg-soc-update-fail",
+	},
+	[STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
+		.name		= "step-chg-soc-update-req",
+	},
+	[FG_FVCAL_QUALIFIED_IRQ] = {
+		.name		= "fg-fvcal-qualified",
+	},
+	[VPH_ALARM_IRQ] = {
+		.name		= "vph-alarm",
+	},
+	[VPH_DROP_PRECHG_IRQ] = {
+		.name		= "vph-drop-prechg",
+	},
+	/* DCDC IRQs */
+	[OTG_FAIL_IRQ] = {
+		.name		= "otg-fail",
+		.handler	= default_irq_handler,
+	},
+	[OTG_OC_DISABLE_SW_IRQ] = {
+		.name		= "otg-oc-disable-sw",
+	},
+	[OTG_OC_HICCUP_IRQ] = {
+		.name		= "otg-oc-hiccup",
+	},
+	[BSM_ACTIVE_IRQ] = {
+		.name		= "bsm-active",
+	},
+	[HIGH_DUTY_CYCLE_IRQ] = {
+		.name		= "high-duty-cycle",
+		.handler	= high_duty_cycle_irq_handler,
+		.wake		= true,
+	},
+	[INPUT_CURRENT_LIMITING_IRQ] = {
+		.name		= "input-current-limiting",
+		.handler	= default_irq_handler,
+	},
+	[CONCURRENT_MODE_DISABLE_IRQ] = {
+		.name		= "concurrent-mode-disable",
+	},
+	[SWITCHER_POWER_OK_IRQ] = {
+		.name		= "switcher-power-ok",
+		.handler	= switcher_power_ok_irq_handler,
+	},
+	/* BATTERY IRQs */
+	[BAT_TEMP_IRQ] = {
+		.name		= "bat-temp",
+		.handler	= batt_temp_changed_irq_handler,
+		.wake		= true,
+	},
+	[ALL_CHNL_CONV_DONE_IRQ] = {
+		.name		= "all-chnl-conv-done",
+	},
+	[BAT_OV_IRQ] = {
+		.name		= "bat-ov",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_LOW_IRQ] = {
+		.name		= "bat-low",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_THERM_OR_ID_MISSING_IRQ] = {
+		.name		= "bat-therm-or-id-missing",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_TERMINAL_MISSING_IRQ] = {
+		.name		= "bat-terminal-missing",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BUCK_OC_IRQ] = {
+		.name		= "buck-oc",
+	},
+	[VPH_OV_IRQ] = {
+		.name		= "vph-ov",
+	},
+	/* USB INPUT IRQs */
+	[USBIN_COLLAPSE_IRQ] = {
+		.name		= "usbin-collapse",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_VASHDN_IRQ] = {
+		.name		= "usbin-vashdn",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_UV_IRQ] = {
+		.name		= "usbin-uv",
+		.handler	= usbin_uv_irq_handler,
+	},
+	[USBIN_OV_IRQ] = {
+		.name		= "usbin-ov",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_PLUGIN_IRQ] = {
+		.name		= "usbin-plugin",
+		.handler	= usb_plugin_irq_handler,
+		.wake           = true,
+	},
+	[USBIN_REVI_CHANGE_IRQ] = {
+		.name		= "usbin-revi-change",
+	},
+	[USBIN_SRC_CHANGE_IRQ] = {
+		.name		= "usbin-src-change",
+		.handler	= usb_source_change_irq_handler,
+		.wake           = true,
+	},
+	[USBIN_ICL_CHANGE_IRQ] = {
+		.name		= "usbin-icl-change",
+		.handler	= icl_change_irq_handler,
+		.wake           = true,
+	},
+	/* DC INPUT IRQs */
+	[DCIN_VASHDN_IRQ] = {
+		.name		= "dcin-vashdn",
+	},
+	[DCIN_UV_IRQ] = {
+		.name		= "dcin-uv",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_OV_IRQ] = {
+		.name		= "dcin-ov",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_PLUGIN_IRQ] = {
+		.name		= "dcin-plugin",
+		.handler	= dc_plugin_irq_handler,
+		.wake           = true,
+	},
+	[DCIN_REVI_IRQ] = {
+		.name		= "dcin-revi",
+	},
+	[DCIN_PON_IRQ] = {
+		.name		= "dcin-pon",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_EN_IRQ] = {
+		.name		= "dcin-en",
+		.handler	= default_irq_handler,
+	},
+	/* TYPEC IRQs */
+	[TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
+		.name		= "typec-or-rid-detect-change",
+		.handler	= typec_or_rid_detection_change_irq_handler,
+		.wake           = true,
+	},
+	[TYPEC_VPD_DETECT_IRQ] = {
+		.name		= "typec-vpd-detect",
+	},
+	[TYPEC_CC_STATE_CHANGE_IRQ] = {
+		.name		= "typec-cc-state-change",
+		.handler	= typec_state_change_irq_handler,
+		.wake           = true,
+	},
+	[TYPEC_VCONN_OC_IRQ] = {
+		.name		= "typec-vconn-oc",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_VBUS_CHANGE_IRQ] = {
+		.name		= "typec-vbus-change",
+	},
+	[TYPEC_ATTACH_DETACH_IRQ] = {
+		.name		= "typec-attach-detach",
+	},
+	[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
+		.name		= "typec-legacy-cable-detect",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
+		.name		= "typec-try-snk-src-detect",
+	},
+	/* MISCELLANEOUS IRQs */
+	[WDOG_SNARL_IRQ] = {
+		.name		= "wdog-snarl",
+	},
+	[WDOG_BARK_IRQ] = {
+		.name		= "wdog-bark",
+		.handler	= wdog_bark_irq_handler,
+	},
+	[AICL_FAIL_IRQ] = {
+		.name		= "aicl-fail",
+	},
+	[AICL_DONE_IRQ] = {
+		.name		= "aicl-done",
+		.handler	= default_irq_handler,
+	},
+	[SMB_EN_IRQ] = {
+		.name		= "smb-en",
+	},
+	[IMP_TRIGGER_IRQ] = {
+		.name		= "imp-trigger",
+	},
+	[TEMP_CHANGE_IRQ] = {
+		.name		= "temp-change",
+	},
+	[TEMP_CHANGE_SMB_IRQ] = {
+		.name		= "temp-change-smb",
+	},
+	/* FLASH */
+	[VREG_OK_IRQ] = {
+		.name		= "vreg-ok",
+	},
+	[ILIM_S2_IRQ] = {
+		.name		= "ilim2-s2",
+		.handler	= schgm_flash_ilim2_irq_handler,
+	},
+	[ILIM_S1_IRQ] = {
+		.name		= "ilim1-s1",
+	},
+	[VOUT_DOWN_IRQ] = {
+		.name		= "vout-down",
+	},
+	[VOUT_UP_IRQ] = {
+		.name		= "vout-up",
+	},
+	[FLASH_STATE_CHANGE_IRQ] = {
+		.name		= "flash-state-change",
+		.handler	= schgm_flash_state_change_irq_handler,
+	},
+	[TORCH_REQ_IRQ] = {
+		.name		= "torch-req",
+	},
+	[FLASH_EN_IRQ] = {
+		.name		= "flash-en",
+	},
+};
+
+static int smb5_get_irq_index_byname(const char *irq_name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (strcmp(smb5_irqs[i].name, irq_name) == 0)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+static int smb5_request_interrupt(struct smb5 *chip,
+				struct device_node *node, const char *irq_name)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc, irq, irq_index;
+	struct smb_irq_data *irq_data;
+
+	irq = of_irq_get_byname(node, irq_name);
+	if (irq < 0) {
+		pr_err("Couldn't get irq %s byname\n", irq_name);
+		return irq;
+	}
+
+	irq_index = smb5_get_irq_index_byname(irq_name);
+	if (irq_index < 0) {
+		pr_err("%s is not a defined irq\n", irq_name);
+		return irq_index;
+	}
+
+	if (!smb5_irqs[irq_index].handler)
+		return 0;
+
+	irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
+	if (!irq_data)
+		return -ENOMEM;
+
+	irq_data->parent_data = chip;
+	irq_data->name = irq_name;
+	irq_data->storm_data = smb5_irqs[irq_index].storm_data;
+	mutex_init(&irq_data->storm_data.storm_lock);
+
+	rc = devm_request_threaded_irq(chg->dev, irq, NULL,
+					smb5_irqs[irq_index].handler,
+					IRQF_ONESHOT, irq_name, irq_data);
+	if (rc < 0) {
+		pr_err("Couldn't request irq %d\n", irq);
+		return rc;
+	}
+
+	smb5_irqs[irq_index].irq = irq;
+	smb5_irqs[irq_index].irq_data = irq_data;
+	if (smb5_irqs[irq_index].wake)
+		enable_irq_wake(irq);
+
+	return rc;
+}
+
+static int smb5_request_interrupts(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct device_node *node = chg->dev->of_node;
+	struct device_node *child;
+	int rc = 0;
+	const char *name;
+	struct property *prop;
+
+	for_each_available_child_of_node(node, child) {
+		of_property_for_each_string(child, "interrupt-names",
+					    prop, name) {
+			rc = smb5_request_interrupt(chip, child, name);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
+		chg->usb_icl_change_irq_enabled = true;
+
+	return rc;
+}
+
+static void smb5_free_interrupts(struct smb_charger *chg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (smb5_irqs[i].irq > 0) {
+			if (smb5_irqs[i].wake)
+				disable_irq_wake(smb5_irqs[i].irq);
+
+			devm_free_irq(chg->dev, smb5_irqs[i].irq,
+						smb5_irqs[i].irq_data);
+		}
+	}
+}
+
+static void smb5_disable_interrupts(struct smb_charger *chg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (smb5_irqs[i].irq > 0)
+			disable_irq(smb5_irqs[i].irq);
+	}
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int force_batt_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->batt_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
+			force_batt_psy_update_write, "0x%02llx\n");
+
+static int force_usb_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->usb_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
+			force_usb_psy_update_write, "0x%02llx\n");
+
+static int force_dc_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->dc_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
+			force_dc_psy_update_write, "0x%02llx\n");
+
+static void smb5_create_debugfs(struct smb5 *chip)
+{
+	struct dentry *file;
+
+	chip->dfs_root = debugfs_create_dir("charger", NULL);
+	if (IS_ERR_OR_NULL(chip->dfs_root)) {
+		pr_err("Couldn't create charger debugfs rc=%ld\n",
+			(long)chip->dfs_root);
+		return;
+	}
+
+	file = debugfs_create_file("force_batt_psy_update", 0600,
+			    chip->dfs_root, chip, &force_batt_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
+			(long)file);
+
+	file = debugfs_create_file("force_usb_psy_update", 0600,
+			    chip->dfs_root, chip, &force_usb_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
+			(long)file);
+
+	file = debugfs_create_file("force_dc_psy_update", 0600,
+			    chip->dfs_root, chip, &force_dc_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
+			(long)file);
+}
+
+#else
+
+static void smb5_create_debugfs(struct smb5 *chip)
+{}
+
+#endif
+
+static int smb5_show_charger_status(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval val;
+	int usb_present, batt_present, batt_health, batt_charge_type;
+	int rc;
+
+	rc = smblib_get_prop_usb_present(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get usb present rc=%d\n", rc);
+		return rc;
+	}
+	usb_present = val.intval;
+
+	rc = smblib_get_prop_batt_present(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt present rc=%d\n", rc);
+		return rc;
+	}
+	batt_present = val.intval;
+
+	rc = smblib_get_prop_batt_health(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt health rc=%d\n", rc);
+		val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+	batt_health = val.intval;
+
+	rc = smblib_get_prop_batt_charge_type(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt charge type rc=%d\n", rc);
+		return rc;
+	}
+	batt_charge_type = val.intval;
+
+	pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
+		usb_present, chg->real_charger_type,
+		batt_present, batt_health, batt_charge_type);
+	return rc;
+}
+
+static int smb5_probe(struct platform_device *pdev)
+{
+	struct smb5 *chip;
+	struct smb_charger *chg;
+	int rc = 0;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chg = &chip->chg;
+	chg->dev = &pdev->dev;
+	chg->debug_mask = &__debug_mask;
+	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
+	chg->mode = PARALLEL_MASTER;
+	chg->irq_info = smb5_irqs;
+	chg->die_health = -EINVAL;
+	chg->otg_present = false;
+
+	chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
+	if (!chg->regmap) {
+		pr_err("parent regmap is missing\n");
+		return -EINVAL;
+	}
+
+	rc = smb5_parse_dt(chip);
+	if (rc < 0) {
+		pr_err("Couldn't parse device tree rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smb5_chg_config_init(chip);
+	if (rc < 0) {
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't setup chg_config rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_init(chg);
+	if (rc < 0) {
+		pr_err("Smblib_init failed rc=%d\n", rc);
+		return rc;
+	}
+
+	/* set driver data before resources request it */
+	platform_set_drvdata(pdev, chip);
+
+	rc = smb5_init_vbus_regulator(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize vbus regulator rc=%d\n",
+			rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_vconn_regulator(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize vconn regulator rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	/* extcon registration */
+	chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
+	if (IS_ERR(chg->extcon)) {
+		rc = PTR_ERR(chg->extcon);
+		dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	rc = devm_extcon_dev_register(chg->dev, chg->extcon);
+	if (rc < 0) {
+		dev_err(chg->dev, "failed to register extcon device rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_hw(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize hardware rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	if (chg->smb_version == PM855B_SUBTYPE) {
+		rc = smb5_init_dc_psy(chip);
+		if (rc < 0) {
+			pr_err("Couldn't initialize dc psy rc=%d\n", rc);
+			goto cleanup;
+		}
+	}
+
+	rc = smb5_init_usb_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_usb_main_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_usb_port_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_batt_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize batt psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_determine_initial_status(chip);
+	if (rc < 0) {
+		pr_err("Couldn't determine initial status rc=%d\n",
+			rc);
+		goto cleanup;
+	}
+
+	rc = smb5_request_interrupts(chip);
+	if (rc < 0) {
+		pr_err("Couldn't request interrupts rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_post_init(chip);
+	if (rc < 0) {
+		pr_err("Failed in post init rc=%d\n", rc);
+		goto free_irq;
+	}
+
+	smb5_create_debugfs(chip);
+
+	rc = smb5_show_charger_status(chip);
+	if (rc < 0) {
+		pr_err("Failed in getting charger status rc=%d\n", rc);
+		goto free_irq;
+	}
+
+	device_init_wakeup(chg->dev, true);
+
+	pr_info("QPNP SMB5 probed successfully\n");
+
+	return rc;
+
+free_irq:
+	smb5_free_interrupts(chg);
+cleanup:
+	smblib_deinit(chg);
+	platform_set_drvdata(pdev, NULL);
+
+	return rc;
+}
+
+static int smb5_remove(struct platform_device *pdev)
+{
+	struct smb5 *chip = platform_get_drvdata(pdev);
+	struct smb_charger *chg = &chip->chg;
+
+	smb5_free_interrupts(chg);
+	smblib_deinit(chg);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static void smb5_shutdown(struct platform_device *pdev)
+{
+	struct smb5 *chip = platform_get_drvdata(pdev);
+	struct smb_charger *chg = &chip->chg;
+
+	/* disable all interrupts */
+	smb5_disable_interrupts(chg);
+
+	/* configure power role for UFP */
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
+		smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
+
+	/* force HVDCP to 5V */
+	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+				HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
+	smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
+
+	/* force enable APSD */
+	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+				BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
+}
+
+static const struct of_device_id match_table[] = {
+	{ .compatible = "qcom,qpnp-smb5", },
+	{ },
+};
+
+static struct platform_driver smb5_driver = {
+	.driver		= {
+		.name		= "qcom,qpnp-smb5",
+		.owner		= THIS_MODULE,
+		.of_match_table	= match_table,
+	},
+	.probe		= smb5_probe,
+	.remove		= smb5_remove,
+	.shutdown	= smb5_shutdown,
+};
+module_platform_driver(smb5_driver);
+
+MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/schgm-flash.c b/drivers/power/supply/qcom/schgm-flash.c
new file mode 100644
index 0000000..eed70d3
--- /dev/null
+++ b/drivers/power/supply/qcom/schgm-flash.c
@@ -0,0 +1,216 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "SCHG-FLASH: %s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/printk.h>
+#include <linux/pmic-voter.h>
+#include "smb5-lib.h"
+#include "schgm-flash.h"
+
+#define IS_BETWEEN(left, right, value) \
+		(((left) >= (right) && (left) >= (value) \
+			&& (value) >= (right)) \
+		|| ((left) <= (right) && (left) <= (value) \
+			&& (value) <= (right)))
+
+irqreturn_t schgm_flash_default_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+
+	pr_debug("IRQ: %s\n", irq_data->name);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+
+	rc = smblib_write(chg, SCHGM_FLASH_S2_LATCH_RESET_CMD_REG,
+				FLASH_S2_LATCH_RESET_BIT);
+	if (rc < 0)
+		pr_err("Couldn't reset S2_LATCH reset rc=%d\n", rc);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+	u8 reg;
+
+	rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &reg);
+	if (rc < 0)
+		pr_err("Couldn't read flash status_3 rc=%d\n", rc);
+	else
+		pr_debug("Flash status changed state=[%x]\n",
+					(reg && FLASH_STATE_MASK));
+
+	return IRQ_HANDLED;
+}
+
+#define FIXED_MODE		0
+#define ADAPTIVE_MODE		1
+static void schgm_flash_parse_dt(struct smb_charger *chg)
+{
+	struct device_node *node = chg->dev->of_node;
+	u32 val;
+	int rc;
+
+	chg->flash_derating_soc = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,flash-derating-soc", &val);
+	if (!rc) {
+		if (IS_BETWEEN(0, 100, val))
+			chg->flash_derating_soc = (val * 255) / 100;
+	}
+
+	chg->flash_disable_soc = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,flash-disable-soc", &val);
+	if (!rc) {
+		if (IS_BETWEEN(0, 100, val))
+			chg->flash_disable_soc = (val * 255) / 100;
+	}
+
+	chg->headroom_mode = -EINVAL;
+	rc = of_property_read_u32(node, "qcom,headroom-mode", &val);
+	if (!rc) {
+		if (IS_BETWEEN(FIXED_MODE, ADAPTIVE_MODE, val))
+			chg->headroom_mode = val;
+	}
+}
+
+int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val)
+{
+	int rc, vreg_state;
+	u8 stat = 0;
+
+	if (!chg->flash_init_done)
+		return -EPERM;
+
+	rc = smblib_read(chg, SCHGM_FLASH_STATUS_2_REG, &stat);
+	if (rc < 0) {
+		pr_err("Couldn't read FLASH STATUS_2 rc=%d\n", rc);
+		return rc;
+	}
+	vreg_state = !!(stat & VREG_OK_BIT);
+
+	/* If VREG_OK is not set check for flash error */
+	if (!vreg_state) {
+		rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &stat);
+		if (rc < 0) {
+			pr_err("Couldn't read FLASH_STATUS_3 rc=%d\n", rc);
+			return rc;
+		}
+		if ((stat & FLASH_STATE_MASK) == FLASH_ERROR_VAL) {
+			vreg_state = -EFAULT;
+			rc = smblib_read(chg, SCHGM_FLASH_STATUS_5_REG,
+					&stat);
+			if (rc < 0) {
+				pr_err("Couldn't read FLASH_STATUS_5 rc=%d\n",
+						rc);
+				return rc;
+			}
+			pr_debug("Flash error: status=%x\n", stat);
+		}
+	}
+
+	/*
+	 * val can be one of the following:
+	 * 1		- VREG_OK is set.
+	 * 0		- VREG_OK is 0 but no Flash error.
+	 * -EFAULT	- Flash Error is set.
+	 */
+	*val = vreg_state;
+
+	return 0;
+}
+
+int schgm_flash_init(struct smb_charger *chg)
+{
+	int rc;
+	u8 reg;
+
+	schgm_flash_parse_dt(chg);
+
+	if (chg->flash_derating_soc != -EINVAL) {
+		rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG,
+					chg->flash_derating_soc);
+		if (rc < 0) {
+			pr_err("Couldn't configure SOC for flash derating rc=%d\n",
+					rc);
+			return rc;
+		}
+	}
+
+	if (chg->flash_disable_soc != -EINVAL) {
+		rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG,
+					chg->flash_disable_soc);
+		if (rc < 0) {
+			pr_err("Couldn't configure SOC for flash disable rc=%d\n",
+					rc);
+			return rc;
+		}
+	}
+
+	if (chg->headroom_mode != -EINVAL) {
+		/*
+		 * configure headroom management policy for
+		 * flash and torch mode.
+		 */
+		reg = (chg->headroom_mode == FIXED_MODE)
+					? FORCE_FLASH_BOOST_5V_BIT : 0;
+		rc = smblib_write(chg, SCHGM_FORCE_BOOST_CONTROL, reg);
+		if (rc < 0) {
+			pr_err("Couldn't write force boost control reg rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		reg = (chg->headroom_mode == FIXED_MODE)
+					? TORCH_PRIORITY_CONTROL_BIT : 0;
+		rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL, reg);
+		if (rc < 0) {
+			pr_err("Couldn't force 5V boost in torch mode rc=%d\n",
+					rc);
+			return rc;
+		}
+	}
+
+	if ((chg->flash_derating_soc != -EINVAL)
+				|| (chg->flash_disable_soc != -EINVAL)) {
+		/* Check if SOC based derating/disable is enabled */
+		rc = smblib_read(chg, SCHGM_FLASH_CONTROL_REG, &reg);
+		if (rc < 0) {
+			pr_err("Couldn't read flash control reg rc=%d\n", rc);
+			return rc;
+		}
+		if (!(reg & SOC_LOW_FOR_FLASH_EN_BIT))
+			pr_warn("Soc based flash derating not enabled\n");
+	}
+
+	chg->flash_init_done = true;
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/schgm-flash.h b/drivers/power/supply/qcom/schgm-flash.h
new file mode 100644
index 0000000..b6fff6c
--- /dev/null
+++ b/drivers/power/supply/qcom/schgm-flash.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SCHGM_FLASH_H__
+#define __SCHGM_FLASH_H__
+
+#include <linux/bitops.h>
+
+#define SCHGM_FLASH_BASE			0xA600
+
+#define SCHGM_FLASH_STATUS_2_REG		(SCHGM_FLASH_BASE + 0x07)
+#define VREG_OK_BIT				BIT(4)
+
+#define SCHGM_FLASH_STATUS_3_REG		(SCHGM_FLASH_BASE + 0x08)
+#define FLASH_STATE_MASK			GENMASK(2, 0)
+#define FLASH_ERROR_VAL				0x7
+
+#define SCHGM_FLASH_INT_RT_STS_REG		(SCHGM_FLASH_BASE + 0x10)
+
+#define SCHGM_FLASH_STATUS_5_REG		(SCHGM_FLASH_BASE + 0x0B)
+
+#define SCHGM_FORCE_BOOST_CONTROL		(SCHGM_FLASH_BASE + 0x41)
+#define FORCE_FLASH_BOOST_5V_BIT		BIT(0)
+
+#define SCHGM_FLASH_S2_LATCH_RESET_CMD_REG	(SCHGM_FLASH_BASE + 0x44)
+#define FLASH_S2_LATCH_RESET_BIT		BIT(0)
+
+#define SCHGM_FLASH_CONTROL_REG			(SCHGM_FLASH_BASE + 0x60)
+#define SOC_LOW_FOR_FLASH_EN_BIT		BIT(7)
+
+#define SCHGM_TORCH_PRIORITY_CONTROL		(SCHGM_FLASH_BASE + 0x63)
+#define TORCH_PRIORITY_CONTROL_BIT		BIT(0)
+
+#define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG	(SCHGM_FLASH_BASE + 0x67)
+
+#define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \
+						(SCHGM_FLASH_BASE + 0x68)
+
+int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val);
+int schgm_flash_init(struct smb_charger *chg);
+
+irqreturn_t schgm_flash_default_irq_handler(int irq, void *data);
+irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data);
+irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data);
+#endif /* __SCHGM_FLASH_H__ */
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 496a276..90745fd 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -4805,7 +4805,7 @@
 
 	if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
 		smblib_err(chg, "VCONN failed to enable after %d attempts\n",
-			   chg->otg_attempts - 1);
+			   chg->vconn_attempts - 1);
 		chg->vconn_en = false;
 		chg->vconn_attempts = 0;
 		goto unlock;
@@ -4829,14 +4829,7 @@
 		chg->vconn_attempts = 0;
 		goto unlock;
 	}
-
 	smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
-	if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
-		smblib_err(chg, "VCONN failed to enable after %d attempts\n",
-			   chg->vconn_attempts - 1);
-		chg->vconn_en = false;
-		goto unlock;
-	}
 
 	rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
 	if (rc < 0) {
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index dfedece..63d57fe 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
 #include <linux/i2c.h>
 #include <linux/debugfs.h>
 #include <linux/errno.h>
+#include <linux/extcon.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -376,6 +377,7 @@
 #define USB2_MAX_CURRENT_MA			500
 #define USB3_MIN_CURRENT_MA			150
 #define USB3_MAX_CURRENT_MA			900
+#define DCP_MAX_CURRENT_MA			1500
 #define SMB1351_IRQ_REG_COUNT			8
 #define SMB1351_CHG_PRE_MIN_MA			100
 #define SMB1351_CHG_FAST_MIN_MA			1000
@@ -424,6 +426,12 @@
 	[SMB1351] = "SMB1351",
 };
 
+static const unsigned int smb1351_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_NONE,
+};
+
 struct smb1351_charger {
 	struct i2c_client	*client;
 	struct device		*dev;
@@ -472,6 +480,7 @@
 	enum chip_version	version;
 
 	/* psy */
+	struct power_supply_desc	usb_psy_d;
 	struct power_supply	*usb_psy;
 	int			usb_psy_ma;
 	struct power_supply	*bms_psy;
@@ -505,6 +514,12 @@
 	/* pinctrl parameters */
 	const char		*pinctrl_state_name;
 	struct pinctrl		*smb_pinctrl;
+
+	/* standalone */
+	bool			charger_present;
+	struct extcon_dev       *extcon;
+	struct regulator	*dpdm_reg;
+	enum power_supply_type	charger_type;
 };
 
 struct smb_irq_info {
@@ -633,6 +648,65 @@
 	return rc;
 }
 
+static int smb1351_get_closest_usb_setpoint(int val)
+{
+	int i;
+
+	for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
+		if (usb_chg_current[i] <= val)
+			break;
+	}
+	if (i < 0)
+		i = 0;
+
+	if (i >= ARRAY_SIZE(usb_chg_current) - 1)
+		return ARRAY_SIZE(usb_chg_current) - 1;
+
+	/* check what is closer, i or i + 1 */
+	if (abs(usb_chg_current[i] - val) < abs(usb_chg_current[i + 1] - val))
+		return i;
+	else
+		return i + 1;
+}
+
+static int smb1351_request_dpdm(struct smb1351_charger *chip, bool enable)
+{
+	int rc = 0;
+
+	/* fetch the DPDM regulator */
+	if (!chip->dpdm_reg && of_get_property(chip->dev->of_node,
+				"dpdm-supply", NULL)) {
+		chip->dpdm_reg = devm_regulator_get(chip->dev, "dpdm");
+		if (IS_ERR(chip->dpdm_reg)) {
+			rc = PTR_ERR(chip->dpdm_reg);
+			pr_err("Couldn't get dpdm regulator rc=%d\n",
+					rc);
+			chip->dpdm_reg = NULL;
+			return rc;
+		}
+	}
+
+	if (enable) {
+		if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) {
+			pr_err("enabling DPDM regulator\n");
+			rc = regulator_enable(chip->dpdm_reg);
+			if (rc < 0)
+				pr_err("Couldn't enable dpdm regulator rc=%d\n",
+					rc);
+		}
+	} else {
+		if (chip->dpdm_reg && regulator_is_enabled(chip->dpdm_reg)) {
+			pr_err("disabling DPDM regulator\n");
+			rc = regulator_disable(chip->dpdm_reg);
+			if (rc < 0)
+				pr_err("Couldn't disable dpdm regulator rc=%d\n",
+					rc);
+		}
+	}
+
+	return rc;
+}
+
 static int smb1351_usb_suspend(struct smb1351_charger *chip, int reason,
 					bool suspend)
 {
@@ -1290,6 +1364,75 @@
 	return rc;
 }
 
+static char *smb1351_usb_supplicants[] = {
+	"bms",
+};
+
+static enum power_supply_property smb1351_usb_properties[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
+};
+
+static int smb1351_usb_get_property(struct power_supply *psy,
+		enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	struct smb1351_charger *chip = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = chip->usb_psy_ma * 1000;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = chip->chg_present;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = chip->chg_present && !chip->usb_suspended_status;
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = chip->charger_type;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int smb1351_usb_set_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  const union power_supply_propval *val)
+{
+	struct smb1351_charger *chip = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		chip->usb_psy_ma = val->intval / 1000;
+		smb1351_enable_volatile_writes(chip);
+		smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	power_supply_changed(psy);
+	return 0;
+}
+
+static int smb1351_usb_is_writeable(struct power_supply *psy,
+					enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int smb1351_batt_property_is_writeable(struct power_supply *psy,
 					enum power_supply_property psp)
 {
@@ -1535,27 +1678,6 @@
 	return 0;
 }
 
-static int smb1351_get_closest_usb_setpoint(int val)
-{
-	int i;
-
-	for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
-		if (usb_chg_current[i] <= val)
-			break;
-	}
-	if (i < 0)
-		i = 0;
-
-	if (i >= ARRAY_SIZE(usb_chg_current) - 1)
-		return ARRAY_SIZE(usb_chg_current) - 1;
-
-	/* check what is closer, i or i + 1 */
-	if (abs(usb_chg_current[i] - val) < abs(usb_chg_current[i + 1] - val))
-		return i;
-	else
-		return i + 1;
-}
-
 static bool smb1351_is_input_current_limited(struct smb1351_charger *chip)
 {
 	int rc;
@@ -2001,10 +2123,10 @@
 static int smb1351_apsd_complete_handler(struct smb1351_charger *chip,
 						u8 status)
 {
-	int rc;
+	int rc, usb_psy_ma = 0;
 	u8 reg = 0;
-	union power_supply_propval prop = {0, };
 	enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN;
+	union extcon_property_value val;
 
 	/*
 	 * If apsd is disabled, charger detection is done by
@@ -2055,18 +2177,12 @@
 						type, chip->chg_present);
 		if (!chip->battery_missing && !chip->apsd_rerun) {
 			if (type == POWER_SUPPLY_TYPE_USB) {
-				pr_debug("Setting usb psy dp=f dm=f SDP and rerun\n");
-				prop.intval = POWER_SUPPLY_DP_DM_DPF_DMF;
-				power_supply_set_property(chip->usb_psy,
-						POWER_SUPPLY_PROP_DP_DM, &prop);
+				smb1351_request_dpdm(chip, false);
+				smb1351_request_dpdm(chip, true);
 				chip->apsd_rerun = true;
 				rerun_apsd(chip);
 				return 0;
 			}
-			pr_debug("Set usb psy dp=f dm=f DCP and no rerun\n");
-			prop.intval = POWER_SUPPLY_DP_DM_DPF_DMF;
-			power_supply_set_property(chip->usb_psy,
-					POWER_SUPPLY_PROP_DP_DM, &prop);
 		}
 		/*
 		 * If defined force hvdcp 2p0 property,
@@ -2087,35 +2203,33 @@
 					msecs_to_jiffies(HVDCP_NOTIFY_MS));
 		}
 
-		prop.intval = type;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_TYPE, &prop);
-		/*
-		 * SMB is now done sampling the D+/D- lines,
-		 * indicate USB driver
-		 */
-		pr_debug("updating usb_psy present=%d\n", chip->chg_present);
-		prop.intval = chip->chg_present;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_PRESENT,
-				&prop);
+		chip->charger_type = type;
+		if (type == POWER_SUPPLY_TYPE_USB
+				|| type == POWER_SUPPLY_TYPE_USB_CDP) {
+			val.intval = true;
+			extcon_set_property(chip->extcon, EXTCON_USB,
+						EXTCON_PROP_USB_SS, val);
+			extcon_set_cable_state_(chip->extcon, EXTCON_USB, true);
+		}
 		chip->apsd_rerun = false;
+
+		/* set the charge current as required */
+		if (type == POWER_SUPPLY_TYPE_USB)
+			usb_psy_ma = USB2_MIN_CURRENT_MA;
+		else /* DCP */
+			usb_psy_ma = DCP_MAX_CURRENT_MA;
+
+		chip->usb_psy_ma = usb_psy_ma;
+		smb1351_enable_volatile_writes(chip);
+		rc = smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
+		if (rc < 0)
+			pr_err("Failed to set USB current rc=%d\n", rc);
+
 	} else if (!chip->apsd_rerun) {
 		/* Handle Charger removal */
-		prop.intval = POWER_SUPPLY_TYPE_UNKNOWN;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_TYPE, &prop);
-
-		chip->chg_present = false;
-		prop.intval = chip->chg_present;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_PRESENT,
-				&prop);
-
-		pr_debug("Set usb psy dm=r df=r\n");
-		prop.intval = POWER_SUPPLY_DP_DM_DPR_DMR;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_DP_DM, &prop);
+		chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+		extcon_set_cable_state_(chip->extcon, EXTCON_USB, false);
+		smb1351_request_dpdm(chip, false);
 	}
 
 	return 0;
@@ -2163,42 +2277,7 @@
 
 static int smb1351_usbin_uv_handler(struct smb1351_charger *chip, u8 status)
 {
-	union power_supply_propval pval = {0, };
-
-	/* use this to detect USB insertion only if !apsd */
-	if (chip->disable_apsd) {
-		/*
-		 * If APSD is disabled, src det interrupt won't trigger.
-		 * Hence use usbin_uv for removal and insertion notification
-		 */
-		if (status == 0) {
-			chip->chg_present = true;
-			pr_debug("updating usb_psy present=%d\n",
-						chip->chg_present);
-			pval.intval = POWER_SUPPLY_TYPE_USB;
-			power_supply_set_property(chip->usb_psy,
-					POWER_SUPPLY_PROP_TYPE, &pval);
-
-			pval.intval = chip->chg_present;
-			power_supply_set_property(chip->usb_psy,
-					POWER_SUPPLY_PROP_PRESENT,
-					&pval);
-		} else {
-			chip->chg_present = false;
-
-			pval.intval = POWER_SUPPLY_TYPE_UNKNOWN;
-			power_supply_set_property(chip->usb_psy,
-					POWER_SUPPLY_PROP_TYPE, &pval);
-
-			pr_debug("updating usb_psy present=%d\n",
-							chip->chg_present);
-			pval.intval = chip->chg_present;
-			power_supply_set_property(chip->usb_psy,
-					POWER_SUPPLY_PROP_PRESENT,
-					&pval);
-		}
-		return 0;
-	}
+	smb1351_request_dpdm(chip, !!status);
 
 	if (status) {
 		cancel_delayed_work_sync(&chip->hvdcp_det_work);
@@ -2218,24 +2297,19 @@
 {
 	int rc;
 	u8 reg = 0;
-	union power_supply_propval pval = {0, };
 
 	rc = smb1351_read_reg(chip, IRQ_E_REG, &reg);
 	if (rc)
 		pr_err("Couldn't read IRQ_E rc = %d\n", rc);
 
 	if (status != 0) {
-		chip->chg_present = false;
 		chip->usbin_ov = true;
+		chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+		if (chip->chg_present)
+			extcon_set_cable_state_(chip->extcon, EXTCON_USB,
+						false);
+		chip->chg_present = false;
 
-		pval.intval = POWER_SUPPLY_TYPE_UNKNOWN;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_TYPE, &pval);
-
-		pval.intval = chip->chg_present;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_PRESENT,
-				&pval);
 	} else {
 		chip->usbin_ov = false;
 		if (reg & IRQ_USBIN_UV_BIT)
@@ -2244,13 +2318,6 @@
 			smb1351_apsd_complete_handler(chip, 1);
 	}
 
-	if (chip->usb_psy) {
-		pval.intval = status ? POWER_SUPPLY_HEALTH_OVERVOLTAGE
-					: POWER_SUPPLY_HEALTH_GOOD;
-		power_supply_set_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_HEALTH, &pval);
-		pr_debug("chip ov status is %d\n", pval.intval);
-	}
 	pr_debug("chip->chg_present = %d\n", chip->chg_present);
 
 	return 0;
@@ -2319,6 +2386,21 @@
 	return 0;
 }
 
+static int smb1351_rid_handler(struct smb1351_charger *chip,
+						u8 status)
+{
+	union extcon_property_value val;
+
+	if (!!status) {
+		val.intval = true;
+		extcon_set_property(chip->extcon, EXTCON_USB_HOST,
+					EXTCON_PROP_USB_SS, val);
+	}
+	extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, !!status);
+
+	return 0;
+}
+
 static struct irq_handler_info handlers[] = {
 	[0] = {
 		.stat_reg	= IRQ_A_REG,
@@ -2413,6 +2495,7 @@
 			{	.name	 = "otg_oc_retry",
 			},
 			{	.name	 = "rid",
+				.smb_irq = smb1351_rid_handler,
 			},
 			{	.name	 = "otg_fail",
 			},
@@ -2524,30 +2607,21 @@
 {
 	struct smb1351_charger *chip = power_supply_get_drvdata(psy);
 	union power_supply_propval prop = {0,};
-	int rc, current_limit = 0, online = 0;
+	int rc, current_limit = 0;
 
 	if (chip->bms_psy_name)
 		chip->bms_psy =
 			power_supply_get_by_name((char *)chip->bms_psy_name);
 
 	rc = power_supply_get_property(chip->usb_psy,
-				POWER_SUPPLY_PROP_ONLINE, &prop);
-	if (rc)
-		pr_err("Couldn't read USB online property, rc=%d\n", rc);
-	else
-		online = prop.intval;
-
-	rc = power_supply_get_property(chip->usb_psy,
 				POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
 	if (rc)
 		pr_err("Couldn't read USB current_max property, rc=%d\n", rc);
 	else
 		current_limit = prop.intval / 1000;
 
-	pr_debug("online = %d, current_limit = %d\n", online, current_limit);
+	pr_debug("current_limit = %d\n", current_limit);
 
-	smb1351_enable_volatile_writes(chip);
-	smb1351_set_usb_chg_current(chip, current_limit);
 
 	pr_debug("updating batt psy\n");
 }
@@ -3002,28 +3076,65 @@
 {
 	int rc;
 	struct smb1351_charger *chip;
-	struct power_supply *usb_psy;
 	struct power_supply_config batt_psy_cfg = {};
+	struct power_supply_config usb_psy_cfg = {};
 	u8 reg = 0;
 
-	usb_psy = power_supply_get_by_name("usb");
-	if (!usb_psy) {
-		pr_debug("USB psy not found; deferring probe\n");
-		return -EPROBE_DEFER;
-	}
-
 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
 	chip->client = client;
 	chip->dev = &client->dev;
-	chip->usb_psy = usb_psy;
 	chip->fake_battery_soc = -EINVAL;
+
+	chip->extcon = devm_extcon_dev_allocate(chip->dev,
+					smb1351_extcon_cable);
+	if (IS_ERR(chip->extcon)) {
+		pr_err("failed to allocate extcon device\n");
+		rc = PTR_ERR(chip->extcon);
+		return rc;
+	}
+
+	rc = devm_extcon_dev_register(chip->dev, chip->extcon);
+	if (rc) {
+		pr_err("failed to register extcon device\n");
+		return rc;
+	}
+
+	rc = extcon_set_property_capability(chip->extcon,
+			EXTCON_USB, EXTCON_PROP_USB_SS);
+	rc |= extcon_set_property_capability(chip->extcon,
+			EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+	if (rc < 0) {
+		pr_err("Failed to register extcon capability rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->usb_psy_d.name = "usb";
+	chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB;
+	chip->usb_psy_d.get_property = smb1351_usb_get_property;
+	chip->usb_psy_d.set_property = smb1351_usb_set_property;
+	chip->usb_psy_d.properties = smb1351_usb_properties;
+	chip->usb_psy_d.num_properties = ARRAY_SIZE(smb1351_usb_properties);
+	chip->usb_psy_d.property_is_writeable = smb1351_usb_is_writeable;
+
+	usb_psy_cfg.drv_data = chip;
+	usb_psy_cfg.supplied_to = smb1351_usb_supplicants;
+	usb_psy_cfg.num_supplicants = ARRAY_SIZE(smb1351_usb_supplicants);
+
+	chip->usb_psy = devm_power_supply_register(chip->dev,
+				&chip->usb_psy_d, &usb_psy_cfg);
+	if (IS_ERR(chip->usb_psy)) {
+		pr_err("Unable to register usb_psy rc = %ld\n",
+			PTR_ERR(chip->usb_psy));
+		rc = PTR_ERR(chip->usb_psy);
+		return rc;
+	}
+
 	INIT_DELAYED_WORK(&chip->chg_remove_work, smb1351_chg_remove_work);
 	INIT_DELAYED_WORK(&chip->hvdcp_det_work, smb1351_hvdcp_det_work);
 	device_init_wakeup(chip->dev, true);
-
 	/* probe the device to check if its actually connected */
 	rc = smb1351_read_reg(chip, CHG_REVISION_REG, &reg);
 	if (rc) {
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index ebaaf5c..ffbced6 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -31,6 +31,7 @@
 
 /* SMB1355 registers, different than mentioned in smb-reg.h */
 
+#define REVID_BASE	0x0100
 #define CHGR_BASE	0x1000
 #define ANA2_BASE	0x1100
 #define BATIF_BASE	0x1200
@@ -38,6 +39,8 @@
 #define ANA1_BASE	0x1400
 #define MISC_BASE	0x1600
 
+#define REVID_MFG_ID_SPARE_REG			(REVID_BASE + 0xFF)
+
 #define BATTERY_STATUS_2_REG			(CHGR_BASE + 0x0B)
 #define DISABLE_CHARGING_BIT			BIT(3)
 
@@ -222,6 +225,8 @@
 	char			*name;
 	struct regmap		*regmap;
 
+	int			max_fcc;
+
 	struct smb_dt_props	dt;
 	struct smb_params	param;
 	struct smb_iio		iio;
@@ -483,6 +488,7 @@
 	POWER_SUPPLY_PROP_PARALLEL_MODE,
 	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -624,6 +630,9 @@
 	case POWER_SUPPLY_PROP_MIN_ICL:
 		val->intval = MIN_PARALLEL_ICL_UA;
 		break;
+	case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
+		val->intval = chip->max_fcc;
+		break;
 	default:
 		pr_err_ratelimited("parallel psy get prop %d not supported\n",
 			prop);
@@ -798,6 +807,37 @@
  * HARDWARE INITIALIZATION *
  ***************************/
 
+#define MFG_ID_SMB1354			0x01
+#define MFG_ID_SMB1355			0xFF
+#define SMB1354_MAX_PARALLEL_FCC_UA	2500000
+static int smb1355_detect_version(struct smb1355 *chip)
+{
+	int rc;
+	u8 val;
+
+	rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val);
+	if (rc < 0) {
+		pr_err("Unable to read REVID rc=%d\n", rc);
+		return rc;
+	}
+
+	switch (val) {
+	case MFG_ID_SMB1354:
+		chip->name = "smb1354";
+		chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA;
+		break;
+	case MFG_ID_SMB1355:
+		chip->name = "smb1355";
+		chip->max_fcc = INT_MAX;
+		break;
+	default:
+		pr_err("Invalid value of REVID val=%d", val);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
 static int smb1355_tskin_sensor_config(struct smb1355 *chip)
 {
 	int rc;
@@ -1196,7 +1236,6 @@
 	chip->dev = &pdev->dev;
 	chip->param = v1_params;
 	chip->c_health = -EINVAL;
-	chip->name = "smb1355";
 	mutex_init(&chip->write_lock);
 	INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work);
 	chip->disabled = true;
@@ -1214,6 +1253,12 @@
 		return -ENODEV;
 	}
 
+	rc = smb1355_detect_version(chip);
+	if (rc < 0) {
+		pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc);
+		goto cleanup;
+	}
+
 	platform_set_drvdata(pdev, chip);
 
 	rc = smb1355_parse_dt(chip);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
new file mode 100644
index 0000000..d20607c
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -0,0 +1,3687 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/driver.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/irq.h>
+#include <linux/pmic-voter.h>
+#include "smb5-lib.h"
+#include "smb5-reg.h"
+#include "battery.h"
+#include "step-chg-jeita.h"
+#include "storm-watch.h"
+
+#define smblib_err(chg, fmt, ...)		\
+	pr_err("%s: %s: " fmt, chg->name,	\
+		__func__, ##__VA_ARGS__)	\
+
+#define smblib_dbg(chg, reason, fmt, ...)			\
+	do {							\
+		if (*chg->debug_mask & (reason))		\
+			pr_info("%s: %s: " fmt, chg->name,	\
+				__func__, ##__VA_ARGS__);	\
+		else						\
+			pr_debug("%s: %s: " fmt, chg->name,	\
+				__func__, ##__VA_ARGS__);	\
+	} while (0)
+
+
+int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
+{
+	unsigned int value;
+	int rc = 0;
+
+	rc = regmap_read(chg->regmap, addr, &value);
+	if (rc >= 0)
+		*val = (u8)value;
+
+	return rc;
+}
+
+int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val,
+			int count)
+{
+	return regmap_bulk_read(chg->regmap, addr, val, count);
+}
+
+int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
+{
+	return regmap_write(chg->regmap, addr, val);
+}
+
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val,
+			int count)
+{
+	return regmap_bulk_write(chg->regmap, addr, val, count);
+}
+
+int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
+{
+	return regmap_update_bits(chg->regmap, addr, mask, val);
+}
+
+int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
+{
+	int rc, cc_minus_ua;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	if (stat & BAT_TEMP_STATUS_HOT_SOFT_BIT) {
+		rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp_hot,
+					&cc_minus_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n",
+					rc);
+			return rc;
+		}
+	} else if (stat & BAT_TEMP_STATUS_COLD_SOFT_BIT) {
+		rc = smblib_get_charge_param(chg,
+					&chg->param.jeita_cc_comp_cold,
+					&cc_minus_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n",
+					rc);
+			return rc;
+		}
+	} else {
+		cc_minus_ua = 0;
+	}
+
+	*cc_delta_ua = -cc_minus_ua;
+
+	return 0;
+}
+
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
+{
+	int rc = 0;
+
+	/* override  = 1, SW STAT override; override = 0, HW auto mode */
+	rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
+				SMB_EN_OVERRIDE_BIT,
+				override ? SMB_EN_OVERRIDE_BIT : 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
+{
+	union extcon_property_value val;
+	union power_supply_propval prop_val;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
+		smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+		val.intval = ((prop_val.intval == 2) ? 1 : 0);
+		extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_TYPEC_POLARITY, val);
+	}
+
+	val.intval = true;
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
+/********************
+ * REGISTER GETTERS *
+ ********************/
+
+int smblib_get_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int *val_u)
+{
+	int rc = 0;
+	u8 val_raw;
+
+	rc = smblib_read(chg, param->reg, &val_raw);
+	if (rc < 0) {
+		smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
+			param->name, param->reg, rc);
+		return rc;
+	}
+
+	if (param->get_proc)
+		*val_u = param->get_proc(param, val_raw);
+	else
+		*val_u = val_raw * param->step_u + param->min_u;
+	smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
+		   param->name, *val_u, val_raw);
+
+	return rc;
+}
+
+int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
+{
+	int rc = 0;
+	u8 temp;
+
+	rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
+		return rc;
+	}
+	*suspend = temp & USBIN_SUSPEND_BIT;
+
+	return rc;
+}
+
+struct apsd_result {
+	const char * const name;
+	const u8 bit;
+	const enum power_supply_type pst;
+};
+
+enum {
+	UNKNOWN,
+	SDP,
+	CDP,
+	DCP,
+	OCP,
+	FLOAT,
+	HVDCP2,
+	HVDCP3,
+	MAX_TYPES
+};
+
+static const struct apsd_result smblib_apsd_results[] = {
+	[UNKNOWN] = {
+		.name	= "UNKNOWN",
+		.bit	= 0,
+		.pst	= POWER_SUPPLY_TYPE_UNKNOWN
+	},
+	[SDP] = {
+		.name	= "SDP",
+		.bit	= SDP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB
+	},
+	[CDP] = {
+		.name	= "CDP",
+		.bit	= CDP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_CDP
+	},
+	[DCP] = {
+		.name	= "DCP",
+		.bit	= DCP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_DCP
+	},
+	[OCP] = {
+		.name	= "OCP",
+		.bit	= OCP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_DCP
+	},
+	[FLOAT] = {
+		.name	= "FLOAT",
+		.bit	= FLOAT_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_FLOAT
+	},
+	[HVDCP2] = {
+		.name	= "HVDCP2",
+		.bit	= DCP_CHARGER_BIT | QC_2P0_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_HVDCP
+	},
+	[HVDCP3] = {
+		.name	= "HVDCP3",
+		.bit	= DCP_CHARGER_BIT | QC_3P0_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_HVDCP_3,
+	},
+};
+
+static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
+{
+	int rc, i;
+	u8 apsd_stat, stat;
+	const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return result;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
+
+	if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
+		return result;
+
+	rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
+			rc);
+		return result;
+	}
+	stat &= APSD_RESULT_STATUS_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
+		if (smblib_apsd_results[i].bit == stat)
+			result = &smblib_apsd_results[i];
+	}
+
+	if (apsd_stat & QC_CHARGER_BIT) {
+		/* since its a qc_charger, either return HVDCP3 or HVDCP2 */
+		if (result != &smblib_apsd_results[HVDCP3])
+			result = &smblib_apsd_results[HVDCP2];
+	}
+
+	return result;
+}
+
+/********************
+ * REGISTER SETTERS *
+ ********************/
+static const struct buck_boost_freq chg_freq_list[] = {
+	[0] = {
+		.freq_khz	= 2400,
+		.val		= 7,
+	},
+	[1] = {
+		.freq_khz	= 2100,
+		.val		= 8,
+	},
+	[2] = {
+		.freq_khz	= 1600,
+		.val		= 11,
+	},
+	[3] = {
+		.freq_khz	= 1200,
+		.val		= 15,
+	},
+};
+
+int smblib_set_chg_freq(struct smb_chg_param *param,
+				int val_u, u8 *val_raw)
+{
+	u8 i;
+
+	if (val_u > param->max_u || val_u < param->min_u)
+		return -EINVAL;
+
+	/* Charger FSW is the configured freqency / 2 */
+	val_u *= 2;
+	for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
+		if (chg_freq_list[i].freq_khz == val_u)
+			break;
+	}
+	if (i == ARRAY_SIZE(chg_freq_list)) {
+		pr_err("Invalid frequency %d Hz\n", val_u / 2);
+		return -EINVAL;
+	}
+
+	*val_raw = chg_freq_list[i].val;
+
+	return 0;
+}
+
+int smblib_set_opt_switcher_freq(struct smb_charger *chg, int fsw_khz)
+{
+	union power_supply_propval pval = {0, };
+	int rc = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, fsw_khz);
+	if (rc < 0)
+		dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
+
+	if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
+		pval.intval = fsw_khz;
+		/*
+		 * Some parallel charging implementations may not have
+		 * PROP_BUCK_FREQ property - they could be running
+		 * with a fixed frequency
+		 */
+		power_supply_set_property(chg->pl.psy,
+				POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
+	}
+
+	return rc;
+}
+
+int smblib_set_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int val_u)
+{
+	int rc = 0;
+	u8 val_raw;
+
+	if (param->set_proc) {
+		rc = param->set_proc(param, val_u, &val_raw);
+		if (rc < 0)
+			return -EINVAL;
+	} else {
+		if (val_u > param->max_u || val_u < param->min_u)
+			smblib_dbg(chg, PR_MISC,
+				"%s: %d is out of range [%d, %d]\n",
+				param->name, val_u, param->min_u, param->max_u);
+
+		if (val_u > param->max_u)
+			val_u = param->max_u;
+		if (val_u < param->min_u)
+			val_u = param->min_u;
+
+		val_raw = (val_u - param->min_u) / param->step_u;
+	}
+
+	rc = smblib_write(chg, param->reg, val_raw);
+	if (rc < 0) {
+		smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
+			param->name, val_raw, param->reg, rc);
+		return rc;
+	}
+
+	smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
+		   param->name, val_u, val_raw);
+
+	return rc;
+}
+
+int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
+{
+	int rc = 0;
+	int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
+
+	if (suspend && irq) {
+		if (chg->usb_icl_change_irq_enabled) {
+			disable_irq_nosync(irq);
+			chg->usb_icl_change_irq_enabled = false;
+		}
+	}
+
+	rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
+				 suspend ? USBIN_SUSPEND_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
+			suspend ? "suspend" : "resume", rc);
+
+	if (!suspend && irq) {
+		if (!chg->usb_icl_change_irq_enabled) {
+			enable_irq(irq);
+			chg->usb_icl_change_irq_enabled = true;
+		}
+	}
+
+	return rc;
+}
+
+int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
+{
+	int rc = 0;
+
+	rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
+				 suspend ? DCIN_SUSPEND_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
+			suspend ? "suspend" : "resume", rc);
+
+	return rc;
+}
+
+static int smblib_set_adapter_allowance(struct smb_charger *chg,
+					u8 allowed_voltage)
+{
+	int rc = 0;
+
+	rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
+			allowed_voltage, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#define MICRO_5V	5000000
+#define MICRO_9V	9000000
+#define MICRO_12V	12000000
+static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
+					int min_allowed_uv, int max_allowed_uv)
+{
+	int rc;
+	u8 allowed_voltage;
+
+	if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_5V);
+	} else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_9V);
+	} else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_12V);
+	} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
+	} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
+	} else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
+	} else {
+		smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
+			min_allowed_uv, max_allowed_uv);
+		return -EINVAL;
+	}
+
+	rc = smblib_set_adapter_allowance(chg, allowed_voltage);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/********************
+ * HELPER FUNCTIONS *
+ ********************/
+static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
+{
+	int rc = 0;
+
+	/* fetch the DPDM regulator */
+	if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
+				"dpdm-supply", NULL)) {
+		chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
+		if (IS_ERR(chg->dpdm_reg)) {
+			rc = PTR_ERR(chg->dpdm_reg);
+			smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
+					rc);
+			chg->dpdm_reg = NULL;
+			return rc;
+		}
+	}
+
+	if (enable) {
+		if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
+			smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
+			rc = regulator_enable(chg->dpdm_reg);
+			if (rc < 0)
+				smblib_err(chg,
+					"Couldn't enable dpdm regulator rc=%d\n",
+					rc);
+		}
+	} else {
+		if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
+			smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
+			rc = regulator_disable(chg->dpdm_reg);
+			if (rc < 0)
+				smblib_err(chg,
+					"Couldn't disable dpdm regulator rc=%d\n",
+					rc);
+		}
+	}
+
+	return rc;
+}
+
+static void smblib_rerun_apsd(struct smb_charger *chg)
+{
+	int rc;
+
+	smblib_dbg(chg, PR_MISC, "re-running APSD\n");
+
+	rc = smblib_masked_write(chg, CMD_APSD_REG,
+				APSD_RERUN_BIT, APSD_RERUN_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
+}
+
+static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* if PD is active, APSD is disabled so won't have a valid result */
+	if (chg->pd_active) {
+		chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
+	} else {
+		/*
+		 * Update real charger type only if its not FLOAT
+		 * detected as as SDP
+		 */
+		if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+			chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			chg->real_charger_type = apsd_result->pst;
+	}
+
+	smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
+					apsd_result->name, chg->pd_active);
+	return apsd_result;
+}
+
+static int smblib_notifier_call(struct notifier_block *nb,
+		unsigned long ev, void *v)
+{
+	struct power_supply *psy = v;
+	struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
+
+	if (!strcmp(psy->desc->name, "bms")) {
+		if (!chg->bms_psy)
+			chg->bms_psy = psy;
+		if (ev == PSY_EVENT_PROP_CHANGED)
+			schedule_work(&chg->bms_update_work);
+	}
+
+	if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
+		chg->pl.psy = psy;
+		schedule_work(&chg->pl_update_work);
+	}
+
+	return NOTIFY_OK;
+}
+
+static int smblib_register_notifier(struct smb_charger *chg)
+{
+	int rc;
+
+	chg->nb.notifier_call = smblib_notifier_call;
+	rc = power_supply_reg_notifier(&chg->nb);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw)
+{
+	if (val_u > param->max_u || val_u < param->min_u)
+		return -EINVAL;
+
+	*val_raw = val_u << 1;
+
+	return 0;
+}
+
+int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
+					   u8 val_raw)
+{
+	int val_u  = val_raw * param->step_u + param->min_u;
+
+	if (val_u > param->max_u)
+		val_u -= param->max_u * 2;
+
+	return val_u;
+}
+
+int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw)
+{
+	if (val_u > param->max_u || val_u < param->min_u - param->max_u)
+		return -EINVAL;
+
+	val_u += param->max_u * 2 - param->min_u;
+	val_u %= param->max_u * 2;
+	*val_raw = val_u / param->step_u;
+
+	return 0;
+}
+
+static void smblib_uusb_removal(struct smb_charger *chg)
+{
+	int rc;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	cancel_delayed_work_sync(&chg->pl_enable_work);
+
+	rc = smblib_request_dpdm(chg, false);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
+
+	if (chg->wa_flags & BOOST_BACK_WA) {
+		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+		if (data) {
+			wdata = &data->storm_data;
+			update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					false, 0);
+		}
+	}
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
+	/* reset both usbin current and voltage votes */
+	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+
+	/* reconfigure allowed voltage for HVDCP */
+	rc = smblib_set_adapter_allowance(chg,
+			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+			rc);
+
+	chg->voltage_min_uv = MICRO_5V;
+	chg->voltage_max_uv = MICRO_5V;
+	chg->usb_icl_delta_ua = 0;
+	chg->pulse_cnt = 0;
+	chg->uusb_apsd_rerun_done = false;
+
+	/* clear USB ICL vote for USB_PSY_VOTER */
+	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+
+	/* clear USB ICL vote for DCP_VOTER */
+	rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+	if (rc < 0)
+		smblib_err(chg,
+			"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
+}
+
+void smblib_suspend_on_debug_battery(struct smb_charger *chg)
+{
+	int rc;
+	union power_supply_propval val;
+
+	rc = power_supply_get_property(chg->bms_psy,
+			POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
+		return;
+	}
+	if (chg->suspend_input_on_debug_batt) {
+		vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+		vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+		if (val.intval)
+			pr_info("Input suspended: Fake battery\n");
+	} else {
+		vote(chg->chg_disable_votable, DEBUG_BOARD_VOTER,
+					val.intval, 0);
+	}
+}
+
+int smblib_rerun_apsd_if_required(struct smb_charger *chg)
+{
+	union power_supply_propval val;
+	int rc;
+
+	rc = smblib_get_prop_usb_present(chg, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
+		return rc;
+	}
+
+	if (!val.intval)
+		return 0;
+
+	rc = smblib_request_dpdm(chg, true);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+
+	chg->uusb_apsd_rerun_done = true;
+	smblib_rerun_apsd(chg);
+
+	return 0;
+}
+
+static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
+{
+	*count = chg->pulse_cnt;
+	return 0;
+}
+
+#define USBIN_25MA	25000
+#define USBIN_100MA	100000
+#define USBIN_150MA	150000
+#define USBIN_500MA	500000
+#define USBIN_900MA	900000
+static int set_sdp_current(struct smb_charger *chg, int icl_ua)
+{
+	int rc;
+	u8 icl_options;
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* power source is SDP */
+	switch (icl_ua) {
+	case USBIN_100MA:
+		/* USB 2.0 100mA */
+		icl_options = 0;
+		break;
+	case USBIN_150MA:
+		/* USB 3.0 150mA */
+		icl_options = CFG_USB3P0_SEL_BIT;
+		break;
+	case USBIN_500MA:
+		/* USB 2.0 500mA */
+		icl_options = USB51_MODE_BIT;
+		break;
+	case USBIN_900MA:
+		/* USB 3.0 900mA */
+		icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
+		break;
+	default:
+		smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
+		return -EINVAL;
+	}
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
+		apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
+		/*
+		 * change the float charger configuration to SDP, if this
+		 * is the case of SDP being detected as FLOAT
+		 */
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+			FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
+						rc);
+			return rc;
+		}
+	}
+
+	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+		CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
+{
+	int rc;
+	u8 icl_options;
+	bool usb3 = false;
+
+	rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
+		return rc;
+	}
+
+	usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
+
+	if (icl_options & USB51_MODE_BIT)
+		*icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
+	else
+		*icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
+
+	return rc;
+}
+
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
+{
+	int rc = 0;
+	bool hc_mode = false;
+
+	/* suspend and return if 25mA or less is requested */
+	if (icl_ua <= USBIN_25MA)
+		return smblib_set_usb_suspend(chg, true);
+
+	if (icl_ua == INT_MAX)
+		goto set_mode;
+
+	/* configure current */
+	if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
+		|| (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+		&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
+		rc = set_sdp_current(chg, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
+			goto out;
+		}
+	} else {
+		set_sdp_current(chg, 100000);
+		rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
+			goto out;
+		}
+		hc_mode = true;
+	}
+
+set_mode:
+	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+		USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
+
+	/* unsuspend after configuring current and override */
+	rc = smblib_set_usb_suspend(chg, false);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
+		goto out;
+	}
+
+out:
+	return rc;
+}
+
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
+{
+	int rc = 0;
+	u8 load_cfg;
+	bool override;
+
+	if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+		|| chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		&& (chg->usb_psy->desc->type == POWER_SUPPLY_TYPE_USB)) {
+		rc = get_sdp_current(chg, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
+			return rc;
+		}
+	} else {
+		rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
+			return rc;
+		}
+		override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
+		if (!override)
+			return INT_MAX;
+
+		/* override is set */
+		rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/*********************
+ * VOTABLE CALLBACKS *
+ *********************/
+
+static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
+			int suspend, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (chg->smb_version == PMI632_SUBTYPE)
+		return 0;
+
+	/* resume input if suspend is invalid */
+	if (suspend < 0)
+		suspend = 0;
+
+	return smblib_set_dc_suspend(chg, (bool)suspend);
+}
+
+static int smblib_pd_disallowed_votable_indirect_callback(
+	struct votable *votable, void *data, int disallowed, const char *client)
+{
+	struct smb_charger *chg = data;
+	int rc;
+
+	rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
+		!disallowed, 0);
+
+	return rc;
+}
+
+static int smblib_awake_vote_callback(struct votable *votable, void *data,
+			int awake, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (awake)
+		pm_stay_awake(chg->dev);
+	else
+		pm_relax(chg->dev);
+
+	return 0;
+}
+
+static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
+			int chg_disable, const char *client)
+{
+	struct smb_charger *chg = data;
+	int rc;
+
+	rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+				 CHARGING_ENABLE_CMD_BIT,
+				 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't %s charging rc=%d\n",
+			chg_disable ? "disable" : "enable", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
+				void *data, int enable, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (!chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq ||
+				!chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		return 0;
+
+	if (enable) {
+		enable_irq(chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq);
+		enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+	} else {
+		disable_irq_nosync(
+			chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq);
+		disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+	}
+
+	return 0;
+}
+
+/*******************
+ * VCONN REGULATOR *
+ * *****************/
+
+int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
+
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_VALUE_BIT, VCONN_EN_VALUE_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_VALUE_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
+
+	return 0;
+}
+
+int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+	u8 cmd;
+
+	rc = smblib_read(chg, TYPE_C_VCONN_CONTROL_REG, &cmd);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	return (cmd & VCONN_EN_VALUE_BIT) ? 1 : 0;
+}
+
+/*****************
+ * OTG REGULATOR *
+ *****************/
+
+int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+
+	smblib_dbg(chg, PR_OTG, "enabling OTG\n");
+
+	rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, OTG_EN_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+
+	smblib_dbg(chg, PR_OTG, "disabling OTG\n");
+
+	rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u8 cmd;
+
+	rc = smblib_read(chg, DCDC_CMD_OTG_REG, &cmd);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read CMD_OTG rc=%d", rc);
+		return rc;
+	}
+
+	return (cmd & OTG_EN_BIT) ? 1 : 0;
+}
+
+/********************
+ * BATT PSY GETTERS *
+ ********************/
+
+int smblib_get_prop_input_suspend(struct smb_charger *chg,
+				  union power_supply_propval *val)
+{
+	val->intval
+		= (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
+		 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
+	return 0;
+}
+
+int smblib_get_prop_batt_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
+					| BAT_TERMINAL_MISSING_RT_STS_BIT));
+
+	return rc;
+}
+
+int smblib_get_prop_batt_capacity(struct smb_charger *chg,
+				  union power_supply_propval *val)
+{
+	int rc = -EINVAL;
+
+	if (chg->fake_capacity >= 0) {
+		val->intval = chg->fake_capacity;
+		return 0;
+	}
+
+	if (chg->bms_psy)
+		rc = power_supply_get_property(chg->bms_psy,
+				POWER_SUPPLY_PROP_CAPACITY, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_status(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	union power_supply_propval pval = {0, };
+	bool usb_online, dc_online;
+	u8 stat;
+	int rc;
+
+	rc = smblib_get_prop_usb_online(chg, &pval);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get usb online property rc=%d\n",
+			rc);
+		return rc;
+	}
+	usb_online = (bool)pval.intval;
+
+	rc = smblib_get_prop_dc_online(chg, &pval);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get dc online property rc=%d\n",
+			rc);
+		return rc;
+	}
+	dc_online = (bool)pval.intval;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+
+	if (!usb_online && !dc_online) {
+		switch (stat) {
+		case TERMINATE_CHARGE:
+		case INHIBIT_CHARGE:
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+			break;
+		}
+		return rc;
+	}
+
+	switch (stat) {
+	case TRICKLE_CHARGE:
+	case PRE_CHARGE:
+	case FULLON_CHARGE:
+	case TAPER_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case TERMINATE_CHARGE:
+	case INHIBIT_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case DISABLE_CHARGE:
+	case PAUSE_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+		return 0;
+
+	if (!usb_online && dc_online
+		&& chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return 0;
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+				rc);
+			return rc;
+	}
+
+	stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
+						ENABLE_FULLON_MODE_BIT;
+
+	if (!stat)
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+	return 0;
+}
+
+int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	switch (stat & BATTERY_CHARGER_STATUS_MASK) {
+	case TRICKLE_CHARGE:
+	case PRE_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	case FULLON_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		break;
+	case TAPER_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	return rc;
+}
+
+int smblib_get_prop_batt_health(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	union power_supply_propval pval;
+	int rc;
+	int effective_fv_uv;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
+		   stat);
+
+	if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
+		rc = smblib_get_prop_batt_voltage_now(chg, &pval);
+		if (!rc) {
+			/*
+			 * If Vbatt is within 40mV above Vfloat, then don't
+			 * treat it as overvoltage.
+			 */
+			effective_fv_uv = get_effective_result(chg->fv_votable);
+			if (pval.intval >= effective_fv_uv + 40000) {
+				val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+				smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
+						pval.intval, effective_fv_uv);
+				goto done;
+			}
+		}
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+	if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_COLD;
+	else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+	else if (stat & BAT_TEMP_STATUS_COLD_SOFT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_COOL;
+	else if (stat & BAT_TEMP_STATUS_HOT_SOFT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_WARM;
+	else
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+
+done:
+	return rc;
+}
+
+int smblib_get_prop_system_temp_level(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->system_temp_level;
+	return 0;
+}
+
+int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->thermal_levels;
+	return 0;
+}
+
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	u8 stat;
+	int rc;
+
+	if (chg->fake_input_current_limited >= 0) {
+		val->intval = chg->fake_input_current_limited;
+		return 0;
+	}
+
+	rc = smblib_read(chg, AICL_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
+		return rc;
+	}
+	val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
+	return 0;
+}
+
+int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_current_now(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_CURRENT_NOW, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_temp(struct smb_charger *chg,
+			      union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_TEMP, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
+					union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+	val->intval = (stat == TERMINATE_CHARGE);
+	return 0;
+}
+
+int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
+	return rc;
+}
+
+/***********************
+ * BATTERY PSY SETTERS *
+ ***********************/
+
+int smblib_set_prop_input_suspend(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	int rc;
+
+	/* vote 0mA when suspended */
+	rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
+			(bool)val->intval ? "suspend" : "resume", rc);
+		return rc;
+	}
+
+	rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
+			(bool)val->intval ? "suspend" : "resume", rc);
+		return rc;
+	}
+
+	power_supply_changed(chg->batt_psy);
+	return rc;
+}
+
+int smblib_set_prop_batt_capacity(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	chg->fake_capacity = val->intval;
+
+	power_supply_changed(chg->batt_psy);
+
+	return 0;
+}
+
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	/* Faking battery full */
+	if (val->intval == POWER_SUPPLY_STATUS_FULL)
+		chg->fake_batt_status = val->intval;
+	else
+		chg->fake_batt_status = -EINVAL;
+
+	power_supply_changed(chg->batt_psy);
+
+	return 0;
+}
+
+int smblib_set_prop_system_temp_level(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	if (val->intval < 0)
+		return -EINVAL;
+
+	if (chg->thermal_levels <= 0)
+		return -EINVAL;
+
+	if (val->intval > chg->thermal_levels)
+		return -EINVAL;
+
+	chg->system_temp_level = val->intval;
+	/* disable parallel charge in case of system temp level */
+	vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
+			chg->system_temp_level ? true : false, 0);
+
+	if (chg->system_temp_level == chg->thermal_levels)
+		return vote(chg->chg_disable_votable,
+			THERMAL_DAEMON_VOTER, true, 0);
+
+	vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
+	if (chg->system_temp_level == 0)
+		return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
+
+	vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
+			chg->thermal_mitigation[chg->system_temp_level]);
+	return 0;
+}
+
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	chg->fake_input_current_limited = val->intval;
+	return 0;
+}
+
+int smblib_rerun_aicl(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+								rc);
+		return rc;
+	}
+
+	/* USB is suspended so skip re-running AICL */
+	if (stat & USBIN_SUSPEND_STS_BIT)
+		return rc;
+
+	smblib_dbg(chg, PR_MISC, "re-running AICL\n");
+
+	rc = smblib_masked_write(chg, AICL_CMD_REG, RERUN_AICL_BIT,
+				RERUN_AICL_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to AICL_CMD_REG rc=%d\n",
+				rc);
+	return 0;
+}
+
+static int smblib_dp_pulse(struct smb_charger *chg)
+{
+	int rc;
+
+	/* QC 3.0 increment */
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
+			SINGLE_INCREMENT_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_dm_pulse(struct smb_charger *chg)
+{
+	int rc;
+
+	/* QC 3.0 decrement */
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
+			SINGLE_DECREMENT_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+	int rc;
+
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+int smblib_dp_dm(struct smb_charger *chg, int val)
+{
+	int target_icl_ua, rc = 0;
+	union power_supply_propval pval;
+
+	switch (val) {
+	case POWER_SUPPLY_DP_DM_DP_PULSE:
+		rc = smblib_dp_pulse(chg);
+		if (!rc)
+			chg->pulse_cnt++;
+		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
+				rc, chg->pulse_cnt);
+		break;
+	case POWER_SUPPLY_DP_DM_DM_PULSE:
+		rc = smblib_dm_pulse(chg);
+		if (!rc && chg->pulse_cnt)
+			chg->pulse_cnt--;
+		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
+				rc, chg->pulse_cnt);
+		break;
+	case POWER_SUPPLY_DP_DM_ICL_DOWN:
+		target_icl_ua = get_effective_result(chg->usb_icl_votable);
+		if (target_icl_ua < 0) {
+			/* no client vote, get the ICL from charger */
+			rc = power_supply_get_property(chg->usb_psy,
+					POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+					&pval);
+			if (rc < 0) {
+				smblib_err(chg, "Couldn't get max curr rc=%d\n",
+					rc);
+				return rc;
+			}
+			target_icl_ua = pval.intval;
+		}
+
+		/*
+		 * Check if any other voter voted on USB_ICL in case of
+		 * voter other than SW_QC3_VOTER reset and restart reduction
+		 * again.
+		 */
+		if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
+							SW_QC3_VOTER))
+			chg->usb_icl_delta_ua = 0;
+
+		chg->usb_icl_delta_ua += 100000;
+		vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
+						target_icl_ua - 100000);
+		smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
+				target_icl_ua, chg->usb_icl_delta_ua);
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_5V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 5V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_9V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 9V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_12V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 12V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_ICL_UP:
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
+{
+	int rc;
+	u8 mask;
+
+	/*
+	 * Disable h/w base JEITA compensation if s/w JEITA is enabled
+	 */
+	mask = JEITA_EN_COLD_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_CCC_BIT
+		| JEITA_EN_COLD_SL_CCC_BIT,
+	rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
+			disable ? 0 : mask);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure s/w jeita rc=%d\n",
+				rc);
+		return rc;
+	}
+	return 0;
+}
+
+/*******************
+ * DC PSY GETTERS *
+ *******************/
+
+int smblib_get_prop_dc_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
+	return 0;
+}
+
+int smblib_get_prop_dc_online(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
+		val->intval = false;
+		return rc;
+	}
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
+		   stat);
+
+	val->intval = (stat & USE_DCIN_BIT) &&
+		      (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
+
+	return rc;
+}
+
+/*******************
+ * USB PSY GETTERS *
+ *******************/
+
+int smblib_get_prop_usb_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+	return 0;
+}
+
+int smblib_get_prop_usb_online(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
+		val->intval = false;
+		return rc;
+	}
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
+		   stat);
+
+	val->intval = (stat & USE_USBIN_BIT) &&
+		      (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
+	return rc;
+}
+
+int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
+				    union power_supply_propval *val)
+{
+	switch (chg->real_charger_type) {
+	case POWER_SUPPLY_TYPE_USB_HVDCP:
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+	case POWER_SUPPLY_TYPE_USB_PD:
+		if (chg->smb_version == PMI632_SUBTYPE)
+			val->intval = MICRO_9V;
+		else
+			val->intval = MICRO_12V;
+		break;
+	default:
+		val->intval = MICRO_5V;
+		break;
+	}
+
+	return 0;
+}
+
+int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
+					 union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
+
+	if (stat & CC_ATTACHED_BIT)
+		val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+	else
+		val->intval = 0;
+
+	return rc;
+}
+
+static const char * const smblib_typec_mode_name[] = {
+	[POWER_SUPPLY_TYPEC_NONE]		  = "NONE",
+	[POWER_SUPPLY_TYPEC_SOURCE_DEFAULT]	  = "SOURCE_DEFAULT",
+	[POWER_SUPPLY_TYPEC_SOURCE_MEDIUM]	  = "SOURCE_MEDIUM",
+	[POWER_SUPPLY_TYPEC_SOURCE_HIGH]	  = "SOURCE_HIGH",
+	[POWER_SUPPLY_TYPEC_NON_COMPLIANT]	  = "NON_COMPLIANT",
+	[POWER_SUPPLY_TYPEC_SINK]		  = "SINK",
+	[POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE]   = "SINK_POWERED_CABLE",
+	[POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
+	[POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER]   = "SINK_AUDIO_ADAPTER",
+	[POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY]   = "POWERED_CABLE_ONLY",
+};
+
+static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_SNK_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
+		return POWER_SUPPLY_TYPEC_NONE;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
+
+	switch (stat & DETECTED_SRC_TYPE_MASK) {
+	case SNK_RP_STD_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
+	case SNK_RP_1P5_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
+	case SNK_RP_3P0_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_TYPEC_NONE;
+}
+
+static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n",
+				rc);
+		return POWER_SUPPLY_TYPEC_NONE;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_SRC_STATUS_REG = 0x%02x\n", stat);
+
+	switch (stat & DETECTED_SNK_TYPE_MASK) {
+	case AUDIO_ACCESS_RA_RA_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
+	case SRC_DEBUG_ACCESS_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
+	case SRC_RD_RA_VCONN_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
+	case SRC_RD_OPEN_BIT:
+		return POWER_SUPPLY_TYPEC_SINK;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_TYPEC_NONE;
+}
+
+static int smblib_get_prop_typec_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
+				rc);
+		return 0;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_MISC_STATUS_REG = 0x%02x\n", stat);
+
+	if (stat & SNK_SRC_MODE_BIT)
+		return smblib_get_prop_dfp_mode(chg);
+	else
+		return smblib_get_prop_ufp_mode(chg);
+}
+
+int smblib_get_prop_typec_power_role(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 ctrl;
+
+	rc = smblib_read(chg, TYPE_C_MODE_CFG_REG, &ctrl);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_MODE_CFG_REG rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_MODE_CFG_REG = 0x%02x\n",
+		   ctrl);
+
+	if (ctrl & TYPEC_DISABLE_CMD_BIT) {
+		val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		return rc;
+	}
+
+	switch (ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT)) {
+	case 0:
+		val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+		break;
+	case EN_SRC_ONLY_BIT:
+		val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+		break;
+	case EN_SNK_ONLY_BIT:
+		val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		smblib_err(chg, "unsupported power role 0x%02lx\n",
+			ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT));
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int smblib_get_prop_pd_allowed(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	val->intval = get_effective_result(chg->pd_allowed_votable);
+	return 0;
+}
+
+int smblib_get_prop_input_current_settled(struct smb_charger *chg,
+					  union power_supply_propval *val)
+{
+	return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
+}
+
+#define HVDCP3_STEP_UV	200000
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+						union power_supply_propval *val)
+{
+	int rc, pulses;
+
+	switch (chg->real_charger_type) {
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+		rc = smblib_get_pulse_cnt(chg, &pulses);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+			return 0;
+		}
+		val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
+		break;
+	case POWER_SUPPLY_TYPE_USB_PD:
+		val->intval = chg->voltage_min_uv;
+		break;
+	default:
+		val->intval = MICRO_5V;
+		break;
+	}
+
+	return 0;
+}
+
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	val->intval = chg->pd_hard_reset;
+	return 0;
+}
+
+int smblib_get_pe_start(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	/*
+	 * hvdcp timeout voter is the last one to allow pd. Use its vote
+	 * to indicate start of pe engine
+	 */
+	val->intval
+		= !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
+			APSD_VOTER);
+	return 0;
+}
+
+int smblib_get_prop_die_health(struct smb_charger *chg,
+						union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
+									rc);
+		return rc;
+	}
+
+	/* TEMP_RANGE bits are mutually exclusive */
+	switch (stat & TEMP_RANGE_MASK) {
+	case TEMP_BELOW_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_COOL;
+		break;
+	case TEMP_WITHIN_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_WARM;
+		break;
+	case TEMP_ABOVE_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_HOT;
+		break;
+	case ALERT_LEVEL_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+
+	return 0;
+}
+
+#define SDP_CURRENT_UA			500000
+#define CDP_CURRENT_UA			1500000
+#define DCP_CURRENT_UA			1500000
+#define HVDCP_CURRENT_UA		3000000
+#define TYPEC_DEFAULT_CURRENT_UA	900000
+#define TYPEC_MEDIUM_CURRENT_UA		1500000
+#define TYPEC_HIGH_CURRENT_UA		3000000
+static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
+{
+	int rp_ua;
+
+	switch (typec_mode) {
+	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+		rp_ua = TYPEC_HIGH_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+	/* fall through */
+	default:
+		rp_ua = DCP_CURRENT_UA;
+	}
+
+	return rp_ua;
+}
+
+/*******************
+ * USB PSY SETTERS *
+ * *****************/
+
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc;
+
+	if (chg->pd_active)
+		rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
+	else
+		rc = -EPERM;
+
+	return rc;
+}
+
+static int smblib_handle_usb_current(struct smb_charger *chg,
+					int usb_current)
+{
+	int rc = 0, rp_ua, typec_mode;
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+		if (usb_current == -ETIMEDOUT) {
+			/*
+			 * Valid FLOAT charger, report the current based
+			 * of Rp
+			 */
+			typec_mode = smblib_get_prop_typec_mode(chg);
+			rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+			rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+								true, rp_ua);
+			if (rc < 0)
+				return rc;
+		} else {
+			/*
+			 * FLOAT charger detected as SDP by USB driver,
+			 * charge with the requested current and update the
+			 * real_charger_type
+			 */
+			chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
+			rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+						true, usb_current);
+			if (rc < 0)
+				return rc;
+			rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+							false, 0);
+			if (rc < 0)
+				return rc;
+		}
+	} else {
+		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+					true, usb_current);
+	}
+
+	return rc;
+}
+
+int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	if (!chg->pd_active) {
+		rc = smblib_handle_usb_current(chg, val->intval);
+	} else if (chg->system_suspend_supported) {
+		if (val->intval <= USBIN_25MA)
+			rc = vote(chg->usb_icl_votable,
+				PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
+		else
+			rc = vote(chg->usb_icl_votable,
+				PD_SUSPEND_SUPPORTED_VOTER, false, 0);
+	}
+	return rc;
+}
+
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+					const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+				val->intval <= chg->boost_threshold_ua ?
+				chg->chg_freq.freq_below_otg_threshold :
+				chg->chg_freq.freq_above_otg_threshold);
+	if (rc < 0) {
+		dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->boost_current_ua = val->intval;
+	return rc;
+}
+
+int smblib_set_prop_typec_power_role(struct smb_charger *chg,
+				     const union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 power_role;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		return 0;
+
+	switch (val->intval) {
+	case POWER_SUPPLY_TYPEC_PR_NONE:
+		power_role = TYPEC_DISABLE_CMD_BIT;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_DUAL:
+		power_role = 0;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_SINK:
+		power_role = EN_SNK_ONLY_BIT;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_SOURCE:
+		power_role = EN_SRC_ONLY_BIT;
+		break;
+	default:
+		smblib_err(chg, "power role %d not supported\n", val->intval);
+		return -EINVAL;
+	}
+
+	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, power_role);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+			power_role, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc, min_uv;
+
+	min_uv = min(val->intval, chg->voltage_max_uv);
+	rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
+					       chg->voltage_max_uv);
+	if (rc < 0) {
+		smblib_err(chg, "invalid max voltage %duV rc=%d\n",
+			val->intval, rc);
+		return rc;
+	}
+
+	chg->voltage_min_uv = min_uv;
+	power_supply_changed(chg->usb_main_psy);
+
+	return rc;
+}
+
+int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc, max_uv;
+
+	max_uv = max(val->intval, chg->voltage_min_uv);
+	rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
+					       max_uv);
+	if (rc < 0) {
+		smblib_err(chg, "invalid min voltage %duV rc=%d\n",
+			val->intval, rc);
+		return rc;
+	}
+
+	chg->voltage_max_uv = max_uv;
+	power_supply_changed(chg->usb_main_psy);
+
+	return rc;
+}
+
+static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
+{
+	int rc = 0;
+
+	chg->pd_active = pd_active;
+
+	if (chg->pd_active) {
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+		/*
+		 * Enforce 500mA for PD until the real vote comes in later.
+		 * It is guaranteed that pd_active is set prior to
+		 * pd_current_max
+		 */
+		rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
+									rc);
+
+		/* since PD was found the cable must be non-legacy */
+		vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+
+		/* clear USB ICL vote for DCP_VOTER */
+		rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+									rc);
+
+		/* remove USB_PSY_VOTER */
+		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+	} else {
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+	}
+
+	smblib_update_usb_type(chg);
+	power_supply_changed(chg->usb_psy);
+	return rc;
+}
+
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+			      const union power_supply_propval *val)
+{
+	if (!get_effective_result(chg->pd_allowed_votable))
+		return -EINVAL;
+
+	return __smblib_set_prop_pd_active(chg, val->intval);
+}
+
+int smblib_set_prop_ship_mode(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc;
+
+	smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
+
+	rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
+			!!val->intval ? SHIP_MODE_EN_BIT : 0);
+	if (rc < 0)
+		dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
+				!!val->intval ? "enable" : "disable", rc);
+
+	return rc;
+}
+
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	if (chg->pd_hard_reset == val->intval)
+		return rc;
+
+	chg->pd_hard_reset = val->intval;
+	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+			EXIT_SNK_BASED_ON_CC_BIT,
+			(chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
+{
+	u8 stat1, stat7;
+	int rc;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat1);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat7);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	if ((chg->jeita_status && !(stat7 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
+		((stat1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
+		/*
+		 * We are moving from JEITA soft -> Normal and charging
+		 * is terminated
+		 */
+		rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't disable charging rc=%d\n",
+						rc);
+			return rc;
+		}
+		rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
+						CHARGING_ENABLE_CMD_BIT);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't enable charging rc=%d\n",
+						rc);
+			return rc;
+		}
+	}
+
+	chg->jeita_status = stat7 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
+
+	return 0;
+}
+
+/************************
+ * USB MAIN PSY GETTERS *
+ ************************/
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc, jeita_cc_delta_ua = 0;
+
+	if (chg->sw_jeita_enabled) {
+		val->intval = 0;
+		return 0;
+	}
+
+	rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+		jeita_cc_delta_ua = 0;
+	}
+
+	val->intval = jeita_cc_delta_ua;
+	return 0;
+}
+
+/************************
+ * USB MAIN PSY SETTERS *
+ ************************/
+int smblib_get_charge_current(struct smb_charger *chg,
+				int *total_current_ua)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+	union power_supply_propval val = {0, };
+	int rc = 0, typec_source_rd, current_ua;
+	bool non_compliant;
+	u8 stat;
+
+	if (chg->pd_active) {
+		*total_current_ua =
+			get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
+		return rc;
+	}
+
+	rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+		return rc;
+	}
+	non_compliant = stat & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
+
+	/* get settled ICL */
+	rc = smblib_get_prop_input_current_settled(chg, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
+		return rc;
+	}
+
+	typec_source_rd = smblib_get_prop_ufp_mode(chg);
+
+	/* QC 2.0/3.0 adapter */
+	if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
+		*total_current_ua = HVDCP_CURRENT_UA;
+		return 0;
+	}
+
+	if (non_compliant) {
+		switch (apsd_result->bit) {
+		case CDP_CHARGER_BIT:
+			current_ua = CDP_CURRENT_UA;
+			break;
+		case DCP_CHARGER_BIT:
+		case OCP_CHARGER_BIT:
+		case FLOAT_CHARGER_BIT:
+			current_ua = DCP_CURRENT_UA;
+			break;
+		default:
+			current_ua = 0;
+			break;
+		}
+
+		*total_current_ua = max(current_ua, val.intval);
+		return 0;
+	}
+
+	switch (typec_source_rd) {
+	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+		switch (apsd_result->bit) {
+		case CDP_CHARGER_BIT:
+			current_ua = CDP_CURRENT_UA;
+			break;
+		case DCP_CHARGER_BIT:
+		case OCP_CHARGER_BIT:
+		case FLOAT_CHARGER_BIT:
+			current_ua = chg->default_icl_ua;
+			break;
+		default:
+			current_ua = 0;
+			break;
+		}
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+		current_ua = TYPEC_MEDIUM_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+		current_ua = TYPEC_HIGH_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
+	case POWER_SUPPLY_TYPEC_NONE:
+	default:
+		current_ua = 0;
+		break;
+	}
+
+	*total_current_ua = max(current_ua, val.intval);
+	return 0;
+}
+
+/**********************
+ * INTERRUPT HANDLERS *
+ **********************/
+
+irqreturn_t default_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t chg_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	u8 stat;
+	int rc;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+				rc);
+		return IRQ_HANDLED;
+	}
+
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t batt_temp_changed_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+
+	rc = smblib_recover_from_soft_jeita(chg);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
+				rc);
+		return IRQ_HANDLED;
+	}
+
+	rerun_election(chg->fcc_votable);
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t batt_psy_changed_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t usbin_uv_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	struct storm_watch *wdata;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data)
+		return IRQ_HANDLED;
+
+	wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data;
+	reset_storm_count(wdata);
+	return IRQ_HANDLED;
+}
+
+#define USB_WEAK_INPUT_UA	1400000
+#define ICL_CHANGE_DELAY_MS	1000
+irqreturn_t icl_change_irq_handler(int irq, void *data)
+{
+	u8 stat;
+	int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if (chg->mode == PARALLEL_MASTER) {
+		rc = smblib_read(chg, AICL_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
+					rc);
+			return IRQ_HANDLED;
+		}
+
+		rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
+					&settled_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
+			return IRQ_HANDLED;
+		}
+
+		/* If AICL settled then schedule work now */
+		if (settled_ua == get_effective_result(chg->usb_icl_votable))
+			delay = 0;
+
+		cancel_delayed_work_sync(&chg->icl_change_work);
+		schedule_delayed_work(&chg->icl_change_work,
+						msecs_to_jiffies(delay));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+	if (vbus_rising) {
+		/* use the typec flag even though its not typec */
+		chg->typec_present = 1;
+	} else {
+		chg->typec_present = 0;
+		smblib_update_usb_type(chg);
+		smblib_notify_device_mode(chg, false);
+		smblib_uusb_removal(chg);
+	}
+}
+
+void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	bool vbus_rising;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+		return;
+	}
+
+	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+
+	if (!vbus_rising) {
+		if (chg->wa_flags & BOOST_BACK_WA) {
+			data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+			if (data) {
+				wdata = &data->storm_data;
+				update_storm_count(wdata,
+						WEAK_CHG_STORM_COUNT);
+				vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
+						false, 0);
+				vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+						false, 0);
+			}
+		}
+	}
+
+	power_supply_changed(chg->usb_psy);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+					vbus_rising ? "attached" : "detached");
+}
+
+#define PL_DELAY_MS	30000
+void smblib_usb_plugin_locked(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	bool vbus_rising;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+		return;
+	}
+
+	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+	smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_5V :
+						chg->chg_freq.freq_removal);
+
+	if (vbus_rising) {
+		rc = smblib_request_dpdm(chg, true);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+
+		/* Schedule work to enable parallel charger */
+		vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
+		schedule_delayed_work(&chg->pl_enable_work,
+					msecs_to_jiffies(PL_DELAY_MS));
+	} else {
+		if (chg->wa_flags & BOOST_BACK_WA) {
+			data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+			if (data) {
+				wdata = &data->storm_data;
+				update_storm_count(wdata,
+						WEAK_CHG_STORM_COUNT);
+				vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
+						false, 0);
+				vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+						false, 0);
+			}
+		}
+
+		rc = smblib_request_dpdm(chg, false);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+	}
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		smblib_micro_usb_plugin(chg, vbus_rising);
+
+	power_supply_changed(chg->usb_psy);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+					vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t usb_plugin_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	mutex_lock(&chg->lock);
+	if (chg->pd_hard_reset)
+		smblib_usb_plugin_hard_reset_locked(chg);
+	else
+		smblib_usb_plugin_locked(chg);
+	mutex_unlock(&chg->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
+					      bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
+		   rising ? "rising" : "falling");
+}
+
+static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
+					       bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
+		   rising ? "rising" : "falling");
+}
+
+#define QC3_PULSES_FOR_6V	5
+#define QC3_PULSES_FOR_9V	20
+#define QC3_PULSES_FOR_12V	35
+static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	int pulses;
+
+	power_supply_changed(chg->usb_main_psy);
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+		rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
+			return;
+		}
+
+		switch (stat & QC_2P0_STATUS_MASK) {
+		case QC_5V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_5V);
+			break;
+		case QC_9V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_9V);
+			break;
+		case QC_12V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_12V);
+			break;
+		default:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_removal);
+			break;
+		}
+	}
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+		rc = smblib_get_pulse_cnt(chg, &pulses);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+			return;
+		}
+
+		if (pulses < QC3_PULSES_FOR_6V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_5V);
+		else if (pulses < QC3_PULSES_FOR_9V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_6V_8V);
+		else if (pulses < QC3_PULSES_FOR_12V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_9V);
+		else
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_12V);
+	}
+}
+
+/* triggers when HVDCP 3.0 authentication has finished */
+static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
+					      bool rising)
+{
+	const struct apsd_result *apsd_result;
+
+	if (!rising)
+		return;
+
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+
+	if (chg->mode == PARALLEL_MASTER)
+		vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
+
+	/* the APSD done handler will set the USB supply type */
+	apsd_result = smblib_get_apsd_result(chg);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
+		   apsd_result->name);
+}
+
+static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
+					      bool rising, bool qc_charger)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* Hold off PD only until hvdcp 2.0 detection timeout */
+	if (rising) {
+
+		/* enable HDC and ICL irq for QC2/3 charger */
+		if (qc_charger)
+			vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
+		else
+			vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+							false, 0);
+
+		/*
+		 * HVDCP detection timeout done
+		 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
+		 */
+		if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
+			/* enforce DCP ICL if specified */
+			vote(chg->usb_icl_votable, DCP_VOTER,
+				chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
+
+		/*
+		 * if pd is not allowed, then set pd_active = false right here,
+		 * so that it starts the hvdcp engine
+		 */
+		if (!get_effective_result(chg->pd_allowed_votable))
+			__smblib_set_prop_pd_active(chg, 0);
+	}
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
+		   rising ? "rising" : "falling");
+}
+
+/* triggers when HVDCP is detected */
+static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
+					    bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
+		   rising ? "rising" : "falling");
+}
+
+static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
+{
+	const struct apsd_result *apsd_result;
+
+	if (!rising)
+		return;
+
+	apsd_result = smblib_update_usb_type(chg);
+
+	switch (apsd_result->bit) {
+	case SDP_CHARGER_BIT:
+	case CDP_CHARGER_BIT:
+		/* if not DCP then no hvdcp timeout happens. Enable pd here */
+		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+				false, 0);
+		if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+				|| chg->use_extcon)
+			smblib_notify_device_mode(chg, true);
+		break;
+	case OCP_CHARGER_BIT:
+	case FLOAT_CHARGER_BIT:
+		/* if not DCP then no hvdcp timeout happens, Enable pd here. */
+		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+				false, 0);
+		break;
+	case DCP_CHARGER_BIT:
+		break;
+	default:
+		break;
+	}
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
+		   apsd_result->name);
+}
+
+irqreturn_t usb_source_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc = 0;
+	u8 stat;
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		&& (stat & APSD_DTC_STATUS_DONE_BIT)
+		&& !chg->uusb_apsd_rerun_done) {
+		/*
+		 * Force re-run APSD to handle slow insertion related
+		 * charger-mis-detection.
+		 */
+		chg->uusb_apsd_rerun_done = true;
+		smblib_rerun_apsd(chg);
+		return IRQ_HANDLED;
+	}
+
+	smblib_handle_apsd_done(chg,
+		(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
+
+	smblib_handle_hvdcp_detect_done(chg,
+		(bool)(stat & QC_CHARGER_BIT));
+
+	smblib_handle_hvdcp_check_timeout(chg,
+		(bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
+		(bool)(stat & QC_CHARGER_BIT));
+
+	smblib_handle_hvdcp_3p0_auth_done(chg,
+		(bool)(stat & QC_AUTH_DONE_STATUS_BIT));
+
+	smblib_handle_sdp_enumeration_done(chg,
+		(bool)(stat & ENUMERATION_DONE_BIT));
+
+	smblib_handle_slow_plugin_timeout(chg,
+		(bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
+
+	smblib_hvdcp_adaptive_voltage_change(chg);
+
+	power_supply_changed(chg->usb_psy);
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+
+	return IRQ_HANDLED;
+}
+
+static void typec_sink_insertion(struct smb_charger *chg)
+{
+	/* when a sink is inserted we should not wait on hvdcp timeout to
+	 * enable pd
+	 */
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+	if (chg->use_extcon) {
+		smblib_notify_usb_host(chg, true);
+		chg->otg_present = true;
+	}
+}
+
+static void typec_sink_removal(struct smb_charger *chg)
+{
+	smblib_set_charge_param(chg, &chg->param.freq_switcher,
+			chg->chg_freq.freq_above_otg_threshold);
+	chg->boost_current_ua = 0;
+}
+
+static void smblib_handle_typec_removal(struct smb_charger *chg)
+{
+	int rc;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_request_dpdm(chg, false);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+
+	if (chg->wa_flags & BOOST_BACK_WA) {
+		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+		if (data) {
+			wdata = &data->storm_data;
+			update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					false, 0);
+		}
+	}
+
+	cancel_delayed_work_sync(&chg->pl_enable_work);
+
+	/* reset input current limit voters */
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+	vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+	vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+	vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+	vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
+
+	/* reset power delivery voters */
+	vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);
+
+	/* reset usb irq voters */
+	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+	vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
+
+	/* reset parallel voters */
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+	vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
+	chg->vconn_attempts = 0;
+	chg->otg_attempts = 0;
+	chg->pulse_cnt = 0;
+	chg->usb_icl_delta_ua = 0;
+	chg->voltage_min_uv = MICRO_5V;
+	chg->voltage_max_uv = MICRO_5V;
+	chg->pd_active = 0;
+	chg->pd_hard_reset = 0;
+
+	/* write back the default FLOAT charger configuration */
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				(u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
+			rc);
+
+	/* reset back to 103mS tCC debounce */
+	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
+					REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
+
+	/* reconfigure allowed voltage for HVDCP */
+	rc = smblib_set_adapter_allowance(chg,
+			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+			rc);
+
+	/* enable DRP */
+	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+	/* HW controlled CC_OUT */
+	rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+				TYPEC_CCOUT_SRC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_SRC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set TYPE_C_VCONN_CONTROL_REG rc=%d\n",
+				rc);
+
+	/* clear exit sink based on cc */
+	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+						EXIT_SNK_BASED_ON_CC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
+				rc);
+
+	typec_sink_removal(chg);
+	smblib_update_usb_type(chg);
+
+	if (chg->use_extcon) {
+		if (chg->otg_present)
+			smblib_notify_usb_host(chg, false);
+		else
+			smblib_notify_device_mode(chg, false);
+	}
+	chg->otg_present = false;
+}
+
+static void smblib_handle_typec_insertion(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+
+	if (stat & SNK_SRC_MODE_BIT) {
+		typec_sink_insertion(chg);
+	} else {
+		rc = smblib_request_dpdm(chg, true);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+		typec_sink_removal(chg);
+	}
+}
+
+static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
+{
+	int rp_ua;
+	const struct apsd_result *apsd = smblib_get_apsd_result(chg);
+
+	if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
+		&& (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
+		return;
+
+	/*
+	 * if APSD indicates FLOAT and the USB stack had detected SDP,
+	 * do not respond to Rp changes as we do not confirm that its
+	 * a legacy cable
+	 */
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+		return;
+	/*
+	 * We want the ICL vote @ 100mA for a FLOAT charger
+	 * until the detection by the USB stack is complete.
+	 * Ignore the Rp changes unless there is a
+	 * pre-existing valid vote.
+	 */
+	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+		get_client_vote(chg->usb_icl_votable,
+			LEGACY_UNKNOWN_VOTER) <= 100000)
+		return;
+
+	/*
+	 * handle Rp change for DCP/FLOAT/OCP.
+	 * Update the current only if the Rp is different from
+	 * the last Rp value.
+	 */
+	smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
+						chg->typec_mode, typec_mode);
+
+	rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
+}
+
+static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
+{
+	u8 stat;
+	int typec_mode, rc;
+
+	if (chg->pr_swap_in_progress)
+		return;
+
+	typec_mode = smblib_get_prop_typec_mode(chg);
+	if (chg->typec_present && (typec_mode != chg->typec_mode))
+		smblib_handle_rp_change(chg, typec_mode);
+
+	chg->typec_mode = typec_mode;
+
+	if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = true;
+		smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+			smblib_typec_mode_name[chg->typec_mode]);
+		smblib_handle_typec_insertion(chg);
+	} else if (chg->typec_present &&
+				chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = false;
+		smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+		smblib_handle_typec_removal(chg);
+	}
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+	/* suspend usb if sink */
+	if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
+		vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+	else
+		vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+				smblib_typec_mode_name[chg->typec_mode]);
+}
+
+static void smblib_usb_typec_change(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	smblib_handle_typec_cc_state_change(chg);
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+
+	if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
+		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
+
+	power_supply_changed(chg->usb_psy);
+}
+
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
+		cancel_delayed_work_sync(&chg->uusb_otg_work);
+		vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
+		smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
+		schedule_delayed_work(&chg->uusb_otg_work,
+				msecs_to_jiffies(chg->otg_delay_ms));
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			|| chg->pr_swap_in_progress) {
+		smblib_dbg(chg, PR_INTERRUPT,
+				"Ignoring since pr_swap_in_progress\n");
+		return IRQ_HANDLED;
+	}
+
+	mutex_lock(&chg->lock);
+	smblib_usb_typec_change(chg);
+	mutex_unlock(&chg->lock);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t dc_plugin_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	power_supply_changed(chg->dc_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t high_duty_cycle_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	chg->is_hdc = true;
+	/*
+	 * Disable usb IRQs after the flag set and re-enable IRQs after
+	 * the flag cleared in the delayed work queue, to avoid any IRQ
+	 * storming during the delays
+	 */
+	if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+
+	schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_bb_removal_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						bb_removal_work.work);
+
+	vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+	vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
+}
+
+#define BOOST_BACK_UNVOTE_DELAY_MS		750
+#define BOOST_BACK_STORM_COUNT			3
+#define WEAK_CHG_STORM_COUNT			8
+irqreturn_t switcher_power_ok_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	struct storm_watch *wdata = &irq_data->storm_data;
+	int rc, usb_icl;
+	u8 stat;
+
+	if (!(chg->wa_flags & BOOST_BACK_WA))
+		return IRQ_HANDLED;
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	/* skip suspending input if its already suspended by some other voter */
+	usb_icl = get_effective_result(chg->usb_icl_votable);
+	if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
+		return IRQ_HANDLED;
+
+	if (stat & USE_DCIN_BIT)
+		return IRQ_HANDLED;
+
+	if (is_storming(&irq_data->storm_data)) {
+		/* This could be a weak charger reduce ICL */
+		if (!is_client_vote_enabled(chg->usb_icl_votable,
+						WEAK_CHARGER_VOTER)) {
+			smblib_err(chg,
+				"Weak charger detected: voting %dmA ICL\n",
+				*chg->weak_chg_icl_ua / 1000);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					true, *chg->weak_chg_icl_ua);
+			/*
+			 * reset storm data and set the storm threshold
+			 * to 3 for reverse boost detection.
+			 */
+			update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
+		} else {
+			smblib_err(chg,
+				"Reverse boost detected: voting 0mA to suspend input\n");
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
+			vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
+			/*
+			 * Remove the boost-back vote after a delay, to avoid
+			 * permanently suspending the input if the boost-back
+			 * condition is unintentionally hit.
+			 */
+			schedule_delayed_work(&chg->bb_removal_work,
+				msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t wdog_bark_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+	rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
+
+	if (chg->step_chg_enabled || chg->sw_jeita_enabled)
+		power_supply_changed(chg->batt_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**************
+ * Additional USB PSY getters/setters
+ * that call interrupt functions
+ ***************/
+
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->pr_swap_in_progress;
+	return 0;
+}
+
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc;
+
+	chg->pr_swap_in_progress = val->intval;
+
+	/*
+	 * call the cc changed irq to handle real removals while
+	 * PR_SWAP was in progress
+	 */
+	smblib_usb_typec_change(chg);
+	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
+			REDUCE_TCCDEBOUNCE_TO_2MS_BIT,
+			val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+	return 0;
+}
+
+/***************
+ * Work Queues *
+ ***************/
+static void smblib_uusb_otg_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						uusb_otg_work.work);
+	int rc;
+	u8 stat;
+	bool otg;
+
+	rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
+		goto out;
+	}
+	otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
+	if (chg->otg_present != otg)
+		smblib_notify_usb_host(chg, otg);
+	chg->otg_present = otg;
+	if (!otg)
+		chg->boost_current_ua = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+				otg ? chg->chg_freq.freq_below_otg_threshold
+					: chg->chg_freq.freq_removal);
+	if (rc < 0)
+		dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_U_USB_STATUS = 0x%02x OTG=%d\n",
+			stat, otg);
+	power_supply_changed(chg->usb_psy);
+
+out:
+	vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
+}
+
+static void bms_update_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						bms_update_work);
+
+	smblib_suspend_on_debug_battery(chg);
+
+	if (chg->batt_psy)
+		power_supply_changed(chg->batt_psy);
+}
+
+static void pl_update_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						pl_update_work);
+
+	smblib_stat_sw_override_cfg(chg, false);
+}
+
+static void clear_hdc_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						clear_hdc_work.work);
+
+	chg->is_hdc = 0;
+	if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+}
+
+static void smblib_icl_change_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+							icl_change_work.work);
+	int rc, settled_ua;
+
+	rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
+		return;
+	}
+
+	power_supply_changed(chg->usb_main_psy);
+
+	smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
+}
+
+static void smblib_pl_enable_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+							pl_enable_work.work);
+
+	smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+}
+
+static int smblib_create_votables(struct smb_charger *chg)
+{
+	int rc = 0;
+
+	chg->fcc_votable = find_votable("FCC");
+	if (chg->fcc_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->fv_votable = find_votable("FV");
+	if (chg->fv_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->usb_icl_votable = find_votable("USB_ICL");
+	if (chg->usb_icl_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->pl_disable_votable = find_votable("PL_DISABLE");
+	if (chg->pl_disable_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
+	if (chg->pl_enable_votable_indirect == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg,
+			"Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+
+	chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
+					smblib_dc_suspend_vote_callback,
+					chg);
+	if (IS_ERR(chg->dc_suspend_votable)) {
+		rc = PTR_ERR(chg->dc_suspend_votable);
+		chg->dc_suspend_votable = NULL;
+		return rc;
+	}
+
+	chg->pd_disallowed_votable_indirect
+		= create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
+			smblib_pd_disallowed_votable_indirect_callback, chg);
+	if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
+		rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
+		chg->pd_disallowed_votable_indirect = NULL;
+		return rc;
+	}
+
+	chg->pd_allowed_votable = create_votable("PD_ALLOWED",
+					VOTE_SET_ANY, NULL, NULL);
+	if (IS_ERR(chg->pd_allowed_votable)) {
+		rc = PTR_ERR(chg->pd_allowed_votable);
+		chg->pd_allowed_votable = NULL;
+		return rc;
+	}
+
+	chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
+					smblib_awake_vote_callback,
+					chg);
+	if (IS_ERR(chg->awake_votable)) {
+		rc = PTR_ERR(chg->awake_votable);
+		chg->awake_votable = NULL;
+		return rc;
+	}
+
+	chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
+					smblib_chg_disable_vote_callback,
+					chg);
+	if (IS_ERR(chg->chg_disable_votable)) {
+		rc = PTR_ERR(chg->chg_disable_votable);
+		chg->chg_disable_votable = NULL;
+		return rc;
+	}
+
+	chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
+					VOTE_SET_ANY,
+					smblib_usb_irq_enable_vote_callback,
+					chg);
+	if (IS_ERR(chg->usb_irq_enable_votable)) {
+		rc = PTR_ERR(chg->usb_irq_enable_votable);
+		chg->usb_irq_enable_votable = NULL;
+		return rc;
+	}
+
+	return rc;
+}
+
+static void smblib_destroy_votables(struct smb_charger *chg)
+{
+	if (chg->dc_suspend_votable)
+		destroy_votable(chg->dc_suspend_votable);
+	if (chg->usb_icl_votable)
+		destroy_votable(chg->usb_icl_votable);
+	if (chg->pd_disallowed_votable_indirect)
+		destroy_votable(chg->pd_disallowed_votable_indirect);
+	if (chg->pd_allowed_votable)
+		destroy_votable(chg->pd_allowed_votable);
+	if (chg->awake_votable)
+		destroy_votable(chg->awake_votable);
+	if (chg->chg_disable_votable)
+		destroy_votable(chg->chg_disable_votable);
+}
+
+int smblib_init(struct smb_charger *chg)
+{
+	int rc = 0;
+
+	mutex_init(&chg->lock);
+	mutex_init(&chg->otg_oc_lock);
+	INIT_WORK(&chg->bms_update_work, bms_update_work);
+	INIT_WORK(&chg->pl_update_work, pl_update_work);
+	INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
+	INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
+	INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+	INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
+	INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
+	chg->fake_capacity = -EINVAL;
+	chg->fake_input_current_limited = -EINVAL;
+	chg->fake_batt_status = -EINVAL;
+
+	switch (chg->mode) {
+	case PARALLEL_MASTER:
+		rc = qcom_batt_init();
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
+						chg->sw_jeita_enabled);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		rc = smblib_create_votables(chg);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't create votables rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		chg->bms_psy = power_supply_get_by_name("bms");
+		chg->pl.psy = power_supply_get_by_name("parallel");
+		if (chg->pl.psy) {
+			rc = smblib_stat_sw_override_cfg(chg, false);
+			if (rc < 0) {
+				smblib_err(chg,
+					"Couldn't config stat sw rc=%d\n", rc);
+				return rc;
+			}
+		}
+		rc = smblib_register_notifier(chg);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't register notifier rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case PARALLEL_SLAVE:
+		break;
+	default:
+		smblib_err(chg, "Unsupported mode %d\n", chg->mode);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int smblib_deinit(struct smb_charger *chg)
+{
+	switch (chg->mode) {
+	case PARALLEL_MASTER:
+		cancel_work_sync(&chg->bms_update_work);
+		cancel_work_sync(&chg->pl_update_work);
+		cancel_delayed_work_sync(&chg->clear_hdc_work);
+		cancel_delayed_work_sync(&chg->icl_change_work);
+		cancel_delayed_work_sync(&chg->pl_enable_work);
+		cancel_delayed_work_sync(&chg->uusb_otg_work);
+		cancel_delayed_work_sync(&chg->bb_removal_work);
+		power_supply_unreg_notifier(&chg->nb);
+		smblib_destroy_votables(chg);
+		qcom_step_chg_deinit();
+		qcom_batt_deinit();
+		break;
+	case PARALLEL_SLAVE:
+		break;
+	default:
+		smblib_err(chg, "Unsupported mode %d\n", chg->mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
new file mode 100644
index 0000000..335764e
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -0,0 +1,529 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SMB5_CHARGER_H
+#define __SMB5_CHARGER_H
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/consumer.h>
+#include <linux/extcon.h>
+#include "storm-watch.h"
+
+enum print_reason {
+	PR_INTERRUPT	= BIT(0),
+	PR_REGISTER	= BIT(1),
+	PR_MISC		= BIT(2),
+	PR_PARALLEL	= BIT(3),
+	PR_OTG		= BIT(4),
+};
+
+#define DEFAULT_VOTER			"DEFAULT_VOTER"
+#define USER_VOTER			"USER_VOTER"
+#define PD_VOTER			"PD_VOTER"
+#define DCP_VOTER			"DCP_VOTER"
+#define QC_VOTER			"QC_VOTER"
+#define PL_USBIN_USBIN_VOTER		"PL_USBIN_USBIN_VOTER"
+#define USB_PSY_VOTER			"USB_PSY_VOTER"
+#define PL_TAPER_WORK_RUNNING_VOTER	"PL_TAPER_WORK_RUNNING_VOTER"
+#define PL_QNOVO_VOTER			"PL_QNOVO_VOTER"
+#define USBIN_V_VOTER			"USBIN_V_VOTER"
+#define CHG_STATE_VOTER			"CHG_STATE_VOTER"
+#define TYPEC_SRC_VOTER			"TYPEC_SRC_VOTER"
+#define TAPER_END_VOTER			"TAPER_END_VOTER"
+#define THERMAL_DAEMON_VOTER		"THERMAL_DAEMON_VOTER"
+#define CC_DETACHED_VOTER		"CC_DETACHED_VOTER"
+#define APSD_VOTER			"APSD_VOTER"
+#define PD_DISALLOWED_INDIRECT_VOTER	"PD_DISALLOWED_INDIRECT_VOTER"
+#define VBUS_CC_SHORT_VOTER		"VBUS_CC_SHORT_VOTER"
+#define PD_INACTIVE_VOTER		"PD_INACTIVE_VOTER"
+#define BOOST_BACK_VOTER		"BOOST_BACK_VOTER"
+#define USBIN_USBIN_BOOST_VOTER		"USBIN_USBIN_BOOST_VOTER"
+#define MICRO_USB_VOTER			"MICRO_USB_VOTER"
+#define DEBUG_BOARD_VOTER		"DEBUG_BOARD_VOTER"
+#define PD_SUSPEND_SUPPORTED_VOTER	"PD_SUSPEND_SUPPORTED_VOTER"
+#define PL_DELAY_VOTER			"PL_DELAY_VOTER"
+#define CTM_VOTER			"CTM_VOTER"
+#define SW_QC3_VOTER			"SW_QC3_VOTER"
+#define AICL_RERUN_VOTER		"AICL_RERUN_VOTER"
+#define LEGACY_UNKNOWN_VOTER		"LEGACY_UNKNOWN_VOTER"
+#define QNOVO_VOTER			"QNOVO_VOTER"
+#define BATT_PROFILE_VOTER		"BATT_PROFILE_VOTER"
+#define OTG_DELAY_VOTER			"OTG_DELAY_VOTER"
+#define USBIN_I_VOTER			"USBIN_I_VOTER"
+#define WEAK_CHARGER_VOTER		"WEAK_CHARGER_VOTER"
+#define OTG_VOTER			"OTG_VOTER"
+#define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
+#define WBC_VOTER			"WBC_VOTER"
+#define HW_LIMIT_VOTER			"HW_LIMIT_VOTER"
+
+#define BOOST_BACK_STORM_COUNT	3
+#define WEAK_CHG_STORM_COUNT	8
+
+#define VBAT_TO_VRAW_ADC(v)		div_u64((u64)v * 1000000UL, 194637UL)
+
+enum smb_mode {
+	PARALLEL_MASTER = 0,
+	PARALLEL_SLAVE,
+	NUM_MODES,
+};
+
+enum {
+	BOOST_BACK_WA			= BIT(0),
+};
+
+enum smb_irq_index {
+	/* CHGR */
+	CHGR_ERROR_IRQ = 0,
+	CHG_STATE_CHANGE_IRQ,
+	STEP_CHG_STATE_CHANGE_IRQ,
+	STEP_CHG_SOC_UPDATE_FAIL_IRQ,
+	STEP_CHG_SOC_UPDATE_REQ_IRQ,
+	FG_FVCAL_QUALIFIED_IRQ,
+	VPH_ALARM_IRQ,
+	VPH_DROP_PRECHG_IRQ,
+	/* DCDC */
+	OTG_FAIL_IRQ,
+	OTG_OC_DISABLE_SW_IRQ,
+	OTG_OC_HICCUP_IRQ,
+	BSM_ACTIVE_IRQ,
+	HIGH_DUTY_CYCLE_IRQ,
+	INPUT_CURRENT_LIMITING_IRQ,
+	CONCURRENT_MODE_DISABLE_IRQ,
+	SWITCHER_POWER_OK_IRQ,
+	/* BATIF */
+	BAT_TEMP_IRQ,
+	ALL_CHNL_CONV_DONE_IRQ,
+	BAT_OV_IRQ,
+	BAT_LOW_IRQ,
+	BAT_THERM_OR_ID_MISSING_IRQ,
+	BAT_TERMINAL_MISSING_IRQ,
+	BUCK_OC_IRQ,
+	VPH_OV_IRQ,
+	/* USB */
+	USBIN_COLLAPSE_IRQ,
+	USBIN_VASHDN_IRQ,
+	USBIN_UV_IRQ,
+	USBIN_OV_IRQ,
+	USBIN_PLUGIN_IRQ,
+	USBIN_REVI_CHANGE_IRQ,
+	USBIN_SRC_CHANGE_IRQ,
+	USBIN_ICL_CHANGE_IRQ,
+	/* DC */
+	DCIN_VASHDN_IRQ,
+	DCIN_UV_IRQ,
+	DCIN_OV_IRQ,
+	DCIN_PLUGIN_IRQ,
+	DCIN_REVI_IRQ,
+	DCIN_PON_IRQ,
+	DCIN_EN_IRQ,
+	/* TYPEC */
+	TYPEC_OR_RID_DETECTION_CHANGE_IRQ,
+	TYPEC_VPD_DETECT_IRQ,
+	TYPEC_CC_STATE_CHANGE_IRQ,
+	TYPEC_VCONN_OC_IRQ,
+	TYPEC_VBUS_CHANGE_IRQ,
+	TYPEC_ATTACH_DETACH_IRQ,
+	TYPEC_LEGACY_CABLE_DETECT_IRQ,
+	TYPEC_TRY_SNK_SRC_DETECT_IRQ,
+	/* MISC */
+	WDOG_SNARL_IRQ,
+	WDOG_BARK_IRQ,
+	AICL_FAIL_IRQ,
+	AICL_DONE_IRQ,
+	SMB_EN_IRQ,
+	IMP_TRIGGER_IRQ,
+	TEMP_CHANGE_IRQ,
+	TEMP_CHANGE_SMB_IRQ,
+	/* FLASH */
+	VREG_OK_IRQ,
+	ILIM_S2_IRQ,
+	ILIM_S1_IRQ,
+	VOUT_DOWN_IRQ,
+	VOUT_UP_IRQ,
+	FLASH_STATE_CHANGE_IRQ,
+	TORCH_REQ_IRQ,
+	FLASH_EN_IRQ,
+	/* END */
+	SMB_IRQ_MAX,
+};
+
+enum float_options {
+	FLOAT_DCP		= 1,
+	FLOAT_SDP		= 2,
+	DISABLE_CHARGING	= 3,
+	SUSPEND_INPUT		= 4,
+};
+
+struct smb_irq_info {
+	const char			*name;
+	const irq_handler_t		handler;
+	const bool			wake;
+	const struct storm_watch	storm_data;
+	struct smb_irq_data		*irq_data;
+	int				irq;
+};
+
+static const unsigned int smblib_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_NONE,
+};
+
+/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
+static const u32 smblib_extcon_exclusive[] = {0x3, 0};
+
+struct smb_regulator {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	rdesc;
+};
+
+struct smb_irq_data {
+	void			*parent_data;
+	const char		*name;
+	struct storm_watch	storm_data;
+};
+
+struct smb_chg_param {
+	const char	*name;
+	u16		reg;
+	int		min_u;
+	int		max_u;
+	int		step_u;
+	int		(*get_proc)(struct smb_chg_param *param,
+				    u8 val_raw);
+	int		(*set_proc)(struct smb_chg_param *param,
+				    int val_u,
+				    u8 *val_raw);
+};
+
+struct buck_boost_freq {
+	int freq_khz;
+	u8 val;
+};
+
+struct smb_chg_freq {
+	unsigned int		freq_5V;
+	unsigned int		freq_6V_8V;
+	unsigned int		freq_9V;
+	unsigned int		freq_12V;
+	unsigned int		freq_removal;
+	unsigned int		freq_below_otg_threshold;
+	unsigned int		freq_above_otg_threshold;
+};
+
+struct smb_params {
+	struct smb_chg_param	fcc;
+	struct smb_chg_param	fv;
+	struct smb_chg_param	usb_icl;
+	struct smb_chg_param	icl_stat;
+	struct smb_chg_param	otg_cl;
+	struct smb_chg_param	jeita_cc_comp_hot;
+	struct smb_chg_param	jeita_cc_comp_cold;
+	struct smb_chg_param	freq_switcher;
+};
+
+struct parallel_params {
+	struct power_supply	*psy;
+};
+
+struct smb_iio {
+	struct iio_channel	*temp_chan;
+	struct iio_channel	*temp_max_chan;
+	struct iio_channel	*usbin_i_chan;
+	struct iio_channel	*usbin_v_chan;
+	struct iio_channel	*batt_i_chan;
+	struct iio_channel	*connector_temp_chan;
+	struct iio_channel	*connector_temp_thr1_chan;
+	struct iio_channel	*connector_temp_thr2_chan;
+	struct iio_channel	*connector_temp_thr3_chan;
+};
+
+struct smb_charger {
+	struct device		*dev;
+	char			*name;
+	struct regmap		*regmap;
+	struct smb_irq_info	*irq_info;
+	struct smb_params	param;
+	struct smb_iio		iio;
+	int			*debug_mask;
+	enum smb_mode		mode;
+	struct smb_chg_freq	chg_freq;
+	int			smb_version;
+	int			otg_delay_ms;
+	int			*weak_chg_icl_ua;
+
+	/* locks */
+	struct mutex		lock;
+	struct mutex		ps_change_lock;
+	struct mutex		otg_oc_lock;
+
+	/* power supplies */
+	struct power_supply		*batt_psy;
+	struct power_supply		*usb_psy;
+	struct power_supply		*dc_psy;
+	struct power_supply		*bms_psy;
+	struct power_supply		*usb_main_psy;
+	struct power_supply		*usb_port_psy;
+	enum power_supply_type		real_charger_type;
+
+	/* notifiers */
+	struct notifier_block	nb;
+
+	/* parallel charging */
+	struct parallel_params	pl;
+
+	/* regulators */
+	struct smb_regulator	*vbus_vreg;
+	struct smb_regulator	*vconn_vreg;
+	struct regulator	*dpdm_reg;
+
+	/* votables */
+	struct votable		*dc_suspend_votable;
+	struct votable		*fcc_votable;
+	struct votable		*fv_votable;
+	struct votable		*usb_icl_votable;
+	struct votable		*pd_disallowed_votable_indirect;
+	struct votable		*pd_allowed_votable;
+	struct votable		*awake_votable;
+	struct votable		*pl_disable_votable;
+	struct votable		*chg_disable_votable;
+	struct votable		*pl_enable_votable_indirect;
+	struct votable		*usb_irq_enable_votable;
+
+	/* work */
+	struct work_struct	bms_update_work;
+	struct work_struct	pl_update_work;
+	struct delayed_work	ps_change_timeout_work;
+	struct delayed_work	clear_hdc_work;
+	struct delayed_work	icl_change_work;
+	struct delayed_work	pl_enable_work;
+	struct delayed_work	uusb_otg_work;
+	struct delayed_work	bb_removal_work;
+
+	/* cached status */
+	int			voltage_min_uv;
+	int			voltage_max_uv;
+	int			pd_active;
+	bool			system_suspend_supported;
+	int			boost_threshold_ua;
+	int			system_temp_level;
+	int			thermal_levels;
+	int			*thermal_mitigation;
+	int			dcp_icl_ua;
+	int			fake_capacity;
+	int			fake_batt_status;
+	bool			step_chg_enabled;
+	bool			sw_jeita_enabled;
+	bool			is_hdc;
+	bool			chg_done;
+	int			connector_type;
+	bool			otg_en;
+	bool			suspend_input_on_debug_batt;
+	int			otg_attempts;
+	int			vconn_attempts;
+	int			default_icl_ua;
+	int			otg_cl_ua;
+	bool			uusb_apsd_rerun_done;
+	bool			pd_hard_reset;
+	bool			typec_present;
+	int			fake_input_current_limited;
+	bool			pr_swap_in_progress;
+	int			typec_mode;
+	int			usb_icl_change_irq_enabled;
+	u32			jeita_status;
+	u8			float_cfg;
+	bool			use_extcon;
+	bool			otg_present;
+	int			hw_max_icl_ua;
+	int			auto_recharge_soc;
+
+	/* workaround flag */
+	u32			wa_flags;
+	int			boost_current_ua;
+
+	/* extcon for VBUS / ID notification to USB for uUSB */
+	struct extcon_dev	*extcon;
+
+	/* battery profile */
+	int			batt_profile_fcc_ua;
+	int			batt_profile_fv_uv;
+
+	int			usb_icl_delta_ua;
+	int			pulse_cnt;
+
+	int			die_health;
+
+	/* flash */
+	u32			flash_derating_soc;
+	u32			flash_disable_soc;
+	u32			headroom_mode;
+	bool			flash_init_done;
+	bool			flash_active;
+};
+
+int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
+int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val);
+int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val, int count);
+int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val, int count);
+
+int smblib_get_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int *val_u);
+int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend);
+
+int smblib_enable_charging(struct smb_charger *chg, bool enable);
+int smblib_set_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int val_u);
+int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend);
+int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend);
+
+int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw);
+int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
+					   u8 val_raw);
+int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw);
+int smblib_set_chg_freq(struct smb_chg_param *param,
+				int val_u, u8 *val_raw);
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
+int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
+int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);
+
+int smblib_vconn_regulator_enable(struct regulator_dev *rdev);
+int smblib_vconn_regulator_disable(struct regulator_dev *rdev);
+int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev);
+
+irqreturn_t default_irq_handler(int irq, void *data);
+irqreturn_t chg_state_change_irq_handler(int irq, void *data);
+irqreturn_t batt_temp_changed_irq_handler(int irq, void *data);
+irqreturn_t batt_psy_changed_irq_handler(int irq, void *data);
+irqreturn_t usbin_uv_irq_handler(int irq, void *data);
+irqreturn_t usb_plugin_irq_handler(int irq, void *data);
+irqreturn_t usb_source_change_irq_handler(int irq, void *data);
+irqreturn_t icl_change_irq_handler(int irq, void *data);
+irqreturn_t typec_state_change_irq_handler(int irq, void *data);
+irqreturn_t dc_plugin_irq_handler(int irq, void *data);
+irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
+irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
+irqreturn_t wdog_bark_irq_handler(int irq, void *data);
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
+
+int smblib_get_prop_input_suspend(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_capacity(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_status(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_health(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_system_temp_level(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_current_now(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_temp(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_input_suspend(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_batt_capacity(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_system_temp_level(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+				const union power_supply_propval *val);
+
+int smblib_get_prop_dc_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_dc_online(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_dc_current_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_dc_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_get_prop_usb_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_online(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_suspend(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_typec_power_role(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_pd_allowed(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_current_settled(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_get_pe_start(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_get_prop_die_health(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_typec_power_role(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_ship_mode(struct smb_charger *chg,
+				const union power_supply_propval *val);
+void smblib_suspend_on_debug_battery(struct smb_charger *chg);
+int smblib_rerun_apsd_if_required(struct smb_charger *chg);
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_dp_dm(struct smb_charger *chg, int val);
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
+int smblib_rerun_aicl(struct smb_charger *chg);
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
+int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);
+
+int smblib_init(struct smb_charger *chg);
+int smblib_deinit(struct smb_charger *chg);
+#endif /* __SMB5_CHARGER_H */
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
new file mode 100644
index 0000000..afc45ab
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -0,0 +1,362 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SMB5_CHARGER_REG_H
+#define __SMB5_CHARGER_REG_H
+
+#include <linux/bitops.h>
+
+#define CHGR_BASE	0x1000
+#define DCDC_BASE	0x1100
+#define BATIF_BASE	0x1200
+#define USBIN_BASE	0x1300
+#define DCIN_BASE	0x1400
+#define TYPEC_BASE	0X1500
+#define MISC_BASE	0x1600
+
+#define PERPH_TYPE_OFFSET	0x04
+#define TYPE_MASK		GENMASK(7, 0)
+#define PERPH_SUBTYPE_OFFSET	0x05
+#define SUBTYPE_MASK		GENMASK(7, 0)
+#define INT_RT_STS_OFFSET	0x10
+
+/********************************
+ *  CHGR Peripheral Registers  *
+ ********************************/
+#define BATTERY_CHARGER_STATUS_1_REG		(CHGR_BASE + 0x06)
+#define BATTERY_CHARGER_STATUS_MASK		GENMASK(2, 0)
+enum {
+	INHIBIT_CHARGE = 0,
+	TRICKLE_CHARGE,
+	PRE_CHARGE,
+	FULLON_CHARGE,
+	TAPER_CHARGE,
+	TERMINATE_CHARGE,
+	PAUSE_CHARGE,
+	DISABLE_CHARGE,
+};
+
+#define BATTERY_CHARGER_STATUS_2_REG		(CHGR_BASE + 0x07)
+#define CHARGER_ERROR_STATUS_BAT_OV_BIT		BIT(1)
+
+#define BATTERY_CHARGER_STATUS_5_REG		(CHGR_BASE + 0x0B)
+#define ENABLE_TRICKLE_BIT			BIT(2)
+#define ENABLE_PRE_CHARGING_BIT			BIT(1)
+#define ENABLE_FULLON_MODE_BIT			BIT(0)
+
+#define BATTERY_CHARGER_STATUS_7_REG		(CHGR_BASE + 0x0D)
+#define BAT_TEMP_STATUS_SOFT_LIMIT_MASK		GENMASK(5, 4)
+#define BAT_TEMP_STATUS_HOT_SOFT_BIT		BIT(5)
+#define BAT_TEMP_STATUS_COLD_SOFT_BIT		BIT(4)
+#define BAT_TEMP_STATUS_TOO_HOT_BIT		BIT(3)
+#define BAT_TEMP_STATUS_TOO_COLD_BIT		BIT(2)
+#define BAT_TEMP_STATUS_TOO_HOT_AFP_BIT		BIT(1)
+#define BAT_TEMP_STATUS_TOO_COLD_AFP_BIT	BIT(0)
+
+#define CHARGING_ENABLE_CMD_REG			(CHGR_BASE + 0x42)
+#define CHARGING_ENABLE_CMD_BIT			BIT(0)
+
+#define CHGR_CFG2_REG				(CHGR_BASE + 0x51)
+#define RECHG_MASK				GENMASK(2, 1)
+#define VBAT_BASED_RECHG_BIT			BIT(2)
+#define SOC_BASED_RECHG_BIT			GENMASK(2, 1)
+#define CHARGER_INHIBIT_BIT			BIT(0)
+
+#define CHGR_FAST_CHARGE_CURRENT_CFG_REG	(CHGR_BASE + 0x61)
+
+#define CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG	(CHGR_BASE + 0x6B)
+#define NO_OF_SAMPLE_FOR_RCHG_SHIFT		2
+#define NO_OF_SAMPLE_FOR_RCHG			GENMASK(3, 2)
+
+#define CHGR_FLOAT_VOLTAGE_CFG_REG		(CHGR_BASE + 0x70)
+
+#define CHARGE_INHIBIT_THRESHOLD_CFG_REG	(CHGR_BASE + 0x72)
+#define CHARGE_INHIBIT_THRESHOLD_MASK		GENMASK(1, 0)
+#define INHIBIT_ANALOG_VFLT_MINUS_50MV		0
+#define INHIBIT_ANALOG_VFLT_MINUS_100MV		1
+#define INHIBIT_ANALOG_VFLT_MINUS_200MV		2
+#define INHIBIT_ANALOG_VFLT_MINUS_300MV		3
+
+#define CHARGE_RCHG_SOC_THRESHOLD_CFG_REG	(CHGR_BASE + 0x7D)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG	(CHGR_BASE + 0x7E)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_LSB_REG	(CHGR_BASE + 0x7F)
+
+#define JEITA_EN_CFG_REG			(CHGR_BASE + 0x90)
+#define JEITA_EN_HOT_SL_FCV_BIT			BIT(3)
+#define JEITA_EN_COLD_SL_FCV_BIT		BIT(2)
+#define JEITA_EN_HOT_SL_CCC_BIT			BIT(1)
+#define JEITA_EN_COLD_SL_CCC_BIT		BIT(0)
+
+#define JEITA_CCCOMP_CFG_HOT_REG		(CHGR_BASE + 0x92)
+#define JEITA_CCCOMP_CFG_COLD_REG		(CHGR_BASE + 0x93)
+
+/********************************
+ *  DCDC Peripheral Registers  *
+ ********************************/
+#define AICL_ICL_STATUS_REG			(DCDC_BASE + 0x08)
+
+#define AICL_STATUS_REG				(DCDC_BASE + 0x0A)
+#define SOFT_ILIMIT_BIT				BIT(6)
+#define AICL_DONE_BIT				BIT(0)
+
+#define POWER_PATH_STATUS_REG			(DCDC_BASE + 0x0B)
+#define USBIN_SUSPEND_STS_BIT			BIT(6)
+#define USE_USBIN_BIT				BIT(4)
+#define USE_DCIN_BIT				BIT(3)
+#define VALID_INPUT_POWER_SOURCE_STS_BIT	BIT(0)
+
+#define DCDC_CMD_OTG_REG			(DCDC_BASE + 0x40)
+#define OTG_EN_BIT				BIT(0)
+
+#define DCDC_FSW_SEL_REG			(DCDC_BASE + 0x50)
+
+#define DCDC_OTG_CURRENT_LIMIT_CFG_REG		(DCDC_BASE + 0x52)
+
+#define DCDC_OTG_CFG_REG			(DCDC_BASE + 0x53)
+#define OTG_EN_SRC_CFG_BIT			BIT(1)
+
+/********************************
+ *  BATIF Peripheral Registers  *
+ ********************************/
+
+/* BATIF Interrupt Bits	 */
+#define VPH_OV_RT_STS_BIT			BIT(7)
+#define BUCK_OC_RT_STS_BIT			BIT(6)
+#define BAT_TERMINAL_MISSING_RT_STS_BIT		BIT(5)
+#define BAT_THERM_OR_ID_MISSING_RT_STS_BIT      BIT(4)
+#define BAT_LOW_RT_STS_BIT			BIT(3)
+#define BAT_OV_RT_STS_BIT			BIT(2)
+#define ALL_CHNL_CONV_DONE_RT_STS		BIT(1)
+#define BAT_TEMP_RT_STS_BIT			BIT(0)
+
+#define SHIP_MODE_REG				(BATIF_BASE + 0x40)
+#define SHIP_MODE_EN_BIT			BIT(0)
+
+/********************************
+ *  USBIN Peripheral Registers  *
+ ********************************/
+#define APSD_STATUS_REG				(USBIN_BASE + 0x07)
+#define APSD_STATUS_7_BIT			BIT(7)
+#define HVDCP_CHECK_TIMEOUT_BIT			BIT(6)
+#define SLOW_PLUGIN_TIMEOUT_BIT			BIT(5)
+#define ENUMERATION_DONE_BIT			BIT(4)
+#define VADP_CHANGE_DONE_AFTER_AUTH_BIT		BIT(3)
+#define QC_AUTH_DONE_STATUS_BIT			BIT(2)
+#define QC_CHARGER_BIT				BIT(1)
+#define APSD_DTC_STATUS_DONE_BIT		BIT(0)
+
+#define APSD_RESULT_STATUS_REG			(USBIN_BASE + 0x08)
+#define APSD_RESULT_STATUS_7_BIT		BIT(7)
+#define APSD_RESULT_STATUS_MASK			GENMASK(6, 0)
+#define QC_3P0_BIT				BIT(6)
+#define QC_2P0_BIT				BIT(5)
+#define FLOAT_CHARGER_BIT			BIT(4)
+#define DCP_CHARGER_BIT				BIT(3)
+#define CDP_CHARGER_BIT				BIT(2)
+#define OCP_CHARGER_BIT				BIT(1)
+#define SDP_CHARGER_BIT				BIT(0)
+
+#define QC_CHANGE_STATUS_REG			(USBIN_BASE + 0x09)
+#define QC_12V_BIT				BIT(2)
+#define QC_9V_BIT				BIT(1)
+#define QC_5V_BIT				BIT(0)
+#define QC_2P0_STATUS_MASK			GENMASK(2, 0)
+
+/* USBIN Interrupt Bits */
+#define USBIN_ICL_CHANGE_RT_STS_BIT		BIT(7)
+#define USBIN_SOURCE_CHANGE_RT_STS_BIT		BIT(6)
+#define USBIN_REVI_RT_STS_BIT			BIT(5)
+#define USBIN_PLUGIN_RT_STS_BIT			BIT(4)
+#define USBIN_OV_RT_STS_BIT			BIT(3)
+#define USBIN_UV_RT_STS_BIT			BIT(2)
+#define USBIN_VASHDN_RT_STS_BIT			BIT(1)
+#define USBIN_COLLAPSE_RT_STS_BIT		BIT(0)
+
+#define USBIN_CMD_IL_REG			(USBIN_BASE + 0x40)
+#define USBIN_SUSPEND_BIT			BIT(0)
+
+#define CMD_APSD_REG				(USBIN_BASE + 0x41)
+#define APSD_RERUN_BIT				BIT(0)
+
+#define CMD_HVDCP_2_REG				(USBIN_BASE + 0x43)
+#define FORCE_12V_BIT				BIT(5)
+#define FORCE_9V_BIT				BIT(4)
+#define FORCE_5V_BIT				BIT(3)
+#define SINGLE_DECREMENT_BIT			BIT(1)
+#define SINGLE_INCREMENT_BIT			BIT(0)
+
+#define USBIN_ADAPTER_ALLOW_CFG_REG		(USBIN_BASE + 0x60)
+enum {
+	USBIN_ADAPTER_ALLOW_5V		= 0,
+	USBIN_ADAPTER_ALLOW_9V		= 2,
+	USBIN_ADAPTER_ALLOW_5V_OR_9V	= 3,
+	USBIN_ADAPTER_ALLOW_12V		= 4,
+	USBIN_ADAPTER_ALLOW_5V_OR_12V	= 5,
+	USBIN_ADAPTER_ALLOW_9V_TO_12V	= 6,
+	USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7,
+	USBIN_ADAPTER_ALLOW_5V_TO_9V	= 8,
+	USBIN_ADAPTER_ALLOW_5V_TO_12V	= 12,
+};
+
+#define USBIN_OPTIONS_1_CFG_REG			(USBIN_BASE + 0x62)
+#define HVDCP_AUTH_ALG_EN_CFG_BIT		BIT(6)
+#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT	BIT(5)
+#define BC1P2_SRC_DETECT_BIT			BIT(3)
+
+#define USBIN_OPTIONS_2_CFG_REG			(USBIN_BASE + 0x63)
+#define FLOAT_OPTIONS_MASK			GENMASK(2, 0)
+#define FLOAT_DIS_CHGING_CFG_BIT		BIT(2)
+#define SUSPEND_FLOAT_CFG_BIT			BIT(1)
+#define FORCE_FLOAT_SDP_CFG_BIT			BIT(0)
+
+#define USBIN_LOAD_CFG_REG			(USBIN_BASE + 0x65)
+#define ICL_OVERRIDE_AFTER_APSD_BIT		BIT(4)
+
+#define USBIN_ICL_OPTIONS_REG			(USBIN_BASE + 0x66)
+#define CFG_USB3P0_SEL_BIT			BIT(2)
+#define	USB51_MODE_BIT				BIT(1)
+#define USBIN_MODE_CHG_BIT			BIT(0)
+
+#define USBIN_CURRENT_LIMIT_CFG_REG		(USBIN_BASE + 0x70)
+
+#define USBIN_AICL_OPTIONS_CFG_REG		(USBIN_BASE + 0x80)
+#define USBIN_AICL_ADC_EN_BIT			BIT(3)
+
+/********************************
+ *  DCIN Peripheral Registers   *
+ ********************************/
+
+/* DCIN Interrupt Bits */
+#define DCIN_PLUGIN_RT_STS_BIT			BIT(4)
+
+#define DCIN_CMD_IL_REG				(DCIN_BASE + 0x40)
+#define DCIN_SUSPEND_BIT			BIT(0)
+
+/********************************
+ *  TYPEC Peripheral Registers  *
+ ********************************/
+#define TYPE_C_SNK_STATUS_REG			(TYPEC_BASE + 0x06)
+#define DETECTED_SRC_TYPE_MASK			GENMASK(3, 1)
+#define SNK_RP_STD_BIT				BIT(3)
+#define SNK_RP_1P5_BIT				BIT(2)
+#define SNK_RP_3P0_BIT				BIT(1)
+
+#define TYPE_C_SRC_STATUS_REG			(TYPEC_BASE + 0x08)
+#define DETECTED_SNK_TYPE_MASK			GENMASK(4, 0)
+#define SRC_DEBUG_ACCESS_BIT			BIT(4)
+#define SRC_RD_OPEN_BIT				BIT(3)
+#define SRC_RD_RA_VCONN_BIT			BIT(2)
+#define SRC_RA_OPEN_BIT				BIT(1)
+#define AUDIO_ACCESS_RA_RA_BIT			BIT(0)
+
+#define TYPE_C_MISC_STATUS_REG			(TYPEC_BASE + 0x0B)
+#define SNK_SRC_MODE_BIT			BIT(6)
+#define TYPEC_VBUS_ERROR_STATUS_BIT		BIT(4)
+#define CC_ORIENTATION_BIT			BIT(1)
+#define CC_ATTACHED_BIT				BIT(0)
+
+#define LEGACY_CABLE_STATUS_REG			(TYPEC_BASE + 0x0D)
+#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT	BIT(0)
+
+#define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)
+#define U_USB_GROUND_NOVBUS_BIT			BIT(6)
+#define U_USB_GROUND_BIT			BIT(4)
+
+#define TYPE_C_MODE_CFG_REG			(TYPEC_BASE + 0x44)
+#define TYPEC_POWER_ROLE_CMD_MASK		GENMASK(2, 0)
+#define EN_SRC_ONLY_BIT				BIT(2)
+#define EN_SNK_ONLY_BIT				BIT(1)
+#define TYPEC_DISABLE_CMD_BIT			BIT(0)
+
+#define TYPE_C_VCONN_CONTROL_REG		(TYPEC_BASE + 0x46)
+#define VCONN_EN_VALUE_BIT			BIT(1)
+#define VCONN_EN_SRC_BIT			BIT(0)
+
+#define TYPE_C_CCOUT_CONTROL_REG		(TYPEC_BASE + 0x48)
+#define TYPEC_CCOUT_SRC_BIT			BIT(0)
+
+#define TYPE_C_EXIT_STATE_CFG_REG		(TYPEC_BASE + 0x50)
+#define EXIT_SNK_BASED_ON_CC_BIT		BIT(0)
+
+#define TYPE_C_INTERRUPT_EN_CFG_1_REG			(TYPEC_BASE + 0x5E)
+#define TYPEC_LEGACY_CABLE_INT_EN_BIT			BIT(7)
+#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT	BIT(6)
+#define TYPEC_TRYSOURCE_DETECT_INT_EN_BIT		BIT(5)
+#define TYPEC_TRYSINK_DETECT_INT_EN_BIT			BIT(4)
+#define TYPEC_CCOUT_DETACH_INT_EN_BIT			BIT(3)
+#define TYPEC_CCOUT_ATTACH_INT_EN_BIT			BIT(2)
+#define TYPEC_VBUS_DEASSERT_INT_EN_BIT			BIT(1)
+#define TYPEC_VBUS_ASSERT_INT_EN_BIT			BIT(0)
+
+#define TYPE_C_INTERRUPT_EN_CFG_2_REG		(TYPEC_BASE + 0x60)
+#define TYPEC_SRC_BATT_HPWR_INT_EN_BIT		BIT(6)
+#define MICRO_USB_STATE_CHANGE_INT_EN_BIT	BIT(5)
+#define TYPEC_STATE_MACHINE_CHANGE_INT_EN_BIT	BIT(4)
+#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN_BIT	BIT(3)
+#define TYPEC_WATER_DETECTION_INT_EN_BIT	BIT(2)
+#define TYPEC_VBUS_ERROR_INT_EN_BIT		BIT(1)
+#define TYPEC_DEBOUNCE_DONE_INT_EN_BIT		BIT(0)
+
+#define TYPE_C_DEBOUNCE_OPTION_REG		(TYPEC_BASE + 0x62)
+#define REDUCE_TCCDEBOUNCE_TO_2MS_BIT		BIT(2)
+
+#define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
+#define EN_MICRO_USB_MODE_BIT			BIT(0)
+
+#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x70)
+#define MICRO_USB_MODE_ONLY_BIT			BIT(0)
+/********************************
+ *  MISC Peripheral Registers  *
+ ********************************/
+#define TEMP_RANGE_STATUS_REG			(MISC_BASE + 0x06)
+#define THERM_REG_ACTIVE_BIT			BIT(6)
+#define TLIM_BIT				BIT(5)
+#define TEMP_RANGE_MASK				GENMASK(4, 1)
+#define ALERT_LEVEL_BIT				BIT(4)
+#define TEMP_ABOVE_RANGE_BIT			BIT(3)
+#define TEMP_WITHIN_RANGE_BIT			BIT(2)
+#define TEMP_BELOW_RANGE_BIT			BIT(1)
+#define THERMREG_DISABLED_BIT			BIT(0)
+
+#define BARK_BITE_WDOG_PET_REG			(MISC_BASE + 0x43)
+#define BARK_BITE_WDOG_PET_BIT			BIT(0)
+
+#define AICL_CMD_REG				(MISC_BASE + 0x44)
+#define RERUN_AICL_BIT				BIT(0)
+
+#define SNARL_BARK_BITE_WD_CFG_REG		(MISC_BASE + 0x43)
+#define BITE_WDOG_DISABLE_CHARGING_CFG_BIT	BIT(7)
+#define BARK_WDOG_TIMEOUT_MASK			GENMASK(3, 2)
+#define BITE_WDOG_TIMEOUT_MASK			GENMASK(1, 0)
+
+#define MISC_SMB_EN_CMD_REG			(MISC_BASE + 0x48)
+#define SMB_EN_OVERRIDE_VALUE_BIT		BIT(4)
+#define SMB_EN_OVERRIDE_BIT			BIT(3)
+#define EN_STAT_CMD_BIT				BIT(2)
+#define EN_CP_FPF_CMD_BIT			BIT(1)
+#define EN_CP_CMD_BIT				BIT(0)
+
+#define WD_CFG_REG				(MISC_BASE + 0x51)
+#define WATCHDOG_TRIGGER_AFP_EN_BIT		BIT(7)
+#define BARK_WDOG_INT_EN_BIT			BIT(6)
+#define WDOG_TIMER_EN_ON_PLUGIN_BIT		BIT(1)
+
+#define MISC_SMB_CFG_REG			(MISC_BASE + 0x90)
+#define SMB_EN_SEL_BIT				BIT(4)
+#define CP_EN_POLARITY_CFG_BIT			BIT(3)
+#define STAT_POLARITY_CFG_BIT			BIT(2)
+#define STAT_FUNCTION_CFG_BIT			BIT(1)
+#define STAT_IRQ_PULSING_EN_BIT			BIT(0)
+
+#endif /* __SMB5_CHARGER_REG_H */
diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c
index 328f4b6..85a5ea0 100644
--- a/drivers/pwm/pwm-qti-lpg.c
+++ b/drivers/pwm/pwm-qti-lpg.c
@@ -28,6 +28,7 @@
 
 #define REG_SIZE_PER_LPG	0x100
 
+#define REG_LPG_PERPH_SUBTYPE		0x05
 #define REG_LPG_PWM_SIZE_CLK		0x41
 #define REG_LPG_PWM_FREQ_PREDIV_CLK	0x42
 #define REG_LPG_PWM_TYPE_CONFIG		0x43
@@ -36,9 +37,15 @@
 #define REG_LPG_ENABLE_CONTROL		0x46
 #define REG_LPG_PWM_SYNC		0x47
 
+/* REG_LPG_PERPH_SUBTYPE */
+#define SUBTYPE_PWM			0x0b
+#define SUBTYPE_LPG_LITE		0x11
+
 /* REG_LPG_PWM_SIZE_CLK */
-#define LPG_PWM_SIZE_MASK		BIT(4)
-#define LPG_PWM_SIZE_SHIFT		4
+#define LPG_PWM_SIZE_MASK_LPG		BIT(4)
+#define LPG_PWM_SIZE_MASK_PWM		BIT(2)
+#define LPG_PWM_SIZE_SHIFT_LPG		4
+#define LPG_PWM_SIZE_SHIFT_PWM		2
 #define LPG_PWM_CLK_FREQ_SEL_MASK	GENMASK(1, 0)
 
 /* REG_LPG_PWM_FREQ_PREDIV_CLK */
@@ -95,6 +102,7 @@
 	u32				lpg_idx;
 	u32				reg_base;
 	u8				src_sel;
+	u8				subtype;
 	int				current_period_ns;
 	int				current_duty_ns;
 };
@@ -108,6 +116,23 @@
 	u32			num_lpgs;
 };
 
+static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val)
+{
+	int rc;
+	unsigned int tmp;
+
+	mutex_lock(&lpg->chip->bus_lock);
+	rc = regmap_read(lpg->chip->regmap, lpg->reg_base + addr, &tmp);
+	if (rc < 0)
+		dev_err(lpg->chip->dev, "Read addr 0x%x failed, rc=%d\n",
+				lpg->reg_base + addr, rc);
+	else
+		*val = (u8)tmp;
+	mutex_unlock(&lpg->chip->bus_lock);
+
+	return rc;
+}
+
 static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
 {
 	int rc;
@@ -166,10 +191,24 @@
 	return -EINVAL;
 }
 
+static int qpnp_lpg_set_glitch_removal(struct qpnp_lpg_channel *lpg, bool en)
+{
+	int rc;
+	u8 mask, val;
+
+	val = en ? LPG_PWM_EN_GLITCH_REMOVAL_MASK : 0;
+	mask = LPG_PWM_EN_GLITCH_REMOVAL_MASK;
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_TYPE_CONFIG, mask, val);
+	if (rc < 0)
+		dev_err(lpg->chip->dev, "Write LPG_PWM_TYPE_CONFIG failed, rc=%d\n",
+							rc);
+	return rc;
+}
+
 static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)
 {
 	int rc;
-	u8 val, mask;
+	u8 val, mask, shift;
 	int pwm_size_idx, pwm_clk_idx, prediv_idx, clk_exp_idx;
 
 	pwm_size_idx = __find_index_in_array(lpg->pwm_config.pwm_size,
@@ -187,8 +226,16 @@
 
 	/* pwm_clk_idx is 1 bit lower than the register value */
 	pwm_clk_idx += 1;
-	val = pwm_size_idx << LPG_PWM_SIZE_SHIFT | pwm_clk_idx;
-	mask = LPG_PWM_SIZE_MASK | LPG_PWM_CLK_FREQ_SEL_MASK;
+	if (lpg->subtype == SUBTYPE_PWM) {
+		shift = LPG_PWM_SIZE_SHIFT_PWM;
+		mask = LPG_PWM_SIZE_MASK_PWM;
+	} else {
+		shift = LPG_PWM_SIZE_SHIFT_LPG;
+		mask = LPG_PWM_SIZE_MASK_LPG;
+	}
+
+	val = pwm_size_idx << shift | pwm_clk_idx;
+	mask |= LPG_PWM_CLK_FREQ_SEL_MASK;
 	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_SIZE_CLK, mask, val);
 	if (rc < 0) {
 		dev_err(lpg->chip->dev, "Write LPG_PWM_SIZE_CLK failed, rc=%d\n",
@@ -377,6 +424,13 @@
 		return -ENODEV;
 	}
 
+	rc = qpnp_lpg_set_glitch_removal(lpg, true);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Enable glitch-removal failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
 	mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
 	val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT | LPG_EN_LPG_OUT_BIT;
 
@@ -405,9 +459,16 @@
 	val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT;
 
 	rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
-	if (rc < 0)
+	if (rc < 0) {
 		dev_err(pwm_chip->dev, "Disable PWM output failed for channel %d, rc=%d\n",
 						lpg->lpg_idx, rc);
+		return;
+	}
+
+	rc = qpnp_lpg_set_glitch_removal(lpg, false);
+	if (rc < 0)
+		dev_err(lpg->chip->dev, "Disable glitch-removal failed, rc=%d\n",
+							rc);
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -490,6 +551,12 @@
 		chip->lpgs[i].lpg_idx = i;
 		chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG;
 		chip->lpgs[i].src_sel = PWM_OUTPUT;
+		rc = qpnp_lpg_read(&chip->lpgs[i], REG_LPG_PERPH_SUBTYPE,
+				&chip->lpgs[i].subtype);
+		if (rc < 0) {
+			dev_err(chip->dev, "Read subtype failed, rc=%d\n", rc);
+			return rc;
+		}
 	}
 
 	return rc;
@@ -511,16 +578,15 @@
 		return -EINVAL;
 	}
 
+	mutex_init(&chip->bus_lock);
 	rc = qpnp_lpg_parse_dt(chip);
 	if (rc < 0) {
 		dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
 				rc);
-		return rc;
+		goto destroy;
 	}
 
 	dev_set_drvdata(chip->dev, chip);
-
-	mutex_init(&chip->bus_lock);
 	chip->pwm_chip.dev = chip->dev;
 	chip->pwm_chip.base = -1;
 	chip->pwm_chip.npwm = chip->num_lpgs;
@@ -529,9 +595,12 @@
 	rc = pwmchip_add(&chip->pwm_chip);
 	if (rc < 0) {
 		dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
-		mutex_destroy(&chip->bus_lock);
+		goto destroy;
 	}
 
+	return 0;
+destroy:
+	mutex_destroy(&chip->bus_lock);
 	return rc;
 }
 
diff --git a/drivers/regulator/cpr-regulator.c b/drivers/regulator/cpr-regulator.c
index 9c47e82..cabcf7f 100644
--- a/drivers/regulator/cpr-regulator.c
+++ b/drivers/regulator/cpr-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 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
@@ -38,8 +38,6 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
-#include <linux/msm_thermal.h>
-#include <linux/msm_tsens.h>
 #include <soc/qcom/scm.h>
 
 /* Register Offsets for RB-CPR and Bit Definitions */
@@ -287,7 +285,6 @@
 	int				corner;
 	int				ceiling_max;
 	struct dentry			*debugfs;
-	struct device			*dev;
 
 	/* eFuse parameters */
 	phys_addr_t	efuse_addr;
@@ -319,14 +316,6 @@
 	/* mem-acc regulator */
 	struct regulator	*mem_acc_vreg;
 
-	/* thermal monitor */
-	int			tsens_id;
-	int			cpr_disable_temp_threshold;
-	int			cpr_enable_temp_threshold;
-	bool			cpr_disable_on_temperature;
-	bool			cpr_thermal_disable;
-	struct threshold_info	tsens_threshold_config;
-
 	/* CPR parameters */
 	u32		num_fuse_corners;
 	u64		cpr_fuse_bits;
@@ -565,8 +554,7 @@
 
 static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
 {
-	if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable ||
-				cpr_vreg->cpr_thermal_disable)
+	if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable)
 		return false;
 	else
 		return true;
@@ -5102,145 +5090,6 @@
 	return rc;
 }
 
-static int cpr_disable_on_temp(struct cpr_regulator *cpr_vreg, bool disable)
-{
-	int rc = 0;
-
-	mutex_lock(&cpr_vreg->cpr_mutex);
-
-	if (cpr_vreg->cpr_fuse_disable ||
-		(cpr_vreg->cpr_thermal_disable == disable))
-		goto out;
-
-	cpr_vreg->cpr_thermal_disable = disable;
-
-	if (cpr_vreg->enable && cpr_vreg->corner) {
-		if (disable) {
-			cpr_debug(cpr_vreg, "Disabling CPR - below temperature threshold [%d]\n",
-					cpr_vreg->cpr_disable_temp_threshold);
-			/* disable CPR and force open-loop */
-			cpr_ctl_disable(cpr_vreg);
-			rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
-						cpr_vreg->corner, false);
-			if (rc < 0)
-				cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
-						rc);
-		} else {
-			/* enable CPR */
-			cpr_debug(cpr_vreg, "Enabling CPR - above temperature thresold [%d]\n",
-					cpr_vreg->cpr_enable_temp_threshold);
-			rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
-						cpr_vreg->corner, true);
-			if (rc < 0)
-				cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
-						rc);
-		}
-	}
-out:
-	mutex_unlock(&cpr_vreg->cpr_mutex);
-	return rc;
-}
-
-static void tsens_threshold_notify(struct therm_threshold *tsens_cb_data)
-{
-	struct threshold_info *info = tsens_cb_data->parent;
-	struct cpr_regulator *cpr_vreg = container_of(info,
-			struct cpr_regulator, tsens_threshold_config);
-	int rc = 0;
-
-	cpr_debug(cpr_vreg, "Triggered tsens-notification trip_type=%d for thermal_zone_id=%d\n",
-		tsens_cb_data->trip_triggered, tsens_cb_data->sensor_id);
-
-	switch (tsens_cb_data->trip_triggered) {
-	case THERMAL_TRIP_CONFIGURABLE_HI:
-		rc = cpr_disable_on_temp(cpr_vreg, false);
-		if (rc < 0)
-			cpr_err(cpr_vreg, "Failed to enable CPR, rc=%d\n", rc);
-		break;
-	case THERMAL_TRIP_CONFIGURABLE_LOW:
-		rc = cpr_disable_on_temp(cpr_vreg, true);
-		if (rc < 0)
-			cpr_err(cpr_vreg, "Failed to disable CPR, rc=%d\n", rc);
-		break;
-	default:
-		cpr_debug(cpr_vreg, "trip-type %d not supported\n",
-				tsens_cb_data->trip_triggered);
-		break;
-	}
-
-	if (tsens_cb_data->cur_state != tsens_cb_data->trip_triggered) {
-		rc = sensor_mgr_set_threshold(tsens_cb_data->sensor_id,
-						tsens_cb_data->threshold);
-		if (rc < 0)
-			cpr_err(cpr_vreg,
-			"Failed to set temp. threshold, rc=%d\n", rc);
-		else
-			tsens_cb_data->cur_state =
-				tsens_cb_data->trip_triggered;
-	}
-}
-
-static int cpr_check_tsens(struct cpr_regulator *cpr_vreg)
-{
-	int rc = 0;
-	struct tsens_device tsens_dev;
-	unsigned long temp = 0;
-	bool disable;
-
-	if (tsens_is_ready() > 0) {
-		tsens_dev.sensor_num = cpr_vreg->tsens_id;
-		rc = tsens_get_temp(&tsens_dev, &temp);
-		if (rc < 0) {
-			cpr_err(cpr_vreg, "Faled to read tsens, rc=%d\n", rc);
-			return rc;
-		}
-
-		disable = (int) temp <= cpr_vreg->cpr_disable_temp_threshold;
-		rc = cpr_disable_on_temp(cpr_vreg, disable);
-		if (rc)
-			cpr_err(cpr_vreg, "Failed to %s CPR, rc=%d\n",
-					disable ? "disable" : "enable", rc);
-	}
-
-	return rc;
-}
-
-static int cpr_thermal_init(struct cpr_regulator *cpr_vreg)
-{
-	int rc;
-	struct device_node *of_node = cpr_vreg->dev->of_node;
-
-	if (!of_find_property(of_node, "qcom,cpr-thermal-sensor-id", NULL))
-		return 0;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-thermal-sensor-id",
-			  &cpr_vreg->tsens_id, rc);
-	if (rc < 0)
-		return rc;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-disable-temp-threshold",
-			  &cpr_vreg->cpr_disable_temp_threshold, rc);
-	if (rc < 0)
-		return rc;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-enable-temp-threshold",
-			  &cpr_vreg->cpr_enable_temp_threshold, rc);
-	if (rc < 0)
-		return rc;
-
-	if (cpr_vreg->cpr_disable_temp_threshold >=
-				cpr_vreg->cpr_enable_temp_threshold) {
-		cpr_err(cpr_vreg, "Invalid temperature threshold cpr_disable_temp[%d] >= cpr_enable_temp[%d]\n",
-				cpr_vreg->cpr_disable_temp_threshold,
-				cpr_vreg->cpr_enable_temp_threshold);
-		return -EINVAL;
-	}
-
-	cpr_vreg->cpr_disable_on_temperature = true;
-
-	return 0;
-}
-
 static int cpr_init_cpr(struct platform_device *pdev,
 			       struct cpr_regulator *cpr_vreg)
 {
@@ -6067,7 +5916,13 @@
 		return -EINVAL;
 	}
 
-	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+	cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
+				GFP_KERNEL);
+	if (!cpr_vreg)
+		return -ENOMEM;
+
+	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
+						&cpr_vreg->rdesc);
 	if (!init_data) {
 		dev_err(dev, "regulator init data is missing\n");
 		return -EINVAL;
@@ -6078,14 +5933,6 @@
 			|= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
 	}
 
-	cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
-				GFP_KERNEL);
-	if (!cpr_vreg) {
-		dev_err(dev, "Can't allocate cpr_regulator memory\n");
-		return -ENOMEM;
-	}
-
-	cpr_vreg->dev = &pdev->dev;
 	cpr_vreg->rdesc.name = init_data->constraints.name;
 	if (cpr_vreg->rdesc.name == NULL) {
 		dev_err(dev, "regulator-name missing\n");
@@ -6182,12 +6029,6 @@
 		return rc;
 	}
 
-	rc = cpr_thermal_init(cpr_vreg);
-	if (rc) {
-		cpr_err(cpr_vreg, "Thermal intialization failed rc=%d\n", rc);
-		return rc;
-	}
-
 	if (of_property_read_bool(pdev->dev.of_node,
 				"qcom,disable-closed-loop-in-pc")) {
 		rc = cpr_init_pm_notification(cpr_vreg);
@@ -6247,17 +6088,6 @@
 	platform_set_drvdata(pdev, cpr_vreg);
 	cpr_debugfs_init(cpr_vreg);
 
-	if (cpr_vreg->cpr_disable_on_temperature) {
-		rc = cpr_check_tsens(cpr_vreg);
-		if (rc < 0) {
-			cpr_err(cpr_vreg, "Unable to config CPR on tsens, rc=%d\n",
-									rc);
-			cpr_apc_exit(cpr_vreg);
-			cpr_debugfs_remove(cpr_vreg);
-			return rc;
-		}
-	}
-
 	/* Register panic notification call back */
 	cpr_vreg->panic_notifier.notifier_call = cpr_panic_callback;
 	atomic_notifier_chain_register(&panic_notifier_list,
@@ -6293,10 +6123,6 @@
 		if (cpr_vreg->cpu_notifier.notifier_call)
 			unregister_hotcpu_notifier(&cpr_vreg->cpu_notifier);
 
-		if (cpr_vreg->cpr_disable_on_temperature)
-			sensor_mgr_remove_threshold(
-				&cpr_vreg->tsens_threshold_config);
-
 		atomic_notifier_chain_unregister(&panic_notifier_list,
 			&cpr_vreg->panic_notifier);
 
@@ -6325,56 +6151,6 @@
 	.resume		= cpr_regulator_resume,
 };
 
-static int initialize_tsens_monitor(struct cpr_regulator *cpr_vreg)
-{
-	int rc;
-
-	rc = cpr_check_tsens(cpr_vreg);
-	if (rc < 0) {
-		cpr_err(cpr_vreg, "Unable to check tsens, rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = sensor_mgr_init_threshold(&cpr_vreg->tsens_threshold_config,
-				cpr_vreg->tsens_id,
-				cpr_vreg->cpr_enable_temp_threshold, /* high */
-				cpr_vreg->cpr_disable_temp_threshold, /* low */
-				tsens_threshold_notify);
-	if (rc < 0) {
-		cpr_err(cpr_vreg, "Failed to init tsens monitor, rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = sensor_mgr_convert_id_and_set_threshold(
-			&cpr_vreg->tsens_threshold_config);
-	if (rc < 0)
-		cpr_err(cpr_vreg, "Failed to set tsens threshold, rc=%d\n",
-					rc);
-
-	return rc;
-}
-
-int __init cpr_regulator_late_init(void)
-{
-	int rc;
-	struct cpr_regulator *cpr_vreg;
-
-	mutex_lock(&cpr_regulator_list_mutex);
-
-	list_for_each_entry(cpr_vreg, &cpr_regulator_list, list) {
-		if (cpr_vreg->cpr_disable_on_temperature) {
-			rc = initialize_tsens_monitor(cpr_vreg);
-			if (rc)
-				cpr_err(cpr_vreg, "Failed to initialize temperature monitor, rc=%d\n",
-					rc);
-		}
-	}
-
-	mutex_unlock(&cpr_regulator_list_mutex);
-	return 0;
-}
-late_initcall(cpr_regulator_late_init);
-
 /**
  * cpr_regulator_init() - register cpr-regulator driver
  *
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 2800607..115a9b7 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -773,12 +773,34 @@
 	return ldo_vreg->vreg_enabled;
 }
 
+/**
+ * msm_gfx_ldo_list_corner_voltage() - return the ldo voltage mapped to
+ *			the specified voltage corner
+ * @rdev:		Regulator device pointer for the msm_gfx_ldo
+ * @corner:		Voltage corner
+ *
+ * Return: voltage value in microvolts or -EINVAL if the corner is out of range
+ */
+static int msm_gfx_ldo_list_corner_voltage(struct regulator_dev *rdev,
+		int corner)
+{
+	struct msm_gfx_ldo *ldo_vreg  = rdev_get_drvdata(rdev);
+
+	corner -= MIN_CORNER_OFFSET;
+
+	if (corner >= 0 && corner < ldo_vreg->num_corners)
+		return ldo_vreg->open_loop_volt[corner];
+	else
+		return -EINVAL;
+}
+
 static struct regulator_ops msm_gfx_ldo_corner_ops = {
-	.enable		= msm_gfx_ldo_corner_enable,
-	.disable	= msm_gfx_ldo_disable,
-	.is_enabled	= msm_gfx_ldo_is_enabled,
-	.set_voltage	= msm_gfx_ldo_set_corner,
-	.get_voltage	= msm_gfx_ldo_get_corner,
+	.enable			= msm_gfx_ldo_corner_enable,
+	.disable		= msm_gfx_ldo_disable,
+	.is_enabled		= msm_gfx_ldo_is_enabled,
+	.set_voltage		= msm_gfx_ldo_set_corner,
+	.get_voltage		= msm_gfx_ldo_get_corner,
+	.list_corner_voltage	= msm_gfx_ldo_list_corner_voltage,
 };
 
 static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index f457eea..88c5697 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -2840,8 +2840,11 @@
 		return true;
 
 	if (labibb->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE &&
-		labibb->mode == QPNP_LABIBB_LCD_MODE)
+		labibb->mode == QPNP_LABIBB_LCD_MODE) {
+		if (labibb->ttw_en)
+			return false;
 		return true;
+	}
 
 	return false;
 }
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index 9fc5a4a..79d7cba 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -998,12 +998,13 @@
 #define VOLTAGE_MIN_STEP_50_MV			4950
 #define VOLTAGE_STEP_100_MV			100
 #define VOLTAGE_STEP_50_MV			50
+#define VOLTAGE_STEP_25_MV			25
 #define VOLTAGE_STEP_50MV_OFFSET		0xA
 static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
 					int voltage_mv, u8 type)
 {
 	int rc = 0;
-	u8 val, mask = 0;
+	u8 val, voltage_step, mask = 0;
 	int bst_voltage_mv;
 	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 	struct ldo_regulator *ldo = &lcdb->ldo;
@@ -1020,10 +1021,16 @@
 		bst_voltage_mv = MAX_BST_VOLTAGE_MV;
 
 	if (bst_voltage_mv != bst->voltage_mv) {
+		if (pmic_subtype == PM660L_SUBTYPE) {
+			mask = PM660_BST_OUTPUT_VOLTAGE_MASK;
+			voltage_step = VOLTAGE_STEP_50_MV;
+		} else {
+			mask =  BST_OUTPUT_VOLTAGE_MASK;
+			voltage_step = VOLTAGE_STEP_25_MV;
+		}
+
 		val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
-						VOLTAGE_STEP_50_MV);
-		mask = (pmic_subtype == PM660L_SUBTYPE) ?
-			PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+							voltage_step);
 		rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
 					LCDB_BST_OUTPUT_VOLTAGE_REG,
 					mask, val);
@@ -1044,7 +1051,7 @@
 					int *voltage_mv)
 {
 	int rc;
-	u8 val, mask = 0;
+	u8 val, voltage_step, mask = 0;
 	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
 	rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG,
@@ -1054,10 +1061,16 @@
 		return rc;
 	}
 
-	mask = (pmic_subtype == PM660L_SUBTYPE) ?
-		PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+	if (pmic_subtype == PM660L_SUBTYPE) {
+		mask = PM660_BST_OUTPUT_VOLTAGE_MASK;
+		voltage_step = VOLTAGE_STEP_50_MV;
+	} else {
+		mask =  BST_OUTPUT_VOLTAGE_MASK;
+		voltage_step = VOLTAGE_STEP_25_MV;
+	}
+
 	val &= mask;
-	*voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV;
+	*voltage_mv = (val * voltage_step) + MIN_BST_VOLTAGE_MV;
 
 	return 0;
 }
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index fac8355..5309edc 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -74,16 +74,18 @@
 /*
  * Steps to write the RTC registers.
  * 1. Disable alarm if enabled.
- * 2. Write 0x00 to LSB.
- * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
- * 4. Enable alarm if disabled in step 1.
+ * 2. Disable rtc if enabled.
+ * 3. Write 0x00 to LSB.
+ * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0].
+ * 5. Enable rtc if disabled in step 2.
+ * 6. Enable alarm if disabled in step 1.
  */
 static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	int rc, i;
 	unsigned long secs, irq_flags;
-	u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0;
-	unsigned int ctrl_reg;
+	u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
+	unsigned int ctrl_reg, rtc_ctrl_reg;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 	const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
 
@@ -92,23 +94,38 @@
 
 	rtc_tm_to_time(tm, &secs);
 
+	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
 	for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
 		value[i] = secs & 0xFF;
 		secs >>= 8;
 	}
 
-	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
-
 	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
 
-	rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
+	rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
 	if (rc)
 		goto rtc_rw_fail;
 
 	if (ctrl_reg & regs->alarm_en) {
 		alarm_enabled = 1;
 		ctrl_reg &= ~regs->alarm_en;
-		rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+		rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
+		if (rc) {
+			dev_err(dev, "Write to RTC Alarm control register failed\n");
+			goto rtc_rw_fail;
+		}
+	}
+
+	/* Disable RTC H/w before writing on RTC register */
+	rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
+	if (rc)
+		goto rtc_rw_fail;
+
+	if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
+		rtc_disabled = 1;
+		rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
+		rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
 		if (rc) {
 			dev_err(dev, "Write to RTC control register failed\n");
 			goto rtc_rw_fail;
@@ -137,15 +154,25 @@
 		goto rtc_rw_fail;
 	}
 
-	if (alarm_enabled) {
-		ctrl_reg |= regs->alarm_en;
-		rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+	/* Enable RTC H/w after writing on RTC register */
+	if (rtc_disabled) {
+		rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
+		rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
 		if (rc) {
 			dev_err(dev, "Write to RTC control register failed\n");
 			goto rtc_rw_fail;
 		}
 	}
 
+	if (alarm_enabled) {
+		ctrl_reg |= regs->alarm_en;
+		rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
+		if (rc) {
+			dev_err(dev, "Write to RTC Alarm control register failed\n");
+			goto rtc_rw_fail;
+		}
+	}
+
 rtc_rw_fail:
 	spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
 
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 0aeecec..e2962f1 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1416,13 +1416,13 @@
 	 * will ensure that i/o is queisced and the card is flushed in that
 	 * case.
 	 */
+	aac_free_irq(aac);
 	aac_fib_map_free(aac);
 	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
 	aac->comm_addr = NULL;
 	aac->comm_phys = 0;
 	kfree(aac->queues);
 	aac->queues = NULL;
-	aac_free_irq(aac);
 	kfree(aac->fsa_dev);
 	aac->fsa_dev = NULL;
 	quirks = aac_get_driver_ident(index)->quirks;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 9962370..0b8db8a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3857,6 +3857,7 @@
 		if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
 			hpsa_get_ioaccel_status(h, scsi3addr, this_device);
 		volume_offline = hpsa_volume_offline(h, scsi3addr);
+		this_device->volume_offline = volume_offline;
 		if (volume_offline == HPSA_LV_FAILED) {
 			rc = HPSA_LV_FAILED;
 			dev_err(&h->pdev->dev,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index a530f08..4abd3fc 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1727,7 +1727,7 @@
 
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 		reason = FAILURE_SESSION_IN_RECOVERY;
-		sc->result = DID_REQUEUE;
+		sc->result = DID_REQUEUE << 16;
 		goto fault;
 	}
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9965135..3a7a86d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -149,7 +149,6 @@
 	struct list_head rq_list; /* head of request list */
 	struct fasync_struct *async_qp;	/* used by asynchronous notification */
 	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
-	char low_dma;		/* as in parent but possibly overridden to 1 */
 	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
 	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
 	unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
@@ -928,26 +927,14 @@
 				/* strange ..., for backward compatibility */
 		return sfp->timeout_user;
 	case SG_SET_FORCE_LOW_DMA:
-		result = get_user(val, ip);
-		if (result)
-			return result;
-		if (val) {
-			sfp->low_dma = 1;
-			if ((0 == sfp->low_dma) && !sfp->res_in_use) {
-				val = (int) sfp->reserve.bufflen;
-				mutex_lock(&sfp->parentdp->open_rel_lock);
-				sg_remove_scat(sfp, &sfp->reserve);
-				sg_build_reserve(sfp, val);
-				mutex_unlock(&sfp->parentdp->open_rel_lock);
-			}
-		} else {
-			if (atomic_read(&sdp->detaching))
-				return -ENODEV;
-			sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-		}
+		/*
+		 * N.B. This ioctl never worked properly, but failed to
+		 * return an error value. So returning '0' to keep compability
+		 * with legacy applications.
+		 */
 		return 0;
 	case SG_GET_LOW_DMA:
-		return put_user((int) sfp->low_dma, ip);
+		return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
 	case SG_GET_SCSI_ID:
 		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
 			return -EFAULT;
@@ -1866,6 +1853,7 @@
 	int sg_tablesize = sfp->parentdp->sg_tablesize;
 	int blk_size = buff_size, order;
 	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+	struct sg_device *sdp = sfp->parentdp;
 
 	if (blk_size < 0)
 		return -EFAULT;
@@ -1891,7 +1879,7 @@
 			scatter_elem_sz_prev = num;
 	}
 
-	if (sfp->low_dma)
+	if (sdp->device->host->unchecked_isa_dma)
 		gfp_mask |= GFP_DMA;
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2154,8 +2142,6 @@
 	sfp->timeout = SG_DEFAULT_TIMEOUT;
 	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
 	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-	    sdp->device->host->unchecked_isa_dma : 1;
 	sfp->cmd_q = SG_DEF_COMMAND_Q;
 	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
 	sfp->parentdp = sdp;
@@ -2614,7 +2600,7 @@
 			   jiffies_to_msecs(fp->timeout),
 			   fp->reserve.bufflen,
 			   (int) fp->reserve.k_use_sg,
-			   (int) fp->low_dma);
+			   (int) sdp->device->host->unchecked_isa_dma);
 		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
 			   (int) fp->cmd_q, (int) fp->force_packid,
 			   (int) fp->keep_orphan);
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ba44523..bca52ca 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -2615,6 +2615,27 @@
 	kfree(testbus);
 }
 
+static void ufs_qcom_print_utp_hci_testbus(struct ufs_hba *hba)
+{
+	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+	u32 *testbus = NULL;
+	int i, nminor = 32, testbus_len = nminor * sizeof(u32);
+
+	testbus = kmalloc(testbus_len, GFP_KERNEL);
+	if (!testbus)
+		return;
+
+	host->testbus.select_major = TSTBUS_UTP_HCI;
+	for (i = 0; i <= nminor; i++) {
+		host->testbus.select_minor = i;
+		ufs_qcom_testbus_config(host);
+		testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+	}
+	print_hex_dump(KERN_ERR, "UTP_HCI_TEST_BUS ", DUMP_PREFIX_OFFSET,
+			16, 4, testbus, testbus_len, false);
+	kfree(testbus);
+}
+
 static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep)
 {
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -2633,6 +2654,8 @@
 	usleep_range(1000, 1100);
 	ufs_qcom_print_unipro_testbus(hba);
 	usleep_range(1000, 1100);
+	ufs_qcom_print_utp_hci_testbus(hba);
+	usleep_range(1000, 1100);
 	ufs_qcom_phy_dbg_register_dump(phy);
 	usleep_range(1000, 1100);
 	ufs_qcom_ice_print_regs(host);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1a93164..fcbc69b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * Authors:
  *	Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -620,6 +620,11 @@
 	ufshcd_cmd_log(hba, str, "dme", 0, cmd_id, 0);
 }
 
+static void ufshcd_custom_cmd_log(struct ufs_hba *hba, char *str)
+{
+	ufshcd_cmd_log(hba, str, "custom", 0, 0, 0);
+}
+
 static void ufshcd_print_cmd_log(struct ufs_hba *hba)
 {
 	int i;
@@ -658,7 +663,7 @@
 
 	entry.str = str;
 	entry.lba = lba;
-	entry->cmd_id = cmd_id;
+	entry.cmd_id = cmd_id;
 	entry.transfer_len = transfer_len;
 	entry.doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 	entry.tag = tag;
@@ -670,6 +675,10 @@
 {
 }
 
+static void ufshcd_custom_cmd_log(struct ufs_hba *hba, char *str)
+{
+}
+
 static void ufshcd_print_cmd_log(struct ufs_hba *hba)
 {
 }
@@ -892,7 +901,7 @@
 
 	dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
 	dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx tasks=0x%lx\n",
-		hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+		hba->lrb_in_use, hba->outstanding_reqs, hba->outstanding_tasks);
 	dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x, saved_ce_err=0x%x\n",
 		hba->saved_err, hba->saved_uic_err, hba->saved_ce_err);
 	dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
@@ -6353,7 +6362,7 @@
 	 * Dump controller state before resetting. Transfer requests state
 	 * will be dump as part of the request completion.
 	 */
-	if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) ||
+	if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR | UIC_LINK_LOST)) ||
 	    hba->auto_h8_err) {
 		dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x",
 			__func__, hba->saved_err, hba->saved_uic_err);
@@ -6370,7 +6379,7 @@
 		hba->auto_h8_err = false;
 	}
 
-	if ((hba->saved_err & INT_FATAL_ERRORS)
+	if ((hba->saved_err & (INT_FATAL_ERRORS | UIC_LINK_LOST))
 	    || hba->saved_ce_err || hba->force_host_reset ||
 	    ((hba->saved_err & UIC_ERROR) &&
 	    (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
@@ -6498,6 +6507,7 @@
 	hba = container_of(work, struct ufs_hba, rls_work);
 	ufshcd_scsi_block_requests(hba);
 	pm_runtime_get_sync(hba->dev);
+	down_write(&hba->lock);
 	ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
 	if (ret) {
 		dev_err(hba->dev,
@@ -6531,6 +6541,7 @@
 		hba->restore_needed = false;
 
 out:
+	up_write(&hba->lock);
 	ufshcd_scsi_unblock_requests(hba);
 	pm_runtime_put_sync(hba->dev);
 }
@@ -6647,6 +6658,12 @@
 	if (hba->errors & INT_FATAL_ERRORS || hba->ce_error)
 		queue_eh_work = true;
 
+	if (hba->errors & UIC_LINK_LOST) {
+		dev_err(hba->dev, "%s: UIC_LINK_LOST received, errors 0x%x\n",
+					__func__, hba->errors);
+		queue_eh_work = true;
+	}
+
 	if (hba->errors & UIC_ERROR) {
 		hba->uic_error = 0;
 		retval = ufshcd_update_uic_error(hba);
@@ -8517,12 +8534,15 @@
 		struct ufs_vreg *vreg, bool on)
 {
 	int ret = 0;
-	struct regulator *reg = vreg->reg;
-	const char *name = vreg->name;
+	struct regulator *reg;
+	const char *name;
 	int min_uV, uA_load;
 
 	BUG_ON(!vreg);
 
+	reg = vreg->reg;
+	name = vreg->name;
+
 	if (regulator_count_voltages(reg) > 0) {
 		min_uV = on ? vreg->min_uV : 0;
 		ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
@@ -8947,7 +8967,8 @@
 		if (ufshcd_is_clkscaling_supported(hba)) {
 			if (hba->devfreq)
 				ufshcd_suspend_clkscaling(hba);
-			destroy_workqueue(hba->clk_scaling.workq);
+			if (hba->clk_scaling.workq)
+				destroy_workqueue(hba->clk_scaling.workq);
 		}
 		ufshcd_disable_clocks(hba, false);
 		ufshcd_setup_hba_vreg(hba, false);
@@ -10128,11 +10149,14 @@
 	if (ret)
 		goto out;
 
+	ufshcd_custom_cmd_log(hba, "waited-for-DB-clear");
+
 	/* scale down the gear before scaling down clocks */
 	if (!scale_up) {
 		ret = ufshcd_scale_gear(hba, false);
 		if (ret)
 			goto clk_scaling_unprepare;
+		ufshcd_custom_cmd_log(hba, "Gear-scaled-down");
 	}
 
 	/*
@@ -10145,17 +10169,20 @@
 		if (ret)
 			/* link will be bad state so no need to scale_up_gear */
 			return ret;
+		ufshcd_custom_cmd_log(hba, "Hibern8-entered");
 	}
 
 	ret = ufshcd_scale_clks(hba, scale_up);
 	if (ret)
 		goto scale_up_gear;
+	ufshcd_custom_cmd_log(hba, "Clk-freq-switched");
 
 	if (ufshcd_is_auto_hibern8_supported(hba)) {
 		ret = ufshcd_uic_hibern8_exit(hba);
 		if (ret)
 			/* link will be bad state so no need to scale_up_gear */
 			return ret;
+		ufshcd_custom_cmd_log(hba, "Hibern8-Exited");
 	}
 
 	/* scale up the gear after scaling up clocks */
@@ -10165,6 +10192,7 @@
 			ufshcd_scale_clks(hba, false);
 			goto clk_scaling_unprepare;
 		}
+		ufshcd_custom_cmd_log(hba, "Gear-scaled-up");
 	}
 
 	if (!ret) {
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index c0e4650..87affc4 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -154,7 +154,7 @@
 
 #define UFSHCD_UIC_MASK		(UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
 
-#define UFSHCD_ERROR_MASK	(UIC_ERROR |\
+#define UFSHCD_ERROR_MASK	(UIC_ERROR | UIC_LINK_LOST |\
 				DEVICE_FATAL_ERROR |\
 				CONTROLLER_FATAL_ERROR |\
 				SYSTEM_BUS_FATAL_ERROR |\
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 01779f9..24a3ccf 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -490,32 +490,26 @@
 	return SLIM_P_INPROGRESS;
 }
 
-static int msm_slim_iommu_map(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+static dma_addr_t msm_slim_iommu_map(struct msm_slim_ctrl *dev, void *buf_addr,
 			      u32 len)
 {
-	int ret;
+	dma_addr_t ret;
+	struct device *devp = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev :
+							dev->dev;
+	ret = dma_map_single(devp, buf_addr, len, DMA_BIDIRECTIONAL);
 
-	if (!dev->iommu_desc.cb_dev)
-		return 0;
+	if (dma_mapping_error(devp, ret))
+		return DMA_ERROR_CODE;
 
-	ret = iommu_map(dev->iommu_desc.iommu_map->domain,
-			rounddown(iobuf, PAGE_SIZE),
-			rounddown(iobuf, PAGE_SIZE),
-			roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
-				PAGE_SIZE), IOMMU_READ | IOMMU_WRITE);
 	return ret;
 }
 
-static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, dma_addr_t buf_addr,
 				u32 len)
 {
-	if (!dev->iommu_desc.cb_dev)
-		return;
-
-	iommu_unmap(dev->iommu_desc.iommu_map->domain,
-		    rounddown(iobuf, PAGE_SIZE),
-		    roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
-			    PAGE_SIZE));
+	struct device *devp = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev :
+							dev->dev;
+	dma_unmap_single(devp, buf_addr, len, DMA_BIDIRECTIONAL);
 }
 
 static void msm_slim_port_cb(struct sps_event_notify *ev)
@@ -539,11 +533,12 @@
 		complete(comp);
 }
 
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, void *buf,
 			u32 len, struct completion *comp)
 {
 	struct sps_register_event sreg;
 	int ret;
+	dma_addr_t dma_buf;
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 
 	if (pn >= dev->port_nums)
@@ -552,9 +547,11 @@
 	if (!dev->pipes[pn].connected)
 		return -ENOTCONN;
 
-	ret = msm_slim_iommu_map(dev, iobuf, len);
-	if (ret)
-		return ret;
+	dma_buf =  msm_slim_iommu_map(dev, buf, len);
+	if (dma_buf == DMA_ERROR_CODE) {
+		dev_err(dev->dev, "error DMA mapping buffers\n");
+		return -ENOMEM;
+	}
 
 	sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR);
 	sreg.mode = SPS_TRIGGER_WAIT;
@@ -564,10 +561,10 @@
 	ret = sps_register_event(dev->pipes[pn].sps, &sreg);
 	if (ret) {
 		dev_dbg(dev->dev, "sps register event error:%x\n", ret);
-		msm_slim_iommu_unmap(dev, iobuf, len);
+		msm_slim_iommu_unmap(dev, dma_buf, len);
 		return ret;
 	}
-	ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
+	ret = sps_transfer_one(dev->pipes[pn].sps, dma_buf, len, comp,
 				SPS_IOVEC_FLAG_INT);
 	dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
 	if (!ret) {
@@ -581,7 +578,7 @@
 		/* Make sure that port registers are updated before returning */
 		mb();
 	} else {
-		msm_slim_iommu_unmap(dev, iobuf, len);
+		msm_slim_iommu_unmap(dev, dma_buf, len);
 	}
 
 	return ret;
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 5859c5f..edebfd9 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -423,7 +423,7 @@
 int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
 enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
 				u8 pn, phys_addr_t *done_buf, u32 *done_len);
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, void *buf,
 			u32 len, struct completion *comp);
 int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
 u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index f34467b..1140b33 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -1600,14 +1600,14 @@
  * Client will call slim_port_get_xfer_status to get error and/or number of
  * bytes transferred if used asynchronously.
  */
-int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf, u32 len,
+int slim_port_xfer(struct slim_device *sb, u32 ph, void *buf, u32 len,
 				struct completion *comp)
 {
 	struct slim_controller *ctrl = sb->ctrl;
 	u8 pn = SLIM_HDL_TO_PORT(ph);
 
 	dev_dbg(&ctrl->dev, "port xfer: num:%d", pn);
-	return ctrl->port_xfer(ctrl, pn, iobuf, len, comp);
+	return ctrl->port_xfer(ctrl, pn, buf, len, comp);
 }
 EXPORT_SYMBOL(slim_port_xfer);
 
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c3b2ca8..c5a15b2 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -250,6 +250,17 @@
 	  deadlocks. It does not run during the bootup process, so it will
 	  not catch any early lockups.
 
+config QCOM_WDOG_IPI_ENABLE
+	bool "Qcom WDT pet optimization"
+	depends on QCOM_WATCHDOG_V2
+	default n
+	help
+	  When this option is enabled, watchdog sends IPI to cores in low power
+	  mode also. For power optimizations, by default watchdog don't ping
+	  cores in low power mode at pettime.
+
+	  To track CPUs health on LPM, or on debug builds enable it.
+
 config QPNP_PBS
 	tristate "PBS trigger support for QPNP PMIC"
 	depends on SPMI
@@ -635,6 +646,15 @@
 	  monitor events that require the core to be awake and ready to
 	  handle the event.
 
+config MSM_AVTIMER
+	tristate "Avtimer Driver"
+	default n
+	help
+	  This driver gets the Q6 out of power collapsed state
+	  and exposes ioctl control to read avtimer tick.
+	  Enables camera to use for VT call to get avtimer
+	  timestamp.
+
 config MSM_PM
 	depends on PM
 	select MSM_IDLE_STATS if DEBUG_FS
@@ -775,4 +795,13 @@
 	  sub-system to USB on APSS side. The driver acts as a bridge between the
 	  MHI and USB interface. If unsure, say N.
 
+config MSM_BAM_DMUX
+	bool "BAM Data Mux Driver"
+	depends on SPS
+	help
+	  Support Muxed Data Channels over BAM interface.
+	  BAM has a limited number of pipes.  This driver
+	  provides a means to support more logical channels
+	  via muxing than BAM could without muxing.
+
 source "drivers/soc/qcom/wcnss/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0255761..c7c7f62 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,9 +65,9 @@
 obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
 
 obj-$(CONFIG_MEM_SHARE_QMI_SERVICE)		+= memshare/
+obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 
 obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
 
@@ -96,4 +96,5 @@
 obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o
 obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
 obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o
+obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
 obj-$(CONFIG_WCNSS_CORE) += wcnss/
diff --git a/drivers/soc/qcom/bam_dmux.c b/drivers/soc/qcom/bam_dmux.c
new file mode 100644
index 0000000..3b75e74
--- /dev/null
+++ b/drivers/soc/qcom/bam_dmux.c
@@ -0,0 +1,2853 @@
+/* Copyright (c) 2011-2016, 2018, 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.
+ *
+ */
+
+/*
+ *  BAM DMUX module.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/clk.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/ipc_logging.h>
+#include <linux/srcu.h>
+#include <linux/msm-sps.h>
+#include <linux/sizes.h>
+#include <soc/qcom/bam_dmux.h>
+#include <soc/qcom/smsm.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#include "bam_dmux_private.h"
+
+#define BAM_CH_LOCAL_OPEN       0x1
+#define BAM_CH_REMOTE_OPEN      0x2
+#define BAM_CH_IN_RESET         0x4
+
+#define LOW_WATERMARK		2
+#define HIGH_WATERMARK		4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
+
+static int msm_bam_dmux_debug_enable;
+module_param_named(debug_enable, msm_bam_dmux_debug_enable, int, 0664);
+static int POLLING_MIN_SLEEP = 2950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP, int, 0664);
+static int POLLING_MAX_SLEEP = 3050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP, int, 0664);
+static int POLLING_INACTIVITY = 1;
+module_param_named(inactivity, POLLING_INACTIVITY, int, 0664);
+static int bam_adaptive_timer_enabled;
+module_param_named(adaptive_timer_enabled,
+			bam_adaptive_timer_enabled, int, 0664);
+
+static struct bam_ops_if bam_default_ops = {
+	/* smsm */
+	.smsm_change_state_ptr = &smsm_change_state,
+	.smsm_get_state_ptr = &smsm_get_state,
+	.smsm_state_cb_register_ptr = &smsm_state_cb_register,
+	.smsm_state_cb_deregister_ptr = &smsm_state_cb_deregister,
+
+	/* sps */
+	.sps_connect_ptr = &sps_connect,
+	.sps_disconnect_ptr = &sps_disconnect,
+	.sps_register_bam_device_ptr = &sps_register_bam_device,
+	.sps_deregister_bam_device_ptr = &sps_deregister_bam_device,
+	.sps_alloc_endpoint_ptr = &sps_alloc_endpoint,
+	.sps_free_endpoint_ptr = &sps_free_endpoint,
+	.sps_set_config_ptr = &sps_set_config,
+	.sps_get_config_ptr = &sps_get_config,
+	.sps_device_reset_ptr = &sps_device_reset,
+	.sps_register_event_ptr = &sps_register_event,
+	.sps_transfer_one_ptr = &sps_transfer_one,
+	.sps_get_iovec_ptr = &sps_get_iovec,
+	.sps_get_unused_desc_num_ptr = &sps_get_unused_desc_num,
+
+	.dma_to = DMA_TO_DEVICE,
+	.dma_from = DMA_FROM_DEVICE,
+};
+static struct bam_ops_if *bam_ops = &bam_default_ops;
+
+#if defined(DEBUG)
+static uint32_t bam_dmux_read_cnt;
+static uint32_t bam_dmux_write_cnt;
+static uint32_t bam_dmux_write_cpy_cnt;
+static uint32_t bam_dmux_write_cpy_bytes;
+static uint32_t bam_dmux_tx_sps_failure_cnt;
+static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
+
+#define DBG(x...) do {		                 \
+		if (msm_bam_dmux_debug_enable)  \
+			pr_debug(x);	         \
+	} while (0)
+
+#define DBG_INC_READ_CNT(x) do {	                               \
+		bam_dmux_read_cnt += (x);                             \
+		if (msm_bam_dmux_debug_enable)                        \
+			pr_debug("%s: total read bytes %u\n",          \
+				 __func__, bam_dmux_read_cnt);        \
+	} while (0)
+
+#define DBG_INC_WRITE_CNT(x)  do {	                               \
+		bam_dmux_write_cnt += (x);                            \
+		if (msm_bam_dmux_debug_enable)                        \
+			pr_debug("%s: total written bytes %u\n",       \
+				 __func__, bam_dmux_write_cnt);       \
+	} while (0)
+
+#define DBG_INC_WRITE_CPY(x)  do {	                                     \
+		bam_dmux_write_cpy_bytes += (x);                            \
+		bam_dmux_write_cpy_cnt++;                                   \
+		if (msm_bam_dmux_debug_enable)                              \
+			pr_debug("%s: total write copy cnt %u, bytes %u\n",  \
+				 __func__, bam_dmux_write_cpy_cnt,          \
+				 bam_dmux_write_cpy_bytes);                 \
+	} while (0)
+
+#define DBG_INC_TX_SPS_FAILURE_CNT() (bam_dmux_tx_sps_failure_cnt++)
+
+#define DBG_INC_TX_STALL_CNT() (bam_dmux_tx_stall_cnt++)
+
+#define DBG_INC_ACK_OUT_CNT() \
+	atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+	atomic_inc(&bam_dmux_ack_in_cnt)
+#else
+#define DBG(x...) do { } while (0)
+#define DBG_INC_READ_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CPY(x...) do { } while (0)
+#define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
+#define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
+#endif
+
+struct bam_ch_info {
+	uint32_t status;
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+	spinlock_t lock;
+	struct platform_device *pdev;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	int num_tx_pkts;
+	int use_wm;
+};
+
+#define A2_NUM_PIPES		6
+#define A2_SUMMING_THRESHOLD	4096
+#define A2_PHYS_BASE		0x124C2000
+#define A2_PHYS_SIZE		0x2000
+#define DEFAULT_NUM_BUFFERS	32
+
+#ifndef A2_BAM_IRQ
+#define A2_BAM_IRQ -1
+#endif
+
+static phys_addr_t a2_phys_base;
+static uint32_t a2_phys_size;
+static int a2_bam_irq;
+static struct sps_bam_props a2_props;
+static unsigned long a2_device_handle;
+static struct sps_pipe *bam_tx_pipe;
+static struct sps_pipe *bam_rx_pipe;
+static struct sps_connect tx_connection;
+static struct sps_connect rx_connection;
+static struct sps_mem_buffer tx_desc_mem_buf;
+static struct sps_mem_buffer rx_desc_mem_buf;
+static struct sps_register_event tx_register_event;
+static struct sps_register_event rx_register_event;
+static bool satellite_mode;
+static uint32_t num_buffers;
+static unsigned long long last_rx_pkt_timestamp;
+static struct device *dma_dev;
+static bool dynamic_mtu_enabled;
+static uint16_t ul_mtu = DEFAULT_BUFFER_SIZE;
+static uint16_t dl_mtu = DEFAULT_BUFFER_SIZE;
+static uint16_t buffer_size = DEFAULT_BUFFER_SIZE;
+static bool no_cpu_affinity;
+
+static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
+static int bam_mux_initialized;
+
+static int polling_mode;
+static unsigned long rx_timer_interval;
+
+static LIST_HEAD(bam_rx_pool);
+static DEFINE_MUTEX(bam_rx_pool_mutexlock);
+static int bam_rx_pool_len;
+static LIST_HEAD(bam_tx_pool);
+static DEFINE_SPINLOCK(bam_tx_pool_spinlock);
+static DEFINE_MUTEX(bam_pdev_mutexlock);
+
+static void notify_all(int event, unsigned long data);
+static void bam_mux_write_done(struct work_struct *work);
+static void handle_bam_mux_cmd(struct work_struct *work);
+static void rx_timer_work_func(struct work_struct *work);
+static void queue_rx_work_func(struct work_struct *work);
+static int ssrestart_check(void);
+
+static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+static DECLARE_WORK(queue_rx_work, queue_rx_work_func);
+
+static struct workqueue_struct *bam_mux_rx_workqueue;
+static struct workqueue_struct *bam_mux_tx_workqueue;
+
+static struct srcu_struct bam_dmux_srcu;
+
+/* A2 power collaspe */
+#define UL_TIMEOUT_DELAY 1000	/* in ms */
+#define UL_FAST_TIMEOUT_DELAY 100 /* in ms */
+#define SHUTDOWN_TIMEOUT_MS	500
+#define UL_WAKEUP_TIMEOUT_MS	2000
+static uint32_t ul_timeout_delay = UL_TIMEOUT_DELAY;
+static void toggle_apps_ack(void);
+static void reconnect_to_bam(void);
+static void disconnect_to_bam(void);
+static void ul_wakeup(void);
+static void ul_timeout(struct work_struct *work);
+static void vote_dfab(void);
+static void unvote_dfab(void);
+static void kickoff_ul_wakeup_func(struct work_struct *work);
+static void grab_wakelock(void);
+static void release_wakelock(void);
+
+static int bam_is_connected;
+static DEFINE_MUTEX(wakeup_lock);
+static struct completion ul_wakeup_ack_completion;
+static struct completion bam_connection_completion;
+static struct delayed_work ul_timeout_work;
+static int ul_packet_written;
+static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
+static struct clk *dfab_clk, *xo_clk;
+static DEFINE_RWLOCK(ul_wakeup_lock);
+static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
+static int bam_connection_is_active;
+static int wait_for_ack;
+static struct wakeup_source bam_wakelock;
+static int a2_pc_disabled;
+static DEFINE_MUTEX(dfab_status_lock);
+static int dfab_is_on;
+static int wait_for_dfab;
+static struct completion dfab_unvote_completion;
+static DEFINE_SPINLOCK(wakelock_reference_lock);
+static int wakelock_reference_count;
+static int a2_pc_disabled_wakelock_skipped;
+static LIST_HEAD(bam_other_notify_funcs);
+static DEFINE_MUTEX(smsm_cb_lock);
+static DEFINE_MUTEX(delayed_ul_vote_lock);
+static int need_delayed_ul_vote;
+static int ssr_skipped_disconnect;
+static struct completion shutdown_completion;
+
+struct outside_notify_func {
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+	struct list_head list_node;
+};
+/* End A2 power collaspe */
+
+/* subsystem restart */
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data);
+
+static struct notifier_block restart_notifier = {
+	.notifier_call = restart_notifier_cb,
+};
+static int in_global_reset;
+/* end subsystem restart */
+
+#define bam_ch_is_open(x)						\
+	(bam_ch[(x)].status == (BAM_CH_LOCAL_OPEN | BAM_CH_REMOTE_OPEN))
+
+#define bam_ch_is_local_open(x)			\
+	(bam_ch[(x)].status & BAM_CH_LOCAL_OPEN)
+
+#define bam_ch_is_remote_open(x)			\
+	(bam_ch[(x)].status & BAM_CH_REMOTE_OPEN)
+
+#define bam_ch_is_in_reset(x)			\
+	(bam_ch[(x)].status & BAM_CH_IN_RESET)
+
+static int bam_dmux_uplink_vote;
+static int bam_dmux_power_state;
+
+static void *bam_ipc_log_txt;
+
+#define BAM_IPC_LOG_PAGES 5
+
+/**
+ * Log a state change along with a small message.
+ * Complete size of message is limited to @todo.
+ * Logging is done using IPC Logging infrastructure.
+ *
+ * States
+ * D: 1 = Power collapse disabled
+ * R: 1 = in global reset
+ * P: 1 = BAM is powered up
+ * A: 1 = BAM initialized and ready for data
+ * V: 1 = Uplink vote for power
+ * U: 1 = Uplink active
+ * W: 1 = Uplink Wait-for-ack
+ * A: 1 = Uplink ACK received
+ * #: >=1 On-demand uplink vote
+ * D: 1 = Disconnect ACK active
+ */
+
+#define BAM_DMUX_LOG(fmt, args...) \
+do { \
+	if (bam_ipc_log_txt) { \
+		ipc_log_string(bam_ipc_log_txt, \
+		"<DMUX> %c%c%c%c %c%c%c%c%d " fmt, \
+		a2_pc_disabled ? 'D' : 'd', \
+		in_global_reset ? 'R' : 'r', \
+		bam_dmux_power_state ? 'P' : 'p', \
+		bam_connection_is_active ? 'A' : 'a', \
+		bam_dmux_uplink_vote ? 'V' : 'v', \
+		bam_is_connected ?  'U' : 'u', \
+		wait_for_ack ? 'W' : 'w', \
+		ul_wakeup_ack_completion.done ? 'A' : 'a', \
+		atomic_read(&ul_ondemand_vote), \
+		args); \
+	} \
+} while (0)
+
+#define DMUX_LOG_KERR(fmt, args...) \
+do { \
+	BAM_DMUX_LOG(fmt, args); \
+	pr_err(fmt, args); \
+} while (0)
+
+static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
+{
+	unsigned long long t_now;
+
+	t_now = sched_clock();
+	pkt->ts_nsec = do_div(t_now, 1000000000U);
+	pkt->ts_sec = (unsigned int)t_now;
+}
+
+static inline void verify_tx_queue_is_empty(const char *func)
+{
+	unsigned long flags;
+	struct tx_pkt_info *info;
+	int reported = 0;
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_for_each_entry(info, &bam_tx_pool, list_node) {
+		if (!reported) {
+			BAM_DMUX_LOG("%s: tx pool not empty\n", func);
+			if (!in_global_reset)
+				pr_err("%s: tx pool not empty\n", func);
+			reported = 1;
+		}
+		BAM_DMUX_LOG("%s: node=%pK ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+		if (!in_global_reset)
+			pr_err("%s: node=%pK ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+}
+
+static void __queue_rx(gfp_t alloc_flags)
+{
+	void *ptr;
+	struct rx_pkt_info *info;
+	int ret;
+	int rx_len_cached;
+	uint16_t current_buffer_size;
+
+	mutex_lock(&bam_rx_pool_mutexlock);
+	rx_len_cached = bam_rx_pool_len;
+	current_buffer_size = buffer_size;
+	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	while (bam_connection_is_active && rx_len_cached < num_buffers) {
+		if (in_global_reset)
+			goto fail;
+
+		info = kmalloc(sizeof(*info), alloc_flags);
+		if (!info)
+			goto fail;
+
+		info->len = current_buffer_size;
+
+		INIT_WORK(&info->work, handle_bam_mux_cmd);
+
+		info->skb = __dev_alloc_skb(info->len, alloc_flags);
+		if (info->skb == NULL)
+			goto fail_info;
+
+		ptr = skb_put(info->skb, info->len);
+
+		info->dma_address = dma_map_single(dma_dev, ptr, info->len,
+							bam_ops->dma_from);
+		if (info->dma_address == 0 || info->dma_address == ~0) {
+			DMUX_LOG_KERR("%s:dma_map_single failure %pK for %pK\n",
+				__func__, (void *)info->dma_address, ptr);
+			goto fail_skb;
+		}
+
+		mutex_lock(&bam_rx_pool_mutexlock);
+		list_add_tail(&info->list_node, &bam_rx_pool);
+		rx_len_cached = ++bam_rx_pool_len;
+		current_buffer_size = buffer_size;
+		ret = bam_ops->sps_transfer_one_ptr(bam_rx_pipe,
+				info->dma_address, info->len, info, 0);
+		if (ret) {
+			list_del(&info->list_node);
+			rx_len_cached = --bam_rx_pool_len;
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			DMUX_LOG_KERR("%s: sps_transfer_one failed %d\n",
+				__func__, ret);
+
+			dma_unmap_single(dma_dev, info->dma_address,
+						info->len,
+						bam_ops->dma_from);
+
+			goto fail_skb;
+		}
+		mutex_unlock(&bam_rx_pool_mutexlock);
+
+	}
+	return;
+
+fail_skb:
+	dev_kfree_skb_any(info->skb);
+
+fail_info:
+	kfree(info);
+
+fail:
+	if (!in_global_reset) {
+		DMUX_LOG_KERR("%s: rescheduling\n", __func__);
+		schedule_work(&queue_rx_work);
+	}
+}
+
+static void queue_rx(void)
+{
+	/*
+	 * Hot path.  Delays waiting for the allocation to find memory if its
+	 * not immediately available, and delays from logging allocation
+	 * failures which cannot be tolerated at this time.
+	 */
+	__queue_rx(GFP_NOWAIT | __GFP_NOWARN);
+}
+
+static void queue_rx_work_func(struct work_struct *work)
+{
+	/*
+	 * Cold path.  Delays can be tolerated.  Use of GFP_KERNEL should
+	 * guarantee the requested memory will be found, after some ammount of
+	 * delay.
+	 */
+	__queue_rx(GFP_KERNEL);
+}
+
+/**
+ * process_dynamic_mtu() - Process the dynamic MTU signal bit from data cmds
+ * @current_state:	State of the dynamic MTU signal bit for the current
+ *			data command packet.
+ */
+static void process_dynamic_mtu(bool current_state)
+{
+	static bool old_state;
+
+	if (!dynamic_mtu_enabled)
+		return;
+
+	if (old_state == current_state)
+		return;
+
+	mutex_lock(&bam_rx_pool_mutexlock);
+	if (current_state) {
+		buffer_size = dl_mtu;
+		BAM_DMUX_LOG("%s: switching to large mtu %x\n", __func__,
+									dl_mtu);
+	} else {
+		buffer_size = DEFAULT_BUFFER_SIZE;
+		BAM_DMUX_LOG("%s: switching to reg mtu %x\n", __func__,
+							DEFAULT_BUFFER_SIZE);
+	}
+	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	old_state = current_state;
+}
+
+static void bam_mux_process_data(struct sk_buff *rx_skb)
+{
+	unsigned long flags;
+	struct bam_mux_hdr *rx_hdr;
+	unsigned long event_data;
+	uint8_t ch_id;
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+
+	rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+	ch_id = rx_hdr->ch_id;
+
+	process_dynamic_mtu(rx_hdr->signal & DYNAMIC_MTU_MASK);
+
+	rx_skb->data = (unsigned char *)(rx_hdr + 1);
+	skb_set_tail_pointer(rx_skb, rx_hdr->pkt_len);
+	rx_skb->len = rx_hdr->pkt_len;
+	rx_skb->truesize = rx_hdr->pkt_len + sizeof(struct sk_buff);
+
+	event_data = (unsigned long)(rx_skb);
+	notify = NULL;
+	priv = NULL;
+
+	spin_lock_irqsave(&bam_ch[ch_id].lock, flags);
+	if (bam_ch[ch_id].notify) {
+		notify = bam_ch[ch_id].notify;
+		priv = bam_ch[ch_id].priv;
+	}
+	spin_unlock_irqrestore(&bam_ch[ch_id].lock, flags);
+	if (notify)
+		notify(priv, BAM_DMUX_RECEIVE, event_data);
+	else
+		dev_kfree_skb_any(rx_skb);
+
+	queue_rx();
+}
+
+/**
+ * set_ul_mtu() - Converts the MTU code received from the remote side in the
+ *		  open cmd into a byte value.
+ * @mtu_code:	MTU size code to translate.
+ * @reset:	Reset the MTU.
+ */
+static void set_ul_mtu(int mtu_code, bool reset)
+{
+	static bool first = true;
+
+	if (reset) {
+		first = true;
+		ul_mtu = DEFAULT_BUFFER_SIZE;
+		return;
+	}
+
+	switch (mtu_code) {
+	case 0:
+		if (ul_mtu != SZ_2K && !first) {
+			BAM_DMUX_LOG("%s: bad request for 2k, ul_mtu is %d\n",
+							__func__, ul_mtu);
+			ssrestart_check();
+		}
+		ul_mtu = SZ_2K;
+		break;
+	case 1:
+		if (ul_mtu != SZ_4K && !first) {
+			BAM_DMUX_LOG("%s: bad request for 4k, ul_mtu is %d\n",
+							__func__, ul_mtu);
+			ssrestart_check();
+		}
+		ul_mtu = SZ_4K;
+		break;
+	case 2:
+		if (ul_mtu != SZ_8K && !first) {
+			BAM_DMUX_LOG("%s: bad request for 8k, ul_mtu is %d\n",
+							__func__, ul_mtu);
+			ssrestart_check();
+		}
+		ul_mtu = SZ_8K;
+		break;
+	case 3:
+		if (ul_mtu != SZ_16K && !first) {
+			BAM_DMUX_LOG("%s: bad request for 16k, ul_mtu is %d\n",
+							__func__, ul_mtu);
+			ssrestart_check();
+		}
+		ul_mtu = SZ_16K;
+		break;
+	default:
+		BAM_DMUX_LOG("%s: bad request %d\n", __func__, mtu_code);
+		ssrestart_check();
+		break;
+	}
+
+	first = false;
+}
+
+static inline void handle_bam_mux_cmd_open(struct bam_mux_hdr *rx_hdr)
+{
+	unsigned long flags;
+	int ret;
+
+	mutex_lock(&bam_pdev_mutexlock);
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: open cid %d aborted due to ssr\n",
+				__func__, rx_hdr->ch_id);
+		mutex_unlock(&bam_pdev_mutexlock);
+		queue_rx();
+		return;
+	}
+	if (rx_hdr->signal & DYNAMIC_MTU_MASK) {
+		dynamic_mtu_enabled = true;
+		set_ul_mtu((rx_hdr->signal & MTU_SIZE_MASK) >> MTU_SIZE_SHIFT,
+									false);
+	} else {
+		set_ul_mtu(0, false);
+	}
+	spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+	if (bam_ch_is_remote_open(rx_hdr->ch_id)) {
+		/*
+		 * Receiving an open command for a channel that is already open
+		 * is an invalid operation and likely signifies a significant
+		 * issue within the A2 which should be caught immediately
+		 * before it snowballs and the root cause is lost.
+		 */
+		panic("A2 sent invalid duplicate open for channel %d\n",
+								rx_hdr->ch_id);
+	}
+	bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
+	bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
+	spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+	ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
+	if (ret)
+		pr_err("%s: platform_device_add() error: %d\n",
+				__func__, ret);
+	mutex_unlock(&bam_pdev_mutexlock);
+	queue_rx();
+}
+
+static void handle_bam_mux_cmd(struct work_struct *work)
+{
+	unsigned long flags;
+	struct bam_mux_hdr *rx_hdr;
+	struct rx_pkt_info *info;
+	struct sk_buff *rx_skb;
+	uint16_t sps_size;
+
+	info = container_of(work, struct rx_pkt_info, work);
+	rx_skb = info->skb;
+	dma_unmap_single(dma_dev, info->dma_address, info->len,
+			bam_ops->dma_from);
+	sps_size = info->sps_size;
+	kfree(info);
+
+	rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+
+	DBG_INC_READ_CNT(sizeof(struct bam_mux_hdr));
+	DBG("%s: magic %x signal %x cmd %d pad %d ch %d len %d\n", __func__,
+			rx_hdr->magic_num, rx_hdr->signal, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+	if (rx_hdr->magic_num != BAM_MUX_HDR_MAGIC_NO) {
+		DMUX_LOG_KERR(
+			"%s: dropping invalid hdr. magic %x signal %x cmd %d pad %d ch %d len %d\n",
+			__func__, rx_hdr->magic_num, rx_hdr->signal,
+			rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+			rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+
+	if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+		DMUX_LOG_KERR(
+			"%s: dropping invalid LCID %d signal %x cmd %d pad %d ch %d len %d\n",
+			__func__, rx_hdr->ch_id, rx_hdr->signal, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+
+	switch (rx_hdr->cmd) {
+	case BAM_MUX_HDR_CMD_DATA:
+		if (rx_hdr->pkt_len == 0xffff)
+			/* SPS includes the header bytes, need just payload */
+			rx_hdr->pkt_len = sps_size - sizeof(*rx_hdr);
+		DBG_INC_READ_CNT(rx_hdr->pkt_len);
+		bam_mux_process_data(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_OPEN:
+		BAM_DMUX_LOG("%s: opening cid %d PC enabled\n", __func__,
+				rx_hdr->ch_id);
+		handle_bam_mux_cmd_open(rx_hdr);
+		dev_kfree_skb_any(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
+		BAM_DMUX_LOG("%s: opening cid %d PC disabled\n", __func__,
+				rx_hdr->ch_id);
+
+		if (!a2_pc_disabled) {
+			a2_pc_disabled = 1;
+			ul_wakeup();
+		}
+
+		handle_bam_mux_cmd_open(rx_hdr);
+		dev_kfree_skb_any(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_CLOSE:
+		/* probably should drop pending write */
+		BAM_DMUX_LOG("%s: closing cid %d\n", __func__,
+				rx_hdr->ch_id);
+		mutex_lock(&bam_pdev_mutexlock);
+		if (in_global_reset) {
+			BAM_DMUX_LOG("%s: close cid %d aborted due to ssr\n",
+					__func__, rx_hdr->ch_id);
+			mutex_unlock(&bam_pdev_mutexlock);
+			break;
+		}
+		spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+		bam_ch[rx_hdr->ch_id].status &= ~BAM_CH_REMOTE_OPEN;
+		spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+		platform_device_unregister(bam_ch[rx_hdr->ch_id].pdev);
+		bam_ch[rx_hdr->ch_id].pdev =
+			platform_device_alloc(bam_ch[rx_hdr->ch_id].name, 2);
+		if (!bam_ch[rx_hdr->ch_id].pdev)
+			pr_err("%s: platform_device_alloc failed\n", __func__);
+		mutex_unlock(&bam_pdev_mutexlock);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		break;
+	default:
+		DMUX_LOG_KERR(
+			"%s: dropping invalid hdr. magic %x signal %x cmd %d pad %d ch %d len %d\n",
+			__func__, rx_hdr->magic_num, rx_hdr->signal,
+			rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+			rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+}
+
+static int bam_mux_write_cmd(void *data, uint32_t len)
+{
+	int rc;
+	struct tx_pkt_info *pkt;
+	dma_addr_t dma_address;
+	unsigned long flags;
+
+	pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+	if (pkt == NULL) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	dma_address = dma_map_single(dma_dev, data, len,
+					bam_ops->dma_to);
+	if (!dma_address) {
+		pr_err("%s: dma_map_single() failed\n", __func__);
+		kfree(pkt);
+		rc = -ENOMEM;
+		return rc;
+	}
+	pkt->skb = (struct sk_buff *)(data);
+	pkt->len = len;
+	pkt->dma_address = dma_address;
+	pkt->is_cmd = 1;
+	set_tx_timestamp(pkt);
+	INIT_WORK(&pkt->work, bam_mux_write_done);
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_add_tail(&pkt->list_node, &bam_tx_pool);
+	rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, len,
+				pkt, SPS_IOVEC_FLAG_EOT);
+	if (rc) {
+		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+			__func__, rc);
+		list_del(&pkt->list_node);
+		DBG_INC_TX_SPS_FAILURE_CNT();
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		dma_unmap_single(dma_dev, pkt->dma_address,
+					pkt->len,
+					bam_ops->dma_to);
+		kfree(pkt);
+	} else {
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+	}
+
+	ul_packet_written = 1;
+	return rc;
+}
+
+static void bam_mux_write_done(struct work_struct *work)
+{
+	struct sk_buff *skb;
+	struct bam_mux_hdr *hdr;
+	struct tx_pkt_info *info;
+	struct tx_pkt_info *info_expected;
+	unsigned long event_data;
+	unsigned long flags;
+
+	if (in_global_reset)
+		return;
+
+	info = container_of(work, struct tx_pkt_info, work);
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	info_expected = list_first_entry(&bam_tx_pool,
+			struct tx_pkt_info, list_node);
+	if (unlikely(info != info_expected)) {
+		struct tx_pkt_info *errant_pkt;
+
+		BAM_DMUX_LOG(
+				"%s: bam_tx_pool mismatch .next=%pK, list_node=%pK, ts=%u.%09lu\n",
+				__func__, bam_tx_pool.next, &info->list_node,
+				info->ts_sec, info->ts_nsec
+				);
+
+		list_for_each_entry(errant_pkt, &bam_tx_pool, list_node) {
+			BAM_DMUX_LOG("%s: node=%pK ts=%u.%09lu\n", __func__,
+			&errant_pkt->list_node, errant_pkt->ts_sec,
+			errant_pkt->ts_nsec);
+
+		}
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		WARN_ON(1);
+	}
+	list_del(&info->list_node);
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	if (info->is_cmd) {
+		kfree(info->skb);
+		kfree(info);
+		return;
+	}
+	skb = info->skb;
+	kfree(info);
+	hdr = (struct bam_mux_hdr *)skb->data;
+	DBG_INC_WRITE_CNT(skb->len);
+	/* Restore skb for client */
+	skb_pull(skb, sizeof(*hdr));
+	if (hdr->pad_len)
+		skb_trim(skb, skb->len - hdr->pad_len);
+
+	event_data = (unsigned long)(skb);
+	spin_lock_irqsave(&bam_ch[hdr->ch_id].lock, flags);
+	bam_ch[hdr->ch_id].num_tx_pkts--;
+	spin_unlock_irqrestore(&bam_ch[hdr->ch_id].lock, flags);
+	if (bam_ch[hdr->ch_id].notify)
+		bam_ch[hdr->ch_id].notify(
+			bam_ch[hdr->ch_id].priv, BAM_DMUX_WRITE_DONE,
+							event_data);
+	else
+		dev_kfree_skb_any(skb);
+}
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	int rc = 0;
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	struct sk_buff *new_skb = NULL;
+	dma_addr_t dma_address;
+	struct tx_pkt_info *pkt;
+	int rcu_id;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	if (!skb)
+		return -EINVAL;
+	if (!bam_mux_initialized)
+		return -ENODEV;
+
+	rcu_id = srcu_read_lock(&bam_dmux_srcu);
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: In SSR... ch_id[%d]\n", __func__, id);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+		return -EFAULT;
+	}
+
+	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	if (!bam_ch_is_open(id)) {
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+		return -ENODEV;
+	}
+
+	if (bam_ch[id].use_wm &&
+	    (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		pr_err("%s: watermark exceeded: %d\n", __func__, id);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+		return -EAGAIN;
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		atomic_inc(&ul_ondemand_vote);
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1)) {
+			srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+			atomic_dec(&ul_ondemand_vote);
+			return -EFAULT;
+		}
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+		atomic_dec(&ul_ondemand_vote);
+	}
+
+	/* if skb do not have any tailroom for padding,
+	 * copy the skb into a new expanded skb
+	 */
+	if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
+		/* revisit, probably dev_alloc_skb and memcpy is effecient */
+		new_skb = skb_copy_expand(skb, skb_headroom(skb),
+					  4 - (skb->len & 0x3), GFP_ATOMIC);
+		if (new_skb == NULL) {
+			pr_err("%s: cannot allocate skb\n", __func__);
+			goto write_fail;
+		}
+		dev_kfree_skb_any(skb);
+		skb = new_skb;
+		DBG_INC_WRITE_CPY(skb->len);
+	}
+
+	hdr = (struct bam_mux_hdr *)skb_push(skb, sizeof(struct bam_mux_hdr));
+
+	/* caller should allocate for hdr and padding
+	 * hdr is fine, padding is tricky
+	 */
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+	hdr->signal = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = skb->len - sizeof(struct bam_mux_hdr);
+	if (skb->len & 0x3)
+		skb_put(skb, 4 - (skb->len & 0x3));
+
+	hdr->pad_len = skb->len - (sizeof(struct bam_mux_hdr) + hdr->pkt_len);
+
+	DBG("%s: data %pK, tail %pK skb len %d pkt len %d pad len %d\n",
+	    __func__, skb->data, skb_tail_pointer(skb), skb->len,
+	    hdr->pkt_len, hdr->pad_len);
+
+	pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+	if (pkt == NULL)
+		goto write_fail2;
+
+	dma_address = dma_map_single(dma_dev, skb->data, skb->len,
+					bam_ops->dma_to);
+	if (!dma_address) {
+		pr_err("%s: dma_map_single() failed\n", __func__);
+		goto write_fail3;
+	}
+	pkt->skb = skb;
+	pkt->dma_address = dma_address;
+	pkt->is_cmd = 0;
+	set_tx_timestamp(pkt);
+	INIT_WORK(&pkt->work, bam_mux_write_done);
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_add_tail(&pkt->list_node, &bam_tx_pool);
+	rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, skb->len,
+				pkt, SPS_IOVEC_FLAG_EOT);
+	if (rc) {
+		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+			__func__, rc);
+		list_del(&pkt->list_node);
+		DBG_INC_TX_SPS_FAILURE_CNT();
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		dma_unmap_single(dma_dev, pkt->dma_address,
+					pkt->skb->len,	bam_ops->dma_to);
+		kfree(pkt);
+		if (new_skb)
+			dev_kfree_skb_any(new_skb);
+	} else {
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		spin_lock_irqsave(&bam_ch[id].lock, flags);
+		bam_ch[id].num_tx_pkts++;
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+	}
+	ul_packet_written = 1;
+	read_unlock(&ul_wakeup_lock);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+	return rc;
+
+write_fail3:
+	kfree(pkt);
+write_fail2:
+	skb_pull(skb, sizeof(struct bam_mux_hdr));
+	if (new_skb)
+		dev_kfree_skb_any(new_skb);
+write_fail:
+	read_unlock(&ul_wakeup_lock);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+	return -ENOMEM;
+}
+
+/**
+ * create_open_signal() - Generate a proper signal field for outgoing open cmds
+ *
+ * A properly constructed signal field of the mux header for opem commands semt
+ * to the remote side depend on what has been locally configured, and what has
+ * been received from the remote side.  The byte value to code translations
+ * must match the valid values in set_rx_buffer_ring_pool() and set_dl_mtu().
+ *
+ * Return: A properly constructed signal field for an outgoing mux open command.
+ */
+static uint8_t create_open_signal(void)
+{
+	uint8_t signal = 0;
+	uint8_t buff_count = 0;
+	uint8_t dl_size = 0;
+
+	if (!dynamic_mtu_enabled)
+		return signal;
+
+	signal = DYNAMIC_MTU_MASK;
+
+	switch (num_buffers) {
+	case SZ_256:
+		buff_count = 3;
+		break;
+	case SZ_128:
+		buff_count = 2;
+		break;
+	case SZ_64:
+		buff_count = 1;
+		break;
+	case SZ_32:
+		buff_count = 0;
+		break;
+	}
+
+	signal |= buff_count << DL_POOL_SIZE_SHIFT;
+
+	switch (dl_mtu) {
+	case SZ_16K:
+		dl_size = 3;
+		break;
+	case SZ_8K:
+		dl_size = 2;
+		break;
+	case SZ_4K:
+		dl_size = 1;
+		break;
+	case SZ_2K:
+		dl_size = 0;
+		break;
+	}
+
+	signal |= dl_size << MTU_SIZE_SHIFT;
+
+	return signal;
+}
+
+int msm_bam_dmux_open(uint32_t id, void *priv,
+			void (*notify)(void *, int, unsigned long))
+{
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	int rc = 0;
+
+	DBG("%s: opening ch %d\n", __func__, id);
+	if (!bam_mux_initialized) {
+		DBG("%s: not inititialized\n", __func__);
+		return -ENODEV;
+	}
+	if (id >= BAM_DMUX_NUM_CHANNELS) {
+		pr_err("%s: invalid channel id %d\n", __func__, id);
+		return -EINVAL;
+	}
+	if (notify == NULL) {
+		pr_err("%s: notify function is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_KERNEL);
+	if (hdr == NULL)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	if (bam_ch_is_open(id)) {
+		DBG("%s: Already opened %d\n", __func__, id);
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		kfree(hdr);
+		goto open_done;
+	}
+	if (!bam_ch_is_remote_open(id)) {
+		DBG("%s: Remote not open; ch: %d\n", __func__, id);
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		kfree(hdr);
+		return -ENODEV;
+	}
+
+	bam_ch[id].notify = notify;
+	bam_ch[id].priv = priv;
+	bam_ch[id].status |= BAM_CH_LOCAL_OPEN;
+	bam_ch[id].num_tx_pkts = 0;
+	bam_ch[id].use_wm = 0;
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	notify(priv, BAM_DMUX_TRANSMIT_SIZE, ul_mtu);
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		atomic_inc(&ul_ondemand_vote);
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1)) {
+			atomic_dec(&ul_ondemand_vote);
+			kfree(hdr);
+			return -EFAULT;
+		}
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+		atomic_dec(&ul_ondemand_vote);
+	}
+
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_OPEN;
+	hdr->signal = create_open_signal();
+	hdr->ch_id = id;
+	hdr->pkt_len = 0;
+	hdr->pad_len = 0;
+
+	rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+	read_unlock(&ul_wakeup_lock);
+
+open_done:
+	DBG("%s: opened ch %d\n", __func__, id);
+	return rc;
+}
+
+int msm_bam_dmux_close(uint32_t id)
+{
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	int rc;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	DBG("%s: closing ch %d\n", __func__, id);
+	if (!bam_mux_initialized || !bam_ch_is_local_open(id))
+		return -ENODEV;
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected && !bam_ch_is_in_reset(id)) {
+		atomic_inc(&ul_ondemand_vote);
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1)) {
+			atomic_dec(&ul_ondemand_vote);
+			return -EFAULT;
+		}
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+		atomic_dec(&ul_ondemand_vote);
+	}
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].notify = NULL;
+	bam_ch[id].priv = NULL;
+	bam_ch[id].status &= ~BAM_CH_LOCAL_OPEN;
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	if (bam_ch_is_in_reset(id)) {
+		read_unlock(&ul_wakeup_lock);
+		bam_ch[id].status &= ~BAM_CH_IN_RESET;
+		return 0;
+	}
+
+	hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_ATOMIC);
+	if (hdr == NULL) {
+		read_unlock(&ul_wakeup_lock);
+		return -ENOMEM;
+	}
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_CLOSE;
+	hdr->signal = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = 0;
+	hdr->pad_len = 0;
+
+	rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+	read_unlock(&ul_wakeup_lock);
+
+	DBG("%s: closed ch %d\n", __func__, id);
+	return rc;
+}
+
+int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].use_wm = 1;
+	ret = bam_ch[id].num_tx_pkts >= HIGH_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
+	     id, bam_ch[id].num_tx_pkts, ret);
+	if (!bam_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	return ret;
+}
+
+int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].use_wm = 1;
+	ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
+	     id, bam_ch[id].num_tx_pkts, ret);
+	if (!bam_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	return ret;
+}
+
+static void rx_switch_to_interrupt_mode(void)
+{
+	struct sps_connect cur_rx_conn;
+	struct sps_iovec iov;
+	struct rx_pkt_info *info;
+	int ret;
+
+	/*
+	 * Attempt to enable interrupts - if this fails,
+	 * continue polling and we will retry later.
+	 */
+	ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	rx_register_event.options = SPS_O_EOT;
+	ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
+	if (ret) {
+		pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+		SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+	ret = bam_ops->sps_set_config_ptr(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+	polling_mode = 0;
+	complete_all(&shutdown_completion);
+	release_wakelock();
+
+	/* handle any rx packets before interrupt was enabled */
+	while (bam_connection_is_active && !polling_mode) {
+		ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
+		if (ret) {
+			pr_err("%s: sps_get_iovec failed %d\n",
+					__func__, ret);
+			break;
+		}
+		if (iov.addr == 0)
+			break;
+
+		mutex_lock(&bam_rx_pool_mutexlock);
+		if (unlikely(list_empty(&bam_rx_pool))) {
+			DMUX_LOG_KERR("%s: have iovec %pK but rx pool empty\n",
+				__func__, (void *)(uintptr_t)iov.addr);
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			continue;
+		}
+		info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
+							list_node);
+		if (info->dma_address != iov.addr) {
+			DMUX_LOG_KERR("%s: iovec %pK != dma %pK\n",
+				__func__,
+				(void *)(uintptr_t)iov.addr,
+				(void *)(uintptr_t)info->dma_address);
+			list_for_each_entry(info, &bam_rx_pool, list_node) {
+				DMUX_LOG_KERR("%s: dma %pK\n", __func__,
+					(void *)(uintptr_t)info->dma_address);
+				if (iov.addr == info->dma_address)
+					break;
+			}
+		}
+		WARN_ON(info->dma_address != iov.addr);
+		list_del(&info->list_node);
+		--bam_rx_pool_len;
+		mutex_unlock(&bam_rx_pool_mutexlock);
+		info->sps_size = iov.size;
+		handle_bam_mux_cmd(&info->work);
+	}
+	return;
+
+fail:
+	pr_err("%s: reverting to polling\n", __func__);
+	if (no_cpu_affinity)
+		queue_work(bam_mux_rx_workqueue, &rx_timer_work);
+	else
+		queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
+}
+
+/**
+ * store_rx_timestamp() - store the current raw time as as a timestamp for when
+ *			the last rx packet was processed
+ */
+static void store_rx_timestamp(void)
+{
+	last_rx_pkt_timestamp = sched_clock();
+}
+
+/**
+ * log_rx_timestamp() - Log the stored rx pkt timestamp in a human readable
+ *			format
+ */
+static void log_rx_timestamp(void)
+{
+	unsigned long long t = last_rx_pkt_timestamp;
+	unsigned long nanosec_rem;
+
+	nanosec_rem = do_div(t, 1000000000U);
+	BAM_DMUX_LOG("Last rx pkt processed at [%6u.%09lu]\n", (unsigned int)t,
+								nanosec_rem);
+}
+
+static void rx_timer_work_func(struct work_struct *work)
+{
+	struct sps_iovec iov;
+	struct rx_pkt_info *info;
+	int inactive_cycles = 0;
+	int ret;
+	u32 buffs_unused, buffs_used;
+
+	BAM_DMUX_LOG("%s: polling start\n", __func__);
+	while (bam_connection_is_active) { /* timer loop */
+		++inactive_cycles;
+		while (bam_connection_is_active) { /* deplete queue loop */
+			if (in_global_reset) {
+				BAM_DMUX_LOG(
+						"%s: polling exit, global reset detected\n",
+						__func__);
+				return;
+			}
+
+			ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
+			if (ret) {
+				DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
+						__func__, ret);
+				break;
+			}
+			if (iov.addr == 0)
+				break;
+			store_rx_timestamp();
+			inactive_cycles = 0;
+			mutex_lock(&bam_rx_pool_mutexlock);
+			if (unlikely(list_empty(&bam_rx_pool))) {
+				DMUX_LOG_KERR(
+					"%s:have iovec %pK but rx pool empty\n",
+					__func__, (void *)(uintptr_t)iov.addr);
+				mutex_unlock(&bam_rx_pool_mutexlock);
+				continue;
+			}
+			info = list_first_entry(&bam_rx_pool,
+					struct rx_pkt_info,	list_node);
+			if (info->dma_address != iov.addr) {
+				DMUX_LOG_KERR("%s: iovec %pK != dma %pK\n",
+					__func__,
+					(void *)(uintptr_t)iov.addr,
+					(void *)(uintptr_t)info->dma_address);
+				list_for_each_entry(info, &bam_rx_pool,
+						list_node) {
+					DMUX_LOG_KERR("%s: dma %pK\n", __func__,
+						(void *)(uintptr_t)
+							info->dma_address);
+					if (iov.addr == info->dma_address)
+						break;
+				}
+			}
+			WARN_ON(info->dma_address != iov.addr);
+			list_del(&info->list_node);
+			--bam_rx_pool_len;
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			info->sps_size = iov.size;
+			handle_bam_mux_cmd(&info->work);
+		}
+
+		if (inactive_cycles >= POLLING_INACTIVITY) {
+			BAM_DMUX_LOG("%s: polling exit, no data\n", __func__);
+			rx_switch_to_interrupt_mode();
+			break;
+		}
+
+		if (bam_adaptive_timer_enabled) {
+			usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+			ret = bam_ops->sps_get_unused_desc_num_ptr(bam_rx_pipe,
+						&buffs_unused);
+
+			if (ret) {
+				DMUX_LOG_KERR(
+					"%s: error getting num buffers unused after sleep\n",
+					__func__);
+
+				break;
+			}
+
+			buffs_used = num_buffers - buffs_unused;
+
+			if (buffs_unused == 0) {
+				rx_timer_interval = MIN_POLLING_SLEEP;
+			} else {
+				if (buffs_used > 0) {
+					rx_timer_interval =
+						(2 * num_buffers *
+							rx_timer_interval)/
+						(3 * buffs_used);
+				} else {
+					rx_timer_interval =
+						MAX_POLLING_SLEEP;
+				}
+			}
+
+			if (rx_timer_interval > MAX_POLLING_SLEEP)
+				rx_timer_interval = MAX_POLLING_SLEEP;
+			else if (rx_timer_interval < MIN_POLLING_SLEEP)
+				rx_timer_interval = MIN_POLLING_SLEEP;
+		} else {
+			usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		}
+	}
+}
+
+static void bam_mux_tx_notify(struct sps_event_notify *notify)
+{
+	struct tx_pkt_info *pkt;
+
+	DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+	if (in_global_reset)
+		return;
+
+	switch (notify->event_id) {
+	case SPS_EVENT_EOT:
+		pkt = notify->data.transfer.user;
+		if (!pkt->is_cmd)
+			dma_unmap_single(dma_dev, pkt->dma_address,
+						pkt->skb->len,
+						bam_ops->dma_to);
+		else
+			dma_unmap_single(dma_dev, pkt->dma_address,
+						pkt->len,
+						bam_ops->dma_to);
+		queue_work(bam_mux_tx_workqueue, &pkt->work);
+		break;
+	default:
+		pr_err("%s: received unexpected event id %d\n", __func__,
+			notify->event_id);
+	}
+}
+
+static void bam_mux_rx_notify(struct sps_event_notify *notify)
+{
+	int ret;
+	struct sps_connect cur_rx_conn;
+
+	DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+	if (in_global_reset)
+		return;
+
+	switch (notify->event_id) {
+	case SPS_EVENT_EOT:
+		/* attempt to disable interrupts in this pipe */
+		if (!polling_mode) {
+			ret = bam_ops->sps_get_config_ptr(bam_rx_pipe,
+					&cur_rx_conn);
+			if (ret) {
+				pr_err("%s: sps_get_config() failed %d, interrupts not disabled\n",
+					__func__, ret);
+				break;
+			}
+			cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+			ret = bam_ops->sps_set_config_ptr(bam_rx_pipe,
+					&cur_rx_conn);
+			if (ret) {
+				pr_err("%s: sps_set_config() failed %d, interrupts not disabled\n",
+					__func__, ret);
+				break;
+			}
+			reinit_completion(&shutdown_completion);
+			grab_wakelock();
+			polling_mode = 1;
+			/*
+			 * run on core 0 so that netif_rx() in rmnet uses only
+			 * one queue if RPS enable use no_cpu_affinity
+			 */
+			if (no_cpu_affinity)
+				queue_work(bam_mux_rx_workqueue,
+							&rx_timer_work);
+			else
+				queue_work_on(0, bam_mux_rx_workqueue,
+							&rx_timer_work);
+		}
+		break;
+	default:
+		pr_err("%s: received unexpected event id %d\n", __func__,
+			notify->event_id);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_tbl(char *buf, int max)
+{
+	int i = 0;
+	int j;
+
+	for (j = 0; j < BAM_DMUX_NUM_CHANNELS; ++j) {
+		i += scnprintf(buf + i, max - i,
+			"ch%02d  local open=%s  remote open=%s\n",
+			j, bam_ch_is_local_open(j) ? "Y" : "N",
+			bam_ch_is_remote_open(j) ? "Y" : "N");
+	}
+
+	return i;
+}
+
+static int debug_ul_pkt_cnt(char *buf, int max)
+{
+	struct list_head *p;
+	unsigned long flags;
+	int n = 0;
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_for_each(p, &bam_tx_pool) {
+		++n;
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	return scnprintf(buf, max, "Number of UL packets in flight: %d\n", n);
+}
+
+static int debug_stats(char *buf, int max)
+{
+	int i = 0;
+
+	i += scnprintf(buf + i, max - i,
+			"skb read cnt:    %u\n"
+			"skb write cnt:   %u\n"
+			"skb copy cnt:    %u\n"
+			"skb copy bytes:  %u\n"
+			"sps tx failures: %u\n"
+			"sps tx stalls:   %u\n"
+			"rx queue len:    %d\n"
+			"a2 ack out cnt:  %d\n"
+			"a2 ack in cnt:   %d\n"
+			"a2 pwr cntl in:  %d\n",
+			bam_dmux_read_cnt,
+			bam_dmux_write_cnt,
+			bam_dmux_write_cpy_cnt,
+			bam_dmux_write_cpy_bytes,
+			bam_dmux_tx_sps_failure_cnt,
+			bam_dmux_tx_stall_cnt,
+			bam_rx_pool_len,
+			atomic_read(&bam_dmux_ack_out_cnt),
+			atomic_read(&bam_dmux_ack_in_cnt),
+			atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
+			);
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+				struct dentry *dent,
+				int (*fill)(char *buf, int max))
+{
+	struct dentry *file;
+
+	file = debugfs_create_file(name, mode, dent, fill, &debug_ops);
+	if (IS_ERR(file))
+		pr_err("%s: debugfs create failed %d\n", __func__,
+				(int)PTR_ERR(file));
+}
+
+#endif
+
+static void notify_all(int event, unsigned long data)
+{
+	int i;
+	unsigned long flags;
+	struct list_head *temp;
+	struct outside_notify_func *func;
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+
+	BAM_DMUX_LOG("%s: event=%d, data=%lu\n", __func__, event, data);
+
+	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+		notify = NULL;
+		priv = NULL;
+		spin_lock_irqsave(&bam_ch[i].lock, flags);
+		if (bam_ch_is_open(i)) {
+			notify = bam_ch[i].notify;
+			priv = bam_ch[i].priv;
+		}
+		spin_unlock_irqrestore(&bam_ch[i].lock, flags);
+		if (notify)
+			notify(priv, event, data);
+	}
+
+	list_for_each(temp, &bam_other_notify_funcs) {
+		func = container_of(temp, struct outside_notify_func,
+								list_node);
+		func->notify(func->priv, event, data);
+	}
+}
+
+static void kickoff_ul_wakeup_func(struct work_struct *work)
+{
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		atomic_inc(&ul_ondemand_vote);
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1)) {
+			atomic_dec(&ul_ondemand_vote);
+			return;
+		}
+		read_lock(&ul_wakeup_lock);
+		ul_packet_written = 1;
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+		atomic_dec(&ul_ondemand_vote);
+	}
+	read_unlock(&ul_wakeup_lock);
+}
+
+int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	int is_connected;
+
+	read_lock(&ul_wakeup_lock);
+	ul_packet_written = 1;
+	is_connected = bam_is_connected;
+	if (!is_connected)
+		queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+	read_unlock(&ul_wakeup_lock);
+
+	return is_connected;
+}
+
+static void power_vote(int vote)
+{
+	BAM_DMUX_LOG("%s: curr=%d, vote=%d\n", __func__,
+			bam_dmux_uplink_vote, vote);
+
+	if (bam_dmux_uplink_vote == vote)
+		BAM_DMUX_LOG("%s: warning - duplicate power vote\n", __func__);
+
+	bam_dmux_uplink_vote = vote;
+	if (vote)
+		bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+			0, SMSM_A2_POWER_CONTROL);
+	else
+		bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+			SMSM_A2_POWER_CONTROL, 0);
+}
+
+/*
+ * @note:  Must be called with ul_wakeup_lock locked.
+ */
+static inline void ul_powerdown(void)
+{
+	BAM_DMUX_LOG("%s: powerdown\n", __func__);
+	verify_tx_queue_is_empty(__func__);
+
+	if (a2_pc_disabled) {
+		wait_for_dfab = 1;
+		reinit_completion(&dfab_unvote_completion);
+		release_wakelock();
+	} else {
+		wait_for_ack = 1;
+		reinit_completion(&ul_wakeup_ack_completion);
+		power_vote(0);
+	}
+	bam_is_connected = 0;
+	notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+}
+
+static inline void ul_powerdown_finish(void)
+{
+	if (a2_pc_disabled && wait_for_dfab) {
+		unvote_dfab();
+		complete_all(&dfab_unvote_completion);
+		wait_for_dfab = 0;
+	}
+}
+
+/*
+ * Votes for UL power and returns current power state.
+ *
+ * @returns true if currently connected
+ */
+int msm_bam_dmux_ul_power_vote(void)
+{
+	int is_connected;
+
+	read_lock(&ul_wakeup_lock);
+	atomic_inc(&ul_ondemand_vote);
+	is_connected = bam_is_connected;
+	if (!is_connected)
+		queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+	read_unlock(&ul_wakeup_lock);
+
+	return is_connected;
+}
+
+/*
+ * Unvotes for UL power.
+ *
+ * @returns true if vote count is 0 (UL shutdown possible)
+ */
+int msm_bam_dmux_ul_power_unvote(void)
+{
+	int vote;
+
+	read_lock(&ul_wakeup_lock);
+	vote = atomic_dec_return(&ul_ondemand_vote);
+	if (unlikely(vote < 0))
+		DMUX_LOG_KERR("%s: invalid power vote %d\n", __func__, vote);
+	read_unlock(&ul_wakeup_lock);
+
+	return vote == 0;
+}
+
+int msm_bam_dmux_reg_notify(void *priv,
+			void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	struct outside_notify_func *func;
+
+	if (!notify)
+		return -EINVAL;
+
+	func = kmalloc(sizeof(struct outside_notify_func), GFP_KERNEL);
+	if (!func)
+		return -ENOMEM;
+
+	func->notify = notify;
+	func->priv = priv;
+	list_add(&func->list_node, &bam_other_notify_funcs);
+
+	return 0;
+}
+
+static void ul_timeout(struct work_struct *work)
+{
+	unsigned long flags;
+	int ret;
+
+	if (in_global_reset)
+		return;
+	ret = write_trylock_irqsave(&ul_wakeup_lock, flags);
+	if (!ret) { /* failed to grab lock, reschedule and bail */
+		schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(ul_timeout_delay));
+		return;
+	}
+	if (bam_is_connected) {
+		if (!ul_packet_written) {
+			spin_lock(&bam_tx_pool_spinlock);
+			if (!list_empty(&bam_tx_pool)) {
+				struct tx_pkt_info *info;
+
+				info = list_first_entry(&bam_tx_pool,
+						struct tx_pkt_info, list_node);
+				DMUX_LOG_KERR("%s: UL delayed ts=%u.%09lu\n",
+					__func__, info->ts_sec, info->ts_nsec);
+				DBG_INC_TX_STALL_CNT();
+				ul_packet_written = 1;
+			}
+			spin_unlock(&bam_tx_pool_spinlock);
+		}
+
+		if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
+			BAM_DMUX_LOG("%s: pkt written %d\n",
+				__func__, ul_packet_written);
+			ul_packet_written = 0;
+			schedule_delayed_work(&ul_timeout_work,
+					msecs_to_jiffies(ul_timeout_delay));
+		} else {
+			ul_powerdown();
+		}
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+}
+
+static int ssrestart_check(void)
+{
+	int ret = 0;
+
+	if (in_global_reset) {
+		DMUX_LOG_KERR("%s: already in SSR\n",
+			__func__);
+		return 1;
+	}
+
+	DMUX_LOG_KERR(
+		"%s: fatal modem interaction: BAM DMUX disabled for SSR\n",
+								__func__);
+	in_global_reset = 1;
+	ret = subsystem_restart("modem");
+	if (ret == -ENODEV)
+		panic("modem subsystem restart failed\n");
+	return 1;
+}
+
+static void ul_wakeup(void)
+{
+	int ret;
+	int do_vote_dfab = 0;
+
+	mutex_lock(&wakeup_lock);
+	if (bam_is_connected) { /* bam got connected before lock grabbed */
+		BAM_DMUX_LOG("%s Already awake\n", __func__);
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
+	 * if this gets hit, that means restart_notifier_cb() has started
+	 * but probably not finished, thus we know SSR has happened, but
+	 * haven't been able to send that info to our clients yet.
+	 * in that case, abort the ul_wakeup() so that we don't undo any
+	 * work restart_notifier_cb() has done.  The clients will be notified
+	 * shortly.  No cleanup necessary (reschedule the wakeup) as our and
+	 * their SSR handling will cover it
+	 */
+	if (unlikely(in_global_reset == 1)) {
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
+	 * if someone is voting for UL before bam is inited (modem up first
+	 * time), set flag for init to kickoff ul wakeup once bam is inited
+	 */
+	mutex_lock(&delayed_ul_vote_lock);
+	if (unlikely(!bam_mux_initialized)) {
+		need_delayed_ul_vote = 1;
+		mutex_unlock(&delayed_ul_vote_lock);
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+
+	if (a2_pc_disabled) {
+		/*
+		 * don't grab the wakelock the first time because it is
+		 * already grabbed when a2 powers on
+		 */
+		if (likely(a2_pc_disabled_wakelock_skipped)) {
+			grab_wakelock();
+			do_vote_dfab = 1; /* vote must occur after wait */
+		} else {
+			a2_pc_disabled_wakelock_skipped = 1;
+		}
+		if (wait_for_dfab) {
+			ret = wait_for_completion_timeout(
+					&dfab_unvote_completion, HZ);
+			WARN_ON(ret == 0);
+		}
+		if (likely(do_vote_dfab))
+			vote_dfab();
+		schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(ul_timeout_delay));
+		bam_is_connected = 1;
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
+	 * must wait for the previous power down request to have been acked
+	 * chances are it already came in and this will just fall through
+	 * instead of waiting
+	 */
+	if (wait_for_ack) {
+		BAM_DMUX_LOG("%s waiting for previous ack\n", __func__);
+		ret = wait_for_completion_timeout(
+					&ul_wakeup_ack_completion,
+					msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+		wait_for_ack = 0;
+		if (unlikely(in_global_reset == 1)
+			|| (unlikely(ret == 0) && ssrestart_check())) {
+			mutex_unlock(&wakeup_lock);
+			BAM_DMUX_LOG("%s timeout previous ack\n", __func__);
+			return;
+		}
+	}
+	reinit_completion(&ul_wakeup_ack_completion);
+	power_vote(1);
+	BAM_DMUX_LOG("%s waiting for wakeup ack\n", __func__);
+	ret = wait_for_completion_timeout(&ul_wakeup_ack_completion,
+					msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+	if (unlikely(in_global_reset == 1)
+		|| (unlikely(ret == 0) && ssrestart_check())) {
+		mutex_unlock(&wakeup_lock);
+		BAM_DMUX_LOG("%s timeout wakeup ack\n", __func__);
+		return;
+	}
+	BAM_DMUX_LOG("%s waiting completion\n", __func__);
+	ret = wait_for_completion_timeout(&bam_connection_completion,
+					msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
+	if (unlikely(in_global_reset == 1)
+		|| (unlikely(ret == 0) && ssrestart_check())) {
+		mutex_unlock(&wakeup_lock);
+		BAM_DMUX_LOG("%s timeout power on\n", __func__);
+		return;
+	}
+
+	bam_is_connected = 1;
+	BAM_DMUX_LOG("%s complete\n", __func__);
+	schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(ul_timeout_delay));
+	mutex_unlock(&wakeup_lock);
+}
+
+static void reconnect_to_bam(void)
+{
+	int i;
+
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: skipping due to SSR\n", __func__);
+		return;
+	}
+
+	vote_dfab();
+
+	if (ssr_skipped_disconnect) {
+		/* delayed to here to prevent bus stall */
+		bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+		bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+		memset(rx_desc_mem_buf.base, 0, rx_desc_mem_buf.size);
+		memset(tx_desc_mem_buf.base, 0, tx_desc_mem_buf.size);
+	}
+	ssr_skipped_disconnect = 0;
+	i = bam_ops->sps_device_reset_ptr(a2_device_handle);
+	if (i)
+		pr_err("%s: device reset failed rc = %d\n", __func__,
+								i);
+	i = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
+	if (i)
+		pr_err("%s: tx connection failed rc = %d\n", __func__,
+								i);
+	i = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
+	if (i)
+		pr_err("%s: rx connection failed rc = %d\n", __func__,
+								i);
+	i = bam_ops->sps_register_event_ptr(bam_tx_pipe,
+			&tx_register_event);
+	if (i)
+		pr_err("%s: tx event reg failed rc = %d\n", __func__,
+								i);
+	i = bam_ops->sps_register_event_ptr(bam_rx_pipe,
+			&rx_register_event);
+	if (i)
+		pr_err("%s: rx event reg failed rc = %d\n", __func__,
+									i);
+	bam_connection_is_active = 1;
+
+	if (polling_mode)
+		rx_switch_to_interrupt_mode();
+
+	toggle_apps_ack();
+	complete_all(&bam_connection_completion);
+	queue_rx();
+}
+
+static void disconnect_to_bam(void)
+{
+	struct list_head *node;
+	struct rx_pkt_info *info;
+	unsigned long flags;
+	unsigned long time_remaining;
+
+	if (!in_global_reset) {
+		time_remaining = wait_for_completion_timeout(
+				&shutdown_completion,
+				msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+		if (time_remaining == 0) {
+			DMUX_LOG_KERR("%s: shutdown completion timed out\n",
+					__func__);
+			log_rx_timestamp();
+			ssrestart_check();
+		}
+	}
+
+	bam_connection_is_active = 0;
+
+	/* handle disconnect during active UL */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		BAM_DMUX_LOG("%s: UL active - forcing powerdown\n", __func__);
+		ul_powerdown();
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+
+	/* tear down BAM connection */
+	reinit_completion(&bam_connection_completion);
+
+	/* documentation/assumptions found in restart_notifier_cb */
+	if (likely(!in_global_reset)) {
+		BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
+		bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+		BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
+		bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+		memset(rx_desc_mem_buf.base, 0, rx_desc_mem_buf.size);
+		memset(tx_desc_mem_buf.base, 0, tx_desc_mem_buf.size);
+		BAM_DMUX_LOG("%s: device reset\n", __func__);
+		bam_ops->sps_device_reset_ptr(a2_device_handle);
+	} else {
+		ssr_skipped_disconnect = 1;
+	}
+	unvote_dfab();
+
+	mutex_lock(&bam_rx_pool_mutexlock);
+	while (!list_empty(&bam_rx_pool)) {
+		node = bam_rx_pool.next;
+		list_del(node);
+		info = container_of(node, struct rx_pkt_info, list_node);
+		dma_unmap_single(dma_dev, info->dma_address, info->len,
+							bam_ops->dma_from);
+		dev_kfree_skb_any(info->skb);
+		kfree(info);
+	}
+	bam_rx_pool_len = 0;
+	mutex_unlock(&bam_rx_pool_mutexlock);
+	toggle_apps_ack();
+	verify_tx_queue_is_empty(__func__);
+}
+
+static void vote_dfab(void)
+{
+	int rc;
+
+	BAM_DMUX_LOG("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (dfab_is_on) {
+		BAM_DMUX_LOG("%s: dfab is already on\n", __func__);
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
+	if (dfab_clk) {
+		rc = clk_prepare_enable(dfab_clk);
+		if (rc)
+			DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n",
+									rc);
+	}
+	if (xo_clk) {
+		rc = clk_prepare_enable(xo_clk);
+		if (rc)
+			DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n",
+									rc);
+	}
+	dfab_is_on = 1;
+	mutex_unlock(&dfab_status_lock);
+}
+
+static void unvote_dfab(void)
+{
+	BAM_DMUX_LOG("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (!dfab_is_on) {
+		DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
+		dump_stack();
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
+	if (dfab_clk)
+		clk_disable_unprepare(dfab_clk);
+	if (xo_clk)
+		clk_disable_unprepare(xo_clk);
+	dfab_is_on = 0;
+	mutex_unlock(&dfab_status_lock);
+}
+
+/* reference counting wrapper around wakelock */
+static void grab_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	if (wakelock_reference_count == 0)
+		__pm_stay_awake(&bam_wakelock);
+	++wakelock_reference_count;
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static void release_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	if (wakelock_reference_count == 0) {
+		DMUX_LOG_KERR("%s: bam_dmux wakelock not locked\n", __func__);
+		dump_stack();
+		spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+		return;
+	}
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	--wakelock_reference_count;
+	if (wakelock_reference_count == 0)
+		__pm_relax(&bam_wakelock);
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data)
+{
+	int i;
+	struct list_head *node;
+	struct tx_pkt_info *info;
+	int temp_remote_status;
+	unsigned long flags;
+
+	/*
+	 * Bam_dmux counts on the fact that the BEFORE_SHUTDOWN level of
+	 * notifications are guaranteed to execute before the AFTER_SHUTDOWN
+	 * level of notifications, and that BEFORE_SHUTDOWN always occurs in
+	 * all SSR events, no matter what triggered the SSR.  Also, bam_dmux
+	 * assumes that SMD does its SSR processing in the AFTER_SHUTDOWN level
+	 * thus bam_dmux is guaranteed to detect SSR before SMD, since the
+	 * callbacks for all the drivers within the AFTER_SHUTDOWN level could
+	 * occur in any order.  Bam_dmux uses this knowledge to skip accessing
+	 * the bam hardware when disconnect_to_bam() is triggered by SMD's SSR
+	 * processing.  We do not wat to access the bam hardware during SSR
+	 * because a watchdog crash from a bus stall would likely occur.
+	 */
+	if (code == SUBSYS_BEFORE_SHUTDOWN) {
+		BAM_DMUX_LOG("%s: begin\n", __func__);
+		in_global_reset = 1;
+		/* wakeup ul_wakeup() thread*/
+		complete_all(&ul_wakeup_ack_completion);
+		complete_all(&bam_connection_completion);
+		/* sync to ensure the driver sees SSR */
+		synchronize_srcu(&bam_dmux_srcu);
+		BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
+		flush_workqueue(bam_mux_rx_workqueue);
+	}
+	if (code == SUBSYS_BEFORE_POWERUP)
+		in_global_reset = 0;
+	if (code != SUBSYS_AFTER_SHUTDOWN)
+		return NOTIFY_DONE;
+
+	/* Handle uplink Powerdown */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		ul_powerdown();
+		wait_for_ack = 0;
+	}
+	/*
+	 * if modem crash during ul_wakeup(), power_vote is 1, needs to be
+	 * reset to 0.  harmless if bam_is_connected check above passes
+	 */
+	power_vote(0);
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+	a2_pc_disabled = 0;
+	a2_pc_disabled_wakelock_skipped = 0;
+	process_dynamic_mtu(false);
+	set_ul_mtu(0, true);
+	dynamic_mtu_enabled = false;
+
+	/* Cleanup Channel States */
+	mutex_lock(&bam_pdev_mutexlock);
+	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+		temp_remote_status = bam_ch_is_remote_open(i);
+		bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
+		bam_ch[i].num_tx_pkts = 0;
+		if (bam_ch_is_local_open(i))
+			bam_ch[i].status |= BAM_CH_IN_RESET;
+		if (temp_remote_status) {
+			platform_device_unregister(bam_ch[i].pdev);
+			bam_ch[i].pdev = platform_device_alloc(
+						bam_ch[i].name, 2);
+		}
+	}
+	mutex_unlock(&bam_pdev_mutexlock);
+
+	/* Cleanup pending UL data */
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	while (!list_empty(&bam_tx_pool)) {
+		node = bam_tx_pool.next;
+		list_del(node);
+		info = container_of(node, struct tx_pkt_info,
+							list_node);
+		if (!info->is_cmd) {
+			dma_unmap_single(dma_dev, info->dma_address,
+						info->skb->len,
+						bam_ops->dma_to);
+			dev_kfree_skb_any(info->skb);
+		} else {
+			dma_unmap_single(dma_dev, info->dma_address,
+						info->len,
+						bam_ops->dma_to);
+			kfree(info->skb);
+		}
+		kfree(info);
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	BAM_DMUX_LOG("%s: complete\n", __func__);
+	return NOTIFY_DONE;
+}
+
+static int bam_init(void)
+{
+	unsigned long h;
+	dma_addr_t dma_addr;
+	int ret;
+	void *a2_virt_addr;
+	int skip_iounmap = 0;
+
+	in_global_reset = 0;
+	vote_dfab();
+	/* init BAM */
+	a2_virt_addr = ioremap_nocache(a2_phys_base, a2_phys_size);
+	if (!a2_virt_addr) {
+		pr_err("%s: ioremap failed\n", __func__);
+		ret = -ENOMEM;
+		goto ioremap_failed;
+	}
+	a2_props.phys_addr = a2_phys_base;
+	a2_props.virt_addr = a2_virt_addr;
+	a2_props.virt_size = a2_phys_size;
+	a2_props.irq = a2_bam_irq;
+	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP | SPS_BAM_HOLD_MEM;
+	a2_props.num_pipes = A2_NUM_PIPES;
+	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+	a2_props.constrained_logging = true;
+	a2_props.logging_number = 1;
+	a2_props.ipc_loglevel = 3;
+	if (satellite_mode)
+		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+	/* need to free on tear down */
+	ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
+	if (ret < 0) {
+		pr_err("%s: register bam error %d\n", __func__, ret);
+		goto register_bam_failed;
+	}
+	a2_device_handle = h;
+
+	bam_tx_pipe = bam_ops->sps_alloc_endpoint_ptr();
+	if (bam_tx_pipe == NULL) {
+		pr_err("%s: tx alloc endpoint failed\n", __func__);
+		ret = -ENOMEM;
+		goto tx_alloc_endpoint_failed;
+	}
+	ret = bam_ops->sps_get_config_ptr(bam_tx_pipe, &tx_connection);
+	if (ret) {
+		pr_err("%s: tx get config failed %d\n", __func__, ret);
+		goto tx_get_config_failed;
+	}
+
+	tx_connection.source = SPS_DEV_HANDLE_MEM;
+	tx_connection.src_pipe_index = 0;
+	tx_connection.destination = h;
+	tx_connection.dest_pipe_index = 4;
+	tx_connection.mode = SPS_MODE_DEST;
+	tx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT;
+	tx_desc_mem_buf.size = 0x800; /* 2k */
+	tx_desc_mem_buf.base = dma_alloc_coherent(dma_dev, tx_desc_mem_buf.size,
+							&dma_addr, 0);
+	if (tx_desc_mem_buf.base == NULL) {
+		ret = -ENOMEM;
+		goto tx_get_config_failed;
+	}
+	tx_desc_mem_buf.phys_base = dma_addr;
+	memset(tx_desc_mem_buf.base, 0x0, tx_desc_mem_buf.size);
+	tx_connection.desc = tx_desc_mem_buf;
+	tx_connection.event_thresh = 0x10;
+
+	ret = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
+	if (ret < 0) {
+		pr_err("%s: tx connect error %d\n", __func__, ret);
+		goto tx_connect_failed;
+	}
+
+	bam_rx_pipe = bam_ops->sps_alloc_endpoint_ptr();
+	if (bam_rx_pipe == NULL) {
+		pr_err("%s: rx alloc endpoint failed\n", __func__);
+		ret = -ENOMEM;
+		goto rx_alloc_endpoint_failed;
+	}
+	ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &rx_connection);
+	if (ret) {
+		pr_err("%s: rx get config failed %d\n", __func__, ret);
+		goto rx_get_config_failed;
+	}
+
+	rx_connection.source = h;
+	rx_connection.src_pipe_index = 5;
+	rx_connection.destination = SPS_DEV_HANDLE_MEM;
+	rx_connection.dest_pipe_index = 1;
+	rx_connection.mode = SPS_MODE_SRC;
+	rx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
+					SPS_O_ACK_TRANSFERS;
+	rx_desc_mem_buf.size = 0x800; /* 2k */
+	rx_desc_mem_buf.base = dma_alloc_coherent(dma_dev, rx_desc_mem_buf.size,
+							&dma_addr, 0);
+	if (rx_desc_mem_buf.base == NULL) {
+		ret = -ENOMEM;
+		goto rx_mem_failed;
+	}
+	rx_desc_mem_buf.phys_base = dma_addr;
+	memset(rx_desc_mem_buf.base, 0x0, rx_desc_mem_buf.size);
+	rx_connection.desc = rx_desc_mem_buf;
+	rx_connection.event_thresh = 0x10;
+
+	ret = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
+	if (ret < 0) {
+		pr_err("%s: rx connect error %d\n", __func__, ret);
+		goto rx_connect_failed;
+	}
+
+	tx_register_event.options = SPS_O_EOT;
+	tx_register_event.mode = SPS_TRIGGER_CALLBACK;
+	tx_register_event.xfer_done = NULL;
+	tx_register_event.callback = bam_mux_tx_notify;
+	tx_register_event.user = NULL;
+	ret = bam_ops->sps_register_event_ptr(bam_tx_pipe, &tx_register_event);
+	if (ret < 0) {
+		pr_err("%s: tx register event error %d\n", __func__, ret);
+		goto rx_event_reg_failed;
+	}
+
+	rx_register_event.options = SPS_O_EOT;
+	rx_register_event.mode = SPS_TRIGGER_CALLBACK;
+	rx_register_event.xfer_done = NULL;
+	rx_register_event.callback = bam_mux_rx_notify;
+	rx_register_event.user = NULL;
+	ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
+	if (ret < 0) {
+		pr_err("%s: tx register event error %d\n", __func__, ret);
+		goto rx_event_reg_failed;
+	}
+
+	mutex_lock(&delayed_ul_vote_lock);
+	bam_mux_initialized = 1;
+	if (need_delayed_ul_vote) {
+		need_delayed_ul_vote = 0;
+		msm_bam_dmux_kickoff_ul_wakeup();
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+	toggle_apps_ack();
+	bam_connection_is_active = 1;
+	complete_all(&bam_connection_completion);
+	queue_rx();
+	return 0;
+
+rx_event_reg_failed:
+	bam_ops->sps_disconnect_ptr(bam_rx_pipe);
+rx_connect_failed:
+	dma_free_coherent(dma_dev, rx_desc_mem_buf.size, rx_desc_mem_buf.base,
+				rx_desc_mem_buf.phys_base);
+rx_mem_failed:
+rx_get_config_failed:
+	bam_ops->sps_free_endpoint_ptr(bam_rx_pipe);
+rx_alloc_endpoint_failed:
+	bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+tx_connect_failed:
+	dma_free_coherent(dma_dev, tx_desc_mem_buf.size, tx_desc_mem_buf.base,
+				tx_desc_mem_buf.phys_base);
+tx_get_config_failed:
+	bam_ops->sps_free_endpoint_ptr(bam_tx_pipe);
+tx_alloc_endpoint_failed:
+	bam_ops->sps_deregister_bam_device_ptr(h);
+	/*
+	 * sps_deregister_bam_device() calls iounmap.  calling iounmap on the
+	 * same handle below will cause a crash, so skip it if we've freed
+	 * the handle here.
+	 */
+	skip_iounmap = 1;
+register_bam_failed:
+	if (!skip_iounmap)
+		iounmap(a2_virt_addr);
+ioremap_failed:
+	/*destroy_workqueue(bam_mux_workqueue);*/
+	return ret;
+}
+
+static void toggle_apps_ack(void)
+{
+	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: skipped due to SSR\n", __func__);
+		return;
+	}
+
+	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
+			clear_bit & 0x1, ~clear_bit & 0x1);
+	bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
+				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
+	clear_bit = ~clear_bit;
+	DBG_INC_ACK_OUT_CNT();
+}
+
+static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
+{
+	static int last_processed_state;
+	int rcu_id;
+
+	rcu_id = srcu_read_lock(&bam_dmux_srcu);
+	mutex_lock(&smsm_cb_lock);
+	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+	DBG_INC_A2_POWER_CONTROL_IN_CNT();
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
+	if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
+		BAM_DMUX_LOG("%s: already processed this state\n", __func__);
+		mutex_unlock(&smsm_cb_lock);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+		return;
+	}
+
+	last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
+
+	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+		BAM_DMUX_LOG("%s: reconnect\n", __func__);
+		grab_wakelock();
+		reconnect_to_bam();
+	} else if (bam_mux_initialized &&
+					!(new_state & SMSM_A2_POWER_CONTROL)) {
+		BAM_DMUX_LOG("%s: disconnect\n", __func__);
+		disconnect_to_bam();
+		release_wakelock();
+	} else if (new_state & SMSM_A2_POWER_CONTROL) {
+		BAM_DMUX_LOG("%s: init\n", __func__);
+		grab_wakelock();
+		bam_init();
+	} else {
+		BAM_DMUX_LOG("%s: bad state change\n", __func__);
+		pr_err("%s: unsupported state change\n", __func__);
+	}
+	mutex_unlock(&smsm_cb_lock);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+}
+
+static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
+						uint32_t new_state)
+{
+	int rcu_id;
+
+	rcu_id = srcu_read_lock(&bam_dmux_srcu);
+	DBG_INC_ACK_IN_CNT();
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
+	complete_all(&ul_wakeup_ack_completion);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+}
+
+/**
+ * msm_bam_dmux_set_bam_ops() - sets the bam_ops
+ * @ops: bam_ops_if to set
+ *
+ * Sets bam_ops to allow switching of runtime behavior. Preconditon, bam dmux
+ * must be in an idle state. If input ops is NULL, then bam_ops will be
+ * restored to their default state.
+ */
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops)
+{
+	if (ops != NULL)
+		bam_ops = ops;
+	else
+		bam_ops = &bam_default_ops;
+}
+EXPORT_SYMBOL(msm_bam_dmux_set_bam_ops);
+
+/**
+ * msm_bam_dmux_deinit() - puts bam dmux into a deinited state
+ *
+ * Puts bam dmux into a deinitialized state by simulating an ssr.
+ */
+void msm_bam_dmux_deinit(void)
+{
+	restart_notifier_cb(NULL, SUBSYS_BEFORE_SHUTDOWN, NULL);
+	restart_notifier_cb(NULL, SUBSYS_AFTER_SHUTDOWN, NULL);
+	restart_notifier_cb(NULL, SUBSYS_BEFORE_POWERUP, NULL);
+	restart_notifier_cb(NULL, SUBSYS_AFTER_POWERUP, NULL);
+	in_global_reset = 0;
+}
+EXPORT_SYMBOL(msm_bam_dmux_deinit);
+
+/**
+ * msm_bam_dmux_reinit() - reinitializes bam dmux
+ */
+void msm_bam_dmux_reinit(void)
+{
+	bam_mux_initialized = 0;
+	bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL,
+			bam_dmux_smsm_cb, NULL);
+	bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL_ACK,
+			bam_dmux_smsm_ack_cb, NULL);
+}
+EXPORT_SYMBOL(msm_bam_dmux_reinit);
+
+/**
+ * set_rx_buffer_ring_pool() - Configure the size of the rx ring pool to a
+ *			       supported value.
+ * @requested_buffs:	Desired pool size.
+ *
+ * The requested size will be reduced to the largest supported size.  The
+ * supported sizes must match the values in create_open_signal() for proper
+ * signal field construction in that function.
+ */
+static void set_rx_buffer_ring_pool(int requested_buffs)
+{
+	if (requested_buffs >= SZ_256) {
+		num_buffers = SZ_256;
+		return;
+	}
+
+	if (requested_buffs >= SZ_128) {
+		num_buffers = SZ_128;
+		return;
+	}
+
+	if (requested_buffs >= SZ_64) {
+		num_buffers = SZ_64;
+		return;
+	}
+
+	num_buffers = SZ_32;
+}
+
+/**
+ * set_dl_mtu() - Configure the non-default MTU to a supported value.
+ * @requested_mtu:	Desired MTU size.
+ *
+ * Sets the dynamic receive MTU which can be enabled via negotiation with the
+ * remote side.  Until the dynamic MTU is enabled, the default MTU will be used.
+ * The requested size will be reduced to the largest supported size.  The
+ * supported sizes must match the values in create_open_signal() for proper
+ * signal field construction in that function.
+ */
+static void set_dl_mtu(int requested_mtu)
+{
+	if (requested_mtu >= SZ_16K) {
+		dl_mtu = SZ_16K;
+		return;
+	}
+
+	if (requested_mtu >= SZ_8K) {
+		dl_mtu = SZ_8K;
+		return;
+	}
+
+	if (requested_mtu >= SZ_4K) {
+		dl_mtu = SZ_4K;
+		return;
+	}
+
+	dl_mtu = SZ_2K;
+}
+
+static int bam_dmux_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct resource *r;
+	void *subsys_h;
+	uint32_t requested_dl_mtu;
+
+	DBG("%s probe called\n", __func__);
+	if (bam_mux_initialized)
+		return 0;
+
+	if (pdev->dev.of_node) {
+		r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!r) {
+			pr_err("%s: reg field missing\n", __func__);
+			return -ENODEV;
+		}
+		a2_phys_base = r->start;
+		a2_phys_size = (uint32_t)(resource_size(r));
+		a2_bam_irq = platform_get_irq(pdev, 0);
+		if (a2_bam_irq == -ENXIO) {
+			pr_err("%s: irq field missing\n", __func__);
+			return -ENODEV;
+		}
+		satellite_mode = of_property_read_bool(pdev->dev.of_node,
+						"qcom,satellite-mode");
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+						"qcom,rx-ring-size",
+						&num_buffers);
+		if (rc) {
+			DBG("%s: falling back to num_buffs default, rc:%d\n",
+							__func__, rc);
+			num_buffers = DEFAULT_NUM_BUFFERS;
+		}
+
+		set_rx_buffer_ring_pool(num_buffers);
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+						"qcom,max-rx-mtu",
+						&requested_dl_mtu);
+		if (rc) {
+			DBG("%s: falling back to dl_mtu default, rc:%d\n",
+							__func__, rc);
+			requested_dl_mtu = 0;
+		}
+
+		set_dl_mtu(requested_dl_mtu);
+
+		no_cpu_affinity = of_property_read_bool(pdev->dev.of_node,
+						"qcom,no-cpu-affinity");
+
+		rc = of_property_read_bool(pdev->dev.of_node,
+						"qcom,fast-shutdown");
+		if (rc)
+			ul_timeout_delay = UL_FAST_TIMEOUT_DELAY;
+
+		BAM_DMUX_LOG(
+			"%s: base:%pK size:%x irq:%d satellite:%d num_buffs:%d dl_mtu:%x cpu-affinity:%d ul_timeout_delay:%d\n",
+						__func__,
+						(void *)(uintptr_t)a2_phys_base,
+						a2_phys_size,
+						a2_bam_irq,
+						satellite_mode,
+						num_buffers,
+						dl_mtu,
+						no_cpu_affinity,
+						ul_timeout_delay);
+	} else { /* fallback to default init data */
+		a2_phys_base = A2_PHYS_BASE;
+		a2_phys_size = A2_PHYS_SIZE;
+		a2_bam_irq = A2_BAM_IRQ;
+		num_buffers = DEFAULT_NUM_BUFFERS;
+		set_rx_buffer_ring_pool(num_buffers);
+	}
+
+	dma_dev = &pdev->dev;
+	/* The BAM only suports 32 bits of address */
+	dma_dev->dma_mask = kmalloc(sizeof(*dma_dev->dma_mask), GFP_KERNEL);
+	if (!dma_dev->dma_mask)
+		return -ENOMEM;
+
+	*dma_dev->dma_mask = DMA_BIT_MASK(32);
+	dma_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_clk)) {
+		BAM_DMUX_LOG("%s: did not get xo clock\n", __func__);
+		xo_clk = NULL;
+	}
+	dfab_clk = clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(dfab_clk)) {
+		BAM_DMUX_LOG("%s: did not get dfab clock\n", __func__);
+		dfab_clk = NULL;
+	} else {
+		rc = clk_set_rate(dfab_clk, 64000000);
+		if (rc)
+			pr_err("%s: unable to set dfab clock rate\n", __func__);
+	}
+
+	/*
+	 * setup the workqueue so that it can be pinned to core 0 and not
+	 * block the watchdog pet function, so that netif_rx() in rmnet
+	 * only uses one queue.
+	 */
+	if (no_cpu_affinity)
+		bam_mux_rx_workqueue =
+			create_singlethread_workqueue("bam_dmux_rx");
+	else
+		bam_mux_rx_workqueue = alloc_workqueue("bam_dmux_rx",
+					WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	if (!bam_mux_rx_workqueue)
+		return -ENOMEM;
+
+	bam_mux_tx_workqueue = create_singlethread_workqueue("bam_dmux_tx");
+	if (!bam_mux_tx_workqueue) {
+		destroy_workqueue(bam_mux_rx_workqueue);
+		return -ENOMEM;
+	}
+
+	for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc) {
+		spin_lock_init(&bam_ch[rc].lock);
+		scnprintf(bam_ch[rc].name, BAM_DMUX_CH_NAME_MAX_LEN,
+					"bam_dmux_ch_%d", rc);
+		/* bus 2, ie a2 stream 2 */
+		bam_ch[rc].pdev = platform_device_alloc(bam_ch[rc].name, 2);
+		if (!bam_ch[rc].pdev) {
+			pr_err("%s: platform device alloc failed\n", __func__);
+			destroy_workqueue(bam_mux_rx_workqueue);
+			destroy_workqueue(bam_mux_tx_workqueue);
+			return -ENOMEM;
+		}
+	}
+
+	init_completion(&ul_wakeup_ack_completion);
+	init_completion(&bam_connection_completion);
+	init_completion(&dfab_unvote_completion);
+	init_completion(&shutdown_completion);
+	complete_all(&shutdown_completion);
+	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+	wakeup_source_init(&bam_wakelock, "bam_dmux_wakelock");
+	init_srcu_struct(&bam_dmux_srcu);
+
+	subsys_h = subsys_notif_register_notifier("modem", &restart_notifier);
+	if (IS_ERR(subsys_h)) {
+		destroy_workqueue(bam_mux_rx_workqueue);
+		destroy_workqueue(bam_mux_tx_workqueue);
+		rc = (int)PTR_ERR(subsys_h);
+		pr_err("%s: failed to register for ssr rc: %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL,
+			bam_dmux_smsm_cb, NULL);
+
+	if (rc) {
+		subsys_notif_unregister_notifier(subsys_h, &restart_notifier);
+		destroy_workqueue(bam_mux_rx_workqueue);
+		destroy_workqueue(bam_mux_tx_workqueue);
+		pr_err("%s: smsm cb register failed, rc: %d\n", __func__, rc);
+		return -ENOMEM;
+	}
+
+	rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL_ACK,
+			bam_dmux_smsm_ack_cb, NULL);
+
+	if (rc) {
+		subsys_notif_unregister_notifier(subsys_h, &restart_notifier);
+		destroy_workqueue(bam_mux_rx_workqueue);
+		destroy_workqueue(bam_mux_tx_workqueue);
+		bam_ops->smsm_state_cb_deregister_ptr(SMSM_MODEM_STATE,
+					SMSM_A2_POWER_CONTROL,
+					bam_dmux_smsm_cb, NULL);
+		pr_err("%s: smsm ack cb register failed, rc: %d\n", __func__,
+				rc);
+		for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc)
+			platform_device_put(bam_ch[rc].pdev);
+		return -ENOMEM;
+	}
+
+	if (bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE) &
+			SMSM_A2_POWER_CONTROL)
+		bam_dmux_smsm_cb(NULL, 0,
+			bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE));
+
+	return 0;
+}
+
+static const struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,bam_dmux"},
+	{},
+};
+
+static struct platform_driver bam_dmux_driver = {
+	.probe		= bam_dmux_probe,
+	.driver		= {
+		.name	= "BAM_RMNT",
+		.owner	= THIS_MODULE,
+		.of_match_table = msm_match_table,
+	},
+};
+
+static int __init bam_dmux_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("bam_dmux", 0);
+	if (!IS_ERR(dent)) {
+		debug_create("tbl", 0444, dent, debug_tbl);
+		debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
+		debug_create("stats", 0444, dent, debug_stats);
+	}
+#endif
+
+	bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux",
+			0);
+	if (!bam_ipc_log_txt)
+		pr_err("%s : unable to create IPC Logging Context", __func__);
+
+	rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
+	return platform_driver_register(&bam_dmux_driver);
+}
+
+late_initcall(bam_dmux_init); /* needs to init after SMD */
+MODULE_DESCRIPTION("MSM BAM DMUX");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/bam_dmux_private.h b/drivers/soc/qcom/bam_dmux_private.h
new file mode 100644
index 0000000..4f39076
--- /dev/null
+++ b/drivers/soc/qcom/bam_dmux_private.h
@@ -0,0 +1,182 @@
+/* Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BAM_DMUX_PRIVATE_H
+#define _BAM_DMUX_PRIVATE_H
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/msm-sps.h>
+
+#define BAM_MUX_HDR_MAGIC_NO			0x33fc
+#define BAM_MUX_HDR_CMD_DATA			0
+#define BAM_MUX_HDR_CMD_OPEN			1
+#define BAM_MUX_HDR_CMD_CLOSE			2
+#define BAM_MUX_HDR_CMD_STATUS			3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC		4
+#define DEFAULT_BUFFER_SIZE			SZ_2K
+
+#define DYNAMIC_MTU_MASK			0x2
+#define MTU_SIZE_MASK				0xc0
+#define MTU_SIZE_SHIFT				0x6
+#define DL_POOL_SIZE_SHIFT			0x4
+
+/**
+ * struct bam_ops_if - collection of function pointers to allow swappable
+ * runtime functionality
+ * @smsm_change_state_ptr: pointer to smsm_change_state function
+ * @smsm_get_state_ptr: pointer to smsm_get_state function
+ * @smsm_state_cb_register_ptr: pointer to smsm_state_cb_register function
+ * @smsm_state_cb_deregister_ptr: pointer to smsm_state_cb_deregister function
+ * @sps_connect_ptr: pointer to sps_connect function
+ * @sps_disconnect_ptr: pointer to sps_disconnect function
+ * @sps_register_bam_device_ptr: pointer to sps_register_bam_device
+ * @sps_deregister_bam_device_ptr: pointer to sps_deregister_bam_device
+ * function
+ * @sps_alloc_endpoint_ptr: pointer to sps_alloc_endpoint function
+ * @sps_free_endpoint_ptr: pointer to sps_free_endpoint function
+ * @sps_set_config_ptr: pointer to sps_set_config function
+ * @sps_get_config_ptr: pointer to sps_get_config function
+ * @sps_device_reset_ptr: pointer to sps_device_reset function
+ * @sps_register_event_ptr: pointer to sps_register_event function
+ * @sps_transfer_one_ptr: pointer to sps_transfer_one function
+ * @sps_get_iovec_ptr: pointer to sps_get_iovec function
+ * @sps_get_unused_desc_num_ptr: pointer to sps_get_unused_desc_num function
+ * @dma_to: enum for the direction of dma operations to device
+ * @dma_from: enum for the direction of dma operations from device
+ *
+ * This struct contains the interface from bam_dmux to smsm and sps. The
+ * pointers can be swapped out at run time to provide different functionality.
+ */
+struct bam_ops_if {
+	/* smsm */
+	int (*smsm_change_state_ptr)(uint32_t smsm_entry,
+		uint32_t clear_mask, uint32_t set_mask);
+
+	uint32_t (*smsm_get_state_ptr)(uint32_t smsm_entry);
+
+	int (*smsm_state_cb_register_ptr)(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+		void *data);
+
+	int (*smsm_state_cb_deregister_ptr)(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t, uint32_t), void *data);
+
+	/* sps */
+	int (*sps_connect_ptr)(struct sps_pipe *h, struct sps_connect *connect);
+
+	int (*sps_disconnect_ptr)(struct sps_pipe *h);
+
+	int (*sps_register_bam_device_ptr)(
+		const struct sps_bam_props *bam_props,
+		unsigned long *dev_handle);
+
+	int (*sps_deregister_bam_device_ptr)(unsigned long dev_handle);
+
+	struct sps_pipe *(*sps_alloc_endpoint_ptr)(void);
+
+	int (*sps_free_endpoint_ptr)(struct sps_pipe *h);
+
+	int (*sps_set_config_ptr)(struct sps_pipe *h,
+		struct sps_connect *config);
+
+	int (*sps_get_config_ptr)(struct sps_pipe *h,
+		struct sps_connect *config);
+
+	int (*sps_device_reset_ptr)(unsigned long dev);
+
+	int (*sps_register_event_ptr)(struct sps_pipe *h,
+		struct sps_register_event *reg);
+
+	int (*sps_transfer_one_ptr)(struct sps_pipe *h,
+		phys_addr_t addr, u32 size,
+		void *user, u32 flags);
+
+	int (*sps_get_iovec_ptr)(struct sps_pipe *h,
+		struct sps_iovec *iovec);
+
+	int (*sps_get_unused_desc_num_ptr)(struct sps_pipe *h,
+		u32 *desc_num);
+
+	enum dma_data_direction dma_to;
+
+	enum dma_data_direction dma_from;
+};
+
+/**
+ * struct bam_mux_hdr - struct which contains bam dmux header info
+ * @magic_num: magic number placed at start to ensure that it is actually a
+ * valid bam dmux header
+ * @signal: optional signaling bits with commmand type specific definitions
+ * @cmd: the command
+ * @pad_len: the length of padding
+ * @ch_id: the id of the bam dmux channel that this is sent on
+ * @pkt_len: the length of the packet that this is the header of
+ */
+struct bam_mux_hdr {
+	uint16_t magic_num;
+	uint8_t signal;
+	uint8_t cmd;
+	uint8_t pad_len;
+	uint8_t ch_id;
+	uint16_t pkt_len;
+};
+
+/**
+ * struct rx_pkt_info - struct describing an rx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @work: work_struct for processing the packet
+ * @list_node: list_head for placing this on a list
+ * @sps_size: size of the sps_iovec for this packet
+ * @len: total length of the buffer containing this packet
+ */
+struct rx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	struct work_struct work;
+	struct list_head list_node;
+	uint16_t sps_size;
+	uint16_t len;
+};
+
+/**
+ * struct tx_pkt_info - struct describing a tx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @is_cmd: signifies whether this is a command or data packet
+ * @len: length og the packet
+ * @work: work_struct for processing this packet
+ * @list_node: list_head for placing this on a list
+ * @ts_sec: seconds portion of the timestamp
+ * @ts_nsec: nanoseconds portion of the timestamp
+ *
+ */
+struct tx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	char is_cmd;
+	uint32_t len;
+	struct work_struct work;
+	struct list_head list_node;
+	unsigned int ts_sec;
+	unsigned long ts_nsec;
+};
+
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops);
+
+void msm_bam_dmux_deinit(void);
+
+void msm_bam_dmux_reinit(void);
+
+#endif /* _BAM_DMUX_PRIVATE_H */
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index 43dddb4..a687286 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -554,7 +554,8 @@
 	if (strlen(buf) >= 10)
 		return -EINVAL;
 
-	strlcpy(str, buf, sizeof(str));
+	if (sscanf(buf, "%9s", str) != 1)
+		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
 	if (drvdata->enable) {
@@ -599,7 +600,8 @@
 	if (strlen(buf) >= 10)
 		return -EINVAL;
 
-	strlcpy(str, buf, sizeof(str));
+	if (sscanf(buf, "%9s", str) != 1)
+		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
 	if (drvdata->enable) {
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index d8cc2c4..4892f50 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -37,6 +37,7 @@
 #define GLINK_QOS_DEF_NUM_PRIORITY	1
 #define GLINK_QOS_DEF_MTU		2048
 
+#define GLINK_CH_XPRT_NAME_SIZE ((3 * GLINK_NAME_SIZE) + 4)
 #define GLINK_KTHREAD_PRIO 1
 
 /**
@@ -376,7 +377,7 @@
 
 static struct channel_ctx *ch_name_to_ch_ctx_create(
 					struct glink_core_xprt_ctx *xprt_ctx,
-					const char *name);
+					const char *name, bool local);
 
 static void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size,
 					uint32_t riid, void *cookie);
@@ -1274,8 +1275,7 @@
 	spin_unlock_irqrestore(&ctx->rmt_rx_intent_lst_lock_lhc2, flags);
 
 	GLINK_DBG_CH(ctx, "%s: R[%u]:%zu Pushed remote intent\n", __func__,
-			intent->id,
-			intent->intent_size);
+			riid, size);
 }
 
 /**
@@ -1836,13 +1836,14 @@
  *                              it is not found and get reference of context.
  * @xprt_ctx:	Transport to search for a matching channel.
  * @name:	Name of the desired channel.
+ * @local:	If called from local open or not
  *
  * Return: The channel corresponding to @name, NULL if a matching channel was
  *         not found AND a new channel could not be created.
  */
 static struct channel_ctx *ch_name_to_ch_ctx_create(
 					struct glink_core_xprt_ctx *xprt_ctx,
-					const char *name)
+					const char *name, bool local)
 {
 	struct channel_ctx *entry;
 	struct channel_ctx *ctx;
@@ -1886,10 +1887,23 @@
 	list_for_each_entry_safe(entry, temp, &xprt_ctx->channels,
 		    port_list_node)
 		if (!strcmp(entry->name, name) && !entry->pending_delete) {
+			rwref_get(&entry->ch_state_lhb2);
+			/* port already exists */
+			if (entry->local_open_state != GLINK_CHANNEL_CLOSED
+								&& local) {
+				/* not ready to be re-opened */
+				GLINK_INFO_CH_XPRT(entry, xprt_ctx,
+					"%s: Ch not ready. State: %u\n",
+					__func__, entry->local_open_state);
+				rwref_put(&entry->ch_state_lhb2);
+				entry = NULL;
+			} else if (local) {
+				entry->local_open_state =
+						GLINK_CHANNEL_OPENING;
+			}
 			spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1,
 					flags);
 			kfree(ctx);
-			rwref_get(&entry->ch_state_lhb2);
 			rwref_write_put(&xprt_ctx->xprt_state_lhb0);
 			return entry;
 		}
@@ -1919,6 +1933,8 @@
 
 		ctx->transport_ptr = xprt_ctx;
 		rwref_get(&ctx->ch_state_lhb2);
+		if (local)
+			ctx->local_open_state = GLINK_CHANNEL_OPENING;
 		list_add_tail(&ctx->port_list_node, &xprt_ctx->channels);
 
 		GLINK_INFO_PERF_CH_XPRT(ctx, xprt_ctx,
@@ -2604,23 +2620,13 @@
 	 * look for an existing port structure which can occur in
 	 * reopen and remote-open-first cases
 	 */
-	ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name);
+	ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name, true);
 	if (ctx == NULL) {
 		GLINK_ERR("%s:%s %s: Error - unable to allocate new channel\n",
 				cfg->transport, cfg->edge, __func__);
 		return ERR_PTR(-ENOMEM);
 	}
 
-	/* port already exists */
-	if (ctx->local_open_state != GLINK_CHANNEL_CLOSED) {
-		/* not ready to be re-opened */
-		GLINK_INFO_CH_XPRT(ctx, transport_ptr,
-		"%s: Channel not ready to be re-opened. State: %u\n",
-		__func__, ctx->local_open_state);
-		rwref_put(&ctx->ch_state_lhb2);
-		return ERR_PTR(-EBUSY);
-	}
-
 	/* initialize port structure */
 	ctx->user_priv = cfg->priv;
 	ctx->rx_intent_req_timeout_jiffies =
@@ -2651,7 +2657,6 @@
 	ctx->local_xprt_req = best_id;
 	ctx->no_migrate = cfg->transport &&
 				!(cfg->options & GLINK_OPT_INITIAL_XPORT);
-	ctx->local_open_state = GLINK_CHANNEL_OPENING;
 	GLINK_INFO_PERF_CH(ctx,
 		"%s: local:GLINK_CHANNEL_CLOSED->GLINK_CHANNEL_OPENING\n",
 		__func__);
@@ -2900,6 +2905,7 @@
 	size_t intent_size;
 	bool is_atomic =
 		tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC);
+	char glink_name[GLINK_CH_XPRT_NAME_SIZE];
 	unsigned long flags;
 	void *cookie = NULL;
 
@@ -2941,21 +2947,22 @@
 		tracer_pkt_log_event(data, GLINK_CORE_TX);
 	}
 
+	scnprintf(glink_name, GLINK_CH_XPRT_NAME_SIZE, "%s_%s_%s", ctx->name,
+			ctx->transport_ptr->edge, ctx->transport_ptr->name);
 	/* find matching rx intent (first-fit algorithm for now) */
 	if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size, &cookie)) {
 		if (!(tx_flags & GLINK_TX_REQ_INTENT)) {
 			/* no rx intent available */
-			GLINK_ERR_CH(ctx,
-				"%s: R[%u]:%zu Intent not present for lcid\n",
-				__func__, riid, size);
+			GLINK_ERR(
+				"%s: %s: R[%u]:%zu Intent not present\n",
+				glink_name, __func__, riid, size);
 			ret = -EAGAIN;
 			goto glink_tx_common_err;
 		}
 		if (is_atomic && !(ctx->transport_ptr->capabilities &
 					  GCAP_AUTO_QUEUE_RX_INT)) {
-			GLINK_ERR_CH(ctx,
-				"%s: Cannot request intent in atomic context\n",
-				__func__);
+			GLINK_ERR("%s: %s: %s\n", glink_name, __func__,
+				"Cannot request intent in atomic context");
 			ret = -EINVAL;
 			goto glink_tx_common_err;
 		}
@@ -2965,8 +2972,8 @@
 		ret = ctx->transport_ptr->ops->tx_cmd_rx_intent_req(
 				ctx->transport_ptr->ops, ctx->lcid, size);
 		if (ret) {
-			GLINK_ERR_CH(ctx, "%s: Request intent failed %d\n",
-					__func__, ret);
+			GLINK_ERR("%s: %s: Request intent failed %d\n",
+					glink_name, __func__, ret);
 			goto glink_tx_common_err;
 		}
 
@@ -2974,18 +2981,18 @@
 						&intent_size, &cookie)) {
 			rwref_read_put(&ctx->ch_state_lhb2);
 			if (is_atomic) {
-				GLINK_ERR_CH(ctx,
-				    "%s Intent of size %zu not ready\n",
-				    __func__, size);
+				GLINK_ERR("%s: %s: Intent of size %zu %s\n",
+					glink_name, __func__, size,
+					"not ready");
 				ret = -EAGAIN;
 				goto glink_tx_common_err_2;
 			}
 
 			if (ctx->transport_ptr->local_state == GLINK_XPRT_DOWN
 			    || !ch_is_fully_opened(ctx)) {
-				GLINK_ERR_CH(ctx,
-					"%s: Channel closed while waiting for intent\n",
-					__func__);
+				GLINK_ERR("%s: %s: %s %s\n", glink_name,
+					 __func__, "Channel closed while",
+					"waiting for intent");
 				ret = -EBUSY;
 				goto glink_tx_common_err_2;
 			}
@@ -2995,17 +3002,17 @@
 					&ctx->int_req_ack_complete,
 					ctx->rx_intent_req_timeout_jiffies)) {
 				GLINK_ERR(
-					"%s: Intent request ack with size: %zu not granted for lcid\n",
-					__func__, size);
+					"%s: %s: %s %zu not granted for lcid\n",
+					glink_name, __func__,
+					"Intent request ack with size:", size);
 				ret = -ETIMEDOUT;
 				goto glink_tx_common_err_2;
 			}
 
 			if (!ctx->int_req_ack) {
-				GLINK_ERR_CH(ctx,
-				    "%s: Intent Request with size: %zu %s",
-				    __func__, size,
-				    "not granted for lcid\n");
+				GLINK_ERR("%s: %s: %s %zu %s\n", glink_name,
+					__func__, "Intent Request with size:",
+					size, "not granted for lcid");
 				ret = -EAGAIN;
 				goto glink_tx_common_err_2;
 			}
@@ -3014,9 +3021,9 @@
 			if (!wait_for_completion_timeout(
 					&ctx->int_req_complete,
 					ctx->rx_intent_req_timeout_jiffies)) {
-				GLINK_ERR(
-					"%s: Intent request with size: %zu not granted for lcid\n",
-					__func__, size);
+				GLINK_ERR("%s: %s: %s %zu %s\n", glink_name,
+					 __func__, "Intent request with size: ",
+					size, "not granted for lcid");
 				ret = -ETIMEDOUT;
 				goto glink_tx_common_err_2;
 			}
@@ -4912,7 +4919,7 @@
 	bool do_migrate;
 
 	glink_core_migration_edge_lock(if_ptr->glink_core_priv);
-	ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name);
+	ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name, false);
 	if (ctx == NULL) {
 		GLINK_ERR_XPRT(if_ptr->glink_core_priv,
 		       "%s: invalid rcid %u received, name '%s'\n",
@@ -5015,6 +5022,7 @@
 	struct channel_ctx *ctx;
 	bool is_ch_fully_closed;
 	struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv;
+	unsigned long flags;
 
 	ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid);
 	if (!ctx) {
@@ -5032,11 +5040,13 @@
 		rwref_put(&ctx->ch_state_lhb2);
 		return;
 	}
+	spin_lock_irqsave(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags);
+	ctx->pending_delete = true;
+	spin_unlock_irqrestore(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags);
 	GLINK_INFO_CH(ctx, "%s: remote: OPENED->CLOSED\n", __func__);
 
 	is_ch_fully_closed = glink_core_remote_close_common(ctx, false);
 
-	ctx->pending_delete = true;
 	if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, rcid);
 
 	if (is_ch_fully_closed) {
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 9becb10..d9cd0fa 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -53,6 +53,8 @@
 #define RPM_FIFO_ADDR_ALIGN_BYTES 3
 #define TRACER_PKT_FEATURE BIT(2)
 #define DEFERRED_CMDS_THRESHOLD 25
+#define NUM_LOG_PAGES	4
+
 /**
  * enum command_types - definition of the types of commands sent/received
  * @VERSION_CMD:		Version and feature set supported
@@ -169,6 +171,7 @@
  * @tx_blocked_signal_sent:	Flag to indicate the flush signal has already
  *				been sent, and a response is pending from the
  *				remote side.  Protected by @write_lock.
+ * @debug_mask			mask to set debugging level.
  * @kwork:			Work to be executed when an irq is received.
  * @kworker:			Handle to the entity processing of
 				deferred commands.
@@ -189,6 +192,7 @@
  * @ramp_time_us:		Array of ramp times in microseconds where array
  *				index position represents a power state.
  * @mailbox:			Mailbox transport channel description reference.
+ * @log_ctx:			Pointer to log context.
  */
 struct edge_info {
 	struct glink_transport_if xprt_if;
@@ -214,9 +218,9 @@
 	wait_queue_head_t tx_blocked_queue;
 	bool tx_resume_needed;
 	bool tx_blocked_signal_sent;
+	unsigned int debug_mask;
 	struct kthread_work kwork;
 	struct kthread_worker kworker;
-	struct work_struct wakeup_work;
 	struct task_struct *task;
 	struct tasklet_struct tasklet;
 	struct srcu_struct use_ref;
@@ -230,6 +234,7 @@
 	uint32_t readback;
 	unsigned long *ramp_time_us;
 	struct mailbox_config_info *mailbox;
+	void *log_ctx;
 };
 
 /**
@@ -262,6 +267,27 @@
 	{1, TRACER_PKT_FEATURE, negotiate_features_v1},
 };
 
+#define SMEM_IPC_LOG(einfo, str, id, param1, param2) do { \
+	if ((glink_xprt_debug_mask & QCOM_GLINK_DEBUG_ENABLE) \
+		&& (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)) \
+		ipc_log_string(einfo->log_ctx, \
+				"%s: Rx:%x:%x Tx:%x:%x Cmd:%x P1:%x P2:%x\n", \
+				str, einfo->rx_ch_desc->read_index, \
+				einfo->rx_ch_desc->write_index, \
+				einfo->tx_ch_desc->read_index, \
+				einfo->tx_ch_desc->write_index, \
+				id, param1, param2); \
+} while (0) \
+
+enum {
+	QCOM_GLINK_DEBUG_ENABLE = 1U << 0,
+	QCOM_GLINK_DEBUG_DISABLE = 1U << 1,
+};
+
+static unsigned int glink_xprt_debug_mask = QCOM_GLINK_DEBUG_ENABLE;
+module_param_named(debug_mask, glink_xprt_debug_mask,
+		   uint, 0664);
+
 /**
  * send_irq() - send an irq to a remote entity as an event signal
  * @einfo:	Which remote entity that should receive the irq.
@@ -641,6 +667,7 @@
 	read_notif_req.reserved = 0;
 	read_notif_req.reserved2 = 0;
 
+	SMEM_IPC_LOG(einfo, __func__, READ_NOTIF_CMD, 0, 0);
 	if (!einfo->tx_blocked_signal_sent) {
 		einfo->tx_blocked_signal_sent = true;
 		fifo_write(einfo, &read_notif_req, sizeof(read_notif_req));
@@ -854,6 +881,39 @@
 }
 
 /**
+ * tx_wakeup_worker() - worker function to wakeup tx blocked thread
+ * @work:	kwork associated with the edge to process commands on.
+ */
+static void tx_wakeup_worker(struct edge_info *einfo)
+{
+	struct glink_transport_if xprt_if = einfo->xprt_if;
+	bool trigger_wakeup = false;
+	bool trigger_resume = false;
+	unsigned long flags;
+
+	if (einfo->in_ssr)
+		return;
+
+	spin_lock_irqsave(&einfo->write_lock, flags);
+	if (fifo_write_avail(einfo)) {
+		if (einfo->tx_blocked_signal_sent)
+			einfo->tx_blocked_signal_sent = false;
+		if (einfo->tx_resume_needed) {
+			einfo->tx_resume_needed = false;
+			trigger_resume = true;
+		}
+	}
+	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
+		trigger_wakeup = true;
+	}
+	spin_unlock_irqrestore(&einfo->write_lock, flags);
+	if (trigger_wakeup)
+		wake_up_all(&einfo->tx_blocked_queue);
+	if (trigger_resume)
+		xprt_if.glink_core_if_ptr->tx_resume(&xprt_if);
+}
+
+/**
  * __rx_worker() - process received commands on a specific edge
  * @einfo:	Edge to process commands on.
  * @atomic_ctx:	Indicates if the caller is in atomic context and requires any
@@ -903,7 +963,7 @@
 
 	if ((atomic_ctx) && ((einfo->tx_resume_needed) ||
 		(waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/
-		schedule_work(&einfo->wakeup_work);
+		tx_wakeup_worker(einfo);
 
 	/*
 	 * Access to the fifo needs to be synchronized, however only the calls
@@ -936,8 +996,12 @@
 			cmd.param2 = d_cmd->param2;
 			cmd_data = d_cmd->data;
 			kfree(d_cmd);
+			SMEM_IPC_LOG(einfo, "kthread", cmd.id, cmd.param1,
+								cmd.param2);
 		} else {
 			fifo_read(einfo, &cmd, sizeof(cmd));
+			SMEM_IPC_LOG(einfo, "IRQ", cmd.id, cmd.param1,
+								cmd.param2);
 			cmd_data = NULL;
 		}
 
@@ -1211,39 +1275,6 @@
 }
 
 /**
- * tx_wakeup_worker() - worker function to wakeup tx blocked thread
- * @work:	kwork associated with the edge to process commands on.
- */
-static void tx_wakeup_worker(struct work_struct *work)
-{
-	struct edge_info *einfo;
-	bool trigger_wakeup = false;
-	unsigned long flags;
-	int rcu_id;
-
-	einfo = container_of(work, struct edge_info, wakeup_work);
-	rcu_id = srcu_read_lock(&einfo->use_ref);
-	if (einfo->in_ssr) {
-		srcu_read_unlock(&einfo->use_ref, rcu_id);
-		return;
-	}
-	if (einfo->tx_resume_needed && fifo_write_avail(einfo)) {
-		einfo->tx_resume_needed = false;
-		einfo->xprt_if.glink_core_if_ptr->tx_resume(
-						&einfo->xprt_if);
-	}
-	spin_lock_irqsave(&einfo->write_lock, flags);
-	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
-		einfo->tx_blocked_signal_sent = false;
-		trigger_wakeup = true;
-	}
-	spin_unlock_irqrestore(&einfo->write_lock, flags);
-	if (trigger_wakeup)
-		wake_up_all(&einfo->tx_blocked_queue);
-	srcu_read_unlock(&einfo->use_ref, rcu_id);
-}
-
-/**
  * rx_worker() - worker function to process received commands
  * @work:	kwork associated with the edge to process commands on.
  */
@@ -1298,6 +1329,7 @@
 	cmd.version = version;
 	cmd.features = features;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.version, cmd.features);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
 }
@@ -1333,6 +1365,7 @@
 	cmd.version = version;
 	cmd.features = features;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.version, cmd.features);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
 }
@@ -1418,6 +1451,7 @@
 	memcpy(buf, &cmd, sizeof(cmd));
 	memcpy(buf + sizeof(cmd), name, cmd.length);
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.length);
 	fifo_tx(einfo, buf, buf_size);
 
 	kfree(buf);
@@ -1456,6 +1490,7 @@
 	cmd.lcid = lcid;
 	cmd.reserved = 0;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.reserved);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1493,6 +1528,7 @@
 	cmd.rcid = rcid;
 	cmd.reserved = 0;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.rcid, cmd.reserved);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
 }
@@ -1527,6 +1563,7 @@
 	cmd.rcid = rcid;
 	cmd.reserved = 0;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.rcid, cmd.reserved);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
 }
@@ -1687,6 +1724,7 @@
 	cmd.size = size;
 	cmd.liid = liid;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.count);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1727,6 +1765,7 @@
 	cmd.lcid = lcid;
 	cmd.liid = liid;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.liid);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
 }
@@ -1772,6 +1811,7 @@
 	cmd.lcid = lcid;
 	cmd.size = size;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.size);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1817,6 +1857,7 @@
 	else
 		cmd.response = 0;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.response);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -1855,6 +1896,7 @@
 	cmd.lcid = lcid;
 	cmd.sigs = sigs;
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.sigs);
 	fifo_tx(einfo, &cmd, sizeof(cmd));
 
 	srcu_read_unlock(&einfo->use_ref, rcu_id);
@@ -2052,6 +2094,7 @@
 		return ret;
 	}
 
+	SMEM_IPC_LOG(einfo, __func__, cmd.id, cmd.lcid, cmd.riid);
 	GLINK_DBG("%s %s: lcid[%u] riid[%u] cmd[%d], size[%d], size_left[%d]\n",
 		"<SMEM>", __func__, cmd.lcid, cmd.riid, cmd.id, cmd.size,
 		cmd.size_left);
@@ -2371,6 +2414,7 @@
 	uint32_t irq_mask;
 	struct resource *r;
 	u32 *cpu_array;
+	char log_name[GLINK_NAME_SIZE*2+7] = {0};
 
 	node = pdev->dev.of_node;
 
@@ -2425,7 +2469,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -2531,6 +2574,16 @@
 		kfree(cpu_array);
 	}
 
+	einfo->debug_mask = QCOM_GLINK_DEBUG_ENABLE;
+	snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+			einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+	if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+		einfo->log_ctx =
+			ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+	if (!einfo->log_ctx)
+		GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+			__func__, einfo->xprt_cfg.edge,
+			einfo->xprt_cfg.name);
 	register_debugfs_info(einfo);
 	/* fake an interrupt on this edge to see if the remote side is up */
 	irq_handler(0, einfo);
@@ -2541,7 +2594,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2573,6 +2625,7 @@
 	char toc[RPM_TOC_SIZE];
 	uint32_t *tocp;
 	uint32_t num_toc_entries;
+	char log_name[GLINK_NAME_SIZE*2+7] = {0};
 
 	node = pdev->dev.of_node;
 
@@ -2629,7 +2682,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->intentless = true;
 	einfo->read_from_fifo = memcpy32_fromio;
@@ -2780,7 +2832,16 @@
 	if (rc < 0)
 		pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
 								irq_line);
-
+	einfo->debug_mask = QCOM_GLINK_DEBUG_DISABLE;
+	snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+			einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+	if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+		einfo->log_ctx =
+			ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+	if (!einfo->log_ctx)
+		GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+			__func__, einfo->xprt_cfg.edge,
+			einfo->xprt_cfg.name);
 	register_debugfs_info(einfo);
 	einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if);
 	return 0;
@@ -2790,7 +2851,6 @@
 reg_xprt_fail:
 toc_init_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2827,6 +2887,7 @@
 	struct mailbox_config_info *mbox_cfg;
 	uint32_t mbox_cfg_size;
 	phys_addr_t cfg_p_addr;
+	char log_name[GLINK_NAME_SIZE*2+7] = {0};
 
 	node = pdev->dev.of_node;
 
@@ -2922,7 +2983,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -3026,7 +3086,16 @@
 	if (rc < 0)
 		pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
 								irq_line);
-
+	einfo->debug_mask = QCOM_GLINK_DEBUG_DISABLE;
+	snprintf(log_name, sizeof(log_name), "%s_%s_xprt",
+			einfo->xprt_cfg.edge, einfo->xprt_cfg.name);
+	if (einfo->debug_mask & QCOM_GLINK_DEBUG_ENABLE)
+		einfo->log_ctx =
+			ipc_log_context_create(NUM_LOG_PAGES, log_name, 0);
+	if (!einfo->log_ctx)
+		GLINK_ERR("%s: unable to create log context for [%s:%s]\n",
+			__func__, einfo->xprt_cfg.edge,
+			einfo->xprt_cfg.name);
 	register_debugfs_info(einfo);
 
 	writel_relaxed(mbox_cfg_size, mbox_size);
@@ -3043,7 +3112,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index 239f2c1..7f97ab0 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -529,7 +529,6 @@
 	 * only modified during setup.
 	 */
 	atomic_set(&responses_remaining, ss_info->notify_list_len);
-	init_waitqueue_head(&waitqueue);
 	notifications_successful = true;
 
 	list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
@@ -935,7 +934,7 @@
 	ss_info->cb_data = NULL;
 	spin_lock_init(&ss_info->link_up_lock);
 	spin_lock_init(&ss_info->cb_lock);
-
+	init_waitqueue_head(&waitqueue);
 	nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
 	if (!nb) {
 		GLINK_SSR_ERR("<SSR> %s: Could not allocate notifier block\n",
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 2fb95fe..d92b495 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -195,6 +195,7 @@
 	ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
 	ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
 	ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+	ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
 	ICNSS_DRIVER_EVENT_MAX,
 };
 
@@ -464,6 +465,7 @@
 	bool bypass_s1_smmu;
 	bool force_err_fatal;
 	bool allow_recursive_recovery;
+	bool early_crash_ind;
 	u8 cause_for_rejuvenation;
 	u8 requesting_sub_system;
 	u16 line_number;
@@ -608,6 +610,8 @@
 		return "UNREGISTER_DRIVER";
 	case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN:
 		return "PD_SERVICE_DOWN";
+	case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
+		return "FW_EARLY_CRASH_IND";
 	case ICNSS_DRIVER_EVENT_MAX:
 		return "EVENT_MAX";
 	}
@@ -1194,7 +1198,24 @@
 	return IRQ_HANDLED;
 }
 
-static void icnss_register_force_error_fatal(struct icnss_priv *priv)
+static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
+{
+	struct icnss_priv *priv = ctx;
+
+	icnss_pr_err("Received early crash indication from FW\n");
+
+	if (priv) {
+		set_bit(ICNSS_FW_DOWN, &priv->state);
+		icnss_ignore_qmi_timeout(true);
+	}
+
+	icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
+				0, NULL);
+
+	return IRQ_HANDLED;
+}
+
+static void register_fw_error_notifications(struct icnss_priv *priv)
 {
 	int gpio, irq, ret;
 
@@ -1217,11 +1238,38 @@
 	ret = request_irq(irq, fw_error_fatal_handler,
 			IRQF_TRIGGER_RISING, "wlanfw-err", priv);
 	if (ret < 0) {
-		icnss_pr_err("Unable to regiser for error fatal IRQ handler %d",
+		icnss_pr_err("Unable to register for error fatal IRQ handler %d",
 				irq);
 		return;
 	}
 	icnss_pr_dbg("FW force error fatal handler registered\n");
+
+	if (!of_find_property(priv->pdev->dev.of_node,
+				"qcom,gpio-early-crash-ind", NULL)) {
+		icnss_pr_dbg("FW early crash indication handler not registered\n");
+		return;
+	}
+	gpio = of_get_named_gpio(priv->pdev->dev.of_node,
+				"qcom,gpio-early-crash-ind", 0);
+	if (!gpio_is_valid(gpio)) {
+		icnss_pr_err("Invalid GPIO for early crash indication %d\n",
+				gpio);
+		return;
+	}
+	irq = gpio_to_irq(gpio);
+	if (irq < 0) {
+		icnss_pr_err("Invalid IRQ for early crash indication %u\n",
+				irq);
+		return;
+	}
+	ret = request_irq(irq, fw_crash_indication_handler,
+			IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv);
+	if (ret < 0) {
+		icnss_pr_err("Unable to register for early crash indication IRQ handler %d",
+				irq);
+		return;
+	}
+	icnss_pr_dbg("FW crash indication handler registered\n");
 }
 
 static int wlfw_msa_mem_info_send_sync_msg(void)
@@ -2113,7 +2161,7 @@
 
 	icnss_init_vph_monitor(penv);
 
-	icnss_register_force_error_fatal(penv);
+	register_fw_error_notifications(penv);
 
 	return ret;
 
@@ -2213,6 +2261,7 @@
 	icnss_call_driver_shutdown(priv);
 
 	clear_bit(ICNSS_PD_RESTART, &priv->state);
+	priv->early_crash_ind = false;
 
 	if (!priv->ops || !priv->ops->reinit)
 		goto out;
@@ -2354,29 +2403,6 @@
 	return 0;
 }
 
-static int icnss_call_driver_remove(struct icnss_priv *priv)
-{
-	icnss_pr_dbg("Calling driver remove state: 0x%lx\n", priv->state);
-
-	clear_bit(ICNSS_FW_READY, &priv->state);
-
-	if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
-		return 0;
-
-	if (!priv->ops || !priv->ops->remove)
-		return 0;
-
-	set_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
-	penv->ops->remove(&priv->pdev->dev);
-
-	clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
-	clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
-
-	icnss_hw_power_off(penv);
-
-	return 0;
-}
-
 static int icnss_fw_crashed(struct icnss_priv *priv,
 			    struct icnss_event_pd_service_down_data *event_data)
 {
@@ -2390,7 +2416,7 @@
 	if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
 		icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
 
-	if (event_data->fw_rejuvenate)
+	if (event_data && event_data->fw_rejuvenate)
 		wlfw_rejuvenate_ack_send_sync_msg(priv);
 
 	return 0;
@@ -2405,6 +2431,12 @@
 	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
 		goto out;
 
+	if (priv->early_crash_ind) {
+		icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n",
+			     event_data->crashed, priv->state);
+		goto out;
+	}
+
 	if (test_bit(ICNSS_PD_RESTART, &priv->state) && event_data->crashed) {
 		icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n",
 			     event_data->crashed, priv->state);
@@ -2416,10 +2448,7 @@
 	if (priv->force_err_fatal)
 		ICNSS_ASSERT(0);
 
-	if (event_data->crashed)
-		icnss_fw_crashed(priv, event_data);
-	else
-		icnss_call_driver_remove(priv);
+	icnss_fw_crashed(priv, event_data);
 
 out:
 	kfree(data);
@@ -2429,6 +2458,25 @@
 	return ret;
 }
 
+static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv,
+					      void *data)
+{
+	int ret = 0;
+
+	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
+		goto out;
+
+	priv->early_crash_ind = true;
+	icnss_fw_crashed(priv, NULL);
+
+out:
+	kfree(data);
+	icnss_ignore_qmi_timeout(false);
+
+	return ret;
+}
+
+
 static void icnss_driver_event_work(struct work_struct *work)
 {
 	struct icnss_driver_event *event;
@@ -2470,6 +2518,10 @@
 			ret = icnss_driver_event_pd_service_down(penv,
 								 event->data);
 			break;
+		case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
+			ret = icnss_driver_event_early_crash_ind(penv,
+								 event->data);
+			break;
 		default:
 			icnss_pr_err("Invalid Event type: %d", event->type);
 			kfree(event);
@@ -3102,6 +3154,12 @@
 	if (!dev)
 		return -ENODEV;
 
+	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+		icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n",
+			     penv->state);
+		return -EINVAL;
+	}
+
 	icnss_pr_dbg("FW log mode: %u\n", fw_log_mode);
 
 	ret = wlfw_ini_send_sync_msg(fw_log_mode);
@@ -3195,6 +3253,12 @@
 	if (!dev)
 		return -ENODEV;
 
+	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+		icnss_pr_err("FW down, ignoring wlan_enable state: 0x%lx\n",
+			     penv->state);
+		return -EINVAL;
+	}
+
 	icnss_pr_dbg("Mode: %d, config: %p, host_version: %s\n",
 		     mode, config, host_version);
 
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index cef3c77..c93e0e1 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -31,6 +31,7 @@
 module_param_named(debug_mask, ipc_router_glink_xprt_debug_mask,
 		   int, 0664);
 
+#define IPCRTR_INTENT_REQ_TIMEOUT_MS 5000
 #if defined(DEBUG)
 #define D(x...) do { \
 if (ipc_router_glink_xprt_debug_mask) \
@@ -43,6 +44,7 @@
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 #define IPC_RTR_XPRT_NAME_LEN (2 * GLINK_NAME_SIZE)
 #define PIL_SUBSYSTEM_NAME_LEN 32
+#define IPC_RTR_WS_NAME_LEN ((2 * GLINK_NAME_SIZE) + 4)
 
 #define MAX_NUM_LO_INTENTS 5
 #define MAX_NUM_MD_INTENTS 3
@@ -59,6 +61,7 @@
  * @transport: Physical Transport Name as identified by Glink.
  * @pil_edge: Edge name understood by PIL.
  * @ipc_rtr_xprt_name: XPRT Name to be registered with IPC Router.
+ * @notify_rx_ws_name: Name of wakesource used in notify rx path.
  * @xprt: IPC Router XPRT structure to contain XPRT specific info.
  * @ch_hndl: Opaque Channel handle returned by GLink.
  * @xprt_wq: Workqueue to queue read & other XPRT related works.
@@ -79,9 +82,11 @@
 	char transport[GLINK_NAME_SIZE];
 	char pil_edge[PIL_SUBSYSTEM_NAME_LEN];
 	char ipc_rtr_xprt_name[IPC_RTR_XPRT_NAME_LEN];
+	char notify_rx_ws_name[IPC_RTR_WS_NAME_LEN];
 	struct msm_ipc_router_xprt xprt;
 	void *ch_hndl;
 	struct workqueue_struct *xprt_wq;
+	struct wakeup_source notify_rxv_ws;
 	struct rw_semaphore ss_reset_rwlock;
 	int ss_reset;
 	void *pil;
@@ -379,6 +384,7 @@
 	glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
 	kfree(rx_work);
 	up_read(&glink_xprtp->ss_reset_rwlock);
+	__pm_relax(&glink_xprtp->notify_rxv_ws);
 }
 
 static void glink_xprt_open_event(struct work_struct *work)
@@ -493,6 +499,8 @@
 	rx_work->iovec_size = size;
 	rx_work->vbuf_provider = vbuf_provider;
 	rx_work->pbuf_provider = pbuf_provider;
+	if (!glink_xprtp->dynamic_wakeup_source)
+		__pm_stay_awake(&glink_xprtp->notify_rxv_ws);
 	INIT_WORK(&rx_work->work, glink_xprt_read_data);
 	queue_work(glink_xprtp->xprt_wq, &rx_work->work);
 }
@@ -602,6 +610,7 @@
 	open_cfg.notify_state = glink_xprt_notify_state;
 	open_cfg.notify_rx_intent_req = glink_xprt_notify_rx_intent_req;
 	open_cfg.priv = glink_xprtp;
+	open_cfg.rx_intent_req_timeout_ms = IPCRTR_INTENT_REQ_TIMEOUT_MS;
 
 	glink_xprtp->pil = msm_ipc_load_subsystem(glink_xprtp);
 	glink_xprtp->ch_hndl =  glink_open(&open_cfg);
@@ -760,7 +769,10 @@
 		kfree(glink_xprtp);
 		return -EFAULT;
 	}
-
+	scnprintf(glink_xprtp->notify_rx_ws_name, IPC_RTR_WS_NAME_LEN,
+			"%s_%s_rx", glink_xprtp->ch_name, glink_xprtp->edge);
+	wakeup_source_init(&glink_xprtp->notify_rxv_ws,
+				glink_xprtp->notify_rx_ws_name);
 	mutex_lock(&glink_xprt_list_lock_lha1);
 	list_add(&glink_xprtp->list, &glink_xprt_list);
 	mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index 4a41eee..97c2f51 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 2018 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
@@ -694,11 +694,14 @@
 {
 	struct list_head *centry = NULL;
 	struct lpm_stats *pos = NULL;
+	struct lpm_stats *n = NULL;
 
 	centry = &stats->child;
-	list_for_each_entry_reverse(pos, centry, sibling) {
-		if (!list_empty(&pos->child))
+	list_for_each_entry_safe_reverse(pos, n, centry, sibling) {
+		if (!list_empty(&pos->child)) {
 			cleanup_stats(pos);
+			continue;
+		}
 
 		list_del_init(&pos->child);
 
diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
index e58fa2e..0ae25a1 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.c
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -324,7 +324,7 @@
 {
 	int i;
 	int ret;
-	u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA};
+	u32 source_vmlist[1] = {VMID_MSS_MSA};
 	int dest_vmids[1] = {VMID_HLOS};
 	int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
 	struct notif_data *notifdata = NULL;
@@ -335,6 +335,9 @@
 
 	case SUBSYS_BEFORE_SHUTDOWN:
 		bootup_request++;
+		for (i = 0; ((i < MAX_CLIENTS) &&
+			!memblock[i].guarantee); i++)
+			memblock[i].alloc_request = 0;
 		break;
 
 	case SUBSYS_RAMDUMP_NOTIFICATION:
@@ -374,14 +377,15 @@
 				if (memblock[i].peripheral ==
 					DHMS_MEM_PROC_MPSS_V01 &&
 					!memblock[i].guarantee &&
-					memblock[i].allotted) {
+					memblock[i].allotted &&
+					!memblock[i].alloc_request) {
 					pr_debug("memshare: hypervisor unmapping  for client id: %d\n",
 						memblock[i].client_id);
 					ret = hyp_assign_phys(
 							memblock[i].phy_addr,
 							memblock[i].size,
 							source_vmlist,
-							2, dest_vmids,
+							1, dest_vmids,
 							dest_perms, 1);
 					if (ret &&
 						memblock[i].hyp_mapping == 1) {
@@ -393,7 +397,6 @@
 						 */
 						pr_err("memshare: %s, failed to unmap the region\n",
 							__func__);
-						memblock[i].hyp_mapping = 1;
 					} else {
 						memblock[i].hyp_mapping = 0;
 					}
@@ -425,9 +428,8 @@
 {
 	int ret;
 	u32 source_vmlist[1] = {VMID_HLOS};
-	int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA};
-	int dest_perms[2] = {PERM_READ|PERM_WRITE,
-				PERM_READ|PERM_WRITE};
+	int dest_vmids[1] = {VMID_MSS_MSA};
+	int dest_perms[1] = {PERM_READ|PERM_WRITE};
 
 	if (client_id == DHMS_MEM_CLIENT_INVALID) {
 		pr_err("memshare: %s, Invalid Client\n", __func__);
@@ -437,7 +439,7 @@
 	ret = hyp_assign_phys(memblock[client_id].phy_addr,
 			memblock[client_id].size,
 			source_vmlist, 1, dest_vmids,
-			dest_perms, 2);
+			dest_perms, 1);
 
 	if (ret != 0) {
 		pr_err("memshare: hyp_assign_phys failed size=%u err=%d\n",
@@ -539,6 +541,7 @@
 			memblock[client_id].allotted = 1;
 			memblock[client_id].size = alloc_req->num_bytes;
 			memblock[client_id].peripheral = alloc_req->proc_id;
+			memblock[client_id].alloc_request = 1;
 		}
 	}
 	pr_debug("memshare: In %s, free memory count for client id: %d = %d",
@@ -603,9 +606,11 @@
 {
 	struct mem_free_generic_req_msg_v01 *free_req;
 	struct mem_free_generic_resp_msg_v01 free_resp;
-	int rc;
-	int flag = 0;
+	int rc, flag = 0, ret = 0;
 	uint32_t client_id;
+	u32 source_vmlist[1] = {VMID_MSS_MSA};
+	int dest_vmids[1] = {VMID_HLOS};
+	int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
 
 	mutex_lock(&memsh_drv->mem_free);
 	free_req = (struct mem_free_generic_req_msg_v01 *)req;
@@ -624,6 +629,17 @@
 					memblock[client_id].allotted) {
 		pr_debug("memshare: %s: size: %d",
 				__func__, memblock[client_id].size);
+		ret = hyp_assign_phys(memblock[client_id].phy_addr,
+				memblock[client_id].size, source_vmlist, 1,
+				dest_vmids, dest_perms, 1);
+		if (ret && memblock[client_id].hyp_mapping == 1) {
+		/*
+		 * This is an error case as hyp mapping was successful
+		 * earlier but during unmap it lead to failure.
+		 */
+			pr_err("memshare: %s, failed to unmap the region\n",
+				__func__);
+		}
 		dma_free_attrs(memsh_drv->dev, memblock[client_id].size,
 			memblock[client_id].virtual_addr,
 			memblock[client_id].phy_addr,
@@ -959,6 +975,7 @@
 			return rc;
 		}
 		memblock[num_clients].allotted = 1;
+		memblock[num_clients].alloc_request = 1;
 		shared_hyp_mapping(num_clients);
 	}
 
diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h
index ca11137..6b54652 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.h
+++ b/drivers/soc/qcom/memshare/msm_memshare.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,8 @@
 	uint32_t guarantee;
 	/* Memory alloted or not */
 	uint32_t allotted;
+	/* Memory allocation request received or not */
+	uint32_t alloc_request;
 	/* Size required for client */
 	uint32_t size;
 	/*
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
index 47f3336..4a22b4d 100644
--- a/drivers/soc/qcom/microdump_collector.c
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -41,7 +41,7 @@
 	unsigned int smem_id = 611;
 	struct ramdump_segment segment[2];
 
-	if (code == SUBSYS_RAMDUMP_NOTIFICATION) {
+	if (SUBSYS_RAMDUMP_NOTIFICATION == code || SUBSYS_SOC_RESET == code) {
 
 		memset(segment, 0, sizeof(segment));
 
diff --git a/drivers/soc/qcom/msm_bus/Makefile b/drivers/soc/qcom/msm_bus/Makefile
index 15569b1..c2ef70c 100644
--- a/drivers/soc/qcom/msm_bus/Makefile
+++ b/drivers/soc/qcom/msm_bus/Makefile
@@ -7,7 +7,7 @@
 
 ifdef CONFIG_QCOM_BUS_CONFIG_RPMH
 	obj-y += msm_bus_fabric_rpmh.o msm_bus_arb_rpmh.o msm_bus_rules.o \
-		msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o
+		msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o msm_bus_proxy_client.o
 	obj-$(CONFIG_OF) += msm_bus_of_rpmh.o
 else
 	obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o \
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
index 437984c..8af9b5a 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -1133,7 +1133,7 @@
 	}
 
 	curr = client->curr;
-	if (curr >= pdata->num_usecases) {
+	if (curr >= pdata->num_usecases || curr < 0) {
 		MSM_BUS_ERR("Invalid index Defaulting curr to 0");
 		curr = 0;
 	}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
index 95c127d..974f74e 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -243,7 +243,7 @@
 	(M_BKE_GC_GC_BMSK >> \
 	(M_BKE_GC_GC_SHFT + 1))
 
-static int bimc_div(int64_t *a, uint32_t b)
+static int bimc_div(uint64_t *a, uint32_t b)
 {
 	if ((*a > 0) && (*a < b)) {
 		*a = 0;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c
new file mode 100644
index 0000000..cdf61f6
--- /dev/null
+++ b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/msm-bus.h>
+
+struct proxy_client {
+	struct msm_bus_scale_pdata *pdata;
+	unsigned int client_handle;
+};
+
+static struct proxy_client proxy_client_info;
+
+static int msm_bus_device_proxy_client_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	proxy_client_info.pdata = msm_bus_cl_get_pdata(pdev);
+
+	if (!proxy_client_info.pdata)
+		return 0;
+
+	proxy_client_info.client_handle =
+		msm_bus_scale_register_client(proxy_client_info.pdata);
+
+	if (!proxy_client_info.client_handle) {
+		dev_err(&pdev->dev, "Unable to register bus client\n");
+		return -ENODEV;
+	}
+
+	ret = msm_bus_scale_client_update_request(
+					proxy_client_info.client_handle, 1);
+	if (ret)
+		dev_err(&pdev->dev, "Bandwidth update failed (%d)\n", ret);
+
+	return ret;
+}
+
+static const struct of_device_id proxy_client_match[] = {
+	{.compatible = "qcom,bus-proxy-client"},
+	{}
+};
+
+static struct platform_driver msm_bus_proxy_client_driver = {
+	.probe = msm_bus_device_proxy_client_probe,
+	.driver = {
+		.name = "msm_bus_proxy_client_device",
+		.owner = THIS_MODULE,
+		.of_match_table = proxy_client_match,
+	},
+};
+
+static int __init msm_bus_proxy_client_init_driver(void)
+{
+	int rc;
+
+	rc =  platform_driver_register(&msm_bus_proxy_client_driver);
+	if (rc) {
+		pr_err("Failed to register proxy client device driver");
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __init msm_bus_proxy_client_unvote(void)
+{
+	int ret;
+
+	if (!proxy_client_info.pdata || !proxy_client_info.client_handle)
+		return 0;
+
+	ret = msm_bus_scale_client_update_request(
+					proxy_client_info.client_handle, 0);
+	if (ret)
+		pr_err("%s: bandwidth update request failed (%d)\n",
+			__func__, ret);
+
+	msm_bus_scale_unregister_client(proxy_client_info.client_handle);
+
+	return 0;
+}
+
+subsys_initcall_sync(msm_bus_proxy_client_init_driver);
+late_initcall_sync(msm_bus_proxy_client_unvote);
diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c
index b5ce753..fb3af15 100644
--- a/drivers/soc/qcom/msm_performance.c
+++ b/drivers/soc/qcom/msm_performance.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -26,59 +26,6 @@
 #include <linux/input.h>
 #include <linux/kthread.h>
 
-static struct mutex managed_cpus_lock;
-
-/* Maximum number to clusters that this module will manage */
-static unsigned int num_clusters;
-struct cluster {
-	cpumask_var_t cpus;
-	/* stats for load detection */
-	/* IO */
-	u64 last_io_check_ts;
-	unsigned int iowait_enter_cycle_cnt;
-	unsigned int iowait_exit_cycle_cnt;
-	spinlock_t iowait_lock;
-	unsigned int cur_io_busy;
-	bool io_change;
-	/* CPU */
-	unsigned int mode;
-	bool mode_change;
-	u64 last_mode_check_ts;
-	unsigned int single_enter_cycle_cnt;
-	unsigned int single_exit_cycle_cnt;
-	unsigned int multi_enter_cycle_cnt;
-	unsigned int multi_exit_cycle_cnt;
-	spinlock_t mode_lock;
-	/* Perf Cluster Peak Loads */
-	unsigned int perf_cl_peak;
-	u64 last_perf_cl_check_ts;
-	bool perf_cl_detect_state_change;
-	unsigned int perf_cl_peak_enter_cycle_cnt;
-	unsigned int perf_cl_peak_exit_cycle_cnt;
-	spinlock_t perf_cl_peak_lock;
-	/* Tunables */
-	unsigned int single_enter_load;
-	unsigned int pcpu_multi_enter_load;
-	unsigned int perf_cl_peak_enter_load;
-	unsigned int single_exit_load;
-	unsigned int pcpu_multi_exit_load;
-	unsigned int perf_cl_peak_exit_load;
-	unsigned int single_enter_cycles;
-	unsigned int single_exit_cycles;
-	unsigned int multi_enter_cycles;
-	unsigned int multi_exit_cycles;
-	unsigned int perf_cl_peak_enter_cycles;
-	unsigned int perf_cl_peak_exit_cycles;
-	unsigned int current_freq;
-	spinlock_t timer_lock;
-	unsigned int timer_rate;
-	struct timer_list mode_exit_timer;
-	struct timer_list perf_cl_peak_mode_exit_timer;
-};
-
-static struct cluster **managed_clusters;
-static bool clusters_inited;
-
 
 /* To handle cpufreq min/max request */
 struct cpu_status {
@@ -87,8 +34,6 @@
 };
 static DEFINE_PER_CPU(struct cpu_status, cpu_stats);
 
-static int init_cluster_control(void);
-static int init_events_group(void);
 struct events {
 	spinlock_t cpu_hotplug_lock;
 	bool cpu_hotplug;
@@ -97,176 +42,7 @@
 static struct events events_group;
 static struct task_struct *events_notify_thread;
 
-#define LAST_UPDATE_TOL		USEC_PER_MSEC
-
-struct input_events {
-	unsigned int evt_x_cnt;
-	unsigned int evt_y_cnt;
-	unsigned int evt_pres_cnt;
-	unsigned int evt_dist_cnt;
-};
-struct trig_thr {
-	unsigned int pwr_cl_trigger_threshold;
-	unsigned int perf_cl_trigger_threshold;
-	unsigned int ip_evt_threshold;
-};
-struct load_stats {
-	u64 last_wallclock;
-	/* IO wait related */
-	u64 last_iowait;
-	unsigned int last_iopercent;
-	/* CPU load related */
-	unsigned int cpu_load;
-	/* CPU Freq */
-	unsigned int freq;
-};
-static bool input_events_handler_registered;
-static struct input_events *ip_evts;
-static struct trig_thr thr;
-static unsigned int use_input_evts_with_hi_slvt_detect;
-static int register_input_handler(void);
-static void unregister_input_handler(void);
-static DEFINE_PER_CPU(struct load_stats, cpu_load_stats);
-
-/* Bitmask to keep track of the workloads being detected */
-static unsigned int workload_detect;
-#define IO_DETECT	1
-#define MODE_DETECT	2
-#define PERF_CL_PEAK_DETECT	4
-
-/* IOwait related tunables */
-static unsigned int io_enter_cycles = 4;
-static unsigned int io_exit_cycles = 4;
-static u64 iowait_ceiling_pct = 25;
-static u64 iowait_floor_pct = 8;
-#define LAST_IO_CHECK_TOL	(3 * USEC_PER_MSEC)
-
-static unsigned int aggr_iobusy;
-static unsigned int aggr_mode;
-
-static struct task_struct *notify_thread;
-
-static struct input_handler *handler;
-
-/* CPU workload detection related */
-#define NO_MODE		(0)
-#define SINGLE		(1)
-#define MULTI		(2)
-#define MIXED		(3)
-#define PERF_CL_PEAK		(4)
-#define DEF_SINGLE_ENT		90
-#define DEF_PCPU_MULTI_ENT	85
-#define DEF_PERF_CL_PEAK_ENT	80
-#define DEF_SINGLE_EX		60
-#define DEF_PCPU_MULTI_EX	50
-#define DEF_PERF_CL_PEAK_EX		70
-#define DEF_SINGLE_ENTER_CYCLE	4
-#define DEF_SINGLE_EXIT_CYCLE	4
-#define DEF_MULTI_ENTER_CYCLE	4
-#define DEF_MULTI_EXIT_CYCLE	4
-#define DEF_PERF_CL_PEAK_ENTER_CYCLE	100
-#define DEF_PERF_CL_PEAK_EXIT_CYCLE	20
-#define LAST_LD_CHECK_TOL	(2 * USEC_PER_MSEC)
-#define CLUSTER_0_THRESHOLD_FREQ	147000
-#define CLUSTER_1_THRESHOLD_FREQ	190000
-#define INPUT_EVENT_CNT_THRESHOLD	15
-#define MAX_LENGTH_CPU_STRING	256
-
 /**************************sysfs start********************************/
-
-static int set_num_clusters(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-	if (num_clusters)
-		return -EINVAL;
-
-	num_clusters = val;
-
-	if (init_cluster_control()) {
-		num_clusters = 0;
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static int get_num_clusters(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", num_clusters);
-}
-
-static const struct kernel_param_ops param_ops_num_clusters = {
-	.set = set_num_clusters,
-	.get = get_num_clusters,
-};
-device_param_cb(num_clusters, &param_ops_num_clusters, NULL, 0644);
-
-
-static int set_managed_cpus(const char *buf, const struct kernel_param *kp)
-{
-	int i, ret;
-	struct cpumask tmp_mask;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	ret = cpulist_parse(buf, &tmp_mask);
-
-	if (ret)
-		return ret;
-
-	for (i = 0; i < num_clusters; i++) {
-		if (cpumask_empty(managed_clusters[i]->cpus)) {
-			mutex_lock(&managed_cpus_lock);
-			cpumask_copy(managed_clusters[i]->cpus, &tmp_mask);
-			mutex_unlock(&managed_cpus_lock);
-			break;
-		}
-	}
-
-	return ret;
-}
-
-static int get_managed_cpus(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0, total_cnt = 0;
-	char tmp[MAX_LENGTH_CPU_STRING] = "";
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++) {
-		cnt = cpumap_print_to_pagebuf(true, buf,
-						managed_clusters[i]->cpus);
-		if ((i + 1) < num_clusters &&
-		    (total_cnt + cnt + 1) <= MAX_LENGTH_CPU_STRING) {
-			snprintf(tmp + total_cnt, cnt, "%s", buf);
-			tmp[cnt-1] = ':';
-			tmp[cnt] = '\0';
-			total_cnt += cnt;
-		} else if ((i + 1) == num_clusters &&
-			(total_cnt + cnt) <= MAX_LENGTH_CPU_STRING) {
-			snprintf(tmp + total_cnt, cnt, "%s", buf);
-			total_cnt += cnt;
-		} else {
-			pr_err("invalid string for managed_cpu:%s%s\n", tmp,
-				buf);
-			break;
-		}
-	}
-	snprintf(buf, PAGE_SIZE, "%s", tmp);
-	return total_cnt;
-}
-
-static const struct kernel_param_ops param_ops_managed_cpus = {
-	.set = set_managed_cpus,
-	.get = get_managed_cpus,
-};
-device_param_cb(managed_cpus, &param_ops_managed_cpus, NULL, 0644);
-
 /*
  * Userspace sends cpu#:min_freq_value to vote for min_freq_value as the new
  * scaling_min. To withdraw its vote it needs to enter cpu#:0
@@ -425,1716 +201,8 @@
 };
 module_param_cb(cpu_max_freq, &param_ops_cpu_max_freq, NULL, 0644);
 
-static int set_ip_evt_trigger_threshold(const char *buf,
-		const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	thr.ip_evt_threshold = val;
-	return 0;
-}
-
-static int get_ip_evt_trigger_threshold(char *buf,
-		const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", thr.ip_evt_threshold);
-}
-
-static const struct kernel_param_ops param_ops_ip_evt_trig_thr = {
-	.set = set_ip_evt_trigger_threshold,
-	.get = get_ip_evt_trigger_threshold,
-};
-device_param_cb(ip_evt_trig_thr, &param_ops_ip_evt_trig_thr, NULL, 0644);
-
-
-static int set_perf_cl_trigger_threshold(const char *buf,
-		 const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	thr.perf_cl_trigger_threshold = val;
-	return 0;
-}
-
-static int get_perf_cl_trigger_threshold(char *buf,
-		const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", thr.perf_cl_trigger_threshold);
-}
-
-static const struct kernel_param_ops param_ops_perf_trig_thr = {
-	.set = set_perf_cl_trigger_threshold,
-	.get = get_perf_cl_trigger_threshold,
-};
-device_param_cb(perf_cl_trig_thr, &param_ops_perf_trig_thr, NULL, 0644);
-
-
-static int set_pwr_cl_trigger_threshold(const char *buf,
-		const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	thr.pwr_cl_trigger_threshold = val;
-	return 0;
-}
-
-static int get_pwr_cl_trigger_threshold(char *buf,
-		const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", thr.pwr_cl_trigger_threshold);
-}
-
-static const struct kernel_param_ops param_ops_pwr_trig_thr = {
-	.set = set_pwr_cl_trigger_threshold,
-	.get = get_pwr_cl_trigger_threshold,
-};
-device_param_cb(pwr_cl_trig_thr, &param_ops_pwr_trig_thr, NULL, 0644);
-
-static int freq_greater_than_threshold(struct cluster *cl, int idx)
-{
-	int rc = 0;
-	/* Check for Cluster 0 */
-	if (!idx && cl->current_freq >= thr.pwr_cl_trigger_threshold)
-		rc = 1;
-	/* Check for Cluster 1 */
-	if (idx && cl->current_freq >= thr.perf_cl_trigger_threshold)
-		rc = 1;
-	return rc;
-}
-
-static bool input_events_greater_than_threshold(void)
-{
-
-	bool rc = false;
-
-	if ((ip_evts->evt_x_cnt >= thr.ip_evt_threshold) ||
-	    (ip_evts->evt_y_cnt >= thr.ip_evt_threshold) ||
-	    !use_input_evts_with_hi_slvt_detect)
-		rc = true;
-
-	return rc;
-}
-
-static int set_single_enter_load(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val < managed_clusters[i]->single_exit_load)
-			return -EINVAL;
-
-		managed_clusters[i]->single_enter_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_single_enter_load(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-				"%u:", managed_clusters[i]->single_enter_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_enter_load = {
-	.set = set_single_enter_load,
-	.get = get_single_enter_load,
-};
-device_param_cb(single_enter_load, &param_ops_single_enter_load, NULL, 0644);
-
-static int set_single_exit_load(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val > managed_clusters[i]->single_enter_load)
-			return -EINVAL;
-
-		managed_clusters[i]->single_exit_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_single_exit_load(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-				"%u:", managed_clusters[i]->single_exit_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_exit_load = {
-	.set = set_single_exit_load,
-	.get = get_single_exit_load,
-};
-device_param_cb(single_exit_load, &param_ops_single_exit_load, NULL, 0644);
-
-static int set_pcpu_multi_enter_load(const char *buf,
-					const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val < managed_clusters[i]->pcpu_multi_exit_load)
-			return -EINVAL;
-
-		managed_clusters[i]->pcpu_multi_enter_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_pcpu_multi_enter_load(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-			"%u:", managed_clusters[i]->pcpu_multi_enter_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_pcpu_multi_enter_load = {
-	.set = set_pcpu_multi_enter_load,
-	.get = get_pcpu_multi_enter_load,
-};
-device_param_cb(pcpu_multi_enter_load, &param_ops_pcpu_multi_enter_load,
-								NULL, 0644);
-
-static int set_pcpu_multi_exit_load(const char *buf,
-						const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val > managed_clusters[i]->pcpu_multi_enter_load)
-			return -EINVAL;
-
-		managed_clusters[i]->pcpu_multi_exit_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_pcpu_multi_exit_load(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-			"%u:", managed_clusters[i]->pcpu_multi_exit_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_pcpu_multi_exit_load = {
-	.set = set_pcpu_multi_exit_load,
-	.get = get_pcpu_multi_exit_load,
-};
-device_param_cb(pcpu_multi_exit_load, &param_ops_pcpu_multi_exit_load,
-		NULL, 0644);
-static int set_perf_cl_peak_enter_load(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val < managed_clusters[i]->perf_cl_peak_exit_load)
-			return -EINVAL;
-
-		managed_clusters[i]->perf_cl_peak_enter_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_perf_cl_peak_enter_load(char *buf,
-				const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-			"%u:", managed_clusters[i]->perf_cl_peak_enter_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_enter_load = {
-	.set = set_perf_cl_peak_enter_load,
-	.get = get_perf_cl_peak_enter_load,
-};
-device_param_cb(perf_cl_peak_enter_load, &param_ops_perf_cl_peak_enter_load,
-		 NULL, 0644);
-
-static int set_perf_cl_peak_exit_load(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		if (val > managed_clusters[i]->perf_cl_peak_enter_load)
-			return -EINVAL;
-
-		managed_clusters[i]->perf_cl_peak_exit_load = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_perf_cl_peak_exit_load(char *buf,
-				const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-			"%u:", managed_clusters[i]->perf_cl_peak_exit_load);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_exit_load = {
-	.set = set_perf_cl_peak_exit_load,
-	.get = get_perf_cl_peak_exit_load,
-};
-device_param_cb(perf_cl_peak_exit_load, &param_ops_perf_cl_peak_exit_load,
-		 NULL, 0644);
-
-static int set_perf_cl_peak_enter_cycles(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->perf_cl_peak_enter_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_perf_cl_peak_enter_cycles(char *buf,
-				const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%u:",
-				managed_clusters[i]->perf_cl_peak_enter_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_enter_cycles = {
-	.set = set_perf_cl_peak_enter_cycles,
-	.get = get_perf_cl_peak_enter_cycles,
-};
-device_param_cb(perf_cl_peak_enter_cycles, &param_ops_perf_cl_peak_enter_cycles,
-		NULL, 0644);
-
-
-static int set_perf_cl_peak_exit_cycles(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->perf_cl_peak_exit_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_perf_cl_peak_exit_cycles(char *buf,
-			const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-			"%u:", managed_clusters[i]->perf_cl_peak_exit_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_perf_cl_peak_exit_cycles = {
-	.set = set_perf_cl_peak_exit_cycles,
-	.get = get_perf_cl_peak_exit_cycles,
-};
-device_param_cb(perf_cl_peak_exit_cycles, &param_ops_perf_cl_peak_exit_cycles,
-		 NULL, 0644);
-
-
-static int set_single_enter_cycles(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->single_enter_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_single_enter_cycles(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%u:",
-				managed_clusters[i]->single_enter_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_enter_cycles = {
-	.set = set_single_enter_cycles,
-	.get = get_single_enter_cycles,
-};
-device_param_cb(single_enter_cycles, &param_ops_single_enter_cycles,
-		NULL, 0644);
-
-
-static int set_single_exit_cycles(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->single_exit_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_single_exit_cycles(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-				"%u:", managed_clusters[i]->single_exit_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_single_exit_cycles = {
-	.set = set_single_exit_cycles,
-	.get = get_single_exit_cycles,
-};
-device_param_cb(single_exit_cycles, &param_ops_single_exit_cycles, NULL, 0644);
-
-static int set_multi_enter_cycles(const char *buf,
-				const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->multi_enter_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_multi_enter_cycles(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-				"%u:", managed_clusters[i]->multi_enter_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_multi_enter_cycles = {
-	.set = set_multi_enter_cycles,
-	.get = get_multi_enter_cycles,
-};
-device_param_cb(multi_enter_cycles, &param_ops_multi_enter_cycles, NULL, 0644);
-
-static int set_multi_exit_cycles(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val, i, ntokens = 0;
-	const char *cp = buf;
-	unsigned int bytes_left;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	while ((cp = strpbrk(cp + 1, ":")))
-		ntokens++;
-
-	if (ntokens != (num_clusters - 1))
-		return -EINVAL;
-
-	cp = buf;
-	for (i = 0; i < num_clusters; i++) {
-
-		if (sscanf(cp, "%u\n", &val) != 1)
-			return -EINVAL;
-
-		managed_clusters[i]->multi_exit_cycles = val;
-
-		bytes_left = PAGE_SIZE - (cp - buf);
-		cp = strnchr(cp, bytes_left, ':');
-		cp++;
-	}
-
-	return 0;
-}
-
-static int get_multi_exit_cycles(char *buf, const struct kernel_param *kp)
-{
-	int i, cnt = 0;
-
-	if (!clusters_inited)
-		return cnt;
-
-	for (i = 0; i < num_clusters; i++)
-		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
-				"%u:", managed_clusters[i]->multi_exit_cycles);
-	cnt--;
-	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " ");
-	return cnt;
-}
-
-static const struct kernel_param_ops param_ops_multi_exit_cycles = {
-	.set = set_multi_exit_cycles,
-	.get = get_multi_exit_cycles,
-};
-device_param_cb(multi_exit_cycles, &param_ops_multi_exit_cycles, NULL, 0644);
-
-static int set_io_enter_cycles(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	io_enter_cycles = val;
-
-	return 0;
-}
-
-static int get_io_enter_cycles(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", io_enter_cycles);
-}
-
-static const struct kernel_param_ops param_ops_io_enter_cycles = {
-	.set = set_io_enter_cycles,
-	.get = get_io_enter_cycles,
-};
-device_param_cb(io_enter_cycles, &param_ops_io_enter_cycles, NULL, 0644);
-
-static int set_io_exit_cycles(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	io_exit_cycles = val;
-
-	return 0;
-}
-
-static int get_io_exit_cycles(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", io_exit_cycles);
-}
-
-static const struct kernel_param_ops param_ops_io_exit_cycles = {
-	.set = set_io_exit_cycles,
-	.get = get_io_exit_cycles,
-};
-device_param_cb(io_exit_cycles, &param_ops_io_exit_cycles, NULL, 0644);
-
-static int set_iowait_floor_pct(const char *buf, const struct kernel_param *kp)
-{
-	u64 val;
-
-	if (sscanf(buf, "%llu\n", &val) != 1)
-		return -EINVAL;
-	if (val > iowait_ceiling_pct)
-		return -EINVAL;
-
-	iowait_floor_pct = val;
-
-	return 0;
-}
-
-static int get_iowait_floor_pct(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%llu", iowait_floor_pct);
-}
-
-static const struct kernel_param_ops param_ops_iowait_floor_pct = {
-	.set = set_iowait_floor_pct,
-	.get = get_iowait_floor_pct,
-};
-device_param_cb(iowait_floor_pct, &param_ops_iowait_floor_pct, NULL, 0644);
-
-static int set_iowait_ceiling_pct(const char *buf,
-						const struct kernel_param *kp)
-{
-	u64 val;
-
-	if (sscanf(buf, "%llu\n", &val) != 1)
-		return -EINVAL;
-	if (val < iowait_floor_pct)
-		return -EINVAL;
-
-	iowait_ceiling_pct = val;
-
-	return 0;
-}
-
-static int get_iowait_ceiling_pct(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%llu", iowait_ceiling_pct);
-}
-
-static const struct kernel_param_ops param_ops_iowait_ceiling_pct = {
-	.set = set_iowait_ceiling_pct,
-	.get = get_iowait_ceiling_pct,
-};
-device_param_cb(iowait_ceiling_pct, &param_ops_iowait_ceiling_pct, NULL, 0644);
-
-static int set_workload_detect(const char *buf, const struct kernel_param *kp)
-{
-	unsigned int val, i;
-	struct cluster *i_cl;
-	unsigned long flags;
-
-	if (!clusters_inited)
-		return -EINVAL;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	if (val == workload_detect)
-		return 0;
-
-	workload_detect = val;
-	if (!(workload_detect & IO_DETECT)) {
-		for (i = 0; i < num_clusters; i++) {
-			i_cl = managed_clusters[i];
-			spin_lock_irqsave(&i_cl->iowait_lock, flags);
-			i_cl->iowait_enter_cycle_cnt = 0;
-			i_cl->iowait_exit_cycle_cnt = 0;
-			i_cl->cur_io_busy = 0;
-			i_cl->io_change = true;
-			spin_unlock_irqrestore(&i_cl->iowait_lock, flags);
-		}
-	}
-	if (!(workload_detect & MODE_DETECT)) {
-		for (i = 0; i < num_clusters; i++) {
-			i_cl = managed_clusters[i];
-			spin_lock_irqsave(&i_cl->mode_lock, flags);
-			i_cl->single_enter_cycle_cnt = 0;
-			i_cl->single_exit_cycle_cnt = 0;
-			i_cl->multi_enter_cycle_cnt = 0;
-			i_cl->multi_exit_cycle_cnt = 0;
-			i_cl->mode = 0;
-			i_cl->mode_change = true;
-			spin_unlock_irqrestore(&i_cl->mode_lock, flags);
-		}
-	}
-
-	if (!(workload_detect & PERF_CL_PEAK_DETECT)) {
-		for (i = 0; i < num_clusters; i++) {
-			i_cl = managed_clusters[i];
-			spin_lock_irqsave(&i_cl->perf_cl_peak_lock, flags);
-			i_cl->perf_cl_peak_enter_cycle_cnt = 0;
-			i_cl->perf_cl_peak_exit_cycle_cnt = 0;
-			i_cl->perf_cl_peak = 0;
-			spin_unlock_irqrestore(&i_cl->perf_cl_peak_lock, flags);
-		}
-	}
-
-	wake_up_process(notify_thread);
-	return 0;
-}
-
-static int get_workload_detect(char *buf, const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u", workload_detect);
-}
-
-static const struct kernel_param_ops param_ops_workload_detect = {
-	.set = set_workload_detect,
-	.get = get_workload_detect,
-};
-device_param_cb(workload_detect, &param_ops_workload_detect, NULL, 0644);
-
-
-static int set_input_evts_with_hi_slvt_detect(const char *buf,
-					const struct kernel_param *kp)
-{
-
-	unsigned int val;
-
-	if (sscanf(buf, "%u\n", &val) != 1)
-		return -EINVAL;
-
-	if (val == use_input_evts_with_hi_slvt_detect)
-		return 0;
-
-	use_input_evts_with_hi_slvt_detect = val;
-
-	if ((workload_detect & PERF_CL_PEAK_DETECT) &&
-		!input_events_handler_registered &&
-		use_input_evts_with_hi_slvt_detect) {
-		if (register_input_handler() == -ENOMEM) {
-			use_input_evts_with_hi_slvt_detect = 0;
-			return -ENOMEM;
-		}
-	} else if ((workload_detect & PERF_CL_PEAK_DETECT) &&
-				input_events_handler_registered &&
-				!use_input_evts_with_hi_slvt_detect) {
-		unregister_input_handler();
-	}
-	return 0;
-}
-
-static int get_input_evts_with_hi_slvt_detect(char *buf,
-					const struct kernel_param *kp)
-{
-	return snprintf(buf, PAGE_SIZE, "%u",
-			use_input_evts_with_hi_slvt_detect);
-}
-
-static const struct kernel_param_ops param_ops_ip_evts_with_hi_slvt_detect = {
-	.set = set_input_evts_with_hi_slvt_detect,
-	.get = get_input_evts_with_hi_slvt_detect,
-};
-device_param_cb(input_evts_with_hi_slvt_detect,
-	&param_ops_ip_evts_with_hi_slvt_detect, NULL, 0644);
-
-static struct kobject *mode_kobj;
-
-static ssize_t show_aggr_mode(struct kobject *kobj,
-					struct kobj_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%u\n", aggr_mode);
-}
-static struct kobj_attribute aggr_mode_attr =
-__ATTR(aggr_mode, 0444, show_aggr_mode, NULL);
-
-static ssize_t show_aggr_iobusy(struct kobject *kobj,
-					struct kobj_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%u\n", aggr_iobusy);
-}
-static struct kobj_attribute aggr_iobusy_attr =
-__ATTR(aggr_iobusy, 0444, show_aggr_iobusy, NULL);
-
-static struct attribute *attrs[] = {
-	&aggr_mode_attr.attr,
-	&aggr_iobusy_attr.attr,
-	NULL,
-};
-
-static struct attribute_group attr_group = {
-	.attrs = attrs,
-};
-
-static bool check_notify_status(void)
-{
-	int i;
-	struct cluster *cl;
-	bool any_change = false;
-	unsigned long flags;
-
-
-	for (i = 0; i < num_clusters; i++) {
-		cl = managed_clusters[i];
-		spin_lock_irqsave(&cl->iowait_lock, flags);
-		if (!any_change)
-			any_change = cl->io_change;
-		cl->io_change = false;
-		spin_unlock_irqrestore(&cl->iowait_lock, flags);
-
-		spin_lock_irqsave(&cl->mode_lock, flags);
-		if (!any_change)
-			any_change = cl->mode_change;
-		cl->mode_change = false;
-		spin_unlock_irqrestore(&cl->mode_lock, flags);
-
-		spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
-		if (!any_change)
-			any_change = cl->perf_cl_detect_state_change;
-		cl->perf_cl_detect_state_change = false;
-		spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
-	}
-
-	return any_change;
-}
-
-static int notify_userspace(void *data)
-{
-	unsigned int i, io, cpu_mode, perf_cl_peak_mode;
-
-	while (1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (!check_notify_status()) {
-			schedule();
-
-			if (kthread_should_stop())
-				break;
-		}
-		set_current_state(TASK_RUNNING);
-
-		io = 0;
-		cpu_mode = 0;
-		perf_cl_peak_mode = 0;
-		for (i = 0; i < num_clusters; i++) {
-			io |= managed_clusters[i]->cur_io_busy;
-			cpu_mode |= managed_clusters[i]->mode;
-			perf_cl_peak_mode |= managed_clusters[i]->perf_cl_peak;
-		}
-		if (io != aggr_iobusy) {
-			aggr_iobusy = io;
-			sysfs_notify(mode_kobj, NULL, "aggr_iobusy");
-			pr_debug("msm_perf: Notifying IO: %u\n", aggr_iobusy);
-		}
-		if ((aggr_mode & (SINGLE | MULTI)) != cpu_mode) {
-			aggr_mode &= ~(SINGLE | MULTI);
-			aggr_mode |= cpu_mode;
-			sysfs_notify(mode_kobj, NULL, "aggr_mode");
-			pr_debug("msm_perf: Notifying CPU mode:%u\n",
-								aggr_mode);
-		}
-		if ((aggr_mode & PERF_CL_PEAK) != perf_cl_peak_mode) {
-			aggr_mode &= ~(PERF_CL_PEAK);
-			aggr_mode |= perf_cl_peak_mode;
-			sysfs_notify(mode_kobj, NULL, "aggr_mode");
-			pr_debug("msm_perf: Notifying Gaming mode:%u\n",
-								aggr_mode);
-		}
-	}
-
-	return 0;
-}
-
-static void check_cluster_iowait(struct cluster *cl, u64 now)
-{
-	struct load_stats *pcpu_st;
-	unsigned int i;
-	unsigned long flags;
-	unsigned int temp_iobusy;
-	u64 max_iowait = 0;
-
-	spin_lock_irqsave(&cl->iowait_lock, flags);
-
-	if (((now - cl->last_io_check_ts)
-		< (cl->timer_rate - LAST_IO_CHECK_TOL)) ||
-		!(workload_detect & IO_DETECT)) {
-		spin_unlock_irqrestore(&cl->iowait_lock, flags);
-		return;
-	}
-
-	temp_iobusy = cl->cur_io_busy;
-	for_each_cpu(i, cl->cpus) {
-		pcpu_st = &per_cpu(cpu_load_stats, i);
-		if ((now - pcpu_st->last_wallclock)
-			> (cl->timer_rate + LAST_UPDATE_TOL))
-			continue;
-		if (max_iowait < pcpu_st->last_iopercent)
-			max_iowait = pcpu_st->last_iopercent;
-	}
-
-	if (!cl->cur_io_busy) {
-		if (max_iowait > iowait_ceiling_pct) {
-			cl->iowait_enter_cycle_cnt++;
-			if (cl->iowait_enter_cycle_cnt >= io_enter_cycles) {
-				cl->cur_io_busy = 1;
-				cl->iowait_enter_cycle_cnt = 0;
-			}
-		} else {
-			cl->iowait_enter_cycle_cnt = 0;
-		}
-	} else {
-		if (max_iowait < iowait_floor_pct) {
-			cl->iowait_exit_cycle_cnt++;
-			if (cl->iowait_exit_cycle_cnt >= io_exit_cycles) {
-				cl->cur_io_busy = 0;
-				cl->iowait_exit_cycle_cnt = 0;
-			}
-		} else {
-			cl->iowait_exit_cycle_cnt = 0;
-		}
-	}
-
-	cl->last_io_check_ts = now;
-	trace_track_iowait(cpumask_first(cl->cpus), cl->iowait_enter_cycle_cnt,
-			cl->iowait_exit_cycle_cnt, cl->cur_io_busy, max_iowait);
-
-	if (temp_iobusy != cl->cur_io_busy) {
-		cl->io_change = true;
-		pr_debug("msm_perf: IO changed to %u\n", cl->cur_io_busy);
-	}
-
-	spin_unlock_irqrestore(&cl->iowait_lock, flags);
-	if (cl->io_change)
-		wake_up_process(notify_thread);
-}
-
-static void disable_timer(struct cluster *cl)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cl->timer_lock, flags);
-
-	if (del_timer(&cl->mode_exit_timer)) {
-		trace_single_cycle_exit_timer_stop(cpumask_first(cl->cpus),
-			cl->single_enter_cycles, cl->single_enter_cycle_cnt,
-			cl->single_exit_cycles, cl->single_exit_cycle_cnt,
-			cl->multi_enter_cycles, cl->multi_enter_cycle_cnt,
-			cl->multi_exit_cycles, cl->multi_exit_cycle_cnt,
-			cl->timer_rate, cl->mode);
-	}
-
-	spin_unlock_irqrestore(&cl->timer_lock, flags);
-}
-
-static void start_timer(struct cluster *cl)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cl->timer_lock, flags);
-	if ((cl->mode & SINGLE) && !timer_pending(&cl->mode_exit_timer)) {
-		/* Set timer for the Cluster since there is none pending */
-		cl->mode_exit_timer.expires = get_jiffies_64() +
-		usecs_to_jiffies(cl->single_exit_cycles * cl->timer_rate);
-		cl->mode_exit_timer.data = cpumask_first(cl->cpus);
-		add_timer(&cl->mode_exit_timer);
-		trace_single_cycle_exit_timer_start(cpumask_first(cl->cpus),
-			cl->single_enter_cycles, cl->single_enter_cycle_cnt,
-			cl->single_exit_cycles, cl->single_exit_cycle_cnt,
-			cl->multi_enter_cycles, cl->multi_enter_cycle_cnt,
-			cl->multi_exit_cycles, cl->multi_exit_cycle_cnt,
-			cl->timer_rate, cl->mode);
-	}
-	spin_unlock_irqrestore(&cl->timer_lock, flags);
-}
-
-static void disable_perf_cl_peak_timer(struct cluster *cl)
-{
-
-	if (del_timer(&cl->perf_cl_peak_mode_exit_timer)) {
-		trace_perf_cl_peak_exit_timer_stop(cpumask_first(cl->cpus),
-			cl->perf_cl_peak_enter_cycles,
-			cl->perf_cl_peak_enter_cycle_cnt,
-			cl->perf_cl_peak_exit_cycles,
-			cl->perf_cl_peak_exit_cycle_cnt,
-			cl->timer_rate, cl->mode);
-	}
-
-}
-
-static void start_perf_cl_peak_timer(struct cluster *cl)
-{
-	if ((cl->mode & PERF_CL_PEAK) &&
-		!timer_pending(&cl->perf_cl_peak_mode_exit_timer)) {
-		/* Set timer for the Cluster since there is none pending */
-		cl->perf_cl_peak_mode_exit_timer.expires = get_jiffies_64() +
-		usecs_to_jiffies(cl->perf_cl_peak_exit_cycles * cl->timer_rate);
-		cl->perf_cl_peak_mode_exit_timer.data = cpumask_first(cl->cpus);
-		add_timer(&cl->perf_cl_peak_mode_exit_timer);
-		trace_perf_cl_peak_exit_timer_start(cpumask_first(cl->cpus),
-			cl->perf_cl_peak_enter_cycles,
-			cl->perf_cl_peak_enter_cycle_cnt,
-			cl->perf_cl_peak_exit_cycles,
-			cl->perf_cl_peak_exit_cycle_cnt,
-			cl->timer_rate, cl->mode);
-	}
-}
-
-static const struct input_device_id msm_perf_input_ids[] = {
-
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-		.evbit = {BIT_MASK(EV_ABS)},
-		.absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
-			BIT_MASK(ABS_MT_POSITION_X) |
-			BIT_MASK(ABS_MT_POSITION_Y)},
-	},
-
-	{},
-};
-
-static void msm_perf_input_event_handler(struct input_handle *handle,
-					unsigned int type,
-					unsigned int code,
-					int value)
-{
-	if (type != EV_ABS)
-		return;
-
-	switch (code) {
-
-	case ABS_MT_POSITION_X:
-		ip_evts->evt_x_cnt++;
-		break;
-	case ABS_MT_POSITION_Y:
-		ip_evts->evt_y_cnt++;
-		break;
-
-	case ABS_MT_DISTANCE:
-		break;
-
-	case ABS_MT_PRESSURE:
-		break;
-
-	default:
-		break;
-
-	}
-}
-static int msm_perf_input_connect(struct input_handler *handler,
-				struct input_dev *dev,
-				const struct input_device_id *id)
-{
-	int rc;
-	struct input_handle *handle;
-
-	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-	if (!handle)
-		return -ENOMEM;
-
-	handle->dev = dev;
-	handle->handler = handler;
-	handle->name = handler->name;
-
-	rc = input_register_handle(handle);
-	if (rc) {
-		pr_err("Failed to register handle\n");
-		goto error;
-	}
-
-	rc = input_open_device(handle);
-	if (rc) {
-		pr_err("Failed to open device\n");
-		goto error_unregister;
-	}
-	return 0;
-
-error_unregister:
-	input_unregister_handle(handle);
-error:
-	kfree(handle);
-	return rc;
-}
-
-static void  msm_perf_input_disconnect(struct input_handle *handle)
-{
-	input_close_device(handle);
-	input_unregister_handle(handle);
-	kfree(handle);
-}
-
-static void unregister_input_handler(void)
-{
-	if (handler != NULL) {
-		input_unregister_handler(handler);
-		input_events_handler_registered = false;
-	}
-}
-
-static int register_input_handler(void)
-{
-	int rc;
-
-	if (handler == NULL) {
-		handler = kzalloc(sizeof(*handler), GFP_KERNEL);
-		if (!handler)
-			return -ENOMEM;
-		handler->event = msm_perf_input_event_handler;
-		handler->connect = msm_perf_input_connect;
-		handler->disconnect = msm_perf_input_disconnect;
-		handler->name = "msm_perf";
-		handler->id_table = msm_perf_input_ids;
-		handler->private = NULL;
-	}
-	rc = input_register_handler(handler);
-	if (rc) {
-		pr_err("Unable to register the input handler for msm_perf\n");
-		kfree(handler);
-	} else {
-		input_events_handler_registered = true;
-	}
-	return rc;
-}
-
-static void check_perf_cl_peak_load(struct cluster *cl, u64 now)
-{
-	struct load_stats *pcpu_st;
-	unsigned int i, ret_mode, max_load = 0;
-	unsigned int total_load = 0, cpu_cnt = 0;
-	unsigned long flags;
-	bool cpu_of_cluster_zero = true;
-
-	spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
-
-	cpu_of_cluster_zero = cpumask_first(cl->cpus) ? false:true;
-	/*
-	 * If delta of last load to now < than timer_rate - ld check tolerance
-	 * which is 18ms OR if perf_cl_peak detection not set
-	 * OR the first CPU of Cluster is CPU 0 (LVT)
-	 * then return do nothing. We are interested only in SLVT
-	 */
-	if (((now - cl->last_perf_cl_check_ts)
-		< (cl->timer_rate - LAST_LD_CHECK_TOL)) ||
-		!(workload_detect & PERF_CL_PEAK_DETECT) ||
-		cpu_of_cluster_zero) {
-		spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
-		return;
-	}
-	for_each_cpu(i, cl->cpus) {
-		pcpu_st = &per_cpu(cpu_load_stats, i);
-		if ((now - pcpu_st->last_wallclock)
-			> (cl->timer_rate + LAST_UPDATE_TOL))
-			continue;
-		if (pcpu_st->cpu_load > max_load)
-			max_load = pcpu_st->cpu_load;
-		 /*
-		  * Save the frequency for the cpu of the cluster
-		  * This frequency is the most recent/current
-		  * as obtained due to a transition
-		  * notifier callback.
-		  */
-		cl->current_freq = pcpu_st->freq;
-	}
-	ret_mode = cl->perf_cl_peak;
-
-	if (!(cl->perf_cl_peak & PERF_CL_PEAK)) {
-		if (max_load >= cl->perf_cl_peak_enter_load &&
-			freq_greater_than_threshold(cl,
-				cpumask_first(cl->cpus))) {
-			/*
-			 * Reset the event count  for the first cycle
-			 * of perf_cl_peak we detect
-			 */
-			if (!cl->perf_cl_peak_enter_cycle_cnt)
-				ip_evts->evt_x_cnt = ip_evts->evt_y_cnt = 0;
-			cl->perf_cl_peak_enter_cycle_cnt++;
-			if (cl->perf_cl_peak_enter_cycle_cnt >=
-				cl->perf_cl_peak_enter_cycles) {
-				if (input_events_greater_than_threshold())
-					ret_mode |= PERF_CL_PEAK;
-				cl->perf_cl_peak_enter_cycle_cnt = 0;
-			}
-		} else {
-			cl->perf_cl_peak_enter_cycle_cnt = 0;
-			/* Reset the event count */
-			ip_evts->evt_x_cnt = ip_evts->evt_y_cnt = 0;
-		}
-	} else {
-		if (max_load >= cl->perf_cl_peak_exit_load &&
-			freq_greater_than_threshold(cl,
-				cpumask_first(cl->cpus))) {
-			cl->perf_cl_peak_exit_cycle_cnt = 0;
-			disable_perf_cl_peak_timer(cl);
-		} else {
-			start_perf_cl_peak_timer(cl);
-			cl->perf_cl_peak_exit_cycle_cnt++;
-			if (cl->perf_cl_peak_exit_cycle_cnt
-				>= cl->perf_cl_peak_exit_cycles) {
-				ret_mode &= ~PERF_CL_PEAK;
-				cl->perf_cl_peak_exit_cycle_cnt = 0;
-				disable_perf_cl_peak_timer(cl);
-			}
-		}
-	}
-
-	cl->last_perf_cl_check_ts = now;
-	if (ret_mode != cl->perf_cl_peak) {
-		pr_debug("msm_perf: Mode changed to %u\n", ret_mode);
-		cl->perf_cl_peak = ret_mode;
-		cl->perf_cl_detect_state_change = true;
-	}
-
-	trace_cpu_mode_detect(cpumask_first(cl->cpus), max_load,
-		cl->single_enter_cycle_cnt, cl->single_exit_cycle_cnt,
-		total_load, cl->multi_enter_cycle_cnt,
-		cl->multi_exit_cycle_cnt, cl->perf_cl_peak_enter_cycle_cnt,
-		cl->perf_cl_peak_exit_cycle_cnt, cl->mode, cpu_cnt);
-
-	spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
-
-	if (cl->perf_cl_detect_state_change)
-		wake_up_process(notify_thread);
-
-}
-
-static void check_cpu_load(struct cluster *cl, u64 now)
-{
-	struct load_stats *pcpu_st;
-	unsigned int i, max_load = 0, total_load = 0, ret_mode, cpu_cnt = 0;
-	unsigned int total_load_ceil, total_load_floor;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cl->mode_lock, flags);
-
-	if (((now - cl->last_mode_check_ts)
-		< (cl->timer_rate - LAST_LD_CHECK_TOL)) ||
-		!(workload_detect & MODE_DETECT)) {
-		spin_unlock_irqrestore(&cl->mode_lock, flags);
-		return;
-	}
-
-	for_each_cpu(i, cl->cpus) {
-		pcpu_st = &per_cpu(cpu_load_stats, i);
-		if ((now - pcpu_st->last_wallclock)
-			> (cl->timer_rate + LAST_UPDATE_TOL))
-			continue;
-		if (pcpu_st->cpu_load > max_load)
-			max_load = pcpu_st->cpu_load;
-		total_load += pcpu_st->cpu_load;
-		cpu_cnt++;
-	}
-
-	if (cpu_cnt > 1) {
-		total_load_ceil = cl->pcpu_multi_enter_load * cpu_cnt;
-		total_load_floor = cl->pcpu_multi_exit_load * cpu_cnt;
-	} else {
-		total_load_ceil = UINT_MAX;
-		total_load_floor = UINT_MAX;
-	}
-
-	ret_mode = cl->mode;
-	if (!(cl->mode & SINGLE)) {
-		if (max_load >= cl->single_enter_load) {
-			cl->single_enter_cycle_cnt++;
-			if (cl->single_enter_cycle_cnt
-				>= cl->single_enter_cycles) {
-				ret_mode |= SINGLE;
-				cl->single_enter_cycle_cnt = 0;
-			}
-		} else {
-			cl->single_enter_cycle_cnt = 0;
-		}
-	} else {
-		if (max_load < cl->single_exit_load) {
-			start_timer(cl);
-			cl->single_exit_cycle_cnt++;
-			if (cl->single_exit_cycle_cnt
-				>= cl->single_exit_cycles) {
-				ret_mode &= ~SINGLE;
-				cl->single_exit_cycle_cnt = 0;
-				disable_timer(cl);
-			}
-		} else {
-			cl->single_exit_cycle_cnt = 0;
-			disable_timer(cl);
-		}
-	}
-
-	if (!(cl->mode & MULTI)) {
-		if (total_load >= total_load_ceil) {
-			cl->multi_enter_cycle_cnt++;
-			if (cl->multi_enter_cycle_cnt
-				>= cl->multi_enter_cycles) {
-				ret_mode |= MULTI;
-				cl->multi_enter_cycle_cnt = 0;
-			}
-		} else {
-			cl->multi_enter_cycle_cnt = 0;
-		}
-	} else {
-		if (total_load < total_load_floor) {
-			cl->multi_exit_cycle_cnt++;
-			if (cl->multi_exit_cycle_cnt
-				>= cl->multi_exit_cycles) {
-				ret_mode &= ~MULTI;
-				cl->multi_exit_cycle_cnt = 0;
-			}
-		} else {
-			cl->multi_exit_cycle_cnt = 0;
-		}
-	}
-
-	cl->last_mode_check_ts = now;
-
-	if (ret_mode != cl->mode) {
-		cl->mode = ret_mode;
-		cl->mode_change = true;
-		pr_debug("msm_perf: Mode changed to %u\n", ret_mode);
-	}
-
-	trace_cpu_mode_detect(cpumask_first(cl->cpus), max_load,
-		cl->single_enter_cycle_cnt, cl->single_exit_cycle_cnt,
-		total_load, cl->multi_enter_cycle_cnt,
-		cl->multi_exit_cycle_cnt, cl->perf_cl_peak_enter_cycle_cnt,
-		cl->perf_cl_peak_exit_cycle_cnt, cl->mode, cpu_cnt);
-
-	spin_unlock_irqrestore(&cl->mode_lock, flags);
-
-	if (cl->mode_change)
-		wake_up_process(notify_thread);
-}
-
-static void check_workload_stats(unsigned int cpu, unsigned int rate, u64 now)
-{
-	struct cluster *cl = NULL;
-	unsigned int i;
-
-	for (i = 0; i < num_clusters; i++) {
-		if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
-			cl = managed_clusters[i];
-			break;
-		}
-	}
-	if (cl == NULL)
-		return;
-
-	cl->timer_rate = rate;
-	check_cluster_iowait(cl, now);
-	check_cpu_load(cl, now);
-	check_perf_cl_peak_load(cl, now);
-}
-
-static int perf_govinfo_notify(struct notifier_block *nb, unsigned long val,
-								void *data)
-{
-	struct cpufreq_govinfo *gov_info = data;
-	unsigned int cpu = gov_info->cpu;
-	struct load_stats *cpu_st = &per_cpu(cpu_load_stats, cpu);
-	u64 now, cur_iowait, time_diff, iowait_diff;
-
-	if (!clusters_inited || !workload_detect)
-		return NOTIFY_OK;
-
-	cur_iowait = get_cpu_iowait_time_us(cpu, &now);
-	if (cur_iowait >= cpu_st->last_iowait)
-		iowait_diff = cur_iowait - cpu_st->last_iowait;
-	else
-		iowait_diff = 0;
-
-	if (now > cpu_st->last_wallclock)
-		time_diff = now - cpu_st->last_wallclock;
-	else
-		return NOTIFY_OK;
-
-	if (iowait_diff <= time_diff) {
-		iowait_diff *= 100;
-		cpu_st->last_iopercent = div64_u64(iowait_diff, time_diff);
-	} else {
-		cpu_st->last_iopercent = 100;
-	}
-
-	cpu_st->last_wallclock = now;
-	cpu_st->last_iowait = cur_iowait;
-	cpu_st->cpu_load = gov_info->load;
-
-	 /*
-	  * Avoid deadlock in case governor notifier ran in the context
-	  * of notify_work thread
-	  */
-	if (current == notify_thread)
-		return NOTIFY_OK;
-
-	check_workload_stats(cpu, gov_info->sampling_rate_us, now);
-
-	return NOTIFY_OK;
-}
-
-static int perf_cputrans_notify(struct notifier_block *nb, unsigned long val,
-								void *data)
-{
-	struct cpufreq_freqs *freq = data;
-	unsigned int cpu = freq->cpu;
-	unsigned long flags;
-	unsigned int i;
-	struct cluster *cl = NULL;
-	struct load_stats *cpu_st = &per_cpu(cpu_load_stats, cpu);
-
-	if (!clusters_inited || !workload_detect)
-		return NOTIFY_OK;
-	for (i = 0; i < num_clusters; i++) {
-		if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
-			cl = managed_clusters[i];
-			break;
-		}
-	}
-	if (cl == NULL)
-		return NOTIFY_OK;
-	if (val == CPUFREQ_POSTCHANGE) {
-		spin_lock_irqsave(&cl->perf_cl_peak_lock, flags);
-		cpu_st->freq = freq->new;
-		spin_unlock_irqrestore(&cl->perf_cl_peak_lock, flags);
-	}
-
-	/*
-	 * Avoid deadlock in case governor notifier ran in the context
-	 * of notify_work thread
-	 */
-	if (current == notify_thread)
-		return NOTIFY_OK;
-	return NOTIFY_OK;
-}
-
-static struct notifier_block perf_govinfo_nb = {
-	.notifier_call = perf_govinfo_notify,
-};
-
-static struct notifier_block perf_cputransitions_nb = {
-	.notifier_call = perf_cputrans_notify,
-};
-
-static void single_mod_exit_timer(unsigned long data)
-{
-	int i;
-	struct cluster *i_cl = NULL;
-	unsigned long flags;
-
-	if (!clusters_inited)
-		return;
-
-	for (i = 0; i < num_clusters; i++) {
-		if (cpumask_test_cpu(data,
-			managed_clusters[i]->cpus)) {
-			i_cl = managed_clusters[i];
-			break;
-		}
-	}
-
-	if (i_cl == NULL)
-		return;
-
-	spin_lock_irqsave(&i_cl->mode_lock, flags);
-	if (i_cl->mode & SINGLE) {
-		/* Disable SINGLE mode and exit since the timer expired */
-		i_cl->mode = i_cl->mode & ~SINGLE;
-		i_cl->single_enter_cycle_cnt = 0;
-		i_cl->single_exit_cycle_cnt = 0;
-		trace_single_mode_timeout(cpumask_first(i_cl->cpus),
-			i_cl->single_enter_cycles, i_cl->single_enter_cycle_cnt,
-			i_cl->single_exit_cycles, i_cl->single_exit_cycle_cnt,
-			i_cl->multi_enter_cycles, i_cl->multi_enter_cycle_cnt,
-			i_cl->multi_exit_cycles, i_cl->multi_exit_cycle_cnt,
-			i_cl->timer_rate, i_cl->mode);
-	}
-	spin_unlock_irqrestore(&i_cl->mode_lock, flags);
-	wake_up_process(notify_thread);
-}
-
-static void perf_cl_peak_mod_exit_timer(unsigned long data)
-{
-	int i;
-	struct cluster *i_cl = NULL;
-	unsigned long flags;
-
-	if (!clusters_inited)
-		return;
-
-	for (i = 0; i < num_clusters; i++) {
-		if (cpumask_test_cpu(data,
-			managed_clusters[i]->cpus)) {
-			i_cl = managed_clusters[i];
-			break;
-		}
-	}
 
-	if (i_cl == NULL)
-		return;
 
-	spin_lock_irqsave(&i_cl->perf_cl_peak_lock, flags);
-	if (i_cl->perf_cl_peak & PERF_CL_PEAK) {
-		/* Disable PERF_CL_PEAK mode and exit since the timer expired */
-		i_cl->perf_cl_peak = i_cl->perf_cl_peak & ~PERF_CL_PEAK;
-		i_cl->perf_cl_peak_enter_cycle_cnt = 0;
-		i_cl->perf_cl_peak_exit_cycle_cnt = 0;
-	}
-	spin_unlock_irqrestore(&i_cl->perf_cl_peak_lock, flags);
-	wake_up_process(notify_thread);
-}
 
 /* CPU Hotplug */
 static struct kobject *events_kobj;
@@ -2186,19 +254,18 @@
 	.notifier_call = perf_adjust_notify,
 };
 
-static void hotplug_notify(int action)
+static int hotplug_notify(unsigned int cpu)
 {
 	unsigned long flags;
 
-	if (!events_group.init_success)
-		return;
-
-	if ((action == CPU_ONLINE) || (action == CPU_DEAD)) {
+	if (events_group.init_success) {
 		spin_lock_irqsave(&(events_group.cpu_hotplug_lock), flags);
 		events_group.cpu_hotplug = true;
 		spin_unlock_irqrestore(&(events_group.cpu_hotplug_lock), flags);
 		wake_up_process(events_notify_thread);
 	}
+
+	return 0;
 }
 
 static int events_notify_userspace(void *data)
@@ -2233,138 +300,7 @@
 
 	return 0;
 }
-static int __ref msm_performance_cpu_callback(struct notifier_block *nfb,
-		unsigned long action, void *hcpu)
-{
-	uint32_t cpu = (uintptr_t)hcpu;
-	unsigned int i;
-	struct cluster *i_cl = NULL;
 
-	hotplug_notify(action);
-
-	if (!clusters_inited)
-		return NOTIFY_OK;
-
-	for (i = 0; i < num_clusters; i++) {
-		if (managed_clusters[i]->cpus == NULL)
-			return NOTIFY_OK;
-		if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
-			i_cl = managed_clusters[i];
-			break;
-		}
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata msm_performance_cpu_notifier = {
-	.notifier_call = msm_performance_cpu_callback,
-};
-
-static int init_cluster_control(void)
-{
-	unsigned int i;
-	int ret = 0;
-
-	struct kobject *module_kobj;
-
-	managed_clusters = kcalloc(num_clusters, sizeof(struct cluster *),
-								GFP_KERNEL);
-	if (!managed_clusters)
-		return -ENOMEM;
-	for (i = 0; i < num_clusters; i++) {
-		managed_clusters[i] = kcalloc(1, sizeof(struct cluster),
-								GFP_KERNEL);
-		if (!managed_clusters[i]) {
-			ret = -ENOMEM;
-			goto error;
-		}
-		if (!alloc_cpumask_var(&managed_clusters[i]->cpus,
-		     GFP_KERNEL)) {
-			ret = -ENOMEM;
-			goto error;
-		}
-
-		managed_clusters[i]->single_enter_load = DEF_SINGLE_ENT;
-		managed_clusters[i]->single_exit_load = DEF_SINGLE_EX;
-		managed_clusters[i]->single_enter_cycles
-						= DEF_SINGLE_ENTER_CYCLE;
-		managed_clusters[i]->single_exit_cycles
-						= DEF_SINGLE_EXIT_CYCLE;
-		managed_clusters[i]->pcpu_multi_enter_load
-						= DEF_PCPU_MULTI_ENT;
-		managed_clusters[i]->pcpu_multi_exit_load = DEF_PCPU_MULTI_EX;
-		managed_clusters[i]->multi_enter_cycles = DEF_MULTI_ENTER_CYCLE;
-		managed_clusters[i]->multi_exit_cycles = DEF_MULTI_EXIT_CYCLE;
-		managed_clusters[i]->perf_cl_peak_enter_load =
-						DEF_PERF_CL_PEAK_ENT;
-		managed_clusters[i]->perf_cl_peak_exit_load =
-						DEF_PERF_CL_PEAK_EX;
-		managed_clusters[i]->perf_cl_peak_enter_cycles =
-						DEF_PERF_CL_PEAK_ENTER_CYCLE;
-		managed_clusters[i]->perf_cl_peak_exit_cycles =
-						DEF_PERF_CL_PEAK_EXIT_CYCLE;
-
-		/* Initialize trigger threshold */
-		thr.perf_cl_trigger_threshold = CLUSTER_1_THRESHOLD_FREQ;
-		thr.pwr_cl_trigger_threshold = CLUSTER_0_THRESHOLD_FREQ;
-		thr.ip_evt_threshold = INPUT_EVENT_CNT_THRESHOLD;
-		spin_lock_init(&(managed_clusters[i]->iowait_lock));
-		spin_lock_init(&(managed_clusters[i]->mode_lock));
-		spin_lock_init(&(managed_clusters[i]->timer_lock));
-		spin_lock_init(&(managed_clusters[i]->perf_cl_peak_lock));
-		init_timer(&managed_clusters[i]->mode_exit_timer);
-		managed_clusters[i]->mode_exit_timer.function =
-			single_mod_exit_timer;
-		init_timer(&managed_clusters[i]->perf_cl_peak_mode_exit_timer);
-		managed_clusters[i]->perf_cl_peak_mode_exit_timer.function =
-			perf_cl_peak_mod_exit_timer;
-	}
-
-	mutex_init(&managed_cpus_lock);
-
-	ip_evts = kcalloc(1, sizeof(struct input_events), GFP_KERNEL);
-	if (!ip_evts) {
-		ret = -ENOMEM;
-		goto error;
-	}
-	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
-	if (!module_kobj) {
-		pr_err("msm_perf: Couldn't find module kobject\n");
-		ret = -ENOENT;
-		goto error;
-	}
-	mode_kobj = kobject_create_and_add("workload_modes", module_kobj);
-	if (!mode_kobj) {
-		pr_err("msm_perf: Failed to add mode_kobj\n");
-		ret = -ENOMEM;
-		kobject_put(module_kobj);
-		goto error;
-	}
-	ret = sysfs_create_group(mode_kobj, &attr_group);
-	if (ret) {
-		pr_err("msm_perf: Failed to create sysfs\n");
-		kobject_put(module_kobj);
-		kobject_put(mode_kobj);
-		goto error;
-	}
-	notify_thread = kthread_run(notify_userspace, NULL, "wrkld_notify");
-
-	clusters_inited = true;
-
-	return 0;
-
-error:
-	for (i = 0; i < num_clusters; i++) {
-		if (!managed_clusters[i])
-			break;
-		if (managed_clusters[i]->cpus)
-			free_cpumask_var(managed_clusters[i]->cpus);
-		kfree(managed_clusters[i]);
-	}
-	kfree(managed_clusters);
-	return ret;
-}
 
 static int init_events_group(void)
 {
@@ -2403,16 +339,17 @@
 static int __init msm_performance_init(void)
 {
 	unsigned int cpu;
+	int rc;
 
 	cpufreq_register_notifier(&perf_cpufreq_nb, CPUFREQ_POLICY_NOTIFIER);
-	cpufreq_register_notifier(&perf_govinfo_nb, CPUFREQ_GOVINFO_NOTIFIER);
-	cpufreq_register_notifier(&perf_cputransitions_nb,
-					CPUFREQ_TRANSITION_NOTIFIER);
 
 	for_each_present_cpu(cpu)
 		per_cpu(cpu_stats, cpu).max = UINT_MAX;
 
-	register_cpu_notifier(&msm_performance_cpu_notifier);
+	rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE,
+		"msm_performance_cpu_hotplug",
+		hotplug_notify,
+		NULL);
 
 	init_events_group();
 
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 1bc9239..3b6c0bd 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -161,7 +161,7 @@
 	region_info = (struct md_ss_region __iomem *)subsys_segtable_base;
 	if (!region_info)
 		return -EINVAL;
-	pr_debug("Segments in minidump 0x%x\n", ss_mdump_seg_cnt);
+	pr_info("Minidump : Segments in minidump 0x%x\n", ss_mdump_seg_cnt);
 	ramdump_segs = kcalloc(ss_mdump_seg_cnt,
 			       sizeof(*ramdump_segs), GFP_KERNEL);
 	if (!ramdump_segs)
@@ -184,7 +184,7 @@
 			offset = offset +
 				sizeof(region_info->region_base_address);
 			s->size = __raw_readl(offset);
-			pr_debug("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n",
+			pr_info("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n",
 				s->name, s->address, (unsigned int)s->size);
 		} else
 			ss_valid_seg_cnt--;
@@ -220,15 +220,15 @@
 	int count = 0, ret;
 
 	if (desc->minidump) {
-		pr_debug("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
 			(unsigned int)desc->minidump->md_ss_toc_init);
-		pr_debug("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n",
 			(unsigned int)desc->minidump->md_ss_enable_status);
-		pr_debug("Minidump : md_ss_toc->encryption_status is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->encryption_status is 0x%x\n",
 			(unsigned int)desc->minidump->encryption_status);
-		pr_debug("Minidump : md_ss_toc->ss_region_count is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->ss_region_count is 0x%x\n",
 			(unsigned int)desc->minidump->ss_region_count);
-		pr_debug("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n",
 			(unsigned int)
 			desc->minidump->md_ss_smem_regions_baseptr);
 		/**
@@ -241,11 +241,11 @@
 				MD_SS_ENABLED)) {
 			if (desc->minidump->encryption_status ==
 				MD_SS_ENCR_DONE) {
-				pr_debug("Dumping Minidump for %s\n",
+				pr_info("Minidump : Dumping for %s\n",
 					desc->name);
 				return pil_do_minidump(desc, minidump_dev);
 			}
-			pr_debug("Minidump aborted for %s\n", desc->name);
+			pr_info("Minidump : aborted for %s\n", desc->name);
 			return -EINVAL;
 		}
 	}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 68ff0f3..80dd2f7 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -367,10 +367,16 @@
 									ret);
 	}
 
-	pil_mss_restart_reg(drv, true);
+	pil_mss_pdc_sync(drv, true);
+	/* Wait 6 32kHz sleep cycles for PDC SYNC true */
+	udelay(200);
+	pil_mss_restart_reg(drv, 1);
 	/* Wait 6 32kHz sleep cycles for reset */
 	udelay(200);
-	ret =  pil_mss_restart_reg(drv, false);
+	ret =  pil_mss_restart_reg(drv, 0);
+	/* Wait 6 32kHz sleep cycles for reset false */
+	udelay(200);
+	pil_mss_pdc_sync(drv, false);
 
 	if (drv->is_booted) {
 		pil_mss_disable_clks(drv);
@@ -557,7 +563,7 @@
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
 	phys_addr_t start_addr = pil_get_entry_addr(pil);
-	u32 debug_val;
+	u32 debug_val = 0;
 	int ret;
 
 	trace_pil_func(__func__);
@@ -576,8 +582,10 @@
 	if (ret)
 		goto err_clks;
 
-	/* Save state of modem debug register before full reset */
-	debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+	if (!pil->minidump || !pil->modem_ssr) {
+		/* Save state of modem debug register before full reset */
+		debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+	}
 
 	/* Assert reset to subsystem */
 	pil_mss_assert_resets(drv);
@@ -587,9 +595,12 @@
 	if (ret)
 		goto err_restart;
 
-	writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
-	if (modem_dbg_cfg)
-		writel_relaxed(modem_dbg_cfg, drv->reg_base + QDSP6SS_DBG_CFG);
+	if (!pil->minidump || !pil->modem_ssr) {
+		writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
+		if (modem_dbg_cfg)
+			writel_relaxed(modem_dbg_cfg,
+				drv->reg_base + QDSP6SS_DBG_CFG);
+	}
 
 	/* Program Image Address */
 	if (drv->self_auth) {
@@ -819,8 +830,8 @@
 	 * Need to Wait for timeout for debug reset sequence to
 	 * complete before returning
 	 */
-	pr_debug("Minidump: waiting encryption to complete\n");
-	msleep(30000);
+	pr_info("Minidump: waiting encryption to complete\n");
+	msleep(10000);
 	if (pil->minidump) {
 		writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG);
 		/* Let write complete before proceeding */
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 721124c..ac322f8 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -167,6 +167,11 @@
 	if (ret)
 		return ret;
 
+	pil_mss_remove_proxy_votes(&drv->q6->desc);
+	ret = pil_mss_make_proxy_votes(&drv->q6->desc);
+	if (ret)
+		return ret;
+
 	ret = pil_mss_reset_load_mba(&drv->q6->desc);
 	if (ret)
 		return ret;
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index b7472a4..105367e 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -42,9 +42,9 @@
 #define QBT1000_IN_DEV_NAME "qbt1000_key_input"
 #define QBT1000_IN_DEV_VERSION 0x0100
 #define MAX_FW_EVENTS 128
-#define FP_APP_CMD_RX_IPC 132
 #define FW_MAX_IPC_MSG_DATA_SIZE 0x500
-#define IPC_MSG_ID_CBGE_REQUIRED 29
+#define SEND_TZ_CMD_RETRY_CNT 10
+#define SEND_TZ_CMD_DELAY 50
 
 /*
  * shared buffer size - init with max value,
@@ -53,6 +53,27 @@
 static uint32_t g_app_buf_size = SZ_256K;
 static char const *const FP_APP_NAME = "fingerpr";
 
+enum fp_app_cmd {
+	FP_APP_CMD_RX_IPC = 132,
+
+};
+
+enum ipc_msg_id {
+	IPC_MSG_ID_CBGE_REQUIRED = 29,
+	IPC_MSG_ID_GESTURE_SWIPE_DOWN = 50,
+	IPC_MSG_ID_GESTURE_SWIPE_UP = 51,
+	IPC_MSG_ID_GESTURE_SWIPE_LEFT = 52,
+	IPC_MSG_ID_GESTURE_SWIPE_RIGHT = 53,
+	IPC_MSG_ID_GESTURE_LONG_PRESS = 54,
+	IPC_MSG_ID_FINGER_ON_SENSOR = 55,
+	IPC_MSG_ID_FINGER_OFF_SENSOR = 56,
+};
+
+enum fd_indication_mode {
+	FD_IND_MODE_BIOMETRIC = 0,
+	FD_IND_MODE_GESTURES,
+};
+
 struct finger_detect_gpio {
 	int gpio;
 	int active_low;
@@ -93,6 +114,9 @@
 	wait_queue_head_t read_wait_queue;
 	struct qseecom_handle *app_handle;
 	struct qseecom_handle *fp_app_handle;
+	enum fd_indication_mode fd_ind_mode;
+	bool ipc_is_stale;
+	bool gestures_enabled;
 };
 
 /*
@@ -129,7 +153,9 @@
 
 /* mapping between firmware IPC message types to HLOS firmware events */
 struct ipc_msg_type_to_fw_event g_msg_to_event[] = {
-		{IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED}
+		{IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED},
+		{IPC_MSG_ID_FINGER_ON_SENSOR, FW_EVENT_FINGER_DOWN},
+		{IPC_MSG_ID_FINGER_OFF_SENSOR, FW_EVENT_FINGER_UP},
 };
 
 /**
@@ -529,9 +555,7 @@
 			pr_err("failed copy from user space %d\n", rc);
 			goto end;
 		}
-
 		drvdata->fd_gpio.key_code = set_fd_key.key_code;
-
 		break;
 	}
 	case QBT1000_CONFIGURE_POWER_KEY:
@@ -547,7 +571,27 @@
 		}
 
 		drvdata->fd_gpio.power_key_enabled = power_key.enable;
+		break;
+	}
+	case QBT1000_ENABLE_GESTURES:
+	{
+		struct qbt1000_enable_gestures enable_gestures;
 
+		if (copy_from_user(&enable_gestures, priv_arg,
+			sizeof(enable_gestures))
+				!= 0) {
+			rc = -EFAULT;
+			pr_err("failed copy from user space %d\n", rc);
+			goto end;
+		}
+
+		if (enable_gestures.enable) {
+			drvdata->fd_ind_mode = FD_IND_MODE_GESTURES;
+			drvdata->gestures_enabled = true;
+		} else {
+			drvdata->fd_ind_mode = FD_IND_MODE_BIOMETRIC;
+			drvdata->gestures_enabled = false;
+		}
 		break;
 	}
 	default:
@@ -734,6 +778,18 @@
 		BIT_MASK(KEY_VOLUMEDOWN);
 	drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
 		BIT_MASK(KEY_POWER);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_UP)] |=
+		BIT_MASK(KEY_FP_GESTURE_UP);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_DOWN)] |=
+		BIT_MASK(KEY_FP_GESTURE_DOWN);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LEFT)] |=
+		BIT_MASK(KEY_FP_GESTURE_LEFT);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_RIGHT)] |=
+		BIT_MASK(KEY_FP_GESTURE_RIGHT);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LONG_PRESS)] |=
+		BIT_MASK(KEY_FP_GESTURE_LONG_PRESS);
+	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_TAP)] |=
+		BIT_MASK(KEY_FP_GESTURE_TAP);
 
 	input_set_abs_params(drvdata->in_dev, ABS_X,
 			     0,
@@ -773,14 +829,10 @@
 	}
 }
 
-static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
+static void gpio_report_event(struct qbt1000_drvdata *drvdata, int state)
 {
-	int state;
 	struct fw_event_desc fw_event;
 
-	state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
-		^ drvdata->fd_gpio.active_low;
-
 	if (drvdata->fd_gpio.event_reported
 		  && state == drvdata->fd_gpio.last_gpio_state)
 		return;
@@ -790,40 +842,62 @@
 	drvdata->fd_gpio.event_reported = 1;
 	drvdata->fd_gpio.last_gpio_state = state;
 
-	if (drvdata->fd_gpio.key_code) {
-		input_event(drvdata->in_dev, EV_KEY,
-			drvdata->fd_gpio.key_code, !!state);
+	if (drvdata->fd_ind_mode == FD_IND_MODE_GESTURES) {
+		pr_debug("tap detected\n");
+		/*
+		 * If a gesture IPC was sent but not yet decrypted and
+		 * dealt with mark it as stale and don't report it
+		 */
+		drvdata->ipc_is_stale = true;
+		input_event(drvdata->in_dev,
+				EV_KEY, KEY_FP_GESTURE_TAP, 1);
 		input_sync(drvdata->in_dev);
-	}
-
-	if (state && drvdata->fd_gpio.power_key_enabled) {
-		input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1);
+		input_event(drvdata->in_dev,
+				EV_KEY, KEY_FP_GESTURE_TAP, 0);
 		input_sync(drvdata->in_dev);
-		input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0);
-		input_sync(drvdata->in_dev);
+	} else if (drvdata->fd_ind_mode == FD_IND_MODE_BIOMETRIC) {
+		if (state && drvdata->fd_gpio.power_key_enabled) {
+			input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1);
+			input_sync(drvdata->in_dev);
+			input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0);
+			input_sync(drvdata->in_dev);
+		} else if (!drvdata->gestures_enabled) {
+			input_event(drvdata->in_dev, EV_KEY,
+				drvdata->fd_gpio.key_code, !!state);
+			input_sync(drvdata->in_dev);
+		}
+		fw_event.ev = state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP;
+
+		mutex_lock(&drvdata->fw_events_mutex);
+
+		if (kfifo_is_full(&drvdata->fw_events)) {
+			struct fw_event_desc dummy_fw_event;
+
+			pr_warn("fw events fifo: full, dropping oldest item\n");
+			if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event))
+				pr_err("fw events fifo: could not remove oldest item\n");
+		}
+
+		purge_finger_events(drvdata);
+
+		if (!kfifo_put(&drvdata->fw_events, fw_event))
+			pr_err("fw events fifo: error adding item\n");
+
+		mutex_unlock(&drvdata->fw_events_mutex);
+		wake_up_interruptible(&drvdata->read_wait_queue);
+	} else {
+		pr_err("invalid mode %d\n", drvdata->fd_ind_mode);
 	}
-
-	fw_event.ev = (state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP);
-
-	mutex_lock(&drvdata->fw_events_mutex);
-
-	if (kfifo_is_full(&drvdata->fw_events)) {
-		struct fw_event_desc dummy_fw_event;
-
-		pr_warn("fw events fifo: full, dropping oldest item\n");
-		if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event))
-			pr_err("fw events fifo: could not remove oldest item\n");
-	}
-
-	purge_finger_events(drvdata);
-
-	if (!kfifo_put(&drvdata->fw_events, fw_event))
-		pr_err("fw events fifo: error adding item\n");
-
-	mutex_unlock(&drvdata->fw_events_mutex);
-	wake_up_interruptible(&drvdata->read_wait_queue);
 }
 
+static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
+{
+	int state;
+
+	state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
+		^ drvdata->fd_gpio.active_low;
+	gpio_report_event(drvdata, state);
+}
 static void qbt1000_gpio_work_func(struct work_struct *work)
 {
 	struct qbt1000_drvdata *drvdata =
@@ -867,7 +941,7 @@
 	uint32_t rxipc = FP_APP_CMD_RX_IPC;
 	struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
 	int rc = 0;
-	uint32_t retry_count = 10;
+	uint32_t retry_count = SEND_TZ_CMD_RETRY_CNT;
 
 	pm_stay_awake(drvdata->dev);
 
@@ -884,6 +958,12 @@
 	if (!drvdata->fp_app_handle)
 		goto end;
 
+	/*
+	 * Indicate that IPC is valid (not stale)
+	 * This is relevant only for gestures IPCs
+	 */
+	drvdata->ipc_is_stale = false;
+
 	while (retry_count > 0) {
 		/*
 		 * send the TZ command to fetch the message from firmware
@@ -893,7 +973,8 @@
 				&rxipc, sizeof(rxipc),
 				(void *)&rx_cmd, sizeof(*rx_cmd));
 		if (rc < 0) {
-			msleep(50); // sleep for 50ms before retry
+			/* sleep before retry */
+			msleep(SEND_TZ_CMD_DELAY);
 			retry_count -= 1;
 			continue;
 		} else {
@@ -915,28 +996,76 @@
 	msg_buffer = rx_cmd->msg_data;
 
 	for (j = 0; j < rx_cmd->numMsgs; j++) {
+		unsigned int key_event_code = 0;
+
 		header = (struct fw_ipc_header *) msg_buffer;
-		/*
-		 * given the IPC message type, search for a corresponding
-		 * event for the driver client. If found, add to the events
-		 * FIFO
-		 */
-		for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
-			if (g_msg_to_event[i].msg_type == header->msg_type) {
-				enum qbt1000_fw_event ev =
+
+		switch (header->msg_type) {
+		case IPC_MSG_ID_GESTURE_SWIPE_UP:
+			key_event_code = KEY_FP_GESTURE_UP;
+			break;
+		case IPC_MSG_ID_GESTURE_SWIPE_DOWN:
+			key_event_code = KEY_FP_GESTURE_DOWN;
+			break;
+		case IPC_MSG_ID_GESTURE_SWIPE_LEFT:
+			key_event_code = KEY_FP_GESTURE_LEFT;
+			break;
+		case IPC_MSG_ID_GESTURE_SWIPE_RIGHT:
+			key_event_code = KEY_FP_GESTURE_RIGHT;
+			break;
+		case IPC_MSG_ID_GESTURE_LONG_PRESS:
+			key_event_code = KEY_FP_GESTURE_LONG_PRESS;
+			break;
+		default:
+			key_event_code = 0;
+			break;
+		}
+
+		if (key_event_code != 0) {
+			pr_debug("geseture detected %d\n", key_event_code);
+			/*
+			 * Send gesture event if no tap arrived
+			 * since the IPC was sent
+			 */
+			if (drvdata->ipc_is_stale == false) {
+				input_event(drvdata->in_dev, EV_KEY,
+						key_event_code, 1);
+				input_sync(drvdata->in_dev);
+				input_event(drvdata->in_dev, EV_KEY,
+						key_event_code, 0);
+				input_sync(drvdata->in_dev);
+			}
+		} else {
+
+			/*
+			 * given the IPC message type, search for a
+			 * corresponding event for the driver client.
+			 * If found, add to the events FIFO
+			 */
+			for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
+				uint32_t msg_type = g_msg_to_event[i].msg_type;
+
+				if (msg_type == header->msg_type) {
+					enum qbt1000_fw_event ev =
 						g_msg_to_event[i].fw_event;
-				struct fw_event_desc fw_ev_desc;
+					struct fw_event_desc fw_ev_desc;
 
-				mutex_lock(&drvdata->fw_events_mutex);
-				pr_debug("fw events: add %d\n", (int) ev);
-				fw_ev_desc.ev = ev;
-
-				if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
-					pr_err("fw events: fifo full, drop event %d\n",
+					mutex_lock(&drvdata->fw_events_mutex);
+					pr_debug("fw events: add %d\n",
 						(int) ev);
+					fw_ev_desc.ev = ev;
 
-				mutex_unlock(&drvdata->fw_events_mutex);
-				break;
+					purge_finger_events(drvdata);
+
+					if (!kfifo_put(&drvdata->fw_events,
+							fw_ev_desc))
+						pr_err("fw events: fifo full");
+						pr_err(", drop event %d\n",
+							(int) ev);
+
+					mutex_unlock(&drvdata->fw_events_mutex);
+					break;
+				}
 			}
 		}
 		msg_buffer += sizeof(*header) + header->msg_len;
@@ -998,6 +1127,7 @@
 	drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio);
 	pr_debug("\nirq %d gpio %d\n",
 			drvdata->fw_ipc.irq, drvdata->fw_ipc.gpio);
+
 	if (drvdata->fw_ipc.irq < 0) {
 		rc = drvdata->fw_ipc.irq;
 		pr_err("no irq for gpio %d, error=%d\n",
@@ -1136,6 +1266,10 @@
 	if (rc < 0)
 		goto end;
 
+	drvdata->fd_ind_mode = FD_IND_MODE_BIOMETRIC;
+	drvdata->ipc_is_stale = false;
+	drvdata->gestures_enabled = false;
+
 end:
 	pr_debug("qbt1000_probe end : %d\n", rc);
 	return rc;
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c
index 3fc7fbf..c29cfcb 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -31,7 +31,6 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
@@ -126,8 +125,6 @@
 	return atomic_notifier_chain_unregister(&msm_rpm_sleep_notifier, nb);
 }
 
-static struct workqueue_struct *msm_rpm_smd_wq;
-
 enum {
 	MSM_RPM_MSG_REQUEST_TYPE = 0,
 	MSM_RPM_MSG_TYPE_NR,
@@ -2120,15 +2117,6 @@
 
 	smd_disable_read_intr(msm_rpm_data.ch_info);
 
-	msm_rpm_smd_wq = alloc_workqueue("rpm-smd",
-				WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
-	if (!msm_rpm_smd_wq) {
-		pr_err("%s: Unable to alloc rpm-smd workqueue\n", __func__);
-		ret = -EINVAL;
-		goto fail;
-	}
-	queue_work(msm_rpm_smd_wq, &msm_rpm_data.work);
-
 	probe_status = ret;
 skip_init:
 	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c
index 2c379a0..bc665fd 100644
--- a/drivers/soc/qcom/rpmh_master_stat.c
+++ b/drivers/soc/qcom/rpmh_master_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,21 +13,25 @@
 
 #define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
 
-#include <linux/debugfs.h>
-#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/uaccess.h>
 #include <soc/qcom/smem.h>
+#include "rpmh_master_stat.h"
+
+#define UNIT_DIST 0x14
+#define REG_VALID 0x0
+#define REG_DATA_LO 0x4
+#define REG_DATA_HI 0x8
+
+#define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO))
 
 enum master_smem_id {
 	MPSS = 605,
@@ -48,6 +52,14 @@
 	PID_DISPLAY = PID_APSS,
 };
 
+enum profile_data {
+	POWER_DOWN_START,
+	POWER_UP_END,
+	POWER_DOWN_END,
+	POWER_UP_START,
+	NUM_UNIT,
+};
+
 struct msm_rpmh_master_data {
 	char *master_name;
 	enum master_smem_id smem_id;
@@ -66,16 +78,24 @@
 struct msm_rpmh_master_stats {
 	uint32_t version_id;
 	uint32_t counts;
-	uint64_t last_entered_at;
-	uint64_t last_exited_at;
+	uint64_t last_entered;
+	uint64_t last_exited;
 	uint64_t accumulated_duration;
 };
 
+struct msm_rpmh_profile_unit {
+	uint64_t value;
+	uint64_t valid;
+};
+
 struct rpmh_master_stats_prv_data {
 	struct kobj_attribute ka;
 	struct kobject *kobj;
 };
 
+static struct msm_rpmh_master_stats apss_master_stats;
+static void __iomem *rpmh_unit_base;
+
 static DEFINE_MUTEX(rpmh_stats_mutex);
 
 static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length,
@@ -88,7 +108,7 @@
 			"\tSleep Last Exited At:0x%llx\n"
 			"\tSleep Accumulated Duration:0x%llx\n\n",
 			name, record->version_id, record->counts,
-			record->last_entered_at, record->last_exited_at,
+			record->last_entered, record->last_exited,
 			record->accumulated_duration);
 }
 
@@ -100,13 +120,16 @@
 	unsigned int size = 0;
 	struct msm_rpmh_master_stats *record = NULL;
 
-	/*
-	 * Read SMEM data written by masters
-	 */
-
 	mutex_lock(&rpmh_stats_mutex);
 
-	for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
+	/* First Read APSS master stats */
+
+	length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE,
+						&apss_master_stats, "APSS");
+
+	/* Read SMEM data written by other masters */
+
+	for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
 		record = (struct msm_rpmh_master_stats *) smem_get_entry(
 					rpmh_masters[i].smem_id, &size,
 					rpmh_masters[i].pid, 0);
@@ -122,30 +145,66 @@
 	return length;
 }
 
+static inline void msm_rpmh_apss_master_stats_update(
+				struct msm_rpmh_profile_unit *profile_unit)
+{
+	apss_master_stats.counts++;
+	apss_master_stats.last_entered = profile_unit[POWER_DOWN_END].value;
+	apss_master_stats.last_exited = profile_unit[POWER_UP_START].value;
+	apss_master_stats.accumulated_duration +=
+					(apss_master_stats.last_exited
+					- apss_master_stats.last_entered);
+}
+
+void msm_rpmh_master_stats_update(void)
+{
+	int i;
+	struct msm_rpmh_profile_unit profile_unit[NUM_UNIT];
+
+	if (!rpmh_unit_base)
+		return;
+
+	for (i = POWER_DOWN_END; i < NUM_UNIT; i++) {
+		profile_unit[i].valid = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_VALID, i));
+
+		/*
+		 * Do not update APSS stats if valid bit is not set.
+		 * It means APSS did not execute cx-off sequence.
+		 * This can be due to fall through at some point.
+		 */
+
+		if (!(profile_unit[i].valid & BIT(REG_VALID)))
+			return;
+
+		profile_unit[i].value = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_DATA_LO, i));
+		profile_unit[i].value |= ((uint64_t)
+					readl_relaxed(rpmh_unit_base +
+					GET_ADDR(REG_DATA_HI, i)) << 32);
+	}
+	msm_rpmh_apss_master_stats_update(profile_unit);
+}
+EXPORT_SYMBOL(msm_rpmh_master_stats_update);
+
 static int msm_rpmh_master_stats_probe(struct platform_device *pdev)
 {
 	struct rpmh_master_stats_prv_data *prvdata = NULL;
 	struct kobject *rpmh_master_stats_kobj = NULL;
-	int ret = 0;
+	int ret = -ENOMEM;
 
 	if (!pdev)
 		return -EINVAL;
 
-	prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data),
-							GFP_KERNEL);
-	if (!prvdata) {
-		ret = -ENOMEM;
-		goto fail;
-	}
+	prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL);
+	if (!prvdata)
+		return ret;
 
 	rpmh_master_stats_kobj = kobject_create_and_add(
 					"rpmh_stats",
 					power_kobj);
-	if (!rpmh_master_stats_kobj) {
-		ret = -ENOMEM;
-		kfree(prvdata);
-		goto fail;
-	}
+	if (!rpmh_master_stats_kobj)
+		return ret;
 
 	prvdata->kobj = rpmh_master_stats_kobj;
 
@@ -158,14 +217,24 @@
 	ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr);
 	if (ret) {
 		pr_err("sysfs_create_file failed\n");
-		kobject_put(prvdata->kobj);
-		kfree(prvdata);
-		goto fail;
+		goto fail_sysfs;
 	}
 
-	platform_set_drvdata(pdev, prvdata);
+	rpmh_unit_base = of_iomap(pdev->dev.of_node, 0);
+	if (!rpmh_unit_base) {
+		pr_err("Failed to get rpmh_unit_base\n");
+		ret = -ENOMEM;
+		goto fail_iomap;
+	}
 
-fail:
+	apss_master_stats.version_id = 0x1;
+	platform_set_drvdata(pdev, prvdata);
+	return ret;
+
+fail_iomap:
+	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
+fail_sysfs:
+	kobject_put(prvdata->kobj);
 	return ret;
 }
 
@@ -181,14 +250,14 @@
 
 	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
 	kobject_put(prvdata->kobj);
-	kfree(prvdata);
 	platform_set_drvdata(pdev, NULL);
+	iounmap(rpmh_unit_base);
 
 	return 0;
 }
 
 static const struct of_device_id rpmh_master_table[] = {
-	{.compatible = "qcom,rpmh-master-stats"},
+	{.compatible = "qcom,rpmh-master-stats-v1"},
 	{},
 };
 
@@ -197,24 +266,11 @@
 	.remove = msm_rpmh_master_stats_remove,
 	.driver = {
 		.name = "msm_rpmh_master_stats",
-		.owner = THIS_MODULE,
 		.of_match_table = rpmh_master_table,
 	},
 };
 
-static int __init msm_rpmh_master_stats_init(void)
-{
-	return platform_driver_register(&msm_rpmh_master_stats_driver);
-}
-
-static void __exit msm_rpmh_master_stats_exit(void)
-{
-	platform_driver_unregister(&msm_rpmh_master_stats_driver);
-}
-
-module_init(msm_rpmh_master_stats_init);
-module_exit(msm_rpmh_master_stats_exit);
-
+module_platform_driver(msm_rpmh_master_stats_driver);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MSM RPMH Master Statistics driver");
 MODULE_ALIAS("platform:msm_rpmh_master_stat_log");
diff --git a/drivers/soc/qcom/rpmh_master_stat.h b/drivers/soc/qcom/rpmh_master_stat.h
new file mode 100644
index 0000000..c3fe7dc
--- /dev/null
+++ b/drivers/soc/qcom/rpmh_master_stat.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#if defined(CONFIG_QTI_RPMH_API) && defined(CONFIG_QTI_RPM_STATS_LOG)
+
+void msm_rpmh_master_stats_update(void);
+
+#else
+
+static inline void msm_rpmh_master_stats_update(void) {}
+
+#endif
diff --git a/drivers/soc/qcom/rq_stats.c b/drivers/soc/qcom/rq_stats.c
index 5850c46..1b4cf4f 100644
--- a/drivers/soc/qcom/rq_stats.c
+++ b/drivers/soc/qcom/rq_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015, 2018, 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
@@ -264,7 +264,7 @@
 static ssize_t show_def_timer_ms(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf)
 {
-	int64_t diff;
+	uint64_t diff;
 	unsigned int udiff;
 
 	diff = ktime_to_ns(ktime_get()) - rq_info.def_start_time;
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index cab7178..fec6f17 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -185,9 +185,8 @@
 	case SCM_ENOMEM:
 		return -ENOMEM;
 	case SCM_EBUSY:
-		return SCM_EBUSY;
 	case SCM_V2_EBUSY:
-		return SCM_V2_EBUSY;
+		return -EBUSY;
 	}
 	return -EINVAL;
 }
@@ -338,13 +337,13 @@
 	do {
 		ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len,
 					resp_buf, resp_len, cmd, len);
-		if (ret == SCM_EBUSY)
+		if (ret == -EBUSY)
 			msleep(SCM_EBUSY_WAIT_MS);
 		if (retry_count == 33)
 			pr_warn("scm: secure world has been busy for 1 second!\n");
-	} while (ret == SCM_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
+	} while (ret == -EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
 
-	if (ret == SCM_EBUSY)
+	if (ret == -EBUSY)
 		pr_err("scm: secure world busy (rc = SCM_EBUSY)\n");
 
 	return ret;
@@ -799,7 +798,7 @@
 
 	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
 				resp_len, cmd, len);
-	if (unlikely(ret == SCM_EBUSY))
+	if (unlikely(ret == -EBUSY))
 		ret = _scm_call_retry(svc_id, cmd_id, cmd_buf, cmd_len,
 				      resp_buf, resp_len, cmd, PAGE_ALIGN(len));
 	kfree(cmd);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 556882c..0e83971 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, 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
@@ -591,6 +591,15 @@
 	[349] = {MSM_CPU_SDM632, "SDM632"},
 	[350] = {MSM_CPU_SDA632, "SDA632"},
 
+	/*MSM8937 ID  */
+	[294] = {MSM_CPU_8937, "MSM8937"},
+	[295] = {MSM_CPU_8937, "APQ8937"},
+
+	/* SDM429 and SDM439 ID*/
+	[353] = {MSM_CPU_SDM439, "SDM439"},
+	[354] = {MSM_CPU_SDM429, "SDM429"},
+
+
 	/* Uninitialized IDs are not known to run Linux.
 	 * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	 * considered as unknown CPU.
@@ -1518,6 +1527,10 @@
 		dummy_socinfo.id = 293;
 		strlcpy(dummy_socinfo.build_id, "msm8953 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8937()) {
+		dummy_socinfo.id = 294;
+		strlcpy(dummy_socinfo.build_id, "msm8937 - ",
+			sizeof(dummy_socinfo.build_id));
 	} else if (early_machine_is_sdm450()) {
 		dummy_socinfo.id = 338;
 		strlcpy(dummy_socinfo.build_id, "sdm450 - ",
@@ -1526,6 +1539,14 @@
 		dummy_socinfo.id = 349;
 		strlcpy(dummy_socinfo.build_id, "sdm632 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm439()) {
+		dummy_socinfo.id = 353;
+		strlcpy(dummy_socinfo.build_id, "sdm439 - ",
+				sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm429()) {
+		dummy_socinfo.id = 354;
+		strlcpy(dummy_socinfo.build_id, "sdm429 - ",
+				sizeof(dummy_socinfo.build_id));
 	}
 
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 480a33c..9c6edbf 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,11 +14,10 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <asm/arch_timer.h>
-
-#include <soc/qcom/rpmh.h>
-#include <soc/qcom/system_pm.h>
-
 #include <clocksource/arm_arch_timer.h>
+#include "rpmh_master_stat.h"
+#include <soc/qcom/lpm_levels.h>
+#include <soc/qcom/rpmh.h>
 
 #define PDC_TIME_VALID_SHIFT	31
 #define PDC_TIME_UPPER_MASK	0xFFFFFF
@@ -36,7 +35,7 @@
 	return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd));
 }
 
-int system_sleep_update_wakeup(void)
+static int system_sleep_update_wakeup(bool from_idle)
 {
 	uint32_t lo = ~0U, hi = ~0U;
 
@@ -45,16 +44,14 @@
 
 	return setup_wakeup(lo, hi);
 }
-EXPORT_SYMBOL(system_sleep_update_wakeup);
 
 /**
  * system_sleep_allowed() - Returns if its okay to enter system low power modes
  */
-bool system_sleep_allowed(void)
+static bool system_sleep_allowed(void)
 {
 	return (rpmh_ctrlr_idle(rpmh_client) == 0);
 }
-EXPORT_SYMBOL(system_sleep_allowed);
 
 /**
  * system_sleep_enter() - Activties done when entering system low power modes
@@ -62,22 +59,25 @@
  * Returns 0 for success or error values from writing the sleep/wake values to
  * the hardware block.
  */
-int system_sleep_enter(void)
+static int system_sleep_enter(struct cpumask *mask)
 {
-	if (IS_ERR_OR_NULL(rpmh_client))
-		return -EFAULT;
-
 	return rpmh_flush(rpmh_client);
 }
-EXPORT_SYMBOL(system_sleep_enter);
 
 /**
  * system_sleep_exit() - Activities done when exiting system low power modes
  */
-void system_sleep_exit(void)
+static void system_sleep_exit(void)
 {
+	msm_rpmh_master_stats_update();
 }
-EXPORT_SYMBOL(system_sleep_exit);
+
+static struct system_pm_ops pm_ops = {
+	.enter = system_sleep_enter,
+	.exit = system_sleep_exit,
+	.update_wakeup = system_sleep_update_wakeup,
+	.sleep_allowed = system_sleep_allowed,
+};
 
 static int sys_pm_probe(struct platform_device *pdev)
 {
@@ -85,7 +85,7 @@
 	if (IS_ERR_OR_NULL(rpmh_client))
 		return PTR_ERR(rpmh_client);
 
-	return 0;
+	return register_system_pm_ops(&pm_ops);
 }
 
 static const struct of_device_id sys_pm_drv_match[] = {
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index f5e76e0..5630dc0 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -112,12 +112,22 @@
 module_param(WDT_HZ, long, 0);
 
 /*
+ * Watchdog ipi optimization:
+ * Does not ping cores in low power mode at pet time to save power.
+ * This feature is enabled by default.
+ *
  * On the kernel command line specify
- * watchdog_v2.ipi_opt_en=1 to enable the watchdog ipi ping
- * optimization. By default it is turned off
+ * watchdog_v2.ipi_en=1 to disable this optimization.
+ * Or, can be turned off, by enabling CONFIG_QCOM_WDOG_IPI_ENABLE.
  */
-static int ipi_opt_en;
-module_param(ipi_opt_en, int, 0);
+#ifdef CONFIG_QCOM_WDOG_IPI_ENABLE
+#define IPI_CORES_IN_LPM 1
+#else
+#define IPI_CORES_IN_LPM 0
+#endif
+
+static int ipi_en = IPI_CORES_IN_LPM;
+module_param(ipi_en, int, 0444);
 
 static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
 {
@@ -463,7 +473,7 @@
 	struct msm_watchdog_data *wdog_dd =
 			(struct msm_watchdog_data *)platform_get_drvdata(pdev);
 
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_unregister_notifier(&wdog_cpu_pm_nb);
 
 	mutex_lock(&wdog_dd->disable_lock);
@@ -709,7 +719,7 @@
 
 	if (wdog_dd->irq_ppi)
 		enable_percpu_irq(wdog_dd->bark_irq, 0);
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_register_notifier(&wdog_cpu_pm_nb);
 	dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
 }
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index deb782f..a6e34f0 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1307,12 +1307,23 @@
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+	int ret;
 
 	spi_bitbang_stop(&spi_imx->bitbang);
 
+	ret = clk_enable(spi_imx->clk_per);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(spi_imx->clk_ipg);
+	if (ret) {
+		clk_disable(spi_imx->clk_per);
+		return ret;
+	}
+
 	writel(0, spi_imx->base + MXC_CSPICTRL);
-	clk_unprepare(spi_imx->clk_ipg);
-	clk_unprepare(spi_imx->clk_per);
+	clk_disable_unprepare(spi_imx->clk_ipg);
+	clk_disable_unprepare(spi_imx->clk_per);
 	spi_imx_sdma_exit(spi_imx);
 	spi_master_put(master);
 
diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c
index eeeeb28..e8028d2 100644
--- a/drivers/staging/android/ion/ion_carveout_heap.c
+++ b/drivers/staging/android/ion/ion_carveout_heap.c
@@ -77,6 +77,7 @@
 	struct sg_table *table;
 	ion_phys_addr_t paddr;
 	int ret;
+	struct device *dev = heap->priv;
 
 	if (align > PAGE_SIZE)
 		return -EINVAL;
@@ -95,8 +96,19 @@
 	}
 
 	sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
+	/*
+	 * This is not correct - sg_dma_address needs a dma_addr_t that is valid
+	 * for the targeted device, but this works on the currently targeted
+	 * hardware.
+	 */
+	sg_dma_address(table->sgl) = sg_phys(table->sgl);
+
 	buffer->priv_virt = table;
 
+	if (ion_buffer_cached(buffer))
+		dma_sync_sg_for_cpu(dev, table->sgl, table->nents,
+				    DMA_BIDIRECTIONAL);
+
 	return 0;
 
 err_free_table:
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 3771726..a3eebca 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -910,6 +910,7 @@
 
 		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
 		vunmap(ptr);
+		ptr = NULL;
 	}
 
 	return 0;
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 41f1a19..a1602e4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -510,17 +510,36 @@
 		if (test_task_flag(tsk, TIF_MM_RELEASED))
 			continue;
 
-		if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
-			if (test_task_lmk_waiting(tsk)) {
-				rcu_read_unlock();
-				mutex_unlock(&scan_mutex);
-				return 0;
-			}
-		}
+		if (oom_reaper) {
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
 
-		p = find_lock_task_mm(tsk);
-		if (!p)
-			continue;
+			if (test_bit(MMF_OOM_VICTIM, &p->mm->flags)) {
+				if (test_bit(MMF_OOM_SKIP, &p->mm->flags)) {
+					task_unlock(p);
+					continue;
+				} else if (time_before_eq(jiffies,
+						lowmem_deathpending_timeout)) {
+					task_unlock(p);
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+			}
+		} else {
+			if (time_before_eq(jiffies,
+					   lowmem_deathpending_timeout))
+				if (test_task_lmk_waiting(tsk)) {
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
+		}
 
 		oom_score_adj = p->signal->oom_score_adj;
 		if (oom_score_adj < min_score_adj) {
@@ -561,13 +580,15 @@
 
 		task_lock(selected);
 		send_sig(SIGKILL, selected, 0);
-		if (selected->mm)
+		if (selected->mm) {
 			task_set_lmk_waiting(selected);
-		if (oom_reaper)
-			mark_lmk_victim(selected);
+			if (!test_bit(MMF_OOM_SKIP, &selected->mm->flags) &&
+			    oom_reaper) {
+				mark_lmk_victim(selected);
+				wake_oom_reaper(selected);
+			}
+		}
 		task_unlock(selected);
-		if (oom_reaper)
-			wake_oom_reaper(selected);
 		trace_lowmemory_kill(selected, cache_size, cache_limit, free);
 		lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
 			"to free %ldkB on behalf of '%s' (%d) because\n"
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 9e88021..e8d9db4 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -824,14 +824,15 @@
 	return conn;
 
  failed_2:
-	kiblnd_destroy_conn(conn, true);
+	kiblnd_destroy_conn(conn);
+	LIBCFS_FREE(conn, sizeof(*conn));
  failed_1:
 	LIBCFS_FREE(init_qp_attr, sizeof(*init_qp_attr));
  failed_0:
 	return NULL;
 }
 
-void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn)
+void kiblnd_destroy_conn(struct kib_conn *conn)
 {
 	struct rdma_cm_id *cmid = conn->ibc_cmid;
 	struct kib_peer *peer = conn->ibc_peer;
@@ -894,8 +895,6 @@
 		rdma_destroy_id(cmid);
 		atomic_dec(&net->ibn_nconns);
 	}
-
-	LIBCFS_FREE(conn, sizeof(*conn));
 }
 
 int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why)
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index 1457697..30cb2f5 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -1018,7 +1018,7 @@
 struct kib_conn *kiblnd_create_conn(struct kib_peer *peer,
 				    struct rdma_cm_id *cmid,
 				    int state, int version);
-void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn);
+void kiblnd_destroy_conn(struct kib_conn *conn);
 void kiblnd_close_conn(struct kib_conn *conn, int error);
 void kiblnd_close_conn_locked(struct kib_conn *conn, int error);
 
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index 995f2da..ea9a0c2 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -3323,11 +3323,13 @@
 			spin_unlock_irqrestore(lock, flags);
 			dropped_lock = 1;
 
-			kiblnd_destroy_conn(conn, !peer);
+			kiblnd_destroy_conn(conn);
 
 			spin_lock_irqsave(lock, flags);
-			if (!peer)
+			if (!peer) {
+				kfree(conn);
 				continue;
+			}
 
 			conn->ibc_peer = peer;
 			if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE)
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index 4de9dbc..c7bf8ab 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -1397,19 +1397,13 @@
 	if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
 	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
 		len = pcur_bss->Ssid.SsidLength;
-
-		wrqu->essid.length = len;
-
 		memcpy(extra, pcur_bss->Ssid.Ssid, len);
-
-		wrqu->essid.flags = 1;
 	} else {
-		ret = -1;
-		goto exit;
+		len = 0;
+		*extra = 0;
 	}
-
-exit:
-
+	wrqu->essid.length = len;
+	wrqu->essid.flags = 1;
 
 	return ret;
 }
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 27bf54b..1259654 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
+obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9e96f8a..2c4a63a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -237,11 +237,17 @@
 	case PM_POST_RESTORE:
 	case PM_POST_SUSPEND:
 		mutex_lock(&cooling_list_lock);
-		mutex_lock(&core_isolate_lock);
 		list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+			mutex_lock(&core_isolate_lock);
 			if (cpufreq_dev->cpufreq_state ==
 				cpufreq_dev->max_level) {
 				cpu = cpumask_any(&cpufreq_dev->allowed_cpus);
+				/*
+				 * Unlock this lock before calling
+				 * schedule_isolate. as this could lead to
+				 * deadlock with hotplug path.
+				 */
+				mutex_unlock(&core_isolate_lock);
 				if (cpu_online(cpu) &&
 					!cpumask_test_and_set_cpu(cpu,
 					&cpus_isolated_by_thermal)) {
@@ -249,9 +255,10 @@
 						cpumask_clear_cpu(cpu,
 						&cpus_isolated_by_thermal);
 				}
+				continue;
 			}
+			mutex_unlock(&core_isolate_lock);
 		}
-		mutex_unlock(&core_isolate_lock);
 		mutex_unlock(&cooling_list_lock);
 
 		atomic_set(&in_suspend, 0);
@@ -727,6 +734,7 @@
 	mutex_lock(&core_isolate_lock);
 	prev_state = cpufreq_device->cpufreq_state;
 	cpufreq_device->cpufreq_state = state;
+	mutex_unlock(&core_isolate_lock);
 	/* If state is the last, isolate the CPU */
 	if (state == cpufreq_device->max_level) {
 		if (cpu_online(cpu) &&
@@ -736,18 +744,11 @@
 				cpumask_clear_cpu(cpu,
 					&cpus_isolated_by_thermal);
 		}
-		mutex_unlock(&core_isolate_lock);
 		return ret;
 	} else if ((prev_state == cpufreq_device->max_level)
 			&& (state < cpufreq_device->max_level)) {
 		if (cpumask_test_and_clear_cpu(cpu, &cpus_pending_online)) {
 			cpu_dev = get_cpu_device(cpu);
-			mutex_unlock(&core_isolate_lock);
-			/*
-			 * Unlock before calling the device_online.
-			 * Else, this will lead to deadlock, since the hp
-			 * online callback will be blocked on this mutex.
-			 */
 			ret = device_online(cpu_dev);
 			if (ret)
 				pr_err("CPU:%d online error:%d\n", cpu, ret);
@@ -757,7 +758,6 @@
 			sched_unisolate_cpu(cpu);
 		}
 	}
-	mutex_unlock(&core_isolate_lock);
 update_frequency:
 	clip_freq = cpufreq_device->freq_table[state];
 	cpufreq_device->clipped_freq = clip_freq;
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index fe0a7c7..c137d3d 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -49,6 +49,11 @@
 	return tmdev->ops->hw_init(tmdev);
 }
 
+static int tsens_calib(struct tsens_device *tmdev)
+{
+	return tmdev->ops->calibrate(tmdev);
+}
+
 static int tsens_register_interrupts(struct tsens_device *tmdev)
 {
 	if (tmdev->ops->interrupts_reg)
@@ -82,6 +87,9 @@
 	{	.compatible = "qcom,tsens24xx",
 		.data = &data_tsens24xx,
 	},
+	{	.compatible = "qcom,msm8937-tsens",
+		.data = &data_tsens14xx,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, tsens_table);
@@ -97,6 +105,7 @@
 	struct device_node *of_node = pdev->dev.of_node;
 	const struct of_device_id *id;
 	const struct tsens_data *data;
+	int rc = 0;
 	struct resource *res_tsens_mem;
 
 	if (!of_match_node(tsens_table, of_node)) {
@@ -150,7 +159,27 @@
 		return PTR_ERR(tmdev->tsens_tm_addr);
 	}
 
-	return 0;
+	/* TSENS eeprom register region */
+	res_tsens_mem = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tsens_eeprom_physical");
+	if (!res_tsens_mem) {
+		pr_debug("Could not get tsens physical address resource\n");
+	} else {
+		tmdev->tsens_calib_addr = devm_ioremap_resource(&pdev->dev,
+								res_tsens_mem);
+		if (IS_ERR(tmdev->tsens_calib_addr)) {
+			dev_err(&pdev->dev, "Failed to IO map TSENS EEPROM registers.\n");
+			rc = PTR_ERR(tmdev->tsens_calib_addr);
+		}  else {
+			rc = tsens_calib(tmdev);
+			if (rc) {
+				pr_err("Error initializing TSENS controller\n");
+				return rc;
+			}
+		}
+	}
+
+	return rc;
 }
 
 static int tsens_thermal_zone_register(struct tsens_device *tmdev)
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index bb5f706..c662cd7 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -430,7 +430,16 @@
 	if (trip >= data->ntrips || trip < 0)
 		return -EDOM;
 
-	*temp = data->trips[trip].temperature;
+	if (data->senps && data->senps->ops->get_trip_temp) {
+		int ret;
+
+		ret = data->senps->ops->get_trip_temp(data->senps->sensor_data,
+						      trip, temp);
+		if (ret)
+			return ret;
+	} else {
+		*temp = data->trips[trip].temperature;
+	}
 
 	return 0;
 }
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index e7d6241..8085606 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -71,3 +71,24 @@
 	  voltage.
 
 	  If you want this support, you should say Y here.
+
+config QTI_BCL_PMIC5
+	bool "BCL driver for BCL peripherals in PMIC5"
+	depends on SPMI && THERMAL_OF
+	help
+	  Say Y here to enable this BCL driver for PMIC5. This driver
+	  provides routines to configure and monitor the BCL
+	  PMIC peripheral. This driver registers the battery current and
+	  voltage sensors with the thermal core framework and can take
+	  threshold input and notify the thermal core when the threshold is
+	  reached.
+
+config QTI_BCL_SOC_DRIVER
+	bool "QTI Battery state of charge sensor driver"
+	depends on THERMAL_OF
+	help
+	  This driver registers battery state of charge as a sensor with
+	  thermal zone. This sensor can monitor for state of charge
+	  threshold and notify the thermal framework.
+
+	  If you want this support, you should say Y here.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 257b714..8387285 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -6,3 +6,5 @@
 obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o
 obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o
 obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o qmi_cooling.o
+obj-$(CONFIG_QTI_BCL_PMIC5) += bcl_pmic5.o
+obj-$(CONFIG_QTI_BCL_SOC_DRIVER) += bcl_soc.o
diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c
new file mode 100644
index 0000000..146d09d
--- /dev/null
+++ b/drivers/thermal/qcom/bcl_pmic5.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+
+#define BCL_DRIVER_NAME       "bcl_pmic5"
+#define BCL_MONITOR_EN        0x46
+#define BCL_IRQ_STATUS        0x09
+
+#define BCL_IBAT_HIGH         0x4B
+#define BCL_IBAT_TOO_HIGH     0x4C
+#define BCL_IBAT_READ         0x86
+#define BCL_IBAT_SCALING_UA   78127
+
+#define BCL_VBAT_READ         0x76
+#define BCL_VBAT_ADC_LOW      0x48
+#define BCL_VBAT_COMP_LOW     0x49
+#define BCL_VBAT_COMP_TLOW    0x4A
+
+#define BCL_IRQ_VCMP_L0       0x1
+#define BCL_IRQ_VCMP_L1       0x2
+#define BCL_IRQ_VCMP_L2       0x4
+#define BCL_IRQ_IBAT_L0       0x10
+#define BCL_IRQ_IBAT_L1       0x20
+#define BCL_IRQ_IBAT_L2       0x40
+
+#define BCL_VBAT_SCALING_UV   49827
+#define BCL_VBAT_NO_READING   127
+#define BCL_VBAT_BASE_MV      2000
+#define BCL_VBAT_INC_MV       25
+#define BCL_VBAT_MAX_MV       3600
+
+enum bcl_dev_type {
+	BCL_IBAT_LVL0,
+	BCL_IBAT_LVL1,
+	BCL_VBAT_LVL0,
+	BCL_VBAT_LVL1,
+	BCL_VBAT_LVL2,
+	BCL_TYPE_MAX,
+};
+
+static char bcl_int_names[BCL_TYPE_MAX][25] = {
+	"bcl-ibat-lvl0",
+	"bcl-ibat-lvl1",
+	"bcl-vbat-lvl0",
+	"bcl-vbat-lvl1",
+	"bcl-vbat-lvl2",
+};
+
+struct bcl_peripheral_data {
+	int                     irq_num;
+	long int		trip_thresh;
+	int                     last_val;
+	struct mutex            state_trans_lock;
+	bool			irq_enabled;
+	enum bcl_dev_type	type;
+	struct thermal_zone_of_device_ops ops;
+	struct thermal_zone_device *tz_dev;
+};
+
+struct bcl_device {
+	struct regmap			*regmap;
+	uint16_t			fg_bcl_addr;
+	struct bcl_peripheral_data	param[BCL_TYPE_MAX];
+};
+
+static struct bcl_device *bcl_perph;
+
+static int bcl_read_register(int16_t reg_offset, unsigned int *data)
+{
+	int ret = 0;
+
+	if (!bcl_perph) {
+		pr_err("BCL device not initialized\n");
+		return -EINVAL;
+	}
+	ret = regmap_read(bcl_perph->regmap,
+			       (bcl_perph->fg_bcl_addr + reg_offset),
+			       data);
+	if (ret < 0)
+		pr_err("Error reading register %d. err:%d\n",
+				reg_offset, ret);
+
+	return ret;
+}
+
+static int bcl_write_general_register(int16_t reg_offset,
+					uint16_t base, uint8_t data)
+{
+	int  ret = 0;
+	uint8_t *write_buf = &data;
+
+	if (!bcl_perph) {
+		pr_err("BCL device not initialized\n");
+		return -EINVAL;
+	}
+	ret = regmap_write(bcl_perph->regmap, (base + reg_offset), *write_buf);
+	if (ret < 0) {
+		pr_err("Error reading register %d. err:%d\n",
+				reg_offset, ret);
+		return ret;
+	}
+	pr_debug("wrote 0x%02x to 0x%04x\n", data, base + reg_offset);
+
+	return ret;
+}
+
+static int bcl_write_register(int16_t reg_offset, uint8_t data)
+{
+	return bcl_write_general_register(reg_offset,
+			bcl_perph->fg_bcl_addr, data);
+}
+
+static void convert_adc_to_vbat_thresh_val(int *val)
+{
+	/*
+	 * Threshold register is bit shifted from ADC MSB.
+	 * So the scaling factor is half.
+	 */
+	*val = (*val * BCL_VBAT_SCALING_UV) / 2000;
+}
+
+static void convert_adc_to_vbat_val(int *val)
+{
+	*val = (*val * BCL_VBAT_SCALING_UV) / 1000;
+}
+
+static void convert_ibat_to_adc_val(int *val)
+{
+	/*
+	 * Threshold register is bit shifted from ADC MSB.
+	 * So the scaling factor is half.
+	 */
+	*val = (*val * 2000) / BCL_IBAT_SCALING_UA;
+}
+
+static void convert_adc_to_ibat_val(int *val)
+{
+	*val = (*val * BCL_IBAT_SCALING_UA) / 1000;
+}
+
+static int bcl_set_ibat(void *data, int low, int high)
+{
+	int ret = 0, ibat_ua, thresh_value;
+	int8_t val = 0;
+	int16_t addr;
+	struct bcl_peripheral_data *bat_data =
+		(struct bcl_peripheral_data *)data;
+
+	mutex_lock(&bat_data->state_trans_lock);
+	thresh_value = high;
+	if (bat_data->trip_thresh == thresh_value)
+		goto set_trip_exit;
+
+	if (bat_data->irq_num && bat_data->irq_enabled) {
+		disable_irq_nosync(bat_data->irq_num);
+		bat_data->irq_enabled = false;
+	}
+	if (thresh_value == INT_MAX) {
+		bat_data->trip_thresh = thresh_value;
+		goto set_trip_exit;
+	}
+
+	ibat_ua = thresh_value;
+	convert_ibat_to_adc_val(&thresh_value);
+	val = (int8_t)thresh_value;
+	if (&bcl_perph->param[BCL_IBAT_LVL0] == bat_data) {
+		addr = BCL_IBAT_HIGH;
+		pr_debug("ibat high threshold:%d mA ADC:0x%02x\n",
+				ibat_ua, val);
+	} else if (&bcl_perph->param[BCL_IBAT_LVL1] == bat_data) {
+		addr = BCL_IBAT_TOO_HIGH;
+		pr_debug("ibat too high threshold:%d mA ADC:0x%02x\n",
+				ibat_ua, val);
+	} else {
+		goto set_trip_exit;
+	}
+	ret = bcl_write_register(addr, val);
+	if (ret)
+		goto set_trip_exit;
+	bat_data->trip_thresh = ibat_ua;
+
+	if (bat_data->irq_num && !bat_data->irq_enabled) {
+		enable_irq(bat_data->irq_num);
+		bat_data->irq_enabled = true;
+	}
+
+set_trip_exit:
+	mutex_unlock(&bat_data->state_trans_lock);
+
+	return ret;
+}
+
+static int bcl_read_ibat(void *data, int *adc_value)
+{
+	int ret = 0;
+	unsigned int val = 0;
+	struct bcl_peripheral_data *bat_data =
+		(struct bcl_peripheral_data *)data;
+
+	*adc_value = val;
+	ret = bcl_read_register(BCL_IBAT_READ, &val);
+	if (ret)
+		goto bcl_read_exit;
+	/* IBat ADC reading is in 2's compliment form */
+	*adc_value = sign_extend32(val, 7);
+	if (val == 0) {
+		/*
+		 * The sensor sometime can read a value 0 if there is
+		 * consequtive reads
+		 */
+		*adc_value = bat_data->last_val;
+	} else {
+		convert_adc_to_ibat_val(adc_value);
+		bat_data->last_val = *adc_value;
+	}
+	pr_debug("ibat:%d mA ADC:0x%02x\n", bat_data->last_val, val);
+
+bcl_read_exit:
+	return ret;
+}
+
+static int bcl_get_vbat_trip(void *data, int type, int *trip)
+{
+	int ret = 0;
+	unsigned int val = 0;
+	struct bcl_peripheral_data *bat_data =
+		(struct bcl_peripheral_data *)data;
+	int16_t addr;
+
+	*trip = 0;
+	if (&bcl_perph->param[BCL_VBAT_LVL0] == bat_data)
+		addr = BCL_VBAT_ADC_LOW;
+	else if (&bcl_perph->param[BCL_VBAT_LVL1] == bat_data)
+		addr = BCL_VBAT_COMP_LOW;
+	else if (&bcl_perph->param[BCL_VBAT_LVL2] == bat_data)
+		addr = BCL_VBAT_COMP_TLOW;
+	else
+		return -ENODEV;
+
+	ret = bcl_read_register(addr, &val);
+	if (ret)
+		return ret;
+
+	if (addr == BCL_VBAT_ADC_LOW) {
+		*trip = val;
+		convert_adc_to_vbat_thresh_val(trip);
+		pr_debug("vbat trip: %d mV ADC:0x%02x\n", *trip, val);
+	} else {
+		*trip = 2250 + val * 25;
+		if (*trip > BCL_VBAT_MAX_MV)
+			*trip = BCL_VBAT_MAX_MV;
+		pr_debug("vbat-%s-low trip: %d mV ADC:0x%02x\n",
+				(addr == BCL_VBAT_COMP_LOW) ?
+				"too" : "critical",
+				*trip, val);
+	}
+
+	return 0;
+}
+
+static int bcl_set_vbat(void *data, int low, int high)
+{
+	struct bcl_peripheral_data *bat_data =
+		(struct bcl_peripheral_data *)data;
+
+	mutex_lock(&bat_data->state_trans_lock);
+
+	if (low == INT_MIN &&
+		bat_data->irq_num && bat_data->irq_enabled) {
+		disable_irq_nosync(bat_data->irq_num);
+		bat_data->irq_enabled = false;
+		pr_debug("vbat: disable irq:%d\n", bat_data->irq_num);
+	} else if (low != INT_MIN &&
+		 bat_data->irq_num && !bat_data->irq_enabled) {
+		enable_irq(bat_data->irq_num);
+		bat_data->irq_enabled = true;
+		pr_debug("vbat: enable irq:%d\n", bat_data->irq_num);
+	}
+
+	/*
+	 * Vbat threshold's are pre-configured and cant be
+	 * programmed.
+	 */
+	mutex_unlock(&bat_data->state_trans_lock);
+
+	return 0;
+}
+
+static int bcl_read_vbat(void *data, int *adc_value)
+{
+	int ret = 0;
+	unsigned int val = 0;
+	struct bcl_peripheral_data *bat_data =
+		(struct bcl_peripheral_data *)data;
+
+	*adc_value = val;
+	ret = bcl_read_register(BCL_VBAT_READ, &val);
+	if (ret)
+		goto bcl_read_exit;
+	*adc_value = val;
+	if (*adc_value == BCL_VBAT_NO_READING) {
+		*adc_value = bat_data->last_val;
+	} else {
+		convert_adc_to_vbat_val(adc_value);
+		bat_data->last_val = *adc_value;
+	}
+	pr_debug("vbat:%d mv\n", bat_data->last_val);
+
+bcl_read_exit:
+	return ret;
+}
+
+static irqreturn_t bcl_handle_irq(int irq, void *data)
+{
+	struct bcl_peripheral_data *perph_data =
+		(struct bcl_peripheral_data *)data;
+	unsigned int irq_status = 0;
+	int ret;
+	bool notify = false;
+
+	mutex_lock(&perph_data->state_trans_lock);
+	if (!perph_data->irq_enabled) {
+		pr_err("irq:%d not in expected state\n", irq);
+		disable_irq_nosync(irq);
+		perph_data->irq_enabled = false;
+		goto exit_intr;
+	}
+	mutex_unlock(&perph_data->state_trans_lock);
+
+	ret = bcl_read_register(BCL_IRQ_STATUS, &irq_status);
+	if (ret) {
+		disable_irq_nosync(irq);
+		perph_data->irq_enabled = false;
+		return IRQ_HANDLED;
+	}
+	pr_debug("Irq:%d triggered for bcl type:%d. status:%u\n",
+			irq, perph_data->type, irq_status);
+	switch (perph_data->type) {
+	case BCL_VBAT_LVL0: /* BCL L0 interrupt */
+		if ((irq_status & BCL_IRQ_VCMP_L0) &&
+		       (bcl_perph->param[BCL_VBAT_LVL0].tz_dev)) {
+			of_thermal_handle_trip(
+				bcl_perph->param[BCL_VBAT_LVL0].tz_dev);
+			notify = true;
+		}
+		if ((irq_status & BCL_IRQ_IBAT_L0) &&
+			(bcl_perph->param[BCL_IBAT_LVL0].tz_dev)) {
+			of_thermal_handle_trip(
+				bcl_perph->param[BCL_IBAT_LVL0].tz_dev);
+			notify = true;
+		}
+		break;
+	case BCL_VBAT_LVL1: /* BCL L1 interrupt */
+		if ((irq_status & BCL_IRQ_VCMP_L1) &&
+			(bcl_perph->param[BCL_VBAT_LVL1].tz_dev)) {
+			of_thermal_handle_trip(
+				bcl_perph->param[BCL_VBAT_LVL1].tz_dev);
+			notify = true;
+		}
+		if ((irq_status & BCL_IRQ_IBAT_L1) &&
+			(bcl_perph->param[BCL_IBAT_LVL1].tz_dev)) {
+			of_thermal_handle_trip(
+				bcl_perph->param[BCL_IBAT_LVL1].tz_dev);
+			notify = true;
+		}
+		break;
+	case BCL_VBAT_LVL2: /* BCL L2 interrupt */
+		if ((irq_status & BCL_IRQ_VCMP_L2) &&
+			(bcl_perph->param[BCL_VBAT_LVL2].tz_dev)) {
+			of_thermal_handle_trip(
+				bcl_perph->param[BCL_VBAT_LVL2].tz_dev);
+			notify = true;
+		}
+		break;
+	default:
+		pr_err("Invalid type%d for interrupt:%d\n",
+				perph_data->type, irq);
+		break;
+	}
+	if (!notify)
+		pr_err_ratelimited("Irq:%d triggered. status:%u\n",
+					irq, irq_status);
+
+	return IRQ_HANDLED;
+
+exit_intr:
+	mutex_unlock(&perph_data->state_trans_lock);
+	return IRQ_HANDLED;
+}
+
+static int bcl_get_devicetree_data(struct platform_device *pdev)
+{
+	int ret = 0;
+	const __be32 *prop = NULL;
+	struct device_node *dev_node = pdev->dev.of_node;
+
+	prop = of_get_address(dev_node, 0, NULL, NULL);
+	if (prop) {
+		bcl_perph->fg_bcl_addr = be32_to_cpu(*prop);
+		pr_debug("fg_bcl@%04x\n", bcl_perph->fg_bcl_addr);
+	} else {
+		dev_err(&pdev->dev, "No fg_bcl registers found\n");
+		return -ENODEV;
+	}
+
+	return ret;
+}
+
+static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type,
+		struct bcl_peripheral_data *data,
+		irqreturn_t (*handle)(int, void *))
+{
+	int ret = 0, irq_num = 0;
+	char *int_name = bcl_int_names[type];
+
+	mutex_lock(&data->state_trans_lock);
+	data->irq_num = 0;
+	data->irq_enabled = false;
+	irq_num = platform_get_irq_byname(pdev, int_name);
+	if (irq_num && handle) {
+		ret = devm_request_threaded_irq(&pdev->dev,
+				irq_num, NULL, handle,
+				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				int_name, data);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Error requesting trip irq. err:%d\n",
+				ret);
+			mutex_unlock(&data->state_trans_lock);
+			return;
+		}
+		disable_irq_nosync(irq_num);
+		data->irq_num = irq_num;
+	} else if (irq_num && !handle) {
+		disable_irq_nosync(irq_num);
+		data->irq_num = irq_num;
+	}
+	mutex_unlock(&data->state_trans_lock);
+}
+
+static void bcl_vbat_init(struct platform_device *pdev,
+		enum bcl_dev_type type)
+{
+	struct bcl_peripheral_data *vbat = &bcl_perph->param[type];
+	irqreturn_t (*handle)(int, void *) = bcl_handle_irq;
+
+	mutex_init(&vbat->state_trans_lock);
+	vbat->type = type;
+	bcl_fetch_trip(pdev, type, vbat, handle);
+	vbat->ops.get_temp = bcl_read_vbat;
+	vbat->ops.set_trips = bcl_set_vbat;
+	vbat->ops.get_trip_temp = bcl_get_vbat_trip;
+	vbat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+				type, vbat, &vbat->ops);
+	if (IS_ERR(vbat->tz_dev)) {
+		pr_debug("vbat[%s] register failed. err:%ld\n",
+				bcl_int_names[type],
+				PTR_ERR(vbat->tz_dev));
+		vbat->tz_dev = NULL;
+		return;
+	}
+	thermal_zone_device_update(vbat->tz_dev, THERMAL_DEVICE_UP);
+}
+
+static void bcl_probe_vbat(struct platform_device *pdev)
+{
+	bcl_vbat_init(pdev, BCL_VBAT_LVL0);
+	bcl_vbat_init(pdev, BCL_VBAT_LVL1);
+	bcl_vbat_init(pdev, BCL_VBAT_LVL2);
+}
+
+static void bcl_ibat_init(struct platform_device *pdev,
+				enum bcl_dev_type type)
+{
+	struct bcl_peripheral_data *ibat = &bcl_perph->param[type];
+
+	mutex_init(&ibat->state_trans_lock);
+	ibat->type = type;
+	bcl_fetch_trip(pdev, type, ibat, NULL);
+	ibat->ops.get_temp = bcl_read_ibat;
+	ibat->ops.set_trips = bcl_set_ibat;
+
+	switch (type) {
+	case BCL_IBAT_LVL0:
+		if (!bcl_perph->param[BCL_VBAT_LVL0].irq_num ||
+			ibat->irq_num !=
+			bcl_perph->param[BCL_VBAT_LVL0].irq_num) {
+			pr_err("ibat[%d]: irq %d mismatch\n",
+				type, ibat->irq_num);
+			return;
+		}
+		break;
+	case BCL_IBAT_LVL1:
+		if (!bcl_perph->param[BCL_VBAT_LVL1].irq_num ||
+			ibat->irq_num !=
+			bcl_perph->param[BCL_VBAT_LVL1].irq_num) {
+			pr_err("ibat[%d]: irq %d mismatch\n",
+				type, ibat->irq_num);
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	ibat->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+				type, ibat, &ibat->ops);
+	if (IS_ERR(ibat->tz_dev)) {
+		pr_debug("ibat:[%s] register failed. err:%ld\n",
+				bcl_int_names[type],
+				PTR_ERR(ibat->tz_dev));
+		ibat->tz_dev = NULL;
+		return;
+	}
+	thermal_zone_device_update(ibat->tz_dev, THERMAL_DEVICE_UP);
+}
+
+static void bcl_probe_ibat(struct platform_device *pdev)
+{
+	bcl_ibat_init(pdev, BCL_IBAT_LVL0);
+	bcl_ibat_init(pdev, BCL_IBAT_LVL1);
+}
+
+static void bcl_configure_bcl_peripheral(void)
+{
+	bcl_write_register(BCL_MONITOR_EN, BIT(7));
+}
+
+static int bcl_remove(struct platform_device *pdev)
+{
+	int i = 0;
+
+	for (; i < BCL_TYPE_MAX; i++) {
+		if (!bcl_perph->param[i].tz_dev)
+			continue;
+		thermal_zone_of_sensor_unregister(&pdev->dev,
+				bcl_perph->param[i].tz_dev);
+	}
+	bcl_perph = NULL;
+
+	return 0;
+}
+
+static int bcl_probe(struct platform_device *pdev)
+{
+	bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
+	if (!bcl_perph)
+		return -ENOMEM;
+
+	bcl_perph->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!bcl_perph->regmap) {
+		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+
+	bcl_get_devicetree_data(pdev);
+	bcl_probe_vbat(pdev);
+	bcl_probe_ibat(pdev);
+	bcl_configure_bcl_peripheral();
+
+	dev_set_drvdata(&pdev->dev, bcl_perph);
+
+	return 0;
+}
+
+static const struct of_device_id bcl_match[] = {
+	{
+		.compatible = "qcom,bcl-v5",
+	},
+	{},
+};
+
+static struct platform_driver bcl_driver = {
+	.probe  = bcl_probe,
+	.remove = bcl_remove,
+	.driver = {
+		.name           = BCL_DRIVER_NAME,
+		.owner          = THIS_MODULE,
+		.of_match_table = bcl_match,
+	},
+};
+
+builtin_platform_driver(bcl_driver);
diff --git a/drivers/thermal/qcom/bcl_soc.c b/drivers/thermal/qcom/bcl_soc.c
new file mode 100644
index 0000000..e4d5157
--- /dev/null
+++ b/drivers/thermal/qcom/bcl_soc.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+
+#define BCL_DRIVER_NAME       "bcl_soc_peripheral"
+
+struct bcl_device {
+	struct notifier_block			psy_nb;
+	struct work_struct			soc_eval_work;
+	long int				trip_temp;
+	int					trip_val;
+	struct mutex				state_trans_lock;
+	bool					irq_enabled;
+	struct thermal_zone_device		*tz_dev;
+	struct thermal_zone_of_device_ops	ops;
+};
+
+static struct bcl_device *bcl_perph;
+
+static int bcl_set_soc(void *data, int low, int high)
+{
+	if (low == bcl_perph->trip_temp)
+		return 0;
+
+	mutex_lock(&bcl_perph->state_trans_lock);
+	pr_debug("low soc threshold:%d\n", low);
+	bcl_perph->trip_temp = low;
+	if (low == INT_MIN) {
+		bcl_perph->irq_enabled = false;
+		goto unlock_and_exit;
+	}
+	bcl_perph->irq_enabled = true;
+	schedule_work(&bcl_perph->soc_eval_work);
+
+unlock_and_exit:
+	mutex_unlock(&bcl_perph->state_trans_lock);
+	return 0;
+}
+
+static int bcl_read_soc(void *data, int *val)
+{
+	static struct power_supply *batt_psy;
+	union power_supply_propval ret = {0,};
+	int err = 0;
+
+	*val = 100;
+	if (!batt_psy)
+		batt_psy = power_supply_get_by_name("battery");
+	if (batt_psy) {
+		err = power_supply_get_property(batt_psy,
+				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		if (err) {
+			pr_err("battery percentage read error:%d\n",
+				err);
+			return err;
+		}
+		*val = ret.intval;
+	}
+	pr_debug("soc:%d\n", *val);
+
+	return err;
+}
+
+static void bcl_evaluate_soc(struct work_struct *work)
+{
+	int battery_percentage;
+
+	if (bcl_read_soc(NULL, &battery_percentage))
+		return;
+
+	mutex_lock(&bcl_perph->state_trans_lock);
+	if (!bcl_perph->irq_enabled)
+		goto eval_exit;
+	if (battery_percentage > bcl_perph->trip_temp)
+		goto eval_exit;
+
+	bcl_perph->trip_val = battery_percentage;
+	mutex_unlock(&bcl_perph->state_trans_lock);
+	of_thermal_handle_trip(bcl_perph->tz_dev);
+
+	return;
+eval_exit:
+	mutex_unlock(&bcl_perph->state_trans_lock);
+}
+
+static int battery_supply_callback(struct notifier_block *nb,
+			unsigned long event, void *data)
+{
+	struct power_supply *psy = data;
+
+	if (strcmp(psy->desc->name, "battery"))
+		return NOTIFY_OK;
+	schedule_work(&bcl_perph->soc_eval_work);
+
+	return NOTIFY_OK;
+}
+
+static int bcl_soc_remove(struct platform_device *pdev)
+{
+	power_supply_unreg_notifier(&bcl_perph->psy_nb);
+	flush_work(&bcl_perph->soc_eval_work);
+	if (bcl_perph->tz_dev)
+		thermal_zone_of_sensor_unregister(&pdev->dev,
+				bcl_perph->tz_dev);
+
+	return 0;
+}
+
+static int bcl_soc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
+	if (!bcl_perph)
+		return -ENOMEM;
+
+	mutex_init(&bcl_perph->state_trans_lock);
+	bcl_perph->ops.get_temp = bcl_read_soc;
+	bcl_perph->ops.set_trips = bcl_set_soc;
+	INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc);
+	bcl_perph->psy_nb.notifier_call = battery_supply_callback;
+
+	ret = power_supply_reg_notifier(&bcl_perph->psy_nb);
+	if (ret < 0) {
+		pr_err("soc notifier registration error. defer. err:%d\n",
+			ret);
+		ret = -EPROBE_DEFER;
+		goto bcl_soc_probe_exit;
+	}
+	bcl_perph->tz_dev = thermal_zone_of_sensor_register(&pdev->dev,
+				0, bcl_perph, &bcl_perph->ops);
+	if (IS_ERR(bcl_perph->tz_dev)) {
+		pr_err("soc TZ register failed. err:%ld\n",
+				PTR_ERR(bcl_perph->tz_dev));
+		ret = PTR_ERR(bcl_perph->tz_dev);
+		bcl_perph->tz_dev = NULL;
+		goto bcl_soc_probe_exit;
+	}
+	thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP);
+	schedule_work(&bcl_perph->soc_eval_work);
+
+	dev_set_drvdata(&pdev->dev, bcl_perph);
+
+	return 0;
+
+bcl_soc_probe_exit:
+	bcl_soc_remove(pdev);
+	return ret;
+}
+
+static const struct of_device_id bcl_match[] = {
+	{
+		.compatible = "qcom,msm-bcl-soc",
+	},
+	{},
+};
+
+static struct platform_driver bcl_driver = {
+	.probe  = bcl_soc_probe,
+	.remove = bcl_soc_remove,
+	.driver = {
+		.name           = BCL_DRIVER_NAME,
+		.owner          = THIS_MODULE,
+		.of_match_table = bcl_match,
+	},
+};
+
+builtin_platform_driver(bcl_driver);
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 94c93b5..66f67ce 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -98,13 +98,13 @@
 	void *int_clr_reg;
 	void *min_freq_reg;
 	cpumask_t core_map;
-	struct timer_list poll_timer;
+	struct delayed_work freq_poll_work;
 	unsigned long max_freq;
 	unsigned long min_freq;
 	unsigned long hw_freq_limit;
 	struct device_attribute lmh_freq_attr;
 	struct list_head list;
-	atomic_t is_irq_enabled;
+	bool is_irq_enabled;
 	struct mutex access_lock;
 	struct __limits_cdev_data *cdev_data;
 	struct regulator *isens_reg;
@@ -184,33 +184,37 @@
 	return max_limit;
 }
 
-static void limits_dcvs_poll(unsigned long data)
+static void limits_dcvs_poll(struct work_struct *work)
 {
 	unsigned long max_limit = 0;
-	struct limits_dcvs_hw *hw = (struct limits_dcvs_hw *)data;
+	struct limits_dcvs_hw *hw = container_of(work,
+					struct limits_dcvs_hw,
+					freq_poll_work.work);
 
+	mutex_lock(&hw->access_lock);
 	if (hw->max_freq == UINT_MAX)
 		limits_dcvs_get_freq_limits(cpumask_first(&hw->core_map),
 			&hw->max_freq, &hw->min_freq);
 	max_limit = limits_mitigation_notify(hw);
 	if (max_limit >= hw->max_freq) {
-		del_timer(&hw->poll_timer);
 		writel_relaxed(0xFF, hw->int_clr_reg);
-		atomic_set(&hw->is_irq_enabled, 1);
+		hw->is_irq_enabled = true;
 		enable_irq(hw->irq_num);
 	} else {
-		mod_timer(&hw->poll_timer, jiffies + msecs_to_jiffies(
-			LIMITS_POLLING_DELAY_MS));
+		mod_delayed_work(system_highpri_wq, &hw->freq_poll_work,
+			 msecs_to_jiffies(LIMITS_POLLING_DELAY_MS));
 	}
+	mutex_unlock(&hw->access_lock);
 }
 
 static void lmh_dcvs_notify(struct limits_dcvs_hw *hw)
 {
-	if (atomic_dec_and_test(&hw->is_irq_enabled)) {
+	if (hw->is_irq_enabled) {
+		hw->is_irq_enabled = false;
 		disable_irq_nosync(hw->irq_num);
 		limits_mitigation_notify(hw);
-		mod_timer(&hw->poll_timer, jiffies + msecs_to_jiffies(
-			LIMITS_POLLING_DELAY_MS));
+		mod_delayed_work(system_highpri_wq, &hw->freq_poll_work,
+			 msecs_to_jiffies(LIMITS_POLLING_DELAY_MS));
 	}
 }
 
@@ -218,7 +222,9 @@
 {
 	struct limits_dcvs_hw *hw = data;
 
+	mutex_lock(&hw->access_lock);
 	lmh_dcvs_notify(hw);
+	mutex_unlock(&hw->access_lock);
 
 	return IRQ_HANDLED;
 }
@@ -373,8 +379,8 @@
 	ret = limits_dcvs_write(hw->affinity, LIMITS_SUB_FN_THERMAL,
 				  LIMITS_FREQ_CAP, max_freq,
 				  (max_freq == U32_MAX) ? 0 : 1, 1);
-	mutex_unlock(&hw->access_lock);
 	lmh_dcvs_notify(hw);
+	mutex_unlock(&hw->access_lock);
 
 	return ret;
 }
@@ -626,9 +632,7 @@
 	}
 
 	mutex_init(&hw->access_lock);
-	init_timer_deferrable(&hw->poll_timer);
-	hw->poll_timer.data = (unsigned long)hw;
-	hw->poll_timer.function = limits_dcvs_poll;
+	INIT_DEFERRABLE_WORK(&hw->freq_poll_work, limits_dcvs_poll);
 	hw->osm_hw_reg = devm_ioremap(&pdev->dev, request_reg, 0x4);
 	if (!hw->osm_hw_reg) {
 		pr_err("register remap failed\n");
@@ -645,7 +649,7 @@
 		pr_err("Error getting IRQ number. err:%d\n", hw->irq_num);
 		goto probe_exit;
 	}
-	atomic_set(&hw->is_irq_enabled, 1);
+	hw->is_irq_enabled = true;
 	ret = devm_request_threaded_irq(&pdev->dev, hw->irq_num, NULL,
 		lmh_dcvs_handle_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT
 		| IRQF_NO_SUSPEND, hw->sensor_name, hw);
diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c
index 9b4fae8..cc66f37 100644
--- a/drivers/thermal/qcom/qti_virtual_sensor.c
+++ b/drivers/thermal/qcom/qti_virtual_sensor.c
@@ -79,6 +79,18 @@
 				"apc1-l2-usr"},
 		.logic = VIRT_MAXIMUM,
 	},
+	{
+		.virt_zone_name = "hepta-cpu-max-step",
+		.num_sensors = 7,
+		.sensor_names = {"apc1-cpu0-usr",
+				"apc1-cpu1-usr",
+				"apc1-cpu2-usr",
+				"apc1-cpu3-usr",
+				"cpuss0-usr",
+				"cpuss1-usr",
+				"cpuss3-usr"},
+		.logic = VIRT_MAXIMUM,
+	},
 };
 
 int qti_virtual_sensor_register(struct device *dev)
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index bec3dea..f8fdc13 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -42,15 +42,128 @@
 #define QPNP_PERPH_TYPE2				0x2
 #define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT		2
 #define QPNP_PERPH_SUBTYPE_TWO_CHANNEL_SUPPORT		0x22
+#define QPNP_STATUS1					0x8
+#define QPNP_STATUS1_OP_MODE				4
+#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS		BIT(2)
+#define QPNP_STATUS1_REQ_STS				BIT(1)
+#define QPNP_STATUS1_EOC				BIT(0)
+#define QPNP_STATUS2					0x9
+#define QPNP_STATUS2_CONV_SEQ_STATE			6
+#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG		BIT(1)
+#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS		BIT(0)
+#define QPNP_CONV_TIMEOUT_ERR				2
+
+#define QPNP_MODE_CTL					0x40
+#define QPNP_OP_MODE_SHIFT				3
+#define QPNP_VREF_XO_THM_FORCE				BIT(2)
+#define QPNP_AMUX_TRIM_EN				BIT(1)
+#define QPNP_ADC_TRIM_EN				BIT(0)
 #define QPNP_EN_CTL1					0x46
 #define QPNP_ADC_TM_EN					BIT(7)
 #define QPNP_BTM_CONV_REQ				0x47
 #define QPNP_ADC_CONV_REQ_EN				BIT(7)
 
+#define QPNP_ADC_DIG_PARAM				0x50
+#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT		3
+#define QPNP_HW_SETTLE_DELAY				0x51
+#define QPNP_CONV_SEQ_CTL				0x54
+#define QPNP_CONV_SEQ_HOLDOFF_SHIFT			4
+#define QPNP_CONV_SEQ_TRIG_CTL				0x55
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL			0x57
+#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT		0x3
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2			0x58
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT		0x4
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK		0xf0
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK		0xf
+
+#define QPNP_ADC_MEAS_INTERVAL_OP_CTL                   0x59
+#define QPNP_ADC_MEAS_INTERVAL_OP                       BIT(7)
+
 #define QPNP_OP_MODE_SHIFT				3
 #define QPNP_CONV_REQ					0x52
 #define QPNP_CONV_REQ_SET				BIT(7)
 
+#define QPNP_FAST_AVG_CTL				0x5a
+#define QPNP_FAST_AVG_EN				0x5b
+#define QPNP_FAST_AVG_ENABLED				BIT(7)
+
+#define QPNP_M0_LOW_THR_LSB				0x5c
+#define QPNP_M0_LOW_THR_MSB				0x5d
+#define QPNP_M0_HIGH_THR_LSB				0x5e
+#define QPNP_M0_HIGH_THR_MSB				0x5f
+#define QPNP_M1_ADC_CH_SEL_CTL				0x68
+#define QPNP_M1_LOW_THR_LSB				0x69
+#define QPNP_M1_LOW_THR_MSB				0x6a
+#define QPNP_M1_HIGH_THR_LSB				0x6b
+#define QPNP_M1_HIGH_THR_MSB				0x6c
+#define QPNP_M2_ADC_CH_SEL_CTL				0x70
+#define QPNP_M2_LOW_THR_LSB				0x71
+#define QPNP_M2_LOW_THR_MSB				0x72
+#define QPNP_M2_HIGH_THR_LSB				0x73
+#define QPNP_M2_HIGH_THR_MSB				0x74
+#define QPNP_M3_ADC_CH_SEL_CTL				0x78
+#define QPNP_M3_LOW_THR_LSB				0x79
+#define QPNP_M3_LOW_THR_MSB				0x7a
+#define QPNP_M3_HIGH_THR_LSB				0x7b
+#define QPNP_M3_HIGH_THR_MSB				0x7c
+#define QPNP_M4_ADC_CH_SEL_CTL				0x80
+#define QPNP_M4_LOW_THR_LSB				0x81
+#define QPNP_M4_LOW_THR_MSB				0x82
+#define QPNP_M4_HIGH_THR_LSB				0x83
+#define QPNP_M4_HIGH_THR_MSB				0x84
+#define QPNP_M5_ADC_CH_SEL_CTL				0x88
+#define QPNP_M5_LOW_THR_LSB				0x89
+#define QPNP_M5_LOW_THR_MSB				0x8a
+#define QPNP_M5_HIGH_THR_LSB				0x8b
+#define QPNP_M5_HIGH_THR_MSB				0x8c
+#define QPNP_M6_ADC_CH_SEL_CTL				0x90
+#define QPNP_M6_LOW_THR_LSB				0x91
+#define QPNP_M6_LOW_THR_MSB				0x92
+#define QPNP_M6_HIGH_THR_LSB				0x93
+#define QPNP_M6_HIGH_THR_MSB				0x94
+#define QPNP_M7_ADC_CH_SEL_CTL				0x98
+#define QPNP_M7_LOW_THR_LSB				0x99
+#define QPNP_M7_LOW_THR_MSB				0x9a
+#define QPNP_M7_HIGH_THR_LSB				0x9b
+#define QPNP_M7_HIGH_THR_MSB				0x9c
+
+#define QPNP_ADC_TM_MULTI_MEAS_EN			0x41
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M0			BIT(0)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M1			BIT(1)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M2			BIT(2)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M3			BIT(3)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M4			BIT(4)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M5			BIT(5)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M6			BIT(6)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M7			BIT(7)
+#define QPNP_ADC_TM_LOW_THR_INT_EN			0x42
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M0			BIT(0)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M1			BIT(1)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M2			BIT(2)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M3			BIT(3)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M4			BIT(4)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M5			BIT(5)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M6			BIT(6)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M7			BIT(7)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN			0x43
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0			BIT(0)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1			BIT(1)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2			BIT(2)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3			BIT(3)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4			BIT(4)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5			BIT(5)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6			BIT(6)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7			BIT(7)
+
+#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL			0x59
+#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL			0x6d
+#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL			0x75
+#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL			0x7d
+#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL			0x85
+#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL			0x8d
+#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL			0x95
+#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL			0x9d
+
 #define QPNP_ADC_TM_STATUS1				0x8
 #define QPNP_ADC_TM_STATUS_LOW				0xa
 #define QPNP_ADC_TM_STATUS_HIGH				0xb
@@ -62,6 +175,10 @@
 #define QPNP_ADC_TM_THR_LSB_MASK(val)			(val & 0xff)
 #define QPNP_ADC_TM_THR_MSB_MASK(val)			((val & 0xff00) >> 8)
 
+#define QPNP_MIN_TIME			2000
+#define QPNP_MAX_TIME			2100
+#define QPNP_RETRY			1000
+
 /* QPNP ADC TM HC start */
 #define QPNP_BTM_HC_STATUS1				0x08
 #define QPNP_BTM_HC_STATUS_LOW				0x0a
@@ -110,6 +227,8 @@
 	u8		adc_tm_high_enable;
 	u8		adc_tm_low_thr_set;
 	u8		adc_tm_high_thr_set;
+	spinlock_t	adc_tm_low_lock;
+	spinlock_t	adc_tm_high_lock;
 };
 
 struct qpnp_adc_thr_client_info {
@@ -168,6 +287,69 @@
 
 LIST_HEAD(qpnp_adc_tm_device_list);
 
+struct qpnp_adc_tm_trip_reg_type {
+	enum qpnp_adc_tm_channel_select	btm_amux_chan;
+	uint16_t			low_thr_lsb_addr;
+	uint16_t			low_thr_msb_addr;
+	uint16_t			high_thr_lsb_addr;
+	uint16_t			high_thr_msb_addr;
+	u8				multi_meas_en;
+	u8				low_thr_int_chan_en;
+	u8				high_thr_int_chan_en;
+	u8				meas_interval_ctl;
+};
+
+static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
+	[QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+		QPNP_M0_LOW_THR_LSB,
+		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
+		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
+		QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+		QPNP_M1_LOW_THR_LSB,
+		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
+		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
+		QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+		QPNP_M2_LOW_THR_LSB,
+		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
+		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
+		QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+		QPNP_M3_LOW_THR_LSB,
+		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
+		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
+		QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+		QPNP_M4_LOW_THR_LSB,
+		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
+		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
+		QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+		QPNP_M5_LOW_THR_LSB,
+		QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
+		QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
+		QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+		QPNP_M6_LOW_THR_LSB,
+		QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
+		QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
+		QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
+	[QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+		QPNP_M7_LOW_THR_LSB,
+		QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
+		QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
+		QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
+};
+
 static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
 	[SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
 	[SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
@@ -208,6 +390,33 @@
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_fast_avg_en(struct qpnp_adc_tm_chip *chip,
+				uint32_t *fast_avg_sample)
+{
+	int rc = 0, version = 0;
+	u8 fast_avg_en = 0;
+
+	version = qpnp_adc_get_revid_version(chip->dev);
+	if (!((version == QPNP_REV_ID_8916_1_0) ||
+		(version == QPNP_REV_ID_8916_1_1) ||
+		(version == QPNP_REV_ID_8916_2_0))) {
+		pr_debug("fast-avg-en not required for this version\n");
+		return rc;
+	}
+
+	fast_avg_en = QPNP_FAST_AVG_ENABLED;
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_EN, fast_avg_en, 1);
+	if (rc < 0) {
+		pr_err("adc-tm fast-avg enable err\n");
+		return rc;
+	}
+
+	if (*fast_avg_sample >= 3)
+		*fast_avg_sample = 2;
+
+	return rc;
+}
+
 static int qpnp_adc_tm_check_vreg_vote(struct qpnp_adc_tm_chip *chip)
 {
 	int rc = 0;
@@ -244,19 +453,37 @@
 		return rc;
 	}
 
-	data = QPNP_ADC_CONV_REQ_EN;
-	rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
-	if (rc < 0) {
-		pr_err("adc-tm enable failed\n");
-		return rc;
+	if (chip->adc_tm_hc) {
+		data = QPNP_ADC_CONV_REQ_EN;
+		rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
+		if (rc < 0) {
+			pr_err("adc-tm enable failed\n");
+			return rc;
+		}
 	}
-
 	return rc;
 }
 
 static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
 {
-	return 0;
+	u8 data = 0;
+	int rc = 0;
+
+	if (chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
+		if (rc < 0) {
+			pr_err("adc-tm enable failed\n");
+			return rc;
+		}
+	}
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data, 1);
+	if (rc < 0) {
+		pr_err("adc-tm disable failed\n");
+		return rc;
+	}
+
+	return rc;
 }
 
 static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
@@ -320,11 +547,129 @@
 static int32_t qpnp_adc_tm_enable_if_channel_meas(
 					struct qpnp_adc_tm_chip *chip)
 {
+	u8 adc_tm_meas_en = 0, status_low = 0, status_high = 0;
 	int rc = 0;
 
-	rc = qpnp_adc_tm_rc_check_channel_en(chip);
+	if (chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_rc_check_channel_en(chip);
+		if (rc) {
+			pr_err("adc_tm channel check failed\n");
+			return rc;
+		}
+	} else {
+		/* Check if a measurement request is still required */
+		rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+				&adc_tm_meas_en, 1);
+		if (rc) {
+			pr_err("read status high failed with %d\n", rc);
+			return rc;
+		}
+		rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+				&status_low, 1);
+		if (rc) {
+			pr_err("read status low failed with %d\n", rc);
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+							&status_high, 1);
+		if (rc) {
+			pr_err("read status high failed with %d\n", rc);
+			return rc;
+		}
+
+		/* Enable only if there are pending measurement requests */
+		if ((adc_tm_meas_en && status_high) ||
+				(adc_tm_meas_en && status_low)) {
+			qpnp_adc_tm_enable(chip);
+			/* Request conversion */
+			rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+							QPNP_CONV_REQ_SET, 1);
+			if (rc < 0) {
+				pr_err("adc-tm request conversion failed\n");
+				return rc;
+			}
+		} else {
+			/* disable the vote if applicable */
+			if (chip->adc_vote_enable && chip->adc->hkadc_ldo &&
+					chip->adc->hkadc_ldo_ok) {
+				qpnp_adc_disable_voltage(chip->adc);
+				chip->adc_vote_enable = false;
+			}
+		}
+	}
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
+								u8 mode_ctl)
+{
+	int rc;
+
+	mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
+
+	/* VADC_BTM current sets mode to recurring measurements */
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl, 1);
+	if (rc < 0)
+		pr_err("adc-tm write mode selection err\n");
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
+{
+	u8 status1 = 0, mode_ctl = 0;
+	int rc, count = 0;
+
+	/* Re-enable the peripheral */
+	rc = qpnp_adc_tm_enable(chip);
 	if (rc) {
-		pr_err("adc_tm channel check failed\n");
+		pr_err("adc-tm re-enable peripheral failed\n");
+		return rc;
+	}
+
+	/* The VADC_TM bank needs to be disabled for new conversion request */
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+	if (rc) {
+		pr_err("adc-tm read status1 failed\n");
+		return rc;
+	}
+
+	/* Disable the bank if a conversion is occurring */
+	while (status1 & QPNP_STATUS1_REQ_STS) {
+		if (count > QPNP_RETRY) {
+			pr_err("retry error=%d with 0x%x\n", count, status1);
+			break;
+		}
+		/*
+		 * Wait time is based on the optimum sampling rate
+		 * and adding enough time buffer to account for ADC conversions
+		 * occurring on different peripheral banks
+		 */
+		usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
+		rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1,
+							&status1, 1);
+		if (rc < 0) {
+			pr_err("adc-tm disable failed\n");
+			return rc;
+		}
+		count++;
+	}
+
+	if (!chip->adc_tm_hc) {
+		/* Change the mode back to recurring measurement mode */
+		mode_ctl = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+		rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+		if (rc < 0) {
+			pr_err("adc-tm mode change to recurring failed\n");
+			return rc;
+		}
+	}
+
+	/* Disable the peripheral */
+	rc = qpnp_adc_tm_disable(chip);
+	if (rc < 0) {
+		pr_err("adc-tm peripheral disable failed\n");
 		return rc;
 	}
 
@@ -337,17 +682,25 @@
 	int rc = 0, i;
 	bool chan_found = false;
 
-	for (i = 0; i < chip->max_channels_available; i++) {
-		if (chip->sensor[i].btm_channel_num == btm_chan) {
-			*btm_chan_idx = i;
-			chan_found = true;
-			break;
+	if (!chip->adc_tm_hc) {
+		for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+			if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+				*btm_chan_idx = i;
+				chan_found = true;
+			}
+		}
+	} else {
+		for (i = 0; i < chip->max_channels_available; i++) {
+			if (chip->sensor[i].btm_channel_num == btm_chan) {
+				*btm_chan_idx = i;
+				chan_found = true;
+				break;
+			}
 		}
 	}
 
 	if (!chan_found)
 		return -EINVAL;
-
 	return rc;
 }
 
@@ -412,19 +765,29 @@
 
 	switch (chip->sensor[chan_idx].timer_select) {
 	case ADC_MEAS_TIMER_SELECT1:
-		rc = qpnp_adc_tm_write_reg(chip,
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_write_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+				chip->sensor[chan_idx].meas_interval, 1);
+		else
+			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_BTM_MEAS_INTERVAL_CTL,
 				chip->sensor[chan_idx].meas_interval, 1);
 		if (rc < 0) {
 			pr_err("timer1 configure failed\n");
 			return rc;
 		}
-	break;
+		break;
 	case ADC_MEAS_TIMER_SELECT2:
 		/* Thermal channels uses timer2, default to 1 second */
-		rc = qpnp_adc_tm_read_reg(chip,
-				QPNP_BTM_MEAS_INTERVAL_CTL2,
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_read_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2, 1);
+		else
+			rc = qpnp_adc_tm_read_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2,
+					&meas_interval_timer2, 1);
 		if (rc < 0) {
 			pr_err("timer2 configure read failed\n");
 			return rc;
@@ -433,7 +796,12 @@
 		timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
 		timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
 		meas_interval_timer2 |= timer_interval_store;
-		rc = qpnp_adc_tm_write_reg(chip,
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_write_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+				meas_interval_timer2, 1);
+		else
+			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_BTM_MEAS_INTERVAL_CTL2,
 				meas_interval_timer2, 1);
 		if (rc < 0) {
@@ -442,7 +810,12 @@
 		}
 	break;
 	case ADC_MEAS_TIMER_SELECT3:
-		rc = qpnp_adc_tm_read_reg(chip,
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_read_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+				&meas_interval_timer2, 1);
+		else
+			rc = qpnp_adc_tm_read_reg(chip,
 				QPNP_BTM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2, 1);
 		if (rc < 0) {
@@ -452,6 +825,11 @@
 		timer_interval_store = chip->sensor[chan_idx].meas_interval;
 		timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
 		meas_interval_timer2 |= timer_interval_store;
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_write_reg(chip,
+				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+				meas_interval_timer2, 1);
+		else
 			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_BTM_MEAS_INTERVAL_CTL2,
 				meas_interval_timer2, 1);
@@ -471,7 +849,12 @@
 		pr_err("Invalid btm channel idx\n");
 		return rc;
 	}
-	rc = qpnp_adc_tm_write_reg(chip,
+	if (!chip->adc_tm_hc)
+		rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].meas_interval_ctl,
+				chip->sensor[chan_idx].timer_select, 1);
+	else
+		rc = qpnp_adc_tm_write_reg(chip,
 			QPNP_BTM_Mn_MEAS_INTERVAL_CTL(btm_chan_idx),
 			chip->sensor[chan_idx].timer_select, 1);
 	if (rc < 0) {
@@ -556,6 +939,69 @@
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
+			uint32_t btm_chan)
+{
+	int rc = 0;
+	u8 data_lsb = 0, data_msb = 0;
+	uint32_t btm_chan_idx = 0;
+	int32_t low_thr = 0, high_thr = 0;
+
+	if (!chip->adc_tm_hc) {
+		pr_err("Not applicable for VADC HC peripheral\n");
+		return -EINVAL;
+	}
+
+	rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip,
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			&data_lsb, 1);
+	if (rc < 0) {
+		pr_err("low threshold lsb setting failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip,
+		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+		&data_msb, 1);
+	if (rc < 0) {
+		pr_err("low threshold msb setting failed\n");
+		return rc;
+	}
+
+	low_thr = (data_msb << 8) | data_lsb;
+
+	rc = qpnp_adc_tm_read_reg(chip,
+		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+		&data_lsb, 1);
+	if (rc < 0) {
+		pr_err("high threshold lsb setting failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip,
+		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+		&data_msb, 1);
+	if (rc < 0) {
+		pr_err("high threshold msb setting failed\n");
+		return rc;
+	}
+
+	high_thr = (data_msb << 8) | data_lsb;
+
+	pr_debug("configured thresholds high:0x%x and low:0x%x\n",
+		high_thr, low_thr);
+
+	return rc;
+}
+
+
+
 static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
 			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
 {
@@ -568,38 +1014,71 @@
 		return rc;
 	}
 
-	rc = qpnp_adc_tm_write_reg(chip,
-		QPNP_BTM_Mn_LOW_THR0(btm_chan_idx),
-		QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
-	if (rc < 0) {
-		pr_err("low threshold lsb setting failed\n");
-		return rc;
-	}
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+		if (rc < 0) {
+			pr_err("low threshold lsb setting failed\n");
+			return rc;
+		}
 
-	rc = qpnp_adc_tm_write_reg(chip,
-		QPNP_BTM_Mn_LOW_THR1(btm_chan_idx),
-		QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
-	if (rc < 0) {
-		pr_err("low threshold msb setting failed\n");
-		return rc;
-	}
+		rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+			QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+		if (rc < 0) {
+			pr_err("low threshold msb setting failed\n");
+			return rc;
+		}
 
-	rc = qpnp_adc_tm_write_reg(chip,
-		QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx),
-		QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
-	if (rc < 0) {
-		pr_err("high threshold lsb setting failed\n");
-		return rc;
-	}
+		rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+		if (rc < 0) {
+			pr_err("high threshold lsb setting failed\n");
+			return rc;
+		}
 
-	rc = qpnp_adc_tm_write_reg(chip,
-		QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx),
-		QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
-	if (rc < 0)
-		pr_err("high threshold msb setting failed\n");
+		rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+			QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+		if (rc < 0)
+			pr_err("high threshold msb setting failed\n");
+	} else {
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_BTM_Mn_LOW_THR0(btm_chan_idx),
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+		if (rc < 0) {
+			pr_err("low threshold lsb setting failed\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_BTM_Mn_LOW_THR1(btm_chan_idx),
+			QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+		if (rc < 0) {
+			pr_err("low threshold msb setting failed\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx),
+			QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+		if (rc < 0) {
+			pr_err("high threshold lsb setting failed\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_write_reg(chip,
+			QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx),
+			QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+		if (rc < 0)
+			pr_err("high threshold msb setting failed\n");
+
+	}
 
 	pr_debug("client requested high:%d and low:%d\n",
-		high_thr, low_thr);
+			high_thr, low_thr);
 
 	return rc;
 }
@@ -734,9 +1213,14 @@
 			pr_debug("low sensor mask:%x with state:%d\n",
 					sensor_mask, chan_prop->state_request);
 			/* Enable low threshold's interrupt */
-			rc = qpnp_adc_tm_reg_update(chip,
-				QPNP_BTM_Mn_EN(btm_chan_idx),
-				QPNP_BTM_Mn_LOW_THR_INT_EN, true);
+			if (!chip->adc_tm_hc)
+				rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_ADC_TM_LOW_THR_INT_EN,
+					sensor_mask, true);
+			else
+				rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_BTM_Mn_EN(btm_chan_idx),
+					QPNP_BTM_Mn_LOW_THR_INT_EN, true);
 			if (rc < 0) {
 				pr_err("low thr enable err:%d\n", btm_chan);
 				return rc;
@@ -746,9 +1230,14 @@
 		if (high_thr_set) {
 			/* Enable high threshold's interrupt */
 			pr_debug("high sensor mask:%x\n", sensor_mask);
-			rc = qpnp_adc_tm_reg_update(chip,
-				QPNP_BTM_Mn_EN(btm_chan_idx),
-				QPNP_BTM_Mn_HIGH_THR_INT_EN, true);
+			if (!chip->adc_tm_hc)
+				rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_ADC_TM_HIGH_THR_INT_EN,
+					sensor_mask, true);
+			else
+				rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_BTM_Mn_EN(btm_chan_idx),
+					QPNP_BTM_Mn_HIGH_THR_INT_EN, true);
 			if (rc < 0) {
 				pr_err("high thr enable err:%d\n", btm_chan);
 				return rc;
@@ -757,13 +1246,16 @@
 	}
 
 	/* Enable corresponding BTM channel measurement */
-	rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_idx),
+	if (!chip->adc_tm_hc)
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
+	else
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_idx),
 			QPNP_BTM_Mn_MEAS_EN, true);
 	if (rc < 0) {
 		pr_err("multi measurement en failed\n");
 		return rc;
 	}
-
 	return rc;
 }
 
@@ -872,12 +1364,120 @@
 	return 0;
 }
 
+static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
+			struct qpnp_adc_amux_properties *chan_prop)
+{
+	u8 decimation = 0, op_cntrl = 0, mode_ctl = 0;
+	int rc = 0;
+	uint32_t btm_chan = 0;
+
+	/* Set measurement in single measurement mode */
+	mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+	rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+	if (rc < 0) {
+		pr_err("adc-tm single mode select failed\n");
+		return rc;
+	}
+
+	/* Disable bank */
+	rc = qpnp_adc_tm_disable(chip);
+	if (rc)
+		return rc;
+
+	/* Check if a conversion is in progress */
+	rc = qpnp_adc_tm_req_sts_check(chip);
+	if (rc < 0) {
+		pr_err("adc-tm req_sts check failed\n");
+		return rc;
+	}
+
+	/* Configure AMUX channel select for the corresponding BTM channel*/
+	btm_chan = chan_prop->chan_prop->tm_channel_select;
+	rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel, 1);
+	if (rc < 0) {
+		pr_err("adc-tm channel selection err\n");
+		return rc;
+	}
+
+	/* Digital parameter setup */
+	decimation |= chan_prop->decimation <<
+				QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation, 1);
+	if (rc < 0) {
+		pr_err("adc-tm digital parameter setup err\n");
+		return rc;
+	}
+
+	/* Hardware setting time */
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
+					chan_prop->hw_settle_time, 1);
+	if (rc < 0) {
+		pr_err("adc-tm hw settling time setup err\n");
+		return rc;
+	}
+
+	/* Fast averaging setup/enable */
+	rc = qpnp_adc_tm_fast_avg_en(chip, &chan_prop->fast_avg_setup);
+	if (rc < 0) {
+		pr_err("adc-tm fast-avg enable err\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
+				chan_prop->fast_avg_setup, 1);
+	if (rc < 0) {
+		pr_err("adc-tm fast-avg setup err\n");
+		return rc;
+	}
+
+	/* Measurement interval setup */
+	rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
+						chan_prop->chan_prop);
+	if (rc < 0) {
+		pr_err("adc-tm timer select failed\n");
+		return rc;
+	}
+
+	/* Channel configuration setup */
+	rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
+			chan_prop->chan_prop, chan_prop->amux_channel);
+	if (rc < 0) {
+		pr_err("adc-tm channel configure failed\n");
+		return rc;
+	}
+
+	/* Recurring interval measurement enable */
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+							&op_cntrl, 1);
+	op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
+	rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+			op_cntrl, true);
+	if (rc < 0) {
+		pr_err("adc-tm meas interval op configure failed\n");
+		return rc;
+	}
+
+	/* Enable bank */
+	rc = qpnp_adc_tm_enable(chip);
+	if (rc)
+		return rc;
+
+	/* Request conversion */
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET, 1);
+	if (rc < 0) {
+		pr_err("adc-tm request conversion failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static int qpnp_adc_tm_set_mode(struct qpnp_adc_tm_sensor *adc_tm,
 			      enum thermal_device_mode mode)
 {
 	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 	int rc = 0, channel;
-	u8 sensor_mask = 0;
+	u8 sensor_mask = 0, mode_ctl = 0;
 	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip)) {
@@ -916,13 +1516,30 @@
 		chip->adc->amux_prop->calib_type =
 			chip->adc->adc_channels[channel].calib_type;
 
-		rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
-		if (rc) {
-			pr_err("hc configure failed with %d\n", rc);
-			goto fail;
+		if (!chip->adc_tm_hc) {
+			rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+			if (rc) {
+				pr_err("adc-tm configure failed with %d\n", rc);
+				goto fail;
+			}
+		} else {
+			rc = qpnp_adc_tm_hc_configure(chip,
+					chip->adc->amux_prop);
+			if (rc) {
+				pr_err("hc configure failed with %d\n", rc);
+				goto fail;
+			}
 		}
 	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		sensor_mask = 1 << adc_tm->sensor_num;
+		if (!chip->adc_tm_hc) {
+			mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+			rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+			if (rc < 0) {
+				pr_err("adc-tm single mode select failed\n");
+				goto fail;
+			}
+		}
 
 		/* Disable bank */
 		rc = qpnp_adc_tm_disable(chip);
@@ -931,12 +1548,28 @@
 			goto fail;
 		}
 
-		rc = qpnp_adc_tm_reg_update(chip,
-			QPNP_BTM_Mn_EN(btm_chan_idx),
-			QPNP_BTM_Mn_MEAS_EN, false);
-		if (rc < 0) {
-			pr_err("multi measurement disable failed\n");
-			goto fail;
+		if (!chip->adc_tm_hc) {
+			/* Check if a conversion is in progress */
+			rc = qpnp_adc_tm_req_sts_check(chip);
+			if (rc < 0) {
+				pr_err("adc-tm req_sts check failed\n");
+				goto fail;
+			}
+			rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_ADC_TM_MULTI_MEAS_EN,
+					sensor_mask, false);
+			if (rc < 0) {
+				pr_err("multi measurement update failed\n");
+				goto fail;
+			}
+		} else {
+			rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_BTM_Mn_EN(btm_chan_idx),
+					QPNP_BTM_Mn_MEAS_EN, false);
+			if (rc < 0) {
+				pr_err("multi measurement disable failed\n");
+				goto fail;
+			}
 		}
 
 		rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -959,6 +1592,7 @@
 {
 	struct qpnp_adc_tm_chip *chip = adc_tm->chip;
 	int rc = 0, sensor_mask = 0;
+	u8 thr_int_en = 0;
 	bool state = false;
 	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
@@ -986,17 +1620,29 @@
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		/* low_thr (lower voltage) for higher temp */
-		rc = qpnp_adc_tm_reg_update(chip,
-			QPNP_BTM_Mn_EN(btm_chan_idx),
-			QPNP_BTM_Mn_LOW_THR_INT_EN, state);
+		thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_reg_update(chip,
+					QPNP_ADC_TM_LOW_THR_INT_EN,
+					sensor_mask, state);
+		else
+			rc = qpnp_adc_tm_reg_update(chip,
+				QPNP_BTM_Mn_EN(btm_chan_idx),
+				QPNP_BTM_Mn_LOW_THR_INT_EN, state);
 		if (rc)
 			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
 		/* high_thr (higher voltage) for cooler temp */
-		rc = qpnp_adc_tm_reg_update(chip,
-			QPNP_BTM_Mn_EN(btm_chan_idx),
-			QPNP_BTM_Mn_HIGH_THR_INT_EN, state);
+		thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
+		if (!chip->adc_tm_hc)
+			rc = qpnp_adc_tm_reg_update(chip,
+				QPNP_ADC_TM_HIGH_THR_INT_EN,
+				sensor_mask, state);
+		else
+			rc = qpnp_adc_tm_reg_update(chip,
+				QPNP_BTM_Mn_EN(btm_chan_idx),
+				QPNP_BTM_Mn_HIGH_THR_INT_EN, state);
 		if (rc)
 			pr_err("channel:%x failed\n", btm_chan);
 	break;
@@ -1060,10 +1706,17 @@
 		return rc;
 	}
 
-	reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
-	reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
-	reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
-	reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+	if (!chip->adc_tm_hc) {
+		reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+		reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+		reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+		reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+	} else {
+		reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
+		reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
+		reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
+		reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+	}
 
 	if (high_temp != INT_MAX) {
 		rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
@@ -1222,6 +1875,144 @@
 	atomic_dec(&chip->wq_cnt);
 }
 
+static int qpnp_adc_tm_recalib_request_check(struct qpnp_adc_tm_chip *chip,
+			int sensor_num, u8 status_high, u8 *notify_check)
+{
+	int rc = 0;
+	u8 sensor_mask = 0, mode_ctl = 0;
+	int32_t old_thr = 0, new_thr = 0;
+	uint32_t channel, btm_chan_num, scale_type;
+	struct qpnp_vadc_result result;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
+	bool status = false;
+
+	if (!chip->adc_tm_recalib_check) {
+		*notify_check = 1;
+		return rc;
+	}
+
+	list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+		client_info = list_entry(thr_list,
+				struct qpnp_adc_thr_client_info, list);
+		channel = client_info->btm_param->channel;
+		btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
+		sensor_mask = 1 << sensor_num;
+
+		rc = qpnp_vadc_read(chip->vadc_dev, channel, &result);
+		if (rc < 0) {
+			pr_err("failure to read vadc channel=%d\n",
+					client_info->btm_param->channel);
+			goto fail;
+		}
+		new_thr = result.physical;
+
+		if (status_high)
+			old_thr = client_info->btm_param->high_thr;
+		else
+			old_thr = client_info->btm_param->low_thr;
+
+		if (new_thr > old_thr)
+			status = (status_high) ? true : false;
+		else
+			status = (status_high) ? false : true;
+
+		pr_debug(
+			"recalib:sen=%d, new_thr=%d, new_thr_adc_code=0x%x, old_thr=%d status=%d valid_status=%d\n",
+			sensor_num, new_thr, result.adc_code,
+			old_thr, status_high, status);
+
+		rc = qpnp_adc_tm_read_thr_value(chip, btm_chan_num);
+		if (rc < 0) {
+			pr_err("adc-tm thresholds read failed\n");
+			goto fail;
+		}
+
+		if (status) {
+			*notify_check = 1;
+			pr_debug("Client can be notify\n");
+			return rc;
+		}
+
+		pr_debug("Client can not be notify, restart measurement\n");
+		/* Set measurement in single measurement mode */
+		mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+		rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+		if (rc < 0) {
+			pr_err("adc-tm single mode select failed\n");
+			goto fail;
+		}
+
+		/* Disable bank */
+		rc = qpnp_adc_tm_disable(chip);
+		if (rc < 0) {
+			pr_err("adc-tm disable failed\n");
+			goto fail;
+		}
+
+		/* Check if a conversion is in progress */
+		rc = qpnp_adc_tm_req_sts_check(chip);
+		if (rc < 0) {
+			pr_err("adc-tm req_sts check failed\n");
+			goto fail;
+		}
+
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+							sensor_mask, false);
+		if (rc < 0) {
+			pr_err("low threshold int write failed\n");
+			goto fail;
+		}
+
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+							sensor_mask, false);
+		if (rc < 0) {
+			pr_err("high threshold int enable failed\n");
+			goto fail;
+		}
+
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+							sensor_mask, false);
+		if (rc < 0) {
+			pr_err("multi measurement en failed\n");
+			goto fail;
+		}
+
+		/* restart measurement */
+		scale_type = chip->sensor[sensor_num].scale_type;
+		chip->adc->amux_prop->amux_channel = channel;
+		chip->adc->amux_prop->decimation =
+			chip->adc->adc_channels[sensor_num].adc_decimation;
+		chip->adc->amux_prop->hw_settle_time =
+			chip->adc->adc_channels[sensor_num].hw_settle_time;
+		chip->adc->amux_prop->fast_avg_setup =
+			chip->adc->adc_channels[sensor_num].fast_avg_setup;
+		chip->adc->amux_prop->mode_sel =
+			ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+		adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev,
+				client_info->btm_param,
+				&chip->adc->amux_prop->chan_prop->low_thr,
+				&chip->adc->amux_prop->chan_prop->high_thr);
+		qpnp_adc_tm_add_to_list(chip, sensor_num,
+				client_info->btm_param,
+				chip->adc->amux_prop->chan_prop);
+		chip->adc->amux_prop->chan_prop->tm_channel_select =
+				chip->sensor[sensor_num].btm_channel_num;
+		chip->adc->amux_prop->chan_prop->state_request =
+				client_info->btm_param->state_request;
+
+		rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+		if (rc) {
+			pr_err("adc-tm configure failed with %d\n", rc);
+			goto fail;
+		}
+		*notify_check = 0;
+		pr_debug("BTM channel reconfigured for measuremnt\n");
+	}
+fail:
+	return rc;
+}
+
 static int qpnp_adc_tm_disable_rearm_high_thresholds(
 			struct qpnp_adc_tm_chip *chip, int sensor_num)
 {
@@ -1229,7 +2020,7 @@
 	struct qpnp_adc_thr_client_info *client_info = NULL;
 	struct list_head *thr_list;
 	uint32_t btm_chan_num = 0, btm_chan_idx = 0;
-	u8 sensor_mask = 0;
+	u8 sensor_mask = 0, notify_check = 0;
 	int rc = 0;
 
 	btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
@@ -1250,14 +2041,24 @@
 		 */
 		sensor_mask = 1 << sensor_num;
 		pr_debug("non thermal node - mask:%x\n", sensor_mask);
-		rc = qpnp_adc_tm_reg_update(chip,
-			QPNP_BTM_Mn_EN(btm_chan_idx),
-			QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
-		if (rc < 0) {
-			pr_err("high threshold int update failed\n");
-			return rc;
+		if (!chip->adc_tm_hc) {
+			rc = qpnp_adc_tm_recalib_request_check(chip,
+					sensor_num, true, &notify_check);
+			if (rc < 0 || !notify_check) {
+				pr_debug("Calib recheck re-armed rc=%d\n", rc);
+				chip->th_info.adc_tm_high_enable = 0;
+				return rc;
+			}
+		} else {
+			rc = qpnp_adc_tm_reg_update(chip,
+				QPNP_BTM_Mn_EN(btm_chan_idx),
+				QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+			if (rc < 0) {
+				pr_err("high threshold int update failed\n");
+				return rc;
+			}
 		}
-	} else {
+		} else {
 		/*
 		 * Uses the thermal sysfs registered device to disable
 		 * the corresponding high voltage threshold which
@@ -1291,12 +2092,22 @@
 	}
 	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
 
-	rc = qpnp_adc_tm_reg_update(chip,
-		QPNP_BTM_Mn_EN(sensor_num),
-		QPNP_BTM_Mn_MEAS_EN, false);
-	if (rc < 0) {
-		pr_err("multi meas disable failed\n");
-		return rc;
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_MULTI_MEAS_EN,
+			sensor_mask, false);
+		if (rc < 0) {
+			pr_err("multi meas disable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_BTM_Mn_EN(sensor_num),
+			QPNP_BTM_Mn_MEAS_EN, false);
+		if (rc < 0) {
+			pr_err("multi meas disable failed\n");
+			return rc;
+		}
 	}
 
 	rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1320,7 +2131,7 @@
 	struct qpnp_adc_thr_client_info *client_info = NULL;
 	struct list_head *thr_list;
 	uint32_t btm_chan_num = 0, btm_chan_idx = 0;
-	u8 sensor_mask = 0;
+	u8 sensor_mask = 0, notify_check = 0;
 	int rc = 0;
 
 	btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
@@ -1341,12 +2152,22 @@
 		 */
 		sensor_mask = 1 << sensor_num;
 		pr_debug("non thermal node - mask:%x\n", sensor_mask);
-		rc = qpnp_adc_tm_reg_update(chip,
-			QPNP_BTM_Mn_EN(btm_chan_idx),
-			QPNP_BTM_Mn_LOW_THR_INT_EN, false);
-		if (rc < 0) {
-			pr_err("low threshold int update failed\n");
-			return rc;
+		if (!chip->adc_tm_hc) {
+			rc = qpnp_adc_tm_recalib_request_check(chip,
+					sensor_num, false, &notify_check);
+			if (rc < 0 || !notify_check) {
+				pr_debug("Calib recheck re-armed rc=%d\n", rc);
+				chip->th_info.adc_tm_low_enable = 0;
+				return rc;
+			}
+		} else {
+			rc = qpnp_adc_tm_reg_update(chip,
+				QPNP_BTM_Mn_EN(btm_chan_idx),
+				QPNP_BTM_Mn_LOW_THR_INT_EN, false);
+			if (rc < 0) {
+				pr_err("low threshold int update failed\n");
+				return rc;
+			}
 		}
 	} else {
 		/*
@@ -1382,12 +2203,22 @@
 	}
 	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
 
-	rc = qpnp_adc_tm_reg_update(chip,
-		QPNP_BTM_Mn_EN(sensor_num),
-		QPNP_BTM_Mn_MEAS_EN, false);
-	if (rc < 0) {
-		pr_err("multi meas disable failed\n");
-		return rc;
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_MULTI_MEAS_EN,
+			sensor_mask, false);
+		if (rc < 0) {
+			pr_err("multi meas disable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_BTM_Mn_EN(sensor_num),
+			QPNP_BTM_Mn_MEAS_EN, false);
+		if (rc < 0) {
+			pr_err("multi meas disable failed\n");
+			return rc;
+		}
 	}
 
 	rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1416,6 +2247,13 @@
 
 	mutex_lock(&chip->adc->adc_lock);
 
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_req_sts_check(chip);
+		if (rc) {
+			pr_err("adc-tm-tm req sts check failed with %d\n", rc);
+			goto fail;
+		}
+	}
 	while (sensor_num < chip->max_channels_available) {
 		if (chip->sensor[sensor_num].high_thr_triggered) {
 			rc = qpnp_adc_tm_disable_rearm_high_thresholds(
@@ -1473,6 +2311,92 @@
 		pr_err("adc-tm high thr work failed\n");
 }
 
+static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
+{
+	struct qpnp_adc_tm_chip *chip = data;
+	u8 mode_ctl = 0, status1 = 0, sensor_mask = 0;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+
+	mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+	/* Set measurement in single measurement mode */
+	qpnp_adc_tm_mode_select(chip, mode_ctl);
+
+	qpnp_adc_tm_disable(chip);
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+	if (rc) {
+		pr_err("adc-tm read status1 failed\n");
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH,
+					&chip->th_info.status_high, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read status high failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+				&chip->th_info.adc_tm_high_thr_set, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read high thr failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	/* Check which interrupt threshold is lower and measure against the
+	 * enabled channel
+	 */
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+				&chip->th_info.qpnp_adc_tm_meas_en, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read status high failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	chip->th_info.adc_tm_high_enable = chip->th_info.qpnp_adc_tm_meas_en &
+						chip->th_info.status_high;
+	chip->th_info.adc_tm_high_enable &= chip->th_info.adc_tm_high_thr_set;
+
+	sensor_notify_num = chip->th_info.adc_tm_high_enable;
+	while (i < chip->max_channels_available) {
+		if ((sensor_notify_num & 0x1) == 1)
+			sensor_num = i;
+		sensor_notify_num >>= 1;
+		i++;
+	}
+
+	if (!chip->sensor[sensor_num].thermal_node) {
+		sensor_mask = 1 << sensor_num;
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_HIGH_THR_INT_EN,
+			sensor_mask, false);
+		if (rc < 0) {
+			pr_err("high threshold int read failed\n");
+			return IRQ_HANDLED;
+		}
+	} else {
+		/*
+		 * Uses the thermal sysfs registered device to disable
+		 * the corresponding high voltage threshold which
+		 * is triggered by low temp
+		 */
+		pr_debug("thermal node with mask:%x\n", sensor_mask);
+		rc = qpnp_adc_tm_activate_trip_type(
+			&chip->sensor[sensor_num],
+			ADC_TM_TRIP_LOW_COOL,
+			THERMAL_TRIP_ACTIVATION_DISABLED);
+		if (rc < 0) {
+			pr_err("notify error:%d\n", sensor_num);
+			return IRQ_HANDLED;
+		}
+	}
+
+	atomic_inc(&chip->wq_cnt);
+	queue_work(chip->high_thr_wq, &chip->trigger_high_thr_work);
+
+	return IRQ_HANDLED;
+}
+
 static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
 {
 	struct qpnp_adc_tm_chip *chip = container_of(work,
@@ -1493,6 +2417,89 @@
 		pr_err("adc-tm low thr work failed\n");
 }
 
+static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
+{
+	struct qpnp_adc_tm_chip *chip = data;
+	u8 mode_ctl = 0, status1 = 0, sensor_mask = 0;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+
+	mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+	/* Set measurement in single measurement mode */
+	qpnp_adc_tm_mode_select(chip, mode_ctl);
+
+	qpnp_adc_tm_disable(chip);
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
+	if (rc) {
+		pr_err("adc-tm read status1 failed\n");
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW,
+					&chip->th_info.status_low, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read status low failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+				&chip->th_info.adc_tm_low_thr_set, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+				&chip->th_info.qpnp_adc_tm_meas_en, 1);
+	if (rc) {
+		pr_err("adc-tm-tm read status high failed with %d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	chip->th_info.adc_tm_low_enable = chip->th_info.qpnp_adc_tm_meas_en &
+					chip->th_info.status_low;
+	chip->th_info.adc_tm_low_enable &= chip->th_info.adc_tm_low_thr_set;
+
+	sensor_notify_num = chip->th_info.adc_tm_low_enable;
+	while (i < chip->max_channels_available) {
+		if ((sensor_notify_num & 0x1) == 1)
+			sensor_num = i;
+		sensor_notify_num >>= 1;
+		i++;
+	}
+
+	if (!chip->sensor[sensor_num].thermal_node) {
+		sensor_mask = 1 << sensor_num;
+		rc = qpnp_adc_tm_reg_update(chip,
+			QPNP_ADC_TM_LOW_THR_INT_EN,
+			sensor_mask, false);
+		if (rc < 0) {
+			pr_err("low threshold int read failed\n");
+			return IRQ_HANDLED;
+		}
+	} else {
+		/*
+		 * Uses the thermal sysfs registered device to disable
+		 * the corresponding low voltage threshold which
+		 * is triggered by high temp
+		 */
+		pr_debug("thermal node with mask:%x\n", sensor_mask);
+		rc = qpnp_adc_tm_activate_trip_type(
+			&chip->sensor[sensor_num],
+			ADC_TM_TRIP_HIGH_WARM,
+			THERMAL_TRIP_ACTIVATION_DISABLED);
+		if (rc < 0) {
+			pr_err("notify error:%d\n", sensor_num);
+			return IRQ_HANDLED;
+		}
+	}
+
+	atomic_inc(&chip->wq_cnt);
+	queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work);
+
+	return IRQ_HANDLED;
+}
+
 static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
 			u8 status_low, u8 status_high, int i,
 			int *sensor_low_notify_num, int *sensor_high_notify_num)
@@ -1743,11 +2750,18 @@
 					param->state_request;
 	chip->adc->amux_prop->calib_type =
 			chip->adc->adc_channels[dt_index].calib_type;
-
-	rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
-	if (rc) {
-		pr_err("adc-tm hc configure failed with %d\n", rc);
-		goto fail_unlock;
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+		if (rc) {
+			pr_err("adc-tm configure failed with %d\n", rc);
+			goto fail_unlock;
+		}
+	} else {
+		rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
+		if (rc) {
+			pr_err("adc-tm hc configure failed with %d\n", rc);
+			goto fail_unlock;
+		}
 	}
 
 	chip->sensor[dt_index].scale_type = scale_type;
@@ -1763,6 +2777,7 @@
 					struct qpnp_adc_tm_btm_param *param)
 {
 	uint32_t channel, dt_index = 0, btm_chan_num;
+	u8 sensor_mask = 0, mode_ctl = 0;
 	int rc = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
@@ -1770,6 +2785,16 @@
 
 	mutex_lock(&chip->adc->adc_lock);
 
+	if (!chip->adc_tm_hc) {
+		/* Set measurement in single measurement mode */
+		mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT;
+		rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+		if (rc < 0) {
+			pr_err("adc-tm single mode select failed\n");
+			goto fail;
+		}
+	}
+
 	/* Disable bank */
 	rc = qpnp_adc_tm_disable(chip);
 	if (rc < 0) {
@@ -1777,6 +2802,15 @@
 		goto fail;
 	}
 
+	if (!chip->adc_tm_hc) {
+		/* Check if a conversion is in progress */
+		rc = qpnp_adc_tm_req_sts_check(chip);
+		if (rc < 0) {
+			pr_err("adc-tm req_sts check failed\n");
+			goto fail;
+		}
+	}
+
 	channel = param->channel;
 	while ((chip->adc->adc_channels[dt_index].channel_num
 		!= channel) && (dt_index < chip->max_channels_available))
@@ -1790,25 +2824,43 @@
 
 	btm_chan_num = chip->sensor[dt_index].btm_channel_num;
 
-	rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
-				QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
-	if (rc < 0) {
-		pr_err("high thr disable err:%d\n", btm_chan_num);
-		return rc;
-	}
+	if (!chip->adc_tm_hc) {
+		sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
 
-	rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+				sensor_mask, false);
+		if (rc < 0) {
+			pr_err("high threshold int enable failed\n");
+			goto fail;
+		}
+
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+				sensor_mask, false);
+		if (rc < 0) {
+			pr_err("multi measurement en failed\n");
+			goto fail;
+		}
+	} else {
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+					QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+		if (rc < 0) {
+			pr_err("high thr disable err:%d\n", btm_chan_num);
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
 				QPNP_BTM_Mn_LOW_THR_INT_EN, false);
-	if (rc < 0) {
-		pr_err("low thr disable err:%d\n", btm_chan_num);
-		return rc;
-	}
+		if (rc < 0) {
+			pr_err("low thr disable err:%d\n", btm_chan_num);
+			return rc;
+		}
 
-	rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+		rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
 				QPNP_BTM_Mn_MEAS_EN, false);
-	if (rc < 0) {
-		pr_err("multi measurement disable failed\n");
-		return rc;
+		if (rc < 0) {
+			pr_err("multi measurement disable failed\n");
+			return rc;
+		}
 	}
 
 	rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1842,6 +2894,35 @@
 }
 EXPORT_SYMBOL(qpnp_get_adc_tm);
 
+static int qpnp_adc_tm_initial_setup(struct qpnp_adc_tm_chip *chip)
+{
+	u8 thr_init = 0;
+	int rc = 0;
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+							thr_init, 1);
+	if (rc < 0) {
+		pr_err("high thr init failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+			thr_init, 1);
+	if (rc < 0) {
+		pr_err("low thr init failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+							thr_init, 1);
+	if (rc < 0) {
+		pr_err("multi meas en failed\n");
+		return rc;
+	}
+
+	return rc;
+}
+
 static const struct of_device_id qpnp_adc_tm_match_table[] = {
 	{	.compatible = "qcom,qpnp-adc-tm" },
 	{	.compatible = "qcom,qpnp-adc-tm-hc" },
@@ -1894,8 +2975,10 @@
 		goto fail;
 	}
 
-	chip->adc_tm_hc = true;
-	chip->adc->adc_hc = true;
+	if (of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc")) {
+		chip->adc_tm_hc = true;
+		chip->adc->adc_hc = true;
+	}
 
 	rc = qpnp_adc_get_devicetree_data(pdev, chip->adc);
 	if (rc) {
@@ -1904,6 +2987,24 @@
 	}
 	mutex_init(&chip->adc->adc_lock);
 
+	/* Register the ADC peripheral interrupt */
+	if (!chip->adc_tm_hc) {
+		chip->adc->adc_high_thr_irq = platform_get_irq_byname(pdev,
+				"high-thr-en-set");
+		if (chip->adc->adc_high_thr_irq < 0) {
+			pr_err("Invalid irq\n");
+			rc = -ENXIO;
+			goto fail;
+		}
+
+		chip->adc->adc_low_thr_irq = platform_get_irq_byname(pdev,
+				"low-thr-en-set");
+		if (chip->adc->adc_low_thr_irq < 0) {
+			pr_err("Invalid irq\n");
+			rc = -ENXIO;
+			goto fail;
+		}
+	}
 	chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "adc_tm");
 	if (IS_ERR(chip->vadc_dev)) {
 		rc = PTR_ERR(chip->vadc_dev);
@@ -2016,17 +3117,45 @@
 	INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
 	atomic_set(&chip->wq_cnt, 0);
 
-	rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
-			qpnp_adc_tm_rc_thr_isr,
-		IRQF_TRIGGER_HIGH, "qpnp_adc_tm_interrupt", chip);
-	if (rc)
-		dev_err(&pdev->dev, "failed to request adc irq\n");
-	else
-		enable_irq_wake(chip->adc->adc_irq_eoc);
+	if (!chip->adc_tm_hc) {
+		rc = qpnp_adc_tm_initial_setup(chip);
+		if (rc)
+			goto fail;
+		rc = devm_request_irq(&pdev->dev, chip->adc->adc_high_thr_irq,
+				qpnp_adc_tm_high_thr_isr,
+		IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to request adc irq\n");
+			goto fail;
+		} else {
+			enable_irq_wake(chip->adc->adc_high_thr_irq);
+		}
+
+		rc = devm_request_irq(&pdev->dev, chip->adc->adc_low_thr_irq,
+				qpnp_adc_tm_low_thr_isr,
+				IRQF_TRIGGER_RISING,
+				"qpnp_adc_tm_low_interrupt", chip);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to request adc irq\n");
+			goto fail;
+		} else {
+			enable_irq_wake(chip->adc->adc_low_thr_irq);
+		}
+	} else {
+		rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
+				qpnp_adc_tm_rc_thr_isr,
+			IRQF_TRIGGER_HIGH, "qpnp_adc_tm_interrupt", chip);
+		if (rc)
+			dev_err(&pdev->dev, "failed to request adc irq\n");
+		else
+			enable_irq_wake(chip->adc->adc_irq_eoc);
+	}
 
 	chip->adc_vote_enable = false;
 	dev_set_drvdata(&pdev->dev, chip);
 	list_add(&chip->list, &qpnp_adc_tm_device_list);
+	spin_lock_init(&chip->th_info.adc_tm_low_lock);
+	spin_lock_init(&chip->th_info.adc_tm_high_lock);
 
 	pr_debug("OK\n");
 	return 0;
diff --git a/drivers/thermal/tsens-mtc.c b/drivers/thermal/tsens-mtc.c
index 529503f..451c6c7 100644
--- a/drivers/thermal/tsens-mtc.c
+++ b/drivers/thermal/tsens-mtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,7 @@
 }
 EXPORT_SYMBOL(tsens_controller_is_present);
 
-static int tsens_mtc_reset_history_counter(unsigned int zone)
+int tsens_mtc_reset_history_counter(unsigned int zone)
 {
 	unsigned int reg_cntl, is_valid;
 	void __iomem *sensor_addr;
diff --git a/drivers/thermal/tsens-mtc.h b/drivers/thermal/tsens-mtc.h
index 979513f..8782728 100644
--- a/drivers/thermal/tsens-mtc.h
+++ b/drivers/thermal/tsens-mtc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -57,3 +57,4 @@
 extern int tsens_set_mtc_zone_sw_mask(unsigned int zone,
 			unsigned int th1_enable, unsigned int th2_enable);
 extern int tsens_get_mtc_zone_log(unsigned int zone, void *zone_log);
+extern int tsens_mtc_reset_history_counter(unsigned int zone);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ae4741d..885b15c 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,10 +23,15 @@
 
 #define DEBUG_SIZE				10
 #define TSENS_MAX_SENSORS			16
+#define TSENS_1x_MAX_SENSORS			11
 #define TSENS_CONTROLLER_ID(n)			(n)
 #define TSENS_CTRL_ADDR(n)			(n)
 #define TSENS_TM_SN_STATUS(n)			((n) + 0xa0)
 
+#define ONE_PT_CALIB		0x1
+#define ONE_PT_CALIB2		0x2
+#define TWO_PT_CALIB		0x3
+
 enum tsens_dbg_type {
 	TSENS_DBG_POLL,
 	TSENS_DBG_LOG_TEMP_READS,
@@ -70,6 +75,8 @@
 	int				high_temp;
 	int				low_temp;
 	int				crit_temp;
+	int				high_adc_code;
+	int				low_adc_code;
 };
 
 struct tsens_sensor {
@@ -79,6 +86,8 @@
 	u32				id;
 	const char			*sensor_name;
 	struct tsens_context		thr_state;
+	int				offset;
+	int				slope;
 };
 
 /**
@@ -93,6 +102,7 @@
 	int (*interrupts_reg)(struct tsens_device *);
 	int (*dbg)(struct tsens_device *, u32, u32, int *);
 	int (*sensor_en)(struct tsens_device *, u32);
+	int (*calibrate)(struct tsens_device *);
 };
 
 struct tsens_irqs {
@@ -116,14 +126,15 @@
 	bool				wd_bark;
 	u32				wd_bark_mask;
 	bool				mtc;
+	bool				valid_status_check;
 };
 
 struct tsens_mtc_sysfs {
-	uint32_t	zone_log;
+	u32			zone_log;
 	int			zone_mtc;
 	int			th1;
 	int			th2;
-	uint32_t	zone_hist;
+	u32			zone_hist;
 };
 
 struct tsens_device {
@@ -134,6 +145,7 @@
 	struct regmap_field		*status_field;
 	void __iomem			*tsens_srot_addr;
 	void __iomem			*tsens_tm_addr;
+	void __iomem			*tsens_calib_addr;
 	const struct tsens_ops		*ops;
 	struct tsens_dbg_context	tsens_dbg;
 	spinlock_t			tsens_crit_lock;
@@ -144,6 +156,7 @@
 };
 
 extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern const struct tsens_data data_tsens14xx;
 extern struct list_head tsens_device_list;
 
 #endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
new file mode 100644
index 0000000..0ea4a46
--- /dev/null
+++ b/drivers/thermal/tsens1xxx.c
@@ -0,0 +1,658 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+#include "thermal_core.h"
+
+#define TSENS_DRIVER_NAME			"msm-tsens"
+
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n)		(n)
+#define TSENS_INTERRUPT_EN		BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n)	((n) + 0x04)
+#define TSENS_UPPER_STATUS_CLR		BIT(21)
+#define TSENS_LOWER_STATUS_CLR		BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK	0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK	0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT	10
+
+#define TSENS_S0_STATUS_ADDR(n)		((n) + 0x30)
+#define TSENS_SN_ADDR_OFFSET		0x4
+#define TSENS_SN_STATUS_TEMP_MASK	0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS	BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS	BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET			2
+
+#define TSENS_TRDY_MASK			BIT(0)
+
+#define TSENS_SN_STATUS_ADDR(n)	((n) + 0x44)
+#define TSENS_SN_STATUS_VALID		BIT(14)
+#define TSENS_SN_STATUS_VALID_MASK	0x4000
+#define TSENS_TRDY_ADDR(n)		((n) + 0x84)
+
+#define TSENS_CTRL_ADDR(n)		(n)
+#define TSENS_EN				BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0x7ff)
+#define TSENS_TRDY_RDY_MIN_TIME		2000
+#define TSENS_TRDY_RDY_MAX_TIME		2100
+#define TSENS_THRESHOLD_MAX_CODE	0x3ff
+#define TSENS_THRESHOLD_MIN_CODE	0x0
+#define TSENS_SCALE_MILLIDEG		1000
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK	0x000000ff
+#define BASE1_MASK	0xff000000
+#define BASE1_SHIFT	24
+
+#define S0_P1_MASK		0x000001f8
+#define S1_P1_MASK		0x001f8000
+#define S2_P1_MASK_0_4		0xf8000000
+#define S2_P1_MASK_5		0x00000001
+#define S3_P1_MASK		0x00001f80
+#define S4_P1_MASK		0x01f80000
+#define S5_P1_MASK		0x00003f00
+#define S6_P1_MASK		0x03f00000
+#define S7_P1_MASK		0x0000003f
+#define S8_P1_MASK		0x0003f000
+#define S9_P1_MASK		0x0000003f
+#define S10_P1_MASK		0x0003f000
+
+#define S0_P2_MASK		0x00007e00
+#define S1_P2_MASK		0x07e00000
+#define S2_P2_MASK		0x0000007e
+#define S3_P2_MASK		0x0007e000
+#define S4_P2_MASK		0x7e000000
+#define S5_P2_MASK		0x000fc000
+#define S6_P2_MASK		0xfc000000
+#define S7_P2_MASK		0x00000fc0
+#define S8_P2_MASK		0x00fc0000
+#define S9_P2_MASK		0x00000fc0
+#define S10_P2_MASK		0x00fc0000
+
+#define S0_P1_SHIFT     3
+#define S1_P1_SHIFT     15
+#define S2_P1_SHIFT_0_4 27
+#define S2_P1_SHIFT_5   5
+#define S3_P1_SHIFT     7
+#define S4_P1_SHIFT     19
+#define S5_P1_SHIFT     8
+#define S6_P1_SHIFT     20
+#define S8_P1_SHIFT     12
+#define S10_P1_SHIFT    12
+
+#define S0_P2_SHIFT     9
+#define S1_P2_SHIFT     21
+#define S2_P2_SHIFT     1
+#define S3_P2_SHIFT     13
+#define S4_P2_SHIFT     25
+#define S5_P2_SHIFT     14
+#define S6_P2_SHIFT     26
+#define S7_P2_SHIFT     6
+#define S8_P2_SHIFT     18
+#define S9_P2_SHIFT     6
+#define S10_P2_SHIFT    18
+
+#define CAL_SEL_MASK	0x00000007
+
+#define CAL_DEGC_PT1		30
+#define CAL_DEGC_PT2		120
+#define SLOPE_FACTOR		1000
+#define SLOPE_DEFAULT		3200
+
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+			     u32 *p2, u32 mode)
+{
+	int i;
+	int num, den;
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		pr_debug(
+			"sensor%d - data_point1:%#x data_point2:%#x\n",
+			i, p1[i], p2[i]);
+
+		tmdev->sensor[i].slope = SLOPE_DEFAULT;
+		if (mode == TWO_PT_CALIB) {
+			/*
+			 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+			 *	temp_120_degc - temp_30_degc (x2 - x1)
+			 */
+			num = p2[i] - p1[i];
+			num *= SLOPE_FACTOR;
+			den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+			tmdev->sensor[i].slope = num / den;
+		}
+
+		tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+				(CAL_DEGC_PT1 *
+				tmdev->sensor[i].slope);
+		pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+	}
+}
+
+static int code_to_degc(u32 adc_code, const struct tsens_sensor *sensor)
+{
+	int degc, num, den;
+
+	num = (adc_code * SLOPE_FACTOR) - sensor->offset;
+	den = sensor->slope;
+
+	if (num > 0)
+		degc = num + (den / 2);
+	else if (num < 0)
+		degc = num - (den / 2);
+	else
+		degc = num;
+
+	degc /= den;
+
+	return degc;
+}
+
+static int degc_to_code(int degc, const struct tsens_sensor *sensor)
+{
+	int code = ((degc * sensor->slope)
+		+ sensor->offset)/SLOPE_FACTOR;
+
+	if (code > TSENS_THRESHOLD_MAX_CODE)
+		code = TSENS_THRESHOLD_MAX_CODE;
+	else if (code < TSENS_THRESHOLD_MIN_CODE)
+		code = TSENS_THRESHOLD_MIN_CODE;
+	pr_debug("raw_code:0x%x, degc:%d\n",
+			code, degc);
+	return code;
+}
+
+static int calibrate_8937(struct tsens_device *tmdev)
+{
+	int base0 = 0, base1 = 0, i;
+	u32 p1[TSENS_1x_MAX_SENSORS], p2[TSENS_1x_MAX_SENSORS];
+	int mode = 0, tmp = 0;
+	u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+	qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+	qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+	qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+	qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+	qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+	mode = (qfprom_cdata[2] & CAL_SEL_MASK);
+	pr_debug("calibration mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
+		p2[0] = (qfprom_cdata[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+		p2[1] = (qfprom_cdata[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+		p2[2] = (qfprom_cdata[3] & S2_P2_MASK) >> S2_P2_SHIFT;
+		p2[3] = (qfprom_cdata[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+		p2[4] = (qfprom_cdata[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+		p2[5] = (qfprom_cdata[0] & S5_P2_MASK) >> S5_P2_SHIFT;
+		p2[6] = (qfprom_cdata[0] & S6_P2_MASK) >> S6_P2_SHIFT;
+		p2[7] = (qfprom_cdata[1] & S7_P2_MASK) >> S7_P2_SHIFT;
+		p2[8] = (qfprom_cdata[1] & S8_P2_MASK) >> S8_P2_SHIFT;
+		p2[9] = (qfprom_cdata[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+		p2[10] = (qfprom_cdata[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+		/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (qfprom_cdata[0] & BASE0_MASK);
+		p1[0] = (qfprom_cdata[2] & S0_P1_MASK) >> S0_P1_SHIFT;
+		p1[1] = (qfprom_cdata[2] & S1_P1_MASK) >> S1_P1_SHIFT;
+		p1[2] = (qfprom_cdata[2] & S2_P1_MASK_0_4) >> S2_P1_SHIFT_0_4;
+		tmp = (qfprom_cdata[3] & S2_P1_MASK_5) << S2_P1_SHIFT_5;
+		p1[2] |= tmp;
+		p1[3] = (qfprom_cdata[3] & S3_P1_MASK) >> S3_P1_SHIFT;
+		p1[4] = (qfprom_cdata[3] & S4_P1_MASK) >> S4_P1_SHIFT;
+		p1[5] = (qfprom_cdata[0] & S5_P1_MASK) >> S5_P1_SHIFT;
+		p1[6] = (qfprom_cdata[0] & S6_P1_MASK) >> S6_P1_SHIFT;
+		p1[7] = (qfprom_cdata[1] & S7_P1_MASK);
+		p1[8] = (qfprom_cdata[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+		p1[9] = (qfprom_cdata[4] & S9_P1_MASK);
+		p1[10] = (qfprom_cdata[4] & S10_P1_MASK) >> S10_P1_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+
+	return 0;
+}
+
+static int tsens1xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int code;
+	void __iomem *sensor_addr;
+	void __iomem *trdy_addr;
+	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+	bool last_temp_valid = false, last_temp2_valid = false;
+	bool last_temp3_valid = false;
+
+	if (!sensor)
+		return -EINVAL;
+
+	tmdev = sensor->tmdev;
+
+	trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_tm_addr);
+	sensor_addr = TSENS_SN_STATUS_ADDR(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed(sensor_addr +
+			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp = code & TSENS_SN_STATUS_TEMP_MASK;
+
+	if (tmdev->ctrl_data->valid_status_check) {
+		if (code & TSENS_SN_STATUS_VALID)
+			last_temp_valid = true;
+		else {
+			code = readl_relaxed(sensor_addr +
+				(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+			last_temp2 = code & TSENS_SN_STATUS_TEMP_MASK;
+			if (code & TSENS_SN_STATUS_VALID) {
+				last_temp = last_temp2;
+				last_temp2_valid = true;
+			} else {
+				code = readl_relaxed(sensor_addr +
+					(sensor->hw_id <<
+					TSENS_STATUS_ADDR_OFFSET));
+				last_temp3 = code & TSENS_SN_STATUS_TEMP_MASK;
+				if (code & TSENS_SN_STATUS_VALID) {
+					last_temp = last_temp3;
+					last_temp3_valid = true;
+				}
+			}
+		}
+	}
+
+	if ((tmdev->ctrl_data->valid_status_check) &&
+		(!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) {
+		if (last_temp == last_temp2)
+			last_temp = last_temp2;
+		else if (last_temp2 == last_temp3)
+			last_temp = last_temp3;
+	}
+
+	*temp = code_to_degc(last_temp, sensor);
+	*temp = *temp * TSENS_SCALE_MILLIDEG;
+
+	return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct tsens_sensor *tm_sensor,
+			int trip, enum thermal_device_mode mode)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+	/* clear the interrupt and unmask */
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+
+	switch (trip) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_th_state = mode;
+
+		code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		mask = TSENS_UPPER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_th_state = mode;
+
+		code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		mask = TSENS_LOWER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == THERMAL_DEVICE_DISABLED)
+		writel_relaxed(reg_cntl | mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+			(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	else
+		writel_relaxed(reg_cntl & ~mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+		(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	/* Enable the thresholds */
+	mb();
+
+	return 0;
+}
+
+static int tsens1xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+						int low_temp, int high_temp)
+{
+	unsigned int reg_cntl;
+	unsigned long flags;
+	struct tsens_device *tmdev = NULL;
+	int high_code, low_code, rc = 0;
+
+	if (!tm_sensor)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
+	if (high_temp != INT_MAX) {
+		high_temp /= TSENS_SCALE_MILLIDEG;
+		high_code = degc_to_code(high_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
+							high_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_temp =
+							high_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					 TSENS_SN_ADDR_OFFSET));
+
+		high_code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+		reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | high_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+
+	if (low_temp != INT_MIN) {
+		low_temp /= TSENS_SCALE_MILLIDEG;
+		low_code = degc_to_code(low_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
+							low_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_temp =
+							low_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET));
+
+		reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | low_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+	/* Set trip temperature thresholds */
+	mb();
+
+	if (high_temp != INT_MAX) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip high enable error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip high disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+	if (low_temp != INT_MIN) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip low enable activation error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip low disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	return rc;
+}
+
+static irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status, threshold, temp, th_temp;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_status_ctrl_addr;
+	u32 rc = 0, addr_offset;
+
+	sensor_status_addr = TSENS_SN_STATUS_ADDR(tm->tsens_tm_addr);
+	sensor_status_ctrl_addr =
+		TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_tm_addr);
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		bool upper_thr = false, lower_thr = false;
+
+		if (IS_ERR(tm->sensor[i].tzd))
+			continue;
+
+		rc = tsens1xxx_get_temp(&tm->sensor[i], &temp);
+		if (rc) {
+			pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+			continue;
+		}
+
+		spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		threshold = readl_relaxed(sensor_status_ctrl_addr +
+								addr_offset);
+
+		if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+			writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_UPPER_THRESHOLD_MASK) >>
+					TSENS_UPPER_THRESHOLD_SHIFT,
+					tm->sensor);
+			if (th_temp > temp) {
+				pr_debug("Re-arm high threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_HI,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("high rearm failed");
+			} else {
+				upper_thr = true;
+				tm->sensor[i].thr_state.high_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+
+		if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+			writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_LOWER_THRESHOLD_MASK),
+					tm->sensor);
+			if (th_temp < temp) {
+				pr_debug("Re-arm Low threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_LOW,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("low rearm failed");
+			} else {
+				lower_thr = true;
+				tm->sensor[i].thr_state.low_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+		spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+		if (upper_thr || lower_thr) {
+			pr_debug("sensor:%d trigger temp (%d degC)\n",
+				tm->sensor[i].hw_id,
+				code_to_degc((status &
+				TSENS_SN_STATUS_TEMP_MASK),
+				tm->sensor));
+			of_thermal_handle_trip(tm->sensor[i].tzd);
+		}
+	}
+
+	/* Disable monitoring sensor trip threshold for triggered sensor */
+	mb();
+
+	return IRQ_HANDLED;
+}
+
+static int tsens1xxx_hw_sensor_en(struct tsens_device *tmdev,
+					u32 sensor_id)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val, sensor_en;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+	sensor_en = ((1 << sensor_id) & srot_val);
+
+	return sensor_en;
+}
+
+static int tsens1xxx_hw_init(struct tsens_device *tmdev)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	if (!(srot_val & TSENS_EN)) {
+		pr_err("TSENS device is not enabled\n");
+		return -ENODEV;
+	}
+
+	writel_relaxed(TSENS_INTERRUPT_EN,
+			TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_tm_addr));
+
+	spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+	return 0;
+}
+
+static const struct tsens_irqs tsens1xxx_irqs[] = {
+	{ "tsens-upper-lower", tsens_irq_thread},
+};
+
+static int tsens1xxx_register_interrupts(struct tsens_device *tmdev)
+{
+	struct platform_device *pdev;
+	int i, rc;
+
+	if (!tmdev)
+		return -EINVAL;
+
+	pdev = tmdev->pdev;
+
+	for (i = 0; i < ARRAY_SIZE(tsens1xxx_irqs); i++) {
+		int irq;
+
+		irq = platform_get_irq_byname(pdev, tsens1xxx_irqs[i].name);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return irq;
+		}
+
+		rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				tsens1xxx_irqs[i].handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				tsens1xxx_irqs[i].name, tmdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return rc;
+		}
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+}
+
+static const struct tsens_ops ops_tsens1xxx = {
+	.hw_init		= tsens1xxx_hw_init,
+	.get_temp		= tsens1xxx_get_temp,
+	.set_trips		= tsens1xxx_set_trip_temp,
+	.interrupts_reg		= tsens1xxx_register_interrupts,
+	.sensor_en		= tsens1xxx_hw_sensor_en,
+	.calibrate		= calibrate_8937,
+};
+
+const struct tsens_data data_tsens14xx = {
+	.ops			= &ops_tsens1xxx,
+	.valid_status_check	= true,
+	.mtc			= true,
+};
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 50c847f..af60a4b 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -59,9 +59,11 @@
 #define TSENS_TM_SCALE_DECI_MILLIDEG		100
 #define TSENS_DEBUG_WDOG_TRIGGER_COUNT		5
 #define TSENS_TM_WATCHDOG_LOG(n)		((n) + 0x13c)
-
 #define TSENS_EN				BIT(0)
 #define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0xffff)
+#define TSENS_TM_TRDY(n)			((n) + 0xe4)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE	BIT(3)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT	3
 
 static void msm_tsens_convert_temp(int last_temp, int *temp)
 {
@@ -79,7 +81,7 @@
 {
 	struct tsens_device *tmdev = NULL;
 	unsigned int code;
-	void __iomem *sensor_addr;
+	void __iomem *sensor_addr, *trdy;
 	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
 
 	if (!sensor)
@@ -87,6 +89,14 @@
 
 	tmdev = sensor->tmdev;
 	sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
+	trdy = TSENS_TM_TRDY(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed_no_log(trdy);
+	if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >>
+			TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT)) {
+		pr_err("TSENS device first round not complete0x%x\n", code);
+		return -ENODATA;
+	}
 
 	code = readl_relaxed_no_log(sensor_addr +
 			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a70356d..521a6e4 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2239,12 +2239,14 @@
 		val &= ~UCR3_AWAKEN;
 	writel(val, sport->port.membase + UCR3);
 
-	val = readl(sport->port.membase + UCR1);
-	if (on)
-		val |= UCR1_RTSDEN;
-	else
-		val &= ~UCR1_RTSDEN;
-	writel(val, sport->port.membase + UCR1);
+	if (sport->have_rtscts) {
+		val = readl(sport->port.membase + UCR1);
+		if (on)
+			val |= UCR1_RTSDEN;
+		else
+			val &= ~UCR1_RTSDEN;
+		writel(val, sport->port.membase + UCR1);
+	}
 }
 
 static int imx_serial_port_suspend_noirq(struct device *dev)
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 185a9e2..563305f 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -111,6 +111,7 @@
 #define DEF_TX_WM		(2)
 #define DEF_FIFO_WIDTH_BITS	(32)
 #define UART_CORE2X_VOTE	(10000)
+#define UART_CONSOLE_CORE2X_VOTE (960)
 
 #define WAKEBYTE_TIMEOUT_MSEC	(2000)
 #define WAIT_XFER_MAX_ITER	(50)
@@ -2367,8 +2368,16 @@
 	}
 	dev_port->wrapper_dev = &wrapper_pdev->dev;
 	dev_port->serial_rsc.wrapper_dev = &wrapper_pdev->dev;
-	ret = geni_se_resources_init(&dev_port->serial_rsc, UART_CORE2X_VOTE,
-					(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+
+	if (is_console)
+		ret = geni_se_resources_init(&dev_port->serial_rsc,
+			UART_CONSOLE_CORE2X_VOTE,
+			(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+	else
+		ret = geni_se_resources_init(&dev_port->serial_rsc,
+			UART_CORE2X_VOTE,
+			(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+
 	if (ret)
 		goto exit_geni_serial_probe;
 
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 2e2b88a..dce39de 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -968,6 +968,8 @@
 		}
 	} else {
 		retval = uart_startup(tty, state, 1);
+		if (retval == 0)
+			tty_port_set_initialized(port, true);
 		if (retval > 0)
 			retval = 0;
 	}
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ea20b2c..34d23cc 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -375,7 +375,7 @@
 
 	res = usb_submit_urb(acm->read_urbs[index], mem_flags);
 	if (res) {
-		if (res != -EPERM) {
+		if (res != -EPERM && res != -ENODEV) {
 			dev_err(&acm->data->dev,
 					"urb %d failed submission with %d\n",
 					index, res);
@@ -1706,6 +1706,9 @@
 	{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
 	.driver_info = SINGLE_RX_URB, /* firmware bug */
 	},
+	{ USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
+	.driver_info = SINGLE_RX_URB,
+	},
 	{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index e0321a1..edf855c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -256,9 +256,9 @@
 
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT, 0);
 
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT, 0);
 
 	return 0;
 }
@@ -366,7 +366,7 @@
 		dwc3_free_one_event_buffer(dwc, evt);
 
 	/* free GSI related event buffers */
-	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE);
+	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE, 0);
 }
 
 /**
@@ -389,7 +389,7 @@
 	dwc->ev_buf = evt;
 
 	/* alloc GSI related event buffers */
-	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC);
+	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC, 0);
 	return 0;
 }
 
@@ -420,7 +420,7 @@
 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
 
 	/* setup GSI related event buffers */
-	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP);
+	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0);
 	return 0;
 }
 
@@ -442,7 +442,7 @@
 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
 
 	/* cleanup GSI related event buffers */
-	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP);
+	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP, 0);
 }
 
 static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
@@ -1026,19 +1026,20 @@
 	dwc3_gadget_restart(dwc);
 }
 
-static void (*notify_event)(struct dwc3 *, unsigned int);
-void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int))
+static void (*notify_event)(struct dwc3 *, unsigned int, unsigned int);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int,
+							unsigned int))
 {
 	notify_event = notify;
 }
 EXPORT_SYMBOL(dwc3_set_notifier);
 
-int dwc3_notify_event(struct dwc3 *dwc, unsigned int event)
+int dwc3_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value)
 {
 	int ret = 0;
 
 	if (dwc->notify_event)
-		dwc->notify_event(dwc, event);
+		dwc->notify_event(dwc, event, value);
 	else
 		ret = -ENODEV;
 
@@ -1459,7 +1460,7 @@
 	int		ret;
 
 	/* Check if platform glue driver handling PM, if not then handle here */
-	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
 		return 0;
 
 	ret = dwc3_suspend_common(dwc);
@@ -1477,7 +1478,7 @@
 	int		ret;
 
 	/* Check if platform glue driver handling PM, if not then handle here */
-	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
 		return 0;
 
 	device_init_wakeup(dev, false);
@@ -1533,7 +1534,7 @@
 	int		ret;
 
 	/* Check if platform glue driver handling PM, if not then handle here */
-	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT))
+	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0))
 		return 0;
 
 	ret = dwc3_suspend_common(dwc);
@@ -1551,7 +1552,7 @@
 	int		ret;
 
 	/* Check if platform glue driver handling PM, if not then handle here */
-	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
 		return 0;
 
 	pinctrl_pm_select_default_state(dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b91642a..69d3fa8 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -821,21 +821,22 @@
 	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
 };
 
-#define DWC3_CONTROLLER_ERROR_EVENT		0
-#define DWC3_CONTROLLER_RESET_EVENT		1
-#define DWC3_CONTROLLER_POST_RESET_EVENT	2
-#define DWC3_CORE_PM_SUSPEND_EVENT		3
-#define DWC3_CORE_PM_RESUME_EVENT		4
-#define DWC3_CONTROLLER_CONNDONE_EVENT		5
-#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT	6
-#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT	7
-#define DWC3_CONTROLLER_RESTART_USB_SESSION	8
+#define DWC3_CONTROLLER_ERROR_EVENT			0
+#define DWC3_CONTROLLER_RESET_EVENT			1
+#define DWC3_CONTROLLER_POST_RESET_EVENT		2
+#define DWC3_CORE_PM_SUSPEND_EVENT			3
+#define DWC3_CORE_PM_RESUME_EVENT			4
+#define DWC3_CONTROLLER_CONNDONE_EVENT			5
+#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT		6
+#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT		7
+#define DWC3_CONTROLLER_RESTART_USB_SESSION		8
+#define DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER		9
 
 /* USB GSI event buffer related notification */
-#define DWC3_GSI_EVT_BUF_ALLOC			9
-#define DWC3_GSI_EVT_BUF_SETUP			10
-#define DWC3_GSI_EVT_BUF_CLEANUP		11
-#define DWC3_GSI_EVT_BUF_FREE			12
+#define DWC3_GSI_EVT_BUF_ALLOC			10
+#define DWC3_GSI_EVT_BUF_SETUP			11
+#define DWC3_GSI_EVT_BUF_CLEANUP		12
+#define DWC3_GSI_EVT_BUF_FREE			13
 
 #define MAX_INTR_STATS				10
 
@@ -1081,7 +1082,7 @@
 	const char		*hsphy_interface;
 
 	unsigned		connected:1;
-	void (*notify_event)(struct dwc3 *, unsigned int);
+	void (*notify_event)(struct dwc3 *, unsigned int, unsigned int);
 	struct work_struct	wakeup_work;
 
 	unsigned		delayed_status:1;
@@ -1416,6 +1417,9 @@
 void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
 
 extern void dwc3_set_notifier(
-		void (*notify)(struct dwc3 *dwc3, unsigned int event));
-extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event);
+	void (*notify)(struct dwc3 *dwc3, unsigned int event,
+						unsigned int value));
+extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event,
+							unsigned int value);
+
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index 44c082a..48b3894 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -37,6 +37,7 @@
 	DBM_HW_TRB2_EP,
 	DBM_HW_TRB3_EP,
 	DBM_PIPE_CFG,
+	DBM_DISABLE_UPDXFER,
 	DBM_SOFT_RESET,
 	DBM_GEN_CFG,
 	DBM_GEVNTADR_LSB,
@@ -103,6 +104,7 @@
 	[DBM_HW_TRB2_EP]	= { 0x0240, 0x4 },
 	[DBM_HW_TRB3_EP]	= { 0x0250, 0x4 },
 	[DBM_PIPE_CFG]		= { 0x0274, 0x0 },
+	[DBM_DISABLE_UPDXFER]	= { 0x0298, 0x0 },
 	[DBM_SOFT_RESET]	= { 0x020C, 0x0 },
 	[DBM_GEN_CFG]		= { 0x0210, 0x0 },
 	[DBM_GEVNTADR_LSB]	= { 0x0260, 0x0 },
@@ -192,7 +194,7 @@
 		if (dbm->ep_num_mapping[i] == usb_ep)
 			return i;
 
-	pr_err("%s: No DBM EP matches USB EP %d", __func__, usb_ep);
+	pr_debug("%s: No DBM EP matches USB EP %d", __func__, usb_ep);
 	return -ENODEV; /* Not found */
 }
 
@@ -291,6 +293,7 @@
 {
 	int dbm_ep;
 	u32 ep_cfg;
+	u32 data;
 
 	if (!dbm) {
 		pr_err("%s: dbm pointer is NULL!\n", __func__);
@@ -312,9 +315,6 @@
 		return -ENODEV;
 	}
 
-	/* First, reset the dbm endpoint */
-	ep_soft_reset(dbm, dbm_ep, 0);
-
 	/* Set ioc bit for dbm_ep if needed */
 	msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG,
 		DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
@@ -337,6 +337,10 @@
 
 	msm_dbm_write_ep_reg_field(dbm, DBM_EP_CFG, dbm_ep, DBM_EN_EP, 1);
 
+	data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+	data &= ~(0x1 << dbm_ep);
+	msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
 	return dbm_ep;
 }
 
@@ -381,7 +385,7 @@
 	dbm_ep = find_matching_dbm_ep(dbm, usb_ep);
 
 	if (dbm_ep < 0) {
-		pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep);
+		pr_debug("usb ep index %d has no corespondng dbm ep\n", usb_ep);
 		return -ENODEV;
 	}
 
@@ -391,23 +395,10 @@
 	data &= (~0x1);
 	msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data);
 
-	/* Reset the dbm endpoint */
-	ep_soft_reset(dbm, dbm_ep, true);
 	/*
-	 * The necessary delay between asserting and deasserting the dbm ep
-	 * reset is based on the number of active endpoints. If there is more
-	 * than one endpoint, a 1 msec delay is required. Otherwise, a shorter
-	 * delay will suffice.
-	 *
-	 * As this function can be called in atomic context, sleeping variants
-	 * for delay are not possible - albeit a 1ms delay.
+	 * ep_soft_reset is not required during disconnect as pipe reset on
+	 * next connect will take care of the same.
 	 */
-	if (dbm_get_num_of_eps_configured(dbm) > 1)
-		udelay(1000);
-	else
-		udelay(10);
-	ep_soft_reset(dbm, dbm_ep, false);
-
 	return 0;
 }
 
@@ -449,6 +440,35 @@
 	return 0;
 }
 
+/**
+ * Disable update xfer before queueing stop xfer command to USB3 core.
+ *
+ * @usb_ep - USB physical EP number.
+ *
+ */
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep)
+{
+	u32 data;
+	int dbm_ep;
+
+	if (!dbm) {
+		pr_err("%s: dbm pointer is NULL!\n", __func__);
+		return -EPERM;
+	}
+
+	dbm_ep = find_matching_dbm_ep(dbm, usb_ep);
+
+	if (dbm_ep < 0) {
+		pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep);
+		return -ENODEV;
+	}
+
+	data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+	data |= (0x1 << dbm_ep);
+	msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
+	return 0;
+}
 
 int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
 				u32 size, u8 dst_pipe_idx)
diff --git a/drivers/usb/dwc3/dbm.h b/drivers/usb/dwc3/dbm.h
index d8e1ce9..259900d 100644
--- a/drivers/usb/dwc3/dbm.h
+++ b/drivers/usb/dwc3/dbm.h
@@ -65,6 +65,7 @@
 				int size);
 int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
 				u32 size, u8 dst_pipe_idx);
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep);
 void dbm_set_speed(struct dbm *dbm, bool speed);
 void dbm_enable(struct dbm *dbm);
 int dbm_ep_soft_reset(struct dbm *dbm, u8 usb_ep, bool enter_reset);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 5c4a24d..ded62f1 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -289,7 +289,8 @@
 
 static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
 static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
-static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event);
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
+						unsigned int value);
 static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
 					unsigned long event, void *ptr);
 
@@ -441,6 +442,16 @@
 	return dwc3_msm_is_dev_superspeed(mdwc);
 }
 
+static int dwc3_msm_dbm_disable_updxfer(struct dwc3 *dwc, u8 usb_ep)
+{
+	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+	dev_dbg(mdwc->dev, "%s\n", __func__);
+	dwc3_dbm_disable_update_xfer(mdwc->dbm, usb_ep);
+
+	return 0;
+}
+
 #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 /**
  * Configure the DBM with the BAM's data fifo.
@@ -697,67 +708,8 @@
 	struct dwc3_msm_req_complete *req_complete;
 	unsigned long flags;
 	int ret = 0, size;
-	u8 bam_pipe;
-	bool producer;
-	bool disable_wb;
-	bool internal_mem;
-	bool ioc;
 	bool superspeed;
 
-	if (!(request->udc_priv & MSM_SPS_MODE)) {
-		/* Not SPS mode, call original queue */
-		dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
-					__func__);
-
-		return (mdwc->original_ep_ops[dep->number])->queue(ep,
-								request,
-								gfp_flags);
-	}
-
-	/* HW restriction regarding TRB size (8KB) */
-	if (req->request.length < 0x2000) {
-		dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
-		return -EINVAL;
-	}
-
-	/*
-	 * Override req->complete function, but before doing that,
-	 * store it's original pointer in the req_complete_list.
-	 */
-	req_complete = kzalloc(sizeof(*req_complete), gfp_flags);
-	if (!req_complete)
-		return -ENOMEM;
-
-	req_complete->req = request;
-	req_complete->orig_complete = request->complete;
-	list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
-	request->complete = dwc3_msm_req_complete_func;
-
-	/*
-	 * Configure the DBM endpoint
-	 */
-	bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
-	producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
-	disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
-	internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
-	ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
-
-	ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
-				disable_wb, internal_mem, ioc);
-	if (ret < 0) {
-		dev_err(mdwc->dev,
-			"error %d after calling dbm_ep_config\n", ret);
-		return ret;
-	}
-
-	dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
-			__func__, request, ep->name, request->length);
-	size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
-	dbm_event_buffer_config(mdwc->dbm,
-		dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
-		dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
-		DWC3_GEVNTSIZ_SIZE(size));
-
 	/*
 	 * We must obtain the lock of the dwc3 core driver,
 	 * including disabling interrupts, so we will be sure
@@ -770,31 +722,83 @@
 		dev_err(mdwc->dev,
 			"%s: trying to queue request %p to disabled ep %s\n",
 			__func__, request, ep->name);
-		ret = -EPERM;
-		goto err;
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EPERM;
+	}
+
+	if (!mdwc->original_ep_ops[dep->number]) {
+		dev_err(mdwc->dev,
+			"ep [%s,%d] was unconfigured as msm endpoint\n",
+			ep->name, dep->number);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EINVAL;
+	}
+
+	if (!request) {
+		dev_err(mdwc->dev, "%s: request is NULL\n", __func__);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EINVAL;
+	}
+
+	if (!(request->udc_priv & MSM_SPS_MODE)) {
+		dev_err(mdwc->dev, "%s: sps mode is not set\n",
+					__func__);
+
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EINVAL;
+	}
+
+	/* HW restriction regarding TRB size (8KB) */
+	if (req->request.length < 0x2000) {
+		dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EINVAL;
 	}
 
 	if (dep->number == 0 || dep->number == 1) {
 		dev_err(mdwc->dev,
 			"%s: trying to queue dbm request %p to control ep %s\n",
 			__func__, request, ep->name);
-		ret = -EPERM;
-		goto err;
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EPERM;
 	}
 
-
-	if (dep->trb_dequeue != dep->trb_enqueue ||
-			!list_empty(&dep->pending_list)
-			|| !list_empty(&dep->started_list)) {
+	if (dep->trb_dequeue != dep->trb_enqueue
+					|| !list_empty(&dep->pending_list)
+					|| !list_empty(&dep->started_list)) {
 		dev_err(mdwc->dev,
 			"%s: trying to queue dbm request %p tp ep %s\n",
 			__func__, request, ep->name);
-		ret = -EPERM;
-		goto err;
-	} else {
-		dep->trb_dequeue = 0;
-		dep->trb_enqueue = 0;
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -EPERM;
 	}
+	dep->trb_dequeue = 0;
+	dep->trb_enqueue = 0;
+
+	/*
+	 * Override req->complete function, but before doing that,
+	 * store it's original pointer in the req_complete_list.
+	 */
+	req_complete = kzalloc(sizeof(*req_complete), gfp_flags);
+
+	if (!req_complete) {
+		dev_err(mdwc->dev, "%s: not enough memory\n", __func__);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -ENOMEM;
+	}
+
+	req_complete->req = request;
+	req_complete->orig_complete = request->complete;
+	list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
+	request->complete = dwc3_msm_req_complete_func;
+
+	dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
+			__func__, request, ep->name, request->length);
+	size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
+	dbm_event_buffer_config(mdwc->dbm,
+		dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
+		dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
+		DWC3_GEVNTSIZ_SIZE(size));
 
 	ret = __dwc3_msm_ep_queue(dep, req);
 	if (ret < 0) {
@@ -1061,6 +1065,8 @@
 	struct dwc3_trb *trb;
 	int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
 					: (req->num_bufs + 2);
+	struct scatterlist *sg;
+	struct sg_table *sgt;
 
 	dep->trb_pool = dma_zalloc_coherent(dwc->sysdev,
 				num_trbs * sizeof(struct dwc3_trb),
@@ -1073,6 +1079,19 @@
 	}
 
 	dep->num_trbs = num_trbs;
+	dma_get_sgtable(dwc->sysdev, &req->sgt_trb_xfer_ring, dep->trb_pool,
+		dep->trb_pool_dma, num_trbs * sizeof(struct dwc3_trb));
+
+	sgt = &req->sgt_trb_xfer_ring;
+	dev_dbg(dwc->dev, "%s(): trb_pool:%pK trb_pool_dma:%lx\n",
+		__func__, dep->trb_pool, (unsigned long)dep->trb_pool_dma);
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i)
+		dev_dbg(dwc->dev,
+			"%i: page_link:%lx offset:%x length:%x address:%lx\n",
+			i, sg->page_link, sg->offset, sg->length,
+			(unsigned long)sg->dma_address);
+
 	/* IN direction */
 	if (dep->direction) {
 		for (i = 0; i < num_trbs ; i++) {
@@ -1138,11 +1157,13 @@
 		}
 	}
 
-	pr_debug("%s: Initialized TRB Ring for %s\n", __func__, dep->name);
+	dev_dbg(dwc->dev, "%s: Initialized TRB Ring for %s\n",
+					__func__, dep->name);
 	trb = &dep->trb_pool[0];
 	if (trb) {
 		for (i = 0; i < num_trbs; i++) {
-			pr_debug("TRB(%d): ADDRESS:%lx bpl:%x bph:%x size:%x ctrl:%x\n",
+			dev_dbg(dwc->dev,
+				"TRB %d: ADDR:%lx bpl:%x bph:%x sz:%x ctl:%x\n",
 				i, (unsigned long)dwc3_trb_dma_offset(dep,
 				&dep->trb_pool[i]), trb->bpl, trb->bph,
 				trb->size, trb->ctrl);
@@ -1159,7 +1180,7 @@
 * @usb_ep - pointer to usb_ep instance.
 *
 */
-static void gsi_free_trbs(struct usb_ep *ep)
+static void gsi_free_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
 {
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
 	struct dwc3 *dwc = dep->dwc;
@@ -1176,6 +1197,7 @@
 		dep->trb_pool = NULL;
 		dep->trb_pool_dma = 0;
 	}
+	sg_free_table(&req->sgt_trb_xfer_ring);
 }
 /*
 * Configures GSI EPs. For GSI EPs we need to set interrupter numbers.
@@ -1365,7 +1387,8 @@
 		break;
 	case GSI_EP_OP_FREE_TRBS:
 		dev_dbg(mdwc->dev, "EP_OP_FREE_TRBS for %s\n", ep->name);
-		gsi_free_trbs(ep);
+		request = (struct usb_gsi_request *)op_data;
+		gsi_free_trbs(ep, request);
 		break;
 	case GSI_EP_OP_CONFIG:
 		request = (struct usb_gsi_request *)op_data;
@@ -1452,37 +1475,68 @@
  *
  * @return int - 0 on success, negetive on error.
  */
-int msm_ep_config(struct usb_ep *ep)
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
 {
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
 	struct dwc3 *dwc = dep->dwc;
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
 	struct usb_ep_ops *new_ep_ops;
+	int ret = 0;
+	u8 bam_pipe;
+	bool producer;
+	bool disable_wb;
+	bool internal_mem;
+	bool ioc;
+	unsigned long flags;
 
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	/* Save original ep ops for future restore*/
 	if (mdwc->original_ep_ops[dep->number]) {
 		dev_err(mdwc->dev,
 			"ep [%s,%d] already configured as msm endpoint\n",
 			ep->name, dep->number);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		return -EPERM;
 	}
 	mdwc->original_ep_ops[dep->number] = ep->ops;
 
 	/* Set new usb ops as we like */
 	new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC);
-	if (!new_ep_ops)
+	if (!new_ep_ops) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		return -ENOMEM;
+	}
 
 	(*new_ep_ops) = (*ep->ops);
 	new_ep_ops->queue = dwc3_msm_ep_queue;
 	new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op;
 	ep->ops = new_ep_ops;
 
+	if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return 0;
+	}
+
 	/*
-	 * Do HERE more usb endpoint configurations
-	 * which are specific to MSM.
+	 * Configure the DBM endpoint if required.
 	 */
+	bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
+	producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
+	disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
+	internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
+	ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
+
+	ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
+					disable_wb, internal_mem, ioc);
+	if (ret < 0) {
+		dev_err(mdwc->dev,
+			"error %d after calling dbm_ep_config\n", ret);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return ret;
+	}
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
@@ -1503,12 +1557,15 @@
 	struct dwc3 *dwc = dep->dwc;
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
 	struct usb_ep_ops *old_ep_ops;
+	unsigned long flags;
 
+	spin_lock_irqsave(&dwc->lock, flags);
 	/* Restore original ep ops */
 	if (!mdwc->original_ep_ops[dep->number]) {
 		dev_err(mdwc->dev,
 			"ep [%s,%d] was not configured as msm endpoint\n",
 			ep->name, dep->number);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		return -EINVAL;
 	}
 	old_ep_ops = (struct usb_ep_ops	*)ep->ops;
@@ -1520,6 +1577,32 @@
 	 * Do HERE more usb endpoint un-configurations
 	 * which are specific to MSM.
 	 */
+	if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return 0;
+	}
+
+	if (dep->trb_dequeue == dep->trb_enqueue
+					&& list_empty(&dep->pending_list)
+					&& list_empty(&dep->started_list)) {
+		dev_dbg(mdwc->dev,
+			"%s: request is not queued, disable DBM ep for ep %s\n",
+			__func__, ep->name);
+		/* Unconfigure dbm ep */
+		dbm_ep_unconfig(mdwc->dbm, dep->number);
+
+		/*
+		 * If this is the last endpoint we unconfigured, than reset also
+		 * the event buffers; unless unconfiguring the ep due to lpm,
+		 * in which case the event buffer only gets reset during the
+		 * block reset.
+		 */
+		if (dbm_get_num_of_eps_configured(mdwc->dbm) == 0 &&
+				!dbm_reset_ep_after_lpm(mdwc->dbm))
+			dbm_event_buffer_config(mdwc->dbm, 0, 0, 0);
+	}
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
@@ -1745,7 +1828,8 @@
 	dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw);
 }
 
-static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event)
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
+							unsigned int value)
 {
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
 	struct dwc3_event_buffer *evt;
@@ -1932,6 +2016,9 @@
 							evt->buf, evt->dma);
 		}
 		break;
+	case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER:
+		dwc3_msm_dbm_disable_updxfer(dwc, value);
+		break;
 	default:
 		dev_dbg(mdwc->dev, "unknown dwc3 event\n");
 		break;
@@ -3499,6 +3586,7 @@
 	mdwc->no_vbus_vote_type_c = of_property_read_bool(node,
 					"qcom,no-vbus-vote-with-type-C");
 
+	mutex_init(&mdwc->suspend_resume_mutex);
 	/* Mark type-C as true by default */
 	mdwc->type_c = true;
 
@@ -3524,7 +3612,6 @@
 	if (ret)
 		goto put_psy;
 
-	mutex_init(&mdwc->suspend_resume_mutex);
 	/* Update initial VBUS/ID state from extcon */
 	if (mdwc->extcon_vbus && extcon_get_state(mdwc->extcon_vbus,
 							EXTCON_USB))
@@ -3800,6 +3887,9 @@
 	if (on) {
 		dev_dbg(mdwc->dev, "%s: turn on host\n", __func__);
 
+		pm_runtime_get_sync(mdwc->dev);
+		dbg_event(0xFF, "StrtHost gync",
+			atomic_read(&mdwc->dev->power.usage_count));
 		mdwc->hs_phy->flags |= PHY_HOST_MODE;
 		if (dwc->maximum_speed == USB_SPEED_SUPER) {
 			mdwc->ss_phy->flags |= PHY_HOST_MODE;
@@ -3808,9 +3898,6 @@
 		}
 
 		usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
-		pm_runtime_get_sync(mdwc->dev);
-		dbg_event(0xFF, "StrtHost gync",
-			atomic_read(&mdwc->dev->power.usage_count));
 		if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
 			ret = regulator_enable(mdwc->vbus_reg);
 		if (ret) {
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8f0ca3f..a06f3a9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -39,6 +39,7 @@
 
 static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, bool remote_wakeup);
 static int dwc3_gadget_wakeup_int(struct dwc3 *dwc);
+static void dwc3_stop_active_transfers(struct dwc3 *dwc);
 /**
  * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
  * @dwc: pointer to our context structure
@@ -416,7 +417,7 @@
 		if (cmd != DWC3_DEPCMD_ENDTRANSFER) {
 			dwc->ep_cmd_timeout_cnt++;
 			dwc3_notify_event(dwc,
-				DWC3_CONTROLLER_RESTART_USB_SESSION);
+				DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
 		}
 		cmd_status = -ETIMEDOUT;
 	}
@@ -2034,6 +2035,14 @@
 		__dwc3_gadget_ep_disable(dwc->eps[0]);
 		__dwc3_gadget_ep_disable(dwc->eps[1]);
 
+		/*
+		 * According to dwc3 databook, it is must to remove any active
+		 * transfers before trying to stop USB device controller. Hence
+		 * call dwc3_stop_active_transfers() API before stopping USB
+		 * device controller.
+		 */
+		dwc3_stop_active_transfers(dwc);
+
 		reg &= ~DWC3_DCTL_RUN_STOP;
 
 		if (dwc->has_hibernation && !suspend)
@@ -2074,7 +2083,7 @@
 	dwc->vbus_draw = mA;
 	dev_dbg(dwc->dev, "Notify controller from %s. mA = %u\n", __func__, mA);
 	dbg_event(0xFF, "currentDraw", mA);
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0);
 	return 0;
 }
 
@@ -2105,7 +2114,8 @@
 	 * during enumeration.
 	 */
 	dwc->b_suspend = false;
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
+
 	ret = dwc3_gadget_run_stop(dwc, is_on, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -2416,7 +2426,7 @@
 	struct dwc3		*dwc = gadget_to_dwc(g);
 
 	dbg_event(0xFF, "RestartUSBSession", 0);
-	return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION);
+	return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
 }
 
 static const struct usb_gadget_ops dwc3_gadget_ops = {
@@ -2969,6 +2979,10 @@
 	if (!dep->resource_index)
 		return;
 
+	if (dep->endpoint.endless)
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
+								dep->number);
+
 	/*
 	 * NOTICE: We are violating what the Databook says about the
 	 * EndTransfer command. Ideally we would _always_ wait for the
@@ -3062,7 +3076,7 @@
 	dbg_event(0xFF, "DISCONNECT INT", 0);
 	dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
 	dwc->b_suspend = false;
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_INITU1ENA;
@@ -3122,7 +3136,7 @@
 	dbg_event(0xFF, "BUS RESET", 0);
 	dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
 	dwc->b_suspend = false;
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
 
 	dwc3_usb3_phy_suspend(dwc, false);
 	usb_gadget_vbus_draw(&dwc->gadget, 100);
@@ -3297,7 +3311,8 @@
 		return;
 	}
 
-	dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT);
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT, 0);
+
 	/*
 	 * Configure PHY via GUSB3PIPECTLn if required.
 	 *
@@ -3332,7 +3347,8 @@
 		 */
 		dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
 		dwc->b_suspend = false;
-		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+		dwc3_notify_event(dwc,
+				DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
 
 		/*
 		 * set state to U0 as function level resume is trying to queue
@@ -3476,7 +3492,7 @@
 
 		dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
 		dwc->b_suspend = true;
-		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
 	}
 
 	dwc->link_state = next;
@@ -3640,7 +3656,8 @@
 			evt->lpos = (evt->lpos + left) %
 					DWC3_EVENT_BUFFERS_SIZE;
 			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), left);
-			if (dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT))
+			if (dwc3_notify_event(dwc,
+						DWC3_CONTROLLER_ERROR_EVENT, 0))
 				dwc->err_evt_seen = 0;
 			break;
 		}
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 4911253..1f75b58 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -76,7 +76,7 @@
 	writel_relaxed(write_val, base + offset - DWC3_GLOBALS_REGS_START);
 
 	/* Read back to see if value was written */
-	tmp = readl_relaxed(base + offset);
+	tmp = readl_relaxed(base + offset - DWC3_GLOBALS_REGS_START);
 
 	dwc3_trace(trace_dwc3_masked_write_readback,
 			"addr %p readback val %08x",
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 598a67d..2bde573 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -10,3 +10,5 @@
 libcomposite-y			+= composite.o functions.o configfs.o u_f.o
 
 obj-$(CONFIG_USB_GADGET)	+= udc/ function/ legacy/
+
+obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
new file mode 100644
index 0000000..d4c243c
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -0,0 +1,556 @@
+/* Copyright (c) 2010-2018, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/ulpi.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "ci13xxx_udc.c"
+
+#define MSM_USB_BASE	(udc->regs)
+
+#define CI13XXX_MSM_MAX_LOG2_ITC	7
+
+struct ci13xxx_udc_context {
+	int irq;
+	void __iomem *regs;
+	int wake_gpio;
+	int wake_irq;
+	bool wake_irq_state;
+	struct pinctrl *ci13xxx_pinctrl;
+	struct timer_list irq_enable_timer;
+	bool irq_disabled;
+};
+
+static struct ci13xxx_udc_context _udc_ctxt;
+#define IRQ_ENABLE_DELAY	(jiffies + msecs_to_jiffies(1000))
+
+static irqreturn_t msm_udc_irq(int irq, void *data)
+{
+	return udc_irq();
+}
+
+static void ci13xxx_msm_suspend(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+
+	dev_dbg(dev, "ci13xxx_msm_suspend\n");
+
+	if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
+		enable_irq_wake(_udc_ctxt.wake_irq);
+		enable_irq(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = true;
+	}
+}
+
+static void ci13xxx_msm_resume(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+
+	dev_dbg(dev, "ci13xxx_msm_resume\n");
+
+	if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
+		disable_irq_wake(_udc_ctxt.wake_irq);
+		disable_irq_nosync(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = false;
+	}
+}
+
+static void ci13xxx_msm_disconnect(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		u32 temp;
+
+		usb_phy_io_write(phy,
+				ULPI_MISC_A_VBUSVLDEXT |
+				ULPI_MISC_A_VBUSVLDEXTSEL,
+				ULPI_CLR(ULPI_MISC_A));
+
+		/* Notify LINK of VBUS LOW */
+		temp = readl_relaxed(USB_USBCMD);
+		temp &= ~USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
+}
+
+/* Link power management will reduce power consumption by
+ * short time HW suspend/resume.
+ */
+static void ci13xxx_msm_set_l1(struct ci13xxx *udc)
+{
+	int temp;
+	struct device *dev = udc->gadget.dev.parent;
+
+	dev_dbg(dev, "Enable link power management\n");
+
+	/* Enable remote wakeup and L1 for IN EPs */
+	writel_relaxed(0xffff0000, USB_L1_EP_CTRL);
+
+	temp = readl_relaxed(USB_L1_CONFIG);
+	temp |= L1_CONFIG_LPM_EN | L1_CONFIG_REMOTE_WAKEUP |
+		L1_CONFIG_GATE_SYS_CLK | L1_CONFIG_PHY_LPM |
+		L1_CONFIG_PLL;
+	writel_relaxed(temp, USB_L1_CONFIG);
+}
+
+static void ci13xxx_msm_connect(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		int	temp;
+
+		usb_phy_io_write(phy,
+			ULPI_MISC_A_VBUSVLDEXT |
+			ULPI_MISC_A_VBUSVLDEXTSEL,
+			ULPI_SET(ULPI_MISC_A));
+
+		temp = readl_relaxed(USB_GENCONFIG_2);
+		temp |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+		writel_relaxed(temp, USB_GENCONFIG_2);
+
+		temp = readl_relaxed(USB_USBCMD);
+		temp |= USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
+}
+
+static void ci13xxx_msm_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+	struct device *dev = udc->gadget.dev.parent;
+	int	temp;
+
+	writel_relaxed(0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	/* workaround for rx buffer collision issue */
+	temp = readl_relaxed(USB_GENCONFIG);
+	temp &= ~GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE;
+	temp &= ~GENCONFIG_ULPI_SERIAL_EN;
+	writel_relaxed(temp, USB_GENCONFIG);
+
+	if (udc->gadget.l1_supported)
+		ci13xxx_msm_set_l1(udc);
+
+	if (phy && (phy->flags & ENABLE_SECONDARY_PHY)) {
+		int	temp;
+
+		dev_dbg(dev, "using secondary hsphy\n");
+		temp = readl_relaxed(USB_PHY_CTRL2);
+		temp |= (1<<16);
+		writel_relaxed(temp, USB_PHY_CTRL2);
+
+		/*
+		 * Add memory barrier to make sure above LINK writes are
+		 * complete before moving ahead with USB peripheral mode
+		 * enumeration.
+		 */
+		mb();
+	}
+}
+
+static void ci13xxx_msm_mark_err_event(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return;
+
+	if (udc->transceiver == NULL)
+		return;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	/* This will trigger hardware reset before next connection */
+	otg->err_event_seen = true;
+}
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned int event)
+{
+	struct device *dev = udc->gadget.dev.parent;
+
+	switch (event) {
+	case CI13XXX_CONTROLLER_RESET_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+		ci13xxx_msm_reset();
+		break;
+	case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
+		ci13xxx_msm_disconnect();
+		ci13xxx_msm_resume();
+		break;
+	case CI13XXX_CONTROLLER_CONNECT_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
+		ci13xxx_msm_connect();
+		break;
+	case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+		ci13xxx_msm_suspend();
+		break;
+	case CI13XXX_CONTROLLER_RESUME_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
+		ci13xxx_msm_resume();
+		break;
+	case CI13XXX_CONTROLLER_ERROR_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_ERROR_EVENT received\n");
+		ci13xxx_msm_mark_err_event();
+		break;
+	case CI13XXX_CONTROLLER_UDC_STARTED_EVENT:
+		dev_info(dev,
+			 "CI13XXX_CONTROLLER_UDC_STARTED_EVENT received\n");
+		break;
+	default:
+		dev_dbg(dev, "unknown ci13xxx_udc event\n");
+		break;
+	}
+}
+
+static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
+{
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return false;
+
+	if (udc->transceiver == NULL)
+		return false;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	return (atomic_read(&otg->in_lpm) != 0);
+}
+
+
+static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (udc->transceiver && udc->vbus_active && udc->suspended)
+		usb_phy_set_suspend(udc->transceiver, 0);
+	else if (!udc->suspended)
+		ci13xxx_msm_resume();
+
+	return IRQ_HANDLED;
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
+	.name			= "ci13xxx_msm",
+	.flags			= CI13XXX_REGS_SHARED |
+				  CI13XXX_REQUIRE_TRANSCEIVER |
+				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_ZERO_ITC |
+				  CI13XXX_DISABLE_STREAMING,
+	.nz_itc			= 0,
+	.notify_event		= ci13xxx_msm_notify_event,
+	.in_lpm                 = ci13xxx_msm_in_lpm,
+};
+
+static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
+				struct resource *res)
+{
+	int wake_irq;
+	int ret;
+	struct pinctrl_state *set_state;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
+
+	_udc_ctxt.wake_gpio = res->start;
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_active");
+		if (IS_ERR(set_state)) {
+			pr_err("cannot get ci13xxx pinctrl active state\n");
+			return PTR_ERR(set_state);
+		}
+		pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl, set_state);
+	}
+	gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
+	gpio_direction_input(_udc_ctxt.wake_gpio);
+	wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio);
+	if (wake_irq < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n");
+		return -ENXIO;
+	}
+
+	dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
+			_udc_ctxt.wake_gpio, wake_irq);
+	ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
+		IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
+		goto gpio_free;
+	}
+	disable_irq(wake_irq);
+	_udc_ctxt.wake_irq = wake_irq;
+
+	return 0;
+
+gpio_free:
+	gpio_free(_udc_ctxt.wake_gpio);
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_sleep");
+		if (IS_ERR(set_state))
+			pr_err("cannot get ci13xxx pinctrl sleep state\n");
+		else
+			pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+					set_state);
+	}
+	_udc_ctxt.wake_gpio = 0;
+	return ret;
+}
+
+static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
+{
+	struct pinctrl_state *set_state;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
+
+	if (_udc_ctxt.wake_gpio) {
+		gpio_free(_udc_ctxt.wake_gpio);
+		if (_udc_ctxt.ci13xxx_pinctrl) {
+			set_state =
+				pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+						"ci13xxx_sleep");
+			if (IS_ERR(set_state))
+				pr_err("cannot get ci13xxx pinctrl sleep state\n");
+			else
+				pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+						set_state);
+		}
+		_udc_ctxt.wake_gpio = 0;
+	}
+}
+
+static void enable_usb_irq_timer_func(unsigned long data);
+static int ci13xxx_msm_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	struct ci13xxx_platform_data *pdata = pdev->dev.platform_data;
+	bool is_l1_supported = false;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+
+	if (pdata) {
+		/* Acceptable values for nz_itc are: 0,1,2,4,8,16,32,64 */
+		if (pdata->log2_itc > CI13XXX_MSM_MAX_LOG2_ITC ||
+			pdata->log2_itc <= 0)
+			ci13xxx_msm_udc_driver.nz_itc = 0;
+		else
+			ci13xxx_msm_udc_driver.nz_itc =
+				1 << (pdata->log2_itc-1);
+
+		is_l1_supported = pdata->l1_supported;
+		/* Set ahb2ahb bypass flag if it is requested. */
+		if (pdata->enable_ahb2ahb_bypass)
+			ci13xxx_msm_udc_driver.flags |=
+				CI13XXX_ENABLE_AHB2AHB_BYPASS;
+
+		/* Clear disable streaming flag if is requested. */
+		if (pdata->enable_streaming)
+			ci13xxx_msm_udc_driver.flags &=
+						~CI13XXX_DISABLE_STREAMING;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get platform resource mem\n");
+		return -ENXIO;
+	}
+
+	_udc_ctxt.regs = ioremap(res->start, resource_size(res));
+	if (!_udc_ctxt.regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, _udc_ctxt.regs);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "udc_probe failed\n");
+		goto iounmap;
+	}
+
+	_udc->gadget.l1_supported = is_l1_supported;
+
+	_udc_ctxt.irq = platform_get_irq(pdev, 0);
+	if (_udc_ctxt.irq < 0) {
+		dev_err(&pdev->dev, "IRQ not found\n");
+		ret = -ENXIO;
+		goto udc_remove;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+	/* Get pinctrl if target uses pinctrl */
+	_udc_ctxt.ci13xxx_pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(_udc_ctxt.ci13xxx_pinctrl)) {
+		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+			ret = PTR_ERR(_udc_ctxt.ci13xxx_pinctrl);
+			goto udc_remove;
+		}
+		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+		_udc_ctxt.ci13xxx_pinctrl = NULL;
+	}
+	if (res) {
+		ret = ci13xxx_msm_install_wake_gpio(pdev, res);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio irq install failed\n");
+			goto udc_remove;
+		}
+	}
+
+	ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
+					  pdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		goto gpio_uninstall;
+	}
+
+	setup_timer(&_udc_ctxt.irq_enable_timer, enable_usb_irq_timer_func,
+							(unsigned long)NULL);
+
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+gpio_uninstall:
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
+udc_remove:
+	udc_remove();
+iounmap:
+	iounmap(_udc_ctxt.regs);
+
+	return ret;
+}
+
+int ci13xxx_msm_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+	free_irq(_udc_ctxt.irq, pdev);
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
+	udc_remove();
+	iounmap(_udc_ctxt.regs);
+	return 0;
+}
+
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+	ci13xxx_pullup(&_udc->gadget, 0);
+}
+
+void msm_hw_soft_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+
+	hw_device_reset(udc);
+}
+
+void msm_hw_bam_disable(bool bam_disable)
+{
+	u32 val;
+	struct ci13xxx *udc = _udc;
+
+	if (bam_disable)
+		val = readl_relaxed(USB_GENCONFIG) | GENCONFIG_BAM_DISABLE;
+	else
+		val = readl_relaxed(USB_GENCONFIG) & ~GENCONFIG_BAM_DISABLE;
+
+	writel_relaxed(val, USB_GENCONFIG);
+}
+
+void msm_usb_irq_disable(bool disable)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	if (_udc_ctxt.irq_disabled == disable) {
+		pr_debug("Interrupt state already disable = %d\n", disable);
+		if (disable)
+			mod_timer(&_udc_ctxt.irq_enable_timer,
+					IRQ_ENABLE_DELAY);
+		spin_unlock_irqrestore(udc->lock, flags);
+		return;
+	}
+
+	if (disable) {
+		disable_irq_nosync(_udc_ctxt.irq);
+		/* start timer here */
+		pr_debug("%s: Disabling interrupts\n", __func__);
+		mod_timer(&_udc_ctxt.irq_enable_timer, IRQ_ENABLE_DELAY);
+		_udc_ctxt.irq_disabled = true;
+
+	} else {
+		pr_debug("%s: Enabling interrupts\n", __func__);
+		del_timer(&_udc_ctxt.irq_enable_timer);
+		enable_irq(_udc_ctxt.irq);
+		_udc_ctxt.irq_disabled = false;
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+}
+
+static void enable_usb_irq_timer_func(unsigned long data)
+{
+	pr_debug("enabling interrupt from timer\n");
+	msm_usb_irq_disable(false);
+}
+
+static struct platform_driver ci13xxx_msm_driver = {
+	.probe = ci13xxx_msm_probe,
+	.driver = {
+		.name = "msm_hsusb",
+	},
+	.remove = ci13xxx_msm_remove,
+	.shutdown = ci13xxx_msm_shutdown,
+};
+MODULE_ALIAS("platform:msm_hsusb");
+
+static int __init ci13xxx_msm_init(void)
+{
+	return platform_driver_register(&ci13xxx_msm_driver);
+}
+module_init(ci13xxx_msm_init);
+
+static void __exit ci13xxx_msm_exit(void)
+{
+	platform_driver_unregister(&ci13xxx_msm_driver);
+}
+module_exit(ci13xxx_msm_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
new file mode 100644
index 0000000..75205bf
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -0,0 +1,4000 @@
+/*
+ * ci13xxx_udc.c - MIPS USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Description: MIPS USB IP core family device controller
+ *              Currently it only supports IP part number CI13412
+ *
+ * This driver is composed of several blocks:
+ * - HW:     hardware interface
+ * - DBG:    debug facilities (optional)
+ * - UTIL:   utilities
+ * - ISR:    interrupts handling
+ * - ENDPT:  endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS:    bus glue code, bus abstraction layer
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN:  non-empty bulk-in pipes cannot be halted
+ *              if defined mass storage compliance succeeds but with warnings
+ *              => case 4: Hi >  Dn
+ *              => case 5: Hi >  Di
+ *              => case 8: Hi <> Do
+ *              if undefined usbtest 13 fails
+ * - TRACE:     enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ratelimit.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb.h>
+
+#include "ci13xxx_udc.h"
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+
+#define USB_MAX_TIMEOUT		25 /* 25msec timeout */
+#define EP_PRIME_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
+#define MAX_PRIME_CHECK_RETRY	3 /*Wait for 3sec for EP prime failure */
+#define EXTRA_ALLOCATION_SIZE	256
+
+/* ctrl register bank access */
+static DEFINE_SPINLOCK(udc_lock);
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_out_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_OUT,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/* UDC descriptor */
+static struct ci13xxx *_udc;
+
+/* Interrupt statistics */
+#define ISR_MASK   0x1F
+static struct {
+	u32 test;
+	u32 ui;
+	u32 uei;
+	u32 pci;
+	u32 uri;
+	u32 sli;
+	u32 none;
+	struct {
+		u32 cnt;
+		u32 buf[ISR_MASK+1];
+		u32 idx;
+	} hndl;
+} isr_statistics;
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static int ffs_nr(u32 x)
+{
+	int n = ffs(x);
+
+	return n ? n-1 : 32;
+}
+
+/******************************************************************************
+ * HW block
+ *****************************************************************************/
+/* register bank descriptor */
+static struct {
+	unsigned int  lpm;    /* is LPM? */
+	void __iomem *abs;    /* bus map offset */
+	void __iomem *cap;    /* bus map offset + CAP offset + CAP data */
+	size_t        size;   /* bank size */
+} hw_bank;
+
+/* MSM specific */
+#define ABS_AHBBURST        (0x0090UL)
+#define ABS_AHBMODE         (0x0098UL)
+/* UDC register map */
+#define ABS_CAPLENGTH       (0x100UL)
+#define ABS_HCCPARAMS       (0x108UL)
+#define ABS_DCCPARAMS       (0x124UL)
+#define ABS_TESTMODE        (hw_bank.lpm ? 0x0FCUL : 0x138UL)
+/* offset to CAPLENTGH (addr + data) */
+#define CAP_USBCMD          (0x000UL)
+#define CAP_USBSTS          (0x004UL)
+#define CAP_USBINTR         (0x008UL)
+#define CAP_DEVICEADDR      (0x014UL)
+#define CAP_ENDPTLISTADDR   (0x018UL)
+#define CAP_PORTSC          (0x044UL)
+#define CAP_DEVLC           (0x084UL)
+#define CAP_ENDPTPIPEID     (0x0BCUL)
+#define CAP_USBMODE         (hw_bank.lpm ? 0x0C8UL : 0x068UL)
+#define CAP_ENDPTSETUPSTAT  (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
+#define CAP_ENDPTPRIME      (hw_bank.lpm ? 0x0DCUL : 0x070UL)
+#define CAP_ENDPTFLUSH      (hw_bank.lpm ? 0x0E0UL : 0x074UL)
+#define CAP_ENDPTSTAT       (hw_bank.lpm ? 0x0E4UL : 0x078UL)
+#define CAP_ENDPTCOMPLETE   (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
+#define CAP_ENDPTCTRL       (hw_bank.lpm ? 0x0ECUL : 0x080UL)
+#define CAP_LAST            (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
+
+#define REMOTE_WAKEUP_DELAY	msecs_to_jiffies(200)
+
+/* maximum number of enpoints: valid only after hw_device_reset() */
+static unsigned int hw_ep_max;
+static void dbg_usb_op_fail(u8 addr, const char *name,
+				const struct ci13xxx_ep *mep);
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+	return num + (dir ? 16 : 0);
+}
+
+static int ep_to_bit(int n)
+{
+	int fill = 16 - hw_ep_max / 2;
+
+	if (n >= hw_ep_max / 2)
+		n += fill;
+
+	return n;
+}
+
+/**
+ * hw_aread: reads from register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_aread(u32 addr, u32 mask)
+{
+	return ioread32(addr + hw_bank.abs) & mask;
+}
+
+/**
+ * hw_awrite: writes to register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_awrite(u32 addr, u32 mask, u32 data)
+{
+	iowrite32(hw_aread(addr, ~mask) | (data & mask),
+		  addr + hw_bank.abs);
+}
+
+/**
+ * hw_cread: reads from register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_cread(u32 addr, u32 mask)
+{
+	return ioread32(addr + hw_bank.cap) & mask;
+}
+
+/**
+ * hw_cwrite: writes to register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_cwrite(u32 addr, u32 mask, u32 data)
+{
+	iowrite32(hw_cread(addr, ~mask) | (data & mask),
+		  addr + hw_bank.cap);
+}
+
+/**
+ * hw_ctest_and_clear: tests & clears register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_clear(u32 addr, u32 mask)
+{
+	u32 reg = hw_cread(addr, mask);
+
+	iowrite32(reg, addr + hw_bank.cap);
+	return reg;
+}
+
+/**
+ * hw_ctest_and_write: tests & writes register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
+{
+	u32 reg = hw_cread(addr, ~0);
+
+	iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
+	return (reg & mask) >> ffs_nr(mask);
+}
+
+static int hw_device_init(void __iomem *base)
+{
+	u32 reg;
+
+	/* bank is a module variable */
+	hw_bank.abs = base;
+
+	hw_bank.cap = hw_bank.abs;
+	hw_bank.cap += ABS_CAPLENGTH;
+	hw_bank.cap += ioread8(hw_bank.cap);
+
+	reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
+	hw_bank.lpm  = reg;
+	hw_bank.size = hw_bank.cap - hw_bank.abs;
+	hw_bank.size += CAP_LAST;
+	hw_bank.size /= sizeof(u32);
+
+	reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
+	hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
+
+	if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
+		return -ENODEV;
+
+	/* setup lock mode ? */
+
+	/* ENDPTSETUPSTAT is '0' by default */
+
+	/* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+	return 0;
+}
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @base: register base address
+ *
+ * This function returns an error code
+ */
+static int hw_device_reset(struct ci13xxx *udc)
+{
+	int delay_count = 25; /* 250 usec */
+
+	/* should flush & stop before reset */
+	hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
+	hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+
+	hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
+	while (delay_count--  && hw_cread(CAP_USBCMD, USBCMD_RST))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("USB controller reset failed\n");
+
+	if (udc->udc_driver->notify_event)
+		udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_RESET_EVENT);
+
+	/* USBMODE should be configured step by step */
+	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
+	hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);  /* HW >= 2.3 */
+
+	/*
+	 * ITC (Interrupt Threshold Control) field is to set the maximum
+	 * rate at which the device controller will issue interrupts.
+	 * The maximum interrupt interval measured in micro frames.
+	 * Valid values are 0, 1, 2, 4, 8, 16, 32, 64. The default value is
+	 * 8 micro frames. If CPU can handle interrupts at faster rate, ITC
+	 * can be set to lesser value to gain performance.
+	 */
+	if (udc->udc_driver->nz_itc)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK,
+			USBCMD_ITC(udc->udc_driver->nz_itc));
+	else if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK, USBCMD_ITC(0));
+
+	if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
+		pr_err("cannot enter in device mode");
+		pr_err("lpm = %i", hw_bank.lpm);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ *                  without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(u32 dma)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (dma) {
+		if (!(udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)) {
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
+			pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+				 __func__, hw_cread(CAP_USBMODE, ~0));
+
+		} else {
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+			pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+				__func__, hw_cread(CAP_USBMODE, ~0));
+		}
+
+		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
+
+
+		/* Set BIT(31) to enable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+			pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
+
+		/* interrupt, error, port change, reset, sleep/suspend */
+		hw_cwrite(CAP_USBINTR, ~0,
+			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
+	} else {
+		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+		hw_cwrite(CAP_USBINTR, ~0, 0);
+		/* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+			pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
+	}
+	return 0;
+}
+
+static void debug_ept_flush_info(int ep_num, int dir)
+{
+	struct ci13xxx *udc = _udc;
+	struct ci13xxx_ep *mep;
+
+	if (dir)
+		mep = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mep = &udc->ci13xxx_ep[ep_num];
+
+	pr_err_ratelimited("USB Registers\n");
+	pr_err_ratelimited("USBCMD:%x\n", hw_cread(CAP_USBCMD, ~0));
+	pr_err_ratelimited("USBSTS:%x\n", hw_cread(CAP_USBSTS, ~0));
+	pr_err_ratelimited("ENDPTLISTADDR:%x\n",
+			hw_cread(CAP_ENDPTLISTADDR, ~0));
+	pr_err_ratelimited("PORTSC:%x\n", hw_cread(CAP_PORTSC, ~0));
+	pr_err_ratelimited("USBMODE:%x\n", hw_cread(CAP_USBMODE, ~0));
+	pr_err_ratelimited("ENDPTSTAT:%x\n", hw_cread(CAP_ENDPTSTAT, ~0));
+
+	dbg_usb_op_fail(0xFF, "FLUSHF", mep);
+}
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(int num, int dir)
+{
+	ktime_t start, diff;
+	int n = hw_ep_bit(num, dir);
+	struct ci13xxx_ep *mEp = &_udc->ci13xxx_ep[n];
+
+	/* Flush ep0 even when queue is empty */
+	if (_udc->skip_flush || (num && list_empty(&mEp->qh.queue)))
+		return 0;
+
+	start = ktime_get();
+	do {
+		/* flush any pending transfer */
+		hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
+		while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) {
+			cpu_relax();
+			diff = ktime_sub(ktime_get(), start);
+			if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+				printk_ratelimited(KERN_ERR
+					"%s: Failed to flush ep#%d %s\n",
+					__func__, num,
+					dir ? "IN" : "OUT");
+				debug_ept_flush_info(num, dir);
+				_udc->skip_flush = true;
+				/* Notify to trigger h/w reset recovery later */
+				if (_udc->udc_driver->notify_event)
+					_udc->udc_driver->notify_event(_udc,
+						CI13XXX_CONTROLLER_ERROR_EVENT);
+				return 0;
+			}
+		}
+	} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
+
+	return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(int num, int dir)
+{
+	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
+		  dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+	return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num:  endpoint number
+ * @dir:  endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(int num, int dir, int type)
+{
+	u32 mask, data;
+
+	if (dir) {
+		mask  = ENDPTCTRL_TXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_TXS;  /* unstall */
+		mask |= ENDPTCTRL_TXR;  /* reset data toggle */
+		data |= ENDPTCTRL_TXR;
+		mask |= ENDPTCTRL_TXE;  /* enable  */
+		data |= ENDPTCTRL_TXE;
+	} else {
+		mask  = ENDPTCTRL_RXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_RXS;  /* unstall */
+		mask |= ENDPTCTRL_RXR;  /* reset data toggle */
+		data |= ENDPTCTRL_RXR;
+		mask |= ENDPTCTRL_RXE;  /* enable  */
+		data |= ENDPTCTRL_RXE;
+	}
+	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
+
+	/* make sure endpoint is enabled before returning */
+	mb();
+
+	return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(int num, int dir)
+{
+	u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+	return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ *                                 interruption)
+ * @n: endpoint number
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(int n)
+{
+	n = ep_to_bit(n);
+	return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num:     endpoint number
+ * @dir:     endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(int num, int dir, int is_ctrl)
+{
+	int n = hw_ep_bit(num, dir);
+
+	if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
+
+	if (is_ctrl && dir == RX  && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	/* status shoult be tested according with manual but it doesn't work */
+	return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ *                 without interruption)
+ * @num:   endpoint number
+ * @dir:   endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(int num, int dir, int value)
+{
+	u32 addr, mask_xs, mask_xr;
+
+	if (value != 0 && value != 1)
+		return -EINVAL;
+
+	do {
+		if (hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+			return 0;
+
+		addr = CAP_ENDPTCTRL + num * sizeof(u32);
+		mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+		mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+		/* data toggle - reserved for EP0 but it's in ESS */
+		hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
+
+	} while (value != hw_ep_get_halt(num, dir));
+
+	return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_cwrite(CAP_USBINTR, BIT(n), 0);
+	hw_cwrite(CAP_USBSTS,  BIT(n), BIT(n));
+	return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+	hw_cwrite(CAP_USBINTR,  BIT(n), BIT(n));
+	hw_cwrite(CAP_USBSTS,   BIT(n), BIT(n));
+	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
+	return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(void)
+{
+	return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
+		hw_cread(CAP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+static u8 hw_port_test_get(void)
+{
+	return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+static int hw_port_test_set(u8 mode)
+{
+	const u8 TEST_MODE_MAX = 7;
+
+	if (mode > TEST_MODE_MAX)
+		return -EINVAL;
+
+	hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+	return 0;
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(void)
+{
+	return hw_cread(CAP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(void)
+{
+	return hw_cread(CAP_USBSTS, ~0);
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf:  destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(u32 *buf, size_t size)
+{
+	unsigned int i;
+
+	if (size > hw_bank.size)
+		size = hw_bank.size;
+
+	for (i = 0; i < size; i++)
+		buf[i] = hw_aread(i * sizeof(u32), ~0);
+
+	return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(u16 addr, u32 data)
+{
+	/* align */
+	addr /= sizeof(u32);
+
+	if (addr >= hw_bank.size)
+		return -EINVAL;
+
+	/* align */
+	addr *= sizeof(u32);
+
+	hw_awrite(addr, ~0, data);
+	return 0;
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ *                             interruption)
+ * @n: endpoint number
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(int n)
+{
+	n = ep_to_bit(n);
+	return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ *                                without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(void)
+{
+	u32 reg = hw_read_intr_status() & hw_read_intr_enable();
+
+	hw_cwrite(CAP_USBSTS, ~0, reg);
+	return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ *                                interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(void)
+{
+	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ *                              interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(void)
+{
+	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function returns an error code
+ */
+static int hw_usb_set_address(u8 value)
+{
+	/* advance */
+	hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
+		  value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
+	return 0;
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ *               interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(void)
+{
+	int delay_count = 10; /* 100 usec delay */
+
+	hw_usb_set_address(0);
+
+	/* ESS flushes only at end?!? */
+	hw_cwrite(CAP_ENDPTFLUSH,    ~0, ~0);   /* flush all EPs */
+
+	/* clear complete status */
+	hw_cwrite(CAP_ENDPTCOMPLETE,  0,  0);   /* writes its content */
+
+	/* wait until all bits cleared */
+	while (delay_count-- && hw_cread(CAP_ENDPTPRIME, ~0))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("ENDPTPRIME is not cleared during bus reset\n");
+
+	/* reset all endpoints ? */
+
+	/*
+	 * reset internal status and wait for further instructions
+	 * no need to verify the port reset status (ESS does it)
+	 */
+
+	return 0;
+}
+
+/******************************************************************************
+ * DBG block
+ *****************************************************************************/
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget *gadget = &udc->gadget;
+	int n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
+		       gadget->speed);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
+		       gadget->max_speed);
+	/* TODO: Scheduled for removal in 3.8. */
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
+		       gadget_is_dualspeed(gadget));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
+		       gadget->is_otg);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
+		       gadget->is_a_peripheral);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n",
+		       gadget->b_hnp_enable);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n",
+		       gadget->a_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+		       gadget->a_alt_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n",
+		       (gadget->name ? gadget->name : ""));
+
+	return n;
+}
+static DEVICE_ATTR(device, 0400, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget_driver *driver = udc->driver;
+	int n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	if (driver == NULL)
+		return scnprintf(buf, PAGE_SIZE,
+				 "There is no gadget attached!\n");
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
+		       (driver->function ? driver->function : ""));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+		       driver->max_speed);
+
+	return n;
+}
+static DEVICE_ATTR(driver, 0400, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG   64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX   128UL
+
+/* Event buffer descriptor */
+static struct {
+	char		(buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned int	idx;   /* index */
+	unsigned int	tty;   /* print to console? */
+	rwlock_t	lck;   /* lock */
+} dbg_data = {
+	.idx = 0,
+	.tty = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned int *idx)
+{
+	*idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned int *idx)
+{
+	*idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+
+static unsigned int ep_addr_txdbg_mask;
+module_param(ep_addr_txdbg_mask, uint, 0644);
+static unsigned int ep_addr_rxdbg_mask;
+module_param(ep_addr_rxdbg_mask, uint, 0644);
+
+static int allow_dbg_print(u8 addr)
+{
+	int dir, num;
+
+	/* allow bus wide events */
+	if (addr == 0xff)
+		return 1;
+
+	dir = addr & USB_ENDPOINT_DIR_MASK ? TX : RX;
+	num = addr & ~USB_ENDPOINT_DIR_MASK;
+	num = 1 << num;
+
+	if ((dir == TX) && (num & ep_addr_txdbg_mask))
+		return 1;
+	if ((dir == RX) && (num & ep_addr_rxdbg_mask))
+		return 1;
+
+	return 0;
+}
+
+#define TIME_BUF_LEN  20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+	unsigned long long t;
+	unsigned long nanosec_rem;
+
+	t = cpu_clock(smp_processor_id());
+	nanosec_rem = do_div(t, 1000000000)/1000;
+	scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+		nanosec_rem);
+	return tbuf;
+}
+
+/**
+ * dbg_print:  prints the common part of the event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ * @extra:  extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+	unsigned long flags;
+	char tbuf[TIME_BUF_LEN];
+
+	if (!allow_dbg_print(addr))
+		return;
+
+	write_lock_irqsave(&dbg_data.lck, flags);
+
+	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+		  "%s\t? %02X %-7.7s %4i ?\t%s\n",
+		  get_timestamp(tbuf), addr, name, status, extra);
+
+	dbg_inc(&dbg_data.idx);
+
+	write_unlock_irqrestore(&dbg_data.lck, flags);
+
+	if (dbg_data.tty != 0)
+		pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+			  get_timestamp(tbuf), addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr:   endpoint address
+ * @td:     transfer descriptor
+ * @status: status
+ */
+static void dbg_done(u8 addr, const u32 token, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	scnprintf(msg, sizeof(msg), "%d %02X",
+		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
+	dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ */
+static void dbg_event(u8 addr, const char *name, int status)
+{
+	if (name != NULL)
+		dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr:   endpoint address
+ * @req:    USB request
+ * @status: status
+ */
+static void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%d %d", !req->no_interrupt, req->length);
+		dbg_print(addr, "QUEUE", status, msg);
+	}
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req:  setup request
+ */
+static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%02X %02X %04X %04X %d", req->bRequestType,
+			  req->bRequest, le16_to_cpu(req->wValue),
+			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+		dbg_print(addr, "SETUP", 0, msg);
+	}
+}
+
+/**
+ * dbg_usb_op_fail: prints USB Operation FAIL event
+ * @addr: endpoint address
+ * @mEp:  endpoint structure
+ */
+static void dbg_usb_op_fail(u8 addr, const char *name,
+				const struct ci13xxx_ep *mep)
+{
+	char msg[DBG_DATA_MSG];
+	struct ci13xxx_req *req;
+	struct list_head *ptr = NULL;
+
+	if (mep != NULL) {
+		scnprintf(msg, sizeof(msg),
+			"%s Fail EP%d%s QH:%08X",
+			name, mep->num,
+			mep->dir ? "IN" : "OUT", mep->qh.ptr->cap);
+		dbg_print(addr, name, 0, msg);
+		scnprintf(msg, sizeof(msg),
+				"cap:%08X %08X %08X\n",
+				mep->qh.ptr->curr, mep->qh.ptr->td.next,
+				mep->qh.ptr->td.token);
+		dbg_print(addr, "QHEAD", 0, msg);
+
+		list_for_each(ptr, &mep->qh.queue) {
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+			scnprintf(msg, sizeof(msg),
+					"%pKa:%08X:%08X\n",
+					&req->dma, req->ptr->next,
+					req->ptr->token);
+			dbg_print(addr, "REQ", 0, msg);
+			scnprintf(msg, sizeof(msg), "%08X:%d\n",
+					req->ptr->page[0],
+					req->req.status);
+			dbg_print(addr, "REQPAGE", 0, msg);
+		}
+	}
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	unsigned long flags;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	read_lock_irqsave(&dbg_data.lck, flags);
+
+	i = dbg_data.idx;
+	for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+		n += strlen(dbg_data.buf[i]);
+		if (n >= PAGE_SIZE) {
+			n -= strlen(dbg_data.buf[i]);
+			break;
+		}
+	}
+	for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+		j += scnprintf(buf + j, PAGE_SIZE - j,
+			       "%s", dbg_data.buf[i]);
+
+	read_unlock_irqrestore(&dbg_data.lck, flags);
+
+	return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned int tty;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (kstrtouint(buf, 10, &tty) || tty > 1) {
+		dev_err(dev, "<1|0>: enable|disable console log\n");
+		goto done;
+	}
+
+	dbg_data.tty = tty;
+	dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(events, 0600, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 intr;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	n += scnprintf(buf + n, PAGE_SIZE - n,
+		       "status = %08x\n", hw_read_intr_status());
+	n += scnprintf(buf + n, PAGE_SIZE - n,
+		       "enable = %08x\n", hw_read_intr_enable());
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+		       isr_statistics.test);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
+		       isr_statistics.ui);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
+		       isr_statistics.uei);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
+		       isr_statistics.pci);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
+		       isr_statistics.uri);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
+		       isr_statistics.sli);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+		       isr_statistics.none);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+		       isr_statistics.hndl.cnt);
+
+	for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+		i   &= ISR_MASK;
+		intr = isr_statistics.hndl.buf[i];
+
+		if (USBi_UI  & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "ui  ");
+		intr &= ~USBi_UI;
+		if (USBi_UEI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+		intr &= ~USBi_UEI;
+		if (USBi_PCI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+		intr &= ~USBi_PCI;
+		if (USBi_URI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+		intr &= ~USBi_URI;
+		if (USBi_SLI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+		intr &= ~USBi_SLI;
+		if (intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+		if (isr_statistics.hndl.buf[i])
+			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ *                   (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int en, bit;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+		dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (en) {
+		if (hw_intr_force(bit))
+			dev_err(dev, "invalid bit number\n");
+		else
+			isr_statistics.test++;
+	} else {
+		if (hw_intr_clear(bit))
+			dev_err(dev, "invalid bit number\n");
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(inters, 0600, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int mode;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	mode = hw_port_test_get();
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int mode;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (kstrtouint(buf, 10, &mode)) {
+		dev_err(dev, "<mode>: set port test mode");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (hw_port_test_set(mode))
+		dev_err(dev, "invalid mode\n");
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(port_test, 0600, show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	for (i = 0; i < hw_ep_max/2; i++) {
+		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+		struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
+
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "EP=%02i: RX=%08X TX=%08X\n",
+			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+				       " %04X:    %08X    %08X\n", j,
+				       *((u32 *)mEpRx->qh.ptr + j),
+				       *((u32 *)mEpTx->qh.ptr + j));
+		}
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(qheads, 0400, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+#define DUMP_ENTRIES	512
+static ssize_t show_registers(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 *dump;
+	unsigned int i, k, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+	if (!dump)
+		return 0;
+
+	spin_lock_irqsave(udc->lock, flags);
+	k = hw_register_read(dump, DUMP_ENTRIES);
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	for (i = 0; i < k; i++) {
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "reg[0x%04X] = 0x%08X\n",
+			       i * (unsigned int)sizeof(u32), dump[i]);
+	}
+	kfree(dump);
+
+	return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long addr, data, flags;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+		dev_err(dev, "<addr> <data>: write data to register address");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (hw_register_write(addr, data))
+		dev_err(dev, "invalid address range\n");
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(registers, 0600, show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	struct list_head   *ptr = NULL;
+	struct ci13xxx_req *req = NULL;
+	unsigned int i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	for (i = 0; i < hw_ep_max; i++)
+		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+		{
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+					"EP=%02i: TD=%08X %s\n",
+					i % hw_ep_max/2, (u32)req->dma,
+					((i < hw_ep_max/2) ? "RX" : "TX"));
+
+			for (j = 0; j < qSize; j++)
+				n += scnprintf(buf + n, PAGE_SIZE - n,
+						" %04X:    %08X\n", j,
+						*((u32 *)req->ptr + j));
+		}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(requests, 0400, show_requests, NULL);
+
+/* EP# and Direction */
+static ssize_t prime_ept(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx_ep *mEp;
+	unsigned int ep_num, dir;
+	int n;
+	struct ci13xxx_req *mReq = NULL;
+
+	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
+		dev_err(dev, "<ep_num> <dir>: prime the ep");
+		goto done;
+	}
+
+	if (dir)
+		mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mEp = &udc->ci13xxx_ep[ep_num];
+
+	n = hw_ep_bit(mEp->num, mEp->dir);
+	mReq =  list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+	mEp->qh.ptr->td.next   = mReq->dma;
+	mEp->qh.ptr->td.token &= ~TD_STATUS;
+
+	/* Makes sure that above write goes through */
+	wmb();
+
+	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
+	while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
+		cpu_relax();
+
+	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s\n", __func__,
+			hw_cread(CAP_ENDPTPRIME, ~0),
+			hw_cread(CAP_ENDPTSTAT, ~0),
+			mEp->num, mEp->dir ? "IN" : "OUT");
+done:
+	return count;
+
+}
+static DEVICE_ATTR(prime, 0200, NULL, prime_ept);
+
+/* EP# and Direction */
+static ssize_t print_dtds(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx_ep *mEp;
+	unsigned int ep_num, dir;
+	int n;
+	struct list_head   *ptr = NULL;
+	struct ci13xxx_req *req = NULL;
+
+	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
+		dev_err(dev, "<ep_num> <dir>: to print dtds");
+		goto done;
+	}
+
+	if (dir)
+		mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mEp = &udc->ci13xxx_ep[ep_num];
+
+	n = hw_ep_bit(mEp->num, mEp->dir);
+	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s dTD_update_fail_count: %lu mEp->dTD_update_fail_count: %lu mEp->dTD_active_re_q_count: %lu mEp->prime_fail_count: %lu\n",
+			__func__,
+			hw_cread(CAP_ENDPTPRIME, ~0),
+			hw_cread(CAP_ENDPTSTAT, ~0),
+			mEp->num, mEp->dir ? "IN" : "OUT",
+			udc->dTD_update_fail_count,
+			mEp->dTD_update_fail_count,
+			mEp->dTD_active_re_q_count,
+			mEp->prime_fail_count);
+
+	pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
+			mEp->qh.ptr->cap, mEp->qh.ptr->curr,
+			mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
+
+	list_for_each(ptr, &mEp->qh.queue) {
+		req = list_entry(ptr, struct ci13xxx_req, queue);
+
+		pr_info("\treq:%pKa next:%08x token:%08x page0:%08x status:%d\n",
+				&req->dma, req->ptr->next, req->ptr->token,
+				req->ptr->page[0], req->req.status);
+	}
+done:
+	return count;
+
+}
+static DEVICE_ATTR(dtds, 0200, NULL, print_dtds);
+
+static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int ret = 0;
+
+	trace();
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!udc->gadget.remote_wakeup) {
+		ret = -EOPNOTSUPP;
+		dbg_trace("remote wakeup feature is not enabled\n");
+		goto out;
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&_gadget->dev);
+
+	udc->udc_driver->notify_event(udc,
+		CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
+
+	if (udc->transceiver)
+		usb_phy_set_suspend(udc->transceiver, 0);
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
+		ret = -EINVAL;
+		dbg_trace("port is not suspended\n");
+		pm_runtime_put(&_gadget->dev);
+		goto out;
+	}
+	hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
+out:
+	spin_unlock_irqrestore(udc->lock, flags);
+	return ret;
+}
+
+static void usb_do_remote_wakeup(struct work_struct *w)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+	bool do_wake;
+
+	/*
+	 * This work can not be canceled from interrupt handler. Check
+	 * if wakeup conditions are still met.
+	 */
+	spin_lock_irqsave(udc->lock, flags);
+	do_wake = udc->suspended && udc->gadget.remote_wakeup;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (do_wake)
+		ci13xxx_wakeup(&udc->gadget);
+}
+
+static ssize_t usb_remote_wakeup(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+
+	ci13xxx_wakeup(&udc->gadget);
+
+	return count;
+}
+static DEVICE_ATTR(wakeup, 0200, 0, usb_remote_wakeup);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+static int __maybe_unused dbg_create_files(struct device *dev)
+{
+	int retval = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+	retval = device_create_file(dev, &dev_attr_device);
+	if (retval)
+		goto done;
+	retval = device_create_file(dev, &dev_attr_driver);
+	if (retval)
+		goto rm_device;
+	retval = device_create_file(dev, &dev_attr_events);
+	if (retval)
+		goto rm_driver;
+	retval = device_create_file(dev, &dev_attr_inters);
+	if (retval)
+		goto rm_events;
+	retval = device_create_file(dev, &dev_attr_port_test);
+	if (retval)
+		goto rm_inters;
+	retval = device_create_file(dev, &dev_attr_qheads);
+	if (retval)
+		goto rm_port_test;
+	retval = device_create_file(dev, &dev_attr_registers);
+	if (retval)
+		goto rm_qheads;
+	retval = device_create_file(dev, &dev_attr_requests);
+	if (retval)
+		goto rm_registers;
+	retval = device_create_file(dev, &dev_attr_wakeup);
+	if (retval)
+		goto rm_remote_wakeup;
+	retval = device_create_file(dev, &dev_attr_prime);
+	if (retval)
+		goto rm_prime;
+	retval = device_create_file(dev, &dev_attr_dtds);
+	if (retval)
+		goto rm_dtds;
+
+	return 0;
+
+rm_dtds:
+	device_remove_file(dev, &dev_attr_dtds);
+rm_prime:
+	device_remove_file(dev, &dev_attr_prime);
+rm_remote_wakeup:
+	device_remove_file(dev, &dev_attr_wakeup);
+ rm_registers:
+	device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+	device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+	device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+	device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+	device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+	device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+	device_remove_file(dev, &dev_attr_device);
+ done:
+	return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+static int __maybe_unused dbg_remove_files(struct device *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+	device_remove_file(dev, &dev_attr_requests);
+	device_remove_file(dev, &dev_attr_registers);
+	device_remove_file(dev, &dev_attr_qheads);
+	device_remove_file(dev, &dev_attr_port_test);
+	device_remove_file(dev, &dev_attr_inters);
+	device_remove_file(dev, &dev_attr_events);
+	device_remove_file(dev, &dev_attr_driver);
+	device_remove_file(dev, &dev_attr_device);
+	device_remove_file(dev, &dev_attr_wakeup);
+	return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep:  endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+	return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+static void ep_prime_timer_func(unsigned long data)
+{
+	struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
+	struct ci13xxx_req *req;
+	struct list_head *ptr = NULL;
+	int n = hw_ep_bit(mep->num, mep->dir);
+	unsigned long flags;
+
+
+	spin_lock_irqsave(mep->lock, flags);
+
+	if (_udc && (!_udc->vbus_active || _udc->suspended)) {
+		pr_debug("ep%d%s prime timer when vbus_active=%d,suspend=%d\n",
+			mep->num, mep->dir ? "IN" : "OUT",
+			_udc->vbus_active, _udc->suspended);
+		goto out;
+	}
+
+	if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
+		goto out;
+
+	if (list_empty(&mep->qh.queue))
+		goto out;
+
+	req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
+
+	/* clean speculative fetches on req->ptr->token */
+	mb();
+	if (!(TD_STATUS_ACTIVE & req->ptr->token))
+		goto out;
+
+	mep->prime_timer_count++;
+	if (mep->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+		mep->prime_timer_count = 0;
+		pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
+				mep->num, mep->dir ? "IN" : "OUT",
+				mep->qh.ptr->cap, mep->qh.ptr->curr,
+				mep->qh.ptr->td.next, mep->qh.ptr->td.token);
+		list_for_each(ptr, &mep->qh.queue) {
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+			pr_info("\treq:%pKa:%08xtkn:%08xpage0:%08xsts:%d\n",
+					&req->dma, req->ptr->next,
+					req->ptr->token, req->ptr->page[0],
+					req->req.status);
+		}
+		dbg_usb_op_fail(0xFF, "PRIMEF", mep);
+		mep->prime_fail_count++;
+	} else {
+		mod_timer(&mep->prime_timer, EP_PRIME_CHECK_DELAY);
+	}
+
+	spin_unlock_irqrestore(mep->lock, flags);
+	return;
+
+out:
+	mep->prime_timer_count = 0;
+	spin_unlock_irqrestore(mep->lock, flags);
+
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	unsigned int i;
+	int ret = 0;
+	unsigned int length = mReq->req.length;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK, %pK", mEp, mReq);
+
+	/* don't queue twice */
+	if (mReq->req.status == -EALREADY)
+		return -EALREADY;
+
+	mReq->req.status = -EALREADY;
+	if (length && mReq->req.dma == DMA_ERROR_CODE) {
+		mReq->req.dma = dma_map_single(mEp->device, mReq->req.buf,
+					length, mEp->dir ? DMA_TO_DEVICE :
+					DMA_FROM_DEVICE);
+		if (mReq->req.dma == 0)
+			return -ENOMEM;
+
+		mReq->map = 1;
+	}
+
+	if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
+		mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+					   &mReq->zdma);
+		if (mReq->zptr == NULL) {
+			if (mReq->map) {
+				dma_unmap_single(mEp->device, mReq->req.dma,
+					length, mEp->dir ? DMA_TO_DEVICE :
+					DMA_FROM_DEVICE);
+				mReq->req.dma = DMA_ERROR_CODE;
+				mReq->map     = 0;
+			}
+			return -ENOMEM;
+		}
+		memset(mReq->zptr, 0, sizeof(*mReq->zptr));
+		mReq->zptr->next    = TD_TERMINATE;
+		mReq->zptr->token   = TD_STATUS_ACTIVE;
+		if (!mReq->req.no_interrupt)
+			mReq->zptr->token   |= TD_IOC;
+	}
+
+	/*
+	 * TD configuration
+	 * TODO - handle requests which spawns into several TDs
+	 */
+	memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
+	mReq->ptr->token   &= TD_TOTAL_BYTES;
+	mReq->ptr->token   |= TD_STATUS_ACTIVE;
+	if (mReq->zptr) {
+		mReq->ptr->next    = mReq->zdma;
+	} else {
+		mReq->ptr->next    = TD_TERMINATE;
+		if (!mReq->req.no_interrupt)
+			mReq->ptr->token  |= TD_IOC;
+	}
+
+	/* MSM Specific: updating the request as required for
+	 * SPS mode. Enable MSM DMA engine according
+	 * to the UDC private data in the request.
+	 */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mReq->ptr->token = TD_STATUS_ACTIVE;
+			if (mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER)
+				mReq->ptr->next = TD_TERMINATE;
+			else
+				mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+			if (!mReq->req.no_interrupt)
+				mReq->ptr->token |= MSM_ETD_IOC;
+		}
+		mReq->req.dma = 0;
+	}
+
+	mReq->ptr->page[0]  = mReq->req.dma;
+	for (i = 1; i < 5; i++)
+		mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) &
+							~TD_RESERVED_MASK;
+	/* Makes sure that above write goes through */
+	wmb();
+
+	/* Remote Wakeup */
+	if (udc->suspended) {
+		if (!udc->gadget.remote_wakeup) {
+			mReq->req.status = -EAGAIN;
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+
+			return -EAGAIN;
+		}
+
+		usb_phy_set_suspend(udc->transceiver, 0);
+		schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
+	}
+
+	if (!list_empty(&mEp->qh.queue)) {
+		struct ci13xxx_req *mReqPrev;
+		int n = hw_ep_bit(mEp->num, mEp->dir);
+		int tmp_stat;
+		ktime_t start, diff;
+
+		mReqPrev = list_entry(mEp->qh.queue.prev,
+				struct ci13xxx_req, queue);
+		if (mReqPrev->zptr)
+			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+		else
+			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+		/* Makes sure that above write goes through */
+		wmb();
+		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
+			goto done;
+		start = ktime_get();
+		do {
+			hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
+			tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
+			diff = ktime_sub(ktime_get(), start);
+			/* poll for max. 100ms */
+			if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+				if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
+					break;
+				printk_ratelimited(KERN_ERR
+				"%s:queue failed ep#%d %s\n",
+				 __func__, mEp->num, mEp->dir ? "IN" : "OUT");
+				return -EAGAIN;
+			}
+		} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
+		hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
+		if (tmp_stat)
+			goto done;
+	}
+
+	/* Hardware may leave few TDs unprocessed, check and reprime with 1st */
+	if (!list_empty(&mEp->qh.queue)) {
+		struct ci13xxx_req *mReq_active, *mReq_next;
+		u32 i = 0;
+
+		/* Nothing to be done if hardware already finished this TD */
+		if ((TD_STATUS_ACTIVE & mReq->ptr->token) == 0)
+			goto done;
+
+		/* Iterate forward to find first TD with ACTIVE bit set */
+		mReq_active = mReq;
+		list_for_each_entry(mReq_next, &mEp->qh.queue, queue) {
+			i++;
+			mEp->dTD_active_re_q_count++;
+			if (TD_STATUS_ACTIVE & mReq_next->ptr->token) {
+				mReq_active = mReq_next;
+				dbg_event(_usb_addr(mEp), "ReQUE",
+					  mReq_next->ptr->token);
+				pr_debug("!!ReQ(%u-%u-%x)-%u!!\n", mEp->num,
+					 mEp->dir, mReq_next->ptr->token, i);
+				break;
+			}
+		}
+
+		/*  QH configuration */
+		mEp->qh.ptr->td.next = mReq_active->dma;
+		mEp->qh.ptr->td.token &= ~TD_STATUS;
+		goto prime;
+	}
+
+	/*  QH configuration */
+	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mEp->qh.ptr->td.next   |= MSM_ETD_TYPE;
+			i = hw_cread(CAP_ENDPTPIPEID +
+						 mEp->num * sizeof(u32), ~0);
+			/* Read current value of this EPs pipe id */
+			i = (mEp->dir == TX) ?
+				((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
+					(i & MSM_PIPE_ID_MASK);
+			/*
+			 * If requested pipe id is different from current,
+			 * then write it
+			 */
+			if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
+				if (mEp->dir == TX)
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK <<
+							MSM_TX_PIPE_ID_OFS,
+						(mReq->req.udc_priv &
+						 MSM_PIPE_ID_MASK)
+							<< MSM_TX_PIPE_ID_OFS);
+				else
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK,
+						mReq->req.udc_priv &
+							MSM_PIPE_ID_MASK);
+			}
+		}
+	}
+
+	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
+	mEp->qh.ptr->cap |=  QH_ZLT;
+
+prime:
+	/* Makes sure that above write goes through */
+	wmb();   /* synchronize before ep prime */
+
+	ret = hw_ep_prime(mEp->num, mEp->dir,
+			   mEp->type == USB_ENDPOINT_XFER_CONTROL);
+	if (!ret)
+		mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+
+done:
+	return ret;
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	trace("%pK, %pK", mEp, mReq);
+
+	if (mReq->req.status != -EALREADY)
+		return -EINVAL;
+
+	/* clean speculative fetches on req->ptr->token */
+	mb();
+
+	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+		return -EBUSY;
+
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+		if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
+			(mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER))
+			return -EBUSY;
+	if (mReq->zptr) {
+		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+			return -EBUSY;
+
+		/* The controller may access this dTD one more time.
+		 * Defer freeing this to next zero length dTD completion.
+		 * It is safe to assume that controller will no longer
+		 * access the previous dTD after next dTD completion.
+		 */
+		if (mEp->last_zptr)
+			dma_pool_free(mEp->td_pool, mEp->last_zptr,
+					mEp->last_zdma);
+		mEp->last_zptr = mReq->zptr;
+		mEp->last_zdma = mReq->zdma;
+
+		mReq->zptr = NULL;
+	}
+
+	mReq->req.status = 0;
+
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
+				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+
+	mReq->req.status = mReq->ptr->token & TD_STATUS;
+	if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+
+	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
+	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+	mReq->req.actual   = mReq->req.length - mReq->req.actual;
+	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
+
+	return mReq->req.actual;
+}
+
+/**
+ * purge_rw_queue: Purge requests pending at the remote-wakeup
+ * queue and send them to the HW.
+ *
+ * Go over all of the endpoints and push any pending requests to
+ * the HW queue.
+ */
+static void purge_rw_queue(struct ci13xxx *udc)
+{
+	int i;
+	struct ci13xxx_ep  *mEp  = NULL;
+	struct ci13xxx_req *mReq = NULL;
+
+	/*
+	 * Go over all of the endpoints and push any pending requests to
+	 * the HW queue.
+	 */
+	for (i = 0; i < hw_ep_max; i++) {
+		mEp = &udc->ci13xxx_ep[i];
+
+		while (!list_empty(&udc->ci13xxx_ep[i].rw_queue)) {
+			int retval;
+
+			/* pop oldest request */
+			mReq = list_entry(udc->ci13xxx_ep[i].rw_queue.next,
+					  struct ci13xxx_req, queue);
+
+			list_del_init(&mReq->queue);
+
+			retval = _hardware_enqueue(mEp, mReq);
+
+			if (retval != 0) {
+				dbg_event(_usb_addr(mEp), "QUEUE", retval);
+				mReq->req.status = retval;
+				if (mReq->req.complete != NULL) {
+					if (mEp->type ==
+					    USB_ENDPOINT_XFER_CONTROL)
+						mReq->req.complete(
+							&(_udc->ep0in.ep),
+							&mReq->req);
+					else
+						mReq->req.complete(
+							&mEp->ep,
+							&mReq->req);
+				}
+				retval = 0;
+			}
+
+			if (!retval)
+				list_add_tail(&mReq->queue, &mEp->qh.queue);
+			else if (mEp->multi_req)
+				mEp->multi_req = false;
+
+		}
+	}
+
+	udc->rw_pending = false;
+}
+
+/**
+ * restore_original_req: Restore original req's attributes
+ * @mReq: Request
+ *
+ * This function restores original req's attributes.  Call
+ * this function before completing the large req (>16K).
+ */
+static void restore_original_req(struct ci13xxx_req *mReq)
+{
+	mReq->req.buf = mReq->multi.buf;
+	mReq->req.length = mReq->multi.len;
+	if (!mReq->req.status)
+		mReq->req.actual = mReq->multi.actual;
+
+	mReq->multi.len = 0;
+	mReq->multi.actual = 0;
+	mReq->multi.buf = NULL;
+}
+
+/**
+ * release_ep_request: Free and endpoint request and release
+ * resources
+ * @mReq: request
+ * @mEp: endpoint
+ *
+ */
+static void release_ep_request(struct ci13xxx_ep  *mEp,
+			       struct ci13xxx_req *mReq)
+{
+	struct ci13xxx_ep *mEpTemp = mEp;
+
+	unsigned int val;
+
+	/* MSM Specific: Clear end point specific register */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			val = hw_cread(CAP_ENDPTPIPEID +
+				mEp->num * sizeof(u32),
+				~0);
+
+			if (val != MSM_EP_PIPE_ID_RESET_VAL)
+				hw_cwrite(
+					CAP_ENDPTPIPEID +
+					 mEp->num * sizeof(u32),
+					~0, MSM_EP_PIPE_ID_RESET_VAL);
+		}
+	}
+	mReq->req.status = -ESHUTDOWN;
+
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma,
+			mReq->req.length,
+			mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
+	if (mEp->multi_req) {
+		restore_original_req(mReq);
+		mEp->multi_req = false;
+	}
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+			mReq->req.length)
+			mEpTemp = &_udc->ep0in;
+		mReq->req.complete(&mEpTemp->ep, &mReq->req);
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mReq->req.complete = NULL;
+		spin_lock(mEp->lock);
+	}
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	trace("%pK", mEp);
+
+	if (mEp == NULL)
+		return -EINVAL;
+
+	del_timer(&mEp->prime_timer);
+	mEp->prime_timer_count = 0;
+
+	hw_ep_flush(mEp->num, mEp->dir);
+
+	while (!list_empty(&mEp->qh.queue)) {
+		/* pop oldest request */
+		struct ci13xxx_req *mReq =
+			list_entry(mEp->qh.queue.next,
+				   struct ci13xxx_req, queue);
+		list_del_init(&mReq->queue);
+
+		release_ep_request(mEp, mReq);
+	}
+
+	/* Clear the requests pending at the remote-wakeup queue */
+	while (!list_empty(&mEp->rw_queue)) {
+
+		/* pop oldest request */
+		struct ci13xxx_req *mReq =
+			list_entry(mEp->rw_queue.next,
+				   struct ci13xxx_req, queue);
+
+		list_del_init(&mReq->queue);
+
+		release_ep_request(mEp, mReq);
+	}
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+{
+	struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	trace("%pK", gadget);
+
+	if (gadget == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.remote_wakeup = 0;
+	udc->suspended = 0;
+	udc->configured = 0;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	udc->driver->disconnect(gadget);
+
+	spin_lock_irqsave(udc->lock, flags);
+	_ep_nuke(&udc->ep0out);
+	_ep_nuke(&udc->ep0in);
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	int retval;
+
+	trace("%pK", udc);
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	dbg_event(0xFF, "BUS RST", 0);
+
+	spin_unlock(udc->lock);
+
+	if (udc->suspended) {
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->driver->resume(&udc->gadget);
+		udc->suspended = 0;
+	}
+
+	/*stop charging upon reset */
+	if (udc->transceiver)
+		usb_phy_set_power(udc->transceiver, 100);
+
+	retval = _gadget_stop_activity(&udc->gadget);
+	if (retval)
+		goto done;
+
+	if (udc->rw_pending)
+		purge_rw_queue(udc);
+
+	_udc->skip_flush = false;
+	retval = hw_usb_reset();
+	if (retval)
+		goto done;
+
+	spin_lock(udc->lock);
+
+ done:
+	if (retval)
+		err("error: %i", retval);
+}
+
+/**
+ * isr_resume_handler: USB PCI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_resume_handler(struct ci13xxx *udc)
+{
+	udc->gadget.speed = hw_port_is_high_speed() ?
+		USB_SPEED_HIGH : USB_SPEED_FULL;
+	if (udc->suspended) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			  CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->suspended = 0;
+		udc->driver->resume(&udc->gadget);
+		spin_lock(udc->lock);
+
+		if (udc->rw_pending)
+			purge_rw_queue(udc);
+
+	}
+}
+
+/**
+ * isr_resume_handler: USB SLI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_suspend_handler(struct ci13xxx *udc)
+{
+	if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		udc->vbus_active) {
+		if (udc->suspended == 0) {
+			spin_unlock(udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			if (udc->udc_driver->notify_event)
+				udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_SUSPEND_EVENT);
+			if (udc->transceiver)
+				usb_phy_set_suspend(udc->transceiver, 1);
+			spin_lock(udc->lock);
+			udc->suspended = 1;
+		}
+	}
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	trace("%pK, %pK", ep, req);
+
+	if (ep == NULL || req == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	if (req->status)
+		err("GET_STATUS failed");
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @udc: udc struct
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx *udc,
+				   struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_ep *mEp = &udc->ep0in;
+	struct usb_request *req = udc->status;
+	int dir, num, retval;
+
+	trace("%pK, %pK", mEp, setup);
+
+	if (mEp == NULL || setup == NULL)
+		return -EINVAL;
+
+	req->complete = isr_get_status_complete;
+	req->length   = 2;
+	req->buf      = udc->status_buf;
+
+	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		/* Assume that device is bus powered for now. */
+		*((u16 *)req->buf) = _udc->gadget.remote_wakeup << 1;
+		retval = 0;
+	} else if ((setup->bRequestType & USB_RECIP_MASK) ==
+							USB_RECIP_ENDPOINT) {
+		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+			TX : RX;
+		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+		*((u16 *)req->buf) = hw_ep_get_halt(num, dir);
+	}
+	/* else do nothing; reserved for future use */
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, req, GFP_ATOMIC);
+	spin_lock(mEp->lock);
+	return retval;
+}
+
+/**
+ * isr_setup_status_complete: setup_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock. Put the port in test mode if test mode
+ * feature is selected.
+ */
+static void
+isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx *udc = req->context;
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (udc->test_mode)
+		hw_port_test_set(udc->test_mode);
+	spin_unlock_irqrestore(udc->lock, flags);
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @udc: udc struct
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx *udc)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	int retval;
+	struct ci13xxx_ep *mEp;
+
+	trace("%pK", udc);
+
+	mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
+	udc->status->context = udc;
+	udc->status->complete = isr_setup_status_complete;
+	udc->status->length = 0;
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
+	spin_lock(mEp->lock);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_req *mReq, *mReqTemp;
+	struct ci13xxx_ep *mEpTemp = mEp;
+	int retval = 0;
+	int req_dequeue = 1;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK", mEp);
+
+	if (list_empty(&mEp->qh.queue))
+		return 0;
+
+	del_timer(&mEp->prime_timer);
+	mEp->prime_timer_count = 0;
+	list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+			queue) {
+dequeue:
+		retval = _hardware_dequeue(mEp, mReq);
+		if (retval < 0) {
+			/*
+			 * FIXME: don't know exact delay
+			 * required for HW to update dTD status
+			 * bits. This is a temporary workaround till
+			 * HW designers come back on this.
+			 */
+			if (retval == -EBUSY && req_dequeue &&
+				(mEp->dir == 0 || mEp->num == 0)) {
+				req_dequeue = 0;
+				udc->dTD_update_fail_count++;
+				mEp->dTD_update_fail_count++;
+				udelay(10);
+				goto dequeue;
+			}
+			break;
+		}
+		req_dequeue = 0;
+
+		if (mEp->multi_req) { /* Large request in progress */
+			unsigned int remain_len;
+
+			mReq->multi.actual += mReq->req.actual;
+			remain_len = mReq->multi.len - mReq->multi.actual;
+			if (mReq->req.status || !remain_len ||
+				(mReq->req.actual != mReq->req.length)) {
+				restore_original_req(mReq);
+				mEp->multi_req = false;
+			} else {
+				mReq->req.buf = mReq->multi.buf +
+						mReq->multi.actual;
+				mReq->req.length = min_t(unsigned int,
+							remain_len,
+							4 * CI13XXX_PAGE_SIZE);
+
+				mReq->req.status = -EINPROGRESS;
+				mReq->req.actual = 0;
+				list_del_init(&mReq->queue);
+				retval = _hardware_enqueue(mEp, mReq);
+				if (retval) {
+					err("Large req failed in middle");
+					mReq->req.status = retval;
+					restore_original_req(mReq);
+					mEp->multi_req = false;
+					goto done;
+				} else {
+					list_add_tail(&mReq->queue,
+						&mEp->qh.queue);
+					return 0;
+				}
+			}
+		}
+		list_del_init(&mReq->queue);
+done:
+
+		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+
+		if (mReq->req.complete != NULL) {
+			spin_unlock(mEp->lock);
+			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+					mReq->req.length)
+				mEpTemp = &_udc->ep0in;
+			mReq->req.complete(&mEpTemp->ep, &mReq->req);
+			spin_lock(mEp->lock);
+		}
+	}
+
+	if (retval == -EBUSY)
+		retval = 0;
+	if (retval < 0)
+		dbg_event(_usb_addr(mEp), "DONE", retval);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	unsigned int i;
+	u8 tmode = 0;
+
+	trace("%pK", udc);
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp  = &udc->ci13xxx_ep[i];
+		int type, num, dir, err = -EINVAL;
+		struct usb_ctrlrequest req;
+
+		if (mEp->desc == NULL)
+			continue;   /* not configured */
+
+		if (hw_test_and_clear_complete(i)) {
+			err = isr_tr_complete_low(mEp);
+			if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+				if (err > 0)   /* needs status phase */
+					err = isr_setup_status_phase(udc);
+				if (err < 0) {
+					dbg_event(_usb_addr(mEp),
+						  "ERROR", err);
+					spin_unlock(udc->lock);
+					if (usb_ep_set_halt(&mEp->ep))
+						err("error: ep_set_halt");
+					spin_lock(udc->lock);
+				}
+			}
+		}
+
+		if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+		    !hw_test_and_clear_setup_status(i))
+			continue;
+
+		if (i != 0) {
+			warn("ctrl traffic received at endpoint");
+			continue;
+		}
+
+		/*
+		 * Flush data and handshake transactions of previous
+		 * setup packet.
+		 */
+		_ep_nuke(&udc->ep0out);
+		_ep_nuke(&udc->ep0in);
+
+		/* read_setup_packet */
+		do {
+			hw_test_and_set_setup_guard();
+			memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+			/* Ensure buffer is read before acknowledging to h/w */
+			mb();
+		} while (!hw_test_and_clear_setup_guard());
+
+		type = req.bRequestType;
+
+		udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+		dbg_setup(_usb_addr(mEp), &req);
+
+		switch (req.bRequest) {
+		case USB_REQ_CLEAR_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += hw_ep_max/2;
+				if (!udc->ci13xxx_ep[num].wedge) {
+					spin_unlock(udc->lock);
+					err = usb_ep_clear_halt(
+						&udc->ci13xxx_ep[num].ep);
+					spin_lock(udc->lock);
+					if (err)
+						break;
+				}
+				err = isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+					le16_to_cpu(req.wValue) ==
+					USB_DEVICE_REMOTE_WAKEUP) {
+				if (req.wLength != 0)
+					break;
+				udc->gadget.remote_wakeup = 0;
+				err = isr_setup_status_phase(udc);
+			} else {
+				goto delegate;
+			}
+			break;
+		case USB_REQ_GET_STATUS:
+			if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
+			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 2 ||
+			    le16_to_cpu(req.wValue)  != 0)
+				break;
+			err = isr_get_status_response(udc, &req);
+			break;
+		case USB_REQ_SET_ADDRESS:
+			if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 0 ||
+			    le16_to_cpu(req.wIndex)  != 0)
+				break;
+			err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
+			if (err)
+				break;
+			err = isr_setup_status_phase(udc);
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			if (type == (USB_DIR_OUT|USB_TYPE_STANDARD))
+				udc->configured = !!req.wValue;
+			goto delegate;
+		case USB_REQ_SET_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += hw_ep_max/2;
+
+				spin_unlock(udc->lock);
+				err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+				spin_lock(udc->lock);
+				if (!err)
+					isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+				if (req.wLength != 0)
+					break;
+				switch (le16_to_cpu(req.wValue)) {
+				case USB_DEVICE_REMOTE_WAKEUP:
+					udc->gadget.remote_wakeup = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_TEST_MODE:
+					tmode = le16_to_cpu(req.wIndex) >> 8;
+					switch (tmode) {
+					case TEST_J:
+					case TEST_K:
+					case TEST_SE0_NAK:
+					case TEST_PACKET:
+					case TEST_FORCE_EN:
+						udc->test_mode = tmode;
+						err = isr_setup_status_phase(
+								udc);
+						break;
+					default:
+						break;
+					}
+				default:
+					goto delegate;
+				}
+			} else {
+				goto delegate;
+			}
+			break;
+		default:
+delegate:
+			if (req.wLength == 0)   /* no data phase */
+				udc->ep0_dir = TX;
+
+			spin_unlock(udc->lock);
+			err = udc->driver->setup(&udc->gadget, &req);
+			spin_lock(udc->lock);
+			break;
+		}
+
+		if (err < 0) {
+			dbg_event(_usb_addr(mEp), "ERROR", err);
+
+			spin_unlock(udc->lock);
+			if (usb_ep_set_halt(&mEp->ep))
+				err("error: ep_set_halt");
+			spin_lock(udc->lock);
+		}
+	}
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+		     const struct usb_endpoint_descriptor *desc)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int retval = 0;
+	unsigned long flags;
+	unsigned int mult = 0;
+
+	trace("ep = %pK, desc = %pK", ep, desc);
+
+	if (ep == NULL || desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should enable ctrl endpts */
+
+	mEp->desc = desc;
+
+	if (!list_empty(&mEp->qh.queue))
+		warn("enabling a non-empty endpoint!");
+
+	mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
+	mEp->num  = usb_endpoint_num(desc);
+	mEp->type = usb_endpoint_type(desc);
+
+	mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+
+	dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+	mEp->qh.ptr->cap = 0;
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		mEp->qh.ptr->cap |=  QH_IOS;
+	} else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
+		mEp->qh.ptr->cap &= ~QH_MULT;
+		mult = ((mEp->ep.maxpacket >> QH_MULT_SHIFT) + 1) & 0x03;
+		mEp->qh.ptr->cap |= (mult << ffs_nr(QH_MULT));
+	} else {
+		mEp->qh.ptr->cap |= QH_ZLT;
+	}
+
+	mEp->qh.ptr->cap |=
+		(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+	mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
+
+	/* complete all the updates to ept->head before enabling endpoint*/
+	mb();
+
+	/*
+	 * Enable endpoints in the HW other than ep0 as ep0
+	 * is always enabled
+	 */
+	if (mEp->num)
+		retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int direction, retval = 0;
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL)
+		return -EINVAL;
+	else if (mEp->desc == NULL)
+		return -EBUSY;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should disable ctrl endpts */
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+		retval |= _ep_nuke(mEp);
+		retval |= hw_ep_disable(mEp->num, mEp->dir);
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	mEp->desc = NULL;
+	mEp->ep.desc = NULL;
+	mEp->ep.maxpacket = USHRT_MAX;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = NULL;
+
+	trace("%pK, %i", ep, gfp_flags);
+
+	if (ep == NULL) {
+		err("EINVAL");
+		return NULL;
+	}
+
+	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+	if (mReq != NULL) {
+		INIT_LIST_HEAD(&mReq->queue);
+		mReq->req.dma = DMA_ERROR_CODE;
+
+		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+					   &mReq->dma);
+		if (mReq->ptr == NULL) {
+			kfree(mReq);
+			mReq = NULL;
+		}
+	}
+
+	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+	return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	if (ep == NULL || req == NULL) {
+		err("EINVAL");
+		return;
+	} else if (!list_empty(&mReq->queue)) {
+		err("EBUSY");
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	if (mReq->ptr)
+		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+	kfree(mReq);
+
+	dbg_event(_usb_addr(mEp), "FREE", 0);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+		    gfp_t __maybe_unused gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	int retval = 0;
+	unsigned long flags;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK, %pK, %X", ep, req, gfp_flags);
+
+	if (ep == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+	if (req == NULL || mEp->desc == NULL) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (!udc->softconnect) {
+		retval = -ENODEV;
+		goto done;
+	}
+
+	if (!udc->configured && mEp->type !=
+		USB_ENDPOINT_XFER_CONTROL) {
+		trace("usb is not configured ept #%d, ept name#%s\n",
+			mEp->num, mEp->ep.name);
+		retval = -ESHUTDOWN;
+		goto done;
+	}
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		if (req->length)
+			mEp = (_udc->ep0_dir == RX) ?
+				&_udc->ep0out : &_udc->ep0in;
+		if (!list_empty(&mEp->qh.queue)) {
+			_ep_nuke(mEp);
+			retval = -EOVERFLOW;
+			warn("endpoint ctrl %X nuked", _usb_addr(mEp));
+		}
+	}
+
+	if (ep->endless && udc->gadget.speed == USB_SPEED_FULL) {
+		err("Queueing endless req is not supported for FS");
+		retval = -EINVAL;
+		goto done;
+	}
+
+	/* first nuke then test link, e.g. previous status has not sent */
+	if (!list_empty(&mReq->queue)) {
+		retval = -EBUSY;
+		err("request already in queue");
+		goto done;
+	}
+	if (mEp->multi_req) {
+		retval = -EAGAIN;
+		err("Large request is in progress. come again");
+		goto done;
+	}
+
+	if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
+		if (!list_empty(&mEp->qh.queue)) {
+			retval = -EAGAIN;
+			err("Queue is busy. Large req is not allowed");
+			goto done;
+		}
+		if ((mEp->type != USB_ENDPOINT_XFER_BULK) ||
+				(mEp->dir != RX)) {
+			retval = -EINVAL;
+			err("Larger req is supported only for Bulk OUT");
+			goto done;
+		}
+		mEp->multi_req = true;
+		mReq->multi.len = req->length;
+		mReq->multi.buf = req->buf;
+		req->length = (4 * CI13XXX_PAGE_SIZE);
+	}
+
+	dbg_queue(_usb_addr(mEp), req, retval);
+
+	/* push request */
+	mReq->req.status = -EINPROGRESS;
+	mReq->req.actual = 0;
+
+	if (udc->rw_pending) {
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+		retval = 0;
+		goto done;
+	}
+
+	if (udc->suspended) {
+		/* Remote Wakeup */
+		if (!udc->gadget.remote_wakeup) {
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+			mEp->multi_req = false;
+
+			retval = -EAGAIN;
+			goto done;
+		}
+
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+
+		udc->rw_pending = true;
+		schedule_delayed_work(&udc->rw_work,
+				      REMOTE_WAKEUP_DELAY);
+
+		retval = 0;
+		goto done;
+	}
+
+	retval = _hardware_enqueue(mEp, mReq);
+
+	if (retval == -EALREADY) {
+		dbg_event(_usb_addr(mEp), "QUEUE", retval);
+		retval = 0;
+	}
+	if (!retval)
+		list_add_tail(&mReq->queue, &mEp->qh.queue);
+	else if (mEp->multi_req)
+		mEp->multi_req = false;
+
+ done:
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_ep *mEpTemp = mEp;
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to dequeue while in LPM\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	if (ep == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+	/*
+	 * Only ep0 IN is exposed to composite.  When a req is dequeued
+	 * on ep0, check both ep0 IN and ep0 OUT queues.
+	 */
+	if (req == NULL || mReq->req.status != -EALREADY ||
+		mEp->desc == NULL || list_empty(&mReq->queue) ||
+		(list_empty(&mEp->qh.queue) && ((mEp->type !=
+			USB_ENDPOINT_XFER_CONTROL) ||
+			list_empty(&_udc->ep0out.qh.queue)))) {
+		spin_unlock_irqrestore(mEp->lock, flags);
+		return -EINVAL;
+	}
+
+	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		hw_ep_flush(_udc->ep0out.num, RX);
+		hw_ep_flush(_udc->ep0in.num, TX);
+	} else {
+		hw_ep_flush(mEp->num, mEp->dir);
+	}
+
+	/* pop request */
+	list_del_init(&mReq->queue);
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
+				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+	req->status = -ECONNRESET;
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
+	if (mEp->multi_req) {
+		restore_original_req(mReq);
+		mEp->multi_req = false;
+	}
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+				mReq->req.length)
+			mEpTemp = &_udc->ep0in;
+		mReq->req.complete(&mEpTemp->ep, &mReq->req);
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mReq->req.complete = NULL;
+		spin_lock(mEp->lock);
+	}
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return 0;
+}
+
+static int is_sps_req(struct ci13xxx_req *mReq)
+{
+	return (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID &&
+			mReq->req.udc_priv & MSM_SPS_MODE);
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx *udc = _udc;
+	int direction, retval = 0;
+	unsigned long flags;
+
+	trace("%pK, %i", ep, value);
+
+	if (ep == NULL || mEp->desc == NULL)
+		return -EINVAL;
+
+	if (udc->suspended) {
+		dev_err(udc->transceiver->dev,
+			"%s: Unable to halt EP while suspended\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+	/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+	if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+		!list_empty(&mEp->qh.queue) &&
+		!is_sps_req(list_entry(mEp->qh.queue.next, struct ci13xxx_req,
+							   queue))){
+		spin_unlock_irqrestore(mEp->lock, flags);
+		return -EAGAIN;
+	}
+#endif
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "HALT", value);
+		retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
+
+		if (!value)
+			mEp->wedge = 0;
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL || mEp->desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "WEDGE", 0);
+	mEp->wedge = 1;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+
+	return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+	struct ci13xxx *udc = _udc;
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL) {
+		err("%02X: -EINVAL", _usb_addr(mEp));
+		return;
+	}
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to fifo_flush while in LPM\n",
+				__func__);
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+	/*
+	 * _ep_nuke() takes care of flushing the endpoint.
+	 * some function drivers expect udc to retire all
+	 * pending requests upon flushing an endpoint.  There
+	 * is no harm in doing it.
+	 */
+	_ep_nuke(mEp);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+	.enable	       = ep_enable,
+	.disable       = ep_disable,
+	.alloc_request = ep_alloc_request,
+	.free_request  = ep_free_request,
+	.queue	       = ep_queue,
+	.dequeue       = ep_dequeue,
+	.set_halt      = ep_set_halt,
+	.set_wedge     = ep_set_wedge,
+	.fifo_flush    = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int gadget_ready = 0;
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+		return -EOPNOTSUPP;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->vbus_active = is_active;
+	if (udc->driver)
+		gadget_ready = 1;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (!gadget_ready)
+		return 0;
+
+	if (is_active) {
+		hw_device_reset(udc);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		/* Enable BAM (if needed) before starting controller */
+		if (udc->softconnect) {
+			dbg_event(0xFF, "BAM EN2",
+				_gadget->bam2bam_func_enabled);
+			msm_usb_bam_enable(CI_CTRL,
+				_gadget->bam2bam_func_enabled);
+			hw_device_state(udc->ep0out.qh.dma);
+		}
+	} else {
+		hw_device_state(0);
+		_gadget_stop_activity(&udc->gadget);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_DISCONNECT_EVENT);
+	}
+
+	return 0;
+}
+
+#define VBUS_DRAW_BUF_LEN 10
+#define MAX_OVERRIDE_VBUS_ALLOWED 900	/* 900 mA */
+static char vbus_draw_mA[VBUS_DRAW_BUF_LEN];
+module_param_string(vbus_draw_mA, vbus_draw_mA, VBUS_DRAW_BUF_LEN, 0644);
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned int mA)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned int override_mA = 0;
+
+	/* override param to draw more current if battery draining faster */
+	if ((mA == CONFIG_USB_GADGET_VBUS_DRAW) &&
+		(vbus_draw_mA[0] != '\0')) {
+		if ((!kstrtoint(vbus_draw_mA, 10, &override_mA)) &&
+				(override_mA <= MAX_OVERRIDE_VBUS_ALLOWED)) {
+			mA = override_mA;
+		}
+	}
+
+	if (udc->transceiver)
+		return usb_phy_set_power(udc->transceiver, mA);
+	return -ENOTSUPP;
+}
+
+static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->softconnect = is_active;
+	if (((udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) &&
+			!udc->vbus_active) || !udc->driver) {
+		spin_unlock_irqrestore(udc->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&_gadget->dev);
+
+	/* Enable BAM (if needed) before starting controller */
+	if (is_active) {
+		dbg_event(0xFF, "BAM EN1", _gadget->bam2bam_func_enabled);
+		msm_usb_bam_enable(CI_CTRL, _gadget->bam2bam_func_enabled);
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!udc->vbus_active) {
+		spin_unlock_irqrestore(udc->lock, flags);
+		pm_runtime_put_sync(&_gadget->dev);
+		return 0;
+	}
+	if (is_active) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		spin_lock(udc->lock);
+		hw_device_state(udc->ep0out.qh.dma);
+	} else {
+		hw_device_state(0);
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
+
+	return 0;
+}
+
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget);
+
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check  "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops = {
+	.vbus_session	= ci13xxx_vbus_session,
+	.wakeup		= ci13xxx_wakeup,
+	.vbus_draw	= ci13xxx_vbus_draw,
+	.pullup		= ci13xxx_pullup,
+	.udc_start	= ci13xxx_start,
+	.udc_stop	= ci13xxx_stop,
+};
+
+/**
+ * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
+ * @driver: the driver being registered
+ *
+ * Interrupts are enabled here.
+ */
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+	int retval = -ENOMEM;
+
+	trace("%pK", driver);
+
+	if (driver             == NULL ||
+	    driver->setup      == NULL ||
+	    driver->disconnect == NULL)
+		return -EINVAL;
+	else if (udc         == NULL)
+		return -ENODEV;
+	else if (udc->driver != NULL)
+		return -EBUSY;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	info("hw_ep_max = %d", hw_ep_max);
+
+	udc->gadget.dev.driver = NULL;
+
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&udc->gadget.dev);
+
+	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+	retval = usb_ep_enable(&udc->ep0out.ep);
+	if (retval)
+		goto pm_put;
+
+	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+	retval = usb_ep_enable(&udc->ep0in.ep);
+	if (retval)
+		goto pm_put;
+	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_KERNEL);
+	if (!udc->status) {
+		retval = -ENOMEM;
+		goto pm_put;
+	}
+
+	udc->status_buf = kzalloc(2 + udc->gadget.extra_buf_alloc,
+				GFP_KERNEL); /* for GET_STATUS */
+	if (!udc->status_buf) {
+		usb_ep_free_request(&udc->ep0in.ep, udc->status);
+		retval = -ENOMEM;
+		goto pm_put;
+	}
+	spin_lock_irqsave(udc->lock, flags);
+
+	udc->gadget.ep0 = &udc->ep0in.ep;
+	/* bind gadget */
+	driver->driver.bus     = NULL;
+	udc->gadget.dev.driver = &driver->driver;
+
+	udc->driver = driver;
+	if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+		if (udc->vbus_active) {
+			if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+				hw_device_reset(udc);
+		} else {
+			goto done;
+		}
+	}
+
+	if (!udc->softconnect)
+		goto done;
+
+	retval = hw_device_state(udc->ep0out.qh.dma);
+
+done:
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (udc->udc_driver->notify_event)
+		udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_UDC_STARTED_EVENT);
+pm_put:
+	pm_runtime_put(&udc->gadget.dev);
+
+	return retval;
+}
+
+/**
+ * ci13xxx_stop: unregister a gadget driver
+ *
+ * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
+ */
+static int ci13xxx_stop(struct usb_gadget *gadget)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+			udc->vbus_active) {
+		hw_device_state(0);
+		spin_unlock_irqrestore(udc->lock, flags);
+		_gadget_stop_activity(&udc->gadget);
+		spin_lock_irqsave(udc->lock, flags);
+	}
+
+	udc->driver = NULL;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	usb_ep_free_request(&udc->ep0in.ep, udc->status);
+	kfree(udc->status_buf);
+
+	return 0;
+}
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: global interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(void)
+{
+	struct ci13xxx *udc = _udc;
+	irqreturn_t retval;
+	u32 intr;
+
+	trace();
+
+	if (udc == NULL) {
+		err("ENODEV");
+		return IRQ_HANDLED;
+	}
+
+	spin_lock(udc->lock);
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		spin_unlock(udc->lock);
+		return IRQ_NONE;
+	}
+
+	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+		if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
+				USBMODE_CM_DEVICE) {
+			spin_unlock(udc->lock);
+			return IRQ_NONE;
+		}
+	}
+	intr = hw_test_and_clear_intr_active();
+	if (intr) {
+		isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
+		isr_statistics.hndl.idx &= ISR_MASK;
+		isr_statistics.hndl.cnt++;
+
+		/* order defines priority - do NOT change it */
+		if (USBi_URI & intr) {
+			isr_statistics.uri++;
+			if (!hw_cread(CAP_PORTSC, PORTSC_PR))
+				pr_info("%s: USB reset interrupt is delayed\n",
+								__func__);
+			isr_reset_handler(udc);
+		}
+		if (USBi_PCI & intr) {
+			isr_statistics.pci++;
+			isr_resume_handler(udc);
+		}
+		if (USBi_UEI & intr)
+			isr_statistics.uei++;
+		if (USBi_UI  & intr) {
+			isr_statistics.ui++;
+			isr_tr_complete_handler(udc);
+		}
+		if (USBi_SLI & intr) {
+			isr_suspend_handler(udc);
+			isr_statistics.sli++;
+		}
+		retval = IRQ_HANDLED;
+	} else {
+		isr_statistics.none++;
+		retval = IRQ_NONE;
+	}
+	spin_unlock(udc->lock);
+
+	return retval;
+}
+
+static void destroy_eps(struct ci13xxx *ci)
+{
+	int i;
+
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+
+		dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+	}
+}
+
+/**
+ * udc_probe: parent probe must call this to initialize UDC
+ * @dev:  parent device
+ * @regs: registers base address
+ * @name: driver name
+ *
+ * This function returns an error code
+ * No interrupts active, the IRQ has not been requested yet
+ * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
+ */
+static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
+		void __iomem *regs)
+{
+	struct ci13xxx *udc;
+	struct ci13xxx_platform_data *pdata;
+	int retval = 0, i, j;
+
+	trace("%pK, %pK, %pK", dev, regs, driver->name);
+
+	if (dev == NULL || regs == NULL || driver == NULL ||
+			driver->name == NULL)
+		return -EINVAL;
+
+	udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
+	if (udc == NULL)
+		return -ENOMEM;
+
+	udc->lock = &udc_lock;
+	udc->regs = regs;
+	udc->udc_driver = driver;
+
+	udc->gadget.ops          = &usb_gadget_ops;
+	udc->gadget.speed        = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed    = USB_SPEED_HIGH;
+	udc->gadget.is_otg       = 0;
+	udc->gadget.name         = driver->name;
+	udc->gadget.is_chipidea  = true;
+
+	/* alloc resources */
+	udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+				       sizeof(struct ci13xxx_qh),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->qh_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_udc;
+	}
+
+	udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+				       sizeof(struct ci13xxx_td),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->td_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_qh_pool;
+	}
+
+	INIT_DELAYED_WORK(&udc->rw_work, usb_do_remote_wakeup);
+
+	retval = hw_device_init(regs);
+	if (retval < 0)
+		goto free_qh_pool;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+		INIT_LIST_HEAD(&mEp->ep.ep_list);
+		INIT_LIST_HEAD(&mEp->rw_queue);
+		setup_timer(&mEp->prime_timer, ep_prime_timer_func,
+			(unsigned long) mEp);
+	}
+
+	arch_setup_dma_ops(&udc->gadget.dev, 0, DMA_BIT_MASK(32), NULL, false);
+	for (i = 0; i < hw_ep_max/2; i++) {
+		for (j = RX; j <= TX; j++) {
+			int k = i + j * hw_ep_max/2;
+			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+					(j == TX)  ? "in" : "out");
+
+			mEp->lock         = udc->lock;
+			mEp->device       = &udc->gadget.dev;
+			mEp->td_pool      = udc->td_pool;
+
+			mEp->ep.name      = mEp->name;
+			mEp->ep.ops       = &usb_ep_ops;
+
+			if (i == 0) {
+				mEp->ep.caps.type_control = true;
+			} else {
+				mEp->ep.caps.type_iso = true;
+				mEp->ep.caps.type_bulk = true;
+				mEp->ep.caps.type_int = true;
+			}
+
+			if (j == TX)
+				mEp->ep.caps.dir_in = true;
+			else
+				mEp->ep.caps.dir_out = true;
+
+			usb_ep_set_maxpacket_limit(&mEp->ep,
+				k ? USHRT_MAX : CTRL_PAYLOAD_MAX);
+
+			INIT_LIST_HEAD(&mEp->qh.queue);
+			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+					&mEp->qh.dma);
+			if (mEp->qh.ptr == NULL)
+				retval = -ENOMEM;
+			else
+				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+			/* skip ep0 out and in endpoints  */
+			if (i == 0)
+				continue;
+
+			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+		}
+	}
+
+	if (retval)
+		goto free_dma_pools;
+
+	udc->gadget.ep0 = &udc->ep0in.ep;
+
+	pdata = dev->platform_data;
+	if (pdata) {
+		if (pdata->enable_axi_prefetch)
+			udc->gadget.extra_buf_alloc = EXTRA_ALLOCATION_SIZE;
+	}
+
+	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (udc->transceiver == NULL) {
+			retval = -ENODEV;
+			goto destroy_eps;
+		}
+	}
+
+	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+		retval = hw_device_reset(udc);
+		if (retval)
+			goto put_transceiver;
+	}
+
+	if (udc->transceiver) {
+		retval = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
+		if (retval)
+			goto put_transceiver;
+	}
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto remove_trans;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	retval = dbg_create_files(&udc->gadget.dev);
+	if (retval) {
+		pr_err("Registering sysfs files for debug failed!!!!\n");
+		goto del_udc;
+	}
+#endif
+
+	pm_runtime_no_callbacks(&udc->gadget.dev);
+	pm_runtime_set_active(&udc->gadget.dev);
+	pm_runtime_enable(&udc->gadget.dev);
+
+	/* Use delayed LPM especially for composition-switch in LPM (suspend) */
+	pm_runtime_set_autosuspend_delay(&udc->gadget.dev, 2000);
+	pm_runtime_use_autosuspend(&udc->gadget.dev);
+
+	_udc = udc;
+	return retval;
+
+del_udc:
+	usb_del_gadget_udc(&udc->gadget);
+remove_trans:
+	if (udc->transceiver)
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+
+	err("error = %i", retval);
+put_transceiver:
+	if (udc->transceiver)
+		usb_put_phy(udc->transceiver);
+destroy_eps:
+	destroy_eps(udc);
+free_dma_pools:
+	dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+	dma_pool_destroy(udc->qh_pool);
+free_udc:
+	kfree(udc);
+	_udc = NULL;
+	return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_remove(void)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		usb_put_phy(udc->transceiver);
+	}
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	dbg_remove_files(&udc->gadget.dev);
+#endif
+	destroy_eps(udc);
+	dma_pool_destroy(udc->td_pool);
+	dma_pool_destroy(udc->qh_pool);
+
+	kfree(udc);
+	_udc = NULL;
+}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
new file mode 100644
index 0000000..8c93080
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -0,0 +1,282 @@
+/*
+ * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Description: MIPS USB IP core family device controller
+ *              Structures, registers and logging macros
+ */
+
+#ifndef _CI13XXX_h_
+#define _CI13XXX_h_
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
+#define ENDPT_MAX          (32)
+#define CTRL_PAYLOAD_MAX   (64)
+#define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
+#define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
+
+/* UDC private data:
+ *  16MSb - Vendor ID | 16 LSb Vendor private data
+ */
+#define CI13XX_REQ_VENDOR_ID(id)  (id & 0xFFFF0000UL)
+
+#define MSM_ETD_TYPE			BIT(1)
+#define MSM_EP_PIPE_ID_RESET_VAL	0x1F001F
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+	/* 0 */
+	u32 next;
+#define TD_TERMINATE          BIT(0)
+#define TD_ADDR_MASK          (0xFFFFFFEUL << 5)
+	/* 1 */
+	u32 token;
+#define TD_STATUS             (0x00FFUL <<  0)
+#define TD_STATUS_TR_ERR      BIT(3)
+#define TD_STATUS_DT_ERR      BIT(5)
+#define TD_STATUS_HALTED      BIT(6)
+#define TD_STATUS_ACTIVE      BIT(7)
+#define TD_MULTO              (0x0003UL << 10)
+#define TD_IOC                BIT(15)
+#define TD_TOTAL_BYTES        (0x7FFFUL << 16)
+	/* 2 */
+	u32 page[5];
+#define TD_CURR_OFFSET        (0x0FFFUL <<  0)
+#define TD_FRAME_NUM          (0x07FFUL <<  0)
+#define TD_RESERVED_MASK      (0x0FFFUL <<  0)
+} __packed __aligned(4);
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+	/* 0 */
+	u32 cap;
+#define QH_IOS                BIT(15)
+#define QH_MAX_PKT            (0x07FFUL << 16)
+#define QH_ZLT                BIT(29)
+#define QH_MULT               (0x0003UL << 30)
+#define QH_MULT_SHIFT         11
+	/* 1 */
+	u32 curr;
+	/* 2 - 8 */
+	struct ci13xxx_td        td;
+	/* 9 */
+	u32 RESERVED;
+	struct usb_ctrlrequest   setup;
+} __packed __aligned(4);
+
+/* cache of larger request's original attributes */
+struct ci13xxx_multi_req {
+	unsigned int	     len;
+	unsigned int	     actual;
+	void                *buf;
+};
+
+/* Extension of usb_request */
+struct ci13xxx_req {
+	struct usb_request   req;
+	unsigned int	     map;
+	struct list_head     queue;
+	struct ci13xxx_td   *ptr;
+	dma_addr_t           dma;
+	struct ci13xxx_td   *zptr;
+	dma_addr_t           zdma;
+	struct ci13xxx_multi_req multi;
+};
+
+/* Extension of usb_ep */
+struct ci13xxx_ep {
+	struct usb_ep                          ep;
+	const struct usb_endpoint_descriptor  *desc;
+	u8                                     dir;
+	u8                                     num;
+	u8                                     type;
+	char                                   name[16];
+	struct {
+		struct list_head   queue;
+		struct ci13xxx_qh *ptr;
+		dma_addr_t         dma;
+	}                                      qh;
+	struct list_head                       rw_queue;
+	int                                    wedge;
+
+	/* global resources */
+	spinlock_t                            *lock;
+	struct device                         *device;
+	struct dma_pool                       *td_pool;
+	struct ci13xxx_td                     *last_zptr;
+	dma_addr_t                            last_zdma;
+	unsigned long                         dTD_update_fail_count;
+	unsigned long                         dTD_active_re_q_count;
+	unsigned long			      prime_fail_count;
+	int				      prime_timer_count;
+	struct timer_list		      prime_timer;
+
+	bool                                  multi_req;
+};
+
+struct ci13xxx;
+struct ci13xxx_udc_driver {
+	const char	*name;
+	unsigned long	 flags;
+	unsigned int nz_itc;
+#define CI13XXX_REGS_SHARED		BIT(0)
+#define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
+#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
+#define CI13XXX_DISABLE_STREAMING	BIT(3)
+#define CI13XXX_ZERO_ITC		BIT(4)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)
+
+#define CI13XXX_CONTROLLER_RESET_EVENT			0
+#define CI13XXX_CONTROLLER_CONNECT_EVENT		1
+#define CI13XXX_CONTROLLER_SUSPEND_EVENT		2
+#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT		3
+#define CI13XXX_CONTROLLER_RESUME_EVENT		4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT		5
+#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT		6
+#define CI13XXX_CONTROLLER_ERROR_EVENT			7
+
+	void	(*notify_event)(struct ci13xxx *udc, unsigned int event);
+	bool    (*in_lpm)(struct ci13xxx *udc);
+};
+
+/* CI13XXX UDC descriptor & global resources */
+struct ci13xxx {
+	spinlock_t		  *lock;      /* ctrl register bank access */
+	void __iomem              *regs;      /* registers address space */
+
+	struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
+	struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
+	struct usb_request        *status;    /* ep0 status request */
+	void                      *status_buf;/* GET_STATUS buffer */
+
+	struct usb_gadget          gadget;     /* USB slave device */
+	struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
+	u32                        ep0_dir;    /* ep0 direction */
+#define ep0out ci13xxx_ep[0]
+#define ep0in  ci13xxx_ep[hw_ep_max / 2]
+	u8                         suspended;  /* suspended by the host */
+	u8                         configured;  /* is device configured */
+	u8                         test_mode;  /* the selected test mode */
+	bool                       rw_pending; /* Remote wakeup pending flag */
+	struct delayed_work        rw_work;    /* remote wakeup delayed work */
+	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
+	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
+	int                        vbus_active; /* is VBUS active */
+	int                        softconnect; /* is pull-up enable allowed */
+	unsigned long dTD_update_fail_count;
+	struct usb_phy            *transceiver; /* Transceiver struct */
+	bool                      skip_flush;   /*
+						 * skip flushing remaining EP
+						 * upon flush timeout for the
+						 * first EP.
+						 */
+};
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS   (32)
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN         BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN         (0x1F << 0)
+#define DCCPARAMS_DC          BIT(7)
+
+/* TESTMODE */
+#define TESTMODE_FORCE        BIT(0)
+
+/* AHB_MODE */
+#define AHB2AHB_BYPASS	      BIT(31)
+
+/* USBCMD */
+#define USBCMD_RS             BIT(0)
+#define USBCMD_RST            BIT(1)
+#define USBCMD_SUTW           BIT(13)
+#define USBCMD_ATDTW          BIT(14)
+
+/* USBSTS & USBINTR */
+#define USBi_UI               BIT(0)
+#define USBi_UEI              BIT(1)
+#define USBi_PCI              BIT(2)
+#define USBi_URI              BIT(6)
+#define USBi_SLI              BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA    BIT(24)
+#define DEVICEADDR_USBADR     (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_FPR            BIT(6)
+#define PORTSC_SUSP           BIT(7)
+#define PORTSC_PR             BIT(8)
+#define PORTSC_HSP            BIT(9)
+#define PORTSC_PTC            (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD            (0x03UL << 25)
+#define    DEVLC_PSPD_HS      (0x02UL << 25)
+
+/* USBMODE */
+#define USBMODE_CM            (0x03UL <<  0)
+#define    USBMODE_CM_IDLE    (0x00UL <<  0)
+#define    USBMODE_CM_DEVICE  (0x02UL <<  0)
+#define    USBMODE_CM_HOST    (0x03UL <<  0)
+#define USBMODE_SLOM          BIT(3)
+#define USBMODE_SDIS          BIT(4)
+#define USBCMD_ITC(n)         (n << 16) /* n = 0, 1, 2, 4, 8, 16, 32, 64 */
+#define USBCMD_ITC_MASK       (0xFF << 16)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS         BIT(0)
+#define ENDPTCTRL_RXT         (0x03UL <<  2)
+#define ENDPTCTRL_RXR         BIT(6)         /* reserved for port 0 */
+#define ENDPTCTRL_RXE         BIT(7)
+#define ENDPTCTRL_TXS         BIT(16)
+#define ENDPTCTRL_TXT         (0x03UL << 18)
+#define ENDPTCTRL_TXR         BIT(22)        /* reserved for port 0 */
+#define ENDPTCTRL_TXE         BIT(23)
+
+/******************************************************************************
+ * LOGGING
+ *****************************************************************************/
+#define ci13xxx_printk(level, format, args...) \
+do { \
+	if (_udc == NULL) \
+		printk(level "[%s] " format "\n", __func__, ## args); \
+	else \
+		dev_printk(level, _udc->gadget.dev.parent, \
+			   "[%s] " format "\n", __func__, ## args); \
+} while (0)
+
+#ifndef err
+#define err(format, args...)    ci13xxx_printk(KERN_ERR, format, ## args)
+#endif
+
+#define warn(format, args...)   ci13xxx_printk(KERN_WARNING, format, ## args)
+#define info(format, args...)   ci13xxx_printk(KERN_INFO, format, ## args)
+
+#ifdef TRACE
+#define trace(format, args...)      ci13xxx_printk(KERN_DEBUG, format, ## args)
+#define dbg_trace(format, args...)  dev_dbg(dev, format, ##args)
+#else
+#define trace(format, args...)      do {} while (0)
+#define dbg_trace(format, args...)  do {} while (0)
+#endif
+
+#endif	/* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4aee8c8..4f8a8f6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -36,7 +36,7 @@
 	 SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW)
 
 /* disable LPM by default */
-static bool disable_l1_for_hs = true;
+static bool disable_l1_for_hs;
 module_param(disable_l1_for_hs, bool, 0644);
 MODULE_PARM_DESC(disable_l1_for_hs,
 	"Disable support for L1 LPM for HS devices");
@@ -167,7 +167,6 @@
 			struct usb_function *f,
 			struct usb_ep *_ep)
 {
-	struct usb_composite_dev	*cdev = get_gadget_data(g);
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
@@ -246,8 +245,12 @@
 			_ep->maxburst = comp_desc->bMaxBurst + 1;
 			break;
 		default:
-			if (comp_desc->bMaxBurst != 0)
+			if (comp_desc->bMaxBurst != 0) {
+				struct usb_composite_dev *cdev;
+
+				cdev = get_gadget_data(g);
 				ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+			}
 			_ep->maxburst = 1;
 			break;
 		}
@@ -1745,7 +1748,9 @@
 			if (!gadget_is_dualspeed(gadget) ||
 			    gadget->speed >= USB_SPEED_SUPER)
 				break;
+			spin_lock(&cdev->lock);
 			device_qual(cdev);
+			spin_unlock(&cdev->lock);
 			value = min_t(int, w_length,
 				sizeof(struct usb_qualifier_descriptor));
 			break;
@@ -1755,7 +1760,9 @@
 				break;
 			/* FALLTHROUGH */
 		case USB_DT_CONFIG:
+			spin_lock(&cdev->lock);
 			value = config_desc(cdev, w_value);
+			spin_unlock(&cdev->lock);
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 			break;
@@ -1766,7 +1773,8 @@
 				value = min(w_length, (u16) value);
 			break;
 		case USB_DT_BOS:
-			if (gadget_is_superspeed(gadget) ||
+			if ((gadget_is_superspeed(gadget) &&
+				(gadget->speed >= USB_SPEED_SUPER)) ||
 				!disable_l1_for_hs) {
 				value = bos_desc(cdev);
 				value = min(w_length, (u16) value);
@@ -2259,7 +2267,8 @@
 	if (!cdev->req)
 		return -ENOMEM;
 
-	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ +
+				(gadget->extra_buf_alloc), GFP_KERNEL);
 	if (!cdev->req->buf)
 		goto fail;
 
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 0e96740..a9344a5 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -64,7 +64,7 @@
 obj-$(CONFIG_USB_F_GSI)         += usb_f_gsi.o
 usb_f_qdss-y			:= f_qdss.o u_qdss.o
 obj-$(CONFIG_USB_F_QDSS)        += usb_f_qdss.o
-usb_f_qcrndis-y			:= f_qc_rndis.o rndis.o u_data_ipa.o
+usb_f_qcrndis-y			:= f_qc_rndis.o u_data_ipa.o
 obj-$(CONFIG_USB_F_QCRNDIS)	+= usb_f_qcrndis.o
-usb_f_rmnet_bam-y		:= f_rmnet.o u_ctrl_qti.o
+usb_f_rmnet_bam-y		:= f_rmnet.o u_ctrl_qti.o u_bam_dmux.o
 obj-$(CONFIG_USB_F_RMNET_BAM)	+= usb_f_rmnet_bam.o
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index 899cbf1..45339c8 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -586,7 +586,8 @@
 
 	/* now allocate requests for our endpoints */
 	for (i = 0; i < TX_REQ_MAX; i++) {
-		req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE);
+		req = acc_request_new(dev->ep_in,
+			BULK_BUFFER_SIZE + cdev->gadget->extra_buf_alloc);
 		if (!req)
 			goto fail;
 		req->complete = acc_complete_in;
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 4f2b847..e9d9918 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -667,7 +667,7 @@
 	/* allocate notification */
 	acm->notify_req = gs_alloc_req(ep,
 			sizeof(struct usb_cdc_notification) + 2,
-			GFP_KERNEL);
+			cdev->gadget->extra_buf_alloc, GFP_KERNEL);
 	if (!acm->notify_req)
 		goto fail;
 
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index 9f7a29a..aaa15da 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -158,6 +158,13 @@
 	.bInterval =		4, /* poll 1 per millisecond */
 };
 
+static struct usb_ss_ep_comp_descriptor ss_as_in_comp_desc = {
+	 .bLength =		 sizeof(ss_as_in_comp_desc),
+	 .bDescriptorType =	 USB_DT_SS_ENDPOINT_COMP,
+
+	 .wBytesPerInterval =	cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+};
+
 /* Standard ISO IN Endpoint Descriptor for highspeed */
 static struct usb_endpoint_descriptor fs_as_in_ep_desc  = {
 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
@@ -198,6 +205,26 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_audio_desc[] = {
+	(struct usb_descriptor_header *)&ac_interface_desc,
+	(struct usb_descriptor_header *)&ac_header_desc,
+
+	(struct usb_descriptor_header *)&input_terminal_desc,
+	(struct usb_descriptor_header *)&output_terminal_desc,
+	(struct usb_descriptor_header *)&feature_unit_desc,
+
+	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
+	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
+	(struct usb_descriptor_header *)&as_header_desc,
+
+	(struct usb_descriptor_header *)&as_type_i_desc,
+
+	(struct usb_descriptor_header *)&hs_as_in_ep_desc,
+	(struct usb_descriptor_header *)&ss_as_in_comp_desc,
+	(struct usb_descriptor_header *)&as_iso_in_desc,
+	NULL,
+};
+
 static struct usb_descriptor_header *fs_audio_desc[] = {
 	(struct usb_descriptor_header *)&ac_interface_desc,
 	(struct usb_descriptor_header *)&ac_header_desc,
@@ -369,15 +396,22 @@
 	s64 msecs;
 	s64 frames;
 	ktime_t now;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->lock, flags);
 	/* audio->substream will be null if we have been closed */
-	if (!audio->substream)
+	if (!audio->substream) {
+		spin_unlock_irqrestore(&audio->lock, flags);
 		return;
+	}
 	/* audio->buffer_pos will be null if we have been stopped */
-	if (!audio->buffer_pos)
+	if (!audio->buffer_pos) {
+		spin_unlock_irqrestore(&audio->lock, flags);
 		return;
+	}
 
 	runtime = audio->substream->runtime;
+	spin_unlock_irqrestore(&audio->lock, flags);
 
 	/* compute number of frames to send */
 	now = ktime_get();
@@ -400,8 +434,21 @@
 
 	while (frames > 0) {
 		req = audio_req_get(audio);
-		if (!req)
+		spin_lock_irqsave(&audio->lock, flags);
+		/* audio->substream will be null if we have been closed */
+		if (!audio->substream) {
+			spin_unlock_irqrestore(&audio->lock, flags);
+			return;
+		}
+		/* audio->buffer_pos will be null if we have been stopped */
+		if (!audio->buffer_pos) {
+			spin_unlock_irqrestore(&audio->lock, flags);
+			return;
+		}
+		if (!req) {
+			spin_unlock_irqrestore(&audio->lock, flags);
 			break;
+		}
 
 		length = frames_to_bytes(runtime, frames);
 		if (length > IN_EP_MAX_PACKET_SIZE)
@@ -427,6 +474,7 @@
 		}
 
 		req->length = length;
+		spin_unlock_irqrestore(&audio->lock, flags);
 		ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
 		if (ret < 0) {
 			pr_err("usb_ep_queue failed ret: %d\n", ret);
@@ -570,14 +618,38 @@
 
 	pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
 
-	ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
-	if (ret)
-		return ret;
+	if (!alt) {
+		usb_ep_disable(audio->in_ep);
+		return 0;
+	}
 
-	usb_ep_enable(audio->in_ep);
+	ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
+	if (ret) {
+		audio->in_ep->desc = NULL;
+		pr_err("config_ep fail for audio ep ret %d\n", ret);
+		return ret;
+	}
+	ret = usb_ep_enable(audio->in_ep);
+	if (ret) {
+		audio->in_ep->desc = NULL;
+		pr_err("failed to enable audio ret %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
+/*
+ * Because the data interface supports multiple altsettings,
+ * this audio_source function *MUST* implement a get_alt() method.
+ */
+static int audio_get_alt(struct usb_function *f, unsigned int intf)
+{
+	struct audio_dev	*audio = func_to_audio(f);
+
+	return audio->in_ep->enabled ? 1 : 0;
+}
+
 static void audio_disable(struct usb_function *f)
 {
 	struct audio_dev	*audio = func_to_audio(f);
@@ -673,6 +745,7 @@
 
 	f->fs_descriptors = fs_audio_desc;
 	f->hs_descriptors = hs_audio_desc;
+	f->ss_descriptors = ss_audio_desc;
 
 	for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
 		req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
@@ -841,6 +914,7 @@
 		.bind = audio_bind,
 		.unbind = audio_unbind,
 		.set_alt = audio_set_alt,
+		.get_alt = audio_get_alt,
 		.setup = audio_setup,
 		.disable = audio_disable,
 		.free_func = audio_free_func,
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c
index 0e86d28..4d4f039 100644
--- a/drivers/usb/gadget/function/f_cdev.c
+++ b/drivers/usb/gadget/function/f_cdev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2013-2018, The Linux Foundation. All rights reserved.
  * Linux Foundation chooses to take subject only to the GPLv2 license terms,
  * and distributes only under these terms.
  *
@@ -709,7 +709,8 @@
 }
 
 static struct usb_request *
-usb_cser_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t flags)
+usb_cser_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_sz,
+			gfp_t flags)
 {
 	struct usb_request *req;
 
@@ -720,7 +721,7 @@
 	}
 
 	req->length = len;
-	req->buf = kmalloc(len, flags);
+	req->buf = kmalloc(len + extra_sz, flags);
 	if (!req->buf) {
 		pr_err("request buf allocation failed\n");
 		usb_ep_free_request(ep, req);
@@ -770,7 +771,8 @@
 	ep->driver_data = cdev;
 	/* allocate notification */
 	port->port_usb.notify_req = usb_cser_alloc_req(ep,
-			sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL);
+			sizeof(struct usb_cdc_notification) + 2,
+			cdev->gadget->extra_buf_alloc, GFP_KERNEL);
 	if (!port->port_usb.notify_req)
 		goto fail;
 
@@ -845,7 +847,7 @@
 }
 
 static int usb_cser_alloc_requests(struct usb_ep *ep, struct list_head *head,
-		int num, int size,
+		int num, int size, size_t extra_sz,
 		void (*cb)(struct usb_ep *ep, struct usb_request *))
 {
 	int i;
@@ -855,7 +857,7 @@
 				ep, head, num, size, cb);
 
 	for (i = 0; i < num; i++) {
-		req = usb_cser_alloc_req(ep, size, GFP_ATOMIC);
+		req = usb_cser_alloc_req(ep, size, extra_sz, GFP_ATOMIC);
 		if (!req) {
 			pr_debug("req allocated:%d\n", i);
 			return list_empty(head) ? -ENOMEM : 0;
@@ -972,6 +974,8 @@
 
 static void usb_cser_start_io(struct f_cdev *port)
 {
+	struct usb_function *f = &port->port_usb.func;
+	struct usb_composite_dev *cdev = f->config->cdev;
 	int ret = -ENODEV;
 	unsigned long	flags;
 
@@ -987,7 +991,7 @@
 
 	ret = usb_cser_alloc_requests(port->port_usb.out,
 				&port->read_pool,
-				BRIDGE_RX_QUEUE_SIZE, BRIDGE_RX_BUF_SIZE,
+				BRIDGE_RX_QUEUE_SIZE, BRIDGE_RX_BUF_SIZE, 0,
 				usb_cser_read_complete);
 	if (ret) {
 		pr_err("unable to allocate out requests\n");
@@ -997,6 +1001,7 @@
 	ret = usb_cser_alloc_requests(port->port_usb.in,
 				&port->write_pool,
 				BRIDGE_TX_QUEUE_SIZE, BRIDGE_TX_BUF_SIZE,
+				cdev->gadget->extra_buf_alloc,
 				usb_cser_write_complete);
 	if (ret) {
 		usb_cser_free_requests(port->port_usb.out, &port->read_pool);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 866c3ec..31c8e4d 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -67,18 +67,27 @@
 static int __must_check
 __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
 
+static LIST_HEAD(inst_list);
+
 /* ffs instance status */
-static DEFINE_MUTEX(ffs_ep_lock);
-static bool ffs_inst_exist;
-static struct f_fs_opts *g_opts;
+#define INST_NAME_SIZE	16
+
+struct ffs_inst_status {
+	char inst_name[INST_NAME_SIZE];
+	struct list_head list;
+	struct mutex ffs_lock;
+	bool inst_exist;
+	struct f_fs_opts *opts;
+	struct ffs_data *ffs_data;
+};
 
 /* Free instance structures */
-static void ffs_inst_clean(struct f_fs_opts *opts);
-static void ffs_inst_clean_delay(void);
-static int ffs_inst_exist_check(void);
-
-/* Global ffs_data pointer */
-static struct ffs_data *g_ffs_data;
+static void ffs_inst_clean(struct f_fs_opts *opts,
+		const char *inst_name);
+static void ffs_inst_clean_delay(const char *inst_name);
+static int ffs_inst_exist_check(const char *inst_name);
+static struct ffs_inst_status *name_to_inst_status(
+		const char *inst_name, bool create_inst);
 
 /* The function structure ***************************************************/
 
@@ -281,7 +290,8 @@
 
 static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
 	__attribute__((warn_unused_result, nonnull));
-static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+static char *ffs_prepare_buffer(const char __user *buf, size_t len,
+	size_t extra_buf_alloc)
 	__attribute__((warn_unused_result, nonnull));
 
 
@@ -357,6 +367,7 @@
 			     size_t len, loff_t *ptr)
 {
 	struct ffs_data *ffs = file->private_data;
+	struct usb_gadget *gadget = ffs->gadget;
 	ssize_t ret;
 	char *data;
 
@@ -365,7 +376,7 @@
 	ffs_log("enter:len %zu state %d setup_state %d flags %lu", len,
 		ffs->state, ffs->setup_state, ffs->flags);
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -388,7 +399,7 @@
 			break;
 		}
 
-		data = ffs_prepare_buffer(buf, len);
+		data = ffs_prepare_buffer(buf, len, 0);
 		if (IS_ERR(data)) {
 			ret = PTR_ERR(data);
 			break;
@@ -460,7 +471,7 @@
 
 		spin_unlock_irq(&ffs->ev.waitq.lock);
 
-		data = ffs_prepare_buffer(buf, len);
+		data = ffs_prepare_buffer(buf, len, gadget->extra_buf_alloc);
 		if (IS_ERR(data)) {
 			ret = PTR_ERR(data);
 			break;
@@ -555,7 +566,7 @@
 	ffs_log("enter:len %zu state %d setup_state %d flags %lu", len,
 		ffs->state, ffs->setup_state, ffs->flags);
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -666,7 +677,7 @@
 	ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state,
 		ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -709,7 +720,7 @@
 	ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state,
 		ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -734,7 +745,7 @@
 	ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state,
 		ffs->setup_state, ffs->flags, atomic_read(&ffs->opened));
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -982,13 +993,19 @@
 	struct ffs_epfile *epfile = file->private_data;
 	struct usb_request *req;
 	struct ffs_ep *ep;
+	struct ffs_data *ffs = epfile->ffs;
 	char *data = NULL;
 	ssize_t ret, data_len = -EINVAL;
 	int halt;
+	size_t extra_buf_alloc = 0;
 
 	ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name,
 		atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE");
 
+	ret = ffs_inst_exist_check(epfile->ffs->dev_name);
+	if (ret < 0)
+		return ret;
+
 	/* to get updated error atomic variable value */
 	smp_mb__before_atomic();
 	if (atomic_read(&epfile->error))
@@ -1075,7 +1092,12 @@
 			data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
 		spin_unlock_irq(&epfile->ffs->eps_lock);
 
-		data = kmalloc(data_len, GFP_KERNEL);
+		extra_buf_alloc = ffs->gadget->extra_buf_alloc;
+		if (io_data->read)
+			data = kmalloc(data_len + extra_buf_alloc,
+					GFP_KERNEL);
+		else
+			data = kmalloc(data_len, GFP_KERNEL);
 		if (unlikely(!data)) {
 			ret = -ENOMEM;
 			goto error_mutex;
@@ -1238,7 +1260,7 @@
 	ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state,
 		epfile->ffs->setup_state, epfile->ffs->flags);
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(epfile->ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -1293,16 +1315,11 @@
 {
 	struct ffs_io_data io_data, *p = &io_data;
 	ssize_t res;
-	int ret;
 
 	ENTER();
 
 	ffs_log("enter");
 
-	ret = ffs_inst_exist_check();
-	if (ret < 0)
-		return ret;
-
 	if (!is_sync_kiocb(kiocb)) {
 		p = kmalloc(sizeof(io_data), GFP_KERNEL);
 		if (unlikely(!p))
@@ -1339,16 +1356,11 @@
 {
 	struct ffs_io_data io_data, *p = &io_data;
 	ssize_t res;
-	int ret;
 
 	ENTER();
 
 	ffs_log("enter");
 
-	ret = ffs_inst_exist_check();
-	if (ret < 0)
-		return ret;
-
 	if (!is_sync_kiocb(kiocb)) {
 		p = kmalloc(sizeof(io_data), GFP_KERNEL);
 		if (unlikely(!p))
@@ -1424,7 +1436,7 @@
 	ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state,
 		epfile->ffs->setup_state, epfile->ffs->flags);
 
-	ret = ffs_inst_exist_check();
+	ret = ffs_inst_exist_check(epfile->ffs->dev_name);
 	if (ret < 0)
 		return ret;
 
@@ -1732,6 +1744,7 @@
 	int ret;
 	void *ffs_dev;
 	struct ffs_data	*ffs;
+	struct ffs_inst_status *inst_status;
 
 	ENTER();
 
@@ -1761,6 +1774,18 @@
 	ffs->private_data = ffs_dev;
 	data.ffs_data = ffs;
 
+	inst_status = name_to_inst_status(ffs->dev_name, false);
+	if (IS_ERR(inst_status)) {
+		ffs_log("failed to find instance (%s)\n",
+				ffs->dev_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Store ffs to global status structure */
+	ffs_dev_lock();
+	inst_status->ffs_data = ffs;
+	ffs_dev_unlock();
+
 	rv = mount_nodev(t, flags, &data, ffs_sb_fill);
 	if (IS_ERR(rv) && data.ffs_data) {
 		ffs_release_dev(data.ffs_data);
@@ -1872,6 +1897,9 @@
 
 static void ffs_data_put(struct ffs_data *ffs)
 {
+	struct ffs_inst_status *inst_status;
+	const char *dev_name;
+
 	ENTER();
 
 	ffs_log("enter");
@@ -1880,16 +1908,20 @@
 	smp_mb__before_atomic();
 	if (unlikely(atomic_dec_and_test(&ffs->ref))) {
 		pr_info("%s(): freeing\n", __func__);
-		/* Clear g_ffs_data */
-		ffs_dev_lock();
-		g_ffs_data = NULL;
-		ffs_dev_unlock();
+		/* Clear ffs from global structure */
+		inst_status = name_to_inst_status(ffs->dev_name, false);
+		if (!IS_ERR(inst_status)) {
+			ffs_dev_lock();
+			inst_status->ffs_data = NULL;
+			ffs_dev_unlock();
+		}
 		ffs_data_clear(ffs);
 		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
 		       waitqueue_active(&ffs->ep0req_completion.wait));
-		kfree(ffs->dev_name);
+		dev_name = ffs->dev_name;
 		kfree(ffs);
-		ffs_inst_clean_delay();
+		ffs_inst_clean_delay(dev_name);
+		kfree(dev_name);
 	}
 
 	ffs_log("exit");
@@ -1956,11 +1988,6 @@
 	/* XXX REVISIT need to update it in some places, or do we? */
 	ffs->ev.can_stall = 1;
 
-	/* Store ffs to g_ffs_data */
-	ffs_dev_lock();
-	g_ffs_data = ffs;
-	ffs_dev_unlock();
-
 	ffs_log("exit");
 
 	return ffs;
@@ -3873,79 +3900,146 @@
 
 /* Function registration interface ******************************************/
 
-static int ffs_inst_exist_check(void)
+static struct ffs_inst_status *name_to_inst_status(
+		const char *inst_name, bool create_inst)
 {
-	mutex_lock(&ffs_ep_lock);
+	struct ffs_inst_status *inst_status;
 
-	if (unlikely(ffs_inst_exist == false)) {
-		mutex_unlock(&ffs_ep_lock);
+	list_for_each_entry(inst_status, &inst_list, list) {
+		if (!strncasecmp(inst_status->inst_name,
+					inst_name, strlen(inst_name)))
+			return inst_status;
+	}
+
+	if (!create_inst)
+		return ERR_PTR(-ENODEV);
+
+	inst_status = kzalloc(sizeof(struct ffs_inst_status),
+					GFP_KERNEL);
+	if (!inst_status)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&inst_status->ffs_lock);
+	snprintf(inst_status->inst_name, INST_NAME_SIZE, inst_name);
+	list_add_tail(&inst_status->list, &inst_list);
+
+	return inst_status;
+}
+
+static int ffs_inst_exist_check(const char *inst_name)
+{
+	struct ffs_inst_status *inst_status;
+
+	inst_status = name_to_inst_status(inst_name, false);
+	if (IS_ERR(inst_status)) {
 		pr_err_ratelimited(
-				"%s: f_fs instance freed already.\n",
-				__func__);
+				"%s: failed to find instance (%s)\n",
+				__func__, inst_name);
 		return -ENODEV;
 	}
 
-	mutex_unlock(&ffs_ep_lock);
+	mutex_lock(&inst_status->ffs_lock);
+
+	if (unlikely(inst_status->inst_exist == false)) {
+		mutex_unlock(&inst_status->ffs_lock);
+		pr_err_ratelimited(
+				"%s: f_fs instance (%s) has been freed already.\n",
+				__func__, inst_name);
+		return -ENODEV;
+	}
+
+	mutex_unlock(&inst_status->ffs_lock);
 
 	return 0;
 }
 
-static void ffs_inst_clean(struct f_fs_opts *opts)
+static void ffs_inst_clean(struct f_fs_opts *opts,
+		const char *inst_name)
 {
-	g_opts = NULL;
+	struct ffs_inst_status *inst_status;
+
+	inst_status = name_to_inst_status(inst_name, false);
+	if (IS_ERR(inst_status)) {
+		pr_err_ratelimited(
+				"%s: failed to find instance (%s)\n",
+				__func__, inst_name);
+		return;
+	}
+
+	inst_status->opts = NULL;
+
 	ffs_dev_lock();
 	_ffs_free_dev(opts->dev);
 	ffs_dev_unlock();
 	kfree(opts);
 }
 
-static void ffs_inst_clean_delay(void)
+static void ffs_inst_clean_delay(const char *inst_name)
 {
-	mutex_lock(&ffs_ep_lock);
+	struct ffs_inst_status *inst_status;
 
-	if (unlikely(ffs_inst_exist == false)) {
-		if (g_opts) {
-			ffs_inst_clean(g_opts);
-			pr_err_ratelimited("%s: Delayed free memory\n",
-					__func__);
-		}
-		mutex_unlock(&ffs_ep_lock);
+	inst_status = name_to_inst_status(inst_name, false);
+	if (IS_ERR(inst_status)) {
+		pr_err_ratelimited(
+				"%s: failed to find (%s) instance\n",
+				__func__, inst_name);
 		return;
 	}
 
-	mutex_unlock(&ffs_ep_lock);
+	mutex_lock(&inst_status->ffs_lock);
+
+	if (unlikely(inst_status->inst_exist == false)) {
+		if (inst_status->opts) {
+			ffs_inst_clean(inst_status->opts, inst_name);
+			pr_err_ratelimited("%s: Delayed free memory\n",
+					__func__);
+		}
+		mutex_unlock(&inst_status->ffs_lock);
+		return;
+	}
+
+	mutex_unlock(&inst_status->ffs_lock);
 }
 
 static void ffs_free_inst(struct usb_function_instance *f)
 {
 	struct f_fs_opts *opts;
+	struct ffs_inst_status *inst_status;
 
 	opts = to_f_fs_opts(f);
 
-	mutex_lock(&ffs_ep_lock);
-	if (opts->dev->ffs_data
-			&& atomic_read(&opts->dev->ffs_data->opened)) {
-		ffs_inst_exist = false;
-		mutex_unlock(&ffs_ep_lock);
-		ffs_log("%s: Dev is open, free mem when dev close\n",
-				__func__);
+	inst_status = name_to_inst_status(opts->dev->name, false);
+	if (IS_ERR(inst_status)) {
+		ffs_log("failed to find (%s) instance\n",
+				opts->dev->name);
 		return;
 	}
 
-	ffs_inst_clean(opts);
-	ffs_inst_exist = false;
-	g_opts = NULL;
-	mutex_unlock(&ffs_ep_lock);
+	mutex_lock(&inst_status->ffs_lock);
+	if (opts->dev->ffs_data
+			&& atomic_read(&opts->dev->ffs_data->opened)) {
+		inst_status->inst_exist = false;
+		mutex_unlock(&inst_status->ffs_lock);
+		ffs_log("Dev is open, free mem when dev (%s) close\n",
+				opts->dev->name);
+		return;
+	}
+
+	ffs_inst_clean(opts, opts->dev->name);
+	inst_status->inst_exist = false;
+	mutex_unlock(&inst_status->ffs_lock);
 }
 
 #define MAX_INST_NAME_LEN	40
 
 static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
 {
-	struct f_fs_opts *opts;
+	struct f_fs_opts *opts, *opts_prev;
+	struct ffs_data *ffs_data_tmp;
 	char *ptr;
 	const char *tmp;
 	int name_len, ret;
+	struct ffs_inst_status *inst_status;
 
 	name_len = strlen(name) + 1;
 	if (name_len > MAX_INST_NAME_LEN)
@@ -3955,13 +4049,22 @@
 	if (!ptr)
 		return -ENOMEM;
 
-	mutex_lock(&ffs_ep_lock);
-	if (g_opts) {
-		mutex_unlock(&ffs_ep_lock);
-		ffs_log("%s: prev inst do not freed yet\n", __func__);
+	inst_status = name_to_inst_status(ptr, true);
+	if (IS_ERR(inst_status)) {
+		ffs_log("failed to create status struct for (%s) instance\n",
+				ptr);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst_status->ffs_lock);
+	opts_prev = inst_status->opts;
+	if (opts_prev) {
+		mutex_unlock(&inst_status->ffs_lock);
+		ffs_log("instance (%s): prev inst do not freed yet\n",
+				inst_status->inst_name);
 		return -EBUSY;
 	}
-	mutex_unlock(&ffs_ep_lock);
+	mutex_unlock(&inst_status->ffs_lock);
 
 	opts = to_f_fs_opts(fi);
 	tmp = NULL;
@@ -3983,8 +4086,9 @@
 	 * ffs_private_data also need to update new allocated opts->dev
 	 * address.
 	 */
-	if (g_ffs_data)
-		opts->dev->ffs_data = g_ffs_data;
+	ffs_data_tmp = inst_status->ffs_data;
+	if (ffs_data_tmp)
+		opts->dev->ffs_data = ffs_data_tmp;
 
 	if (opts->dev->ffs_data)
 		opts->dev->ffs_data->private_data = opts->dev;
@@ -3993,10 +4097,10 @@
 
 	kfree(tmp);
 
-	mutex_lock(&ffs_ep_lock);
-	ffs_inst_exist = true;
-	g_opts = opts;
-	mutex_unlock(&ffs_ep_lock);
+	mutex_lock(&inst_status->ffs_lock);
+	inst_status->inst_exist = true;
+	inst_status->opts = opts;
+	mutex_unlock(&inst_status->ffs_lock);
 
 	return 0;
 }
@@ -4370,14 +4474,23 @@
 		: mutex_lock_interruptible(mutex);
 }
 
-static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+/**
+ * ffs_prepare_buffer() - copy userspace buffer into kernel.
+ * @buf: userspace buffer
+ * @len: length of the buffer
+ * @extra_alloc_buf: Extra buffer allocation if required by UDC.
+ *
+ * This function returns pointer to the copied buffer
+ */
+static char *ffs_prepare_buffer(const char __user *buf, size_t len,
+		size_t extra_buf_alloc)
 {
 	char *data;
 
 	if (unlikely(!len))
 		return NULL;
 
-	data = kmalloc(len, GFP_KERNEL);
+	data = kmalloc(len + extra_buf_alloc, GFP_KERNEL);
 	if (unlikely(!data))
 		return ERR_PTR(-ENOMEM);
 
@@ -4392,6 +4505,24 @@
 	return data;
 }
 
+static void __exit ffs_exit(void)
+{
+	struct ffs_inst_status *inst_status, *inst_status_tmp = NULL;
+
+	list_for_each_entry(inst_status, &inst_list, list) {
+		if (inst_status_tmp) {
+			list_del(&inst_status_tmp->list);
+			kfree(inst_status_tmp);
+		}
+		inst_status_tmp = inst_status;
+	}
+	if (inst_status_tmp) {
+		list_del(&inst_status_tmp->list);
+		kfree(inst_status_tmp);
+	}
+}
+module_exit(ffs_exit);
+
 DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Nazarewicz");
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 37903f9..7d509db 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -307,6 +307,10 @@
 	in_params->data_buff_base_len = d_port->in_request.buf_len *
 					d_port->in_request.num_bufs;
 	in_params->data_buff_base_addr_iova = d_port->in_request.dma;
+	in_params->sgt_xfer_rings = &d_port->in_request.sgt_trb_xfer_ring;
+	in_params->sgt_data_buff = &d_port->in_request.sgt_data_buff;
+	log_event_dbg("%s(): IN: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
+		__func__, in_params->sgt_xfer_rings, in_params->sgt_data_buff);
 	in_params->xfer_scratch.const_buffer_size =
 		gsi_channel_info.const_buffer_size;
 	in_params->xfer_scratch.depcmd_low_addr =
@@ -344,6 +348,13 @@
 			d_port->out_request.num_bufs;
 		out_params->data_buff_base_addr_iova =
 			d_port->out_request.dma;
+		out_params->sgt_xfer_rings =
+			&d_port->out_request.sgt_trb_xfer_ring;
+		out_params->sgt_data_buff = &d_port->out_request.sgt_data_buff;
+		log_event_dbg("%s(): OUT: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
+			__func__, out_params->sgt_xfer_rings,
+			out_params->sgt_data_buff);
+
 		out_params->xfer_scratch.last_trb_addr_iova =
 			gsi_channel_info.last_trb_addr;
 		out_params->xfer_scratch.const_buffer_size =
@@ -497,10 +508,12 @@
 	gsi->d_port.in_channel_handle = -EINVAL;
 	gsi->d_port.out_channel_handle = -EINVAL;
 
-	usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_FREE_TRBS);
+	usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
+							GSI_EP_OP_FREE_TRBS);
 
 	if (gsi->d_port.out_ep)
-		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_FREE_TRBS);
+		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
+							GSI_EP_OP_FREE_TRBS);
 
 	/* free buffers allocated with each TRB */
 	gsi_free_trb_buffer(gsi);
@@ -519,6 +532,9 @@
 	if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend,
 				GSI_EP_OP_CHECK_FOR_SUSPEND)) {
 		ret = -EFAULT;
+		block_db = false;
+		usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
+			GSI_EP_OP_SET_CLR_BLOCK_DBL);
 		goto done;
 	}
 
@@ -1642,11 +1658,10 @@
 
 	buf = (rndis_init_msg_type *)req->buf;
 	if (buf->MessageType == RNDIS_MSG_INIT) {
-		gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
-						gsi->params->dl_max_xfer_size);
-		log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
-				gsi->params->dl_max_xfer_size,
-				gsi->d_port.in_aggr_size);
+		/* honor host dl aggr size */
+		gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
+		log_event_dbg("RNDIS host dl_aggr_size:%d\n",
+				gsi->params->dl_max_xfer_size);
 	}
 }
 
@@ -1945,6 +1960,11 @@
 			ret = -ENOMEM;
 			goto fail1;
 		}
+
+		dma_get_sgtable(dev->parent,
+			&gsi->d_port.in_request.sgt_data_buff,
+			gsi->d_port.in_request.buf_base_addr,
+			gsi->d_port.in_request.dma, len_in);
 	}
 
 	if (gsi->d_port.out_ep && !gsi->d_port.out_request.buf_base_addr) {
@@ -1964,6 +1984,11 @@
 			ret = -ENOMEM;
 			goto fail;
 		}
+
+		dma_get_sgtable(dev->parent,
+			&gsi->d_port.out_request.sgt_data_buff,
+			gsi->d_port.out_request.buf_base_addr,
+			gsi->d_port.out_request.dma, len_out);
 	}
 
 	log_event_dbg("finished allocating trb's buffer\n");
@@ -1994,6 +2019,7 @@
 			gsi->d_port.out_request.buf_base_addr,
 			gsi->d_port.out_request.dma);
 		gsi->d_port.out_request.buf_base_addr = NULL;
+		sg_free_table(&gsi->d_port.out_request.sgt_data_buff);
 	}
 
 	if (gsi->d_port.in_ep &&
@@ -2004,6 +2030,7 @@
 			gsi->d_port.in_request.buf_base_addr,
 			gsi->d_port.in_request.dma);
 		gsi->d_port.in_request.buf_base_addr = NULL;
+		sg_free_table(&gsi->d_port.in_request.sgt_data_buff);
 	}
 }
 
@@ -2054,13 +2081,8 @@
 		/* for rndis and rmnet alt is always 0 update alt accordingly */
 		if (gsi->prot_id == IPA_USB_RNDIS ||
 				gsi->prot_id == IPA_USB_RMNET ||
-				gsi->prot_id == IPA_USB_DIAG) {
-			if (gsi->d_port.in_ep &&
-				!gsi->d_port.in_ep->driver_data)
+				gsi->prot_id == IPA_USB_DIAG)
 				alt = 1;
-			else
-				alt = 0;
-		}
 
 		if (alt > 1)
 			goto notify_ep_disable;
@@ -2353,7 +2375,7 @@
 		if (!ep)
 			goto fail;
 		gsi->d_port.in_ep = ep;
-		msm_ep_config(gsi->d_port.in_ep);
+		msm_ep_config(gsi->d_port.in_ep, NULL);
 		ep->driver_data = cdev;	/* claim */
 	}
 
@@ -2363,7 +2385,7 @@
 		if (!ep)
 			goto fail;
 		gsi->d_port.out_ep = ep;
-		msm_ep_config(gsi->d_port.out_ep);
+		msm_ep_config(gsi->d_port.out_ep, NULL);
 		ep->driver_data = cdev;	/* claim */
 	}
 
@@ -2540,7 +2562,7 @@
 		info.out_epname = "gsi-epout";
 		info.in_req_buf_len = GSI_IN_BUFF_SIZE;
 		gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE;
-		info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
+		info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS;
 		gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
 		info.out_req_buf_len = GSI_OUT_AGGR_SIZE;
 		info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 58a7706..71bea5e 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -34,13 +34,13 @@
 #define GSI_MAX_CTRL_PKT_SIZE 4096
 #define GSI_CTRL_DTR (1 << 0)
 
-
+#define GSI_NUM_IN_RNDIS_BUFFERS 50
 #define GSI_NUM_IN_BUFFERS 15
 #define GSI_IN_BUFF_SIZE 2048
 #define GSI_NUM_OUT_BUFFERS 14
 #define GSI_OUT_AGGR_SIZE 24576
 
-#define GSI_IN_RNDIS_AGGR_SIZE 9216
+#define GSI_IN_RNDIS_AGGR_SIZE 16384
 #define GSI_IN_MBIM_AGGR_SIZE 16384
 #define GSI_IN_RMNET_AGGR_SIZE 16384
 #define GSI_ECM_AGGR_SIZE 2048
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 33ed64f..b24ad72 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2750,7 +2750,8 @@
 		bh->next = bh + 1;
 		++bh;
 buffhds_first_it:
-		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+		bh->buf = kmalloc(FSG_BUFLEN + EXTRA_ALLOCATION_SIZE,
+				GFP_KERNEL);
 		if (unlikely(!bh->buf))
 			goto error_release;
 	} while (--i);
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 239d9bf..714e395 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -497,6 +497,7 @@
 	struct usb_composite_dev *cdev = dev->cdev;
 	struct usb_request *req;
 	struct usb_ep *ep;
+	size_t extra_buf_alloc = cdev->gadget->extra_buf_alloc;
 	int i;
 
 	DBG(cdev, "create_bulk_endpoints dev: %pK\n", dev);
@@ -531,7 +532,8 @@
 retry_tx_alloc:
 	/* now allocate requests for our endpoints */
 	for (i = 0; i < mtp_tx_reqs; i++) {
-		req = mtp_request_new(dev->ep_in, mtp_tx_req_len);
+		req = mtp_request_new(dev->ep_in,
+				mtp_tx_req_len + extra_buf_alloc);
 		if (!req) {
 			if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE)
 				goto fail;
@@ -569,7 +571,8 @@
 		dev->rx_req[i] = req;
 	}
 	for (i = 0; i < INTR_REQ_MAX; i++) {
-		req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE);
+		req = mtp_request_new(dev->ep_intr,
+				INTR_BUFFER_SIZE + extra_buf_alloc);
 		if (!req)
 			goto fail;
 		req->complete = mtp_complete_intr;
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index b0d0020..6f3b623 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1510,7 +1510,8 @@
 	ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
 	if (!ncm->notify_req)
 		goto fail;
-	ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
+	ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT
+			+ (cdev->gadget->extra_buf_alloc), GFP_KERNEL);
 	if (!ncm->notify_req->buf)
 		goto fail;
 	ncm->notify_req->context = ncm;
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
index a8e7092..908805a 100644
--- a/drivers/usb/gadget/function/f_qc_rndis.c
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -102,7 +102,7 @@
 	struct usb_ep			*notify;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
-	struct gadget_ipa_port		bam_port;
+	struct data_port		bam_port;
 	struct cdev			cdev;
 	struct device			*dev;
 	u8				port_num;
diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c
index 64532f6..ffc6897 100644
--- a/drivers/usb/gadget/function/f_rmnet.c
+++ b/drivers/usb/gadget/function/f_rmnet.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,7 +19,6 @@
 #include <linux/usb_bam.h>
 #include <linux/module.h>
 
-#include "u_rmnet.h"
 #include "u_data_ipa.h"
 #include "configfs.h"
 
@@ -31,13 +30,15 @@
 struct f_rmnet {
 	struct usb_function             func;
 	enum qti_port_type		qti_port_type;
-	enum ipa_func_type		func_type;
+	enum bam_dmux_func_type		bam_dmux_func_type;
+	enum data_xport_type		xport_type;
+	enum ipa_func_type		ipa_func_type;
 	struct grmnet			port;
 	int				ifc_id;
 	atomic_t			online;
 	atomic_t			ctrl_online;
 	struct usb_composite_dev	*cdev;
-	struct gadget_ipa_port		ipa_port;
+	struct data_port		bam_port;
 	spinlock_t			lock;
 
 	/* usb eps*/
@@ -219,6 +220,14 @@
 	.bInterfaceProtocol =	0xff,
 };
 
+static struct usb_endpoint_descriptor dpl_fs_data_desc = {
+	.bLength              =	 USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType      =	 USB_DT_ENDPOINT,
+	.bEndpointAddress     =	 USB_DIR_IN,
+	.bmAttributes         =	 USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize       =	 cpu_to_le16(64),
+};
+
 static struct usb_endpoint_descriptor dpl_hs_data_desc = {
 	.bLength              =	 USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType      =	 USB_DT_ENDPOINT,
@@ -243,6 +252,12 @@
 	.wBytesPerInterval    =	 0,
 };
 
+static struct usb_descriptor_header *dpl_fs_data_only_desc[] = {
+	(struct usb_descriptor_header *) &dpl_data_intf_desc,
+	(struct usb_descriptor_header *) &dpl_fs_data_desc,
+	NULL,
+};
+
 static struct usb_descriptor_header *dpl_hs_data_only_desc[] = {
 	(struct usb_descriptor_header *) &dpl_data_intf_desc,
 	(struct usb_descriptor_header *) &dpl_hs_data_desc,
@@ -294,11 +309,22 @@
 
 	if (!strncasecmp("rmnet", name, MAX_INST_NAME_LEN)) {
 		dev->qti_port_type = QTI_PORT_RMNET;
-		dev->func_type = USB_IPA_FUNC_RMNET;
+		dev->xport_type = BAM2BAM_IPA;
+		dev->ipa_func_type = USB_IPA_FUNC_RMNET;
 	} else if (!strncasecmp("dpl", name, MAX_INST_NAME_LEN)) {
 		dev->qti_port_type = QTI_PORT_DPL;
-		dev->func_type = USB_IPA_FUNC_DPL;
+		dev->xport_type = BAM2BAM_IPA;
+		dev->ipa_func_type = USB_IPA_FUNC_DPL;
+	} else if (!strncasecmp("rmnet_bam_dmux", name, MAX_INST_NAME_LEN)) {
+		dev->qti_port_type = QTI_PORT_RMNET;
+		dev->xport_type = BAM_DMUX;
+		dev->bam_dmux_func_type = BAM_DMUX_FUNC_RMNET;
+	} else if (!strncasecmp("dpl_bam_dmux", name, MAX_INST_NAME_LEN)) {
+		dev->qti_port_type = QTI_PORT_DPL;
+		dev->xport_type = BAM_DMUX;
+		dev->bam_dmux_func_type = BAM_DMUX_FUNC_DPL;
 	}
+
 	return 0;
 
 error:
@@ -306,7 +332,8 @@
 }
 
 static struct usb_request *
-frmnet_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t flags)
+frmnet_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_buf_alloc,
+		gfp_t flags)
 {
 	struct usb_request *req;
 
@@ -314,7 +341,7 @@
 	if (!req)
 		return ERR_PTR(-ENOMEM);
 
-	req->buf = kmalloc(len, flags);
+	req->buf = kmalloc(len + extra_buf_alloc, flags);
 	if (!req->buf) {
 		usb_ep_free_request(ep, req);
 		return ERR_PTR(-ENOMEM);
@@ -366,7 +393,8 @@
 	enum usb_ctrl		usb_bam_type;
 	int bam_pipe_num = (dev->qti_port_type == QTI_PORT_DPL) ? 1 : 0;
 
-	ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id);
+	ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id,
+							dev->xport_type);
 	if (ret) {
 		pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
 			__func__, ret);
@@ -374,31 +402,42 @@
 	}
 	if (dev->qti_port_type == QTI_PORT_DPL)
 		dev->port.send_encap_cmd(QTI_PORT_DPL, NULL, 0);
-	dev->ipa_port.cdev = dev->cdev;
-	ipa_data_port_select(dev->func_type);
-	usb_bam_type = usb_bam_get_bam_type(gadget->name);
+	dev->bam_port.cdev = dev->cdev;
+	if (dev->xport_type == BAM_DMUX) {
+		ret = gbam_connect(&dev->bam_port, dev->bam_dmux_func_type);
+		if (ret)
+			pr_err("%s: gbam_connect failed: err:%d\n",
+				__func__, ret);
+	} else {
+		ipa_data_port_select(dev->ipa_func_type);
+		usb_bam_type = usb_bam_get_bam_type(gadget->name);
 
-	if (dev->ipa_port.in) {
-		dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
-			IPA_P_BAM, PEER_PERIPHERAL_TO_USB,
-			USB_BAM_DEVICE, bam_pipe_num);
+		if (dev->bam_port.in) {
+			dst_connection_idx = usb_bam_get_connection_idx(
+						usb_bam_type, IPA_P_BAM,
+						PEER_PERIPHERAL_TO_USB,
+						USB_BAM_DEVICE, bam_pipe_num);
+		}
+		if (dev->bam_port.out) {
+			src_connection_idx = usb_bam_get_connection_idx(
+						usb_bam_type, IPA_P_BAM,
+						USB_TO_PEER_PERIPHERAL,
+						USB_BAM_DEVICE, bam_pipe_num);
+		}
+		if (dst_connection_idx < 0 || src_connection_idx < 0) {
+			pr_err("%s: usb_bam_get_connection_idx failed\n",
+				__func__);
+			gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
+			return -EINVAL;
+		}
+		ret = ipa_data_connect(&dev->bam_port, dev->ipa_func_type,
+				src_connection_idx, dst_connection_idx);
+		if (ret)
+			pr_err("%s: ipa_data_connect failed: err:%d\n",
+				__func__, ret);
 	}
-	if (dev->ipa_port.out) {
-		src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
-			IPA_P_BAM, USB_TO_PEER_PERIPHERAL,
-			USB_BAM_DEVICE, bam_pipe_num);
-	}
-	if (dst_connection_idx < 0 || src_connection_idx < 0) {
-		pr_err("%s: usb_bam_get_connection_idx failed\n",
-			__func__);
-		gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
-		return -EINVAL;
-	}
-	ret = ipa_data_connect(&dev->ipa_port, dev->func_type,
-			src_connection_idx, dst_connection_idx);
+
 	if (ret) {
-		pr_err("%s: ipa_data_connect failed: err:%d\n",
-			__func__, ret);
 		gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
 		return ret;
 	}
@@ -408,7 +447,11 @@
 static int gport_rmnet_disconnect(struct f_rmnet *dev)
 {
 	gqti_ctrl_disconnect(&dev->port, dev->qti_port_type);
-	ipa_data_disconnect(&dev->ipa_port, dev->func_type);
+	if (dev->xport_type == BAM_DMUX)
+		gbam_disconnect(&dev->bam_port, dev->bam_dmux_func_type);
+	else
+		ipa_data_disconnect(&dev->bam_port, dev->ipa_func_type);
+
 	return 0;
 }
 
@@ -474,7 +517,10 @@
 		usb_ep_fifo_flush(dev->notify);
 		frmnet_purge_responses(dev);
 	}
-	ipa_data_suspend(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
+
+	if (dev->xport_type == BAM2BAM_IPA)
+		ipa_data_suspend(&dev->bam_port, dev->ipa_func_type,
+							remote_wakeup_allowed);
 }
 
 static void frmnet_resume(struct usb_function *f)
@@ -489,8 +535,9 @@
 
 	pr_debug("%s: dev: %pK remote_wakeup: %d\n", __func__, dev,
 			remote_wakeup_allowed);
-
-	ipa_data_resume(&dev->ipa_port, dev->func_type, remote_wakeup_allowed);
+	if (dev->xport_type == BAM2BAM_IPA)
+		ipa_data_resume(&dev->bam_port, dev->ipa_func_type,
+							remote_wakeup_allowed);
 }
 
 static void frmnet_disable(struct usb_function *f)
@@ -543,20 +590,20 @@
 		dev->notify->driver_data = dev;
 	}
 
-	if (dev->ipa_port.in && !dev->ipa_port.in->desc
-		&& config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in)) {
+	if (dev->bam_port.in && !dev->bam_port.in->desc
+		&& config_ep_by_speed(cdev->gadget, f, dev->bam_port.in)) {
 		pr_err("%s(): config_ep_by_speed failed.\n",
 				__func__);
-		dev->ipa_port.in->desc = NULL;
+		dev->bam_port.in->desc = NULL;
 		ret = -EINVAL;
 		goto err_disable_ep;
 	}
 
-	if (dev->ipa_port.out && !dev->ipa_port.out->desc
-		&& config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) {
+	if (dev->bam_port.out && !dev->bam_port.out->desc
+		&& config_ep_by_speed(cdev->gadget, f, dev->bam_port.out)) {
 		pr_err("%s(): config_ep_by_speed failed.\n",
 				__func__);
-		dev->ipa_port.out->desc = NULL;
+		dev->bam_port.out->desc = NULL;
 		ret = -EINVAL;
 		goto err_disable_ep;
 	}
@@ -940,7 +987,7 @@
 					__func__);
 			return -ENODEV;
 		}
-		dev->ipa_port.in = ep;
+		dev->bam_port.in = ep;
 		ep->driver_data = cdev;
 	}
 
@@ -952,7 +999,7 @@
 			status = -ENODEV;
 			goto ep_auto_out_fail;
 		}
-		dev->ipa_port.out = ep;
+		dev->bam_port.out = ep;
 		ep->driver_data = cdev;
 	}
 
@@ -968,6 +1015,7 @@
 		ep->driver_data = cdev;
 		dev->notify_req = frmnet_alloc_req(ep,
 				sizeof(struct usb_cdc_notification),
+				cdev->gadget->extra_buf_alloc,
 				GFP_KERNEL);
 		if (IS_ERR(dev->notify_req)) {
 			pr_err("%s: unable to allocate memory for notify req\n",
@@ -1044,11 +1092,11 @@
 		dev->notify->driver_data = NULL;
 		dev->notify = NULL;
 ep_auto_notify_fail:
-		dev->ipa_port.out->driver_data = NULL;
-		dev->ipa_port.out = NULL;
+		dev->bam_port.out->driver_data = NULL;
+		dev->bam_port.out = NULL;
 ep_auto_out_fail:
-		dev->ipa_port.in->driver_data = NULL;
-		dev->ipa_port.in = NULL;
+		dev->bam_port.in->driver_data = NULL;
+		dev->bam_port.in = NULL;
 
 	return status;
 }
@@ -1087,10 +1135,10 @@
 	} else {
 		info.string_defs = dpl_string_defs;
 		info.data_desc = &dpl_data_intf_desc;
-		info.fs_in_desc = &dpl_hs_data_desc;
+		info.fs_in_desc = &dpl_fs_data_desc;
 		info.hs_in_desc = &dpl_hs_data_desc;
 		info.ss_in_desc = &dpl_ss_data_desc;
-		info.fs_desc_hdr = dpl_hs_data_only_desc;
+		info.fs_desc_hdr = dpl_fs_data_only_desc;
 		info.hs_desc_hdr = dpl_hs_data_only_desc;
 		info.ss_desc_hdr = dpl_ss_data_only_desc;
 	}
@@ -1149,7 +1197,11 @@
 {
 	struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts,
 						func_inst);
-	ipa_data_free(opts->dev->func_type);
+	if (opts->dev->xport_type == BAM_DMUX)
+		gbam_cleanup(opts->dev->bam_dmux_func_type);
+	else
+		ipa_data_free(opts->dev->ipa_func_type);
+
 	kfree(opts->dev);
 	kfree(opts);
 }
@@ -1180,14 +1232,20 @@
 	}
 
 	if (dev->qti_port_type >= QTI_NUM_PORTS ||
-		dev->func_type >= USB_IPA_NUM_FUNCS) {
+		dev->xport_type >= NR_XPORT_TYPES ||
+		dev->ipa_func_type >= USB_IPA_NUM_FUNCS ||
+		dev->bam_dmux_func_type >= BAM_DMUX_NUM_FUNCS) {
 		pr_err("%s: invalid prot\n", __func__);
 		ret = -EINVAL;
 		goto fail;
 	}
 
 	INIT_LIST_HEAD(&dev->cpkt_resp_q);
-	ret = ipa_data_setup(dev->func_type);
+	if (dev->xport_type == BAM_DMUX)
+		ret = gbam_setup(dev->bam_dmux_func_type);
+	else
+		ret = ipa_data_setup(dev->ipa_func_type);
+
 	if (ret)
 		goto fail;
 
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 56a8e1b..6153c54 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -93,6 +93,9 @@
 	atomic_t			notify_count;
 };
 
+static struct f_rndis *__rndis;
+static spinlock_t _rndis_lock;
+
 static inline struct f_rndis *func_to_rndis(struct usb_function *f)
 {
 	return container_of(f, struct f_rndis, port.func);
@@ -422,10 +425,19 @@
 
 static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct f_rndis			*rndis = req->context;
-	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
+	struct f_rndis			*rndis;
+	struct usb_composite_dev	*cdev;
 	int				status = req->status;
+	struct usb_ep *notify_ep;
 
+	spin_lock(&_rndis_lock);
+	rndis = __rndis;
+	if (!rndis || !rndis->notify) {
+		spin_unlock(&_rndis_lock);
+		return;
+	}
+
+	cdev = rndis->port.func.config->cdev;
 	/* after TX:
 	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
 	 *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
@@ -435,7 +447,7 @@
 	case -ESHUTDOWN:
 		/* connection gone */
 		atomic_set(&rndis->notify_count, 0);
-		break;
+		goto out;
 	default:
 		DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
 			ep->name, status,
@@ -443,29 +455,53 @@
 		/* FALLTHROUGH */
 	case 0:
 		if (ep != rndis->notify)
-			break;
+			goto out;
 
 		/* handle multiple pending RNDIS_RESPONSE_AVAILABLE
 		 * notifications by resending until we're done
 		 */
 		if (atomic_dec_and_test(&rndis->notify_count))
-			break;
-		status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+			goto out;
+		notify_ep = rndis->notify;
+		spin_unlock(&_rndis_lock);
+		status = usb_ep_queue(notify_ep, req, GFP_ATOMIC);
 		if (status) {
-			atomic_dec(&rndis->notify_count);
+			spin_lock(&_rndis_lock);
+			if (!__rndis)
+				goto out;
+			atomic_dec(&__rndis->notify_count);
 			DBG(cdev, "notify/1 --> %d\n", status);
+			spin_unlock(&_rndis_lock);
 		}
-		break;
 	}
+
+	return;
+
+out:
+	spin_unlock(&_rndis_lock);
 }
 
 static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct f_rndis			*rndis = req->context;
-	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;
+	struct f_rndis			*rndis;
+	struct usb_composite_dev	*cdev;
 	int				status;
 	rndis_init_msg_type		*buf;
 
+	if (req->status != 0) {
+		pr_err("%s: RNDIS command completion error:%d\n",
+				__func__, req->status);
+		return;
+	}
+
+	spin_lock(&_rndis_lock);
+	rndis = __rndis;
+	if (!rndis || !rndis->notify) {
+		spin_unlock(&_rndis_lock);
+		return;
+	}
+
+	cdev = rndis->port.func.config->cdev;
 	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 //	spin_lock(&dev->lock);
 	status = rndis_msg_parser(rndis->params, (u8 *) req->buf);
@@ -488,6 +524,7 @@
 			rndis->port.multi_pkt_xfer = 0;
 	}
 //	spin_unlock(&dev->lock);
+	spin_unlock(&_rndis_lock);
 }
 
 static int
@@ -639,13 +676,16 @@
 {
 	struct f_rndis		*rndis = func_to_rndis(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
+	unsigned long flags;
 
 	if (!rndis->notify->enabled)
 		return;
 
 	DBG(cdev, "rndis deactivated\n");
 
+	spin_lock_irqsave(&_rndis_lock, flags);
 	rndis_uninit(rndis->params);
+	spin_unlock_irqrestore(&_rndis_lock, flags);
 	gether_disconnect(&rndis->port);
 
 	usb_ep_disable(rndis->notify);
@@ -793,7 +833,8 @@
 	rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
 	if (!rndis->notify_req)
 		goto fail;
-	rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
+	rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT +
+			cdev->gadget->extra_buf_alloc, GFP_KERNEL);
 	if (!rndis->notify_req->buf)
 		goto fail;
 	rndis->notify_req->length = STATUS_BYTECOUNT;
@@ -937,6 +978,7 @@
 	opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id;
 
 	mutex_init(&opts->lock);
+	spin_lock_init(&_rndis_lock);
 	opts->func_inst.free_func_inst = rndis_free_inst;
 	opts->net = gether_setup_default();
 	if (IS_ERR(opts->net)) {
@@ -966,11 +1008,15 @@
 {
 	struct f_rndis *rndis;
 	struct f_rndis_opts *opts;
+	unsigned long flags;
 
 	rndis = func_to_rndis(f);
 	rndis_deregister(rndis->params);
 	opts = container_of(f->fi, struct f_rndis_opts, func_inst);
+	spin_lock_irqsave(&_rndis_lock, flags);
 	kfree(rndis);
+	__rndis = NULL;
+	spin_unlock_irqrestore(&_rndis_lock, flags);
 	mutex_lock(&opts->lock);
 	opts->refcnt--;
 	mutex_unlock(&opts->lock);
@@ -999,6 +1045,8 @@
 	if (!rndis)
 		return ERR_PTR(-ENOMEM);
 
+	__rndis = rndis;
+
 	opts = container_of(fi, struct f_rndis_opts, func_inst);
 	mutex_lock(&opts->lock);
 	opts->refcnt++;
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index cb00ada..405becf9 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -31,13 +31,43 @@
 	struct gserial			port;
 	u8				data_id;
 	u8				port_num;
+	spinlock_t			lock;
+
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+
+	u8				online;
+	u8				pending;
+	struct usb_cdc_line_coding	port_line_coding;
+
+	/* SetControlLineState request */
+	u16				port_handshake_bits;
+#define ACM_CTRL_RTS	(1 << 1)	/* unused with full duplex */
+#define ACM_CTRL_DTR	(1 << 0)	/* host is ready for data r/w */
+
+	/* SerialState notification */
+	u16				serial_state;
+#define ACM_CTRL_OVERRUN	(1 << 6)
+#define ACM_CTRL_PARITY		(1 << 5)
+#define ACM_CTRL_FRAMING	(1 << 4)
+#define ACM_CTRL_RI		(1 << 3)
+#define ACM_CTRL_BRK		(1 << 2)
+#define ACM_CTRL_DSR		(1 << 1)
+#define ACM_CTRL_DCD		(1 << 0)
 };
 
+static inline struct f_gser *port_to_gser(struct gserial *p)
+{
+	return container_of(p, struct f_gser, port);
+}
+
 static inline struct f_gser *func_to_gser(struct usb_function *f)
 {
 	return container_of(f, struct f_gser, port.func);
 }
 
+#define GS_LOG2_NOTIFY_INTERVAL		5	/* 1 << 5 == 32 msec */
+#define GS_NOTIFY_MAXPACKET		10	/* notification + 2 bytes */
 /*-------------------------------------------------------------------------*/
 
 /* interface descriptor: */
@@ -46,15 +76,55 @@
 	.bLength =		USB_DT_INTERFACE_SIZE,
 	.bDescriptorType =	USB_DT_INTERFACE,
 	/* .bInterfaceNumber = DYNAMIC */
-	.bNumEndpoints =	2,
+	.bNumEndpoints =	3,
 	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
 	.bInterfaceSubClass =	0,
 	.bInterfaceProtocol =	0,
 	/* .iInterface = DYNAMIC */
 };
 
+static struct usb_cdc_header_desc gser_header_desc  = {
+	.bLength =		sizeof(gser_header_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor
+gser_call_mgmt_descriptor  = {
+	.bLength =		sizeof(gser_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	/* .bDataInterface = DYNAMIC */
+};
+
+static struct usb_cdc_acm_descriptor gser_descriptor  = {
+	.bLength =		sizeof(gser_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	USB_CDC_CAP_LINE,
+};
+
+static struct usb_cdc_union_desc gser_union_desc  = {
+	.bLength =		sizeof(gser_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
 /* full speed support: */
 
+static struct usb_endpoint_descriptor gser_fs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
+};
+
 static struct usb_endpoint_descriptor gser_fs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -71,12 +141,25 @@
 
 static struct usb_descriptor_header *gser_fs_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_fs_notify_desc,
 	(struct usb_descriptor_header *) &gser_fs_in_desc,
 	(struct usb_descriptor_header *) &gser_fs_out_desc,
 	NULL,
 };
 
 /* high speed support: */
+static struct usb_endpoint_descriptor gser_hs_notify_desc  = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
 
 static struct usb_endpoint_descriptor gser_hs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
@@ -94,6 +177,11 @@
 
 static struct usb_descriptor_header *gser_hs_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_hs_notify_desc,
 	(struct usb_descriptor_header *) &gser_hs_in_desc,
 	(struct usb_descriptor_header *) &gser_hs_out_desc,
 	NULL,
@@ -118,8 +206,33 @@
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
+static struct usb_endpoint_descriptor gser_ss_notify_desc  = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_ss_ep_comp_descriptor gser_ss_notify_comp_desc = {
+	.bLength =		sizeof(gser_ss_notify_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+};
+
 static struct usb_descriptor_header *gser_ss_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_comp_desc,
 	(struct usb_descriptor_header *) &gser_ss_in_desc,
 	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
 	(struct usb_descriptor_header *) &gser_ss_out_desc,
@@ -130,7 +243,7 @@
 /* string descriptors: */
 
 static struct usb_string gser_string_defs[] = {
-	[0].s = "Generic Serial",
+	[0].s = "DUN over Serial",
 	{  } /* end of list */
 };
 
@@ -145,13 +258,131 @@
 };
 
 /*-------------------------------------------------------------------------*/
+static void gser_complete_set_line_coding(struct usb_ep *ep,
+					struct usb_request *req)
+{
+	struct f_gser            *gser = ep->driver_data;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	if (req->status != 0) {
+		dev_dbg(&cdev->gadget->dev, "gser ttyGS%d completion, err %d\n",
+				gser->port_num, req->status);
+		return;
+	}
+
+	/* normal completion */
+	if (req->actual != sizeof(gser->port_line_coding)) {
+		dev_dbg(&cdev->gadget->dev, "gser ttyGS%d short resp, len %d\n",
+				gser->port_num, req->actual);
+		usb_ep_set_halt(ep);
+	} else {
+		struct usb_cdc_line_coding *value = req->buf;
+
+		gser->port_line_coding = *value;
+	}
+}
+
+static int
+gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_gser            *gser = func_to_gser(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request       *req = cdev->req;
+	int                      value = -EOPNOTSUPP;
+	u16                      w_index = le16_to_cpu(ctrl->wIndex);
+	u16                      w_value = le16_to_cpu(ctrl->wValue);
+	u16                      w_length = le16_to_cpu(ctrl->wLength);
+
+
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+	/* SET_LINE_CODING ... just read and save what the host sends */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_LINE_CODING:
+		if (w_length != sizeof(struct usb_cdc_line_coding))
+			goto invalid;
+
+		value = w_length;
+		cdev->gadget->ep0->driver_data = gser;
+		req->complete = gser_complete_set_line_coding;
+		break;
+
+	/* GET_LINE_CODING ... return what host sent, or initial value */
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_GET_LINE_CODING:
+		value = min_t(unsigned int, w_length,
+				sizeof(struct usb_cdc_line_coding));
+		memcpy(req->buf, &gser->port_line_coding, value);
+		break;
+
+	/* SET_CONTROL_LINE_STATE ... save what the host sent */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+
+		value = 0;
+		gser->port_handshake_bits = w_value;
+		pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d RST:%d\n",
+			__func__, w_value & ACM_CTRL_DTR ? 1 : 0,
+			w_value & ACM_CTRL_RTS ? 1 : 0);
+
+		if (gser->port.notify_modem)
+			gser->port.notify_modem(&gser->port, 0, w_value);
+
+		break;
+
+	default:
+invalid:
+		dev_dbg(&cdev->gadget->dev,
+			"invalid control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* respond with data transfer or status phase? */
+	if (value >= 0) {
+		dev_dbg(&cdev->gadget->dev,
+			"gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
+			gser->port_num, ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = 0;
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0)
+			ERROR(cdev, "gser response on ttyGS%d, err %d\n",
+					gser->port_num, value);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
 
 static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_gser		*gser = func_to_gser(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
+	int rc = 0;
 
 	/* we know alt == 0, so this is an activation or a reset */
+	if (gser->notify->driver_data) {
+		dev_dbg(&cdev->gadget->dev,
+			"reset generic ctl ttyGS%d\n", gser->port_num);
+		usb_ep_disable(gser->notify);
+	}
+
+	if (!gser->notify->desc) {
+		if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
+			gser->notify->desc = NULL;
+			return -EINVAL;
+		}
+	}
+
+	rc = usb_ep_enable(gser->notify);
+	if (rc) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			gser->notify->name, rc);
+		return rc;
+	}
+	gser->notify->driver_data = gser;
 
 	if (gser->port.in->enabled) {
 		dev_dbg(&cdev->gadget->dev,
@@ -169,7 +400,9 @@
 		}
 	}
 	gserial_connect(&gser->port, gser->port_num);
-	return 0;
+	gser->online = 1;
+
+	return rc;
 }
 
 static void gser_disable(struct usb_function *f)
@@ -180,6 +413,178 @@
 	dev_dbg(&cdev->gadget->dev,
 		"generic ttyGS%d deactivated\n", gser->port_num);
 	gserial_disconnect(&gser->port);
+	usb_ep_disable(gser->notify);
+	gser->notify->driver_data = NULL;
+	gser->online = 0;
+}
+
+static int gser_notify(struct f_gser *gser, u8 type, u16 value,
+		void *data, unsigned int length)
+{
+	struct usb_ep			*ep = gser->notify;
+	struct usb_request		*req;
+	struct usb_cdc_notification	*notify;
+	const unsigned int		len = sizeof(*notify) + length;
+	void                            *buf;
+	int                             status;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	req = gser->notify_req;
+	gser->notify_req = NULL;
+	gser->pending = false;
+
+	req->length = len;
+	notify = req->buf;
+	buf = notify + 1;
+
+	notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+			| USB_RECIP_INTERFACE;
+	notify->bNotificationType = type;
+	notify->wValue = cpu_to_le16(value);
+	notify->wIndex = cpu_to_le16(gser->data_id);
+	notify->wLength = cpu_to_le16(length);
+	memcpy(buf, data, length);
+
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (status < 0) {
+		ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
+				gser->port_num, status);
+		gser->notify_req = req;
+	}
+
+	return status;
+}
+
+static int gser_notify_serial_state(struct f_gser *gser)
+{
+	int		status;
+	unsigned long	flags;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	spin_lock_irqsave(&gser->lock, flags);
+	if (gser->notify_req) {
+		DBG(cdev, "gser ttyGS%d serial state %04x\n",
+				gser->port_num, gser->serial_state);
+		status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
+				0, &gser->serial_state,
+				sizeof(gser->serial_state));
+	} else {
+		gser->pending = true;
+		status = 0;
+	}
+
+	spin_unlock_irqrestore(&gser->lock, flags);
+	return status;
+}
+
+static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_gser *gser = req->context;
+	u8            doit = false;
+	unsigned long flags;
+
+	/* on this call path we do NOT hold the port spinlock,
+	 * which is why ACM needs its own spinlock
+	 */
+
+	spin_lock_irqsave(&gser->lock, flags);
+	if (req->status != -ESHUTDOWN)
+		doit = gser->pending;
+
+	gser->notify_req = req;
+	spin_unlock_irqrestore(&gser->lock, flags);
+
+	if (doit && gser->online)
+		gser_notify_serial_state(gser);
+}
+
+static void gser_connect(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
+	gser_notify_serial_state(gser);
+}
+
+static unsigned int gser_get_dtr(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	if (gser->port_handshake_bits & ACM_CTRL_DTR)
+		return 1;
+	else
+		return 0;
+}
+
+static unsigned int gser_get_rts(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	if (gser->port_handshake_bits & ACM_CTRL_RTS)
+		return 1;
+	else
+		return 0;
+}
+
+static unsigned int gser_send_carrier_detect(struct gserial *port,
+	unsigned int yes)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_DCD;
+	if (yes)
+		state |= ACM_CTRL_DCD;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static unsigned int gser_send_ring_indicator(struct gserial *port,
+	unsigned int yes)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_RI;
+	if (yes)
+		state |= ACM_CTRL_RI;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static void gser_disconnect(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
+	gser_notify_serial_state(gser);
+}
+
+static int gser_send_break(struct gserial *port, int duration)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_BRK;
+	if (duration)
+		state |= ACM_CTRL_BRK;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static int gser_send_modem_ctrl_bits(struct gserial *port, int ctrl_bits)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state = ctrl_bits;
+
+	return gser_notify_serial_state(gser);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -225,6 +630,21 @@
 		goto fail;
 	gser->port.out = ep;
 
+	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
+	if (!ep)
+		goto fail;
+	gser->notify = ep;
+	ep->driver_data = cdev;	/* claim */
+	/* allocate notification */
+	gser->notify_req = gs_alloc_req(ep,
+			sizeof(struct usb_cdc_notification) + 2,
+			cdev->gadget->extra_buf_alloc, GFP_KERNEL);
+	if (!gser->notify_req)
+		goto fail;
+
+	gser->notify_req->complete = gser_notify_complete;
+	gser->notify_req->context = gser;
+
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -235,6 +655,15 @@
 	gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
 	gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
 
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		gser_hs_notify_desc.bEndpointAddress =
+				gser_fs_notify_desc.bEndpointAddress;
+	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		gser_ss_notify_desc.bEndpointAddress =
+				gser_fs_notify_desc.bEndpointAddress;
+	}
+
 	status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
 			gser_ss_function, NULL);
 	if (status)
@@ -247,6 +676,18 @@
 	return 0;
 
 fail:
+	if (gser->notify_req)
+		gs_free_req(gser->notify, gser->notify_req);
+
+	/* we might as well release our claims on endpoints */
+	if (gser->notify)
+		gser->notify->driver_data = NULL;
+	/* we might as well release our claims on endpoints */
+	if (gser->port.out)
+		gser->port.out->driver_data = NULL;
+	if (gser->port.in)
+		gser->port.in->driver_data = NULL;
+
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 
 	return status;
@@ -327,7 +768,10 @@
 
 static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+	struct f_gser *gser = func_to_gser(f);
+
 	usb_free_all_descriptors(f);
+	gs_free_req(gser->notify, gser->notify_req);
 }
 
 static struct usb_function *gser_alloc(struct usb_function_instance *fi)
@@ -342,6 +786,7 @@
 
 	opts = container_of(fi, struct f_serial_opts, func_inst);
 
+	spin_lock_init(&gser->lock);
 	gser->port_num = opts->port_num;
 
 	gser->port.func.name = "gser";
@@ -351,6 +796,15 @@
 	gser->port.func.set_alt = gser_set_alt;
 	gser->port.func.disable = gser_disable;
 	gser->port.func.free_func = gser_free;
+	gser->port.func.setup = gser_setup;
+	gser->port.connect = gser_connect;
+	gser->port.get_dtr = gser_get_dtr;
+	gser->port.get_rts = gser_get_rts;
+	gser->port.send_carrier_detect = gser_send_carrier_detect;
+	gser->port.send_ring_indicator = gser_send_ring_indicator;
+	gser->port.send_modem_ctrl_bits = gser_send_modem_ctrl_bits;
+	gser->port.disconnect = gser_disconnect;
+	gser->port.send_break = gser_send_break;
 
 	return &gser->port.func;
 }
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 5d8e6fa..038993d 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -932,6 +932,7 @@
 	}
 #endif
 
+	spin_lock_init(&params->lock);
 	params->confignr = i;
 	params->used = 1;
 	params->state = RNDIS_UNINITIALIZED;
@@ -1096,29 +1097,36 @@
 void rndis_free_response(struct rndis_params *params, u8 *buf)
 {
 	rndis_resp_t *r, *n;
+	unsigned long flags;
 
+	spin_lock_irqsave(&params->lock, flags);
 	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
 		if (r->buf == buf) {
 			list_del(&r->list);
 			kfree(r);
 		}
 	}
+	spin_unlock_irqrestore(&params->lock, flags);
 }
 EXPORT_SYMBOL_GPL(rndis_free_response);
 
 u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
 {
 	rndis_resp_t *r, *n;
+	unsigned long flags;
 
 	if (!length) return NULL;
 
+	spin_lock_irqsave(&params->lock, flags);
 	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
 		if (!r->send) {
 			r->send = 1;
 			*length = r->length;
+			spin_unlock_irqrestore(&params->lock, flags);
 			return r->buf;
 		}
 	}
+	spin_unlock_irqrestore(&params->lock, flags);
 
 	return NULL;
 }
@@ -1127,6 +1135,7 @@
 static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
 {
 	rndis_resp_t *r;
+	unsigned long flags;
 
 	/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
 	r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
@@ -1136,7 +1145,9 @@
 	r->length = length;
 	r->send = 0;
 
+	spin_lock_irqsave(&params->lock, flags);
 	list_add_tail(&r->list, &params->resp_queue);
+	spin_unlock_irqrestore(&params->lock, flags);
 	return r;
 }
 
@@ -1144,7 +1155,7 @@
 			struct sk_buff *skb,
 			struct sk_buff_head *list)
 {
-	int num_pkts = 1;
+	int num_pkts = 0;
 
 	if (skb->len > rndis_ul_max_xfer_size_rcvd)
 		rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1154,12 +1165,6 @@
 		struct sk_buff          *skb2;
 		u32             msg_len, data_offset, data_len;
 
-		/* some rndis hosts send extra byte to avoid zlp, ignore it */
-		if (skb->len == 1) {
-			dev_kfree_skb_any(skb);
-			return 0;
-		}
-
 		if (skb->len < sizeof *hdr) {
 			pr_err("invalid rndis pkt: skblen:%u hdr_len:%zu",
 					skb->len, sizeof *hdr);
@@ -1188,9 +1193,12 @@
 			return -EINVAL;
 		}
 
+		num_pkts++;
+
 		skb_pull(skb, data_offset + 8);
 
-		if (msg_len == skb->len) {
+		if (data_len == skb->len ||
+				data_len == (skb->len - 1)) {
 			skb_trim(skb, data_len);
 			break;
 		}
@@ -1205,8 +1213,6 @@
 		skb_pull(skb, msg_len - sizeof *hdr);
 		skb_trim(skb2, data_len);
 		skb_queue_tail(list, skb2);
-
-		num_pkts++;
 	}
 
 	if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
@@ -1244,7 +1250,9 @@
 			 "speed     : %d\n"
 			 "cable     : %s\n"
 			 "vendor ID : 0x%08X\n"
-			 "vendor    : %s\n",
+			 "vendor    : %s\n"
+			 "ul-max-xfer-size:%zu max-xfer-size-rcvd: %d\n"
+			 "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
 			 param->confignr, (param->used) ? "y" : "n",
 			 ({ char *s = "?";
 			 switch (param->state) {
@@ -1258,7 +1266,13 @@
 			 param->medium,
 			 (param->media_state) ? 0 : param->speed*100,
 			 (param->media_state) ? "disconnected" : "connected",
-			 param->vendorID, param->vendorDescr);
+			 param->vendorID, param->vendorDescr,
+			 param->dev ? param->max_pkt_per_xfer *
+				 (param->dev->mtu + sizeof(struct ethhdr) +
+				 sizeof(struct rndis_packet_msg_type) + 22) : 0,
+			 rndis_ul_max_xfer_size_rcvd,
+			 param->max_pkt_per_xfer,
+			 rndis_ul_max_pkt_per_xfer_rcvd);
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index a3051c4..2211146 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -203,6 +203,7 @@
 
 	void			*v;
 	struct list_head	resp_queue;
+	spinlock_t		lock;
 } rndis_params;
 
 /* RNDIS Message parser and other useless functions */
diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
index e698489..614c281 100644
--- a/drivers/usb/gadget/function/storage_common.h
+++ b/drivers/usb/gadget/function/storage_common.h
@@ -128,6 +128,7 @@
 
 /* Default size of buffer length. */
 #define FSG_BUFLEN	((u32)16384)
+#define EXTRA_ALLOCATION_SIZE	((u32)256)
 
 /* Maximal number of LUNs supported in mass storage function */
 #define FSG_MAX_LUNS	16
diff --git a/drivers/usb/gadget/function/u_bam_dmux.c b/drivers/usb/gadget/function/u_bam_dmux.c
new file mode 100644
index 0000000..78dfe7b
--- /dev/null
+++ b/drivers/usb/gadget/function/u_bam_dmux.c
@@ -0,0 +1,1475 @@
+/* Copyright (c) 2011-2018, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <soc/qcom/smd.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+#include <linux/platform_device.h>
+
+#include <soc/qcom/bam_dmux.h>
+
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/usb_ctrl_qti.h>
+#include <linux/usb_bam.h>
+
+#include "u_rmnet.h"
+
+static struct workqueue_struct *gbam_wq;
+static unsigned int n_tx_req_queued;
+
+static unsigned int bam_ch_ids[BAM_DMUX_NUM_FUNCS] = {
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_USB_DPL
+};
+
+static char bam_ch_names[BAM_DMUX_NUM_FUNCS][BAM_DMUX_CH_NAME_MAX_LEN];
+
+#define BAM_PENDING_PKTS_LIMIT			220
+#define BAM_MUX_TX_PKT_DROP_THRESHOLD		1000
+#define BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD		500
+#define BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD		300
+#define BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT	1
+
+#define BAM_MUX_HDR				8
+
+#define BAM_MUX_RX_Q_SIZE			128
+#define BAM_MUX_TX_Q_SIZE			200
+#define BAM_MUX_RX_REQ_SIZE			2048   /* Must be 1KB aligned */
+
+#define DL_INTR_THRESHOLD			20
+#define BAM_PENDING_BYTES_LIMIT			(50 * BAM_MUX_RX_REQ_SIZE)
+#define BAM_PENDING_BYTES_FCTRL_EN_TSHOLD	(BAM_PENDING_BYTES_LIMIT / 3)
+
+/* Extra buffer size to allocate for tx */
+#define EXTRA_ALLOCATION_SIZE_U_BAM	128
+
+static unsigned int bam_pending_pkts_limit = BAM_PENDING_PKTS_LIMIT;
+module_param(bam_pending_pkts_limit, uint, 0644);
+
+static unsigned int bam_pending_bytes_limit = BAM_PENDING_BYTES_LIMIT;
+module_param(bam_pending_bytes_limit, uint, 0644);
+
+static unsigned int bam_pending_bytes_fctrl_en_thold =
+					BAM_PENDING_BYTES_FCTRL_EN_TSHOLD;
+module_param(bam_pending_bytes_fctrl_en_thold, uint, 0644);
+
+static unsigned int bam_mux_tx_pkt_drop_thld = BAM_MUX_TX_PKT_DROP_THRESHOLD;
+module_param(bam_mux_tx_pkt_drop_thld, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_en_thld = BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD;
+module_param(bam_mux_rx_fctrl_en_thld, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_support = BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT;
+module_param(bam_mux_rx_fctrl_support, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_dis_thld = BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD;
+module_param(bam_mux_rx_fctrl_dis_thld, uint, 0644);
+
+static unsigned int bam_mux_tx_q_size = BAM_MUX_TX_Q_SIZE;
+module_param(bam_mux_tx_q_size, uint, 0644);
+
+static unsigned int bam_mux_rx_q_size = BAM_MUX_RX_Q_SIZE;
+module_param(bam_mux_rx_q_size, uint, 0644);
+
+static unsigned long bam_mux_rx_req_size = BAM_MUX_RX_REQ_SIZE;
+module_param(bam_mux_rx_req_size, ulong, 0444);
+
+static unsigned int dl_intr_threshold = DL_INTR_THRESHOLD;
+module_param(dl_intr_threshold, uint, 0644);
+
+#define BAM_CH_OPENED			BIT(0)
+#define BAM_CH_READY			BIT(1)
+#define BAM_CH_WRITE_INPROGRESS		BIT(2)
+
+enum u_bam_event_type {
+	U_BAM_DISCONNECT_E = 0,
+	U_BAM_CONNECT_E,
+	U_BAM_SUSPEND_E,
+	U_BAM_RESUME_E
+};
+
+struct bam_ch_info {
+	unsigned long		flags;
+	unsigned int		id;
+
+	struct list_head        tx_idle;
+	struct sk_buff_head	tx_skb_q;
+
+	struct list_head        rx_idle;
+	struct sk_buff_head	rx_skb_q;
+	struct sk_buff_head	rx_skb_idle;
+
+	struct gbam_port	*port;
+	struct work_struct	write_tobam_w;
+	struct work_struct	write_tohost_w;
+
+	struct usb_request	*rx_req;
+	struct usb_request	*tx_req;
+
+	/* stats */
+	unsigned int		pending_pkts_with_bam;
+	unsigned int		pending_bytes_with_bam;
+	unsigned int		tohost_drp_cnt;
+	unsigned int		tomodem_drp_cnt;
+	unsigned int		tx_len;
+	unsigned int		rx_len;
+	unsigned long		to_modem;
+	unsigned long		to_host;
+	unsigned int		rx_flow_control_disable;
+	unsigned int		rx_flow_control_enable;
+	unsigned int		rx_flow_control_triggered;
+	unsigned int		max_num_pkts_pending_with_bam;
+	unsigned int		max_bytes_pending_with_bam;
+	unsigned int		delayed_bam_mux_write_done;
+	unsigned long		skb_expand_cnt;
+};
+
+struct gbam_port {
+	bool			is_connected;
+	enum u_bam_event_type	last_event;
+	unsigned int		port_num;
+	spinlock_t		port_lock_ul;
+	spinlock_t		port_lock_dl;
+	spinlock_t		port_lock;
+
+	struct data_port	*port_usb;
+	struct usb_gadget	*gadget;
+
+	struct bam_ch_info	data_ch;
+
+	struct work_struct	connect_w;
+	struct work_struct	disconnect_w;
+};
+
+static struct bam_portmaster {
+	struct gbam_port *port;
+	struct platform_driver pdrv;
+} bam_ports[BAM_DMUX_NUM_FUNCS];
+
+struct  u_bam_data_connect_info {
+	u32 usb_bam_pipe_idx;
+	u32 peer_pipe_idx;
+	unsigned long usb_bam_handle;
+};
+
+static void gbam_start_rx(struct gbam_port *port);
+static void gbam_notify(void *p, int event, unsigned long data);
+static void gbam_data_write_tobam(struct work_struct *w);
+
+/*---------------misc functions---------------- */
+static void gbam_free_requests(struct usb_ep *ep, struct list_head *head)
+{
+	struct usb_request	*req;
+
+	while (!list_empty(head)) {
+		req = list_entry(head->next, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(ep, req);
+	}
+}
+
+static int gbam_alloc_requests(struct usb_ep *ep, struct list_head *head,
+		int num,
+		void (*cb)(struct usb_ep *ep, struct usb_request *),
+		gfp_t flags)
+{
+	int i;
+	struct usb_request *req;
+
+	pr_debug("%s: ep:%pK head:%pK num:%d cb:%pK", __func__,
+			ep, head, num, cb);
+
+	for (i = 0; i < num; i++) {
+		req = usb_ep_alloc_request(ep, flags);
+		if (!req) {
+			pr_debug("%s: req allocated:%d\n", __func__, i);
+			return list_empty(head) ? -ENOMEM : 0;
+		}
+		req->complete = cb;
+		list_add(&req->list, head);
+	}
+
+	return 0;
+}
+
+static inline dma_addr_t gbam_get_dma_from_skb(struct sk_buff *skb)
+{
+	return *((dma_addr_t *)(skb->cb));
+}
+
+/* This function should be called with port_lock_ul lock held */
+static struct sk_buff *gbam_alloc_skb_from_pool(struct gbam_port *port)
+{
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+	dma_addr_t      skb_buf_dma_addr;
+
+	if (!port)
+		return NULL;
+
+	d = &port->data_ch;
+	if (!d)
+		return NULL;
+
+	if (d->rx_skb_idle.qlen == 0) {
+		/*
+		 * In case skb idle pool is empty, we allow to allocate more
+		 * skbs so we dynamically enlarge the pool size when needed.
+		 * Therefore, in steady state this dynamic allocation will
+		 * stop when the pool will arrive to its optimal size.
+		 */
+		pr_debug("%s: allocate skb\n", __func__);
+		skb = alloc_skb(bam_mux_rx_req_size + BAM_MUX_HDR, GFP_ATOMIC);
+
+		if (!skb)
+			goto alloc_exit;
+
+		skb_reserve(skb, BAM_MUX_HDR);
+		skb_buf_dma_addr = DMA_ERROR_CODE;
+
+		memcpy(skb->cb, &skb_buf_dma_addr,
+			sizeof(skb_buf_dma_addr));
+
+	} else {
+		pr_debug("%s: pull skb from pool\n", __func__);
+		skb = __skb_dequeue(&d->rx_skb_idle);
+		if (!skb)
+			goto alloc_exit;
+
+		if (skb_headroom(skb) < BAM_MUX_HDR)
+			skb_reserve(skb, BAM_MUX_HDR);
+	}
+
+alloc_exit:
+	return skb;
+}
+
+/* This function should be called with port_lock_ul lock held */
+static void gbam_free_skb_to_pool(struct gbam_port *port, struct sk_buff *skb)
+{
+	struct bam_ch_info *d;
+
+	if (!port)
+		return;
+	d = &port->data_ch;
+
+	skb->len = 0;
+	skb_reset_tail_pointer(skb);
+	__skb_queue_tail(&d->rx_skb_idle, skb);
+}
+
+static void gbam_free_rx_skb_idle_list(struct gbam_port *port)
+{
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+	struct usb_gadget *gadget = NULL;
+
+	if (!port)
+		return;
+	d = &port->data_ch;
+
+	gadget = port->port_usb->cdev->gadget;
+
+	while (d->rx_skb_idle.qlen > 0) {
+		skb = __skb_dequeue(&d->rx_skb_idle);
+		if (!skb)
+			break;
+
+		dma_addr = gbam_get_dma_from_skb(skb);
+
+		if (gadget && dma_addr != DMA_ERROR_CODE) {
+			dma_unmap_single(&gadget->dev, dma_addr,
+				bam_mux_rx_req_size, DMA_BIDIRECTIONAL);
+
+			dma_addr = DMA_ERROR_CODE;
+			memcpy(skb->cb, &dma_addr,
+				sizeof(dma_addr));
+		}
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/*--------------------------------------------- */
+
+/*------------data_path----------------------------*/
+static void gbam_write_data_tohost(struct gbam_port *port)
+{
+	unsigned long			flags;
+	struct bam_ch_info		*d = &port->data_ch;
+	struct sk_buff			*skb;
+	struct sk_buff			*new_skb;
+	int				ret;
+	int				tail_room = 0;
+	int				extra_alloc = 0;
+	struct usb_request		*req;
+	struct usb_ep			*ep;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		return;
+	}
+
+	ep = port->port_usb->in;
+
+	while (!list_empty(&d->tx_idle)) {
+		skb = __skb_dequeue(&d->tx_skb_q);
+		if (!skb)
+			break;
+
+		/*
+		 * Some UDC requires allocation of some extra bytes for
+		 * TX buffer due to hardware requirement. Check if extra
+		 * bytes are already there, otherwise allocate new buffer
+		 * with extra bytes and do memcpy.
+		 */
+		if (port->gadget->extra_buf_alloc)
+			extra_alloc = EXTRA_ALLOCATION_SIZE_U_BAM;
+		tail_room = skb_tailroom(skb);
+		if (tail_room < extra_alloc) {
+			pr_debug("%s: tail_room  %d less than %d\n", __func__,
+					tail_room, extra_alloc);
+			new_skb = skb_copy_expand(skb, 0, extra_alloc -
+					tail_room, GFP_ATOMIC);
+			if (!new_skb) {
+				pr_err("skb_copy_expand failed\n");
+				break;
+			}
+			dev_kfree_skb_any(skb);
+			skb = new_skb;
+			d->skb_expand_cnt++;
+		}
+
+		req = list_first_entry(&d->tx_idle,
+				struct usb_request,
+				list);
+		req->context = skb;
+		req->buf = skb->data;
+		req->length = skb->len;
+		n_tx_req_queued++;
+		if (n_tx_req_queued == dl_intr_threshold) {
+			req->no_interrupt = 0;
+			n_tx_req_queued = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
+
+		/* Send ZLP in case packet length is multiple of maxpacksize */
+		req->zero = 1;
+
+		list_del(&req->list);
+
+		spin_unlock(&port->port_lock_dl);
+		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
+		spin_lock(&port->port_lock_dl);
+		if (ret) {
+			pr_err_ratelimited("%s: usb epIn failed with %d\n",
+					 __func__, ret);
+			list_add(&req->list, &d->tx_idle);
+			dev_kfree_skb_any(skb);
+			break;
+		}
+		d->to_host++;
+	}
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+}
+
+static void gbam_write_data_tohost_w(struct work_struct *w)
+{
+	struct bam_ch_info	*d;
+	struct gbam_port	*port;
+
+	d = container_of(w, struct bam_ch_info, write_tohost_w);
+	port = d->port;
+
+	gbam_write_data_tohost(port);
+}
+
+static void gbam_data_recv_cb(void *p, struct sk_buff *skb)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info	*d = &port->data_ch;
+	unsigned long		flags;
+
+	if (!skb)
+		return;
+
+	pr_debug("%s: p:%pK#%d d:%pK skb_len:%d\n", __func__,
+			port, port->port_num, d, skb->len);
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	if (d->tx_skb_q.qlen > bam_mux_tx_pkt_drop_thld) {
+		d->tohost_drp_cnt++;
+		printk_ratelimited(KERN_ERR "%s: tx pkt dropped: tx_drop_cnt:%u\n",
+					__func__, d->tohost_drp_cnt);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	__skb_queue_tail(&d->tx_skb_q, skb);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+
+	gbam_write_data_tohost(port);
+}
+
+static void gbam_data_write_done(void *p, struct sk_buff *skb)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info	*d = &port->data_ch;
+	unsigned long		flags;
+
+	if (!skb)
+		return;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+
+	d->pending_pkts_with_bam--;
+	d->pending_bytes_with_bam -= skb->len;
+	gbam_free_skb_to_pool(port, skb);
+
+	pr_debug("%s:port:%pK d:%pK tom:%lu ppkt:%u pbytes:%u pno:%d\n",
+		       __func__, port, d, d->to_modem, d->pending_pkts_with_bam,
+		       d->pending_bytes_with_bam, port->port_num);
+
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	/*
+	 * If BAM doesn't have much pending data then push new data from here:
+	 * write_complete notify only to avoid any underruns due to wq latency
+	 */
+	if (d->pending_bytes_with_bam <= bam_pending_bytes_fctrl_en_thold) {
+		gbam_data_write_tobam(&d->write_tobam_w);
+	} else {
+		d->delayed_bam_mux_write_done++;
+		queue_work(gbam_wq, &d->write_tobam_w);
+	}
+}
+
+/* This function should be called with port_lock_ul spinlock acquired */
+static bool gbam_ul_bam_limit_reached(struct bam_ch_info *data_ch)
+{
+	unsigned int	curr_pending_pkts = data_ch->pending_pkts_with_bam;
+	unsigned int	curr_pending_bytes = data_ch->pending_bytes_with_bam;
+	struct sk_buff	*skb;
+
+	if (curr_pending_pkts >= bam_pending_pkts_limit)
+		return true;
+
+	/* check if next skb length doesn't exceed pending_bytes_limit */
+	skb = skb_peek(&data_ch->rx_skb_q);
+	if (!skb)
+		return false;
+
+	if ((curr_pending_bytes + skb->len) > bam_pending_bytes_limit)
+		return true;
+	else
+		return false;
+}
+
+static void gbam_data_write_tobam(struct work_struct *w)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	int			ret;
+	int			qlen;
+
+	d = container_of(w, struct bam_ch_info, write_tobam_w);
+	port = d->port;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+	/* Bail out if already in progress */
+	if (test_bit(BAM_CH_WRITE_INPROGRESS, &d->flags)) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+
+	set_bit(BAM_CH_WRITE_INPROGRESS, &d->flags);
+
+	while (!gbam_ul_bam_limit_reached(d)) {
+		skb =  __skb_dequeue(&d->rx_skb_q);
+		if (!skb)
+			break;
+
+		d->pending_pkts_with_bam++;
+		d->pending_bytes_with_bam += skb->len;
+		d->to_modem++;
+
+		pr_debug("%s: port:%pK d:%pK tom:%lu ppkts:%u pbytes:%u pno:%d\n",
+				__func__, port, d,
+				d->to_modem, d->pending_pkts_with_bam,
+				d->pending_bytes_with_bam, port->port_num);
+
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		ret = msm_bam_dmux_write(d->id, skb);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		if (ret) {
+			pr_debug("%s: write error:%d\n", __func__, ret);
+			d->pending_pkts_with_bam--;
+			d->pending_bytes_with_bam -= skb->len;
+			d->to_modem--;
+			d->tomodem_drp_cnt++;
+			gbam_free_skb_to_pool(port, skb);
+			break;
+		}
+		if (d->pending_pkts_with_bam > d->max_num_pkts_pending_with_bam)
+			d->max_num_pkts_pending_with_bam =
+					d->pending_pkts_with_bam;
+		if (d->pending_bytes_with_bam > d->max_bytes_pending_with_bam)
+			d->max_bytes_pending_with_bam =
+					d->pending_bytes_with_bam;
+	}
+
+	qlen = d->rx_skb_q.qlen;
+
+	clear_bit(BAM_CH_WRITE_INPROGRESS, &d->flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	if (qlen < bam_mux_rx_fctrl_dis_thld) {
+		if (d->rx_flow_control_triggered) {
+			d->rx_flow_control_disable++;
+			d->rx_flow_control_triggered = 0;
+		}
+		gbam_start_rx(port);
+	}
+}
+/*-------------------------------------------------------------*/
+
+static void gbam_epin_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gbam_port	*port = ep->driver_data;
+	struct bam_ch_info	*d;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+
+	switch (status) {
+	case 0:
+		/* successful completion */
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		dev_kfree_skb_any(skb);
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		pr_err("%s: data tx ep error %d\n",
+				__func__, status);
+		break;
+	}
+
+	dev_kfree_skb_any(skb);
+
+	if (!port)
+		return;
+
+	spin_lock(&port->port_lock_dl);
+	d = &port->data_ch;
+	list_add_tail(&req->list, &d->tx_idle);
+	spin_unlock(&port->port_lock_dl);
+
+	queue_work(gbam_wq, &d->write_tohost_w);
+}
+
+static void
+gbam_epout_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gbam_port	*port = ep->driver_data;
+	struct bam_ch_info	*d = &port->data_ch;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+	int			queue = 0;
+
+	switch (status) {
+	case 0:
+		skb_put(skb, req->actual);
+		queue = 1;
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* cable disconnection */
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+		req->buf = NULL;
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		printk_ratelimited(KERN_ERR "%s: %s response error %d, %d/%d\n",
+			__func__, ep->name, status, req->actual, req->length);
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+		break;
+	}
+
+	spin_lock(&port->port_lock_ul);
+
+	if (queue) {
+		__skb_queue_tail(&d->rx_skb_q, skb);
+		queue_work(gbam_wq, &d->write_tobam_w);
+	}
+
+	/* TODO: Handle flow control gracefully by having
+	 * having call back mechanism from bam driver
+	 */
+	if (bam_mux_rx_fctrl_support &&
+		d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld) {
+		if (!d->rx_flow_control_triggered) {
+			d->rx_flow_control_triggered = 1;
+			d->rx_flow_control_enable++;
+		}
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+		return;
+	}
+
+	skb = gbam_alloc_skb_from_pool(port);
+	if (!skb) {
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+		return;
+	}
+	spin_unlock(&port->port_lock_ul);
+
+	req->buf = skb->data;
+	req->dma = gbam_get_dma_from_skb(skb);
+	req->length = bam_mux_rx_req_size;
+
+	req->context = skb;
+
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (status) {
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+
+		printk_ratelimited(KERN_ERR "%s: data rx enqueue err %d\n",
+					__func__, status);
+
+		spin_lock(&port->port_lock_ul);
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+	}
+}
+
+static void gbam_start_rx(struct gbam_port *port)
+{
+	struct usb_request		*req;
+	struct bam_ch_info		*d;
+	struct usb_ep			*ep;
+	unsigned long			flags;
+	int				ret;
+	struct sk_buff			*skb;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb || !port->port_usb->out) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+
+	d = &port->data_ch;
+	ep = port->port_usb->out;
+
+	while (port->port_usb && !list_empty(&d->rx_idle)) {
+
+		if (bam_mux_rx_fctrl_support &&
+			d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld)
+			break;
+
+		req = list_first_entry(&d->rx_idle, struct usb_request, list);
+
+		skb = gbam_alloc_skb_from_pool(port);
+		if (!skb)
+			break;
+
+		list_del(&req->list);
+		req->buf = skb->data;
+		req->dma = gbam_get_dma_from_skb(skb);
+		req->length = bam_mux_rx_req_size;
+
+		req->context = skb;
+
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		if (ret) {
+			gbam_free_skb_to_pool(port, skb);
+
+			printk_ratelimited(KERN_ERR "%s: rx queue failed %d\n",
+							__func__, ret);
+
+			if (port->port_usb)
+				list_add(&req->list, &d->rx_idle);
+			else
+				usb_ep_free_request(ep, req);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+}
+
+static int _gbam_start_io(struct gbam_port *port, bool in)
+{
+	unsigned long		flags;
+	int			ret = 0;
+	struct usb_ep		*ep;
+	struct list_head	*idle;
+	unsigned int		queue_size;
+	spinlock_t		*spinlock;
+	void		(*ep_complete)(struct usb_ep *, struct usb_request *);
+
+	if (in)
+		spinlock = &port->port_lock_dl;
+	else
+		spinlock = &port->port_lock_ul;
+
+	spin_lock_irqsave(spinlock, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(spinlock, flags);
+		return -EBUSY;
+	}
+
+	if (in) {
+		ep = port->port_usb->in;
+		idle = &port->data_ch.tx_idle;
+		queue_size = bam_mux_tx_q_size;
+		ep_complete = gbam_epin_complete;
+	} else {
+		ep = port->port_usb->out;
+		if (!ep)
+			goto out;
+		idle = &port->data_ch.rx_idle;
+		queue_size = bam_mux_rx_q_size;
+		ep_complete = gbam_epout_complete;
+	}
+
+	ret = gbam_alloc_requests(ep, idle, queue_size, ep_complete,
+			GFP_ATOMIC);
+out:
+	spin_unlock_irqrestore(spinlock, flags);
+	if (ret)
+		pr_err("%s: allocation failed\n", __func__);
+
+	return ret;
+}
+
+static void gbam_start_io(struct gbam_port *port)
+{
+	unsigned long		flags;
+
+	pr_debug("%s: port:%pK\n", __func__, port);
+
+	if (_gbam_start_io(port, true))
+		return;
+
+	if (_gbam_start_io(port, false)) {
+		spin_lock_irqsave(&port->port_lock_dl, flags);
+		if (port->port_usb)
+			gbam_free_requests(port->port_usb->in,
+				&port->data_ch.tx_idle);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		return;
+	}
+
+	/* queue out requests */
+	gbam_start_rx(port);
+}
+
+static void gbam_notify(void *p, int event, unsigned long data)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+
+	if (port == NULL)
+		pr_err("BAM DMUX notifying after channel close\n");
+
+	switch (event) {
+	case BAM_DMUX_RECEIVE:
+		skb = (struct sk_buff *)data;
+		if (port)
+			gbam_data_recv_cb(p, skb);
+		else
+			dev_kfree_skb_any(skb);
+		break;
+	case BAM_DMUX_WRITE_DONE:
+		skb = (struct sk_buff *)data;
+		if (port)
+			gbam_data_write_done(p, skb);
+		else
+			dev_kfree_skb_any(skb);
+		break;
+	case BAM_DMUX_TRANSMIT_SIZE:
+		d = &port->data_ch;
+		if (test_bit(BAM_CH_OPENED, &d->flags))
+			pr_warn("%s, BAM channel opened already", __func__);
+		bam_mux_rx_req_size = data;
+		pr_debug("%s rx_req_size: %lu", __func__, bam_mux_rx_req_size);
+		break;
+	}
+}
+
+static void gbam_free_rx_buffers(struct gbam_port *port)
+{
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	struct bam_ch_info	*d;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+
+	if (!port->port_usb || !port->port_usb->out)
+		goto free_rx_buf_out;
+
+	d = &port->data_ch;
+	gbam_free_requests(port->port_usb->out, &d->rx_idle);
+
+	while ((skb = __skb_dequeue(&d->rx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+	gbam_free_rx_skb_idle_list(port);
+
+free_rx_buf_out:
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+}
+
+static void gbam_free_tx_buffers(struct gbam_port *port)
+{
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	struct bam_ch_info	*d;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+
+	if (!port->port_usb)
+		goto free_tx_buf_out;
+
+	d = &port->data_ch;
+	gbam_free_requests(port->port_usb->in, &d->tx_idle);
+
+	while ((skb = __skb_dequeue(&d->tx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+free_tx_buf_out:
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+}
+
+static void gbam_free_buffers(struct gbam_port *port)
+{
+	gbam_free_rx_buffers(port);
+	gbam_free_tx_buffers(port);
+}
+
+static void gbam_disconnect_work(struct work_struct *w)
+{
+	struct gbam_port *port =
+			container_of(w, struct gbam_port, disconnect_w);
+	struct bam_ch_info *d = &port->data_ch;
+
+	if (!test_bit(BAM_CH_OPENED, &d->flags)) {
+		pr_err("%s: Bam channel is not opened\n", __func__);
+		goto exit;
+	}
+
+	msm_bam_dmux_close(d->id);
+	clear_bit(BAM_CH_OPENED, &d->flags);
+exit:
+	return;
+}
+
+static void gbam_connect_work(struct work_struct *w)
+{
+	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct bam_ch_info *d = &port->data_ch;
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock(&port->port_lock_dl);
+	if (!port->port_usb) {
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	if (!test_bit(BAM_CH_READY, &d->flags)) {
+		pr_err("%s: Bam channel is not ready\n", __func__);
+		return;
+	}
+
+	ret = msm_bam_dmux_open(d->id, port, gbam_notify);
+	if (ret) {
+		pr_err("%s: unable open bam ch:%d err:%d\n",
+				__func__, d->id, ret);
+		return;
+	}
+
+	set_bit(BAM_CH_OPENED, &d->flags);
+
+	gbam_start_io(port);
+
+	pr_debug("%s: done\n", __func__);
+}
+
+/* BAM data channel ready, allow attempt to open */
+static int gbam_data_ch_probe(struct platform_device *pdev)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			i;
+	unsigned long		flags;
+	bool			do_work = false;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
+		port = bam_ports[i].port;
+		if (!port)
+			continue;
+
+		d = &port->data_ch;
+
+		if (!strcmp(bam_ch_names[i], pdev->name)) {
+			set_bit(BAM_CH_READY, &d->flags);
+
+			/* if usb is online, try opening bam_ch */
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock(&port->port_lock_dl);
+			if (port->port_usb)
+				do_work = true;
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+			if (do_work)
+				queue_work(gbam_wq, &port->connect_w);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* BAM data channel went inactive, so close it */
+static int gbam_data_ch_remove(struct platform_device *pdev)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct usb_ep		*ep_in = NULL;
+	struct usb_ep		*ep_out = NULL;
+	unsigned long		flags;
+	int			i;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
+		if (!strcmp(bam_ch_names[i], pdev->name)) {
+			port = bam_ports[i].port;
+			if (!port)
+				continue;
+
+			d = &port->data_ch;
+
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock(&port->port_lock_dl);
+			if (port->port_usb) {
+				ep_in = port->port_usb->in;
+				ep_out = port->port_usb->out;
+			}
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+			if (ep_in)
+				usb_ep_fifo_flush(ep_in);
+			if (ep_out)
+				usb_ep_fifo_flush(ep_out);
+
+			gbam_free_buffers(port);
+
+			msm_bam_dmux_close(d->id);
+
+			/* bam dmux will free all pending skbs */
+			d->pending_pkts_with_bam = 0;
+			d->pending_bytes_with_bam = 0;
+
+			clear_bit(BAM_CH_READY, &d->flags);
+			clear_bit(BAM_CH_OPENED, &d->flags);
+		}
+	}
+
+	return 0;
+}
+
+static void gbam_port_free(enum bam_dmux_func_type func)
+{
+	struct gbam_port *port = bam_ports[func].port;
+	struct platform_driver *pdrv = &bam_ports[func].pdrv;
+
+	if (port)
+		platform_driver_unregister(pdrv);
+
+	kfree(port);
+}
+
+static int gbam_port_alloc(enum bam_dmux_func_type func)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct platform_driver	*pdrv;
+
+	port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->port_num = func;
+
+	/* port initialization */
+	port->is_connected = false;
+	spin_lock_init(&port->port_lock_ul);
+	spin_lock_init(&port->port_lock_dl);
+	spin_lock_init(&port->port_lock);
+	INIT_WORK(&port->connect_w, gbam_connect_work);
+	INIT_WORK(&port->disconnect_w, gbam_disconnect_work);
+
+	/* data ch */
+	d = &port->data_ch;
+	d->port = port;
+	INIT_LIST_HEAD(&d->tx_idle);
+	INIT_LIST_HEAD(&d->rx_idle);
+	INIT_WORK(&d->write_tobam_w, gbam_data_write_tobam);
+	INIT_WORK(&d->write_tohost_w, gbam_write_data_tohost_w);
+	skb_queue_head_init(&d->tx_skb_q);
+	skb_queue_head_init(&d->rx_skb_q);
+	skb_queue_head_init(&d->rx_skb_idle);
+	d->id = bam_ch_ids[func];
+
+	bam_ports[func].port = port;
+
+	scnprintf(bam_ch_names[func], BAM_DMUX_CH_NAME_MAX_LEN,
+			"bam_dmux_ch_%d", bam_ch_ids[func]);
+	pdrv = &bam_ports[func].pdrv;
+	pdrv->probe = gbam_data_ch_probe;
+	pdrv->remove = gbam_data_ch_remove;
+	pdrv->driver.name = bam_ch_names[func];
+	pdrv->driver.owner = THIS_MODULE;
+
+	platform_driver_register(pdrv);
+	pr_debug("%s: port:%pK portno:%d\n", __func__, port, func);
+
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE	1024
+static ssize_t gbam_read_stats(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	char			*buf;
+	unsigned long		flags;
+	int			ret;
+	int			i;
+	int			temp = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
+		port = bam_ports[i].port;
+		if (!port)
+			continue;
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock(&port->port_lock_dl);
+
+		d = &port->data_ch;
+
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"#PORT:%d port:%pK data_ch:%pK#\n"
+				"dpkts_to_usbhost: %lu\n"
+				"dpkts_to_modem:  %lu\n"
+				"dpkts_pwith_bam: %u\n"
+				"dbytes_pwith_bam: %u\n"
+				"to_usbhost_dcnt:  %u\n"
+				"tomodem__dcnt:  %u\n"
+				"rx_flow_control_disable_count: %u\n"
+				"rx_flow_control_enable_count: %u\n"
+				"rx_flow_control_triggered: %u\n"
+				"max_num_pkts_pending_with_bam: %u\n"
+				"max_bytes_pending_with_bam: %u\n"
+				"delayed_bam_mux_write_done: %u\n"
+				"tx_buf_len:	 %u\n"
+				"rx_buf_len:	 %u\n"
+				"data_ch_open:   %d\n"
+				"data_ch_ready:  %d\n"
+				"skb_expand_cnt: %lu\n",
+				i, port, &port->data_ch,
+				d->to_host, d->to_modem,
+				d->pending_pkts_with_bam,
+				d->pending_bytes_with_bam,
+				d->tohost_drp_cnt, d->tomodem_drp_cnt,
+				d->rx_flow_control_disable,
+				d->rx_flow_control_enable,
+				d->rx_flow_control_triggered,
+				d->max_num_pkts_pending_with_bam,
+				d->max_bytes_pending_with_bam,
+				d->delayed_bam_mux_write_done,
+				d->tx_skb_q.qlen, d->rx_skb_q.qlen,
+				test_bit(BAM_CH_OPENED, &d->flags),
+				test_bit(BAM_CH_READY, &d->flags),
+				d->skb_expand_cnt);
+
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t gbam_reset_stats(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			i;
+	unsigned long		flags;
+
+	for (i = 0; i < BAM_DMUX_NUM_FUNCS; i++) {
+		port = bam_ports[i].port;
+		if (!port)
+			continue;
+
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock(&port->port_lock_dl);
+
+		d = &port->data_ch;
+
+		d->to_host = 0;
+		d->to_modem = 0;
+		d->pending_pkts_with_bam = 0;
+		d->pending_bytes_with_bam = 0;
+		d->tohost_drp_cnt = 0;
+		d->tomodem_drp_cnt = 0;
+		d->rx_flow_control_disable = 0;
+		d->rx_flow_control_enable = 0;
+		d->rx_flow_control_triggered = 0;
+		d->max_num_pkts_pending_with_bam = 0;
+		d->max_bytes_pending_with_bam = 0;
+		d->delayed_bam_mux_write_done = 0;
+		d->skb_expand_cnt = 0;
+
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	}
+	return count;
+}
+
+static const struct file_operations gbam_stats_ops = {
+	.read = gbam_read_stats,
+	.write = gbam_reset_stats,
+};
+
+static struct dentry *gbam_dent;
+static void gbam_debugfs_init(void)
+{
+	struct dentry *dfile;
+
+	if (gbam_dent)
+		return;
+
+	gbam_dent = debugfs_create_dir("usb_rmnet", NULL);
+	if (!gbam_dent || IS_ERR(gbam_dent))
+		return;
+
+	dfile = debugfs_create_file("status", 0444, gbam_dent, NULL,
+			&gbam_stats_ops);
+	if (!dfile || IS_ERR(dfile)) {
+		debugfs_remove(gbam_dent);
+		gbam_dent = NULL;
+		return;
+	}
+}
+static void gbam_debugfs_remove(void)
+{
+	debugfs_remove_recursive(gbam_dent);
+}
+#else
+static inline void gbam_debugfs_init(void) {}
+static inline void gbam_debugfs_remove(void) {}
+#endif
+
+void gbam_disconnect(struct data_port *gr, enum bam_dmux_func_type func)
+{
+	struct gbam_port	*port;
+	unsigned long		flags, flags_ul;
+	struct bam_ch_info	*d;
+
+	pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, func);
+
+	if (func >= BAM_DMUX_NUM_FUNCS) {
+		pr_err("%s: invalid bam portno#%d\n", __func__, func);
+		return;
+	}
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return;
+	}
+	port = bam_ports[func].port;
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+	/* Already disconnected due to suspend with remote wake disabled */
+	if (port->last_event == U_BAM_DISCONNECT_E) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+
+	port->port_usb = gr;
+
+	gbam_free_buffers(port);
+
+	spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+	spin_lock(&port->port_lock_dl);
+	port->port_usb = NULL;
+	n_tx_req_queued = 0;
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+
+	usb_ep_disable(gr->in);
+	/* disable endpoints */
+	if (gr->out)
+		usb_ep_disable(gr->out);
+
+	gr->in->driver_data = NULL;
+	if (gr->out)
+		gr->out->driver_data = NULL;
+
+	port->last_event = U_BAM_DISCONNECT_E;
+	queue_work(gbam_wq, &port->disconnect_w);
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+int gbam_connect(struct data_port *gr, enum bam_dmux_func_type func)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			ret;
+	unsigned long		flags, flags_ul;
+
+	pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, func);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!gr->cdev->gadget) {
+		pr_err("%s: gadget handle not passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (func >= BAM_DMUX_NUM_FUNCS) {
+		pr_err("%s: invalid portno#%d\n", __func__, func);
+		return -ENODEV;
+	}
+
+	port = bam_ports[func].port;
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+	spin_lock(&port->port_lock_dl);
+	port->port_usb = gr;
+	port->gadget = port->port_usb->cdev->gadget;
+
+	d->to_host = 0;
+	d->to_modem = 0;
+	d->pending_pkts_with_bam = 0;
+	d->pending_bytes_with_bam = 0;
+	d->tohost_drp_cnt = 0;
+	d->tomodem_drp_cnt = 0;
+	d->rx_flow_control_disable = 0;
+	d->rx_flow_control_enable = 0;
+	d->rx_flow_control_triggered = 0;
+	d->max_num_pkts_pending_with_bam = 0;
+	d->max_bytes_pending_with_bam = 0;
+	d->delayed_bam_mux_write_done = 0;
+
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+
+	ret = usb_ep_enable(gr->in);
+	if (ret) {
+		pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK",
+			__func__, gr->in);
+		usb_ep_free_request(port->port_usb->out, d->rx_req);
+		d->rx_req = NULL;
+		usb_ep_free_request(port->port_usb->in, d->tx_req);
+		d->tx_req = NULL;
+		goto exit;
+	}
+	gr->in->driver_data = port;
+
+	/*
+	 * DPL traffic is routed through BAM-DMUX on some targets.
+	 * DPL function has only 1 IN endpoint. Add out endpoint
+	 * checks for BAM-DMUX transport.
+	 */
+	if (gr->out) {
+		ret = usb_ep_enable(gr->out);
+		if (ret) {
+			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%pK",
+					__func__, gr->out);
+			gr->in->driver_data = NULL;
+			usb_ep_disable(gr->in);
+			usb_ep_free_request(port->port_usb->out, d->rx_req);
+			d->rx_req = NULL;
+			usb_ep_free_request(port->port_usb->in, d->tx_req);
+			d->tx_req = NULL;
+			goto exit;
+		}
+		gr->out->driver_data = port;
+	}
+
+	port->last_event = U_BAM_CONNECT_E;
+	queue_work(gbam_wq, &port->connect_w);
+
+	ret = 0;
+exit:
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	return ret;
+}
+
+int gbam_setup(enum bam_dmux_func_type func)
+{
+	int	ret;
+
+	pr_debug("%s: requested BAM port:%d\n", __func__, func);
+
+	if (func >= BAM_DMUX_NUM_FUNCS) {
+		pr_err("%s: Invalid num of ports count:%d\n", __func__, func);
+		return -EINVAL;
+	}
+
+	if (!gbam_wq) {
+		gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
+					WQ_MEM_RECLAIM, 1);
+		if (!gbam_wq) {
+			pr_err("%s: Unable to create workqueue gbam_wq\n",
+					__func__);
+			return -ENOMEM;
+		}
+	}
+
+	ret = gbam_port_alloc(func);
+	if (ret) {
+		pr_err("%s: Unable to alloc port:%d\n", __func__, func);
+		goto destroy_wq;
+	}
+
+	gbam_debugfs_init();
+
+	return 0;
+
+destroy_wq:
+	destroy_workqueue(gbam_wq);
+
+	return ret;
+}
+
+void gbam_cleanup(enum bam_dmux_func_type func)
+{
+	gbam_debugfs_remove();
+	gbam_port_free(func);
+}
+
+int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
+			struct usb_ep *out)
+{
+	struct data_port *gr;
+
+	gr = kzalloc(sizeof(*gr), GFP_ATOMIC);
+	if (!gr)
+		return -ENOMEM;
+	gr->in = in;
+	gr->out = out;
+	gr->cdev->gadget = g;
+
+	return gbam_connect(gr, BAM_DMUX_FUNC_MBIM);
+}
+
+void gbam_mbim_disconnect(void)
+{
+	struct gbam_port *port = bam_ports[BAM_DMUX_FUNC_MBIM].port;
+	struct data_port *gr = port->port_usb;
+
+	if (!gr) {
+		pr_err("%s: port_usb is NULL\n", __func__);
+		return;
+	}
+
+	gbam_disconnect(gr, BAM_DMUX_FUNC_MBIM);
+	kfree(gr);
+}
+
+int gbam_mbim_setup(void)
+{
+	int ret = 0;
+
+	ret = gbam_setup(BAM_DMUX_FUNC_MBIM);
+
+	return ret;
+}
diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c
index 96018f7..4ab7bc4 100644
--- a/drivers/usb/gadget/function/u_ctrl_qti.c
+++ b/drivers/usb/gadget/function/u_ctrl_qti.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,8 @@
 #include <linux/cdev.h>
 #include <linux/debugfs.h>
 
+#include <soc/qcom/bam_dmux.h>
+
 #include "u_rmnet.h"
 #include "f_qdss.h"
 
@@ -206,7 +208,8 @@
 	qti_ctrl_queue_notify(port);
 }
 
-int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf)
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf,
+						enum data_xport_type dxport)
 {
 	struct qti_ctrl_port	*port;
 	struct grmnet *g_rmnet = NULL;
@@ -226,8 +229,16 @@
 
 	spin_lock_irqsave(&port->lock, flags);
 	port->port_type = qport;
-	port->ep_type = DATA_EP_TYPE_HSUSB;
-	port->intf = intf;
+	if (dxport == BAM_DMUX) {
+		port->ep_type = DATA_EP_TYPE_BAM_DMUX;
+		port->intf = (qport == QTI_PORT_RMNET) ?
+			BAM_DMUX_USB_RMNET_0 : BAM_DMUX_USB_DPL;
+		port->ipa_prod_idx = 0;
+		port->ipa_cons_idx = 0;
+	} else {
+		port->ep_type = DATA_EP_TYPE_HSUSB;
+		port->intf = intf;
+	}
 
 	if (gr) {
 		port->port_usb = gr;
@@ -330,7 +341,7 @@
 static int qti_ctrl_open(struct inode *ip, struct file *fp)
 {
 	unsigned long		flags;
-	struct qti_ctrl_port *port = container_of(fp->private_data,
+	struct qti_ctrl_port *port = container_of(ip->i_cdev,
 						struct qti_ctrl_port,
 						ctrl_device);
 
@@ -342,6 +353,7 @@
 		return -EBUSY;
 	}
 
+	fp->private_data = port;
 	spin_lock_irqsave(&port->lock, flags);
 	port->is_open = true;
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -352,7 +364,7 @@
 static int qti_ctrl_release(struct inode *ip, struct file *fp)
 {
 	unsigned long		flags;
-	struct qti_ctrl_port *port = container_of(fp->private_data,
+	struct qti_ctrl_port *port = container_of(ip->i_cdev,
 						struct qti_ctrl_port,
 						ctrl_device);
 
@@ -370,9 +382,7 @@
 static ssize_t
 qti_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
 {
-	struct qti_ctrl_port *port = container_of(fp->private_data,
-						struct qti_ctrl_port,
-						ctrl_device);
+	struct qti_ctrl_port *port = fp->private_data;
 	struct rmnet_ctrl_pkt *cpkt = NULL;
 	unsigned long flags;
 	int ret = 0;
@@ -444,9 +454,7 @@
 qti_ctrl_write(struct file *fp, const char __user *buf, size_t count,
 		   loff_t *pos)
 {
-	struct qti_ctrl_port *port = container_of(fp->private_data,
-						struct qti_ctrl_port,
-						ctrl_device);
+	struct qti_ctrl_port *port = fp->private_data;
 	void *kbuf;
 	unsigned long flags;
 	int ret = 0;
@@ -523,9 +531,7 @@
 
 static long qti_ctrl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 {
-	struct qti_ctrl_port *port = container_of(fp->private_data,
-						struct qti_ctrl_port,
-						ctrl_device);
+	struct qti_ctrl_port *port = fp->private_data;
 	struct grmnet *gr = NULL;
 	struct ep_info info;
 	int val, ret = 0;
@@ -621,9 +627,7 @@
 
 static unsigned int qti_ctrl_poll(struct file *file, poll_table *wait)
 {
-	struct qti_ctrl_port *port = container_of(file->private_data,
-						struct qti_ctrl_port,
-						ctrl_device);
+	struct qti_ctrl_port *port = file->private_data;
 	unsigned long flags;
 	unsigned int mask = 0;
 
@@ -756,18 +760,19 @@
 #endif
 	.poll = qti_ctrl_poll,
 };
+#define RMNET_MODULE_NAME "rmnet_ctrl"
 
 static int qti_ctrl_alloc_chardev_region(void)
 {
 	int ret;
 
-	rmnet_class = class_create(THIS_MODULE, MODULE_NAME);
+	rmnet_class = class_create(THIS_MODULE, RMNET_MODULE_NAME);
 	if (IS_ERR(rmnet_class)) {
 		pr_err("class_create() failed ENOMEM\n");
 		ret = -ENOMEM;
 	}
 	ret = alloc_chrdev_region(&qti_ctrl_dev, 0, QTI_NUM_PORTS,
-		MODULE_NAME);
+		RMNET_MODULE_NAME);
 	if (ret < 0) {
 		pr_err("alloc_chrdev_region() failed ret:%i\n", ret);
 		return ret;
@@ -819,18 +824,6 @@
 			snprintf(port->name, sz, "%s%d",
 				RMNET_CTRL_QTI_NAME, i);
 
-		port->ctrl_device.owner = THIS_MODULE;
-		if (i == QTI_PORT_DPL)
-			cdev_init(&port->ctrl_device, &dpl_qti_ctrl_fops);
-		else
-			cdev_init(&port->ctrl_device, &qti_ctrl_fops);
-
-		ret = cdev_add(&port->ctrl_device, qti_ctrl_dev + i, 1);
-		if (ret < 0) {
-			pr_err("cdev_add() failed ret:%d\n", ret);
-			goto fail_cdev;
-		}
-
 		port->dev = device_create(rmnet_class, NULL, qti_ctrl_dev+i,
 				port->dev, port->name);
 		if (IS_ERR(port->dev)) {
@@ -838,12 +831,24 @@
 			ret = -ENOMEM;
 			goto fail_device_create;
 		}
+
+		if (i == QTI_PORT_DPL)
+			cdev_init(&port->ctrl_device, &dpl_qti_ctrl_fops);
+		else
+			cdev_init(&port->ctrl_device, &qti_ctrl_fops);
+
+		port->ctrl_device.owner = THIS_MODULE;
+		ret = cdev_add(&port->ctrl_device, qti_ctrl_dev + i, 1);
+		if (ret < 0) {
+			pr_err("cdev_add() failed ret:%d\n", ret);
+			goto fail_cdev;
+		}
 	}
 	qti_ctrl_debugfs_init();
 	return ret;
-fail_device_create:
-	cdev_del(&port->ctrl_device);
 fail_cdev:
+	cdev_del(&port->ctrl_device);
+fail_device_create:
 	class_destroy(rmnet_class);
 	unregister_chrdev_region(MAJOR(qti_ctrl_dev), QTI_NUM_PORTS);
 fail_init:
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index f379028..7af152b3 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -23,7 +23,6 @@
 #include <linux/usb_bam.h>
 
 #include "u_data_ipa.h"
-#include "u_rmnet.h"
 
 struct ipa_data_ch_info {
 	struct usb_request			*rx_req;
@@ -45,7 +44,7 @@
 	u8					src_connection_idx;
 	u8					dst_connection_idx;
 	enum usb_ctrl				usb_bam_type;
-	struct gadget_ipa_port			*port_usb;
+	struct data_port			*port_usb;
 	struct usb_gadget			*gadget;
 	atomic_t				pipe_connect_notified;
 	struct usb_bam_connect_ipa_params	ipa_params;
@@ -299,7 +298,7 @@
  * switch is being trigger. This API performs restoring USB endpoint operation
  * and disable USB endpoint used for accelerated path.
  */
-void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func)
+void ipa_data_disconnect(struct data_port *gp, enum ipa_func_type func)
 {
 	struct ipa_data_ch_info *port;
 	unsigned long flags;
@@ -402,7 +401,7 @@
 {
 	struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
 								connect_w);
-	struct gadget_ipa_port	*gport;
+	struct data_port	*gport;
 	struct usb_gadget	*gadget = NULL;
 	struct teth_bridge_connect_params connect_params;
 	struct teth_bridge_init_params teth_bridge_params;
@@ -478,7 +477,7 @@
 		configure_fifo(port->usb_bam_type,
 				port->src_connection_idx,
 				port->port_usb->out);
-		ret = msm_ep_config(gport->out);
+		ret = msm_ep_config(gport->out, port->rx_req);
 		if (ret) {
 			pr_err("msm_ep_config() failed for OUT EP\n");
 			spin_unlock_irqrestore(&port->port_lock, flags);
@@ -503,7 +502,7 @@
 		port->tx_req->udc_priv = sps_params;
 		configure_fifo(port->usb_bam_type,
 				port->dst_connection_idx, gport->in);
-		ret = msm_ep_config(gport->in);
+		ret = msm_ep_config(gport->in, port->tx_req);
 		if (ret) {
 			pr_err("msm_ep_config() failed for IN EP\n");
 			spin_unlock_irqrestore(&port->port_lock, flags);
@@ -730,7 +729,7 @@
  * initiate USB BAM IPA connection. This API is enabling accelerated endpoints
  * and schedule connect_work() which establishes USB IPA BAM communication.
  */
-int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+int ipa_data_connect(struct data_port *gp, enum ipa_func_type func,
 		u8 src_connection_idx, u8 dst_connection_idx)
 {
 	struct ipa_data_ch_info *port;
@@ -939,7 +938,7 @@
  * It is being used to initiate USB BAM IPA suspend functionality
  * for USB bus suspend functionality.
  */
-void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_suspend(struct data_port *gp, enum ipa_func_type func,
 			bool remote_wakeup_enabled)
 {
 	struct ipa_data_ch_info *port;
@@ -1050,7 +1049,7 @@
  * It is being used to initiate USB resume functionality
  * for USB bus resume case.
  */
-void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_resume(struct data_port *gp, enum ipa_func_type func,
 			bool remote_wakeup_enabled)
 {
 	struct ipa_data_ch_info *port;
diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h
index 70d4293..d2d419b 100644
--- a/drivers/usb/gadget/function/u_data_ipa.h
+++ b/drivers/usb/gadget/function/u_data_ipa.h
@@ -34,19 +34,6 @@
 /* Max Number of IPA data ports supported */
 #define IPA_N_PORTS USB_IPA_NUM_FUNCS
 
-struct gadget_ipa_port {
-	struct usb_composite_dev	*cdev;
-	struct usb_function		*func;
-	int				rx_buffer_size;
-	struct usb_ep			*in;
-	struct usb_ep			*out;
-	int				ipa_consumer_ep;
-	int				ipa_producer_ep;
-	const struct usb_endpoint_descriptor	*in_ep_desc_backup;
-	const struct usb_endpoint_descriptor	*out_ep_desc_backup;
-
-};
-
 struct ipa_function_bind_info {
 	struct usb_string *string_defs;
 	int data_str_idx;
@@ -85,16 +72,16 @@
 };
 
 void ipa_data_port_select(enum ipa_func_type func);
-void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func);
-int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_disconnect(struct data_port *gp, enum ipa_func_type func);
+int ipa_data_connect(struct data_port *gp, enum ipa_func_type func,
 			u8 src_connection_idx, u8 dst_connection_idx);
 int ipa_data_setup(enum ipa_func_type func);
 void ipa_data_free(enum ipa_func_type func);
 
 void ipa_data_flush_workqueue(void);
-void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_resume(struct data_port *gp, enum ipa_func_type func,
 		bool remote_wakeup_enabled);
-void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+void ipa_data_suspend(struct data_port *gp, enum ipa_func_type func,
 		bool remote_wakeup_enabled);
 
 void ipa_data_set_ul_max_xfer_size(u32 ul_max_xfer_size);
@@ -109,11 +96,34 @@
 
 void ipa_data_stop_rndis_ipa(enum ipa_func_type func);
 
+#ifdef CONFIG_USB_F_QCRNDIS
 void *rndis_qc_get_ipa_priv(void);
 void *rndis_qc_get_ipa_rx_cb(void);
 bool rndis_qc_get_skip_ep_config(void);
 void *rndis_qc_get_ipa_tx_cb(void);
 void rndis_ipa_reset_trigger(void);
+#else
+static inline void *rndis_qc_get_ipa_priv(void)
+{
+	return NULL;
+}
+static inline void *rndis_qc_get_ipa_rx_cb(void)
+{
+	return NULL;
+}
+static inline bool rndis_qc_get_skip_ep_config(void)
+{
+	return true;
+}
+static inline void *rndis_qc_get_ipa_tx_cb(void)
+{
+	return NULL;
+}
+static inline void rndis_ipa_reset_trigger(void)
+{
+}
+#endif /* CONFIG_USB_F_QCRNDIS */
+
 #if IS_ENABLED(CONFIG_USB_CONFIGFS_RMNET_BAM)
 void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
 				u32 ipa_prod, u32 ipa_cons);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index cb1ecfa..24f8f1c 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -21,6 +21,10 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/msm_rmnet.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include "u_ether.h"
 
@@ -55,6 +59,9 @@
 
 static struct workqueue_struct	*uether_wq;
 
+/* Extra buffer size to allocate for tx */
+#define EXTRA_ALLOCATION_SIZE_U_ETH	128
+
 struct eth_dev {
 	/* lock is held while accessing port_usb
 	 */
@@ -68,7 +75,7 @@
 	struct list_head	tx_reqs, rx_reqs;
 	unsigned		tx_qlen;
 /* Minimum number of TX USB request queued to UDC */
-#define TX_REQ_THRESHOLD	5
+#define MAX_TX_REQ_WITH_NO_INT	5
 	int			no_tx_req_used;
 	int			tx_skb_hold_count;
 	u32			tx_req_bufsize;
@@ -89,20 +96,43 @@
 	struct work_struct	rx_work;
 
 	unsigned long		todo;
+	unsigned long		flags;
+	unsigned short		rx_needed_headroom;
 #define	WORK_RX_MEMORY		0
 
 	bool			zlp;
 	bool			no_skb_reserve;
 	u8			host_mac[ETH_ALEN];
 	u8			dev_mac[ETH_ALEN];
+	unsigned long		tx_throttle;
+	unsigned long		rx_throttle;
+	unsigned int		tx_pkts_rcvd;
+	unsigned long		skb_expand_cnt;
+	struct dentry		*uether_dent;
+	struct dentry		*uether_dfile;
 };
 
+static void uether_debugfs_init(struct eth_dev *dev);
+static void uether_debugfs_exit(struct eth_dev *dev);
+
 /*-------------------------------------------------------------------------*/
 
 #define RX_EXTRA	20	/* bytes guarding against rx overflows */
 
 #define DEFAULT_QLEN	2	/* double buffering by default */
 
+/*
+ * Usually downlink rates are higher than uplink rates and it
+ * deserve higher number of requests. For CAT-6 data rates of
+ * 300Mbps (~30 packets per milli-sec) 40 usb request may not
+ * be sufficient. At this rate and with interrupt moderation
+ * of interconnect, data can be very bursty. tx_qmult is the
+ * additional multipler on qmult.
+ */
+static unsigned int tx_qmult = 2;
+module_param(tx_qmult, uint, 0644);
+MODULE_PARM_DESC(tx_qmult, "Additional queue length multiplier for tx");
+
 /* for dual-speed hardware, use deeper queues at high/super speed */
 static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
 {
@@ -114,6 +144,10 @@
 }
 
 /*-------------------------------------------------------------------------*/
+#define U_ETHER_RX_PENDING_TSHOLD 500
+
+static unsigned int u_ether_rx_pending_thld = U_ETHER_RX_PENDING_TSHOLD;
+module_param(u_ether_rx_pending_thld, uint, 0644);
 
 /* REVISIT there must be a better way than having two sets
  * of debug calls ...
@@ -161,6 +195,25 @@
 	return 0;
 }
 
+static int ueth_change_mtu_ip(struct net_device *net, int new_mtu)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	unsigned long	flags;
+	int		status = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (new_mtu <= 0)
+		status = -EINVAL;
+	else
+		net->mtu = new_mtu;
+
+	DBG(dev, "[%s] MTU change: old=%d new=%d\n", net->name,
+					net->mtu, new_mtu);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return status;
+}
+
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
 	struct eth_dev *dev = netdev_priv(net);
@@ -208,11 +261,11 @@
 		out = dev->port_usb->out_ep;
 	else
 		out = NULL;
-	spin_unlock_irqrestore(&dev->lock, flags);
 
-	if (!out)
+	if (!out) {
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOTCONN;
-
+	}
 
 	/* Padding up to RX_EXTRA handles minor disagreements with host.
 	 * Normally we use the USB "terminate on short read" convention;
@@ -236,9 +289,10 @@
 
 	if (dev->port_usb->is_fixed)
 		size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+	spin_unlock_irqrestore(&dev->lock, flags);
 
 	DBG(dev, "%s: size: %zd\n", __func__, size);
-	skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+	skb = alloc_skb(size, gfp_flags);
 	if (skb == NULL) {
 		DBG(dev, "no rx skb\n");
 		goto enomem;
@@ -249,7 +303,7 @@
 	 * RNDIS headers involve variable numbers of LE32 values.
 	 */
 	if (likely(!dev->no_skb_reserve))
-		skb_reserve(skb, NET_IP_ALIGN);
+		skb_reserve(skb, 0);
 
 	req->buf = skb->data;
 	req->length = size;
@@ -333,9 +387,20 @@
 	}
 
 clean:
-	spin_lock(&dev->req_lock);
-	list_add(&req->list, &dev->rx_reqs);
-	spin_unlock(&dev->req_lock);
+	if (queue && dev->rx_frames.qlen <= u_ether_rx_pending_thld) {
+		if (rx_submit(dev, req, GFP_ATOMIC) < 0) {
+			spin_lock(&dev->req_lock);
+			list_add(&req->list, &dev->rx_reqs);
+			spin_unlock(&dev->req_lock);
+		}
+	} else {
+		/* rx buffers draining is delayed,defer further queuing to wq */
+		if (queue)
+			dev->rx_throttle++;
+		spin_lock(&dev->req_lock);
+		list_add(&req->list, &dev->rx_reqs);
+		spin_unlock(&dev->req_lock);
+	}
 
 	if (queue)
 		queue_work(uether_wq, &dev->rx_work);
@@ -382,15 +447,20 @@
 
 static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
 {
-	int	status;
+	int	status = 0;
 
 	spin_lock(&dev->req_lock);
-	status = prealloc(&dev->tx_reqs, link->in_ep, n);
-	if (status < 0)
-		goto fail;
-	status = prealloc(&dev->rx_reqs, link->out_ep, n);
-	if (status < 0)
-		goto fail;
+	if (link->in_ep) {
+		status = prealloc(&dev->tx_reqs, link->in_ep, n * tx_qmult);
+			if (status < 0)
+			goto fail;
+	}
+
+	if (link->out_ep) {
+		status = prealloc(&dev->rx_reqs, link->out_ep, n);
+		if (status < 0)
+			goto fail;
+	}
 	goto done;
 fail:
 	DBG(dev, "can't alloc requests\n");
@@ -430,6 +500,31 @@
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 }
 
+static __be16 ether_ip_type_trans(struct sk_buff *skb,
+	struct net_device *dev)
+{
+	__be16	protocol = 0;
+
+	skb->dev = dev;
+
+	switch (skb->data[0] & 0xf0) {
+	case 0x40:
+		protocol = htons(ETH_P_IP);
+		break;
+	case 0x60:
+		protocol = htons(ETH_P_IPV6);
+		break;
+	default:
+		if ((skb->data[0] & 0x40) == 0x00)
+			protocol = htons(ETH_P_MAP);
+		else
+			pr_debug_ratelimited("[%s] L3 protocol decode error: 0x%02x",
+					dev->name, skb->data[0] & 0xf0);
+	}
+
+	return protocol;
+}
+
 static void process_rx_w(struct work_struct *work)
 {
 	struct eth_dev	*dev = container_of(work, struct eth_dev, rx_work);
@@ -449,7 +544,12 @@
 			dev_kfree_skb_any(skb);
 			continue;
 		}
-		skb->protocol = eth_type_trans(skb, dev->net);
+
+		if (test_bit(RMNET_MODE_LLP_IP, &dev->flags))
+			skb->protocol = ether_ip_type_trans(skb, dev->net);
+		else
+			skb->protocol = eth_type_trans(skb, dev->net);
+
 		dev->net->stats.rx_packets++;
 		dev->net->stats.rx_bytes += skb->len;
 
@@ -483,6 +583,11 @@
 	int length;
 	int retval;
 
+	if (!dev->port_usb) {
+		usb_ep_free_request(ep, req);
+		return;
+	}
+
 	switch (req->status) {
 	default:
 		dev->net->stats.tx_errors++;
@@ -493,21 +598,21 @@
 		break;
 	case 0:
 		if (!req->zero)
-			dev->net->stats.tx_bytes += req->length-1;
+			dev->net->stats.tx_bytes += req->actual-1;
 		else
-			dev->net->stats.tx_bytes += req->length;
+			dev->net->stats.tx_bytes += req->actual;
 	}
 	dev->net->stats.tx_packets++;
 
 	spin_lock(&dev->req_lock);
-	list_add_tail(&req->list, &dev->tx_reqs);
 
-	if (dev->port_usb->multi_pkt_xfer) {
+	if (dev->port_usb->multi_pkt_xfer && !req->context) {
 		dev->no_tx_req_used--;
 		req->length = 0;
 		in = dev->port_usb->in_ep;
 
-		if (!list_empty(&dev->tx_reqs)) {
+		/* Do not process further if no_interrupt is set */
+		if (!req->no_interrupt && !list_empty(&dev->tx_reqs)) {
 			new_req = container_of(dev->tx_reqs.next,
 					struct usb_request, list);
 			list_del(&new_req->list);
@@ -535,11 +640,27 @@
 					length++;
 				}
 
+				/* set when tx completion interrupt needed */
+				spin_lock(&dev->req_lock);
+				dev->tx_qlen++;
+				if (dev->tx_qlen == MAX_TX_REQ_WITH_NO_INT) {
+					new_req->no_interrupt = 0;
+					dev->tx_qlen = 0;
+				} else {
+					new_req->no_interrupt = 1;
+				}
+				spin_unlock(&dev->req_lock);
 				new_req->length = length;
+				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
 					DBG(dev, "tx queue err %d\n", retval);
+					new_req->length = 0;
+					spin_lock(&dev->req_lock);
+					list_add_tail(&new_req->list,
+							&dev->tx_reqs);
+					spin_unlock(&dev->req_lock);
 					break;
 				case 0:
 					spin_lock(&dev->req_lock);
@@ -549,17 +670,37 @@
 				}
 			} else {
 				spin_lock(&dev->req_lock);
-				list_add(&new_req->list, &dev->tx_reqs);
+				/*
+				 * Put the idle request at the back of the
+				 * queue. The xmit function will put the
+				 * unfinished request at the beginning of the
+				 * queue.
+				 */
+				list_add_tail(&new_req->list, &dev->tx_reqs);
 				spin_unlock(&dev->req_lock);
 			}
 		} else {
 			spin_unlock(&dev->req_lock);
 		}
 	} else {
+		/* Is aggregation already enabled and buffers allocated ? */
+		if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) {
+			req->buf = kzalloc(dev->tx_req_bufsize
+				+ dev->gadget->extra_buf_alloc, GFP_ATOMIC);
+			req->context = NULL;
+		} else {
+			req->buf = NULL;
+		}
+
 		spin_unlock(&dev->req_lock);
 		dev_kfree_skb_any(skb);
 	}
 
+	/* put the completed req back to tx_reqs tail pool */
+	spin_lock(&dev->req_lock);
+	list_add_tail(&req->list, &dev->tx_reqs);
+	spin_unlock(&dev->req_lock);
+
 	if (netif_carrier_ok(dev->net))
 		netif_wake_queue(dev->net);
 }
@@ -569,7 +710,7 @@
 	return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
 }
 
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
 {
 	struct list_head	*act;
 	struct usb_request	*req;
@@ -584,9 +725,26 @@
 	list_for_each(act, &dev->tx_reqs) {
 		req = container_of(act, struct usb_request, list);
 		if (!req->buf)
-			req->buf = kmalloc(dev->tx_req_bufsize,
-						GFP_ATOMIC);
+			req->buf = kmalloc(dev->tx_req_bufsize
+				+ dev->gadget->extra_buf_alloc, GFP_ATOMIC);
+
+		if (!req->buf)
+			goto free_buf;
+
+		/* req->context is not used for multi_pkt_xfers */
+		req->context = NULL;
 	}
+	return 0;
+
+free_buf:
+	/* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+	dev->tx_req_bufsize = 0;
+	list_for_each(act, &dev->tx_reqs) {
+		req = container_of(act, struct usb_request, list);
+		kfree(req->buf);
+		req->buf = NULL;
+	}
+	return -ENOMEM;
 }
 
 static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -594,19 +752,25 @@
 {
 	struct eth_dev		*dev = netdev_priv(net);
 	int			length = 0;
+	int			tail_room = 0;
+	int			extra_alloc = 0;
 	int			retval;
 	struct usb_request	*req = NULL;
+	struct sk_buff		*new_skb;
 	unsigned long		flags;
-	struct usb_ep		*in;
-	u16			cdc_filter;
+	struct usb_ep		*in = NULL;
+	u16			cdc_filter = 0;
+	bool			multi_pkt_xfer = false;
+	u32			fixed_in_len = 0;
+	bool			is_fixed = false;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->port_usb) {
 		in = dev->port_usb->in_ep;
 		cdc_filter = dev->port_usb->cdc_filter;
-	} else {
-		in = NULL;
-		cdc_filter = 0;
+		is_fixed = dev->port_usb->is_fixed;
+		fixed_in_len = dev->port_usb->fixed_in_len;
+		multi_pkt_xfer = dev->port_usb->multi_pkt_xfer;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -615,10 +779,6 @@
 		return NETDEV_TX_OK;
 	}
 
-	/* Allocate memory for tx_reqs to support multi packet transfer */
-	if (dev->port_usb->multi_pkt_xfer && !dev->tx_req_bufsize)
-		alloc_tx_buffer(dev);
-
 	/* apply outgoing CDC or RNDIS filters */
 	if (skb && !is_promisc(cdc_filter)) {
 		u8		*dest = skb->data;
@@ -641,7 +801,41 @@
 		/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
 	}
 
+	dev->tx_pkts_rcvd++;
+	/*
+	 * no buffer copies needed, unless the network stack did it
+	 * or the hardware can't use skb buffers.
+	 * or there's not enough space for extra headers we need
+	 */
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->wrap && dev->port_usb)
+		skb = dev->wrap(dev->port_usb, skb);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (!skb) {
+		if (dev->port_usb && dev->port_usb->supports_multi_frame) {
+			/*
+			 * Multi frame CDC protocols may store the frame for
+			 * later which is not a dropped frame.
+			 */
+		} else {
+			dev->net->stats.tx_dropped++;
+		}
+
+		/* no error code for dropped packets */
+		return NETDEV_TX_OK;
+	}
+
+	/* Allocate memory for tx_reqs to support multi packet transfer */
 	spin_lock_irqsave(&dev->req_lock, flags);
+	if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+		retval = alloc_tx_buffer(dev);
+		if (retval < 0) {
+			spin_unlock_irqrestore(&dev->req_lock, flags);
+			return -ENOMEM;
+		}
+	}
+
 	/*
 	 * this freelist can be empty if an interrupt triggered disconnect()
 	 * and reconfigured the gadget (shutting down this queue) after the
@@ -656,37 +850,20 @@
 	list_del(&req->list);
 
 	/* temporarily stop TX queue when the freelist empties */
-	if (list_empty(&dev->tx_reqs))
+	if (list_empty(&dev->tx_reqs)) {
+		/*
+		 * tx_throttle gives info about number of times u_ether
+		 * asked network layer to stop queueing packets to it
+		 * when transmit resources are unavailable
+		 */
+		dev->tx_throttle++;
 		netif_stop_queue(net);
-	spin_unlock_irqrestore(&dev->req_lock, flags);
-
-	/* no buffer copies needed, unless the network stack did it
-	 * or the hardware can't use skb buffers.
-	 * or there's not enough space for extra headers we need
-	 */
-	if (dev->wrap) {
-		unsigned long	flags;
-
-		spin_lock_irqsave(&dev->lock, flags);
-		if (dev->port_usb)
-			skb = dev->wrap(dev->port_usb, skb);
-		spin_unlock_irqrestore(&dev->lock, flags);
-		if (!skb) {
-			/* Multi frame CDC protocols may store the frame for
-			 * later which is not a dropped frame.
-			 */
-			if (dev->port_usb &&
-					dev->port_usb->supports_multi_frame)
-				goto multiframe;
-			goto drop;
-		}
 	}
 
-	spin_lock_irqsave(&dev->req_lock, flags);
 	dev->tx_skb_hold_count++;
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 
-	if (dev->port_usb->multi_pkt_xfer) {
+	if (multi_pkt_xfer) {
 		memcpy(req->buf + req->length, skb->data, skb->len);
 		req->length = req->length + skb->len;
 		length = req->length;
@@ -694,7 +871,13 @@
 
 		spin_lock_irqsave(&dev->req_lock, flags);
 		if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
-			if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
+			/*
+			 * should allow aggregation only, if the number of
+			 * requests queued more than the tx requests that can
+			 * be queued with no interrupt flag set sequentially.
+			 * Otherwise, packets may be blocked forever.
+			 */
+			if (dev->no_tx_req_used > MAX_TX_REQ_WITH_NO_INT) {
 				list_add(&req->list, &dev->tx_reqs);
 				spin_unlock_irqrestore(&dev->req_lock, flags);
 				goto success;
@@ -708,6 +891,35 @@
 		dev->tx_skb_hold_count = 0;
 		spin_unlock_irqrestore(&dev->lock, flags);
 	} else {
+		bool do_align = false;
+
+		/* Check if TX buffer should be aligned before queuing to hw */
+		if (dev->gadget->is_chipidea &&
+		    !IS_ALIGNED((size_t)skb->data, 4))
+			do_align = true;
+
+		/*
+		 * Some UDC requires allocation of some extra bytes for
+		 * TX buffer due to hardware requirement. Check if extra
+		 * bytes are already there, otherwise allocate new buffer
+		 * with extra bytes and do memcpy to align skb as well.
+		 */
+		if (dev->gadget->extra_buf_alloc)
+			extra_alloc = EXTRA_ALLOCATION_SIZE_U_ETH;
+		tail_room = skb_tailroom(skb);
+		if (do_align || tail_room < extra_alloc) {
+			pr_debug("%s:align skb and update tail_room %d to %d\n",
+					__func__, tail_room, extra_alloc);
+			tail_room = extra_alloc;
+			new_skb = skb_copy_expand(skb, 0, tail_room,
+						  GFP_ATOMIC);
+			if (!new_skb)
+				return -ENOMEM;
+			dev_kfree_skb_any(skb);
+			skb = new_skb;
+			dev->skb_expand_cnt++;
+		}
+
 		length = skb->len;
 		req->buf = skb->data;
 		req->context = skb;
@@ -716,9 +928,7 @@
 	req->complete = tx_complete;
 
 	/* NCM requires no zlp if transfer is dwNtbInMaxSize */
-	if (dev->port_usb &&
-	    dev->port_usb->is_fixed &&
-	    length == dev->port_usb->fixed_in_len &&
+	if (is_fixed && length == fixed_in_len &&
 	    (length % in->maxpacket) == 0)
 		req->zero = 0;
 	else
@@ -738,13 +948,15 @@
 	/* throttle highspeed IRQ rate back slightly */
 	if (gadget_is_dualspeed(dev->gadget) &&
 			 (dev->gadget->speed == USB_SPEED_HIGH)) {
+		spin_lock_irqsave(&dev->req_lock, flags);
 		dev->tx_qlen++;
-		if (dev->tx_qlen == (dev->qmult/2)) {
+		if (dev->tx_qlen == MAX_TX_REQ_WITH_NO_INT) {
 			req->no_interrupt = 0;
 			dev->tx_qlen = 0;
 		} else {
 			req->no_interrupt = 1;
 		}
+		spin_unlock_irqrestore(&dev->req_lock, flags);
 	} else {
 		req->no_interrupt = 0;
 	}
@@ -759,11 +971,11 @@
 	}
 
 	if (retval) {
-		if (!dev->port_usb->multi_pkt_xfer)
+		if (!multi_pkt_xfer)
 			dev_kfree_skb_any(skb);
-drop:
+		else
+			req->length = 0;
 		dev->net->stats.tx_dropped++;
-multiframe:
 		spin_lock_irqsave(&dev->req_lock, flags);
 		if (list_empty(&dev->tx_reqs))
 			netif_start_queue(net);
@@ -838,16 +1050,24 @@
 		 * their own pace; the network stack can handle old packets.
 		 * For the moment we leave this here, since it works.
 		 */
-		in = link->in_ep->desc;
-		out = link->out_ep->desc;
-		usb_ep_disable(link->in_ep);
-		usb_ep_disable(link->out_ep);
-		if (netif_carrier_ok(net)) {
-			DBG(dev, "host still using in/out endpoints\n");
-			link->in_ep->desc = in;
-			link->out_ep->desc = out;
-			usb_ep_enable(link->in_ep);
-			usb_ep_enable(link->out_ep);
+		if (link->in_ep) {
+			in = link->in_ep->desc;
+			usb_ep_disable(link->in_ep);
+			if (netif_carrier_ok(net)) {
+				DBG(dev, "host still using in endpoints\n");
+				link->in_ep->desc = in;
+				usb_ep_enable(link->in_ep);
+			}
+		}
+
+		if (link->out_ep) {
+			out = link->out_ep->desc;
+			usb_ep_disable(link->out_ep);
+			if (netif_carrier_ok(net)) {
+				DBG(dev, "host still using out endpoints\n");
+				link->out_ep->desc = out;
+				usb_ep_enable(link->out_ep);
+			}
 		}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -887,15 +1107,176 @@
 	return 18;
 }
 
+static int ether_ioctl(struct net_device *, struct ifreq *, int);
+
 static const struct net_device_ops eth_netdev_ops = {
 	.ndo_open		= eth_open,
 	.ndo_stop		= eth_stop,
 	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
 	.ndo_change_mtu		= ueth_change_mtu,
 	.ndo_set_mac_address 	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
+static const struct net_device_ops eth_netdev_ops_ip = {
+	.ndo_open		= eth_open,
+	.ndo_stop		= eth_stop,
+	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
+	.ndo_change_mtu		= ueth_change_mtu_ip,
+	.ndo_set_mac_address	= NULL,
+	.ndo_validate_addr	= NULL,
+};
+
+static int rmnet_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
+{
+	struct rmnet_ioctl_extended_s ext_cmd;
+	struct eth_dev *eth_dev = netdev_priv(dev);
+	int rc = 0;
+
+	rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data,
+			    sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc) {
+		DBG(eth_dev, "%s(): copy_from_user() failed\n", __func__);
+		return rc;
+	}
+
+	switch (ext_cmd.extended_ioctl) {
+	case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
+		ext_cmd.u.data = 0;
+		break;
+
+	case RMNET_IOCTL_SET_MRU:
+		if (netif_running(dev))
+			return -EBUSY;
+
+		/* 16K max */
+		if ((size_t)ext_cmd.u.data > 0x4000)
+			return -EINVAL;
+
+		if (eth_dev->port_usb) {
+			eth_dev->port_usb->is_fixed = true;
+			eth_dev->port_usb->fixed_out_len =
+				(size_t) ext_cmd.u.data;
+			DBG(eth_dev, "[%s] rmnet_ioctl(): SET MRU to %u\n",
+				dev->name, eth_dev->port_usb->fixed_out_len);
+		} else {
+			pr_err("[%s]: %s: SET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_MRU:
+		if (eth_dev->port_usb) {
+			ext_cmd.u.data = eth_dev->port_usb->is_fixed ?
+					eth_dev->port_usb->fixed_out_len :
+					dev->mtu;
+		} else {
+			pr_err("[%s]: %s: GET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_DRIVER_NAME:
+		strlcpy(ext_cmd.u.if_name, dev->name,
+			sizeof(ext_cmd.u.if_name));
+		break;
+
+	default:
+		break;
+	}
+
+	rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd,
+			  sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc)
+		DBG(eth_dev, "%s(): copy_to_user() failed\n", __func__);
+	return rc;
+}
+
+static int ether_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct eth_dev	*eth_dev = netdev_priv(dev);
+	void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
+	int		prev_mtu = dev->mtu;
+	u32		state, old_opmode;
+	int		rc = -EFAULT;
+
+	old_opmode = eth_dev->flags;
+	/* Process IOCTL command */
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_ETHERNET:	/*Set Ethernet protocol*/
+		/* Perform Ethernet config only if in IP mode currently*/
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags)) {
+			ether_setup(dev);
+			dev->mtu = prev_mtu;
+			dev->netdev_ops = &eth_netdev_ops;
+			clear_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set Ethernet proto mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_LLP_IP:		/* Set RAWIP protocol*/
+		/* Perform IP config only if in Ethernet mode currently*/
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags)) {
+			/* Undo config done in ether_setup() */
+			dev->header_ops = NULL;  /* No header */
+			dev->type = ARPHRD_RAWIP;
+			dev->hard_header_len = 0;
+			dev->mtu = prev_mtu;
+			dev->addr_len = 0;
+			dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+			dev->netdev_ops = &eth_netdev_ops_ip;
+			clear_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set IP protocol mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_GET_LLP:	/* Get link protocol state */
+		state = eth_dev->flags & (RMNET_MODE_LLP_ETH
+						| RMNET_MODE_LLP_IP);
+		if (copy_to_user(addr, &state, sizeof(state)))
+			break;
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_RX_HEADROOM:	/* Set RX headroom */
+		if (copy_from_user(&eth_dev->rx_needed_headroom, addr,
+					sizeof(eth_dev->rx_needed_headroom)))
+			break;
+		DBG(eth_dev, "[%s] ioctl(): set RX HEADROOM: %x\n",
+				dev->name, eth_dev->rx_needed_headroom);
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_EXTENDED:
+		rc = rmnet_ioctl_extended(dev, ifr);
+		break;
+
+	default:
+		pr_err("[%s] error: ioctl called for unsupported cmd[%d]",
+			dev->name, cmd);
+		rc = -EINVAL;
+	}
+
+	DBG(eth_dev, "[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+		dev->name, __func__, cmd, old_opmode, eth_dev->flags);
+
+	return rc;
+}
+
 static struct device_type gadget_type = {
 	.name	= "gadget",
 };
@@ -955,6 +1336,9 @@
 
 	net->ethtool_ops = &ops;
 
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	dev->gadget = g;
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
@@ -974,6 +1358,7 @@
 		 *  - tx queueing enabled if open *and* carrier is "on"
 		 */
 		netif_carrier_off(net);
+		uether_debugfs_init(dev);
 	}
 
 	return dev;
@@ -1012,6 +1397,10 @@
 	net->netdev_ops = &eth_netdev_ops;
 
 	net->ethtool_ops = &ops;
+
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
 
 	return net;
@@ -1171,8 +1560,10 @@
 	if (!dev)
 		return;
 
+	uether_debugfs_exit(dev);
 	unregister_netdev(dev->net);
 	flush_work(&dev->work);
+	cancel_work_sync(&dev->rx_work);
 	free_netdev(dev->net);
 }
 EXPORT_SYMBOL_GPL(gether_cleanup);
@@ -1201,20 +1592,24 @@
 	if (!dev)
 		return ERR_PTR(-EINVAL);
 
-	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->in_ep->name, result);
-		goto fail0;
+	if (link->in_ep) {
+		link->in_ep->driver_data = dev;
+		result = usb_ep_enable(link->in_ep);
+		if (result != 0) {
+			DBG(dev, "enable %s --> %d\n",
+				link->in_ep->name, result);
+			goto fail0;
+		}
 	}
 
-	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->out_ep->name, result);
-		goto fail1;
+	if (link->out_ep) {
+		link->out_ep->driver_data = dev;
+		result = usb_ep_enable(link->out_ep);
+		if (result != 0) {
+			DBG(dev, "enable %s --> %d\n",
+				link->out_ep->name, result);
+			goto fail1;
+		}
 	}
 
 	if (result == 0)
@@ -1252,9 +1647,11 @@
 
 	/* on error, disable any endpoints  */
 	} else {
-		(void) usb_ep_disable(link->out_ep);
+		if (link->out_ep)
+			(void) usb_ep_disable(link->out_ep);
 fail1:
-		(void) usb_ep_disable(link->in_ep);
+		if (link->in_ep)
+			(void) usb_ep_disable(link->in_ep);
 	}
 fail0:
 	/* caller is responsible for cleanup on error */
@@ -1295,41 +1692,53 @@
 	 * of all pending i/o.  then free the request objects
 	 * and forget about the endpoints.
 	 */
-	usb_ep_disable(link->in_ep);
-	spin_lock(&dev->req_lock);
-	while (!list_empty(&dev->tx_reqs)) {
-		req = container_of(dev->tx_reqs.next,
-					struct usb_request, list);
-		list_del(&req->list);
-
-		spin_unlock(&dev->req_lock);
-		if (link->multi_pkt_xfer)
-			kfree(req->buf);
-		usb_ep_free_request(link->in_ep, req);
+	if (link->in_ep) {
+		usb_ep_disable(link->in_ep);
 		spin_lock(&dev->req_lock);
-	}
-	spin_unlock(&dev->req_lock);
-	link->in_ep->desc = NULL;
+		while (!list_empty(&dev->tx_reqs)) {
+			req = container_of(dev->tx_reqs.next,
+						struct usb_request, list);
+			list_del(&req->list);
 
-	usb_ep_disable(link->out_ep);
-	spin_lock(&dev->req_lock);
-	while (!list_empty(&dev->rx_reqs)) {
-		req = container_of(dev->rx_reqs.next,
-					struct usb_request, list);
-		list_del(&req->list);
-
+			spin_unlock(&dev->req_lock);
+			if (link->multi_pkt_xfer) {
+				kfree(req->buf);
+				req->buf = NULL;
+			}
+			usb_ep_free_request(link->in_ep, req);
+			spin_lock(&dev->req_lock);
+		}
 		spin_unlock(&dev->req_lock);
-		usb_ep_free_request(link->out_ep, req);
-		spin_lock(&dev->req_lock);
+		link->in_ep->desc = NULL;
 	}
-	spin_unlock(&dev->req_lock);
 
-	spin_lock(&dev->rx_frames.lock);
-	while ((skb = __skb_dequeue(&dev->rx_frames)))
-		dev_kfree_skb_any(skb);
-	spin_unlock(&dev->rx_frames.lock);
+	if (link->out_ep) {
+		usb_ep_disable(link->out_ep);
+		spin_lock(&dev->req_lock);
+		while (!list_empty(&dev->rx_reqs)) {
+			req = container_of(dev->rx_reqs.next,
+						struct usb_request, list);
+			list_del(&req->list);
 
-	link->out_ep->desc = NULL;
+			spin_unlock(&dev->req_lock);
+			usb_ep_free_request(link->out_ep, req);
+			spin_lock(&dev->req_lock);
+		}
+		spin_unlock(&dev->req_lock);
+
+		spin_lock(&dev->rx_frames.lock);
+		while ((skb = __skb_dequeue(&dev->rx_frames)))
+			dev_kfree_skb_any(skb);
+		spin_unlock(&dev->rx_frames.lock);
+
+		link->out_ep->desc = NULL;
+	}
+
+	pr_debug("%s(): tx_throttle count= %lu", __func__,
+					dev->tx_throttle);
+	/* reset tx_throttle count */
+	dev->tx_throttle = 0;
+	dev->rx_throttle = 0;
 
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
@@ -1342,6 +1751,73 @@
 }
 EXPORT_SYMBOL_GPL(gether_disconnect);
 
+static int uether_stat_show(struct seq_file *s, void *unused)
+{
+	struct eth_dev *dev = s->private;
+	int ret = 0;
+
+	if (dev) {
+		seq_printf(s, "tx_throttle = %lu\n", dev->tx_throttle);
+		seq_printf(s, "tx_pkts_rcvd=%u\n", dev->tx_pkts_rcvd);
+		seq_printf(s, "rx_throttle = %lu\n", dev->rx_throttle);
+		seq_printf(s, "skb_expand_cnt = %lu\n",
+					dev->skb_expand_cnt);
+	}
+	return ret;
+}
+
+static int uether_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, uether_stat_show, inode->i_private);
+}
+
+static ssize_t uether_stat_reset(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct eth_dev *dev = s->private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* Reset tx_throttle */
+	dev->tx_throttle = 0;
+	dev->rx_throttle = 0;
+	dev->skb_expand_cnt = 0;
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return count;
+}
+
+static const struct file_operations uether_stats_ops = {
+	.open = uether_open,
+	.read = seq_read,
+	.write = uether_stat_reset,
+};
+
+static void uether_debugfs_init(struct eth_dev *dev)
+{
+	struct dentry *uether_dent;
+	struct dentry *uether_dfile;
+
+	uether_dent = debugfs_create_dir("uether_rndis", NULL);
+	if (IS_ERR(uether_dent))
+		return;
+	dev->uether_dent = uether_dent;
+
+	uether_dfile = debugfs_create_file("status", 0644,
+				uether_dent, dev, &uether_stats_ops);
+	if (!uether_dfile || IS_ERR(uether_dfile))
+		debugfs_remove(uether_dent);
+	dev->uether_dfile = uether_dfile;
+}
+
+static void uether_debugfs_exit(struct eth_dev *dev)
+{
+	debugfs_remove(dev->uether_dfile);
+	debugfs_remove(dev->uether_dent);
+	dev->uether_dent = NULL;
+	dev->uether_dfile = NULL;
+}
+
 static int __init gether_init(void)
 {
 	uether_wq  = create_singlethread_workqueue("uether");
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index b4353ac..d445e51 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -131,11 +131,12 @@
 
 static int init_data(struct usb_ep *ep)
 {
+	struct f_qdss *qdss = ep->driver_data;
 	int res = 0;
 
 	pr_debug("init_data\n");
 
-	res = msm_ep_config(ep);
+	res = msm_ep_config(ep, qdss->endless_req);
 	if (res)
 		pr_err("msm_ep_config failed\n");
 
diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h
index 0126932..f639722 100644
--- a/drivers/usb/gadget/function/u_rmnet.h
+++ b/drivers/usb/gadget/function/u_rmnet.h
@@ -20,12 +20,32 @@
 
 #include "f_qdss.h"
 
+enum bam_dmux_func_type {
+	BAM_DMUX_FUNC_RMNET,
+	BAM_DMUX_FUNC_MBIM,
+	BAM_DMUX_FUNC_DPL,
+	BAM_DMUX_NUM_FUNCS,
+};
+
 struct rmnet_ctrl_pkt {
 	void	*buf;
 	int	len;
 	struct list_head	list;
 };
 
+struct data_port {
+	struct usb_composite_dev	*cdev;
+	struct usb_function		*func;
+	int				rx_buffer_size;
+	struct usb_ep			*in;
+	struct usb_ep			*out;
+	int				ipa_consumer_ep;
+	int				ipa_producer_ep;
+	const struct usb_endpoint_descriptor	*in_ep_desc_backup;
+	const struct usb_endpoint_descriptor	*out_ep_desc_backup;
+
+};
+
 struct grmnet {
 	/* to usb host, aka laptop, windows pc etc. Will
 	 * be filled by usb driver of rmnet functionality
@@ -49,7 +69,23 @@
 	NR_CTRL_CLIENTS
 };
 
-int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf);
+enum data_xport_type {
+	BAM_DMUX,
+	BAM2BAM_IPA,
+	NR_XPORT_TYPES
+};
+
+int gbam_connect(struct data_port *gr, enum bam_dmux_func_type func);
+void gbam_disconnect(struct data_port *gr, enum bam_dmux_func_type func);
+void gbam_cleanup(enum bam_dmux_func_type func);
+int gbam_setup(enum bam_dmux_func_type func);
+int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
+			struct usb_ep *out);
+void gbam_mbim_disconnect(void);
+int gbam_mbim_setup(void);
+
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf,
+						enum data_xport_type dxport);
 void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport);
 int gqti_ctrl_init(void);
 void gqti_ctrl_cleanup(void);
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index e0cd1e4..2ec28c8 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -304,7 +304,8 @@
  * usb_request or NULL if there is an error.
  */
 struct usb_request *
-gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
+gs_alloc_req(struct usb_ep *ep, unsigned int len, size_t extra_sz,
+		gfp_t kmalloc_flags)
 {
 	struct usb_request *req;
 
@@ -312,7 +313,7 @@
 
 	if (req != NULL) {
 		req->length = len;
-		req->buf = kmalloc(len, kmalloc_flags);
+		req->buf = kmalloc(len + extra_sz, kmalloc_flags);
 		if (req->buf == NULL) {
 			usb_ep_free_request(ep, req);
 			return NULL;
@@ -654,6 +655,7 @@
 }
 
 static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
+		size_t extra_sz,
 		void (*fn)(struct usb_ep *, struct usb_request *),
 		int *allocated)
 {
@@ -666,7 +668,7 @@
 	 * be as speedy as we might otherwise be.
 	 */
 	for (i = 0; i < n; i++) {
-		req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+		req = gs_alloc_req(ep, ep->maxpacket, extra_sz, GFP_ATOMIC);
 		if (!req)
 			return list_empty(head) ? -ENOMEM : 0;
 		req->complete = fn;
@@ -688,6 +690,8 @@
  */
 static int gs_start_io(struct gs_port *port)
 {
+	struct usb_function	*f = &port->port_usb->func;
+	struct usb_composite_dev *cdev = f->config->cdev;
 	struct list_head	*head = &port->read_pool;
 	struct usb_ep		*ep = port->port_usb->out;
 	int			status;
@@ -699,12 +703,13 @@
 	 * configurations may use different endpoints with a given port;
 	 * and high speed vs full speed changes packet sizes too.
 	 */
-	status = gs_alloc_requests(ep, head, gs_read_complete,
+	status = gs_alloc_requests(ep, head, 0, gs_read_complete,
 		&port->read_allocated);
 	if (status)
 		return status;
 
 	status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
+			cdev->gadget->extra_buf_alloc,
 			gs_write_complete, &port->write_allocated);
 	if (status) {
 		gs_free_requests(ep, head, &port->read_allocated);
diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h
index c20210c..cc78165 100644
--- a/drivers/usb/gadget/function/u_serial.h
+++ b/drivers/usb/gadget/function/u_serial.h
@@ -45,15 +45,28 @@
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
+	u16				serial_state;
+
+	/* control signal callbacks*/
+	unsigned int (*get_dtr)(struct gserial *p);
+	unsigned int (*get_rts)(struct gserial *p);
 
 	/* notification callbacks */
 	void (*connect)(struct gserial *p);
 	void (*disconnect)(struct gserial *p);
 	int (*send_break)(struct gserial *p, int duration);
+	unsigned int (*send_carrier_detect)(struct gserial *p,
+			unsigned int yes);
+	unsigned int (*send_ring_indicator)(struct gserial *p,
+			unsigned int yes);
+	int (*send_modem_ctrl_bits)(struct gserial *p, int ctrl_bits);
+	/* notification changes to modem */
+	void (*notify_modem)(void *gser, u8 portno, int ctrl_bits);
 };
 
 /* utilities to allocate/free request and buffer */
-struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
+struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
+					size_t extra_sz, gfp_t flags);
 void gs_free_req(struct usb_ep *, struct usb_request *req);
 
 /* management of individual TTY ports */
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 984b1d7..4debbcbf 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -2518,7 +2518,7 @@
 	.release		= uvc_attr_release,
 };
 
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit)		\
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit)	\
 static ssize_t f_uvc_opts_##cname##_show(				\
 	struct config_item *item, char *page)				\
 {									\
@@ -2565,12 +2565,12 @@
 
 #define identity_conv(x) (x)
 
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
-	       16);
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
-	       3072);
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
-	       15);
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
+	       kstrtou8, u8, identity_conv, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
+	       kstrtou16, u16, le16_to_cpu, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
+	       kstrtou8, u8, identity_conv, 15);
 
 #undef identity_conv
 
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 658b8da..42028cc 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -389,6 +389,21 @@
 	  dynamically linked module called "udc-xilinx" and force all
 	  gadget drivers to also be dynamically linked.
 
+config USB_CI13XXX_MSM
+	tristate "MIPS USB CI13xxx for MSM"
+	select USB_MSM_OTG
+	help
+	  MSM SoC has chipidea USB controller.  This driver uses
+	  ci13xxx_udc core.
+	  This driver depends on OTG driver for PHY initialization,
+	  clock management, powering up VBUS, and power management.
+	  This driver is not supported on boards like trout which
+	  has an external PHY.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "ci13xxx_msm" and force all
+	  gadget drivers to also be dynamically linked.
+
 #
 # LAST -- dummy/emulated controller
 #
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 26bfa73..6959071 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -964,7 +964,7 @@
 		return 0;
 
 	/* "high bandwidth" works only at high speed */
-	if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
+	if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp_mult(desc) > 1)
 		return 0;
 
 	switch (type) {
@@ -1172,6 +1172,10 @@
 	INIT_WORK(&gadget->work, usb_gadget_state_work);
 	gadget->dev.parent = parent;
 
+	dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+	gadget->dev.dma_parms = parent->dma_parms;
+	gadget->dev.dma_mask = parent->dma_mask;
+
 	if (release)
 		gadget->dev.release = release;
 	else
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 74f62d6..b09392f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1267,7 +1267,7 @@
 			spin_lock_irqsave(&ehci->lock, flags);
 
 			/* Put all enabled ports into suspend */
-			while (ports--) {
+			while (!ehci->no_testmode_suspend && ports--) {
 				u32 __iomem *sreg =
 						&ehci->regs->port_status[ports];
 
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 2f8d3af..3e36edd 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -1,6 +1,6 @@
 /* ehci-msm.c - HSUSB Host Controller Driver Implementation
  *
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
  *
  * Partly derived from ehci-fsl.c and ehci-hcd.c
  * Copyright (c) 2000-2004 by David Brownell
@@ -29,11 +29,13 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+
 #include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
-#include <linux/acpi.h>
 
 #include "ehci.h"
 
@@ -51,25 +53,32 @@
 
 	ehci->caps = USB_CAPLENGTH;
 	hcd->has_tt = 1;
+	ehci->no_testmode_suspend = true;
 
 	retval = ehci_setup(hcd);
 	if (retval)
 		return retval;
 
-	/* select ULPI phy and clear other status/control bits in PORTSC */
-	writel(PORTSC_PTS_ULPI, USB_PORTSC);
 	/* bursts of unspecified length. */
-	writel(0, USB_AHBBURST);
-	/* Use the AHB transactor, allow posted data writes */
-	writel(0x8, USB_AHBMODE);
+	writel_relaxed(0, USB_AHBBURST);
+	/* Use the AHB transactor */
+	writel_relaxed(0x08, USB_AHBMODE);
 	/* Disable streaming mode and select host mode */
-	writel(0x13, USB_USBMODE);
-	/* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
-	writel(readl(USB_GENCONFIG_2) & ~ULPI_TX_PKT_EN_CLR_FIX, USB_GENCONFIG_2);
+	writel_relaxed(0x13, USB_USBMODE);
 
+	if (hcd->usb_phy->flags & ENABLE_SECONDARY_PHY) {
+		ehci_dbg(ehci, "using secondary hsphy\n");
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+							USB_PHY_CTRL2);
+	}
+
+	/* Disable ULPI_TX_PKT_EN_CLR_FIX which is valid only for HSIC */
+	writel_relaxed(readl_relaxed(USB_GENCONFIG_2) & ~(1<<19),
+					USB_GENCONFIG_2);
 	return 0;
 }
 
+static u64 msm_ehci_dma_mask = DMA_BIT_MASK(32);
 static int ehci_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -79,12 +88,20 @@
 
 	dev_dbg(&pdev->dev, "ehci_msm proble\n");
 
-	hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &msm_ehci_dma_mask;
+	if (!pdev->dev.coherent_dma_mask)
+		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
+			     dev_name(&pdev->dev));
 	if (!hcd) {
 		dev_err(&pdev->dev, "Unable to create HCD\n");
 		return  -ENOMEM;
 	}
 
+	hcd_to_bus(hcd)->skip_resume = true;
+
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -93,61 +110,43 @@
 	hcd->irq = ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Unable to get memory resource\n");
-		ret = -ENODEV;
+	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hcd->regs)) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = PTR_ERR(hcd->regs);
 		goto put_hcd;
 	}
-
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
-	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
-	if (!hcd->regs) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto put_hcd;
-	}
 
 	/*
-	 * If there is an OTG driver, let it take care of PHY initialization,
-	 * clock management, powering up VBUS, mapping of registers address
-	 * space and power management.
+	 * OTG driver takes care of PHY initialization, clock management,
+	 * powering up VBUS, mapping of registers address space and power
+	 * management.
 	 */
 	if (pdev->dev.of_node)
 		phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
 	else
 		phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
 
-	if (IS_ERR(phy)) {
-		if (PTR_ERR(phy) == -EPROBE_DEFER) {
-			dev_err(&pdev->dev, "unable to find transceiver\n");
-			ret = -EPROBE_DEFER;
-			goto put_hcd;
-		}
-		phy = NULL;
+	if (IS_ERR_OR_NULL(phy)) {
+		dev_err(&pdev->dev, "unable to find transceiver\n");
+		ret = -EPROBE_DEFER;
+		goto put_hcd;
+	}
+
+	ret = otg_set_host(phy->otg, &hcd->self);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "unable to register with transceiver\n");
+		goto put_hcd;
 	}
 
 	hcd->usb_phy = phy;
 	device_init_wakeup(&pdev->dev, 1);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
 
-	if (phy && phy->otg) {
-		/*
-		 * MSM OTG driver takes care of adding the HCD and
-		 * placing hardware into low power mode via runtime PM.
-		 */
-		ret = otg_set_host(phy->otg, &hcd->self);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "unable to register with transceiver\n");
-			goto put_hcd;
-		}
-
-		pm_runtime_no_callbacks(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-	} else {
-		ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
-		if (ret)
-			goto put_hcd;
-	}
+	msm_bam_set_usb_host_dev(&pdev->dev);
 
 	return 0;
 
@@ -165,10 +164,8 @@
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
-	if (hcd->usb_phy && hcd->usb_phy->otg)
-		otg_set_host(hcd->usb_phy->otg, NULL);
-	else
-		usb_remove_hcd(hcd);
+	otg_set_host(hcd->usb_phy->otg, NULL);
+	hcd->usb_phy = NULL;
 
 	usb_put_hcd(hcd);
 
@@ -176,51 +173,34 @@
 }
 
 #ifdef CONFIG_PM
-static int ehci_msm_pm_suspend(struct device *dev)
+static int ehci_msm_runtime_suspend(struct device *dev)
 {
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	bool do_wakeup = device_may_wakeup(dev);
-
-	dev_dbg(dev, "ehci-msm PM suspend\n");
-
-	/* Only call ehci_suspend if ehci_setup has been done */
-	if (ehci->sbrn)
-		return ehci_suspend(hcd, do_wakeup);
+	dev_dbg(dev, "ehci runtime suspend\n");
 
 	return 0;
 }
 
-static int ehci_msm_pm_resume(struct device *dev)
+static int ehci_msm_runtime_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	u32 portsc;
 
-	dev_dbg(dev, "ehci-msm PM resume\n");
+	dev_dbg(dev, "ehci runtime resume\n");
 
-	/* Only call ehci_resume if ehci_setup has been done */
-	if (ehci->sbrn)
-		ehci_resume(hcd, false);
+	portsc = readl_relaxed(USB_PORTSC);
+	portsc &= ~PORT_RWC_BITS;
+	portsc |= PORT_RESUME;
+	writel_relaxed(portsc, USB_PORTSC);
 
 	return 0;
 }
-
-#else
-#define ehci_msm_pm_suspend	NULL
-#define ehci_msm_pm_resume	NULL
 #endif
 
 static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
-	.suspend         = ehci_msm_pm_suspend,
-	.resume          = ehci_msm_pm_resume,
+	SET_RUNTIME_PM_OPS(ehci_msm_runtime_suspend, ehci_msm_runtime_resume,
+			   NULL)
 };
 
-static const struct acpi_device_id msm_ehci_acpi_ids[] = {
-	{ "QCOM8040", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(acpi, msm_ehci_acpi_ids);
-
 static const struct of_device_id msm_ehci_dt_match[] = {
 	{ .compatible = "qcom,ehci-host", },
 	{}
@@ -235,7 +215,6 @@
 		   .name = "msm_hsusb_host",
 		   .pm = &ehci_msm_dev_pm_ops,
 		   .of_match_table = msm_ehci_dt_match,
-		   .acpi_match_table = ACPI_PTR(msm_ehci_acpi_ids),
 	},
 };
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 3f3b74a..53f21da 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -229,6 +229,7 @@
 	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+	bool			no_testmode_suspend; /* MSM Chipidea HC */
 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
 
 	/* required for usb32 quirk */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 09ae74e..4220575 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -340,14 +340,14 @@
 	 * seconds), then it should assume that the there are
 	 * larger problems with the xHC and assert HCRST.
 	 */
-	ret = xhci_handshake(&xhci->op_regs->cmd_ring,
+	ret = xhci_handshake_check_state(xhci, &xhci->op_regs->cmd_ring,
 			CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
 	if (ret < 0) {
 		/* we are about to kill xhci, give it one more chance */
 		xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
 			      &xhci->op_regs->cmd_ring);
 		udelay(1000);
-		ret = xhci_handshake(&xhci->op_regs->cmd_ring,
+		ret = xhci_handshake_check_state(xhci, &xhci->op_regs->cmd_ring,
 				     CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
 		if (ret < 0) {
 			xhci_err(xhci, "Stopped the command ring failed, "
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ae8a727..84ace86 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -78,6 +78,25 @@
 	return -ETIMEDOUT;
 }
 
+int xhci_handshake_check_state(struct xhci_hcd *xhci,
+		void __iomem *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl_relaxed(ptr);
+		if (result == ~(u32)0 ||
+		xhci->xhc_state == XHCI_STATE_REMOVING)	/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay(1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
 /*
  * Disable interrupts and begin the xHCI halting process.
  */
@@ -769,6 +788,10 @@
 		usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
 
 	spin_lock_irq(&xhci->lock);
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		spin_unlock_irq(&xhci->lock);
+		return;
+	}
 	xhci_halt(xhci);
 	/* Workaround for spurious wakeups at shutdown with HSW */
 	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c11eab1..4c1f556 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1864,6 +1864,8 @@
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
 int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
+int xhci_handshake_check_state(struct xhci_hcd *xhci,
+		void __iomem *ptr, u32 mask, u32 done, int usec);
 void xhci_quiesce(struct xhci_hcd *xhci);
 int xhci_halt(struct xhci_hcd *xhci);
 int xhci_reset(struct xhci_hcd *xhci);
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 17e8edb..4e223f5 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -253,4 +253,15 @@
 	  the high-speed PHY which is usually paired with either the ChipIdea or
 	  Synopsys DWC3 USB IPs on MSM SOCs. This driver expects to configure the
 	  PHY with a dedicated register I/O memory region.
+
+config USB_MSM_OTG
+	tristate "Qualcomm Technologies, Inc. on-chip USB OTG controller support"
+	depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
+	select USB_PHY
+	help
+	  Enable this to support the USB OTG transceiver on Qualcomm chips. It
+	  handles PHY initialization, clock management, and workarounds
+	  required after resetting the hardware and power management.
+	  This driver is required even for peripheral only or host only
+	  mode configurations.
 endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 285659d..7e9ffa0 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -31,3 +31,4 @@
 obj-$(CONFIG_USB_MSM_SSPHY_QMP)     	+= phy-msm-ssusb-qmp.o
 obj-$(CONFIG_MSM_QUSB_PHY)              += phy-msm-qusb.o phy-msm-qusb-v2.o
 obj-$(CONFIG_MSM_HSUSB_PHY)		+= phy-msm-snps-hs.o
+obj-$(CONFIG_USB_MSM_OTG)		+= phy-msm-usb.o
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index cce17e0..e28173b 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -26,6 +26,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/usb/phy.h>
 #include <linux/reset.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/debugfs.h>
 #include <linux/hrtimer.h>
 
@@ -70,6 +71,9 @@
 #define SQ_CTRL1_CHIRP_DISABLE		0x20
 #define SQ_CTRL2_CHIRP_DISABLE		0x80
 
+#define PORT_TUNE1_OVERRIDE_VAL		0xc5
+#define DEBUG_CTRL1_OVERRIDE_VAL	0x09
+
 /* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
 #define BANDGAP_BYPASS			BIT(0)
 
@@ -83,6 +87,7 @@
 	BIAS_CTRL_2,
 	SQ_CTRL1,
 	SQ_CTRL2,
+	DEBUG_CTRL1,
 	USB2_PHY_REG_MAX,
 };
 
@@ -146,8 +151,73 @@
 	u8			tune[5];
 
 	struct hrtimer		timer;
+	int			soc_min_rev;
+	bool			host_chirp_erratum;
 };
 
+#ifdef CONFIG_NVMEM
+/* Parse qfprom data for deciding on errata work-arounds */
+static long qfprom_read(struct device *dev, const char *name)
+{
+	struct nvmem_cell *cell;
+	ssize_t len = 0;
+	u32 *buf, val = 0;
+	long err = 0;
+
+	cell = nvmem_cell_get(dev, name);
+	if (IS_ERR(cell)) {
+		err = PTR_ERR(cell);
+		dev_err(dev, "failed opening nvmem cell err : %ld\n", err);
+		/* If entry does not exist, then that is not an error */
+		if (err == -ENOENT)
+			err = 0;
+		return err;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	if (IS_ERR(buf) || !len) {
+		dev_err(dev, "Failed reading nvmem cell, err: %u, bytes fetched: %zd\n",
+				*buf, len);
+		if (!IS_ERR(buf)) {
+			kfree(buf);
+			err = -EINVAL;
+		} else {
+			err = PTR_ERR(buf);
+		}
+	} else {
+		/*
+		 * The bits are read from bit-0 to bit-29
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
+		kfree(buf);
+	}
+
+	nvmem_cell_put(cell);
+	return err ? err : (long) val;
+}
+
+/* Reads the SoC version */
+static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
+{
+	if (!qphy->host_chirp_erratum)
+		return 0;
+
+	qphy->soc_min_rev  = qfprom_read(dev, "minor_rev");
+	if (qphy->soc_min_rev < 0)
+		dev_err(dev, "failed getting soc_min_rev, err : %d\n",
+				qphy->soc_min_rev);
+
+	return qphy->soc_min_rev;
+};
+#else
+/* Reads the SoC version */
+static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
+{
+	return 0;
+}
+#endif
+
 static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
 {
 	dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d on:%d\n",
@@ -406,10 +476,24 @@
 
 	dev_dbg(phy->dev, "%s\n", __func__);
 
-	qusb_phy_reset(qphy);
 	qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq,
 			qphy->host_init_seq_len, 0);
 
+	/* If soc revision is mentioned and host_chirp_erratum flag is set
+	 * then override TUNE1 and DEBUG_CTRL1
+	 */
+	if (qphy->soc_min_rev && qphy->host_chirp_erratum) {
+		writel_relaxed(PORT_TUNE1_OVERRIDE_VAL,
+				qphy->base + qphy->phy_reg[PORT_TUNE1]);
+		writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+				qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+	}
+
+	if (qphy->refgen_north_bg_reg)
+		if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS)
+			writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
+				qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
+
 	/* Ensure above write is completed before turning ON ref clk */
 	wmb();
 
@@ -439,6 +523,12 @@
 	qusb_phy_enable_clocks(qphy, true);
 
 	qusb_phy_reset(qphy);
+
+	if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE) {
+		qusb_phy_host_init(phy);
+		return 0;
+	}
+
 	if (qphy->emulation) {
 		if (qphy->emu_init_seq)
 			qusb_phy_write_seq(qphy->emu_phy_base + 0x8000,
@@ -684,9 +774,6 @@
 
 	qphy->cable_connected = true;
 
-	if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE)
-		qusb_phy_host_init(phy);
-
 	dev_dbg(phy->dev, "QUSB PHY: connect notification cable_connected=%d\n",
 							qphy->cable_connected);
 	return 0;
@@ -766,6 +853,7 @@
 			return ret;
 		}
 		qphy->dpdm_enable = true;
+		qusb_phy_reset(qphy);
 	}
 
 	return ret;
@@ -1099,6 +1187,9 @@
 			return -ENOMEM;
 	}
 
+	qphy->host_chirp_erratum = of_property_read_bool(dev->of_node,
+					"qcom,host-chirp-erratum");
+
 	ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
 					 (u32 *) qphy->vdd_levels,
 					 ARRAY_SIZE(qphy->vdd_levels));
@@ -1125,6 +1216,11 @@
 		return PTR_ERR(qphy->vdda18);
 	}
 
+	ret = qusb_phy_get_socrev(&pdev->dev, qphy);
+	if (ret == -EPROBE_DEFER) {
+		dev_err(&pdev->dev, "SoC version rd: fail: defer for now\n");
+		return ret;
+	}
 	qphy->pinctrl = devm_pinctrl_get(dev);
 	if (IS_ERR(qphy->pinctrl)) {
 		ret = PTR_ERR(qphy->pinctrl);
@@ -1159,7 +1255,14 @@
 	qphy->phy.type			= USB_PHY_TYPE_USB2;
 	qphy->phy.notify_connect        = qusb_phy_notify_connect;
 	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
-	qphy->phy.disable_chirp		= qusb_phy_disable_chirp;
+
+	/*
+	 * qusb_phy_disable_chirp is not required if soc version is
+	 * mentioned and is not base version.
+	 */
+	if (!qphy->soc_min_rev)
+		qphy->phy.disable_chirp	= qusb_phy_disable_chirp;
+
 	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;
 
 	ret = usb_add_phy_dev(&qphy->phy);
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index fd84889..a259790 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -96,6 +96,9 @@
 	bool			suspended;
 	bool			cable_connected;
 
+	int			*param_override_seq;
+	int			param_override_seq_cnt;
+
 	/* emulation targets specific */
 	void __iomem		*emu_phy_base;
 	int			*emu_init_seq;
@@ -251,6 +254,7 @@
 		dev_err(phy->phy.dev, "Unable to set LPM of vdda18\n");
 
 disable_vdd:
+	ret = regulator_disable(phy->vdd);
 	if (ret)
 		dev_err(phy->phy.dev, "Unable to disable vdd:%d\n",
 								ret);
@@ -381,6 +385,11 @@
 	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
 				VBUSVLDEXT0, VBUSVLDEXT0);
 
+	/* set parameter ovrride  if needed */
+	if (phy->param_override_seq)
+		hsusb_phy_write_seq(phy->base, phy->param_override_seq,
+				phy->param_override_seq_cnt, 0);
+
 	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
 				VREGBYPASS, VREGBYPASS);
 
@@ -422,6 +431,28 @@
 
 static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
 {
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+	if (phy->suspended && suspend) {
+		dev_dbg(uphy->dev, "%s: USB PHY is already suspended\n",
+			__func__);
+		return 0;
+	}
+
+	if (suspend) { /* Bus suspend */
+		if (phy->cable_connected ||
+			(phy->phy.flags & PHY_HOST_MODE)) {
+			msm_hsphy_enable_clocks(phy, false);
+		} else {/* Cable disconnect */
+			msm_hsphy_enable_clocks(phy, false);
+			msm_hsphy_enable_power(phy, false);
+		}
+		phy->suspended = true;
+	} else { /* Bus resume and cable connect */
+			msm_hsphy_enable_clocks(phy, true);
+			phy->suspended = false;
+		}
+
 	return 0;
 }
 
@@ -554,6 +585,34 @@
 		}
 	}
 
+	phy->param_override_seq_cnt = of_property_count_elems_of_size(
+					dev->of_node,
+					"qcom,param-override-seq",
+					sizeof(*phy->param_override_seq));
+	if (phy->param_override_seq_cnt > 0) {
+		phy->param_override_seq = devm_kcalloc(dev,
+					phy->param_override_seq_cnt,
+					sizeof(*phy->param_override_seq),
+					GFP_KERNEL);
+		if (!phy->param_override_seq)
+			return -ENOMEM;
+
+		if (phy->param_override_seq_cnt % 2) {
+			dev_err(dev, "invalid param_override_seq_len\n");
+			return -EINVAL;
+		}
+
+		ret = of_property_read_u32_array(dev->of_node,
+				"qcom,param-override-seq",
+				phy->param_override_seq,
+				phy->param_override_seq_cnt);
+		if (ret) {
+			dev_err(dev, "qcom,param-override-seq read failed %d\n",
+				ret);
+			return ret;
+		}
+	}
+
 	ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
 					 (u32 *) phy->vdd_levels,
 					 ARRAY_SIZE(phy->vdd_levels));
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 8134579..ad3bbf7 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 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
@@ -112,6 +112,7 @@
 	struct usb_phy		phy;
 	void __iomem		*base;
 	void __iomem		*vls_clamp_reg;
+	void __iomem		*pcs_clamp_enable_reg;
 	void __iomem		*tcsr_usb3_dp_phymode;
 
 	struct regulator	*vdd;
@@ -187,6 +188,8 @@
 	case USB_PHY_TYPE_USB3_OR_DP:
 	case USB_PHY_TYPE_USB3:
 		writel_relaxed(!!val, phy->vls_clamp_reg);
+		if (phy->pcs_clamp_enable_reg)
+			writel_relaxed(!val, phy->pcs_clamp_enable_reg);
 		break;
 	default:
 		break;
@@ -892,6 +895,16 @@
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"pcs_clamp_enable_reg");
+	if (res) {
+		phy->pcs_clamp_enable_reg = devm_ioremap_resource(dev, res);
+		if (IS_ERR(phy->pcs_clamp_enable_reg)) {
+			dev_err(dev, "err getting pcs_clamp_enable_reg address.\n");
+			return PTR_ERR(phy->pcs_clamp_enable_reg);
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 			"tcsr_usb3_dp_phymode");
 	if (res) {
 		phy->tcsr_usb3_dp_phymode = devm_ioremap_resource(dev, res);
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
new file mode 100644
index 0000000..155a9b9
--- /dev/null
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -0,0 +1,4368 @@
+/* Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_wakeup.h>
+#include <linux/reset.h>
+#include <linux/extcon.h>
+#include <soc/qcom/scm.h>
+
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/qpnp/qpnp-adc.h>
+
+#include <linux/msm-bus.h>
+
+/**
+ * Requested USB votes for BUS bandwidth
+ *
+ * USB_NO_PERF_VOTE     BUS Vote for inactive USB session or disconnect
+ * USB_MAX_PERF_VOTE    Maximum BUS bandwidth vote
+ * USB_MIN_PERF_VOTE    Minimum BUS bandwidth vote (for some hw same as NO_PERF)
+ *
+ */
+enum usb_bus_vote {
+	USB_NO_PERF_VOTE = 0,
+	USB_MAX_PERF_VOTE,
+	USB_MIN_PERF_VOTE,
+};
+
+/**
+ * Supported USB modes
+ *
+ * USB_PERIPHERAL       Only peripheral mode is supported.
+ * USB_HOST             Only host mode is supported.
+ * USB_OTG              OTG mode is supported.
+ *
+ */
+enum usb_mode_type {
+	USB_NONE = 0,
+	USB_PERIPHERAL,
+	USB_HOST,
+	USB_OTG,
+};
+
+/**
+ * OTG control
+ *
+ * OTG_NO_CONTROL	Id/VBUS notifications not required. Useful in host
+ *                      only configuration.
+ * OTG_PHY_CONTROL	Id/VBUS notifications comes form USB PHY.
+ * OTG_PMIC_CONTROL	Id/VBUS notifications comes from PMIC hardware.
+ * OTG_USER_CONTROL	Id/VBUS notifcations comes from User via sysfs.
+ *
+ */
+enum otg_control_type {
+	OTG_NO_CONTROL = 0,
+	OTG_PHY_CONTROL,
+	OTG_PMIC_CONTROL,
+	OTG_USER_CONTROL,
+};
+
+/**
+ * PHY used in
+ *
+ * INVALID_PHY			Unsupported PHY
+ * CI_PHY                      Chipidea PHY
+ * SNPS_PICO_PHY               Synopsis Pico PHY
+ * SNPS_FEMTO_PHY              Synopsis Femto PHY
+ * QUSB_ULPI_PHY
+ *
+ */
+enum msm_usb_phy_type {
+	INVALID_PHY = 0,
+	CI_PHY,			/* not supported */
+	SNPS_PICO_PHY,
+	SNPS_FEMTO_PHY,
+	QUSB_ULPI_PHY,
+};
+
+#define IDEV_CHG_MAX	1500
+#define IUNIT		100
+#define IDEV_HVDCP_CHG_MAX	1800
+
+/**
+ * Used different VDDCX voltage values
+ */
+enum usb_vdd_value {
+	VDD_NONE = 0,
+	VDD_MIN,
+	VDD_MAX,
+	VDD_VAL_MAX,
+};
+
+/**
+ * struct msm_otg_platform_data - platform device data
+ *              for msm_otg driver.
+ * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
+ *              "do not overwrite default value at this address".
+ * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
+ * @mode: Supported mode (OTG/peripheral/host).
+ * @otg_control: OTG switch controlled by user/Id pin
+ * @default_mode: Default operational mode. Applicable only if
+ *              OTG switch is controller by user.
+ * @pmic_id_irq: IRQ number assigned for PMIC USB ID line.
+ * @disable_reset_on_disconnect: perform USB PHY and LINK reset
+ *              on USB cable disconnection.
+ * @pnoc_errata_fix: workaround needed for PNOC hardware bug that
+ *              affects USB performance.
+ * @enable_lpm_on_suspend: Enable the USB core to go into Low
+ *              Power Mode, when USB bus is suspended but cable
+ *              is connected.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ *              USB enters LPM.
+ * @delay_lpm_on_disconnect: Use a delay before entering LPM
+ *              upon USB cable disconnection.
+ * @enable_sec_phy: Use second HSPHY with USB2 core
+ * @bus_scale_table: parameters for bus bandwidth requirements
+ * @log2_itc: value of 2^(log2_itc-1) will be used as the
+ *              interrupt threshold (ITC), when log2_itc is
+ *              between 1 to 7.
+ * @l1_supported: enable link power management support.
+ * @dpdm_pulldown_added: Indicates whether pull down resistors are
+ *		connected on data lines or not.
+ * @vddmin_gpio: dedictaed gpio in the platform that is used for
+ *		pullup the D+ line in case of bus suspend with
+ *		phy retention.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ *		mode with controller in device mode.
+ * @bool disable_retention_with_vdd_min: Indicates whether to enable
+		allowing VDDmin without putting PHY into retention.
+ * @bool enable_phy_id_pullup: Indicates whether phy id pullup is
+		enabled or not.
+ * @usb_id_gpio: Gpio used for USB ID detection.
+ * @hub_reset_gpio: Gpio used for hub reset.
+ * @switch_sel_gpio: Gpio used for controlling switch that
+		routing D+/D- from the USB HUB to the USB jack type B
+		for peripheral mode.
+ * @bool phy_dvdd_always_on: PHY DVDD is supplied by always on PMIC LDO.
+ * @bool emulation: Indicates whether we are running on emulation platform.
+ * @bool enable_streaming: Indicates whether streaming to be enabled by default.
+ * @bool enable_axi_prefetch: Indicates whether AXI Prefetch interface is used
+		for improving data performance.
+ * @usbeth_reset_gpio: Gpio used for external usb-to-eth reset.
+ */
+struct msm_otg_platform_data {
+	int *phy_init_seq;
+	int phy_init_sz;
+	unsigned int power_budget;
+	enum usb_mode_type mode;
+	enum otg_control_type otg_control;
+	enum usb_mode_type default_mode;
+	enum msm_usb_phy_type phy_type;
+	int pmic_id_irq;
+	bool disable_reset_on_disconnect;
+	bool pnoc_errata_fix;
+	bool enable_lpm_on_dev_suspend;
+	bool core_clk_always_on_workaround;
+	bool delay_lpm_on_disconnect;
+	bool dp_manual_pullup;
+	bool enable_sec_phy;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	int log2_itc;
+	bool l1_supported;
+	bool dpdm_pulldown_added;
+	int vddmin_gpio;
+	bool enable_ahb2ahb_bypass;
+	bool disable_retention_with_vdd_min;
+	bool enable_phy_id_pullup;
+	int usb_id_gpio;
+	int hub_reset_gpio;
+	int usbeth_reset_gpio;
+	int switch_sel_gpio;
+	bool phy_dvdd_always_on;
+	bool emulation;
+	bool enable_streaming;
+	bool enable_axi_prefetch;
+	bool vbus_low_as_hostmode;
+};
+
+#define MSM_USB_BASE	(motg->regs)
+#define MSM_USB_PHY_CSR_BASE (motg->phy_csr_regs)
+
+#define DRIVER_NAME	"msm_otg"
+
+#define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
+#define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
+#define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
+#define USB_PHY_3P3_HPM_LOAD	50000	/* uA */
+#define USB_PHY_3P3_LPM_LOAD	4000	/* uA */
+
+#define USB_PHY_1P8_VOL_MIN	1800000 /* uV */
+#define USB_PHY_1P8_VOL_MAX	1800000 /* uV */
+#define USB_PHY_1P8_HPM_LOAD	50000	/* uA */
+#define USB_PHY_1P8_LPM_LOAD	4000	/* uA */
+
+#define USB_DEFAULT_SYSTEM_CLOCK 80000000	/* 80 MHz */
+
+#define PM_QOS_SAMPLE_SEC	2
+#define PM_QOS_THRESHOLD	400
+
+enum msm_otg_phy_reg_mode {
+	USB_PHY_REG_OFF,
+	USB_PHY_REG_ON,
+	USB_PHY_REG_LPM_ON,
+	USB_PHY_REG_LPM_OFF,
+	USB_PHY_REG_3P3_ON,
+	USB_PHY_REG_3P3_OFF,
+};
+
+static char *override_phy_init;
+module_param(override_phy_init, charp, 0644);
+MODULE_PARM_DESC(override_phy_init,
+	"Override HSUSB PHY Init Settings");
+
+unsigned int lpm_disconnect_thresh = 1000;
+module_param(lpm_disconnect_thresh, uint, 0644);
+MODULE_PARM_DESC(lpm_disconnect_thresh,
+	"Delay before entering LPM on USB disconnect");
+
+/* by default debugging is enabled */
+static unsigned int enable_dbg_log = 1;
+module_param(enable_dbg_log, uint, 0644);
+MODULE_PARM_DESC(enable_dbg_log, "Debug buffer events");
+
+static struct msm_otg *the_msm_otg;
+static bool debug_bus_voting_enabled;
+
+static struct regulator *hsusb_3p3;
+static struct regulator *hsusb_1p8;
+static struct regulator *hsusb_vdd;
+static struct regulator *vbus_otg;
+static struct power_supply *psy;
+
+static int vdd_val[VDD_VAL_MAX];
+static u32 bus_freqs[USB_NOC_NUM_VOTE][USB_NUM_BUS_CLOCKS]  /*bimc,snoc,pcnoc*/;
+static char bus_clkname[USB_NUM_BUS_CLOCKS][20] = {"bimc_clk", "snoc_clk",
+						"pcnoc_clk"};
+static bool bus_clk_rate_set;
+
+static void dbg_inc(unsigned int *idx)
+{
+	*idx = (*idx + 1) & (DEBUG_MAX_MSG-1);
+}
+
+static void
+msm_otg_dbg_log_event(struct usb_phy *phy, char *event, int d1, int d2)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	unsigned long flags;
+	unsigned long long t;
+	unsigned long nanosec;
+
+	if (!enable_dbg_log)
+		return;
+
+	write_lock_irqsave(&motg->dbg_lock, flags);
+	t = cpu_clock(smp_processor_id());
+	nanosec = do_div(t, 1000000000)/1000;
+	scnprintf(motg->buf[motg->dbg_idx], DEBUG_MSG_LEN,
+			"[%5lu.%06lu]: %s :%d:%d",
+			(unsigned long)t, nanosec, event, d1, d2);
+
+	motg->dbg_idx++;
+	motg->dbg_idx = motg->dbg_idx % DEBUG_MAX_MSG;
+	write_unlock_irqrestore(&motg->dbg_lock, flags);
+}
+
+static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
+{
+	int rc = 0;
+
+	if (init) {
+		hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
+		if (IS_ERR(hsusb_3p3)) {
+			dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
+			return PTR_ERR(hsusb_3p3);
+		}
+
+		rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
+				USB_PHY_3P3_VOL_MAX);
+		if (rc) {
+			dev_err(motg->phy.dev, "unable to set voltage level for hsusb 3p3\n"
+									);
+			return rc;
+		}
+		hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
+		if (IS_ERR(hsusb_1p8)) {
+			dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
+			rc = PTR_ERR(hsusb_1p8);
+			goto put_3p3_lpm;
+		}
+		rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
+				USB_PHY_1P8_VOL_MAX);
+		if (rc) {
+			dev_err(motg->phy.dev, "unable to set voltage level for hsusb 1p8\n"
+									);
+			goto put_1p8;
+		}
+
+		return 0;
+	}
+
+put_1p8:
+	regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
+put_3p3_lpm:
+	regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
+	return rc;
+}
+
+static int msm_hsusb_config_vddcx(int high)
+{
+	struct msm_otg *motg = the_msm_otg;
+	int max_vol = vdd_val[VDD_MAX];
+	int min_vol;
+	int ret;
+
+	min_vol = vdd_val[!!high];
+	ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
+	if (ret) {
+		pr_err("%s: unable to set the voltage for regulator HSUSB_VDDCX\n",
+								__func__);
+		return ret;
+	}
+
+	pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+	msm_otg_dbg_log_event(&motg->phy, "CONFIG VDDCX", min_vol, max_vol);
+
+	return ret;
+}
+
+static int msm_hsusb_ldo_enable(struct msm_otg *motg,
+	enum msm_otg_phy_reg_mode mode)
+{
+	int ret = 0;
+
+	if (IS_ERR(hsusb_1p8)) {
+		pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(hsusb_3p3)) {
+		pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	switch (mode) {
+	case USB_PHY_REG_ON:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator HSUSB_1p8\n",
+								__func__);
+			return ret;
+		}
+
+		ret = regulator_enable(hsusb_1p8);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, 0);
+			return ret;
+		}
+
+	/* fall through */
+	case USB_PHY_REG_3P3_ON:
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator HSUSB_3p3\n",
+								__func__);
+			if (mode == USB_PHY_REG_ON) {
+				regulator_set_load(hsusb_1p8, 0);
+				regulator_disable(hsusb_1p8);
+			}
+			return ret;
+		}
+
+		ret = regulator_enable(hsusb_3p3);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
+				__func__);
+			regulator_set_load(hsusb_3p3, 0);
+			if (mode == USB_PHY_REG_ON) {
+				regulator_set_load(hsusb_1p8, 0);
+				regulator_disable(hsusb_1p8);
+			}
+			return ret;
+		}
+
+		break;
+
+	case USB_PHY_REG_OFF:
+		ret = regulator_disable(hsusb_1p8);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_1p8, 0);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator HSUSB_1p8\n",
+								__func__);
+
+	/* fall through */
+	case USB_PHY_REG_3P3_OFF:
+		ret = regulator_disable(hsusb_3p3);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
+				 __func__);
+			return ret;
+		}
+		ret = regulator_set_load(hsusb_3p3, 0);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator HSUSB_3p3\n",
+								__func__);
+
+		break;
+
+	case USB_PHY_REG_LPM_ON:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	case USB_PHY_REG_LPM_OFF:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	default:
+		pr_err("%s: Unsupported mode (%d).", __func__, mode);
+		return -ENOTSUPP;
+	}
+
+	pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
+	msm_otg_dbg_log_event(&motg->phy, "USB REG MODE", mode, ret);
+	return ret < 0 ? ret : 0;
+}
+
+static int ulpi_read(struct usb_phy *phy, u32 reg)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	int cnt = 0;
+
+	if (motg->pdata->emulation)
+		return 0;
+
+	if (motg->pdata->phy_type == QUSB_ULPI_PHY && reg > 0x3F) {
+		pr_debug("%s: ULPI vendor-specific reg 0x%02x not supported\n",
+			__func__, reg);
+		return 0;
+	}
+
+	/* initiate read operation */
+	writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(phy->dev, "ulpi_read: timeout %08x\n",
+			readl_relaxed(USB_ULPI_VIEWPORT));
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
+		return -ETIMEDOUT;
+	}
+	return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	int cnt = 0;
+
+	if (motg->pdata->emulation)
+		return 0;
+
+	if (motg->pdata->phy_type == QUSB_ULPI_PHY && reg > 0x3F) {
+		pr_debug("%s: ULPI vendor-specific reg 0x%02x not supported\n",
+			__func__, reg);
+		return 0;
+	}
+
+	/* initiate write operation */
+	writel_relaxed(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(phy->dev, "ulpi_write: timeout\n");
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static struct usb_phy_io_ops msm_otg_io_ops = {
+	.read = ulpi_read,
+	.write = ulpi_write,
+};
+
+static void ulpi_init(struct msm_otg *motg)
+{
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int aseq[10];
+	int *seq = NULL;
+
+	if (override_phy_init) {
+		pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
+				override_phy_init);
+		get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
+		seq = &aseq[1];
+	} else {
+		seq = pdata->phy_init_seq;
+	}
+
+	if (!seq)
+		return;
+
+	while (seq[0] >= 0) {
+		if (override_phy_init)
+			pr_debug("ulpi: write 0x%02x to 0x%02x\n",
+					seq[0], seq[1]);
+
+		dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
+				seq[0], seq[1]);
+		msm_otg_dbg_log_event(&motg->phy, "ULPI WRITE", seq[0], seq[1]);
+		ulpi_write(&motg->phy, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+static int msm_otg_phy_clk_reset(struct msm_otg *motg)
+{
+	int ret;
+
+	if (!motg->phy_reset_clk)
+		return 0;
+
+	if (motg->sleep_clk)
+		clk_disable_unprepare(motg->sleep_clk);
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+
+	ret = reset_control_assert(motg->phy_reset);
+	if (ret) {
+		pr_err("phy_reset_clk assert failed %d\n", ret);
+		return ret;
+	}
+	/*
+	 * As per databook, 10 usec delay is required between
+	 * PHY POR assert and de-assert.
+	 */
+	usleep_range(10, 15);
+	ret = reset_control_deassert(motg->phy_reset);
+	if (ret) {
+		pr_err("phy_reset_clk de-assert failed %d\n", ret);
+		return ret;
+	}
+	/*
+	 * As per databook, it takes 75 usec for PHY to stabilize
+	 * after the reset.
+	 */
+	usleep_range(80, 100);
+
+	if (motg->phy_csr_clk)
+		clk_prepare_enable(motg->phy_csr_clk);
+	if (motg->sleep_clk)
+		clk_prepare_enable(motg->sleep_clk);
+
+	return 0;
+}
+
+static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
+{
+	int ret;
+
+	if (assert) {
+		/* Using asynchronous block reset to the hardware */
+		dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
+		clk_disable_unprepare(motg->pclk);
+		clk_disable_unprepare(motg->core_clk);
+		ret = reset_control_assert(motg->core_reset);
+		if (ret)
+			dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
+	} else {
+		dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
+		ret = reset_control_deassert(motg->core_reset);
+		ndelay(200);
+		ret = clk_prepare_enable(motg->core_clk);
+		WARN(ret, "USB core_clk enable failed\n");
+		ret = clk_prepare_enable(motg->pclk);
+		WARN(ret, "USB pclk enable failed\n");
+		if (ret)
+			dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
+	}
+	return ret;
+}
+
+static int msm_otg_phy_reset(struct msm_otg *motg)
+{
+	u32 val;
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	/*
+	 * AHB2AHB Bypass mode shouldn't be enable before doing
+	 * async clock reset. If it is enable, disable the same.
+	 */
+	val = readl_relaxed(USB_AHBMODE);
+	if (val & AHB2AHB_BYPASS) {
+		pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+						__func__, val);
+		val &= ~AHB2AHB_BYPASS_BIT_MASK;
+		writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+		pr_err("%s(): AHBMODE: %x\n", __func__,
+				readl_relaxed(USB_AHBMODE));
+	}
+
+	ret = msm_otg_link_clk_reset(motg, 1);
+	if (ret)
+		return ret;
+
+	msm_otg_phy_clk_reset(motg);
+
+	/* wait for 1ms delay as suggested in HPG. */
+	usleep_range(1000, 1200);
+
+	ret = msm_otg_link_clk_reset(motg, 0);
+	if (ret)
+		return ret;
+
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+							USB_PHY_CTRL2);
+	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	dev_info(motg->phy.dev, "phy_reset: success\n");
+	msm_otg_dbg_log_event(&motg->phy, "PHY RESET SUCCESS",
+			motg->inputs, motg->phy.otg->state);
+	return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
+static int msm_otg_link_reset(struct msm_otg *motg)
+{
+	int cnt = 0;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	writel_relaxed(USBCMD_RESET, USB_USBCMD);
+	while (cnt < LINK_RESET_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
+			break;
+		udelay(1);
+		cnt++;
+	}
+	if (cnt >= LINK_RESET_TIMEOUT_USEC)
+		return -ETIMEDOUT;
+
+	/* select ULPI phy */
+	writel_relaxed(0x80000000, USB_PORTSC);
+	writel_relaxed(0x0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
+	return 0;
+}
+
+#define QUSB2PHY_PORT_POWERDOWN		0xB4
+#define QUSB2PHY_PORT_UTMI_CTRL2	0xC4
+
+static void msm_usb_phy_reset(struct msm_otg *motg)
+{
+	u32 val;
+	int ret, *seq;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		/* Assert USB PHY_PON */
+		val =  readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_POR_BIT_MASK;
+		val |= PHY_POR_ASSERT;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+
+		/* wait for minimum 10 microseconds as
+		 * suggested in HPG.
+		 */
+		usleep_range(10, 15);
+
+		/* Deassert USB PHY_PON */
+		val =  readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_POR_BIT_MASK;
+		val |= PHY_POR_DEASSERT;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case QUSB_ULPI_PHY:
+		ret = reset_control_assert(motg->phy_reset);
+		if (ret) {
+			pr_err("phy_reset_clk assert failed %d\n", ret);
+			break;
+		}
+
+		/* need to delay 10us for PHY to reset */
+		usleep_range(10, 20);
+
+		ret = reset_control_deassert(motg->phy_reset);
+		if (ret) {
+			pr_err("phy_reset_clk de-assert failed %d\n", ret);
+			break;
+		}
+
+		/* Ensure that RESET operation is completed. */
+		mb();
+
+		writel_relaxed(0x23,
+				motg->phy_csr_regs + QUSB2PHY_PORT_POWERDOWN);
+		writel_relaxed(0x0,
+				motg->phy_csr_regs + QUSB2PHY_PORT_UTMI_CTRL2);
+
+		/* Program tuning parameters for PHY */
+		seq = motg->pdata->phy_init_seq;
+		if (seq) {
+			while (seq[0] >= 0) {
+				writel_relaxed(seq[1],
+						motg->phy_csr_regs + seq[0]);
+				seq += 2;
+			}
+		}
+
+		/* ensure above writes are completed before re-enabling PHY */
+		wmb();
+		writel_relaxed(0x22,
+				motg->phy_csr_regs + QUSB2PHY_PORT_POWERDOWN);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (!motg->phy_por_clk) {
+			pr_err("phy_por_clk missing\n");
+			break;
+		}
+		ret = reset_control_assert(motg->phy_por_reset);
+		if (ret) {
+			pr_err("phy_por_clk assert failed %d\n", ret);
+			break;
+		}
+		/*
+		 * The Femto PHY is POR reset in the following scenarios.
+		 *
+		 * 1. After overriding the parameter registers.
+		 * 2. Low power mode exit from PHY retention.
+		 *
+		 * Ensure that SIDDQ is cleared before bringing the PHY
+		 * out of reset.
+		 *
+		 */
+
+		val = readb_relaxed(USB_PHY_CSR_PHY_CTRL_COMMON0);
+		val &= ~SIDDQ;
+		writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL_COMMON0);
+
+		/*
+		 * As per databook, 10 usec delay is required between
+		 * PHY POR assert and de-assert.
+		 */
+		usleep_range(10, 20);
+		ret = reset_control_deassert(motg->phy_por_reset);
+		if (ret) {
+			pr_err("phy_por_clk de-assert failed %d\n", ret);
+			break;
+		}
+		/*
+		 * As per databook, it takes 75 usec for PHY to stabilize
+		 * after the reset.
+		 */
+		usleep_range(80, 100);
+		break;
+	default:
+		break;
+	}
+	/* Ensure that RESET operation is completed. */
+	mb();
+}
+
+static int msm_otg_reset(struct usb_phy *phy)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int ret;
+	u32 val = 0;
+	u32 ulpi_val = 0;
+
+	msm_otg_dbg_log_event(&motg->phy, "USB RESET", phy->otg->state,
+			get_pm_runtime_counter(phy->dev));
+	/*
+	 * USB PHY and Link reset also reset the USB BAM.
+	 * Thus perform reset operation only once to avoid
+	 * USB BAM reset on other cases e.g. USB cable disconnections.
+	 * If hardware reported error then it must be reset for recovery.
+	 */
+	if (motg->err_event_seen)
+		dev_info(phy->dev, "performing USB h/w reset for recovery\n");
+	else if (pdata->disable_reset_on_disconnect && motg->reset_counter)
+		return 0;
+
+	motg->reset_counter++;
+
+	disable_irq(motg->irq);
+	if (motg->phy_irq)
+		disable_irq(motg->phy_irq);
+
+	ret = msm_otg_phy_reset(motg);
+	if (ret) {
+		dev_err(phy->dev, "phy_reset failed\n");
+		if (motg->phy_irq)
+			enable_irq(motg->phy_irq);
+
+		enable_irq(motg->irq);
+		return ret;
+	}
+
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+
+	enable_irq(motg->irq);
+	ret = msm_otg_link_reset(motg);
+	if (ret) {
+		dev_err(phy->dev, "link reset failed\n");
+		return ret;
+	}
+
+	msleep(100);
+
+	/* Reset USB PHY after performing USB Link RESET */
+	msm_usb_phy_reset(motg);
+
+	/* Program USB PHY Override registers. */
+	ulpi_init(motg);
+
+	/*
+	 * It is required to reset USB PHY after programming
+	 * the USB PHY Override registers to get the new
+	 * values into effect.
+	 */
+	msm_usb_phy_reset(motg);
+
+	if (pdata->otg_control == OTG_PHY_CONTROL) {
+		val = readl_relaxed(USB_OTGSC);
+		if (pdata->mode == USB_OTG) {
+			ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+			val |= OTGSC_IDIE | OTGSC_BSVIE;
+		} else if (pdata->mode == USB_PERIPHERAL) {
+			ulpi_val = ULPI_INT_SESS_VALID;
+			val |= OTGSC_BSVIE;
+		}
+		writel_relaxed(val, USB_OTGSC);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
+	} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+		ulpi_write(phy, OTG_COMP_DISABLE,
+			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
+		if (motg->phy_irq)
+			writeb_relaxed(USB_PHY_ID_MASK,
+				USB2_PHY_USB_PHY_INTERRUPT_MASK1);
+	}
+
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
+		writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU),
+				USB_OTGSC);
+
+	msm_otg_dbg_log_event(&motg->phy, "USB RESET DONE", phy->otg->state,
+			get_pm_runtime_counter(phy->dev));
+
+	if (pdata->enable_axi_prefetch)
+		writel_relaxed(readl_relaxed(USB_HS_APF_CTRL) | (APF_CTRL_EN),
+							USB_HS_APF_CTRL);
+
+	/*
+	 * Disable USB BAM as block reset resets USB BAM registers.
+	 */
+	msm_usb_bam_enable(CI_CTRL, false);
+
+	return 0;
+}
+
+static void msm_otg_kick_sm_work(struct msm_otg *motg)
+{
+	if (atomic_read(&motg->in_lpm))
+		motg->resume_pending = true;
+
+	/* For device mode, resume now. Let pm_resume handle other cases */
+	if (atomic_read(&motg->pm_suspended) &&
+			motg->phy.otg->state != OTG_STATE_B_SUSPEND) {
+		motg->sm_work_pending = true;
+	} else if (!motg->sm_work_pending) {
+		/* process event only if previous one is not pending */
+		queue_work(motg->otg_wq, &motg->sm_work);
+	}
+}
+
+/*
+ * UDC calls usb_phy_set_suspend() to notify during bus suspend/resume.
+ * Update relevant state-machine inputs and queue sm_work.
+ * LPM enter/exit doesn't happen directly from this routine.
+ */
+
+static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+	pr_debug("%s(%d) in %s state\n", __func__, suspend,
+				usb_otg_state_string(phy->otg->state));
+	msm_otg_dbg_log_event(phy, "SET SUSPEND", suspend, phy->otg->state);
+
+	if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+		return 0;
+
+	if (suspend) {
+		/* called in suspend interrupt context */
+		pr_debug("peripheral bus suspend\n");
+		msm_otg_dbg_log_event(phy, "PERIPHERAL BUS SUSPEND",
+				motg->inputs, phy->otg->state);
+
+		set_bit(A_BUS_SUSPEND, &motg->inputs);
+	} else {
+		/* host resume or remote-wakeup */
+		pr_debug("peripheral bus resume\n");
+		msm_otg_dbg_log_event(phy, "PERIPHERAL BUS RESUME",
+				motg->inputs, phy->otg->state);
+
+		clear_bit(A_BUS_SUSPEND, &motg->inputs);
+	}
+	/* use kick_sm_work to handle race with pm_resume */
+	msm_otg_kick_sm_work(motg);
+
+	return 0;
+}
+
+static int msm_otg_bus_freq_set(struct msm_otg *motg, enum usb_noc_mode mode)
+{
+	int i, ret;
+	long rate;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		rate = bus_freqs[mode][i];
+		if (!rate) {
+			pr_debug("%s rate not available\n", bus_clkname[i]);
+			continue;
+		}
+
+		ret = clk_set_rate(motg->bus_clks[i], rate);
+		if (ret) {
+			pr_err("%s set rate failed: %d\n", bus_clkname[i], ret);
+			return ret;
+		}
+		pr_debug("%s set to %lu Hz\n", bus_clkname[i],
+			 clk_get_rate(motg->bus_clks[i]));
+		msm_otg_dbg_log_event(&motg->phy, "OTG BUS FREQ SET", i, rate);
+	}
+
+	bus_clk_rate_set = true;
+
+	return 0;
+}
+
+static int msm_otg_bus_freq_get(struct msm_otg *motg)
+{
+	struct device *dev = motg->phy.dev;
+	struct device_node *np = dev->of_node;
+	int len = 0, i, count = USB_NUM_BUS_CLOCKS;
+
+	if (!np)
+		return -EINVAL;
+
+	/* SVS requires extra set of frequencies for perf_mode sysfs node */
+	if (motg->default_noc_mode == USB_NOC_SVS_VOTE)
+		count *= 2;
+
+	len = of_property_count_elems_of_size(np, "qcom,bus-clk-rate",
+							sizeof(len));
+	if (!len || (len != count)) {
+		pr_err("Invalid bus rate:%d %u\n", len, motg->default_noc_mode);
+		return -EINVAL;
+	}
+	of_property_read_u32_array(np, "qcom,bus-clk-rate", bus_freqs[0],
+				   count);
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (bus_freqs[0][i] == 0) {
+			motg->bus_clks[i] = NULL;
+			pr_debug("%s not available\n", bus_clkname[i]);
+			continue;
+		}
+
+		motg->bus_clks[i] = devm_clk_get(dev, bus_clkname[i]);
+		if (IS_ERR(motg->bus_clks[i])) {
+			pr_err("%s get failed\n", bus_clkname[i]);
+			return PTR_ERR(motg->bus_clks[i]);
+		}
+	}
+	return 0;
+}
+
+static void msm_otg_bus_clks_enable(struct msm_otg *motg)
+{
+	int i;
+	int ret;
+
+	if (!bus_clk_rate_set || motg->bus_clks_enabled)
+		return;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (motg->bus_clks[i] == NULL)
+			continue;
+		ret = clk_prepare_enable(motg->bus_clks[i]);
+		if (ret) {
+			pr_err("%s enable rate failed: %d\n", bus_clkname[i],
+				ret);
+			goto err_clk_en;
+		}
+	}
+	motg->bus_clks_enabled = true;
+	return;
+err_clk_en:
+	for (--i; i >= 0; --i) {
+		if (motg->bus_clks[i] != NULL)
+			clk_disable_unprepare(motg->bus_clks[i]);
+	}
+}
+
+static void msm_otg_bus_clks_disable(struct msm_otg *motg)
+{
+	int i;
+
+	if (!bus_clk_rate_set || !motg->bus_clks_enabled)
+		return;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (motg->bus_clks[i] != NULL)
+			clk_disable_unprepare(motg->bus_clks[i]);
+	}
+	motg->bus_clks_enabled = false;
+}
+
+static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
+{
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	msm_otg_dbg_log_event(&motg->phy, "BUS VOTE", vote,
+						motg->phy.otg->state);
+	/* Check if target allows min_vote to be same as no_vote */
+	if (pdata->bus_scale_table &&
+	    vote >= pdata->bus_scale_table->num_usecases)
+		vote = USB_NO_PERF_VOTE;
+
+	if (motg->bus_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+			motg->bus_perf_client, vote);
+		if (ret)
+			dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
+				   "for bus bw %d\n", __func__, vote, ret);
+	}
+
+	if (vote == USB_MAX_PERF_VOTE)
+		msm_otg_bus_clks_enable(motg);
+	else
+		msm_otg_bus_clks_disable(motg);
+}
+
+static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
+{
+	bool bsv_id_hv_int = false;
+	bool dp_dm_hv_int = false;
+	u32 val;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
+				motg->phy_irq)
+		bsv_id_hv_int = true;
+	if (motg->host_bus_suspend || motg->device_bus_suspend)
+		dp_dm_hv_int = true;
+
+	if (!bsv_id_hv_int && !dp_dm_hv_int)
+		return;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		if (bsv_id_hv_int)
+			val |= (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+		if (dp_dm_hv_int)
+			val |= PHY_CLAMP_DPDMSE_EN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (bsv_id_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL1);
+			val |= ID_HV_CLAMP_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL1);
+		}
+
+		if (dp_dm_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL3);
+			val |= CLAMP_MPM_DPSE_DMSE_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL3);
+		}
+		break;
+	default:
+		break;
+	}
+	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
+			__func__, bsv_id_hv_int, dp_dm_hv_int);
+	msm_otg_dbg_log_event(&motg->phy, "PHY HV INTR ENABLED",
+			bsv_id_hv_int, dp_dm_hv_int);
+}
+
+static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
+{
+	bool bsv_id_hv_int = false;
+	bool dp_dm_hv_int = false;
+	u32 val;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
+				motg->phy_irq)
+		bsv_id_hv_int = true;
+	if (motg->host_bus_suspend || motg->device_bus_suspend)
+		dp_dm_hv_int = true;
+
+	if (!bsv_id_hv_int && !dp_dm_hv_int)
+		return;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		if (bsv_id_hv_int)
+			val &= ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+		if (dp_dm_hv_int)
+			val &= ~PHY_CLAMP_DPDMSE_EN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (bsv_id_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL1);
+			val &= ~ID_HV_CLAMP_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL1);
+		}
+
+		if (dp_dm_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL3);
+			val &= ~CLAMP_MPM_DPSE_DMSE_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL3);
+		}
+		break;
+	default:
+		break;
+	}
+	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
+			__func__, bsv_id_hv_int, dp_dm_hv_int);
+	msm_otg_dbg_log_event(&motg->phy, "PHY HV INTR DISABLED",
+			bsv_id_hv_int, dp_dm_hv_int);
+}
+
+static void msm_otg_enter_phy_retention(struct msm_otg *motg)
+{
+	u32 val;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_RETEN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		/* Retention is supported via SIDDQ */
+		val = readb_relaxed(USB_PHY_CSR_PHY_CTRL_COMMON0);
+		val |= SIDDQ;
+		writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL_COMMON0);
+		break;
+	default:
+		break;
+	}
+	pr_debug("USB PHY is in retention\n");
+	msm_otg_dbg_log_event(&motg->phy, "USB PHY ENTER RETENTION",
+			motg->pdata->phy_type, 0);
+}
+
+static void msm_otg_exit_phy_retention(struct msm_otg *motg)
+{
+	int val;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		val |= PHY_RETEN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		/*
+		 * It is required to do USB block reset to bring Femto PHY out
+		 * of retention.
+		 */
+		msm_otg_reset(&motg->phy);
+		break;
+	default:
+		break;
+	}
+	pr_debug("USB PHY is exited from retention\n");
+	msm_otg_dbg_log_event(&motg->phy, "USB PHY EXIT RETENTION",
+			motg->pdata->phy_type, 0);
+}
+
+static void msm_id_status_w(struct work_struct *w);
+static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+
+	msm_otg_dbg_log_event(&motg->phy, "PHY ID IRQ",
+			atomic_read(&motg->in_lpm), motg->phy.otg->state);
+	if (atomic_read(&motg->in_lpm)) {
+		pr_debug("PHY ID IRQ in LPM\n");
+		motg->phy_irq_pending = true;
+		msm_otg_kick_sm_work(motg);
+	} else {
+		pr_debug("PHY ID IRQ outside LPM\n");
+		msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC (5 * 1000)
+#define PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC 100
+#define PHY_RESUME_TIMEOUT_USEC	(100 * 1000)
+
+#define PHY_SUSPEND_RETRIES_MAX 3
+
+static void msm_otg_set_vbus_state(int online);
+static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode);
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_suspend(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int cnt;
+	bool host_bus_suspend, device_bus_suspend, sm_work_busy;
+	u32 cmd_val;
+	u32 portsc, config2;
+	u32 func_ctrl;
+	int phcd_retry_cnt = 0, ret;
+	unsigned int phy_suspend_timeout;
+
+	cnt = 0;
+	msm_otg_dbg_log_event(phy, "LPM ENTER START",
+			motg->inputs, phy->otg->state);
+
+	if (atomic_read(&motg->in_lpm))
+		return 0;
+
+	cancel_delayed_work_sync(&motg->perf_vote_work);
+
+	disable_irq(motg->irq);
+	if (motg->phy_irq)
+		disable_irq(motg->phy_irq);
+lpm_start:
+	host_bus_suspend = phy->otg->host && !test_bit(ID, &motg->inputs);
+	device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
+		test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
+
+	if (host_bus_suspend)
+		msm_otg_perf_vote_update(motg, false);
+
+	/* !BSV, but its handling is in progress by otg sm_work */
+	sm_work_busy = !test_bit(B_SESS_VLD, &motg->inputs) &&
+			phy->otg->state == OTG_STATE_B_PERIPHERAL;
+
+	/* Perform block reset to recover from UDC error events on disconnect */
+	if (motg->err_event_seen)
+		msm_otg_reset(phy);
+
+	/* Enable line state difference wakeup fix for only device and host
+	 * bus suspend scenarios.  Otherwise PHY can not be suspended when
+	 * a charger that pulls DP/DM high is connected.
+	 */
+	config2 = readl_relaxed(USB_GENCONFIG_2);
+	if (device_bus_suspend)
+		config2 |= GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
+	else
+		config2 &= ~GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
+	writel_relaxed(config2, USB_GENCONFIG_2);
+
+	/*
+	 * Abort suspend when,
+	 * 1. host mode activation in progress due to Micro-A cable insertion
+	 * 2. !BSV, but its handling is in progress by otg sm_work
+	 * Don't abort suspend in case of dcp detected by PMIC
+	 */
+
+	if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend) ||
+							sm_work_busy) {
+		msm_otg_dbg_log_event(phy, "LPM ENTER ABORTED",
+						motg->inputs, 0);
+		enable_irq(motg->irq);
+		if (motg->phy_irq)
+			enable_irq(motg->phy_irq);
+		return -EBUSY;
+	}
+
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+		/* put the controller in non-driving mode */
+		func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+		ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+		ulpi_write(phy, ULPI_IFC_CTRL_AUTORESUME,
+						ULPI_CLR(ULPI_IFC_CTRL));
+	}
+
+	/*
+	 * PHY suspend sequence as mentioned in the databook.
+	 *
+	 * Device bus suspend: The controller may abort PHY suspend if
+	 * there is an incoming reset or resume from the host. If PHCD
+	 * is not set within 100 usec. Abort the LPM sequence.
+	 *
+	 * Host bus suspend: If the peripheral is attached, PHY is already
+	 * put into suspend along with the peripheral bus suspend. poll for
+	 * PHCD upto 5 msec. If the peripheral is not attached i.e entering
+	 * LPM with Micro-A cable, set the PHCD and poll for it for 5 msec.
+	 *
+	 * No cable connected: Set the PHCD to suspend the PHY. Poll for PHCD
+	 * upto 5 msec.
+	 *
+	 * The controller aborts PHY suspend only in device bus suspend case.
+	 * In other cases, it is observed that PHCD may not get set within
+	 * the timeout. If so, set the PHCD again and poll for it before
+	 * reset recovery.
+	 */
+
+phcd_retry:
+	if (device_bus_suspend)
+		phy_suspend_timeout = PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC;
+	else
+		phy_suspend_timeout = PHY_SUSPEND_TIMEOUT_USEC;
+
+	cnt = 0;
+	portsc = readl_relaxed(USB_PORTSC);
+	if (!(portsc & PORTSC_PHCD)) {
+		writel_relaxed(portsc | PORTSC_PHCD,
+				USB_PORTSC);
+		while (cnt < phy_suspend_timeout) {
+			if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+				break;
+			udelay(1);
+			cnt++;
+		}
+	}
+
+	if (cnt >= phy_suspend_timeout) {
+		if (phcd_retry_cnt > PHY_SUSPEND_RETRIES_MAX) {
+			msm_otg_dbg_log_event(phy, "PHY SUSPEND FAILED",
+				phcd_retry_cnt, phy->otg->state);
+			dev_err(phy->dev, "PHY suspend failed\n");
+			ret = -EBUSY;
+			goto phy_suspend_fail;
+		}
+
+		if (device_bus_suspend) {
+			dev_dbg(phy->dev, "PHY suspend aborted\n");
+			ret = -EBUSY;
+			goto phy_suspend_fail;
+		} else {
+			if (phcd_retry_cnt++ < PHY_SUSPEND_RETRIES_MAX) {
+				dev_dbg(phy->dev, "PHY suspend retry\n");
+				goto phcd_retry;
+			} else {
+				dev_err(phy->dev, "reset attempt during PHY suspend\n");
+				phcd_retry_cnt++;
+				motg->reset_counter = 0;
+				msm_otg_reset(phy);
+				goto lpm_start;
+			}
+		}
+	}
+
+	/*
+	 * PHY has capability to generate interrupt asynchronously in low
+	 * power mode (LPM). This interrupt is level triggered. So USB IRQ
+	 * line must be disabled till async interrupt enable bit is cleared
+	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+	 * block data communication from PHY.
+	 *
+	 * PHY retention mode is disallowed while entering to LPM with wall
+	 * charger connected.  But PHY is put into suspend mode. Hence
+	 * enable asynchronous interrupt to detect charger disconnection when
+	 * PMIC notifications are unavailable.
+	 */
+	cmd_val = readl_relaxed(USB_USBCMD);
+	if (host_bus_suspend || device_bus_suspend ||
+		(motg->pdata->otg_control == OTG_PHY_CONTROL))
+		cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
+	else
+		cmd_val |= ULPI_STP_CTRL;
+	writel_relaxed(cmd_val, USB_USBCMD);
+
+	/*
+	 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
+	 * PHY retention and collapse can not happen with VDP_SRC enabled.
+	 */
+
+
+	/*
+	 * We come here in 3 scenarios.
+	 *
+	 * (1) No cable connected (out of session):
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- PHY is put in retention.
+	 *	- If allowed (PMIC based detection), PHY is power collapsed.
+	 *	- DVDD (CX/MX) minimization and XO shutdown are allowed.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user.
+	 * (2) USB wall charger:
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- For BC1.2 compliant charger, retention is not allowed to
+	 *	keep VDP_SRC on. XO shutdown is allowed.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user.
+	 * (3) Device/Host Bus suspend (if LPM is enabled):
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- D+/D- MPM pin are configured to wakeup from line state
+	 *	change through PHY HV interrupts. PHY HV interrupts are
+	 *	also enabled. If MPM pins are not available, retention and
+	 *	XO is not allowed.
+	 *	- PHY is put into retention only if a gpio is used to keep
+	 *	the D+ pull-up. ALLOW_BUS_SUSPEND_WITHOUT_REWORK capability
+	 *	is set means, PHY can enable D+ pull-up or D+/D- pull-down
+	 *	without any re-work and PHY should not be put into retention.
+	 *	- DVDD (CX/MX) minimization and XO shutdown is allowed if
+	 *	ALLOW_BUS_SUSPEND_WITHOUT_REWORK is set (PHY DVDD is supplied
+	 *	via PMIC LDO) or board level re-work is present.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user
+	 *	or USB link asynchronous interrupt for line state change.
+	 *
+	 */
+	motg->host_bus_suspend = host_bus_suspend;
+	motg->device_bus_suspend = device_bus_suspend;
+
+	if (motg->caps & ALLOW_PHY_RETENTION && !device_bus_suspend &&
+		 (!host_bus_suspend || (motg->caps &
+		ALLOW_BUS_SUSPEND_WITHOUT_REWORK) ||
+		  ((motg->caps & ALLOW_HOST_PHY_RETENTION)
+		&& (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS))))) {
+		msm_otg_enable_phy_hv_int(motg);
+		if ((!host_bus_suspend || !(motg->caps &
+			ALLOW_BUS_SUSPEND_WITHOUT_REWORK)) &&
+			!(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+			msm_otg_enter_phy_retention(motg);
+			motg->lpm_flags |= PHY_RETENTIONED;
+		}
+	} else if (device_bus_suspend) {
+		/* DP DM HV interrupts are used for bus resume from XO off */
+		msm_otg_enable_phy_hv_int(motg);
+		if (motg->caps & ALLOW_PHY_RETENTION && pdata->vddmin_gpio) {
+
+			/*
+			 * This is HW WA needed when PHY_CLAMP_DPDMSE_EN is
+			 * enabled and we put the phy in retention mode.
+			 * Without this WA, the async_irq will be fired right
+			 * after suspending whithout any bus resume.
+			 */
+			config2 = readl_relaxed(USB_GENCONFIG_2);
+			config2 &= ~GENCONFIG_2_DPSE_DMSE_HV_INTR_EN;
+			writel_relaxed(config2, USB_GENCONFIG_2);
+
+			msm_otg_enter_phy_retention(motg);
+			motg->lpm_flags |= PHY_RETENTIONED;
+			gpio_direction_output(pdata->vddmin_gpio, 1);
+		}
+	}
+
+	/* Ensure that above operation is completed before turning off clocks */
+	mb();
+	/* Consider clocks on workaround flag only in case of bus suspend */
+	if (!(phy->otg->state == OTG_STATE_B_PERIPHERAL &&
+			test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
+			!motg->pdata->core_clk_always_on_workaround) {
+		clk_disable_unprepare(motg->pclk);
+		clk_disable_unprepare(motg->core_clk);
+		if (motg->phy_csr_clk)
+			clk_disable_unprepare(motg->phy_csr_clk);
+		motg->lpm_flags |= CLOCKS_DOWN;
+	}
+
+	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
+	if (!host_bus_suspend || (motg->caps &
+		ALLOW_BUS_SUSPEND_WITHOUT_REWORK) ||
+		((motg->caps & ALLOW_HOST_PHY_RETENTION) &&
+		(pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS)))) {
+		if (motg->xo_clk) {
+			clk_disable_unprepare(motg->xo_clk);
+			motg->lpm_flags |= XO_SHUTDOWN;
+		}
+	}
+
+	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
+			!host_bus_suspend && !device_bus_suspend) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+		motg->lpm_flags |= PHY_PWR_COLLAPSED;
+	} else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
+			!host_bus_suspend && !device_bus_suspend) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
+		motg->lpm_flags |= PHY_REGULATORS_LPM;
+	}
+
+	if (motg->lpm_flags & PHY_RETENTIONED ||
+		(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+		regulator_disable(hsusb_vdd);
+		msm_hsusb_config_vddcx(0);
+	}
+
+	if (device_may_wakeup(phy->dev)) {
+		if (host_bus_suspend || device_bus_suspend) {
+			enable_irq_wake(motg->async_irq);
+			enable_irq_wake(motg->irq);
+		}
+
+		if (motg->phy_irq)
+			enable_irq_wake(motg->phy_irq);
+		if (motg->pdata->pmic_id_irq)
+			enable_irq_wake(motg->pdata->pmic_id_irq);
+		if (motg->ext_id_irq)
+			enable_irq_wake(motg->ext_id_irq);
+	}
+	if (bus)
+		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+	msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+
+	atomic_set(&motg->in_lpm, 1);
+
+	/* Enable ASYNC IRQ during LPM */
+	enable_irq(motg->async_irq);
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+
+	enable_irq(motg->irq);
+	pm_relax(&motg->pdev->dev);
+
+	dev_dbg(phy->dev, "LPM caps = %lu flags = %lu\n",
+			motg->caps, motg->lpm_flags);
+	dev_info(phy->dev, "USB in low power mode\n");
+	msm_otg_dbg_log_event(phy, "LPM ENTER DONE",
+			motg->caps, motg->lpm_flags);
+
+	if (motg->err_event_seen) {
+		motg->err_event_seen = false;
+		if (motg->vbus_state != test_bit(B_SESS_VLD, &motg->inputs))
+			msm_otg_set_vbus_state(motg->vbus_state);
+		if (motg->id_state != test_bit(ID, &motg->inputs))
+			msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	return 0;
+
+phy_suspend_fail:
+	enable_irq(motg->irq);
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+	return ret;
+}
+
+static int msm_otg_resume(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
+	struct usb_hcd *hcd = bus_to_hcd(phy->otg->host);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int cnt = 0;
+	unsigned int temp;
+	unsigned int ret;
+	u32 func_ctrl;
+
+	msm_otg_dbg_log_event(phy, "LPM EXIT START", motg->inputs,
+							phy->otg->state);
+	if (!atomic_read(&motg->in_lpm)) {
+		msm_otg_dbg_log_event(phy, "USB NOT IN LPM",
+				atomic_read(&motg->in_lpm), phy->otg->state);
+		return 0;
+	}
+
+	disable_irq(motg->irq);
+	pm_stay_awake(&motg->pdev->dev);
+
+	/*
+	 * If we are resuming from the device bus suspend, restore
+	 * the max performance bus vote. Otherwise put a minimum
+	 * bus vote to satisfy the requirement for enabling clocks.
+	 */
+
+	if (motg->device_bus_suspend && debug_bus_voting_enabled)
+		msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+	else
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
+	/* Vote for TCXO when waking up the phy */
+	if (motg->lpm_flags & XO_SHUTDOWN) {
+		if (motg->xo_clk)
+			clk_prepare_enable(motg->xo_clk);
+		motg->lpm_flags &= ~XO_SHUTDOWN;
+	}
+
+	if (motg->lpm_flags & CLOCKS_DOWN) {
+		if (motg->phy_csr_clk) {
+			ret = clk_prepare_enable(motg->phy_csr_clk);
+			WARN(ret, "USB phy_csr_clk enable failed\n");
+		}
+		ret = clk_prepare_enable(motg->core_clk);
+		WARN(ret, "USB core_clk enable failed\n");
+		ret = clk_prepare_enable(motg->pclk);
+		WARN(ret, "USB pclk enable failed\n");
+		motg->lpm_flags &= ~CLOCKS_DOWN;
+	}
+
+	if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
+		motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
+	} else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
+		motg->lpm_flags &= ~PHY_REGULATORS_LPM;
+	}
+
+	if (motg->lpm_flags & PHY_RETENTIONED ||
+		(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+		msm_hsusb_config_vddcx(1);
+		ret = regulator_enable(hsusb_vdd);
+		WARN(ret, "hsusb_vdd LDO enable failed\n");
+		msm_otg_disable_phy_hv_int(motg);
+		msm_otg_exit_phy_retention(motg);
+		motg->lpm_flags &= ~PHY_RETENTIONED;
+		if (pdata->vddmin_gpio && motg->device_bus_suspend)
+			gpio_direction_input(pdata->vddmin_gpio);
+	} else if (motg->device_bus_suspend) {
+		msm_otg_disable_phy_hv_int(motg);
+	}
+
+	temp = readl_relaxed(USB_USBCMD);
+	temp &= ~ASYNC_INTR_CTRL;
+	temp &= ~ULPI_STP_CTRL;
+	writel_relaxed(temp, USB_USBCMD);
+
+	/*
+	 * PHY comes out of low power mode (LPM) in case of wakeup
+	 * from asynchronous interrupt.
+	 */
+	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+		goto skip_phy_resume;
+
+	writel_relaxed(readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
+
+	while (cnt < PHY_RESUME_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
+		/*
+		 * This is a fatal error. Reset the link and
+		 * PHY. USB state can not be restored. Re-insertion
+		 * of USB cable is the only way to get USB working.
+		 */
+		dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n"
+									);
+		msm_otg_reset(phy);
+	}
+
+skip_phy_resume:
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+		/* put the controller in normal mode */
+		func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+		ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+	}
+
+	if (device_may_wakeup(phy->dev)) {
+		if (motg->host_bus_suspend || motg->device_bus_suspend) {
+			disable_irq_wake(motg->async_irq);
+			disable_irq_wake(motg->irq);
+		}
+
+		if (motg->phy_irq)
+			disable_irq_wake(motg->phy_irq);
+		if (motg->pdata->pmic_id_irq)
+			disable_irq_wake(motg->pdata->pmic_id_irq);
+		if (motg->ext_id_irq)
+			disable_irq_wake(motg->ext_id_irq);
+	}
+	if (bus)
+		set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+	atomic_set(&motg->in_lpm, 0);
+
+	if (motg->async_int) {
+		/* Match the disable_irq call from ISR */
+		enable_irq(motg->async_int);
+		motg->async_int = 0;
+	}
+	enable_irq(motg->irq);
+
+	/* Enable ASYNC_IRQ only during LPM */
+	disable_irq(motg->async_irq);
+
+	if (motg->phy_irq_pending) {
+		motg->phy_irq_pending = false;
+		msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	if (motg->host_bus_suspend) {
+		usb_hcd_resume_root_hub(hcd);
+		schedule_delayed_work(&motg->perf_vote_work,
+			msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+	}
+
+	dev_info(phy->dev, "USB exited from low power mode\n");
+	msm_otg_dbg_log_event(phy, "LPM EXIT DONE",
+			motg->caps, motg->lpm_flags);
+
+	return 0;
+}
+#endif
+
+static void msm_otg_notify_chg_current(struct msm_otg *motg, unsigned int mA)
+{
+	struct usb_gadget *g = motg->phy.otg->gadget;
+	union power_supply_propval pval = {0};
+	bool enable;
+	int limit;
+
+	if (g && g->is_a_peripheral)
+		return;
+
+	dev_dbg(motg->phy.dev, "Requested curr from USB = %u\n", mA);
+
+	if (motg->cur_power == mA)
+		return;
+
+	dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
+	msm_otg_dbg_log_event(&motg->phy, "AVAIL CURR FROM USB", mA, 0);
+
+	if (!psy) {
+		dev_dbg(motg->phy.dev, "no usb power supply registered\n");
+		goto psy_error;
+	}
+
+	if (motg->cur_power == 0 && mA > 2) {
+		/* Enable charging */
+		enable = true;
+		limit = 1000 * mA;
+	} else if (motg->cur_power >= 0 && (mA == 0 || mA == 2)) {
+		/* Disable charging */
+		enable = false;
+		/* Set max current limit in uA */
+		limit = 1000 * mA;
+	} else {
+		enable = true;
+		/* Current has changed (100/2 --> 500) */
+		limit = 1000 * mA;
+	}
+
+	pval.intval = enable;
+	if (power_supply_set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval))
+		goto psy_error;
+
+	pval.intval = limit;
+	if (power_supply_set_property(psy, POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+									&pval))
+		goto psy_error;
+
+psy_error:
+	dev_dbg(motg->phy.dev, "power supply error when setting property\n");
+
+	motg->cur_power = mA;
+}
+
+static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+	/*
+	 * Gadget driver uses set_power method to notify about the
+	 * available current based on suspend/configured states.
+	 */
+	msm_otg_notify_chg_current(motg, mA);
+
+	return 0;
+}
+
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on);
+
+static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode)
+{
+	static bool curr_perf_mode;
+	int ret, latency = motg->pm_qos_latency;
+	long clk_rate;
+
+	if (curr_perf_mode == perf_mode)
+		return;
+
+	if (perf_mode) {
+		if (latency)
+			pm_qos_update_request(&motg->pm_qos_req_dma, latency);
+		msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+		clk_rate = motg->core_clk_rate;
+	} else {
+		if (latency)
+			pm_qos_update_request(&motg->pm_qos_req_dma,
+						PM_QOS_DEFAULT_VALUE);
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+		clk_rate = motg->core_clk_svs_rate;
+	}
+
+	if (clk_rate) {
+		ret = clk_set_rate(motg->core_clk, clk_rate);
+		if (ret)
+			dev_err(motg->phy.dev, "sys_clk set_rate fail:%d %ld\n",
+					ret, clk_rate);
+	}
+	curr_perf_mode = perf_mode;
+	pr_debug("%s: latency updated to: %d, core_freq to: %ld\n", __func__,
+					latency, clk_rate);
+}
+
+static void msm_otg_perf_vote_work(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg,
+						perf_vote_work.work);
+	unsigned int curr_sample_int_count;
+	bool in_perf_mode = false;
+
+	curr_sample_int_count = motg->usb_irq_count;
+	motg->usb_irq_count = 0;
+
+	if (curr_sample_int_count >= PM_QOS_THRESHOLD)
+		in_perf_mode = true;
+
+	msm_otg_perf_vote_update(motg, in_perf_mode);
+	pr_debug("%s: in_perf_mode:%u, interrupts in last sample:%u\n",
+		 __func__, in_perf_mode, curr_sample_int_count);
+
+	schedule_delayed_work(&motg->perf_vote_work,
+			msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+}
+
+static void msm_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct usb_hcd *hcd;
+	u32 val;
+
+	if (!otg->host)
+		return;
+
+	hcd = bus_to_hcd(otg->host);
+
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartHost GET",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_get_sync(otg->usb_phy->dev);
+	if (on) {
+		dev_dbg(otg->usb_phy->dev, "host on\n");
+		msm_otg_dbg_log_event(&motg->phy, "HOST ON",
+				motg->inputs, otg->state);
+		msm_hsusb_vbus_power(motg, 1);
+		msm_otg_reset(&motg->phy);
+
+		if (pdata->otg_control == OTG_PHY_CONTROL)
+			ulpi_write(otg->usb_phy, OTG_COMP_DISABLE,
+				ULPI_SET(ULPI_PWR_CLK_MNG_REG));
+
+		if (pdata->enable_axi_prefetch) {
+			val = readl_relaxed(USB_HS_APF_CTRL);
+			val &= ~APF_CTRL_EN;
+			writel_relaxed(val, USB_HS_APF_CTRL);
+		}
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+#ifdef CONFIG_SMP
+		motg->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ;
+		motg->pm_qos_req_dma.irq = motg->irq;
+#endif
+		pm_qos_add_request(&motg->pm_qos_req_dma,
+				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+		/* start in perf mode for better performance initially */
+		msm_otg_perf_vote_update(motg, true);
+		schedule_delayed_work(&motg->perf_vote_work,
+				msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+	} else {
+		dev_dbg(otg->usb_phy->dev, "host off\n");
+		msm_otg_dbg_log_event(&motg->phy, "HOST OFF",
+				motg->inputs, otg->state);
+		msm_hsusb_vbus_power(motg, 0);
+
+		cancel_delayed_work_sync(&motg->perf_vote_work);
+		msm_otg_perf_vote_update(motg, false);
+		pm_qos_remove_request(&motg->pm_qos_req_dma);
+
+		pm_runtime_disable(&hcd->self.root_hub->dev);
+		pm_runtime_barrier(&hcd->self.root_hub->dev);
+		usb_remove_hcd(hcd);
+		msm_otg_reset(&motg->phy);
+
+		if (pdata->enable_axi_prefetch)
+			writel_relaxed(readl_relaxed(USB_HS_APF_CTRL)
+					| (APF_CTRL_EN), USB_HS_APF_CTRL);
+
+		/* HCD core reset all bits of PORTSC. select ULPI phy */
+		writel_relaxed(0x80000000, USB_PORTSC);
+
+		if (pdata->otg_control == OTG_PHY_CONTROL)
+			ulpi_write(otg->usb_phy, OTG_COMP_DISABLE,
+				ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
+	}
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartHost PUT",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+
+	pm_runtime_mark_last_busy(otg->usb_phy->dev);
+	pm_runtime_put_autosuspend(otg->usb_phy->dev);
+}
+
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
+{
+	int ret;
+	static bool vbus_is_on;
+
+	msm_otg_dbg_log_event(&motg->phy, "VBUS POWER", on, vbus_is_on);
+	if (vbus_is_on == on)
+		return;
+
+	if (!vbus_otg) {
+		pr_err("vbus_otg is NULL.");
+		return;
+	}
+
+	/*
+	 * if entering host mode tell the charger to not draw any current
+	 * from usb before turning on the boost.
+	 * if exiting host mode disable the boost before enabling to draw
+	 * current from the source.
+	 */
+	if (on) {
+		ret = regulator_enable(vbus_otg);
+		if (ret) {
+			pr_err("unable to enable vbus_otg\n");
+			return;
+		}
+		vbus_is_on = true;
+	} else {
+		ret = regulator_disable(vbus_otg);
+		if (ret) {
+			pr_err("unable to disable vbus_otg\n");
+			return;
+		}
+		vbus_is_on = false;
+	}
+}
+
+static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct usb_hcd *hcd;
+
+	/*
+	 * Fail host registration if this board can support
+	 * only peripheral configuration.
+	 */
+	if (motg->pdata->mode == USB_PERIPHERAL) {
+		dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
+		return -ENODEV;
+	}
+
+	if (host) {
+		vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
+		if (IS_ERR(vbus_otg)) {
+			msm_otg_dbg_log_event(&motg->phy,
+					"UNABLE TO GET VBUS_OTG",
+					otg->state, 0);
+			pr_err("Unable to get vbus_otg\n");
+			return PTR_ERR(vbus_otg);
+		}
+	} else {
+		if (otg->state == OTG_STATE_A_HOST) {
+			msm_otg_start_host(otg, 0);
+			otg->host = NULL;
+			otg->state = OTG_STATE_UNDEFINED;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		} else {
+			otg->host = NULL;
+		}
+
+		return 0;
+	}
+
+	hcd = bus_to_hcd(host);
+	hcd->power_budget = motg->pdata->power_budget;
+
+	otg->host = host;
+	dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
+	msm_otg_dbg_log_event(&motg->phy, "HOST DRIVER REGISTERED",
+			hcd->power_budget, motg->pdata->mode);
+
+	/*
+	 * Kick the state machine work, if peripheral is not supported
+	 * or peripheral is already registered with us.
+	 */
+	if (motg->pdata->mode == USB_HOST || otg->gadget)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	return 0;
+}
+
+static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct pinctrl_state *set_state;
+	int ret;
+
+	if (!otg->gadget)
+		return;
+
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartPeri GET",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_get_sync(otg->usb_phy->dev);
+	if (on) {
+		dev_dbg(otg->usb_phy->dev, "gadget on\n");
+		msm_otg_dbg_log_event(&motg->phy, "GADGET ON",
+				motg->inputs, otg->state);
+
+		/* Configure BUS performance parameters for MAX bandwidth */
+		if (debug_bus_voting_enabled)
+			msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+		/* bump up usb core_clk to default */
+		clk_set_rate(motg->core_clk, motg->core_clk_rate);
+
+		usb_gadget_vbus_connect(otg->gadget);
+
+		/*
+		 * Request VDD min gpio, if need to support VDD
+		 * minimazation during peripheral bus suspend.
+		 */
+		if (pdata->vddmin_gpio) {
+			if (motg->phy_pinctrl) {
+				set_state =
+					pinctrl_lookup_state(motg->phy_pinctrl,
+							"hsusb_active");
+				if (IS_ERR(set_state)) {
+					pr_err("cannot get phy pinctrl active state\n");
+				} else {
+					pinctrl_select_state(motg->phy_pinctrl,
+								set_state);
+				}
+			}
+
+			ret = gpio_request(pdata->vddmin_gpio,
+					"MSM_OTG_VDD_MIN_GPIO");
+			if (ret < 0) {
+				dev_err(otg->usb_phy->dev, "gpio req failed for vdd min:%d\n",
+						ret);
+				pdata->vddmin_gpio = 0;
+			}
+		}
+	} else {
+		dev_dbg(otg->usb_phy->dev, "gadget off\n");
+		msm_otg_dbg_log_event(&motg->phy, "GADGET OFF",
+			motg->inputs, otg->state);
+		usb_gadget_vbus_disconnect(otg->gadget);
+		clear_bit(A_BUS_SUSPEND, &motg->inputs);
+		/* Configure BUS performance parameters to default */
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
+		if (pdata->vddmin_gpio) {
+			gpio_free(pdata->vddmin_gpio);
+			if (motg->phy_pinctrl) {
+				set_state =
+					pinctrl_lookup_state(motg->phy_pinctrl,
+							"hsusb_sleep");
+				if (IS_ERR(set_state))
+					pr_err("cannot get phy pinctrl sleep state\n");
+				else
+					pinctrl_select_state(motg->phy_pinctrl,
+						set_state);
+			}
+		}
+	}
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartPeri PUT",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_mark_last_busy(otg->usb_phy->dev);
+	pm_runtime_put_autosuspend(otg->usb_phy->dev);
+}
+
+static int msm_otg_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+
+	/*
+	 * Fail peripheral registration if this board can support
+	 * only host configuration.
+	 */
+	if (motg->pdata->mode == USB_HOST) {
+		dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
+		return -ENODEV;
+	}
+
+	if (!gadget) {
+		if (otg->state == OTG_STATE_B_PERIPHERAL) {
+			msm_otg_dbg_log_event(&motg->phy,
+				"PM RUNTIME: PERIPHERAL GET1",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget = NULL;
+			otg->state = OTG_STATE_UNDEFINED;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		} else {
+			otg->gadget = NULL;
+		}
+
+		return 0;
+	}
+	otg->gadget = gadget;
+	dev_dbg(otg->usb_phy->dev, "peripheral driver registered w/ tranceiver\n");
+	msm_otg_dbg_log_event(&motg->phy, "PERIPHERAL DRIVER REGISTERED",
+			otg->state, motg->pdata->mode);
+
+	/*
+	 * Kick the state machine work, if host is not supported
+	 * or host is already registered with us.
+	 */
+	if (motg->pdata->mode == USB_PERIPHERAL || otg->host)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	return 0;
+}
+
+static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
+{
+	unsigned long flags;
+	bool id;
+	int ret;
+
+	if (!motg->pdata->pmic_id_irq)
+		return -ENODEV;
+
+	local_irq_save(flags);
+	ret = irq_get_irqchip_state(motg->pdata->pmic_id_irq,
+					IRQCHIP_STATE_LINE_LEVEL, &id);
+	local_irq_restore(flags);
+
+	/*
+	 * If we can not read ID line state for some reason, treat
+	 * it as float. This would prevent MHL discovery and kicking
+	 * host mode unnecessarily.
+	 */
+	if (ret < 0)
+		return true;
+
+	return !!id;
+}
+
+static bool msm_otg_read_phy_id_state(struct msm_otg *motg)
+{
+	u8 val;
+
+	/*
+	 * clear the pending/outstanding interrupts and
+	 * read the ID status from the SRC_STATUS register.
+	 */
+	writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);
+
+	writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
+	/*
+	 * Databook says 200 usec delay is required for
+	 * clearing the interrupts.
+	 */
+	udelay(200);
+	writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);
+
+	val = readb_relaxed(USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS);
+	if (val & USB_PHY_IDDIG_1_0)
+		return false; /* ID is grounded */
+	else
+		return true;
+}
+
+/*
+ * We support OTG, Peripheral only and Host only configurations. In case
+ * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
+ * via Id pin status or user request (debugfs). Id/BSV interrupts are not
+ * enabled when switch is controlled by user and default mode is supplied
+ * by board file, which can be changed by userspace later.
+ */
+static void msm_otg_init_sm(struct msm_otg *motg)
+{
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	u32 otgsc = readl_relaxed(USB_OTGSC);
+
+	switch (pdata->mode) {
+	case USB_OTG:
+		if (pdata->otg_control == OTG_USER_CONTROL) {
+			if (pdata->default_mode == USB_HOST) {
+				clear_bit(ID, &motg->inputs);
+			} else if (pdata->default_mode == USB_PERIPHERAL) {
+				set_bit(ID, &motg->inputs);
+				set_bit(B_SESS_VLD, &motg->inputs);
+			} else {
+				set_bit(ID, &motg->inputs);
+				clear_bit(B_SESS_VLD, &motg->inputs);
+			}
+		} else if (pdata->otg_control == OTG_PHY_CONTROL) {
+			if (otgsc & OTGSC_ID)
+				set_bit(ID, &motg->inputs);
+			else
+				clear_bit(ID, &motg->inputs);
+			if (otgsc & OTGSC_BSV)
+				set_bit(B_SESS_VLD, &motg->inputs);
+			else
+				clear_bit(B_SESS_VLD, &motg->inputs);
+		} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+			if (pdata->pmic_id_irq) {
+				if (msm_otg_read_pmic_id_state(motg))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			} else if (motg->ext_id_irq) {
+				if (gpio_get_value(pdata->usb_id_gpio))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			} else if (motg->phy_irq) {
+				if (msm_otg_read_phy_id_state(motg))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			}
+		}
+		break;
+	case USB_HOST:
+		clear_bit(ID, &motg->inputs);
+		break;
+	case USB_PERIPHERAL:
+		set_bit(ID, &motg->inputs);
+		if (pdata->otg_control == OTG_PHY_CONTROL) {
+			if (otgsc & OTGSC_BSV)
+				set_bit(B_SESS_VLD, &motg->inputs);
+			else
+				clear_bit(B_SESS_VLD, &motg->inputs);
+		} else if (pdata->otg_control == OTG_USER_CONTROL) {
+			set_bit(ID, &motg->inputs);
+			set_bit(B_SESS_VLD, &motg->inputs);
+		}
+		break;
+	default:
+		break;
+	}
+	msm_otg_dbg_log_event(&motg->phy, "SM INIT", pdata->mode, motg->inputs);
+	if (motg->id_state != USB_ID_GROUND)
+		motg->id_state = (test_bit(ID, &motg->inputs)) ? USB_ID_FLOAT :
+							USB_ID_GROUND;
+}
+
+static void msm_otg_sm_work(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
+	struct usb_otg *otg = motg->phy.otg;
+	struct device *dev = otg->usb_phy->dev;
+	bool work = 0;
+	int ret;
+
+	pr_debug("%s work\n", usb_otg_state_string(otg->state));
+	msm_otg_dbg_log_event(&motg->phy, "SM WORK:",
+			otg->state, motg->inputs);
+
+	/* Just resume h/w if reqd, pm_count is handled based on state/inputs */
+	if (motg->resume_pending) {
+		pm_runtime_get_sync(otg->usb_phy->dev);
+		if (atomic_read(&motg->in_lpm)) {
+			dev_err(dev, "SM WORK: USB is in LPM\n");
+			msm_otg_dbg_log_event(&motg->phy,
+					"SM WORK: USB IS IN LPM",
+					otg->state, motg->inputs);
+			msm_otg_resume(motg);
+		}
+		motg->resume_pending = false;
+		pm_runtime_put_noidle(otg->usb_phy->dev);
+	}
+
+	switch (otg->state) {
+	case OTG_STATE_UNDEFINED:
+		pm_runtime_get_sync(otg->usb_phy->dev);
+		msm_otg_reset(otg->usb_phy);
+		/* Add child device only after block reset */
+		ret = of_platform_populate(motg->pdev->dev.of_node, NULL, NULL,
+					&motg->pdev->dev);
+		if (ret)
+			dev_dbg(&motg->pdev->dev, "failed to add BAM core\n");
+
+		msm_otg_init_sm(motg);
+		otg->state = OTG_STATE_B_IDLE;
+		if (!test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(ID, &motg->inputs)) {
+			msm_otg_dbg_log_event(&motg->phy,
+				"PM RUNTIME: UNDEF PUT",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+			pm_runtime_put_sync(otg->usb_phy->dev);
+			break;
+		}
+		pm_runtime_put(otg->usb_phy->dev);
+		/* FALL THROUGH */
+	case OTG_STATE_B_IDLE:
+		if (!test_bit(ID, &motg->inputs) && otg->host) {
+			pr_debug("!id\n");
+			msm_otg_dbg_log_event(&motg->phy, "!ID",
+					motg->inputs, otg->state);
+			if (!otg->host) {
+				msm_otg_dbg_log_event(&motg->phy,
+					"SM WORK: Host Not Set",
+					otg->state, motg->inputs);
+				break;
+			}
+
+			msm_otg_start_host(otg, 1);
+			otg->state = OTG_STATE_A_HOST;
+		} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("b_sess_vld\n");
+			msm_otg_dbg_log_event(&motg->phy, "B_SESS_VLD",
+					motg->inputs, otg->state);
+			if (!otg->gadget) {
+				msm_otg_dbg_log_event(&motg->phy,
+					"SM WORK: Gadget Not Set",
+					otg->state, motg->inputs);
+				break;
+			}
+
+			pm_runtime_get_sync(otg->usb_phy->dev);
+			msm_otg_start_peripheral(otg, 1);
+			otg->state = OTG_STATE_B_PERIPHERAL;
+		} else {
+			pr_debug("Cable disconnected\n");
+			msm_otg_dbg_log_event(&motg->phy, "RT: Cable DISC",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+
+			msm_otg_notify_chg_current(motg, 0);
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!test_bit(B_SESS_VLD, &motg->inputs)) {
+			msm_otg_start_peripheral(otg, 0);
+			msm_otg_dbg_log_event(&motg->phy, "RT PM: B_PERI A PUT",
+				get_pm_runtime_counter(dev), 0);
+			/* _put for _get done on cable connect in B_IDLE */
+			pm_runtime_mark_last_busy(dev);
+			pm_runtime_put_autosuspend(dev);
+			/* Schedule work to finish cable disconnect processing*/
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("a_bus_suspend\n");
+			msm_otg_dbg_log_event(&motg->phy,
+				"BUS_SUSPEND: PM RT PUT",
+				get_pm_runtime_counter(dev), 0);
+			otg->state = OTG_STATE_B_SUSPEND;
+			/* _get on connect in B_IDLE or host resume in B_SUSP */
+			pm_runtime_mark_last_busy(dev);
+			pm_runtime_put_autosuspend(dev);
+		}
+		break;
+	case OTG_STATE_B_SUSPEND:
+		if (!test_bit(B_SESS_VLD, &motg->inputs)) {
+			msm_otg_start_peripheral(otg, 0);
+			otg->state = OTG_STATE_B_IDLE;
+			/* Schedule work to finish cable disconnect processing*/
+			work = 1;
+		} else if (!test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("!a_bus_suspend\n");
+			otg->state = OTG_STATE_B_PERIPHERAL;
+			msm_otg_dbg_log_event(&motg->phy,
+				"BUS_RESUME: PM RT GET",
+				get_pm_runtime_counter(dev), 0);
+			pm_runtime_get_sync(dev);
+		}
+		break;
+	case OTG_STATE_A_HOST:
+		if (test_bit(ID, &motg->inputs)) {
+			msm_otg_start_host(otg, 0);
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (work)
+		queue_work(motg->otg_wq, &motg->sm_work);
+}
+
+static irqreturn_t msm_otg_irq(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+	struct usb_otg *otg = motg->phy.otg;
+	u32 otgsc = 0;
+	bool work = 0;
+
+	if (atomic_read(&motg->in_lpm)) {
+		pr_debug("OTG IRQ: %d in LPM\n", irq);
+		msm_otg_dbg_log_event(&motg->phy, "OTG IRQ IS IN LPM",
+				irq, otg->state);
+		/*Ignore interrupt if one interrupt already seen in LPM*/
+		if (motg->async_int)
+			return IRQ_HANDLED;
+
+		disable_irq_nosync(irq);
+		motg->async_int = irq;
+		msm_otg_kick_sm_work(motg);
+
+		return IRQ_HANDLED;
+	}
+	motg->usb_irq_count++;
+
+	otgsc = readl_relaxed(USB_OTGSC);
+	if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+		return IRQ_NONE;
+
+	if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
+		if (otgsc & OTGSC_ID) {
+			dev_dbg(otg->usb_phy->dev, "ID set\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID SET",
+				motg->inputs, otg->state);
+			set_bit(ID, &motg->inputs);
+		} else {
+			dev_dbg(otg->usb_phy->dev, "ID clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID CLEAR",
+					motg->inputs, otg->state);
+			clear_bit(ID, &motg->inputs);
+		}
+		work = 1;
+	} else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+		if (otgsc & OTGSC_BSV) {
+			dev_dbg(otg->usb_phy->dev, "BSV set\n");
+			msm_otg_dbg_log_event(&motg->phy, "BSV SET",
+					motg->inputs, otg->state);
+			set_bit(B_SESS_VLD, &motg->inputs);
+		} else {
+			dev_dbg(otg->usb_phy->dev, "BSV clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "BSV CLEAR",
+					motg->inputs, otg->state);
+			clear_bit(B_SESS_VLD, &motg->inputs);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+		}
+		work = 1;
+	}
+	if (work)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	writel_relaxed(otgsc, USB_OTGSC);
+
+	return IRQ_HANDLED;
+}
+
+static void msm_otg_set_vbus_state(int online)
+{
+	struct msm_otg *motg = the_msm_otg;
+
+	motg->vbus_state = online;
+
+	if (motg->err_event_seen)
+		return;
+
+	if (online) {
+		pr_debug("EXTCON: BSV set\n");
+		msm_otg_dbg_log_event(&motg->phy, "EXTCON: BSV SET",
+				motg->inputs, 0);
+		if (test_and_set_bit(B_SESS_VLD, &motg->inputs))
+			return;
+	} else {
+		pr_debug("EXTCON: BSV clear\n");
+		msm_otg_dbg_log_event(&motg->phy, "EXTCON: BSV CLEAR",
+				motg->inputs, 0);
+		if (!test_and_clear_bit(B_SESS_VLD, &motg->inputs))
+			return;
+	}
+
+	msm_otg_dbg_log_event(&motg->phy, "CHECK VBUS EVENT DURING SUSPEND",
+			atomic_read(&motg->pm_suspended),
+			motg->sm_work_pending);
+
+	/* Move to host mode on vbus low if required */
+	if (motg->pdata->vbus_low_as_hostmode) {
+		if (!test_bit(B_SESS_VLD, &motg->inputs))
+			clear_bit(ID, &motg->inputs);
+		else
+			set_bit(ID, &motg->inputs);
+	}
+	msm_otg_kick_sm_work(motg);
+}
+
+static void msm_id_status_w(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg,
+						id_status_work.work);
+	int work = 0;
+
+	dev_dbg(motg->phy.dev, "ID status_w\n");
+
+	if (motg->pdata->pmic_id_irq)
+		motg->id_state = msm_otg_read_pmic_id_state(motg);
+	else if (motg->ext_id_irq)
+		motg->id_state = gpio_get_value(motg->pdata->usb_id_gpio);
+	else if (motg->phy_irq)
+		motg->id_state = msm_otg_read_phy_id_state(motg);
+
+	if (motg->err_event_seen)
+		return;
+
+	if (motg->id_state) {
+		if (gpio_is_valid(motg->pdata->switch_sel_gpio))
+			gpio_direction_input(motg->pdata->switch_sel_gpio);
+		if (!test_and_set_bit(ID, &motg->inputs)) {
+			pr_debug("ID set\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID SET",
+					motg->inputs, motg->phy.otg->state);
+			work = 1;
+		}
+	} else {
+		if (gpio_is_valid(motg->pdata->switch_sel_gpio))
+			gpio_direction_output(motg->pdata->switch_sel_gpio, 1);
+		if (test_and_clear_bit(ID, &motg->inputs)) {
+			pr_debug("ID clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID CLEAR",
+					motg->inputs, motg->phy.otg->state);
+			work = 1;
+		}
+	}
+
+	if (work && (motg->phy.otg->state != OTG_STATE_UNDEFINED)) {
+		msm_otg_dbg_log_event(&motg->phy,
+				"CHECK ID EVENT DURING SUSPEND",
+				atomic_read(&motg->pm_suspended),
+				motg->sm_work_pending);
+		msm_otg_kick_sm_work(motg);
+	}
+}
+
+#define MSM_ID_STATUS_DELAY	5 /* 5msec */
+static irqreturn_t msm_id_irq(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+
+	/*schedule delayed work for 5msec for ID line state to settle*/
+	queue_delayed_work(motg->otg_wq, &motg->id_status_work,
+			msecs_to_jiffies(MSM_ID_STATUS_DELAY));
+
+	return IRQ_HANDLED;
+}
+
+int msm_otg_pm_notify(struct notifier_block *notify_block,
+					unsigned long mode, void *unused)
+{
+	struct msm_otg *motg = container_of(
+		notify_block, struct msm_otg, pm_notify);
+
+	dev_dbg(motg->phy.dev, "OTG PM notify:%lx, sm_pending:%u\n", mode,
+					motg->sm_work_pending);
+	msm_otg_dbg_log_event(&motg->phy, "PM NOTIFY",
+			mode, motg->sm_work_pending);
+
+	switch (mode) {
+	case PM_POST_SUSPEND:
+		/* OTG sm_work can be armed now */
+		atomic_set(&motg->pm_suspended, 0);
+
+		/* Handle any deferred wakeup events from USB during suspend */
+		if (motg->sm_work_pending) {
+			motg->sm_work_pending = false;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int msm_otg_mode_show(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	struct usb_otg *otg = motg->phy.otg;
+
+	switch (otg->state) {
+	case OTG_STATE_A_HOST:
+		seq_puts(s, "host\n");
+		break;
+	case OTG_STATE_B_IDLE:
+	case OTG_STATE_B_PERIPHERAL:
+	case OTG_STATE_B_SUSPEND:
+		seq_puts(s, "peripheral\n");
+		break;
+	default:
+		seq_puts(s, "none\n");
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_otg_mode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_mode_show, inode->i_private);
+}
+
+static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+	char buf[16];
+	struct usb_phy *phy = &motg->phy;
+	int status = count;
+	enum usb_mode_type req_mode;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+		status = -EFAULT;
+		goto out;
+	}
+
+	if (!strcmp(buf, "host")) {
+		req_mode = USB_HOST;
+	} else if (!strcmp(buf, "peripheral")) {
+		req_mode = USB_PERIPHERAL;
+	} else if (!strcmp(buf, "none")) {
+		req_mode = USB_NONE;
+	} else {
+		status = -EINVAL;
+		goto out;
+	}
+
+	switch (req_mode) {
+	case USB_NONE:
+		switch (phy->otg->state) {
+		case OTG_STATE_A_HOST:
+		case OTG_STATE_B_PERIPHERAL:
+		case OTG_STATE_B_SUSPEND:
+			set_bit(ID, &motg->inputs);
+			clear_bit(B_SESS_VLD, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	case USB_PERIPHERAL:
+		switch (phy->otg->state) {
+		case OTG_STATE_B_IDLE:
+		case OTG_STATE_A_HOST:
+			set_bit(ID, &motg->inputs);
+			set_bit(B_SESS_VLD, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	case USB_HOST:
+		switch (phy->otg->state) {
+		case OTG_STATE_B_IDLE:
+		case OTG_STATE_B_PERIPHERAL:
+		case OTG_STATE_B_SUSPEND:
+			clear_bit(ID, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	default:
+		goto out;
+	}
+
+	motg->id_state = (test_bit(ID, &motg->inputs)) ? USB_ID_FLOAT :
+							USB_ID_GROUND;
+	queue_work(motg->otg_wq, &motg->sm_work);
+out:
+	return status;
+}
+
+const struct file_operations msm_otg_mode_fops = {
+	.open = msm_otg_mode_open,
+	.read = seq_read,
+	.write = msm_otg_mode_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	struct usb_phy *phy = &motg->phy;
+
+	seq_printf(s, "%s\n", usb_otg_state_string(phy->otg->state));
+	return 0;
+}
+
+static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_show_otg_state, inode->i_private);
+}
+
+const struct file_operations msm_otg_state_fops = {
+	.open = msm_otg_otg_state_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_bus_show(struct seq_file *s, void *unused)
+{
+	if (debug_bus_voting_enabled)
+		seq_puts(s, "enabled\n");
+	else
+		seq_puts(s, "disabled\n");
+
+	return 0;
+}
+
+static int msm_otg_bus_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_bus_show, inode->i_private);
+}
+
+static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[8];
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strcmp(buf, "enable")) {
+		/* Do not vote here. Let OTG statemachine decide when to vote */
+		debug_bus_voting_enabled = true;
+	} else {
+		debug_bus_voting_enabled = false;
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+	}
+
+	return count;
+}
+
+static int msm_otg_dbg_buff_show(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	unsigned long	flags;
+	unsigned int	i;
+
+	read_lock_irqsave(&motg->dbg_lock, flags);
+
+	i = motg->dbg_idx;
+	if (strnlen(motg->buf[i], DEBUG_MSG_LEN))
+		seq_printf(s, "%s\n", motg->buf[i]);
+	for (dbg_inc(&i); i != motg->dbg_idx;  dbg_inc(&i)) {
+		if (!strnlen(motg->buf[i], DEBUG_MSG_LEN))
+			continue;
+		seq_printf(s, "%s\n", motg->buf[i]);
+	}
+	read_unlock_irqrestore(&motg->dbg_lock, flags);
+
+	return 0;
+}
+
+static int msm_otg_dbg_buff_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_dbg_buff_show, inode->i_private);
+}
+
+const struct file_operations msm_otg_dbg_buff_fops = {
+	.open = msm_otg_dbg_buff_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_dpdm_regulator_enable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	if (!motg->rm_pulldown) {
+		ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_3P3_ON);
+		if (!ret) {
+			motg->rm_pulldown = true;
+			msm_otg_dbg_log_event(&motg->phy, "RM Pulldown",
+					motg->rm_pulldown, 0);
+		}
+	}
+
+	return ret;
+}
+
+static int msm_otg_dpdm_regulator_disable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	if (motg->rm_pulldown) {
+		ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_3P3_OFF);
+		if (!ret) {
+			motg->rm_pulldown = false;
+			msm_otg_dbg_log_event(&motg->phy, "RM Pulldown",
+					motg->rm_pulldown, 0);
+		}
+	}
+
+	return ret;
+}
+
+static int msm_otg_dpdm_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	return motg->rm_pulldown;
+}
+
+static struct regulator_ops msm_otg_dpdm_regulator_ops = {
+	.enable		= msm_otg_dpdm_regulator_enable,
+	.disable	= msm_otg_dpdm_regulator_disable,
+	.is_enabled	= msm_otg_dpdm_regulator_is_enabled,
+};
+
+static int usb_phy_regulator_init(struct msm_otg *motg)
+{
+	struct device *dev = motg->phy.dev;
+	struct regulator_config cfg = {};
+	struct regulator_init_data *init_data;
+
+	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+	if (!init_data)
+		return -ENOMEM;
+
+	init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+	motg->dpdm_rdesc.owner = THIS_MODULE;
+	motg->dpdm_rdesc.type = REGULATOR_VOLTAGE;
+	motg->dpdm_rdesc.ops = &msm_otg_dpdm_regulator_ops;
+	motg->dpdm_rdesc.name = kbasename(dev->of_node->full_name);
+
+	cfg.dev = dev;
+	cfg.init_data = init_data;
+	cfg.driver_data = motg;
+	cfg.of_node = dev->of_node;
+
+	motg->dpdm_rdev = devm_regulator_register(dev, &motg->dpdm_rdesc, &cfg);
+	if (IS_ERR(motg->dpdm_rdev))
+		return PTR_ERR(motg->dpdm_rdev);
+
+	return 0;
+}
+
+const struct file_operations msm_otg_bus_fops = {
+	.open = msm_otg_bus_open,
+	.read = seq_read,
+	.write = msm_otg_bus_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct dentry *msm_otg_dbg_root;
+
+static int msm_otg_debugfs_init(struct msm_otg *motg)
+{
+	struct dentry *msm_otg_dentry;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
+
+	if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
+		return -ENODEV;
+
+	if ((pdata->mode == USB_OTG || pdata->mode == USB_PERIPHERAL) &&
+		pdata->otg_control == OTG_USER_CONTROL) {
+
+		msm_otg_dentry = debugfs_create_file("mode", 0644,
+			msm_otg_dbg_root, motg, &msm_otg_mode_fops);
+
+		if (!msm_otg_dentry) {
+			debugfs_remove(msm_otg_dbg_root);
+			msm_otg_dbg_root = NULL;
+			return -ENODEV;
+		}
+	}
+
+	msm_otg_dentry = debugfs_create_file("bus_voting", 0644,
+			msm_otg_dbg_root, motg, &msm_otg_bus_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+
+	msm_otg_dentry = debugfs_create_file("otg_state", 0444,
+			msm_otg_dbg_root, motg, &msm_otg_state_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+
+	msm_otg_dentry = debugfs_create_file("dbg_buff", 0444,
+			msm_otg_dbg_root, motg, &msm_otg_dbg_buff_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void msm_otg_debugfs_cleanup(void)
+{
+	debugfs_remove_recursive(msm_otg_dbg_root);
+}
+
+static ssize_t
+set_msm_otg_perf_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct msm_otg *motg = the_msm_otg;
+	int ret;
+	long clk_rate;
+
+	pr_debug("%s: enable:%d\n", __func__, !strncasecmp(buf, "enable", 6));
+
+	if (!strncasecmp(buf, "enable", 6)) {
+		clk_rate = motg->core_clk_nominal_rate;
+		msm_otg_bus_freq_set(motg, USB_NOC_NOM_VOTE);
+	} else {
+		clk_rate = motg->core_clk_svs_rate;
+		msm_otg_bus_freq_set(motg, USB_NOC_SVS_VOTE);
+	}
+
+	if (clk_rate) {
+		pr_debug("Set usb sys_clk rate:%ld\n", clk_rate);
+		ret = clk_set_rate(motg->core_clk, clk_rate);
+		if (ret)
+			pr_err("sys_clk set_rate fail:%d %ld\n", ret, clk_rate);
+		msm_otg_dbg_log_event(&motg->phy, "OTG PERF SET",
+							clk_rate, ret);
+	} else {
+		pr_err("usb sys_clk rate is undefined\n");
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(perf_mode, 0200, NULL, set_msm_otg_perf_mode);
+
+#define MSM_OTG_CMD_ID		0x09
+#define MSM_OTG_DEVICE_ID	0x04
+#define MSM_OTG_VMID_IDX	0xFF
+#define MSM_OTG_MEM_TYPE	0x02
+struct msm_otg_scm_cmd_buf {
+	unsigned int device_id;
+	unsigned int vmid_idx;
+	unsigned int mem_type;
+} __attribute__ ((__packed__));
+
+static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
+{
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct msm_otg_scm_cmd_buf cmd_buf;
+
+	if (!pdata->pnoc_errata_fix)
+		return;
+
+	dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
+
+	cmd_buf.device_id = MSM_OTG_DEVICE_ID;
+	cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
+	cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
+
+	ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
+				sizeof(cmd_buf), NULL, 0);
+
+	if (ret)
+		dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
+}
+
+static u64 msm_otg_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device *msm_otg_add_pdev(
+		struct platform_device *ofdev, const char *name)
+{
+	struct platform_device *pdev;
+	const struct resource *res = ofdev->resource;
+	unsigned int num = ofdev->num_resources;
+	int retval;
+	struct ci13xxx_platform_data ci_pdata;
+	struct msm_otg_platform_data *otg_pdata;
+	struct msm_otg *motg;
+
+	pdev = platform_device_alloc(name, -1);
+	if (!pdev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	pdev->dev.dma_mask = &msm_otg_dma_mask;
+	pdev->dev.parent = &ofdev->dev;
+
+	if (num) {
+		retval = platform_device_add_resources(pdev, res, num);
+		if (retval)
+			goto error;
+	}
+
+	if (!strcmp(name, "msm_hsusb")) {
+		otg_pdata =
+			(struct msm_otg_platform_data *)
+				ofdev->dev.platform_data;
+		motg = platform_get_drvdata(ofdev);
+		ci_pdata.log2_itc = otg_pdata->log2_itc;
+		ci_pdata.usb_core_id = 0;
+		ci_pdata.l1_supported = otg_pdata->l1_supported;
+		ci_pdata.enable_ahb2ahb_bypass =
+				otg_pdata->enable_ahb2ahb_bypass;
+		ci_pdata.enable_streaming = otg_pdata->enable_streaming;
+		ci_pdata.enable_axi_prefetch = otg_pdata->enable_axi_prefetch;
+		retval = platform_device_add_data(pdev, &ci_pdata,
+			sizeof(ci_pdata));
+		if (retval)
+			goto error;
+	}
+
+	arch_setup_dma_ops(&pdev->dev, 0, DMA_BIT_MASK(32), NULL, false);
+	retval = platform_device_add(pdev);
+	if (retval)
+		goto error;
+
+	return pdev;
+
+error:
+	platform_device_put(pdev);
+	return ERR_PTR(retval);
+}
+
+static int msm_otg_setup_devices(struct platform_device *ofdev,
+		enum usb_mode_type mode, bool init)
+{
+	const char *gadget_name = "msm_hsusb";
+	const char *host_name = "msm_hsusb_host";
+	static struct platform_device *gadget_pdev;
+	static struct platform_device *host_pdev;
+	int retval = 0;
+
+	if (!init) {
+		if (gadget_pdev) {
+			device_remove_file(&gadget_pdev->dev,
+					   &dev_attr_perf_mode);
+			platform_device_unregister(gadget_pdev);
+		}
+		if (host_pdev)
+			platform_device_unregister(host_pdev);
+		return 0;
+	}
+
+	switch (mode) {
+	case USB_OTG:
+		/* fall through */
+	case USB_PERIPHERAL:
+		gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
+		if (IS_ERR(gadget_pdev)) {
+			retval = PTR_ERR(gadget_pdev);
+			break;
+		}
+		if (device_create_file(&gadget_pdev->dev, &dev_attr_perf_mode))
+			dev_err(&gadget_pdev->dev, "perf_mode file failed\n");
+		if (mode == USB_PERIPHERAL)
+			break;
+		/* fall through */
+	case USB_HOST:
+		host_pdev = msm_otg_add_pdev(ofdev, host_name);
+		if (IS_ERR(host_pdev)) {
+			retval = PTR_ERR(host_pdev);
+			if (mode == USB_OTG) {
+				platform_device_unregister(gadget_pdev);
+				device_remove_file(&gadget_pdev->dev,
+						   &dev_attr_perf_mode);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+static ssize_t dpdm_pulldown_enable_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct msm_otg *motg = the_msm_otg;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", pdata->dpdm_pulldown_added ?
+							"enabled" : "disabled");
+}
+
+static ssize_t dpdm_pulldown_enable_store(struct device *dev,
+		struct device_attribute *attr, const char
+		*buf, size_t size)
+{
+	struct msm_otg *motg = the_msm_otg;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	if (!strncasecmp(buf, "enable", 6)) {
+		pdata->dpdm_pulldown_added = true;
+		return size;
+	} else if (!strncasecmp(buf, "disable", 7)) {
+		pdata->dpdm_pulldown_added = false;
+		return size;
+	}
+
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(dpdm_pulldown_enable, 0644,
+		dpdm_pulldown_enable_show, dpdm_pulldown_enable_store);
+
+static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
+				void *ptr)
+{
+	msm_otg_set_vbus_state(!!event);
+
+	return NOTIFY_DONE;
+}
+
+static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
+				void *ptr)
+{
+	struct msm_otg *motg = container_of(nb, struct msm_otg, id_nb);
+
+	if (event)
+		motg->id_state = USB_ID_GROUND;
+	else
+		motg->id_state = USB_ID_FLOAT;
+
+	msm_id_status_w(&motg->id_status_work.work);
+
+	return NOTIFY_DONE;
+}
+
+static int msm_otg_extcon_register(struct msm_otg *motg)
+{
+	struct device_node *node = motg->pdev->dev.of_node;
+	struct extcon_dev *edev;
+	int ret = 0;
+
+	if (!of_property_read_bool(node, "extcon"))
+		return 0;
+
+	edev = extcon_get_edev_by_phandle(&motg->pdev->dev, 0);
+	if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV)
+		return PTR_ERR(edev);
+
+	if (!IS_ERR(edev)) {
+		motg->extcon_vbus = edev;
+		motg->vbus_nb.notifier_call = msm_otg_vbus_notifier;
+		ret = extcon_register_notifier(edev, EXTCON_USB,
+							&motg->vbus_nb);
+		if (ret < 0) {
+			dev_err(&motg->pdev->dev, "failed to register notifier for USB\n");
+			return ret;
+		}
+	}
+
+	if (of_count_phandle_with_args(node, "extcon", NULL) > 1) {
+		edev = extcon_get_edev_by_phandle(&motg->pdev->dev, 1);
+		if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
+			ret = PTR_ERR(edev);
+			goto err;
+		}
+	}
+
+	if (!IS_ERR(edev)) {
+		motg->extcon_id = edev;
+		motg->id_nb.notifier_call = msm_otg_id_notifier;
+		ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+							&motg->id_nb);
+		if (ret < 0) {
+			dev_err(&motg->pdev->dev, "failed to register notifier for USB-HOST\n");
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	if (motg->extcon_vbus)
+		extcon_unregister_notifier(motg->extcon_vbus, EXTCON_USB,
+								&motg->vbus_nb);
+
+	return ret;
+}
+
+struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_otg_platform_data *pdata;
+	int len = 0;
+	int res_gpio;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	len = of_property_count_elems_of_size(node,
+			"qcom,hsusb-otg-phy-init-seq", sizeof(len));
+	if (len > 0) {
+		pdata->phy_init_seq = devm_kzalloc(&pdev->dev,
+						len * sizeof(len), GFP_KERNEL);
+		if (!pdata->phy_init_seq)
+			return NULL;
+		of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
+				pdata->phy_init_seq, len);
+	}
+	of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
+				&pdata->power_budget);
+	of_property_read_u32(node, "qcom,hsusb-otg-mode",
+				&pdata->mode);
+	of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
+				&pdata->otg_control);
+	of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
+				&pdata->default_mode);
+	of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
+				&pdata->phy_type);
+	pdata->disable_reset_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-disable-reset");
+	pdata->pnoc_errata_fix = of_property_read_bool(node,
+				"qcom,hsusb-otg-pnoc-errata-fix");
+	pdata->enable_lpm_on_dev_suspend = of_property_read_bool(node,
+				"qcom,hsusb-otg-lpm-on-dev-suspend");
+	pdata->core_clk_always_on_workaround = of_property_read_bool(node,
+				"qcom,hsusb-otg-clk-always-on-workaround");
+	pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-delay-lpm");
+	pdata->dp_manual_pullup = of_property_read_bool(node,
+				"qcom,dp-manual-pullup");
+	pdata->enable_sec_phy = of_property_read_bool(node,
+					"qcom,usb2-enable-hsphy2");
+	of_property_read_u32(node, "qcom,hsusb-log2-itc",
+				&pdata->log2_itc);
+
+	pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
+	if (pdata->pmic_id_irq < 0)
+		pdata->pmic_id_irq = 0;
+
+	pdata->hub_reset_gpio = of_get_named_gpio(
+			node, "qcom,hub-reset-gpio", 0);
+	if (!gpio_is_valid(pdata->hub_reset_gpio))
+		pr_debug("hub_reset_gpio is not available\n");
+
+	pdata->usbeth_reset_gpio = of_get_named_gpio(
+			node, "qcom,usbeth-reset-gpio", 0);
+	if (!gpio_is_valid(pdata->usbeth_reset_gpio))
+		pr_debug("usbeth_reset_gpio is not available\n");
+
+	pdata->switch_sel_gpio =
+			of_get_named_gpio(node, "qcom,sw-sel-gpio", 0);
+	if (!gpio_is_valid(pdata->switch_sel_gpio))
+		pr_debug("switch_sel_gpio is not available\n");
+
+	pdata->usb_id_gpio =
+			of_get_named_gpio(node, "qcom,usbid-gpio", 0);
+	if (!gpio_is_valid(pdata->usb_id_gpio))
+		pr_debug("usb_id_gpio is not available\n");
+
+	pdata->l1_supported = of_property_read_bool(node,
+				"qcom,hsusb-l1-supported");
+	pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+				"qcom,ahb-async-bridge-bypass");
+	pdata->disable_retention_with_vdd_min = of_property_read_bool(node,
+				"qcom,disable-retention-with-vdd-min");
+	pdata->enable_phy_id_pullup = of_property_read_bool(node,
+				"qcom,enable-phy-id-pullup");
+	pdata->phy_dvdd_always_on = of_property_read_bool(node,
+				"qcom,phy-dvdd-always-on");
+
+	res_gpio = of_get_named_gpio(node, "qcom,hsusb-otg-vddmin-gpio", 0);
+	if (!gpio_is_valid(res_gpio))
+		res_gpio = 0;
+	pdata->vddmin_gpio = res_gpio;
+
+	pdata->emulation = of_property_read_bool(node,
+						"qcom,emulation");
+
+	pdata->enable_streaming = of_property_read_bool(node,
+					"qcom,boost-sysclk-with-streaming");
+
+	pdata->enable_axi_prefetch = of_property_read_bool(node,
+						"qcom,axi-prefetch-enable");
+
+	pdata->vbus_low_as_hostmode = of_property_read_bool(node,
+					"qcom,vbus-low-as-hostmode");
+	return pdata;
+}
+
+static int msm_otg_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int len = 0;
+	u32 tmp[3];
+	struct resource *res;
+	struct msm_otg *motg;
+	struct usb_phy *phy;
+	struct msm_otg_platform_data *pdata;
+	void __iomem *tcsr;
+	int id_irq = 0;
+
+	dev_info(&pdev->dev, "msm_otg probe\n");
+
+	motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+	if (!motg) {
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	/*
+	 * USB Core is running its protocol engine based on CORE CLK,
+	 * CORE CLK  must be running at >55Mhz for correct HSUSB
+	 * operation and USB core cannot tolerate frequency changes on
+	 * CORE CLK. For such USB cores, vote for maximum clk frequency
+	 * on pclk source
+	 */
+	motg->core_clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(motg->core_clk)) {
+		ret = PTR_ERR(motg->core_clk);
+		motg->core_clk = NULL;
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to get core_clk\n");
+		goto free_motg;
+	}
+
+	motg->core_reset = devm_reset_control_get(&pdev->dev, "core_reset");
+	if (IS_ERR(motg->core_reset)) {
+		dev_err(&pdev->dev, "failed to get core_reset\n");
+		ret = PTR_ERR(motg->core_reset);
+		goto put_core_clk;
+	}
+
+	/*
+	 * USB Core CLK can run at max freq if streaming is enabled. Hence,
+	 * get Max supported clk frequency for USB Core CLK and request to set
+	 * the same. Otherwise set USB Core CLK to defined default value.
+	 */
+	if (of_property_read_u32(pdev->dev.of_node,
+					"qcom,max-nominal-sysclk-rate", &ret)) {
+		ret = -EINVAL;
+		goto put_core_clk;
+	} else {
+		motg->core_clk_nominal_rate = clk_round_rate(motg->core_clk,
+							     ret);
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node,
+					"qcom,max-svs-sysclk-rate", &ret)) {
+		dev_dbg(&pdev->dev, "core_clk svs freq not specified\n");
+	} else {
+		motg->core_clk_svs_rate = clk_round_rate(motg->core_clk, ret);
+	}
+
+	motg->default_noc_mode = USB_NOC_NOM_VOTE;
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,default-mode-svs")) {
+		motg->core_clk_rate = motg->core_clk_svs_rate;
+		motg->default_noc_mode = USB_NOC_SVS_VOTE;
+	} else if (of_property_read_bool(pdev->dev.of_node,
+					"qcom,boost-sysclk-with-streaming")) {
+		motg->core_clk_rate = motg->core_clk_nominal_rate;
+	} else {
+		motg->core_clk_rate = clk_round_rate(motg->core_clk,
+						USB_DEFAULT_SYSTEM_CLOCK);
+	}
+
+	if (IS_ERR_VALUE(motg->core_clk_rate)) {
+		dev_err(&pdev->dev, "fail to get core clk max freq.\n");
+	} else {
+		ret = clk_set_rate(motg->core_clk, motg->core_clk_rate);
+		if (ret)
+			dev_err(&pdev->dev, "fail to set core_clk freq:%d\n",
+									ret);
+	}
+
+	motg->pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(motg->pclk)) {
+		ret = PTR_ERR(motg->pclk);
+		motg->pclk = NULL;
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to get iface_clk\n");
+		goto put_core_clk;
+	}
+
+	motg->xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(motg->xo_clk)) {
+		ret = PTR_ERR(motg->xo_clk);
+		motg->xo_clk = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto put_pclk;
+	}
+
+	/*
+	 * On few platforms USB PHY is fed with sleep clk.
+	 * Hence don't fail probe.
+	 */
+	motg->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (IS_ERR(motg->sleep_clk)) {
+		ret = PTR_ERR(motg->sleep_clk);
+		motg->sleep_clk = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto put_xo_clk;
+		else
+			dev_dbg(&pdev->dev, "failed to get sleep_clk\n");
+	} else {
+		ret = clk_prepare_enable(motg->sleep_clk);
+		if (ret) {
+			dev_err(&pdev->dev, "%s failed to vote sleep_clk%d\n",
+						__func__, ret);
+			goto put_xo_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_reset_clk is used to reset the PHY, ULPI bridge
+	 * and CSR Wrapper. This is a reset only clock.
+	 */
+
+	if (of_property_match_string(pdev->dev.of_node,
+			"clock-names", "phy_reset_clk") >= 0) {
+		motg->phy_reset_clk = devm_clk_get(&pdev->dev, "phy_reset_clk");
+		if (IS_ERR(motg->phy_reset_clk)) {
+			ret = PTR_ERR(motg->phy_reset_clk);
+			goto disable_sleep_clk;
+		}
+
+		motg->phy_reset = devm_reset_control_get(&pdev->dev,
+								"phy_reset");
+		if (IS_ERR(motg->phy_reset)) {
+			dev_err(&pdev->dev, "failed to get phy_reset\n");
+			ret = PTR_ERR(motg->phy_reset);
+			goto disable_sleep_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_por_clk is used to assert/de-assert phy POR
+	 * input. This is a reset only clock. phy POR must be asserted
+	 * after overriding the parameter registers via CSR wrapper or
+	 * ULPI bridge.
+	 */
+	if (of_property_match_string(pdev->dev.of_node,
+				"clock-names", "phy_por_clk") >= 0) {
+		motg->phy_por_clk = devm_clk_get(&pdev->dev, "phy_por_clk");
+		if (IS_ERR(motg->phy_por_clk)) {
+			ret = PTR_ERR(motg->phy_por_clk);
+			goto disable_sleep_clk;
+		}
+
+		motg->phy_por_reset = devm_reset_control_get(&pdev->dev,
+							"phy_por_reset");
+		if (IS_ERR(motg->phy_por_reset)) {
+			dev_err(&pdev->dev, "failed to get phy_por_reset\n");
+			ret = PTR_ERR(motg->phy_por_reset);
+			goto disable_sleep_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_csr_clk is required for accessing PHY
+	 * CSR registers via AHB2PHY interface.
+	 */
+	if (of_property_match_string(pdev->dev.of_node,
+				"clock-names", "phy_csr_clk") >= 0) {
+		motg->phy_csr_clk = devm_clk_get(&pdev->dev, "phy_csr_clk");
+		if (IS_ERR(motg->phy_csr_clk)) {
+			ret = PTR_ERR(motg->phy_csr_clk);
+			goto disable_sleep_clk;
+		} else {
+			ret = clk_prepare_enable(motg->phy_csr_clk);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"fail to enable phy csr clk %d\n", ret);
+				goto disable_sleep_clk;
+			}
+		}
+	}
+
+	of_property_read_u32(pdev->dev.of_node, "qcom,pm-qos-latency",
+				&motg->pm_qos_latency);
+
+	pdata = msm_otg_dt_to_pdata(pdev);
+	if (!pdata) {
+		ret = -ENOMEM;
+		goto disable_phy_csr_clk;
+	}
+	pdev->dev.platform_data = pdata;
+
+	pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+	if (!pdata->bus_scale_table)
+		dev_dbg(&pdev->dev, "bus scaling is disabled\n");
+
+	if (pdata->phy_type == QUSB_ULPI_PHY) {
+		if (of_property_match_string(pdev->dev.of_node,
+					"clock-names", "phy_ref_clk") >= 0) {
+			motg->phy_ref_clk = devm_clk_get(&pdev->dev,
+						"phy_ref_clk");
+			if (IS_ERR(motg->phy_ref_clk)) {
+				ret = PTR_ERR(motg->phy_ref_clk);
+				goto disable_phy_csr_clk;
+			} else {
+				ret = clk_prepare_enable(motg->phy_ref_clk);
+				if (ret) {
+					dev_err(&pdev->dev,
+						"fail to enable phy ref clk %d\n",
+						ret);
+					goto disable_phy_csr_clk;
+				}
+			}
+		}
+	}
+
+	motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
+							GFP_KERNEL);
+	if (!motg->phy.otg) {
+		ret = -ENOMEM;
+		goto disable_phy_csr_clk;
+	}
+
+	the_msm_otg = motg;
+	motg->pdata = pdata;
+	phy = &motg->phy;
+	phy->dev = &pdev->dev;
+	motg->pdev = pdev;
+	motg->dbg_idx = 0;
+	motg->dbg_lock = __RW_LOCK_UNLOCKED(lck);
+
+	if (motg->pdata->bus_scale_table) {
+		motg->bus_perf_client =
+		    msm_bus_scale_register_client(motg->pdata->bus_scale_table);
+		if (!motg->bus_perf_client) {
+			dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
+						"scaling client!!\n", __func__);
+		} else {
+			debug_bus_voting_enabled = true;
+			/* Some platforms require BUS vote to control clocks */
+			msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+		}
+	}
+
+	ret = msm_otg_bus_freq_get(motg);
+	if (ret) {
+		pr_err("failed to get noc clocks: %d\n", ret);
+	} else {
+		ret = msm_otg_bus_freq_set(motg, motg->default_noc_mode);
+		if (ret)
+			pr_err("failed to vote explicit noc rates: %d\n", ret);
+	}
+
+	/* initialize reset counter */
+	motg->reset_counter = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get core iomem resource\n");
+		ret = -ENODEV;
+		goto devote_bus_bw;
+	}
+
+	motg->io_res = res;
+	motg->regs = ioremap(res->start, resource_size(res));
+	if (!motg->regs) {
+		dev_err(&pdev->dev, "core iomem ioremap failed\n");
+		ret = -ENOMEM;
+		goto devote_bus_bw;
+	}
+	dev_info(&pdev->dev, "OTG regs = %pK\n", motg->regs);
+
+	if (pdata->enable_sec_phy) {
+		res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tcsr");
+		if (!res) {
+			dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
+		} else {
+			tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
+				resource_size(res));
+			if (!tcsr) {
+				dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
+			} else {
+				/* Enable USB2 on secondary HSPHY. */
+				writel_relaxed(0x1, tcsr);
+				/*
+				 * Ensure that TCSR write is completed before
+				 * USB registers initialization.
+				 */
+				mb();
+			}
+		}
+	}
+
+	if (pdata->enable_sec_phy)
+		motg->usb_phy_ctrl_reg = USB_PHY_CTRL2;
+	else
+		motg->usb_phy_ctrl_reg = USB_PHY_CTRL;
+
+	/*
+	 * The USB PHY wrapper provides a register interface
+	 * through AHB2PHY for performing PHY related operations
+	 * like retention, HV interrupts and overriding parameter
+	 * registers etc. The registers start at 4 byte boundary
+	 * but only the first byte is valid and remaining are not
+	 * used. Relaxed versions of readl/writel should be used.
+	 *
+	 * The link does not have any PHY specific registers.
+	 * Hence set motg->usb_phy_ctrl_reg to.
+	 */
+	if (motg->pdata->phy_type == SNPS_FEMTO_PHY ||
+		pdata->phy_type == QUSB_ULPI_PHY) {
+		res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "phy_csr");
+		if (!res) {
+			dev_err(&pdev->dev, "PHY CSR IOMEM missing!\n");
+			ret = -ENODEV;
+			goto free_regs;
+		}
+		motg->phy_csr_regs = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(motg->phy_csr_regs)) {
+			ret = PTR_ERR(motg->phy_csr_regs);
+			dev_err(&pdev->dev, "PHY CSR ioremap failed!\n");
+			goto free_regs;
+		}
+		motg->usb_phy_ctrl_reg = 0;
+	}
+
+	motg->irq = platform_get_irq(pdev, 0);
+	if (!motg->irq) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		ret = -ENODEV;
+		goto free_regs;
+	}
+
+	motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+	if (motg->async_irq < 0) {
+		dev_err(&pdev->dev, "platform_get_irq for async_int failed\n");
+		motg->async_irq = 0;
+		goto free_regs;
+	}
+
+	if (motg->xo_clk) {
+		ret = clk_prepare_enable(motg->xo_clk);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s failed to vote for TCXO %d\n",
+					__func__, ret);
+			goto free_xo_handle;
+		}
+	}
+
+
+	clk_prepare_enable(motg->pclk);
+
+	hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
+	if (IS_ERR(hsusb_vdd)) {
+		hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
+		if (IS_ERR(hsusb_vdd)) {
+			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
+			ret = PTR_ERR(hsusb_vdd);
+			goto devote_xo_handle;
+		}
+	}
+
+	len = of_property_count_elems_of_size(pdev->dev.of_node,
+			"qcom,vdd-voltage-level", sizeof(len));
+	if (len > 0) {
+		if (len == sizeof(tmp) / sizeof(len)) {
+			of_property_read_u32_array(pdev->dev.of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len);
+			vdd_val[0] = tmp[0];
+			vdd_val[1] = tmp[1];
+			vdd_val[2] = tmp[2];
+		} else {
+			dev_dbg(&pdev->dev,
+				"Using default hsusb vdd config.\n");
+			goto devote_xo_handle;
+		}
+	} else {
+		goto devote_xo_handle;
+	}
+
+	ret = msm_hsusb_config_vddcx(1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+		goto devote_xo_handle;
+	}
+
+	ret = regulator_enable(hsusb_vdd);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
+		goto free_config_vddcx;
+	}
+
+	ret = msm_hsusb_ldo_init(motg, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+		goto free_hsusb_vdd;
+	}
+
+	/* Get pinctrl if target uses pinctrl */
+	motg->phy_pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(motg->phy_pinctrl)) {
+		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+			ret = PTR_ERR(motg->phy_pinctrl);
+			goto free_ldo_init;
+		}
+		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+		motg->phy_pinctrl = NULL;
+	}
+
+	ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+		goto free_ldo_init;
+	}
+	clk_prepare_enable(motg->core_clk);
+
+	/* Check if USB mem_type change is needed to workaround PNOC hw issue */
+	msm_otg_pnoc_errata_fix(motg);
+
+	writel_relaxed(0, USB_USBINTR);
+	writel_relaxed(0, USB_OTGSC);
+	/* Ensure that above STOREs are completed before enabling interrupts */
+	mb();
+
+	motg->id_state = USB_ID_FLOAT;
+	set_bit(ID, &motg->inputs);
+	INIT_WORK(&motg->sm_work, msm_otg_sm_work);
+	INIT_DELAYED_WORK(&motg->id_status_work, msm_id_status_w);
+	INIT_DELAYED_WORK(&motg->perf_vote_work, msm_otg_perf_vote_work);
+	motg->otg_wq = alloc_ordered_workqueue("k_otg", 0);
+	if (!motg->otg_wq) {
+		pr_err("%s: Unable to create workqueue otg_wq\n",
+			__func__);
+		goto disable_core_clk;
+	}
+
+	ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,
+					"msm_otg", motg);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq failed\n");
+		goto destroy_wq;
+	}
+
+	motg->phy_irq = platform_get_irq_byname(pdev, "phy_irq");
+	if (motg->phy_irq < 0) {
+		dev_dbg(&pdev->dev, "phy_irq is not present\n");
+		motg->phy_irq = 0;
+	} else {
+
+		/* clear all interrupts before enabling the IRQ */
+		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR0);
+		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);
+
+		writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
+		/*
+		 * Databook says 200 usec delay is required for
+		 * clearing the interrupts.
+		 */
+		udelay(200);
+		writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);
+
+		ret = devm_request_irq(&pdev->dev, motg->phy_irq,
+			msm_otg_phy_irq_handler, IRQF_TRIGGER_RISING,
+			"msm_otg_phy_irq", motg);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "phy_irq request fail %d\n", ret);
+			goto destroy_wq;
+		}
+	}
+
+	ret = devm_request_irq(&pdev->dev, motg->async_irq, msm_otg_irq,
+				IRQF_TRIGGER_RISING, "msm_otg", motg);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+		goto destroy_wq;
+	}
+	disable_irq(motg->async_irq);
+
+	phy->init = msm_otg_reset;
+	phy->set_power = msm_otg_set_power;
+	phy->set_suspend = msm_otg_set_suspend;
+	phy->dbg_event = msm_otg_dbg_log_event;
+
+	phy->io_ops = &msm_otg_io_ops;
+
+	phy->otg->usb_phy = &motg->phy;
+	phy->otg->set_host = msm_otg_set_host;
+	phy->otg->set_peripheral = msm_otg_set_peripheral;
+	if (pdata->dp_manual_pullup)
+		phy->flags |= ENABLE_DP_MANUAL_PULLUP;
+
+	if (pdata->enable_sec_phy)
+		phy->flags |= ENABLE_SECONDARY_PHY;
+
+	ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
+	if (ret) {
+		dev_err(&pdev->dev, "usb_add_phy failed\n");
+		goto destroy_wq;
+	}
+
+	ret = usb_phy_regulator_init(motg);
+	if (ret) {
+		dev_err(&pdev->dev, "usb_phy_regulator_init failed\n");
+		goto remove_phy;
+	}
+
+	if (motg->pdata->mode == USB_OTG &&
+		motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+		!motg->phy_irq) {
+
+		if (gpio_is_valid(motg->pdata->usb_id_gpio)) {
+			/* usb_id_gpio request */
+			ret = devm_gpio_request(&pdev->dev,
+						motg->pdata->usb_id_gpio,
+						"USB_ID_GPIO");
+			if (ret < 0) {
+				dev_err(&pdev->dev, "gpio req failed for id\n");
+				goto phy_reg_deinit;
+			}
+
+			/*
+			 * The following code implements switch between the HOST
+			 * mode to device mode when used different HW components
+			 * on the same port: USB HUB and the usb jack type B
+			 * for device mode In this case HUB should be gone
+			 * only once out of reset at the boot time and after
+			 * that always stay on
+			 */
+			if (gpio_is_valid(motg->pdata->hub_reset_gpio)) {
+				ret = devm_gpio_request(&pdev->dev,
+						motg->pdata->hub_reset_gpio,
+						"qcom,hub-reset-gpio");
+				if (ret < 0) {
+					dev_err(&pdev->dev, "gpio req failed for hub reset\n");
+					goto phy_reg_deinit;
+				}
+				gpio_direction_output(
+					motg->pdata->hub_reset_gpio, 1);
+			}
+
+			if (gpio_is_valid(motg->pdata->switch_sel_gpio)) {
+				ret = devm_gpio_request(&pdev->dev,
+						motg->pdata->switch_sel_gpio,
+						"qcom,sw-sel-gpio");
+				if (ret < 0) {
+					dev_err(&pdev->dev, "gpio req failed for switch sel\n");
+					goto phy_reg_deinit;
+				}
+				if (gpio_get_value(motg->pdata->usb_id_gpio))
+					gpio_direction_input(
+						motg->pdata->switch_sel_gpio);
+
+				else
+					gpio_direction_output(
+					    motg->pdata->switch_sel_gpio,
+					    1);
+			}
+
+			/* usb_id_gpio to irq */
+			id_irq = gpio_to_irq(motg->pdata->usb_id_gpio);
+			motg->ext_id_irq = id_irq;
+		} else if (motg->pdata->pmic_id_irq) {
+			id_irq = motg->pdata->pmic_id_irq;
+		}
+
+		if (id_irq) {
+			ret = devm_request_irq(&pdev->dev, id_irq,
+					  msm_id_irq,
+					  IRQF_TRIGGER_RISING |
+					  IRQF_TRIGGER_FALLING,
+					  "msm_otg", motg);
+			if (ret) {
+				dev_err(&pdev->dev, "request irq failed for ID\n");
+				goto phy_reg_deinit;
+			}
+		} else {
+			/* PMIC does USB ID detection and notifies through
+			 * USB_OTG property of USB powersupply.
+			 */
+			dev_dbg(&pdev->dev, "PMIC does ID detection\n");
+		}
+	}
+
+	platform_set_drvdata(pdev, motg);
+	device_init_wakeup(&pdev->dev, 1);
+
+	ret = msm_otg_debugfs_init(motg);
+	if (ret)
+		dev_dbg(&pdev->dev, "mode debugfs file is not available\n");
+
+	if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+			(!(motg->pdata->mode == USB_OTG) ||
+			 motg->pdata->pmic_id_irq || motg->ext_id_irq ||
+								!motg->phy_irq))
+		motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq ||
+				motg->pdata->enable_phy_id_pullup)
+		motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM;
+
+	motg->caps |= ALLOW_HOST_PHY_RETENTION;
+
+	device_create_file(&pdev->dev, &dev_attr_dpdm_pulldown_enable);
+
+	if (motg->pdata->enable_lpm_on_dev_suspend)
+		motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+
+	if (motg->pdata->disable_retention_with_vdd_min)
+		motg->caps |= ALLOW_VDD_MIN_WITH_RETENTION_DISABLED;
+
+	/*
+	 * PHY DVDD is supplied by a always on PMIC LDO (unlike
+	 * vddcx/vddmx). PHY can keep D+ pull-up and D+/D-
+	 * pull-down during suspend without any additional
+	 * hardware re-work.
+	 */
+	if (motg->pdata->phy_type == SNPS_FEMTO_PHY)
+		motg->caps |= ALLOW_BUS_SUSPEND_WITHOUT_REWORK;
+
+	pm_stay_awake(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	if (motg->pdata->delay_lpm_on_disconnect) {
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+			lpm_disconnect_thresh);
+		pm_runtime_use_autosuspend(&pdev->dev);
+	}
+
+	if (pdev->dev.of_node) {
+		ret = msm_otg_setup_devices(pdev, pdata->mode, true);
+		if (ret) {
+			dev_err(&pdev->dev, "devices setup failed\n");
+			goto remove_cdev;
+		}
+	}
+
+	psy = power_supply_get_by_name("usb");
+	if (!psy) {
+		dev_dbg(&pdev->dev, "Could not get usb power_supply\n");
+		ret = -EPROBE_DEFER;
+		goto otg_remove_devices;
+	}
+
+
+	ret = msm_otg_extcon_register(motg);
+	if (ret)
+		goto put_psy;
+
+	if (motg->extcon_vbus && extcon_get_cable_state_(motg->extcon_vbus,
+							EXTCON_USB))
+		msm_otg_vbus_notifier(&motg->vbus_nb, true, motg->extcon_vbus);
+
+	if (motg->extcon_id && extcon_get_cable_state_(motg->extcon_id,
+							EXTCON_USB_HOST))
+		msm_otg_id_notifier(&motg->id_nb, true, motg->extcon_id);
+
+	if (gpio_is_valid(motg->pdata->hub_reset_gpio)) {
+		ret = devm_gpio_request(&pdev->dev,
+				motg->pdata->hub_reset_gpio,
+				"HUB_RESET");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio req failed for hub_reset\n");
+		} else {
+			gpio_direction_output(
+				motg->pdata->hub_reset_gpio, 0);
+			/* 5 microsecs reset signaling to usb hub */
+			usleep_range(5, 10);
+			gpio_direction_output(
+				motg->pdata->hub_reset_gpio, 1);
+		}
+	}
+
+	if (gpio_is_valid(motg->pdata->usbeth_reset_gpio)) {
+		ret = devm_gpio_request(&pdev->dev,
+				motg->pdata->usbeth_reset_gpio,
+				"ETH_RESET");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio req failed for usbeth_reset\n");
+		} else {
+			gpio_direction_output(
+				motg->pdata->usbeth_reset_gpio, 0);
+			/* 100 microsecs reset signaling to usb-to-eth */
+			usleep_range(100, 110);
+			gpio_direction_output(
+				motg->pdata->usbeth_reset_gpio, 1);
+		}
+	}
+
+	motg->pm_notify.notifier_call = msm_otg_pm_notify;
+	register_pm_notifier(&motg->pm_notify);
+	msm_otg_dbg_log_event(phy, "OTG PROBE", motg->caps, motg->lpm_flags);
+
+	return 0;
+
+put_psy:
+	if (psy)
+		power_supply_put(psy);
+otg_remove_devices:
+	if (pdev->dev.of_node)
+		msm_otg_setup_devices(pdev, motg->pdata->mode, false);
+remove_cdev:
+	pm_runtime_disable(&pdev->dev);
+	device_remove_file(&pdev->dev, &dev_attr_dpdm_pulldown_enable);
+	msm_otg_debugfs_cleanup();
+phy_reg_deinit:
+	devm_regulator_unregister(motg->phy.dev, motg->dpdm_rdev);
+remove_phy:
+	usb_remove_phy(&motg->phy);
+destroy_wq:
+	destroy_workqueue(motg->otg_wq);
+disable_core_clk:
+	clk_disable_unprepare(motg->core_clk);
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+free_ldo_init:
+	msm_hsusb_ldo_init(motg, 0);
+free_hsusb_vdd:
+	regulator_disable(hsusb_vdd);
+free_config_vddcx:
+	regulator_set_voltage(hsusb_vdd,
+		vdd_val[VDD_NONE],
+		vdd_val[VDD_MAX]);
+devote_xo_handle:
+	clk_disable_unprepare(motg->pclk);
+	if (motg->xo_clk)
+		clk_disable_unprepare(motg->xo_clk);
+free_xo_handle:
+	if (motg->xo_clk) {
+		clk_put(motg->xo_clk);
+		motg->xo_clk = NULL;
+	}
+free_regs:
+	iounmap(motg->regs);
+devote_bus_bw:
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
+disable_phy_csr_clk:
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+disable_sleep_clk:
+	if (motg->sleep_clk)
+		clk_disable_unprepare(motg->sleep_clk);
+put_xo_clk:
+	if (motg->xo_clk)
+		clk_put(motg->xo_clk);
+put_pclk:
+	if (motg->pclk)
+		clk_put(motg->pclk);
+put_core_clk:
+	if (motg->core_clk)
+		clk_put(motg->core_clk);
+free_motg:
+	kfree(motg);
+	return ret;
+}
+
+static int msm_otg_remove(struct platform_device *pdev)
+{
+	struct msm_otg *motg = platform_get_drvdata(pdev);
+	struct usb_phy *phy = &motg->phy;
+	int cnt = 0;
+
+	if (phy->otg->host || phy->otg->gadget)
+		return -EBUSY;
+
+	unregister_pm_notifier(&motg->pm_notify);
+
+	extcon_unregister_notifier(motg->extcon_id, EXTCON_USB_HOST,
+							&motg->id_nb);
+	extcon_unregister_notifier(motg->extcon_vbus, EXTCON_USB,
+							&motg->vbus_nb);
+
+	if (pdev->dev.of_node)
+		msm_otg_setup_devices(pdev, motg->pdata->mode, false);
+	if (psy)
+		power_supply_put(psy);
+	msm_otg_debugfs_cleanup();
+	cancel_delayed_work_sync(&motg->id_status_work);
+	cancel_delayed_work_sync(&motg->perf_vote_work);
+	msm_otg_perf_vote_update(motg, false);
+	cancel_work_sync(&motg->sm_work);
+	destroy_workqueue(motg->otg_wq);
+
+	pm_runtime_resume(&pdev->dev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	pm_runtime_disable(&pdev->dev);
+
+	usb_remove_phy(phy);
+
+	device_remove_file(&pdev->dev, &dev_attr_dpdm_pulldown_enable);
+
+	/*
+	 * Put PHY in low power mode.
+	 */
+	ulpi_read(phy, 0x14);
+	ulpi_write(phy, 0x08, 0x09);
+
+	writel_relaxed(readl_relaxed(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+		if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+			break;
+		udelay(1);
+		cnt++;
+	}
+	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
+		dev_err(phy->dev, "Unable to suspend PHY\n");
+
+	clk_disable_unprepare(motg->pclk);
+	clk_disable_unprepare(motg->core_clk);
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+	if (motg->xo_clk) {
+		clk_disable_unprepare(motg->xo_clk);
+		clk_put(motg->xo_clk);
+	}
+
+	if (!IS_ERR(motg->sleep_clk))
+		clk_disable_unprepare(motg->sleep_clk);
+
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+	msm_hsusb_ldo_init(motg, 0);
+	regulator_disable(hsusb_vdd);
+	regulator_set_voltage(hsusb_vdd,
+		vdd_val[VDD_NONE],
+		vdd_val[VDD_MAX]);
+
+	iounmap(motg->regs);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	clk_put(motg->pclk);
+	clk_put(motg->core_clk);
+
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
+
+	return 0;
+}
+
+static void msm_otg_shutdown(struct platform_device *pdev)
+{
+	struct msm_otg *motg = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "OTG shutdown\n");
+	msm_hsusb_vbus_power(motg, 0);
+}
+
+#ifdef CONFIG_PM
+static int msm_otg_runtime_idle(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+	struct usb_phy *phy = &motg->phy;
+
+	dev_dbg(dev, "OTG runtime idle\n");
+	msm_otg_dbg_log_event(phy, "RUNTIME IDLE", phy->otg->state, 0);
+
+	if (phy->otg->state == OTG_STATE_UNDEFINED)
+		return -EAGAIN;
+
+	return 0;
+}
+
+static int msm_otg_runtime_suspend(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG runtime suspend\n");
+	msm_otg_dbg_log_event(&motg->phy, "RUNTIME SUSPEND",
+			get_pm_runtime_counter(dev), 0);
+	return msm_otg_suspend(motg);
+}
+
+static int msm_otg_runtime_resume(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG runtime resume\n");
+	msm_otg_dbg_log_event(&motg->phy, "RUNTIME RESUME",
+			get_pm_runtime_counter(dev), 0);
+
+	return msm_otg_resume(motg);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_pm_suspend(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG PM suspend\n");
+	msm_otg_dbg_log_event(&motg->phy, "PM SUSPEND START",
+			get_pm_runtime_counter(dev),
+			atomic_read(&motg->pm_suspended));
+
+	/* flush any pending sm_work first */
+	flush_work(&motg->sm_work);
+	if (!atomic_read(&motg->in_lpm)) {
+		dev_err(dev, "Abort PM suspend!! (USB is outside LPM)\n");
+		return -EBUSY;
+	}
+	atomic_set(&motg->pm_suspended, 1);
+
+	return 0;
+}
+
+static int msm_otg_pm_resume(struct device *dev)
+{
+	int ret = 0;
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG PM resume\n");
+	msm_otg_dbg_log_event(&motg->phy, "PM RESUME START",
+			get_pm_runtime_counter(dev), pm_runtime_suspended(dev));
+
+	if (motg->resume_pending || motg->phy_irq_pending) {
+		msm_otg_dbg_log_event(&motg->phy, "PM RESUME BY USB",
+				motg->async_int, motg->resume_pending);
+		/* sm work if pending will start in pm notify to exit LPM */
+	}
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops msm_otg_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
+	SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
+				msm_otg_runtime_idle)
+};
+#endif
+
+static const struct of_device_id msm_otg_dt_match[] = {
+	{	.compatible = "qcom,hsusb-otg",
+	},
+	{}
+};
+
+static struct platform_driver msm_otg_driver = {
+	.probe = msm_otg_probe,
+	.remove = msm_otg_remove,
+	.shutdown = msm_otg_shutdown,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &msm_otg_dev_pm_ops,
+#endif
+		.of_match_table = msm_otg_dt_match,
+	},
+};
+
+module_platform_driver(msm_otg_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM USB transceiver driver");
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..584ae8c 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -63,6 +63,7 @@
 		- Google USB serial devices
 		- HP4x calculators
 		- a number of Motorola phones
+		- Motorola Tetra devices
 		- Novatel Wireless GPS receivers
 		- Siemens USB/MPI adapter.
 		- ViVOtech ViVOpay USB device.
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 464db17..de61271 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2215,7 +2215,6 @@
 		/* something went wrong */
 		dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n",
 			__func__, status);
-		usb_kill_urb(urb);
 		usb_free_urb(urb);
 		atomic_dec(&CmdUrbs);
 		return status;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a818c43..1799aa0 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -383,6 +383,9 @@
 #define FOUR_G_SYSTEMS_PRODUCT_W14		0x9603
 #define FOUR_G_SYSTEMS_PRODUCT_W100		0x9b01
 
+/* Fujisoft products */
+#define FUJISOFT_PRODUCT_FS040U			0x9b02
+
 /* iBall 3.5G connect wireless modem */
 #define IBALL_3_5G_CONNECT			0x9605
 
@@ -1897,6 +1900,8 @@
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
 	  .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
 	},
+	{USB_DEVICE(LONGCHEER_VENDOR_ID, FUJISOFT_PRODUCT_FS040U),
+	 .driver_info = (kernel_ulong_t)&net_intf3_blacklist},
 	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
 	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff),
 	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index a51b283..3da25ad 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -39,6 +39,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 3b5a15d..1232890 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -17,6 +17,7 @@
 #define PL2303_PRODUCT_ID_DCU11		0x1234
 #define PL2303_PRODUCT_ID_PHAROS	0xaaa0
 #define PL2303_PRODUCT_ID_RSAQ3		0xaaa2
+#define PL2303_PRODUCT_ID_CHILITAG	0xaaa8
 #define PL2303_PRODUCT_ID_ALDIGA	0x0611
 #define PL2303_PRODUCT_ID_MMX		0x0612
 #define PL2303_PRODUCT_ID_GPRS		0x0609
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index e98b6e5..6aa7ff2 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -80,6 +80,11 @@
 	{ USB_DEVICE(0x22b8, 0x2c64) }	/* Motorola V950 phone */
 DEVICE(moto_modem, MOTO_IDS);
 
+/* Motorola Tetra driver */
+#define MOTOROLA_TETRA_IDS()			\
+	{ USB_DEVICE(0x0cad, 0x9011) }	/* Motorola Solutions TETRA PEI */
+DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
+
 /* Novatel Wireless GPS driver */
 #define NOVATEL_IDS()			\
 	{ USB_DEVICE(0x09d7, 0x0100) }	/* NovAtel FlexPack GPS */
@@ -110,6 +115,7 @@
 	&google_device,
 	&vivopay_device,
 	&moto_modem_device,
+	&motorola_tetra_device,
 	&novatel_gps_device,
 	&hp4x_device,
 	&suunto_device,
@@ -125,6 +131,7 @@
 	GOOGLE_IDS(),
 	VIVOPAY_IDS(),
 	MOTO_IDS(),
+	MOTOROLA_TETRA_IDS(),
 	NOVATEL_IDS(),
 	HP4X_IDS(),
 	SUUNTO_IDS(),
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 9876af4..6891e90 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -1076,20 +1076,19 @@
 		return 0;
 
 	err = uas_configure_endpoints(devinfo);
-	if (err) {
+	if (err && err != ENODEV)
 		shost_printk(KERN_ERR, shost,
 			     "%s: alloc streams error %d after reset",
 			     __func__, err);
-		return 1;
-	}
 
+	/* we must unblock the host in every case lest we deadlock */
 	spin_lock_irqsave(shost->host_lock, flags);
 	scsi_report_bus_reset(shost, 0);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	scsi_unblock_requests(shost);
 
-	return 0;
+	return err ? 1 : 0;
 }
 
 static int uas_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 9f49037..f0b955f 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -271,6 +271,7 @@
 	/* lock for status */
 	spinlock_t lock;
 
+	int sockfd;
 	struct socket *tcp_socket;
 
 	struct task_struct *tcp_rx;
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 7f161b0..dbe615b 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -300,7 +300,7 @@
 		case USB_PORT_FEAT_POWER:
 			usbip_dbg_vhci_rh(
 				" ClearPortFeature: USB_PORT_FEAT_POWER\n");
-			dum->port_status[rhport] = 0;
+			dum->port_status[rhport] &= ~USB_PORT_STAT_POWER;
 			dum->resuming = 0;
 			break;
 		case USB_PORT_FEAT_C_RESET:
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index c404017..c287ccc 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -49,13 +49,17 @@
 
 	/*
 	 * output example:
-	 * port sta spd dev      socket           local_busid
-	 * 0000 004 000 00000000         c5a7bb80 1-2.3
-	 * 0001 004 000 00000000         d8cee980 2-3.4
+	 * port sta spd dev      sockfd local_busid
+	 * 0000 004 000 00000000 000003 1-2.3
+	 * 0001 004 000 00000000 000004 2-3.4
 	 *
-	 * IP address can be retrieved from a socket pointer address by looking
-	 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-	 * port number and its peer IP address.
+	 * Output includes socket fd instead of socket pointer address to
+	 * avoid leaking kernel memory address in:
+	 *	/sys/devices/platform/vhci_hcd.0/status and in debug output.
+	 * The socket pointer address is not used at the moment and it was
+	 * made visible as a convenient way to find IP address from socket
+	 * pointer address by looking up /proc/net/{tcp,tcp6}. As this opens
+	 * a security hole, the change is made to use sockfd instead.
 	 */
 	for (i = 0; i < VHCI_HC_PORTS; i++) {
 		struct vhci_device *vdev = &vhci->vdev[i];
@@ -68,13 +72,13 @@
 		if (vdev->ud.status == VDEV_ST_USED) {
 			out += sprintf(out, "%03u %08x ",
 					    vdev->speed, vdev->devid);
-			out += sprintf(out, "%16p %s",
-					    vdev->ud.tcp_socket,
+			out += sprintf(out, "%06u %s",
+					    vdev->ud.sockfd,
 					    dev_name(&vdev->udev->dev));
 
 		} else {
 			out += sprintf(out, "000 00000000 ");
-			out += sprintf(out, "0000000000000000 0-0");
+			out += sprintf(out, "000000 0-0");
 		}
 
 		out += sprintf(out, "\n");
@@ -125,7 +129,7 @@
 	int pdev_nr;
 
 	out += sprintf(out,
-		       "port sta spd dev      socket           local_busid\n");
+		       "port sta spd dev      sockfd local_busid\n");
 
 	pdev_nr = status_name_to_id(attr->attr.name);
 	if (pdev_nr < 0)
@@ -324,6 +328,7 @@
 
 	vdev->devid         = devid;
 	vdev->speed         = speed;
+	vdev->ud.sockfd     = sockfd;
 	vdev->ud.tcp_socket = socket;
 	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
@@ -361,6 +366,7 @@
 	status->attr.attr.name = status->name;
 	status->attr.attr.mode = S_IRUGO;
 	status->attr.show = status_show;
+	sysfs_attr_init(&status->attr.attr);
 }
 
 static int init_status_attrs(void)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 96a0661..e5b7652 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1078,6 +1078,7 @@
 	}
 	vhost_net_stop(n, &tx_sock, &rx_sock);
 	vhost_net_flush(n);
+	vhost_dev_stop(&n->dev);
 	vhost_dev_reset_owner(&n->dev, umem);
 	vhost_net_vq_reset(n);
 done:
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 5d3b0db..1809e66 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2328,6 +2328,19 @@
 	  Select this option if display contents should be inherited as set by
 	  the bootloader.
 
+config FB_MSM
+	tristate "MSM Framebuffer support"
+	depends on FB && ARCH_QCOM
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select SYNC_FILE
+	---help---
+	  The MSM driver implements a frame buffer interface to
+	  provide access to the display hardware and provide
+	  a way for users to display graphics
+	  on connected display panels.
+
 config FB_MX3
 	tristate "MX3 Framebuffer support"
 	depends on FB && MX3_IPU
@@ -2448,6 +2461,7 @@
 source "drivers/video/fbdev/omap/Kconfig"
 source "drivers/video/fbdev/omap2/Kconfig"
 source "drivers/video/fbdev/mmp/Kconfig"
+source "drivers/video/fbdev/msm/Kconfig"
 
 config FB_SH_MOBILE_MERAM
 	tristate "SuperH Mobile MERAM read ahead support"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index ee8c814..c16b198 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -130,6 +130,11 @@
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
 
+ifeq ($(CONFIG_FB_MSM),y)
+obj-y                             += msm/
+else
+obj-$(CONFIG_MSM_DBA)             += msm/msm_dba/
+endif
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index f8a3839..2ef33d4 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1085,7 +1085,7 @@
 EXPORT_SYMBOL(fb_blank);
 
 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
-			unsigned long arg)
+			unsigned long arg, struct file *file)
 {
 	struct fb_ops *fb;
 	struct fb_var_screeninfo var;
@@ -1222,7 +1222,9 @@
 		if (!lock_fb_info(info))
 			return -ENODEV;
 		fb = info->fbops;
-		if (fb->fb_ioctl)
+		if (fb->fb_ioctl_v2)
+			ret = fb->fb_ioctl_v2(info, cmd, arg, file);
+		else if (fb->fb_ioctl)
 			ret = fb->fb_ioctl(info, cmd, arg);
 		else
 			ret = -ENOTTY;
@@ -1237,7 +1239,7 @@
 
 	if (!info)
 		return -ENODEV;
-	return do_fb_ioctl(info, cmd, arg);
+	return do_fb_ioctl(info, cmd, arg, file);
 }
 
 #ifdef CONFIG_COMPAT
@@ -1268,7 +1270,7 @@
 };
 
 static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
-			  unsigned long arg)
+			  unsigned long arg, struct file *file)
 {
 	struct fb_cmap_user __user *cmap;
 	struct fb_cmap32 __user *cmap32;
@@ -1291,7 +1293,7 @@
 	    put_user(compat_ptr(data), &cmap->transp))
 		return -EFAULT;
 
-	err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
+	err = do_fb_ioctl(info, cmd, (unsigned long) cmap, file);
 
 	if (!err) {
 		if (copy_in_user(&cmap32->start,
@@ -1336,7 +1338,7 @@
 }
 
 static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
-			      unsigned long arg)
+			      unsigned long arg, struct file *file)
 {
 	mm_segment_t old_fs;
 	struct fb_fix_screeninfo fix;
@@ -1347,7 +1349,7 @@
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
+	err = do_fb_ioctl(info, cmd, (unsigned long) &fix, file);
 	set_fs(old_fs);
 
 	if (!err)
@@ -1374,20 +1376,22 @@
 	case FBIOPUT_CON2FBMAP:
 		arg = (unsigned long) compat_ptr(arg);
 	case FBIOBLANK:
-		ret = do_fb_ioctl(info, cmd, arg);
+		ret = do_fb_ioctl(info, cmd, arg, file);
 		break;
 
 	case FBIOGET_FSCREENINFO:
-		ret = fb_get_fscreeninfo(info, cmd, arg);
+		ret = fb_get_fscreeninfo(info, cmd, arg, file);
 		break;
 
 	case FBIOGETCMAP:
 	case FBIOPUTCMAP:
-		ret = fb_getput_cmap(info, cmd, arg);
+		ret = fb_getput_cmap(info, cmd, arg, file);
 		break;
 
 	default:
-		if (fb->fb_compat_ioctl)
+		if (fb->fb_compat_ioctl_v2)
+			ret = fb->fb_compat_ioctl_v2(info, cmd, arg, file);
+		else if (fb->fb_compat_ioctl)
 			ret = fb->fb_compat_ioctl(info, cmd, arg);
 		break;
 	}
diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig
index 60b86e7..e8f902b 100644
--- a/drivers/video/fbdev/msm/Kconfig
+++ b/drivers/video/fbdev/msm/Kconfig
@@ -21,8 +21,7 @@
 
 config FB_MSM_MDSS
 	bool "MDSS HW"
-	select SYNC
-	select SW_SYNC
+	select SYNC_FILE
 	select FB_MSM_MDSS_COMMON
 	---help---
 	The Mobile Display Sub System (MDSS) driver supports devices which
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index ed3ff87..4ee7f4a 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -1,6 +1,7 @@
 ccflags-y += -I$(src)
 
 obj-$(CONFIG_FB_MSM_MDSS_MHL3) += mhl3/
+obj-$(CONFIG_MSM_DBA) += msm_dba/
 
 mdss-mdp3-objs = mdp3.o mdp3_layer.o mdp3_dma.o mdp3_ctrl.o dsi_status_v2.o
 mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
@@ -9,7 +10,7 @@
 ccflags-y += -DTARGET_HW_MDSS_MDP3
 endif
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o dsi_status_6g.o
-mdss-mdp-objs += mdss_mdp_pp.o mdss_mdp_pp_debug.o mdss_mdp_pp_cache_config.o
+mdss-mdp-objs += mdss_mdp_pp.o mdss_mdp_pp_debug.o mdss_mdp_pp_cache_config.o mdss_sync.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
 mdss-mdp-objs += mdss_mdp_intf_cmd.o
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
@@ -20,6 +21,7 @@
 mdss-mdp-objs += mdss_mdp_cdm.o
 mdss-mdp-objs += mdss_smmu.o
 mdss-mdp-objs += mdss_mdp_wfd.o
+mdss-mdp-objs += mdss_io_util.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_mdp_debug.o
 
@@ -63,7 +65,7 @@
 
 obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
 
-mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o
+mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o mdss_sync.o
 obj-$(CONFIG_FB_MSM_QPIC) += mdss-qpic.o
 obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
 
diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c
index 2782702..33775ec 100644
--- a/drivers/video/fbdev/msm/dsi_host_v2.c
+++ b/drivers/video/fbdev/msm/dsi_host_v2.c
@@ -1114,7 +1114,7 @@
 
 	if (!pdata->panel_info.dynamic_switch_pending) {
 		for (i = 0; !ret && (i < DSI_MAX_PM); i++) {
-			ret = msm_dss_enable_vreg(
+			ret = msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 1);
 			if (ret) {
@@ -1215,7 +1215,7 @@
 error_vreg:
 	if (ret) {
 		for (; i >= 0; i--)
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 	}
@@ -1250,7 +1250,7 @@
 
 	if (!pdata->panel_info.dynamic_switch_pending) {
 		for (i = DSI_MAX_PM - 1; i >= 0; i--) {
-			ret = msm_dss_enable_vreg(
+			ret = msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 			if (ret)
@@ -1287,7 +1287,7 @@
 	pinfo = &pdata->panel_info;
 	mutex_lock(&ctrl_pdata->mutex);
 	for (i = 0; !ret && (i < DSI_MAX_PM); i++) {
-		ret = msm_dss_enable_vreg(
+		ret = msm_mdss_enable_vreg(
 			ctrl_pdata->power_data[i].vreg_config,
 			ctrl_pdata->power_data[i].num_vreg, 1);
 		if (ret) {
@@ -1314,7 +1314,7 @@
 error_vreg:
 	if (ret) {
 		for (; i >= 0; i--)
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 	}
diff --git a/drivers/video/fbdev/msm/dsi_io_v2.c b/drivers/video/fbdev/msm/dsi_io_v2.c
index dd2e308..28441b6 100644
--- a/drivers/video/fbdev/msm/dsi_io_v2.c
+++ b/drivers/video/fbdev/msm/dsi_io_v2.c
@@ -50,7 +50,7 @@
 	}
 }
 
-int msm_dsi_io_init(struct platform_device *pdev, struct dss_module_power *mp)
+int msm_dsi_io_init(struct platform_device *pdev, struct mdss_module_power *mp)
 {
 	int rc;
 
@@ -67,7 +67,7 @@
 		return rc;
 	}
 
-	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+	rc = msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 						mp->num_vreg, 1);
 	if (rc) {
 		pr_err("fail to initialize DSI regulator\n");
@@ -78,11 +78,11 @@
 }
 
 void msm_dsi_io_deinit(struct platform_device *pdev,
-				 struct dss_module_power *mp)
+				 struct mdss_module_power *mp)
 {
 	if (dsi_io_private) {
 		msm_dsi_clk_deinit();
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 					mp->num_vreg, 0);
 		kfree(dsi_io_private);
 		dsi_io_private = NULL;
diff --git a/drivers/video/fbdev/msm/dsi_io_v2.h b/drivers/video/fbdev/msm/dsi_io_v2.h
index dd9adf9..d0227ec 100644
--- a/drivers/video/fbdev/msm/dsi_io_v2.h
+++ b/drivers/video/fbdev/msm/dsi_io_v2.h
@@ -18,10 +18,10 @@
 void msm_dsi_ahb_ctrl(int enable);
 
 int msm_dsi_io_init(struct platform_device *dev,
-				struct dss_module_power *mp);
+				struct mdss_module_power *mp);
 
 void msm_dsi_io_deinit(struct platform_device *dev,
-				struct dss_module_power *mp);
+				struct mdss_module_power *mp);
 
 int msm_dsi_clk_init(struct platform_device *dev);
 
diff --git a/drivers/video/fbdev/msm/dsi_v2.c b/drivers/video/fbdev/msm/dsi_v2.c
index 92d512a..74c0726 100644
--- a/drivers/video/fbdev/msm/dsi_v2.c
+++ b/drivers/video/fbdev/msm/dsi_v2.c
@@ -237,7 +237,7 @@
 }
 
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		pr_err("%s: invalid input\n", __func__);
@@ -252,7 +252,7 @@
 }
 
 static int mdss_dsi_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp, enum dsi_pm_type module)
+	struct mdss_module_power *mp, enum dsi_pm_type module)
 {
 	int i = 0, rc = 0;
 	u32 tmp = 0;
@@ -287,7 +287,7 @@
 		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
 	}
 
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		mp->num_vreg, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		rc = -ENOMEM;
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c
index 308af51..5cf439c 100644
--- a/drivers/video/fbdev/msm/mdp3.c
+++ b/drivers/video/fbdev/msm/mdp3.c
@@ -45,7 +45,6 @@
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
 #include <linux/qcom_iommu.h>
-#include <linux/msm_iommu_domains.h>
 
 #include <linux/msm_dma_iommu_mapping.h>
 
diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h
index 3f0d979..6fb39a7 100644
--- a/drivers/video/fbdev/msm/mdp3.h
+++ b/drivers/video/fbdev/msm/mdp3.h
@@ -19,8 +19,6 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <linux/msm_iommu_domains.h>
-
 #include "mdss_dsi_clk.h"
 #include "mdp3_dma.h"
 #include "mdss_fb.h"
@@ -111,7 +109,6 @@
 struct mdp3_iommu_domain_map {
 	u32 domain_type;
 	char *client_name;
-	struct msm_iova_partition partitions[1];
 	int npartitions;
 	int domain_idx;
 	struct iommu_domain *domain;
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index 889c302..17dadf4 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -271,7 +271,7 @@
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
 
 	atomic_inc(&session->dma_done_cnt);
-	queue_kthread_work(&session->worker, &session->dma_done_work);
+	kthread_queue_work(&session->worker, &session->dma_done_work);
 	complete_all(&session->dma_completion);
 }
 
diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c
index b7c8d43..089d32d 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.c
+++ b/drivers/video/fbdev/msm/mdp3_dma.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018, 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.
diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h
index 6c8e7fe..24caedb9 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.h
+++ b/drivers/video/fbdev/msm/mdp3_dma.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018, 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.
diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c
index 7964cf0..3b72b2d 100644
--- a/drivers/video/fbdev/msm/mdp3_ppp.c
+++ b/drivers/video/fbdev/msm/mdp3_ppp.c
@@ -1661,7 +1661,7 @@
 
 	mdp3_ppp_req_push(req_q, req);
 	mutex_unlock(&ppp_stat->req_mutex);
-	queue_kthread_work(&ppp_stat->kworker, &ppp_stat->blit_work);
+	kthread_queue_work(&ppp_stat->kworker, &ppp_stat->blit_work);
 	if (!async) {
 		/* wait for release fence */
 		rc = sync_fence_wait(fence,
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 5d9e612..12a3171 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -209,7 +209,7 @@
 struct mdss_smmu_client {
 	struct device *dev;
 	struct dma_iommu_mapping *mmu_mapping;
-	struct dss_module_power mp;
+	struct mdss_module_power mp;
 	struct reg_bus_client *reg_bus_clt;
 	bool domain_attached;
 	bool handoff_pending;
@@ -232,6 +232,13 @@
 	u32 *dest_scaler_off;
 	u32 *dest_scaler_lut_off;
 	struct mdss_mdp_qseed3_lut_tbl lut_tbl;
+
+	/*
+	 * Lock is mainly to serialize access to LUT.
+	 * LUT values come asynchronously from userspace
+	 * via ioctl.
+	 */
+	struct mutex scaler_lock;
 };
 
 struct mdss_data_type;
@@ -283,9 +290,9 @@
 	struct mdss_panel_data *pdata;
 
 	struct platform_device *pdev;
-	struct dss_io_data mdss_io;
-	struct dss_io_data vbif_io;
-	struct dss_io_data vbif_nrt_io;
+	struct mdss_io_data mdss_io;
+	struct mdss_io_data vbif_io;
+	struct mdss_io_data vbif_nrt_io;
 	char __iomem *mdp_base;
 
 	struct mdss_smmu_client mdss_smmu[MDSS_IOMMU_MAX_DOMAIN];
@@ -590,14 +597,14 @@
 }
 
 #define MDSS_VBIF_WRITE(mdata, offset, value, nrt_vbif) \
-		(nrt_vbif ? dss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\
-		dss_reg_w(&mdata->vbif_io, offset, value, 0))
+		(nrt_vbif ? mdss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\
+		mdss_reg_w(&mdata->vbif_io, offset, value, 0))
 #define MDSS_VBIF_READ(mdata, offset, nrt_vbif) \
-		(nrt_vbif ? dss_reg_r(&mdata->vbif_nrt_io, offset, 0) :\
-		dss_reg_r(&mdata->vbif_io, offset, 0))
+		(nrt_vbif ? mdss_reg_r(&mdata->vbif_nrt_io, offset, 0) :\
+		mdss_reg_r(&mdata->vbif_io, offset, 0))
 #define MDSS_REG_WRITE(mdata, offset, value) \
-		dss_reg_w(&mdata->mdss_io, offset, value, 0)
+		mdss_reg_w(&mdata->mdss_io, offset, value, 0)
 #define MDSS_REG_READ(mdata, offset) \
-		dss_reg_r(&mdata->mdss_io, offset, 0)
+		mdss_reg_r(&mdata->mdss_io, offset, 0)
 
 #endif /* MDSS_H */
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c
index 06da395..9a9f5e4 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.c
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.c
@@ -4307,7 +4307,7 @@
 		break;
 	}
 
-	if (ret == -ENOTSUP)
+	if (ret == -ENOTSUPP)
 		pr_err("%s: unsupported ioctl\n", __func__);
 	else if (ret)
 		pr_debug("%s: ioctl err cmd=%u ret=%d\n", __func__, cmd, ret);
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h
index 9dcf6d4..ebae393 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.h
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.h
@@ -18,11 +18,13 @@
 /*
  * To allow proper structure padding for 64bit/32bit target
  */
+#ifndef MDP_LAYER_COMMIT_V1_PAD
 #ifdef __LP64
 #define MDP_LAYER_COMMIT_V1_PAD 2
 #else
 #define MDP_LAYER_COMMIT_V1_PAD 3
 #endif
+#endif
 
 struct mdp_buf_sync32 {
 	u32		flags;
diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index 9edf2a8..2758a5a 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -14,7 +14,7 @@
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <video/msm_dba.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
 
 #include "mdss_dba_utils.h"
 #include "mdss_hdmi_edid.h"
@@ -32,8 +32,8 @@
 	bool hpd_state;
 	bool audio_switch_registered;
 	bool display_switch_registered;
-	struct switch_dev sdev_display;
-	struct switch_dev sdev_audio;
+	struct extcon_dev sdev_display;
+	struct extcon_dev sdev_audio;
 	struct kobject *kobj;
 	struct mdss_panel_info *pinfo;
 	void *dba_data;
@@ -103,7 +103,7 @@
 
 	state = udata->sdev_display.state;
 
-	switch_set_state(&udata->sdev_display, val);
+	extcon_set_state_sync(&udata->sdev_display, 0, val);
 
 	pr_debug("cable state %s %d\n",
 		udata->sdev_display.state == state ?
@@ -128,7 +128,7 @@
 
 	state = udata->sdev_audio.state;
 
-	switch_set_state(&udata->sdev_audio, val);
+	extcon_set_state_sync(&udata->sdev_audio, 0, val);
 
 	pr_debug("audio state %s %d\n",
 		udata->sdev_audio.state == state ?
@@ -485,7 +485,7 @@
 
 	/* create switch device to update display modules */
 	udata->sdev_display.name = "hdmi";
-	rc = switch_dev_register(&udata->sdev_display);
+	rc = extcon_dev_register(&udata->sdev_display);
 	if (rc) {
 		pr_err("display switch registration failed\n");
 		goto end;
@@ -495,7 +495,7 @@
 
 	/* create switch device to update audio modules */
 	udata->sdev_audio.name = "hdmi_audio";
-	ret = switch_dev_register(&udata->sdev_audio);
+	ret = extcon_dev_register(&udata->sdev_audio);
 	if (ret) {
 		pr_err("audio switch registration failed\n");
 		goto end;
@@ -895,10 +895,10 @@
 	}
 
 	if (udata->audio_switch_registered)
-		switch_dev_unregister(&udata->sdev_audio);
+		extcon_dev_unregister(&udata->sdev_audio);
 
 	if (udata->display_switch_registered)
-		switch_dev_unregister(&udata->sdev_display);
+		extcon_dev_unregister(&udata->sdev_display);
 
 	if (udata->kobj)
 		mdss_dba_utils_sysfs_remove(udata->kobj);
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 19335772..f38d40c 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -886,7 +886,7 @@
 
 	buf[count] = 0;	/* end of string */
 
-	if (kstrtoint(buf, "%d", &perf_mode) != 1)
+	if (kstrtoint(buf, 10, &perf_mode) != 1)
 		return -EFAULT;
 
 	if (perf_mode) {
@@ -1023,7 +1023,7 @@
 
 	buf[count] = 0;	/* end of string */
 
-	if (kstrtoint(buf, "%d", &disable_panic) != 1)
+	if (kstrtoint(buf, 10, &disable_panic) != 1)
 		return -EFAULT;
 
 	if (disable_panic) {
@@ -1169,10 +1169,10 @@
 		(struct mdss_data_type *)mdata, &mdss_perf_panic_enable);
 
 	debugfs_create_bool("enable_bw_release", 0644, mdd->perf,
-		(u32 *)&mdata->enable_bw_release);
+		(bool *)&mdata->enable_bw_release);
 
 	debugfs_create_bool("enable_rotator_bw_release", 0644, mdd->perf,
-		(u32 *)&mdata->enable_rotator_bw_release);
+		(bool *)&mdata->enable_rotator_bw_release);
 
 	debugfs_create_file("ab_factor", 0644, mdd->perf,
 		&mdata->ab_factor, &mdss_factor_fops);
@@ -1685,7 +1685,7 @@
 		resp->crc_op_mode = map->crc_op_mode;
 		break;
 	default:
-		ret = -ENOTSUP;
+		ret = -ENOTSUPP;
 		break;
 	}
 
diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h
index 01d300e..0d482c0 100644
--- a/drivers/video/fbdev/msm/mdss_debug.h
+++ b/drivers/video/fbdev/msm/mdss_debug.h
@@ -78,8 +78,8 @@
 #define MDSS_XLOG_IOMMU(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_IOMMU, \
 		##__VA_ARGS__, DATA_LIMITER)
 
-#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
-#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
+#define ATRACE_END(name) trace_mdss_mark_write(current->tgid, name, 0)
+#define ATRACE_BEGIN(name) trace_mdss_mark_write(current->tgid, name, 1)
 #define ATRACE_FUNC() ATRACE_BEGIN(__func__)
 
 #define ATRACE_INT(name, value) \
@@ -225,7 +225,7 @@
 int mdss_dump_misr_data(char **buf, u32 size);
 
 static inline int mdss_debug_register_io(const char *name,
-		struct dss_io_data *io_data, struct mdss_debug_base **dbg_blk)
+		struct mdss_io_data *io_data, struct mdss_debug_base **dbg_blk)
 {
 	return mdss_debug_register_base(name, io_data->base, io_data->len,
 		dbg_blk);
diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c
index e493dcd..49684f4 100644
--- a/drivers/video/fbdev/msm/mdss_debug_xlog.c
+++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c
@@ -734,7 +734,7 @@
 	debugfs_create_u32("enable", 0644, mdss_dbg_xlog.xlog,
 			    &mdss_dbg_xlog.xlog_enable);
 	debugfs_create_bool("panic", 0644, mdss_dbg_xlog.xlog,
-			    &mdss_dbg_xlog.panic_on_err);
+			    (bool *)&mdss_dbg_xlog.panic_on_err);
 	debugfs_create_u32("reg_dump", 0644, mdss_dbg_xlog.xlog,
 			    &mdss_dbg_xlog.enable_reg_dump);
 	debugfs_create_u32("dbgbus_dump", 0644, mdss_dbg_xlog.xlog,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index bc6d568..d70c1e8 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -26,6 +26,7 @@
 #include <linux/uaccess.h>
 #include <linux/msm-bus.h>
 #include <linux/pm_qos.h>
+#include <linux/mdss_io_util.h>
 
 #include "mdss.h"
 #include "mdss_panel.h"
@@ -253,14 +254,14 @@
 	}
 
 	for (i = DSI_CORE_PM; !rc && (i < DSI_MAX_PM); i++) {
-		rc = msm_dss_config_vreg(&pdev->dev,
+		rc = msm_mdss_config_vreg(&pdev->dev,
 			sdata->power_data[i].vreg_config,
 			sdata->power_data[i].num_vreg, 1);
 		if (rc) {
 			pr_err("%s: failed to init vregs for %s\n",
 				__func__, __mdss_dsi_pm_name(i));
 			for (j = i-1; j >= DSI_CORE_PM; j--) {
-				msm_dss_config_vreg(&pdev->dev,
+				msm_mdss_config_vreg(&pdev->dev,
 				sdata->power_data[j].vreg_config,
 				sdata->power_data[j].num_vreg, 0);
 			}
@@ -293,7 +294,7 @@
 	if (mdss_dsi_pinctrl_set_state(ctrl_pdata, false))
 		pr_debug("reset disable: pinctrl not enabled\n");
 
-	ret = msm_dss_enable_vreg(
+	ret = msm_mdss_enable_vreg(
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 0);
 	if (ret)
@@ -317,7 +318,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	ret = msm_dss_enable_vreg(
+	ret = msm_mdss_enable_vreg(
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 1);
 	if (ret) {
@@ -378,11 +379,11 @@
 		if (i == DSI_CORE_PM)
 			continue;
 		if (i == DSI_PANEL_PM)
-			ret = msm_dss_config_vreg_opt_mode(
+			ret = msm_mdss_config_vreg_opt_mode(
 				ctrl_pdata->panel_power_data.vreg_config,
 				ctrl_pdata->panel_power_data.num_vreg, mode);
 		else
-			ret = msm_dss_config_vreg_opt_mode(
+			ret = msm_mdss_config_vreg_opt_mode(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, mode);
 		if (ret) {
@@ -395,7 +396,7 @@
 	if (ret) {
 		mode = enable ? DSS_REG_MODE_ENABLE : DSS_REG_MODE_ULP;
 		for (; i >= 0; i--)
-			msm_dss_config_vreg_opt_mode(
+			msm_mdss_config_vreg_opt_mode(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, mode);
 	}
@@ -405,7 +406,7 @@
 int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
 	int power_state)
 {
-	int ret;
+	int ret = 0;
 	struct mdss_panel_info *pinfo;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
@@ -478,7 +479,7 @@
 }
 
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		pr_err("%s: invalid input\n", __func__);
@@ -493,7 +494,7 @@
 }
 
 static int mdss_dsi_get_dt_vreg_data(struct device *dev,
-	struct device_node *of_node, struct dss_module_power *mp,
+	struct device_node *of_node, struct mdss_module_power *mp,
 	enum dsi_pm_type module)
 {
 	int i = 0, rc = 0;
@@ -535,7 +536,7 @@
 		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
 	}
 
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		mp->num_vreg, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		rc = -ENOMEM;
@@ -1033,9 +1034,9 @@
 			   &dfs->override_flag);
 
 	debugfs_create_bool("cmd_sync_wait_broadcast", 0644, dfs->root,
-			    (u32 *)&dfs_ctrl->cmd_sync_wait_broadcast);
+		&dfs_ctrl->cmd_sync_wait_broadcast);
 	debugfs_create_bool("cmd_sync_wait_trigger", 0644, dfs->root,
-			    (u32 *)&dfs_ctrl->cmd_sync_wait_trigger);
+		&dfs_ctrl->cmd_sync_wait_trigger);
 
 	debugfs_create_file("dsi_on_cmd_state", 0644, dfs->root,
 		&dfs_ctrl->on_cmds.link_state, &mdss_dsi_cmd_state_fop);
@@ -2028,7 +2029,7 @@
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
-	struct mdss_panel_info *pinfo, *spinfo;
+	struct mdss_panel_info *pinfo, *spinfo = NULL;
 	int rc = 0;
 
 	if (pdata == NULL) {
@@ -3452,7 +3453,7 @@
 		goto res_release;
 
 	for (i = (DSI_MAX_PM - 1); i >= DSI_CORE_PM; i--) {
-		if (msm_dss_config_vreg(&pdev->dev,
+		if (msm_mdss_config_vreg(&pdev->dev,
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 1) < 0)
 			pr_err("%s: failed to de-init vregs for %s\n",
@@ -3748,12 +3749,6 @@
 		return -EPROBE_DEFER;
 	}
 
-	if (util->display_disabled) {
-		pr_info("%s: Display is disabled, not progressing with dsi probe\n",
-			__func__);
-		return -ENOTSUPP;
-	}
-
 	if (!pdev || !pdev->dev.of_node) {
 		pr_err("%s: DSI driver only supports device tree probe\n",
 			__func__);
@@ -3824,7 +3819,7 @@
 
 	mdss_dsi_pm_qos_remove_request(ctrl_pdata->shared_data);
 
-	if (msm_dss_config_vreg(&pdev->dev,
+	if (msm_mdss_config_vreg(&pdev->dev,
 			ctrl_pdata->panel_power_data.vreg_config,
 			ctrl_pdata->panel_power_data.num_vreg, 1) < 0)
 		pr_err("%s: failed to de-init vregs for %s\n",
@@ -3832,9 +3827,9 @@
 	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->panel_power_data);
 
 	mfd = platform_get_drvdata(pdev);
-	msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
-	msm_dss_iounmap(&ctrl_pdata->phy_io);
-	msm_dss_iounmap(&ctrl_pdata->ctrl_io);
+	msm_mdss_iounmap(&ctrl_pdata->mmss_misc_io);
+	msm_mdss_iounmap(&ctrl_pdata->phy_io);
+	msm_mdss_iounmap(&ctrl_pdata->ctrl_io);
 	mdss_dsi_debugfs_cleanup(ctrl_pdata);
 
 	if (ctrl_pdata->workq)
@@ -3877,7 +3872,7 @@
 		return -EPERM;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
 	if (rc) {
 		pr_err("%s:%d unable to remap dsi ctrl resources\n",
 			       __func__, __LINE__);
@@ -3887,14 +3882,14 @@
 	ctrl->ctrl_base = ctrl->ctrl_io.base;
 	ctrl->reg_size = ctrl->ctrl_io.len;
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
 	if (rc) {
 		pr_err("%s:%d unable to remap dsi phy resources\n",
 			       __func__, __LINE__);
 		return rc;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_regulator_io,
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->phy_regulator_io,
 			"dsi_phy_regulator");
 	if (rc)
 		pr_debug("%s:%d unable to remap dsi phy regulator resources\n",
@@ -3908,7 +3903,7 @@
 		__func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base,
 		ctrl->phy_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
 		"mmss_misc_phys");
 	if (rc) {
 		pr_debug("%s:%d mmss_misc IO remap failed\n",
@@ -3924,7 +3919,7 @@
 	int ret;
 
 	ret = devm_request_irq(dev, irq_no, mdss_dsi_isr,
-				IRQF_DISABLED, "DSI", ctrl);
+				0, "DSI", ctrl);
 	if (ret) {
 		pr_err("msm_dsi_irq_init request_irq() failed!\n");
 		return ret;
@@ -4181,7 +4176,7 @@
 		return rc;
 	}
 
-	rc = msm_dss_config_vreg(&ctrl_pdev->dev,
+	rc = msm_mdss_config_vreg(&ctrl_pdev->dev,
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 1);
 	if (rc) {
@@ -4263,7 +4258,7 @@
 	sdata = ctrl_pdata->shared_data;
 
 	if (pinfo->ulps_suspend_enabled) {
-		rc = msm_dss_enable_vreg(
+		rc = msm_mdss_enable_vreg(
 			sdata->power_data[DSI_PHY_PM].vreg_config,
 			sdata->power_data[DSI_PHY_PM].num_vreg, 1);
 		if (rc) {
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index ea38c0d..60bc455 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -272,7 +272,7 @@
 	struct clk *pixel1_parent;
 
 	/* DSI core regulators */
-	struct dss_module_power power_data[DSI_MAX_PM];
+	struct mdss_module_power power_data[DSI_MAX_PM];
 
 	/* Shared mutex for DSI PHY regulator */
 	struct mutex phy_reg_lock;
@@ -407,10 +407,10 @@
 	void (*switch_mode)(struct mdss_panel_data *pdata, int mode);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
-	struct dss_io_data ctrl_io;
-	struct dss_io_data mmss_misc_io;
-	struct dss_io_data phy_io;
-	struct dss_io_data phy_regulator_io;
+	struct mdss_io_data ctrl_io;
+	struct mdss_io_data mmss_misc_io;
+	struct mdss_io_data phy_io;
+	struct mdss_io_data phy_regulator_io;
 	int reg_size;
 	u32 flags;
 	struct clk *byte_clk;
@@ -459,8 +459,8 @@
 	u32 pclk_rate_bkp;
 	u32 byte_clk_rate_bkp;
 	bool refresh_clk_rate; /* flag to recalculate clk_rate */
-	struct dss_module_power panel_power_data;
-	struct dss_module_power power_data[DSI_MAX_PM]; /* for 8x10 */
+	struct mdss_module_power panel_power_data;
+	struct mdss_module_power power_data[DSI_MAX_PM]; /* for 8x10 */
 	u32 dsi_irq_mask;
 	struct mdss_hw *dsi_hw;
 	struct mdss_intf_recovery *recovery;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 14ac3e1..988c7a9 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1656,7 +1656,7 @@
 				len = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 			else
 				len = mdss_dsi_cmd_dma_tx(ctrl, tp);
-			if (IS_ERR_VALUE(len)) {
+			if (IS_ERR_VALUE((unsigned long)len)) {
 				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 				pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
 					__func__,  cm->payload[0]);
@@ -1886,7 +1886,7 @@
 			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 		else
 			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 			pr_err("%s: failed to tx max_pkt_size\n",
 				__func__);
@@ -1924,7 +1924,7 @@
 			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 		else
 			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 			pr_err("%s: failed to tx cmd = 0x%x\n",
 				__func__,  cmds->payload[0]);
@@ -2043,7 +2043,7 @@
 	if (ctrl->mdss_util->iommu_attached()) {
 		ret = mdss_smmu_dsi_map_buffer(tp->dmap, domain, ctrl->dma_size,
 			&(ctrl->dma_addr), tp->start, DMA_TO_DEVICE);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("unable to map dma memory to iommu(%d)\n", ret);
 			ctrl->mdss_util->iommu_unlock();
 			return -ENOMEM;
@@ -2116,7 +2116,7 @@
 		}
 	}
 
-	if (!IS_ERR_VALUE(ret))
+	if (!IS_ERR_VALUE((unsigned long)ret))
 		ret = tp->len;
 
 	if (mctrl && mctrl->dma_addr) {
@@ -2678,7 +2678,7 @@
 
 		if (ctrl->mdss_util->iommu_ctrl) {
 			rc = ctrl->mdss_util->iommu_ctrl(1);
-			if (IS_ERR_VALUE(rc)) {
+			if (IS_ERR_VALUE((unsigned long)rc)) {
 				pr_err("IOMMU attach failed\n");
 				mutex_unlock(&ctrl->cmd_mutex);
 				return rc;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index d84cf5e..1cbaa44 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -79,10 +79,10 @@
 
 	if (level == 0) {
 		if (ctrl->pwm_enabled) {
-			ret = pwm_config_us(ctrl->pwm_bl, level,
-					ctrl->pwm_period);
+			ret = pwm_config(ctrl->pwm_bl, 0,
+					ctrl->pwm_period * NSEC_PER_USEC);
 			if (ret)
-				pr_err("%s: pwm_config_us() failed err=%d.\n",
+				pr_err("%s: pwm_config() failed err=%d.\n",
 						__func__, ret);
 			pwm_disable(ctrl->pwm_bl);
 		}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index 7b6be11..992d687 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.c
@@ -227,17 +227,6 @@
 int __init mdss_dsi_status_init(void)
 {
 	int rc = 0;
-	struct mdss_util_intf *util = mdss_get_util_intf();
-
-	if (!util) {
-		pr_err("%s: Failed to get utility functions\n", __func__);
-		return -ENODEV;
-	}
-
-	if (util->display_disabled) {
-		pr_info("Display is disabled, not progressing with dsi_init\n");
-		return -ENOTSUPP;
-	}
 
 	pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
 	if (!pstatus_data)
diff --git a/drivers/video/fbdev/msm/mdss_edp.c b/drivers/video/fbdev/msm/mdss_edp.c
index 55d4ab3..79eae8b 100644
--- a/drivers/video/fbdev/msm/mdss_edp.c
+++ b/drivers/video/fbdev/msm/mdss_edp.c
@@ -27,12 +27,9 @@
 #include <linux/clk.h>
 #include <linux/spinlock_types.h>
 #include <linux/kthread.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
 
 #include "mdss.h"
 #include "mdss_edp.h"
-#include "mdss_debug.h"
 
 #define RGB_COMPONENTS		3
 #define VDDA_MIN_UV			1800000	/* uV units */
diff --git a/drivers/video/fbdev/msm/mdss_edp_aux.c b/drivers/video/fbdev/msm/mdss_edp_aux.c
index dc12f3b..268daaa 100644
--- a/drivers/video/fbdev/msm/mdss_edp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_edp_aux.c
@@ -28,10 +28,6 @@
 #include <linux/of_gpio.h>
 #include <linux/clk/msm-clk.h>
 
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/dma.h>
-
 #include "mdss_panel.h"
 #include "mdss_edp.h"
 
@@ -611,7 +607,6 @@
 
 /*
  * EDID structure can be found in VESA standard here:
- * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
  *
  * following table contains default edid
  * static char edid_raw_data[128] = {
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 64f462f..ae9b7cf 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -43,8 +43,6 @@
 #include <linux/uaccess.h>
 #include <linux/version.h>
 #include <linux/vmalloc.h>
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/file.h>
 #include <linux/kthread.h>
 #include <linux/dma-buf.h>
@@ -55,6 +53,7 @@
 #include "mdss_smmu.h"
 #include "mdss_mdp.h"
 #include "mdp3_ctrl.h"
+#include "mdss_sync.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MDSS_FB_NUM 3
@@ -280,7 +279,7 @@
 				      enum led_brightness value)
 {
 	struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
-	int bl_lvl;
+	u64 bl_lvl;
 
 	if (mfd->boot_notification_led) {
 		led_trigger_event(mfd->boot_notification_led, 0);
@@ -519,13 +518,13 @@
 {
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct msm_fb_data_type *mfd = fbi->par;
-	unsigned int fps_int, fps_float;
+	u64 fps_int, fps_float;
 
 	if (mfd->panel_power_state != MDSS_PANEL_POWER_ON)
 		mfd->fps_info.measured_fps = 0;
-	fps_int = (unsigned int) mfd->fps_info.measured_fps;
+	fps_int = (u64) mfd->fps_info.measured_fps;
 	fps_float = do_div(fps_int, 10);
-	return scnprintf(buf, PAGE_SIZE, "%d.%d\n", fps_int, fps_float);
+	return scnprintf(buf, PAGE_SIZE, "%llu.%llu\n", fps_int, fps_float);
 
 }
 
@@ -945,9 +944,6 @@
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
-	if (!mfd)
-		return;
-
 	mfd->shutdown_pending = true;
 
 	/* wake up threads waiting on idle or kickoff queues */
@@ -1314,12 +1310,20 @@
 
 	mfd->mdp_sync_pt_data.fence_name = "mdp-fence";
 	if (mfd->mdp_sync_pt_data.timeline == NULL) {
-		char timeline_name[16];
+		char timeline_name[32];
 
 		snprintf(timeline_name, sizeof(timeline_name),
 			"mdss_fb_%d", mfd->index);
 		 mfd->mdp_sync_pt_data.timeline =
-				sw_sync_timeline_create(timeline_name);
+				mdss_create_timeline(timeline_name);
+		if (mfd->mdp_sync_pt_data.timeline == NULL) {
+			pr_err("cannot create release fence time line\n");
+			return -ENOMEM;
+		}
+		snprintf(timeline_name, sizeof(timeline_name),
+			"mdss_fb_%d_retire", mfd->index);
+		 mfd->mdp_sync_pt_data.timeline_retire =
+				mdss_create_timeline(timeline_name);
 		if (mfd->mdp_sync_pt_data.timeline == NULL) {
 			pr_err("cannot create release fence time line\n");
 			return -ENOMEM;
@@ -1864,7 +1868,7 @@
 	/* Start Display thread */
 	if (mfd->disp_thread == NULL) {
 		ret = mdss_fb_start_disp_thread(mfd);
-		if (IS_ERR_VALUE(ret))
+		if (IS_ERR_VALUE((unsigned long)ret))
 			return ret;
 	}
 
@@ -2288,9 +2292,10 @@
 			pr_debug("vma=%pK, addr=%x len=%ld\n",
 					vma, (unsigned int)addr, len);
 			pr_debug("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
-					(unsigned int)vma->vm_start,
-					(unsigned int)vma->vm_end,
-					(unsigned long int)vma->vm_page_prot);
+				(unsigned int)vma->vm_start,
+				(unsigned int)vma->vm_end,
+				(unsigned long int)pgprot_val(
+							vma->vm_page_prot));
 
 			io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
 					vma->vm_page_prot);
@@ -2874,7 +2879,7 @@
 }
 
 static void __mdss_fb_copy_fence(struct msm_sync_pt_data *sync_pt_data,
-	struct sync_fence **fences, u32 *fence_cnt)
+	struct mdss_fence **fences, u32 *fence_cnt)
 {
 	pr_debug("%s: wait for fences\n", sync_pt_data->fence_name);
 
@@ -2887,12 +2892,12 @@
 	sync_pt_data->acq_fen_cnt = 0;
 	if (*fence_cnt)
 		memcpy(fences, sync_pt_data->acq_fen,
-				*fence_cnt * sizeof(struct sync_fence *));
+				*fence_cnt * sizeof(struct mdss_fence *));
 	mutex_unlock(&sync_pt_data->sync_mutex);
 }
 
 static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data,
-	struct sync_fence **fences, int fence_cnt)
+	struct mdss_fence **fences, int fence_cnt)
 {
 	int i, ret = 0;
 	unsigned long max_wait = msecs_to_jiffies(WAIT_MAX_FENCE_TIMEOUT);
@@ -2916,7 +2921,7 @@
 			wait_ms = min_t(long, WAIT_FENCE_FIRST_TIMEOUT,
 					wait_ms);
 
-		ret = sync_fence_wait(fences[i], wait_ms);
+		ret = mdss_wait_sync_fence(fences[i], wait_ms);
 
 		if (ret == -ETIME) {
 			wait_jf = timeout - jiffies;
@@ -2928,31 +2933,31 @@
 						wait_ms);
 
 			pr_warn("%s: sync_fence_wait timed out! ",
-					fences[i]->name);
+					mdss_get_sync_fence_name(fences[i]));
 			pr_cont("Waiting %ld.%ld more seconds\n",
 				(wait_ms/MSEC_PER_SEC), (wait_ms%MSEC_PER_SEC));
 			MDSS_XLOG(sync_pt_data->timeline_value);
 			MDSS_XLOG_TOUT_HANDLER("mdp");
-			ret = sync_fence_wait(fences[i], wait_ms);
+			ret = mdss_wait_sync_fence(fences[i], wait_ms);
 
 			if (ret == -ETIME)
 				break;
 		}
-		sync_fence_put(fences[i]);
+		mdss_put_sync_fence(fences[i]);
 	}
 
 	if (ret < 0) {
 		pr_err("%s: sync_fence_wait failed! ret = %x\n",
 				sync_pt_data->fence_name, ret);
 		for (; i < fence_cnt; i++)
-			sync_fence_put(fences[i]);
+			mdss_put_sync_fence(fences[i]);
 	}
 	return ret;
 }
 
 int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
 {
-	struct sync_fence *fences[MDP_MAX_FENCE_FD];
+	struct mdss_fence *fences[MDP_MAX_FENCE_FD];
 	int fence_cnt = 0;
 
 	__mdss_fb_copy_fence(sync_pt_data, fences, &fence_cnt);
@@ -2977,7 +2982,8 @@
 	mutex_lock(&sync_pt_data->sync_mutex);
 	if (atomic_add_unless(&sync_pt_data->commit_cnt, -1, 0) &&
 			sync_pt_data->timeline) {
-		sw_sync_timeline_inc(sync_pt_data->timeline, 1);
+		mdss_inc_timeline(sync_pt_data->timeline, 1);
+		mdss_inc_timeline(sync_pt_data->timeline_retire, 1);
 		MDSS_XLOG(sync_pt_data->timeline_value);
 		sync_pt_data->timeline_value++;
 
@@ -3009,7 +3015,8 @@
 	if (sync_pt_data->timeline) {
 		val = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
-		sw_sync_timeline_inc(sync_pt_data->timeline, val);
+		mdss_resync_timeline(sync_pt_data->timeline);
+		mdss_resync_timeline(sync_pt_data->timeline_retire);
 		sync_pt_data->timeline_value += val;
 		atomic_set(&sync_pt_data->commit_cnt, 0);
 	}
@@ -3182,7 +3189,7 @@
 	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
 		return -EINVAL;
 
-	ret = mdss_fb_pan_idle(mfd);
+	ret = mdss_fb_wait_for_kickoff(mfd);
 	if (ret) {
 		pr_err("wait_for_kick failed. rc=%d\n", ret);
 		return ret;
@@ -3513,7 +3520,7 @@
 
 	if (var->grayscale > 1) {
 		format = mdss_grayscale_to_mdp_format(var->grayscale);
-		if (!IS_ERR_VALUE(format))
+		if (!IS_ERR_VALUE((unsigned long)format))
 			pinfo->out_format = format;
 		else
 			pr_warn("Failed to map grayscale value (%d) to an MDP format\n",
@@ -3593,7 +3600,7 @@
 {
 	struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
 	struct msm_fb_backup_type *fb_backup = &mfd->msm_fb_backup;
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	u32 new_dsi_mode, dynamic_dsi_switch = 0;
 
 	if (!sync_pt_data->async_wait_fences)
@@ -3648,7 +3655,7 @@
 	if (!ret)
 		mdss_fb_update_backlight(mfd);
 
-	if (IS_ERR_VALUE(ret) || !sync_pt_data->flushed) {
+	if (IS_ERR_VALUE((unsigned long)ret) || !sync_pt_data->flushed) {
 		mdss_fb_release_kickoff(mfd);
 		mdss_fb_signal_timeline(sync_pt_data);
 		if ((mfd->panel.type == MIPI_CMD_PANEL) &&
@@ -3823,7 +3830,7 @@
 		mdss_fb_var_to_panelinfo(var, panel_info);
 		rc = mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
 			panel_info);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			kfree(panel_info);
 			return rc;
 		}
@@ -3984,7 +3991,7 @@
 				mfd->fbi->var.yres) * mfd->fb_page;
 
 	old_format = mdss_grayscale_to_mdp_format(var->grayscale);
-	if (!IS_ERR_VALUE(old_format)) {
+	if (!IS_ERR_VALUE((unsigned long)old_format)) {
 		if (old_format != mfd->panel_info->out_format)
 			mfd->panel_reconfig = true;
 	}
@@ -4186,24 +4193,16 @@
  * Function returns a fence on the timeline given with the name provided.
  * The fence created will be signaled when the timeline is advanced.
  */
-struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+struct mdss_fence *mdss_fb_sync_get_fence(struct mdss_timeline *timeline,
 		const char *fence_name, int val)
 {
-	struct sync_pt *sync_pt;
-	struct sync_fence *fence;
+	struct mdss_fence *fence;
 
-	pr_debug("%s: buf sync fence timeline=%d\n", fence_name, val);
 
-	sync_pt = sw_sync_pt_create(timeline, val);
-	if (sync_pt == NULL) {
-		pr_err("%s: cannot create sync point\n", fence_name);
-		return NULL;
-	}
-
-	/* create fence */
-	fence = sync_fence_create(fence_name, sync_pt);
+	fence = mdss_get_sync_fence(timeline, fence_name, NULL, val);
+	pr_debug("%s: buf sync fence timeline=%d\n",
+		 mdss_get_sync_fence_name(fence), val);
 	if (fence == NULL) {
-		sync_pt_free(sync_pt);
 		pr_err("%s: cannot create fence\n", fence_name);
 		return NULL;
 	}
@@ -4216,7 +4215,7 @@
 {
 	int i, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
-	struct sync_fence *fence, *rel_fence, *retire_fence;
+	struct mdss_fence *fence, *rel_fence, *retire_fence;
 	int rel_fen_fd;
 	int retire_fen_fd;
 	int val;
@@ -4240,7 +4239,7 @@
 
 	mutex_lock(&sync_pt_data->sync_mutex);
 	for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
-		fence = sync_fence_fdget(acq_fen_fd[i]);
+		fence = mdss_get_fd_sync_fence(acq_fen_fd[i]);
 		if (fence == NULL) {
 			pr_err("%s: null fence! i=%d fd=%d\n",
 					sync_pt_data->fence_name, i,
@@ -4254,7 +4253,7 @@
 	if (ret)
 		goto buf_sync_err_1;
 
-	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
+	val = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
 
 	MDSS_XLOG(sync_pt_data->timeline_value, val,
@@ -4273,7 +4272,7 @@
 	}
 
 	/* create fd */
-	rel_fen_fd = get_unused_fd_flags(0);
+	rel_fen_fd = mdss_get_sync_fence_fd(rel_fence);
 	if (rel_fen_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed error:0x%x\n",
 				sync_pt_data->fence_name, rel_fen_fd);
@@ -4307,13 +4306,13 @@
 		ret = retire_fence ? PTR_ERR(rel_fence) : -ENOMEM;
 		goto buf_sync_err_3;
 	}
-	retire_fen_fd = get_unused_fd_flags(0);
+	retire_fen_fd = mdss_get_sync_fence_fd(retire_fence);
 
 	if (retire_fen_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed for retire fence error:0x%x\n",
 				sync_pt_data->fence_name, retire_fen_fd);
 		ret = retire_fen_fd;
-		sync_fence_put(retire_fence);
+		mdss_put_sync_fence(retire_fence);
 		goto buf_sync_err_3;
 	}
 
@@ -4323,14 +4322,12 @@
 		pr_err("%s: copy_to_user failed for retire fence\n",
 				sync_pt_data->fence_name);
 		put_unused_fd(retire_fen_fd);
-		sync_fence_put(retire_fence);
+		mdss_put_sync_fence(retire_fence);
 		goto buf_sync_err_3;
 	}
 
-	sync_fence_install(retire_fence, retire_fen_fd);
-
 skip_retire_fence:
-	sync_fence_install(rel_fence, rel_fen_fd);
+	mdss_get_sync_fence_fd(rel_fence);
 	mutex_unlock(&sync_pt_data->sync_mutex);
 
 	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
@@ -4340,10 +4337,10 @@
 buf_sync_err_3:
 	put_unused_fd(rel_fen_fd);
 buf_sync_err_2:
-	sync_fence_put(rel_fence);
+	mdss_put_sync_fence(rel_fence);
 buf_sync_err_1:
 	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
-		sync_fence_put(sync_pt_data->acq_fen[i]);
+		mdss_put_sync_fence(sync_pt_data->acq_fen[i]);
 	sync_pt_data->acq_fen_cnt = 0;
 	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
@@ -4796,7 +4793,7 @@
 {
 	struct msm_fb_data_type *mfd;
 	void __user *argp = (void __user *)arg;
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	struct mdp_buf_sync buf_sync;
 	unsigned int dsi_mode = 0;
 	struct mdss_panel_data *pdata = NULL;
@@ -4884,7 +4881,7 @@
 		break;
 	}
 
-	if (ret == -ENOTSUP)
+	if (ret == -ENOTSUPP)
 		pr_err("unsupported ioctl (%x)\n", cmd);
 
 exit:
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index f8ef48a..c85f033 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -171,11 +171,12 @@
 struct msm_sync_pt_data {
 	char *fence_name;
 	u32 acq_fen_cnt;
-	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+	struct mdss_fence *acq_fen[MDP_MAX_FENCE_FD];
 	u32 temp_fen_cnt;
-	struct sync_fence *temp_fen[MDP_MAX_FENCE_FD];
+	struct mdss_fence *temp_fen[MDP_MAX_FENCE_FD];
 
-	struct sw_sync_timeline *timeline;
+	struct mdss_timeline *timeline;
+	struct mdss_timeline *timeline_retire;
 	int timeline_value;
 	u32 threshold;
 	u32 retire_threshold;
@@ -186,7 +187,7 @@
 	struct mutex sync_mutex;
 	struct notifier_block notifier;
 
-	struct sync_fence *(*get_retire_fence)
+	struct mdss_fence *(*get_retire_fence)
 		(struct msm_sync_pt_data *sync_pt_data);
 };
 
@@ -306,7 +307,7 @@
 	u32 calib_mode;
 	u32 calib_mode_bl;
 	u32 ad_bl_level;
-	u32 bl_level;
+	u64 bl_level;
 	u32 bl_scale;
 	u32 bl_min_lvl;
 	u32 unset_bl_level;
@@ -452,7 +453,7 @@
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
 int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
 void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
-struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+struct mdss_fence *mdss_fb_sync_get_fence(struct mdss_timeline *timeline,
 				const char *fence_name, int val);
 int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_audio.c b/drivers/video/fbdev/msm/mdss_hdmi_audio.c
index e4dc530..446e8b4 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_audio.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_audio.c
@@ -19,7 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/iopoll.h>
 #include <linux/types.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
 #include <linux/gcd.h>
 
 #include "mdss_hdmi_audio.h"
@@ -63,9 +63,9 @@
 };
 
 struct hdmi_audio {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct msm_hdmi_audio_setup_params params;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 	u32 pclk;
 	bool ack_enabled;
 	bool audio_ack_enabled;
@@ -143,7 +143,7 @@
 
 static void hdmi_audio_acr_enable(struct hdmi_audio *audio)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_audio_acr acr;
 	struct msm_hdmi_audio_setup_params *params;
 	u32 pclk, layout, multiplier = 1, sample_rate;
@@ -260,7 +260,7 @@
 
 static void hdmi_audio_infoframe_setup(struct hdmi_audio *audio, bool enabled)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	u32 channels, channel_allocation, level_shift, down_mix, layout;
 	u32 hdmi_debug_reg = 0, audio_info_0_reg = 0, audio_info_1_reg = 0;
 	u32 audio_info_ctrl_reg, aud_pck_ctrl_2_reg;
@@ -393,7 +393,7 @@
 		return;
 	}
 
-	switch_set_state(&audio->sdev, val);
+	extcon_set_state_sync(&audio->sdev, 0, val);
 	switched = audio->sdev.state != state;
 
 	if (audio->ack_enabled && switched)
@@ -490,7 +490,7 @@
 		goto end;
 
 	audio->sdev.name = "hdmi_audio";
-	rc = switch_dev_register(&audio->sdev);
+	rc = extcon_dev_register(&audio->sdev);
 	if (rc) {
 		pr_err("audio switch registration failed\n");
 		kzfree(audio);
@@ -520,7 +520,7 @@
 	struct hdmi_audio *audio = ctx;
 
 	if (audio) {
-		switch_dev_unregister(&audio->sdev);
+		extcon_dev_unregister(&audio->sdev);
 		kfree(ctx);
 	}
 }
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_audio.h b/drivers/video/fbdev/msm/mdss_hdmi_audio.h
index 7b33cb8..2449123 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_audio.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_audio.h
@@ -62,7 +62,7 @@
  * Defines the data needed to be provided while initializing audio module
  */
 struct hdmi_audio_init_data {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_audio_ops *ops;
 };
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.c b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
index f1be313..f15272e 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_cec.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
@@ -52,7 +52,7 @@
 	u32 frame_retransmit = RETRANSMIT_MAX_NUM;
 	bool frame_type;
 	unsigned long flags;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)data;
 
 	if (!cec_ctrl || !cec_ctrl->init_data.io || !msg) {
@@ -169,7 +169,7 @@
 	int i;
 	u32 data;
 	struct hdmi_cec_ctrl *cec_ctrl = NULL;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct cec_msg msg;
 	struct cec_cbs *cbs;
 
@@ -262,7 +262,7 @@
 	int rc = 0;
 	u32 cec_intr, cec_status;
 	unsigned long flags;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
 
 	if (!cec_ctrl || !cec_ctrl->init_data.io) {
@@ -368,7 +368,7 @@
 {
 	int ret = 0;
 	u32 hdmi_hw_version, reg_val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
 	struct mdss_panel_info *pinfo;
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.h b/drivers/video/fbdev/msm/mdss_hdmi_cec.h
index 57a7664..de4bb35 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_cec.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.h
@@ -30,7 +30,7 @@
  */
 struct hdmi_cec_init_data {
 	struct workqueue_struct *workq;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct mdss_panel_info *pinfo;
 	struct cec_cbs *cbs;
 	struct cec_ops *ops;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index d6e37a1..ab8491d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -738,7 +738,7 @@
 	}
 
 	rc = sscanf(buf,
-		"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+		"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %u",
 		(unsigned long *) &timing.active_h,
 		(unsigned long *) &timing.front_porch_h,
 		(unsigned long *) &timing.pulse_width_h,
@@ -753,7 +753,7 @@
 		(unsigned long *) &timing.refresh_rate,
 		(unsigned long *) &timing.interlaced,
 		(unsigned long *) &timing.supported,
-		(unsigned long *) &timing.ar);
+		(unsigned int *) &timing.ar);
 
 	if (rc != 15) {
 		DEV_ERR("%s: error reading buf\n", __func__);
@@ -762,7 +762,7 @@
 
 	rc = hdmi_set_resv_timing_info(&timing);
 
-	if (!IS_ERR_VALUE(rc)) {
+	if (!IS_ERR_VALUE((unsigned long)rc)) {
 		DEV_DBG("%s: added new res %d\n", __func__, rc);
 	} else {
 		DEV_ERR("%s: error adding new res %d\n", __func__, rc);
@@ -1499,7 +1499,7 @@
 		rc = -EINVAL;
 	}
 
-	if (!IS_ERR_VALUE(rc)) {
+	if (!IS_ERR_VALUE((unsigned long)rc)) {
 		*disp_mode = rc;
 		DEV_DBG("%s: DTD mode found: %d\n", __func__, *disp_mode);
 	} else {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
index bbdf485..41c6844 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
@@ -87,7 +87,7 @@
 	int hdcp_ddc_status;
 	int failure;
 	int nack0;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -166,7 +166,7 @@
 
 static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	u32 hdcp_ddc_status, ddc_hw_status;
 	u32 ddc_xfer_done, ddc_xfer_req;
 	u32 ddc_hw_req, ddc_hw_not_idle;
@@ -254,8 +254,8 @@
 	u32 ksv_lsb_addr, ksv_msb_addr;
 	u32 aksv_lsb, aksv_msb;
 	u8 aksv[5];
-	struct dss_io_data *io;
-	struct dss_io_data *qfprom_io;
+	struct mdss_io_data *io;
+	struct mdss_io_data *qfprom_io;
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = input;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
@@ -352,8 +352,8 @@
 	u32 link0_an_0, link0_an_1;
 	u32 timeout_count;
 	bool is_match;
-	struct dss_io_data *io;
-	struct dss_io_data *hdcp_io;
+	struct mdss_io_data *io;
+	struct mdss_io_data *hdcp_io;
 	u8 aksv[5], *bksv = NULL;
 	u8 an[8];
 	u8 bcaps = 0;
@@ -676,30 +676,34 @@
 	return rc;
 } /* hdmi_hdcp_authentication_part1 */
 
-static  int read_write_v_h(dss_io_data *io, int off. char *name, u32 reg,
-				    bool wr)
+static int read_write_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+			  struct hdmi_tx_ddc_data ddc_data,
+			  struct mdss_io_data *io, int off, char *name,
+			  u32 reg, bool wr)
 {
-	char what[20];
 	int rc = 0;
 
 	do {
 		ddc_data.offset = off;
-		memset(what, 0, sizeof(what));
-		snprintf(what, 20, name);
+		memset(ddc_data.what, 0, 20);
+		snprintf(ddc_data.what, 20, name);
 		hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
 		rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
 		if (rc) {
 			DEV_ERR("%s: %s: Read %s failed\n", __func__,
-				HDCP_STATE_NAME, what);
+				HDCP_STATE_NAME, ddc_data.what);
 			return rc;
 		}
 		DEV_DBG("%s: %s: %s: buf[0]=%x, [1]=%x,[2]=%x, [3]=%x\n",
-			__func__, HDCP_STATE_NAME, what, buf[0], buf[1],
-			buf[2], buf[3]);
+			__func__, HDCP_STATE_NAME, ddc_data.what,
+			ddc_data.data_buf[0], ddc_data.data_buf[1],
+			ddc_data.data_buf[2], ddc_data.data_buf[3]);
 		if (wr) {
 			DSS_REG_W((io), (reg),
-					(buf[3] << 24 | buf[2] << 16 |
-					buf[1] << 8 | buf[0]));
+					(ddc_data.data_buf[3] << 24 |
+					 ddc_data.data_buf[2] << 16 |
+					 ddc_data.data_buf[1] << 8 |
+					 ddc_data.data_buf[0]));
 		}
 	} while (0);
 	return rc;
@@ -711,7 +715,7 @@
 	int rc = 0;
 	u8 buf[4];
 	struct hdmi_tx_ddc_data ddc_data;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
 	u32 phy_addr;
@@ -728,14 +732,6 @@
 	u32 ret  = 0;
 	u32 resp = 0;
 
-	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	phy_addr = hdcp_ctrl->init_data.phy_addr;
-
-	io = hdcp_ctrl->init_data.core_io;
 	memset(&ddc_data, 0, sizeof(ddc_data));
 	ddc_data.dev_addr = 0x74;
 	ddc_data.data_buf = buf;
@@ -744,13 +740,23 @@
 	ddc_data.retry = 5;
 	ddc_data.what = what;
 
+	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	phy_addr = hdcp_ctrl->init_data.phy_addr;
+
+	io = hdcp_ctrl->init_data.core_io;
+
 	if (hdcp_ctrl->tz_hdcp) {
 		memset(scm_buf, 0x00, sizeof(scm_buf));
 
 		for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) {
 			struct hdmi_hdcp_reg_data *rd = reg_data + iter;
 
-			if (read_write_v_h(io, rd->off, rd->name, 0, false))
+			if (read_write_v_h(hdcp_ctrl, ddc_data, io, rd->off,
+					   rd->name, 0, false))
 				goto error;
 
 			rd->reg_val = buf[3] << 24 | buf[2] << 16 |
@@ -768,56 +774,56 @@
 			goto error;
 		}
 	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
-		struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;
+		struct mdss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;
 
 		/* Read V'.HO 4 Byte at offset 0x20 */
-		if (read_write_v_h(hdcp_io, 0x20, "V' H0",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x20, "V' H0",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true))
 			goto error;
 
 		/* Read V'.H1 4 Byte at offset 0x24 */
-		if (read_write_v_h(hdcp_io, 0x24, "V' H1",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x24, "V' H1",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true))
 			goto error;
 
 		/* Read V'.H2 4 Byte at offset 0x28 */
-		if (read_write_v_h(hdcp_io, 0x28, "V' H2",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x28, "V' H2",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true))
 			goto error;
 
 		/* Read V'.H3 4 Byte at offset 0x2C */
-		if (read_write_v_h(hdcp_io, 0x2C, "V' H3",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x2C, "V' H3",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true))
 			goto error;
 
 		/* Read V'.H4 4 Byte at offset 0x30 */
-		if (read_write_v_h(hdcp_io, 0x30, "V' H4",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x30, "V' H4",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true))
 			goto error;
 	} else {
 		/* Read V'.HO 4 Byte at offset 0x20 */
-		if (read_write_v_h(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x20, "V' H0",
+				   HDMI_HDCP_RCVPORT_DATA7, true))
 			goto error;
 
 		/* Read V'.H1 4 Byte at offset 0x24 */
-		if (read_write_v_h(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x24, "V' H1",
+				   HDMI_HDCP_RCVPORT_DATA8, true))
 			goto error;
 
 		/* Read V'.H2 4 Byte at offset 0x28 */
-		if (read_write_v_h(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x28, "V' H2",
+				   HDMI_HDCP_RCVPORT_DATA9, true))
 			goto error;
 
 		/* Read V'.H3 4 Byte at offset 0x2C */
-		if (read_write_v_h(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x2C, "V' H3",
+				   HDMI_HDCP_RCVPORT_DATA10, true))
 			goto error;
 
 		/* Read V'.H4 4 Byte at offset 0x30 */
-		if (read_write_v_h(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x30, "V' H4",
+				   HDMI_HDCP_RCVPORT_DATA11, true))
 			goto error;
 	}
 
@@ -837,7 +843,7 @@
 	u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0;
 	u32 link0_status;
 	u32 ksv_bytes;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
 	u32 phy_addr;
@@ -1241,7 +1247,7 @@
 	struct delayed_work *dw = to_delayed_work(work);
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(dw,
 		struct hdmi_hdcp_ctrl, hdcp_auth_work);
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	if (!hdcp_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -1347,7 +1353,7 @@
 int hdmi_hdcp_reauthenticate(void *input)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 hdmi_hw_version;
 	u32 ret = 0;
 
@@ -1394,7 +1400,7 @@
 void hdmi_hdcp_off(void *input)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	int rc = 0;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
@@ -1447,7 +1453,7 @@
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
 	int rc = 0;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 hdcp_int_val;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
index 2098943..2276009 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
@@ -28,9 +28,9 @@
 };
 
 struct hdmi_hdcp_init_data {
-	struct dss_io_data *core_io;
-	struct dss_io_data *qfprom_io;
-	struct dss_io_data *hdcp_io;
+	struct mdss_io_data *core_io;
+	struct mdss_io_data *qfprom_io;
+	struct mdss_io_data *hdcp_io;
 	struct mutex *mutex;
 	struct kobject *sysfs_kobj;
 	struct workqueue_struct *workq;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
index fc0c878..8dce151 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
@@ -64,7 +64,7 @@
 	void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
 	struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
 
-	enum hdmi_hdcp_wakeup_cmd wakeup_cmd;
+	enum hdcp_wakeup_cmd wakeup_cmd;
 	enum hdmi_auth_status auth_status;
 	char *send_msg_buf;
 	uint32_t send_msg_len;
@@ -89,7 +89,7 @@
 
 static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl)
 {
-	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
+	if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE)
 		return true;
 
 	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
@@ -99,7 +99,7 @@
 }
 
 static int hdmi_hdcp2p2_copy_buf(struct hdmi_hdcp2p2_ctrl *ctrl,
-	struct hdmi_hdcp_wakeup_data *data)
+	struct hdcp_wakeup_data *data)
 {
 	mutex_lock(&ctrl->msg_lock);
 
@@ -126,7 +126,7 @@
 	return 0;
 }
 
-static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
+static int hdmi_hdcp2p2_wakeup(struct hdcp_wakeup_data *data)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl;
 
@@ -144,7 +144,7 @@
 	mutex_lock(&ctrl->wakeup_mutex);
 
 	pr_debug("cmd: %s, timeout %dms, tethered %d\n",
-		hdmi_hdcp_cmd_to_str(data->cmd),
+		hdcp_cmd_to_str(data->cmd),
 		data->timeout, ctrl->tethered);
 
 	ctrl->wakeup_cmd = data->cmd;
@@ -162,30 +162,30 @@
 	if (hdmi_hdcp2p2_copy_buf(ctrl, data))
 		goto exit;
 
-	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS)
+	if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS)
 		ctrl->auth_status = HDMI_HDCP_AUTH_STATUS_SUCCESS;
-	else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED)
+	else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED)
 		ctrl->auth_status = HDMI_HDCP_AUTH_STATUS_FAILURE;
 
 	if (ctrl->tethered)
 		goto exit;
 
 	switch (ctrl->wakeup_cmd) {
-	case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
-		queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
+	case HDCP_WKUP_CMD_SEND_MESSAGE:
+		kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
 		break;
-	case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
-		queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
+	case HDCP_WKUP_CMD_RECV_MESSAGE:
+		kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
 		break;
-	case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
-	case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
-		queue_kthread_work(&ctrl->worker, &ctrl->status);
+	case HDCP_WKUP_CMD_STATUS_SUCCESS:
+	case HDCP_WKUP_CMD_STATUS_FAILED:
+		kthread_queue_work(&ctrl->worker, &ctrl->status);
 		break;
-	case HDMI_HDCP_WKUP_CMD_LINK_POLL:
-		queue_kthread_work(&ctrl->worker, &ctrl->poll);
+	case HDCP_WKUP_CMD_LINK_POLL:
+		kthread_queue_work(&ctrl->worker, &ctrl->poll);
 		break;
-	case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
-		queue_kthread_work(&ctrl->worker, &ctrl->auth);
+	case HDCP_WKUP_CMD_AUTHENTICATE:
+		kthread_queue_work(&ctrl->worker, &ctrl->auth);
 		break;
 	default:
 		pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
@@ -220,19 +220,19 @@
 
 	while (1) {
 		switch (ctrl->wakeup_cmd) {
-		case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
-			ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+		case HDCP_WKUP_CMD_SEND_MESSAGE:
+			ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 			hdmi_hdcp2p2_send_msg(ctrl);
 			break;
-		case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
-			ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+		case HDCP_WKUP_CMD_RECV_MESSAGE:
+			ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 			hdmi_hdcp2p2_recv_msg(ctrl);
 			break;
-		case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
-		case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
+		case HDCP_WKUP_CMD_STATUS_SUCCESS:
+		case HDCP_WKUP_CMD_STATUS_FAILED:
 			hdmi_hdcp2p2_auth_status(ctrl);
 			goto exit;
-		case HDMI_HDCP_WKUP_CMD_LINK_POLL:
+		case HDCP_WKUP_CMD_LINK_POLL:
 			hdmi_hdcp2p2_link_check(ctrl);
 			goto exit;
 		default:
@@ -240,7 +240,7 @@
 		}
 	}
 exit:
-	ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+	ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 }
 
 int hdmi_hdcp2p2_authenticate_tethered(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -278,7 +278,7 @@
 static void hdmi_hdcp2p2_off(void *input)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
-	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
+	struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
@@ -287,7 +287,7 @@
 
 	hdmi_hdcp2p2_reset(ctrl);
 
-	flush_kthread_worker(&ctrl->worker);
+	kthread_flush_worker(&ctrl->worker);
 
 	hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
 
@@ -302,7 +302,7 @@
 static int hdmi_hdcp2p2_authenticate(void *input)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl = input;
-	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
+	struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
 	u32 regval;
 	int rc = 0;
 
@@ -312,7 +312,7 @@
 
 	DSS_REG_W(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2, regval);
 
-	flush_kthread_worker(&ctrl->worker);
+	kthread_flush_worker(&ctrl->worker);
 
 	ctrl->sink_status = SINK_CONNECTED;
 	atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
@@ -385,8 +385,8 @@
 
 	ctrl->tethered = !!tethered;
 
-	if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx)
-		ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered);
+	//if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx)
+	//	ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered);
 exit:
 	mutex_unlock(&ctrl->mutex);
 
@@ -661,7 +661,7 @@
 	}
 
 	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
-		queue_kthread_work(&ctrl->worker, &ctrl->link);
+		kthread_queue_work(&ctrl->worker, &ctrl->link);
 }
 
 static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -1042,7 +1042,7 @@
 	register_data.client_ops = &client_ops;
 	register_data.txmtr_ops = &txmtr_ops;
 	register_data.client_ctx = ctrl;
-	register_data.tethered = ctrl->tethered;
+	//register_data.tethered = ctrl->tethered;
 
 	rc = hdcp_library_register(&register_data);
 	if (rc) {
@@ -1050,14 +1050,14 @@
 		goto error;
 	}
 
-	init_kthread_worker(&ctrl->worker);
+	kthread_init_worker(&ctrl->worker);
 
-	init_kthread_work(&ctrl->auth,     hdmi_hdcp2p2_auth_work);
-	init_kthread_work(&ctrl->send_msg, hdmi_hdcp2p2_send_msg_work);
-	init_kthread_work(&ctrl->recv_msg, hdmi_hdcp2p2_recv_msg_work);
-	init_kthread_work(&ctrl->status,   hdmi_hdcp2p2_auth_status_work);
-	init_kthread_work(&ctrl->link,     hdmi_hdcp2p2_link_work);
-	init_kthread_work(&ctrl->poll,     hdmi_hdcp2p2_poll_work);
+	kthread_init_work(&ctrl->auth,     hdmi_hdcp2p2_auth_work);
+	kthread_init_work(&ctrl->send_msg, hdmi_hdcp2p2_send_msg_work);
+	kthread_init_work(&ctrl->recv_msg, hdmi_hdcp2p2_recv_msg_work);
+	kthread_init_work(&ctrl->status,   hdmi_hdcp2p2_auth_status_work);
+	kthread_init_work(&ctrl->link,     hdmi_hdcp2p2_link_work);
+	kthread_init_work(&ctrl->poll,     hdmi_hdcp2p2_poll_work);
 
 	ctrl->thread = kthread_run(kthread_worker_fn,
 		&ctrl->worker, "hdmi_hdcp2p2");
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
index 9e082b3a..3823d3b 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
@@ -108,7 +108,7 @@
 };
 
 struct hdmi_panel {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_util_ds_data *ds_data;
 	struct hdmi_panel_data *data;
 	struct hdmi_video_config vid_cfg;
@@ -275,7 +275,7 @@
 	u32 total_h, start_h, end_h;
 	u32 total_v, start_v, end_v;
 	u32 div = 0;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 	struct msm_hdmi_mode_timing_info *timing;
 
 	timing = panel->vid_cfg.timing;
@@ -342,7 +342,7 @@
 	u8  avi_iframe[AVI_MAX_DATA_BYTES] = {0};
 	u8 checksum;
 	u32 sum, reg_val;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 	struct hdmi_avi_infoframe_config *avi;
 	struct msm_hdmi_mode_timing_info *timing;
 
@@ -477,7 +477,7 @@
 	u32 sum, reg_val;
 	u32 hdmi_vic, hdmi_video_format, s3d_struct = 0;
 	struct hdmi_panel *panel = input;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 
 	/* HDMI Spec 1.4a Table 8-10 */
 	vs_iframe[0] = 0x81; /* type */
@@ -564,7 +564,7 @@
 	u32 packet_control = 0;
 	u8 *vendor_name = NULL;
 	u8 *product_description = NULL;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 
 	vendor_name = panel->spd_vendor_name;
 	product_description = panel->spd_product_description;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
index 4685b4e..50e168a 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
@@ -73,7 +73,7 @@
  * @version:  hardware version of the hdmi tx
  */
 struct hdmi_panel_init_data {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_util_ds_data *ds_data;
 	struct hdmi_panel_data *panel_data;
 	struct hdmi_tx_ddc_ctrl *ddc;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 12aba84..4f2bb09 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -117,23 +117,23 @@
 	.irq_handler = hdmi_tx_isr,
 };
 
-static struct dss_gpio hpd_gpio_config[] = {
+static struct mdss_gpio hpd_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-hpd"},
 	{0, 1, COMPATIBLE_NAME "-mux-en"},
 	{0, 0, COMPATIBLE_NAME "-mux-sel"},
 	{0, 1, COMPATIBLE_NAME "-mux-lpm"}
 };
 
-static struct dss_gpio ddc_gpio_config[] = {
+static struct mdss_gpio ddc_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-ddc-mux-sel"},
 	{0, 1, COMPATIBLE_NAME "-ddc-clk"},
 	{0, 1, COMPATIBLE_NAME "-ddc-data"}
 };
 
-static struct dss_gpio core_gpio_config[] = {
+static struct mdss_gpio core_gpio_config[] = {
 };
 
-static struct dss_gpio cec_gpio_config[] = {
+static struct mdss_gpio cec_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-cec"}
 };
 
@@ -152,7 +152,7 @@
 {
 	int rc;
 	int reg_val;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true);
 	if (rc) {
@@ -369,7 +369,7 @@
 	}
 	state = hdmi_ctrl->sdev.state;
 
-	switch_set_state(&hdmi_ctrl->sdev, val);
+	extcon_set_state_sync(&hdmi_ctrl->sdev, EXTCON_DISP_HDMI, state);
 
 	DEV_INFO("%s: cable state %s %d\n", __func__,
 		hdmi_ctrl->sdev.state == state ?
@@ -392,7 +392,7 @@
 {
 	u64 status = 0;
 	u32 wait_for_vote = 50;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -483,7 +483,7 @@
 
 static int hdmi_tx_config_5v(struct hdmi_tx_ctrl *hdmi_ctrl, bool enable)
 {
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 	int ret = 0;
 
 	if (!hdmi_ctrl) {
@@ -644,7 +644,7 @@
 
 static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	struct mdss_panel_info *pinfo;
 	int rc = 0;
 
@@ -675,7 +675,7 @@
 
 	DEV_DBG("%s: rate %ld\n", __func__, power_data->clk_config->rate);
 
-	msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk);
+	msm_mdss_clk_set_rate(power_data->clk_config, power_data->num_clk);
 end:
 	return rc;
 }
@@ -736,7 +736,7 @@
 {
 	int sim_mode, rc;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
 
@@ -1222,7 +1222,7 @@
 {
 	int read, ret;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 
 	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
 	if (!hdmi_ctrl) {
@@ -1333,7 +1333,7 @@
 
 static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, bool set)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 av_mute_status;
 	bool av_pkt_en = false;
 
@@ -1374,7 +1374,7 @@
 
 static bool hdmi_tx_is_encryption_set(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	bool enc_en = true;
 	u32 reg_val;
 
@@ -1960,7 +1960,7 @@
 
 static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	struct mdss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 
 	return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
 } /* hdmi_tx_is_controller_on */
@@ -2096,7 +2096,7 @@
 static void hdmi_tx_hpd_int_work(struct work_struct *work)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	int rc = -EINVAL;
 	int retry = MAX_EDID_READ_RETRY;
 
@@ -2149,7 +2149,7 @@
 static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	u32 hdmi_disabled, hdcp_disabled, reg_val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	int ret = 0;
 
 	if (!hdmi_ctrl) {
@@ -2208,7 +2208,7 @@
 
 static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	/* Defaults: Disable block, HDMI mode */
 	u32 reg_val = BIT(1);
 
@@ -2260,7 +2260,7 @@
 {
 	struct pinctrl_state *pin_state = NULL;
 	int rc = -EFAULT;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	u64 cur_pin_states;
 
 	if (!hdmi_ctrl) {
@@ -2357,7 +2357,7 @@
 	enum hdmi_tx_power_module_type module, int config)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	char name[MAX_CLIENT_NAME_LEN];
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
@@ -2374,7 +2374,7 @@
 	}
 
 	if (config) {
-		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to config %s vreg. Err=%d\n",
@@ -2387,13 +2387,13 @@
 			mdss_reg_bus_vote_client_create(name);
 		if (IS_ERR(hdmi_ctrl->pdata.reg_bus_clt[module])) {
 			pr_err("reg bus client create failed\n");
-			msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 			rc = PTR_ERR(hdmi_ctrl->pdata.reg_bus_clt[module]);
 			goto exit;
 		}
 
-		rc = msm_dss_get_clk(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_get_clk(&hdmi_ctrl->pdev->dev,
 			power_data->clk_config, power_data->num_clk);
 		if (rc) {
 			DEV_ERR("%s: Failed to get %s clk. Err=%d\n",
@@ -2402,16 +2402,16 @@
 			mdss_reg_bus_vote_client_destroy(
 				hdmi_ctrl->pdata.reg_bus_clt[module]);
 			hdmi_ctrl->pdata.reg_bus_clt[module] = NULL;
-			msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 		}
 	} else {
-		msm_dss_put_clk(power_data->clk_config, power_data->num_clk);
+		msm_mdss_put_clk(power_data->clk_config, power_data->num_clk);
 		mdss_reg_bus_vote_client_destroy(
 			hdmi_ctrl->pdata.reg_bus_clt[module]);
 		hdmi_ctrl->pdata.reg_bus_clt[module] = NULL;
 
-		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 		if (rc)
 			DEV_ERR("%s: Fail to deconfig %s vreg. Err=%d\n",
@@ -2427,7 +2427,7 @@
 {
 	int i;
 	int rc = 0;
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
 		DEV_ERR("%s: Error: invalid input\n", __func__);
@@ -2473,7 +2473,7 @@
 	enum hdmi_tx_power_module_type module, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
 		DEV_ERR("%s: Error: invalid input\n", __func__);
@@ -2495,7 +2495,7 @@
 	}
 
 	if (enable && !hdmi_ctrl->power_data_enable[module]) {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 			power_data->num_vreg, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
@@ -2510,7 +2510,7 @@
 			goto error;
 		}
 
-		rc = msm_dss_enable_gpio(power_data->gpio_config,
+		rc = msm_mdss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
@@ -2520,7 +2520,7 @@
 		mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 			VOTE_INDEX_LOW);
 
-		rc = msm_dss_clk_set_rate(power_data->clk_config,
+		rc = msm_mdss_clk_set_rate(power_data->clk_config,
 			power_data->num_clk);
 		if (rc) {
 			DEV_ERR("%s: failed to set clks rate for %s. err=%d\n",
@@ -2528,7 +2528,7 @@
 			goto disable_gpio;
 		}
 
-		rc = msm_dss_enable_clk(power_data->clk_config,
+		rc = msm_mdss_enable_clk(power_data->clk_config,
 			power_data->num_clk, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable clks for %s. Error=%d\n",
@@ -2539,14 +2539,14 @@
 	} else if (!enable && hdmi_ctrl->power_data_enable[module] &&
 		(!hdmi_tx_is_cec_wakeup_en(hdmi_ctrl) ||
 		((module != HDMI_TX_HPD_PM) && (module != HDMI_TX_CEC_PM)))) {
-		msm_dss_enable_clk(power_data->clk_config,
+		msm_mdss_enable_clk(power_data->clk_config,
 			power_data->num_clk, 0);
 		mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 			VOTE_INDEX_DISABLE);
-		msm_dss_enable_gpio(power_data->gpio_config,
+		msm_mdss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 0);
 		hdmi_tx_pinctrl_set_state(hdmi_ctrl, module, 0);
-		msm_dss_enable_vreg(power_data->vreg_config,
+		msm_mdss_enable_vreg(power_data->vreg_config,
 			power_data->num_vreg, 0);
 		hdmi_ctrl->power_data_enable[module] = false;
 	}
@@ -2556,9 +2556,9 @@
 disable_gpio:
 	mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 		VOTE_INDEX_DISABLE);
-	msm_dss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
+	msm_mdss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
 disable_vreg:
-	msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
+	msm_mdss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
 error:
 	return rc;
 } /* hdmi_tx_enable_power */
@@ -2607,7 +2607,7 @@
 	unsigned int phy_reset_polarity = 0x0;
 	unsigned int pll_reset_polarity = 0x0;
 	unsigned int val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -2803,7 +2803,7 @@
 	return hpd;
 }
 
-int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+int msm_mdss_hdmi_register_audio_codec(struct platform_device *pdev,
 	struct msm_hdmi_audio_codec_ops *ops)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -2819,7 +2819,7 @@
 
 	return 0;
 } /* hdmi_tx_audio_register */
-EXPORT_SYMBOL(msm_hdmi_register_audio_codec);
+EXPORT_SYMBOL(msm_mdss_hdmi_register_audio_codec);
 
 static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
@@ -2865,7 +2865,7 @@
 static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
 	bool polarity)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	bool cable_sense;
 
 	if (!hdmi_ctrl) {
@@ -2913,7 +2913,7 @@
 
 static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	void *pdata =  NULL;
 
 	if (!hdmi_ctrl) {
@@ -3041,7 +3041,7 @@
 static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	int rc = 0;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	unsigned long flags;
 
 	if (!hdmi_ctrl) {
@@ -3091,7 +3091,7 @@
 {
 	u32 reg_val;
 	int rc = 0;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -3114,7 +3114,7 @@
 			return rc;
 		}
 
-		dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
+		mdss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
 
 		if (!hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
 			hdmi_tx_set_mode(hdmi_ctrl, false);
@@ -3213,7 +3213,7 @@
 
 static irqreturn_t hdmi_tx_isr(int irq, void *data)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
 	unsigned long flags;
 	u32 hpd_current_state;
@@ -3304,7 +3304,7 @@
 	hdmi_ctrl->hdcp_ops = NULL;
 	hdmi_ctrl->hdcp_data = NULL;
 
-	switch_dev_unregister(&hdmi_ctrl->sdev);
+	extcon_dev_unregister(&hdmi_ctrl->sdev);
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
 	mutex_destroy(&hdmi_ctrl->tx_lock);
@@ -3407,7 +3407,7 @@
 	}
 
 	hdmi_ctrl->sdev.name = "hdmi";
-	rc = switch_dev_register(&hdmi_ctrl->sdev);
+	rc = extcon_set_state_sync(&hdmi_ctrl->sdev, EXTCON_DISP_HDMI, false);
 	if (rc) {
 		DEV_ERR("%s: display switch registration failed\n", __func__);
 		goto end;
@@ -3581,7 +3581,7 @@
 	return 0;
 
 primary_err:
-	switch_dev_unregister(&hdmi_ctrl->sdev);
+	extcon_dev_unregister(&hdmi_ctrl->sdev);
 switch_err:
 	hdmi_tx_deinit_features(hdmi_ctrl, HDMI_TX_FEAT_MAX);
 init_err:
@@ -3854,7 +3854,7 @@
 	/* IO */
 	for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
 		if (hdmi_ctrl->pdata.io[i].base)
-			msm_dss_iounmap(&hdmi_ctrl->pdata.io[i]);
+			msm_mdss_iounmap(&hdmi_ctrl->pdata.io[i]);
 	}
 } /* hdmi_tx_deinit_resource */
 
@@ -3874,7 +3874,7 @@
 
 	/* IO */
 	for (i = 0; i < HDMI_TX_MAX_IO; i++) {
-		rc = msm_dss_ioremap_byname(hdmi_ctrl->pdev, &pdata->io[i],
+		rc = msm_mdss_ioremap_byname(hdmi_ctrl->pdev, &pdata->io[i],
 			hdmi_tx_io_name(i));
 		if (rc) {
 			DEV_DBG("%s: '%s' remap failed or not available\n",
@@ -3903,7 +3903,7 @@
 } /* hdmi_tx_init_resource */
 
 static void hdmi_tx_put_dt_clk_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -3919,7 +3919,7 @@
 
 /* todo: once clk are moved to device tree then change this implementation */
 static int hdmi_tx_get_dt_clk_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int rc = 0;
 
@@ -3933,7 +3933,7 @@
 	switch (module_type) {
 	case HDMI_TX_HPD_PM:
 		mp->num_clk = 4;
-		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct mdss_clk) *
 			mp->num_clk, GFP_KERNEL);
 		if (!mp->clk_config) {
 			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
@@ -3966,7 +3966,7 @@
 
 	case HDMI_TX_CORE_PM:
 		mp->num_clk = 1;
-		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct mdss_clk) *
 			mp->num_clk, GFP_KERNEL);
 		if (!mp->clk_config) {
 			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
@@ -4005,7 +4005,7 @@
 } /* hdmi_tx_get_dt_clk_data */
 
 static void hdmi_tx_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -4020,7 +4020,7 @@
 } /* hdmi_tx_put_dt_vreg_data */
 
 static int hdmi_tx_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int i, j, rc = 0;
 	int dt_vreg_total = 0, mod_vreg_total = 0;
@@ -4085,7 +4085,7 @@
 
 	if (mod_vreg_total > 0) {
 		mp->num_vreg = mod_vreg_total;
-		mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+		mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 			mod_vreg_total, GFP_KERNEL);
 		if (!mp->vreg_config) {
 			DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
@@ -4198,7 +4198,7 @@
 } /* hdmi_tx_get_dt_vreg_data */
 
 static void hdmi_tx_put_dt_gpio_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -4213,11 +4213,11 @@
 } /* hdmi_tx_put_dt_gpio_data */
 
 static int hdmi_tx_get_dt_gpio_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int i, j;
 	int mp_gpio_cnt = 0, gpio_list_size = 0;
-	struct dss_gpio *gpio_list = NULL;
+	struct mdss_gpio *gpio_list = NULL;
 	struct device_node *of_node = NULL;
 
 	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
@@ -4264,7 +4264,7 @@
 	DEV_DBG("%s: mp_gpio_cnt = %d\n", __func__, mp_gpio_cnt);
 	mp->num_gpio = mp_gpio_cnt;
 
-	mp->gpio_config = devm_kzalloc(dev, sizeof(struct dss_gpio) *
+	mp->gpio_config = devm_kzalloc(dev, sizeof(struct mdss_gpio) *
 		mp_gpio_cnt, GFP_KERNEL);
 	if (!mp->gpio_config) {
 		DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
@@ -4283,7 +4283,7 @@
 			continue;
 		}
 		memcpy(&mp->gpio_config[j], &gpio_list[i],
-			sizeof(struct dss_gpio));
+			sizeof(struct mdss_gpio));
 
 		mp->gpio_config[j].gpio = (unsigned int)gpio;
 
@@ -4531,17 +4531,17 @@
 
 	if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
 		for (i = 0; i < HDMI_TX_MAX_PM; i++) {
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				hdmi_ctrl->pdata.power_data[i].vreg_config,
 				hdmi_ctrl->pdata.power_data[i].num_vreg, 1);
 
 			hdmi_tx_pinctrl_set_state(hdmi_ctrl, i, 1);
 
-			msm_dss_enable_gpio(
+			msm_mdss_enable_gpio(
 				hdmi_ctrl->pdata.power_data[i].gpio_config,
 				hdmi_ctrl->pdata.power_data[i].num_gpio, 1);
 
-			msm_dss_enable_clk(
+			msm_mdss_enable_clk(
 				hdmi_ctrl->pdata.power_data[i].clk_config,
 				hdmi_ctrl->pdata.power_data[i].num_clk, 1);
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index e55aaea..6a13c75 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -13,7 +13,7 @@
 #ifndef __MDSS_HDMI_TX_H__
 #define __MDSS_HDMI_TX_H__
 
-#include <linux/switch.h>
+#include <linux/extcon.h>
 #include "mdss_hdmi_util.h"
 #include "mdss_hdmi_panel.h"
 #include "mdss_cec_core.h"
@@ -41,8 +41,8 @@
 	bool primary;
 	bool cont_splash_enabled;
 	bool cond_power_on;
-	struct dss_io_data io[HDMI_TX_MAX_IO];
-	struct dss_module_power power_data[HDMI_TX_MAX_PM];
+	struct mdss_io_data io[HDMI_TX_MAX_IO];
+	struct mdss_module_power power_data[HDMI_TX_MAX_PM];
 	struct reg_bus_client *reg_bus_clt[HDMI_TX_MAX_PM];
 	/* bitfield representing each module's pin state */
 	u64 pin_states;
@@ -72,7 +72,7 @@
 	struct mutex tx_lock;
 	struct list_head cable_notify_handlers;
 	struct kobject *kobj;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 	struct workqueue_struct *workq;
 	struct hdmi_util_ds_data ds_data;
 	struct completion hpd_int_done;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index 8942e71..b5bedfa 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -186,7 +186,7 @@
 {
 	u32 reg_val;
 	int rc;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!ctrl || !ctrl->io) {
 		pr_err("invalid input\n");
@@ -655,7 +655,7 @@
 		enum trigger_mode mode, bool seg)
 {
 	struct hdmi_tx_ddc_data *ddc_data = &ddc_ctrl->ddc_data;
-	struct dss_io_data *io = ddc_ctrl->io;
+	struct mdss_io_data *io = ddc_ctrl->io;
 	u32 const seg_addr = 0x60, seg_num = 0x01;
 	u32 ddc_ctrl_reg_val;
 
@@ -738,7 +738,7 @@
 	u32 reg_val, ndx, time_out_count, wait_time;
 	struct hdmi_tx_ddc_data *ddc_data;
 	int status;
-	int busy_wait_us;
+	int busy_wait_us = 0;
 
 	if (!ddc_ctrl || !ddc_ctrl->io) {
 		pr_err("invalid input\n");
@@ -886,7 +886,7 @@
 
 static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_tx_hdcp2p2_ddc_data *data;
 	u32 intr0, intr2, intr5;
 	u32 msg_size;
@@ -1022,7 +1022,7 @@
 
 static int hdmi_ddc_scrambling_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	bool scrambler_timer_off = false;
 	u32 intr2, intr5;
 
@@ -1216,7 +1216,7 @@
 	u32 time_out_count;
 	struct hdmi_tx_ddc_data *ddc_data;
 	u32 wait_time;
-	int busy_wait_us;
+	int busy_wait_us = 0;
 
 	if (!ddc_ctrl || !ddc_ctrl->io) {
 		pr_err("invalid input\n");
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h
index d26be99..ecab9d5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h
@@ -447,7 +447,7 @@
 	atomic_t write_busy_wait_done;
 	atomic_t read_busy_wait_done;
 	atomic_t rxstatus_busy_wait_done;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct completion ddc_sw_done;
 	struct hdmi_tx_ddc_data ddc_data;
 	struct hdmi_tx_hdcp2p2_ddc_data hdcp2p2_ddc_data;
diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c
index bd96c605..3117793 100644
--- a/drivers/video/fbdev/msm/mdss_io_util.c
+++ b/drivers/video/fbdev/msm/mdss_io_util.c
@@ -17,7 +17,7 @@
 #include <linux/mdss_io_util.h>
 
 #define MAX_I2C_CMDS  16
-void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
+void mdss_reg_w(struct mdss_io_data *io, u32 offset, u32 value, u32 debug)
 {
 	u32 in_val;
 
@@ -41,10 +41,10 @@
 
 			value, in_val);
 	}
-} /* dss_reg_w */
-EXPORT_SYMBOL(dss_reg_w);
+} /* mdss_reg_w */
+EXPORT_SYMBOL(mdss_reg_w);
 
-u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
+u32 mdss_reg_r(struct mdss_io_data *io, u32 offset, u32 debug)
 {
 	u32 value;
 
@@ -66,19 +66,19 @@
 			(u32)(unsigned long)(io->base + offset), value);
 
 	return value;
-} /* dss_reg_r */
-EXPORT_SYMBOL(dss_reg_r);
+} /* mdss_reg_r */
+EXPORT_SYMBOL(mdss_reg_r);
 
-void dss_reg_dump(void __iomem *base, u32 length, const char *prefix,
+void mdss_reg_dump(void __iomem *base, u32 length, const char *prefix,
 	u32 debug)
 {
 	if (debug)
 		print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
 			(void *)base, length, false);
-} /* dss_reg_dump */
-EXPORT_SYMBOL(dss_reg_dump);
+} /* mdss_reg_dump */
+EXPORT_SYMBOL(mdss_reg_dump);
 
-static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
+static struct resource *msm_mdss_get_res_byname(struct platform_device *pdev,
 	unsigned int type, const char *name)
 {
 	struct resource *res = NULL;
@@ -88,11 +88,11 @@
 		DEV_ERR("%s: '%s' resource not found\n", __func__, name);
 
 	return res;
-} /* msm_dss_get_res_byname */
-EXPORT_SYMBOL(msm_dss_get_res_byname);
+} /* msm_mdss_get_res_byname */
+EXPORT_SYMBOL(msm_mdss_get_res_byname);
 
-int msm_dss_ioremap_byname(struct platform_device *pdev,
-	struct dss_io_data *io_data, const char *name)
+int msm_mdss_ioremap_byname(struct platform_device *pdev,
+	struct mdss_io_data *io_data, const char *name)
 {
 	struct resource *res = NULL;
 
@@ -102,9 +102,9 @@
 		return -EINVAL;
 	}
 
-	res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
+	res = msm_mdss_get_res_byname(pdev, IORESOURCE_MEM, name);
 	if (!res) {
-		DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
+		DEV_ERR("%pS->%s: '%s' msm_mdss_get_res_byname failed\n",
 			__builtin_return_address(0), __func__, name);
 		return -ENODEV;
 	}
@@ -118,10 +118,10 @@
 	}
 
 	return 0;
-} /* msm_dss_ioremap_byname */
-EXPORT_SYMBOL(msm_dss_ioremap_byname);
+} /* msm_mdss_ioremap_byname */
+EXPORT_SYMBOL(msm_mdss_ioremap_byname);
 
-void msm_dss_iounmap(struct dss_io_data *io_data)
+void msm_mdss_iounmap(struct mdss_io_data *io_data)
 {
 	if (!io_data) {
 		DEV_ERR("%pS->%s: invalid input\n",
@@ -134,15 +134,15 @@
 		io_data->base = NULL;
 	}
 	io_data->len = 0;
-} /* msm_dss_iounmap */
-EXPORT_SYMBOL(msm_dss_iounmap);
+} /* msm_mdss_iounmap */
+EXPORT_SYMBOL(msm_mdss_iounmap);
 
-int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+int msm_mdss_config_vreg(struct device *dev, struct mdss_vreg *in_vreg,
 	int num_vreg, int config)
 {
 	int i = 0, rc = 0;
-	struct dss_vreg *curr_vreg = NULL;
-	enum dss_vreg_type type;
+	struct mdss_vreg *curr_vreg = NULL;
+	enum mdss_vreg_type type;
 
 	if (!in_vreg || !num_vreg)
 		return rc;
@@ -196,7 +196,7 @@
 
 vreg_unconfig:
 if (type == DSS_REG_LDO)
-	regulator_set_optimum_mode(curr_vreg->vreg, 0);
+	regulator_set_load(curr_vreg->vreg, 0);
 
 vreg_set_voltage_fail:
 	regulator_put(curr_vreg->vreg);
@@ -210,11 +210,11 @@
 		goto vreg_unconfig;
 	}
 	return rc;
-} /* msm_dss_config_vreg */
-EXPORT_SYMBOL(msm_dss_config_vreg);
+} /* msm_mdss_config_vreg */
+EXPORT_SYMBOL(msm_mdss_config_vreg);
 
-int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
-				 enum dss_vreg_mode mode)
+int msm_mdss_config_vreg_opt_mode(struct mdss_vreg *in_vreg, int num_vreg,
+				 enum mdss_vreg_mode mode)
 {
 	int i = 0, rc = 0;
 
@@ -237,7 +237,7 @@
 		DEV_DBG("%s: Setting optimum mode %d for %s (load=%d)\n",
 			__func__, mode, in_vreg[i].vreg_name,
 			in_vreg[i].load[mode]);
-		rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+		rc = regulator_set_load(in_vreg[i].vreg,
 					in_vreg[i].load[mode]);
 		if (rc < 0) {
 			DEV_ERR("%pS->%s: %s set opt mode failed. rc=%d\n",
@@ -246,7 +246,7 @@
 			goto error;
 		} else {
 			/*
-			 * regulator_set_optimum_mode can return non-zero
+			 * regulator_set_load can return non-zero
 			 * value for success. However, this API is expected
 			 * to return 0 for success.
 			 */
@@ -257,9 +257,9 @@
 error:
 	return rc;
 }
-EXPORT_SYMBOL(msm_dss_config_vreg_opt_mode);
+EXPORT_SYMBOL(msm_mdss_config_vreg_opt_mode);
 
-int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
+int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable)
 {
 	int i = 0, rc = 0;
 	bool need_sleep;
@@ -277,7 +277,7 @@
 			if (in_vreg[i].pre_on_sleep && need_sleep)
 				usleep_range(in_vreg[i].pre_on_sleep * 1000,
 					in_vreg[i].pre_on_sleep * 1000);
-			rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+			rc = regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_ENABLE]);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s set opt m fail\n",
@@ -301,7 +301,7 @@
 			if (in_vreg[i].pre_off_sleep)
 				usleep_range(in_vreg[i].pre_off_sleep * 1000,
 					in_vreg[i].pre_off_sleep * 1000);
-			regulator_set_optimum_mode(in_vreg[i].vreg,
+			regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 
 			if (regulator_is_enabled(in_vreg[i].vreg))
@@ -315,7 +315,7 @@
 	return rc;
 
 disable_vreg:
-	regulator_set_optimum_mode(in_vreg[i].vreg,
+	regulator_set_load(in_vreg[i].vreg,
 					in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 
 vreg_set_opt_mode_fail:
@@ -323,7 +323,7 @@
 		if (in_vreg[i].pre_off_sleep)
 			usleep_range(in_vreg[i].pre_off_sleep * 1000,
 				in_vreg[i].pre_off_sleep * 1000);
-		regulator_set_optimum_mode(in_vreg[i].vreg,
+		regulator_set_load(in_vreg[i].vreg,
 			in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 		regulator_disable(in_vreg[i].vreg);
 		if (in_vreg[i].post_off_sleep)
@@ -332,10 +332,10 @@
 	}
 
 	return rc;
-} /* msm_dss_enable_vreg */
-EXPORT_SYMBOL(msm_dss_enable_vreg);
+} /* msm_mdss_enable_vreg */
+EXPORT_SYMBOL(msm_mdss_enable_vreg);
 
-int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
+int msm_mdss_enable_gpio(struct mdss_gpio *in_gpio, int num_gpio, int enable)
 {
 	int i = 0, rc = 0;
 
@@ -372,10 +372,10 @@
 			gpio_free(in_gpio[i].gpio);
 
 	return rc;
-} /* msm_dss_enable_gpio */
-EXPORT_SYMBOL(msm_dss_enable_gpio);
+} /* msm_mdss_enable_gpio */
+EXPORT_SYMBOL(msm_mdss_enable_gpio);
 
-void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
+void msm_mdss_put_clk(struct mdss_clk *clk_arry, int num_clk)
 {
 	int i;
 
@@ -384,10 +384,10 @@
 			clk_put(clk_arry[i].clk);
 		clk_arry[i].clk = NULL;
 	}
-} /* msm_dss_put_clk */
-EXPORT_SYMBOL(msm_dss_put_clk);
+} /* msm_mdss_put_clk */
+EXPORT_SYMBOL(msm_mdss_put_clk);
 
-int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
+int msm_mdss_get_clk(struct device *dev, struct mdss_clk *clk_arry, int num_clk)
 {
 	int i, rc = 0;
 
@@ -405,13 +405,13 @@
 	return rc;
 
 error:
-	msm_dss_put_clk(clk_arry, num_clk);
+	msm_mdss_put_clk(clk_arry, num_clk);
 
 	return rc;
-} /* msm_dss_get_clk */
-EXPORT_SYMBOL(msm_dss_get_clk);
+} /* msm_mdss_get_clk */
+EXPORT_SYMBOL(msm_mdss_get_clk);
 
-int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
+int msm_mdss_clk_set_rate(struct mdss_clk *clk_arry, int num_clk)
 {
 	int i, rc = 0;
 
@@ -442,10 +442,10 @@
 	}
 
 	return rc;
-} /* msm_dss_clk_set_rate */
-EXPORT_SYMBOL(msm_dss_clk_set_rate);
+} /* msm_mdss_clk_set_rate */
+EXPORT_SYMBOL(msm_mdss_clk_set_rate);
 
-int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
+int msm_mdss_enable_clk(struct mdss_clk *clk_arry, int num_clk, int enable)
 {
 	int i, rc = 0;
 
@@ -469,7 +469,7 @@
 			}
 
 			if (rc) {
-				msm_dss_enable_clk(&clk_arry[i],
+				msm_mdss_enable_clk(&clk_arry[i],
 					i, false);
 				break;
 			}
@@ -490,8 +490,8 @@
 	}
 
 	return rc;
-} /* msm_dss_enable_clk */
-EXPORT_SYMBOL(msm_dss_enable_clk);
+} /* msm_mdss_enable_clk */
+EXPORT_SYMBOL(msm_mdss_enable_clk);
 
 
 int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 73324489..13a4bb6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -114,7 +114,7 @@
 	.irq_handler = NULL,
 };
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 #define MDP_REG_BUS_VECTOR_ENTRY(ab_val, ib_val)	\
 	{						\
 		.src = MSM_BUS_MASTER_AMPSS_M0,		\
@@ -354,7 +354,6 @@
 	/* check here if virq is a valid interrupt line */
 	irq_set_chip_and_handler(virq, &mdss_irq_chip, handle_level_irq);
 	irq_set_chip_data(virq, mdata);
-	set_irq_flags(virq, IRQF_VALID);
 	return 0;
 }
 
@@ -418,7 +417,7 @@
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata)
 {
 	struct msm_bus_scale_pdata *reg_bus_pdata;
@@ -812,7 +811,7 @@
 
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
 {
-	int irq_idx, idx;
+	int irq_idx;
 	unsigned long irq_flags;
 	int ret = 0;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -831,7 +830,7 @@
 	spin_lock_irqsave(&mdp_lock, irq_flags);
 	if (mdata->mdp_irq_mask[irq.reg_idx] & irq.irq_mask) {
 		pr_warn("MDSS MDP IRQ-0x%x is already set, mask=%x\n",
-				irq.irq_mask, mdata->mdp_irq_mask[idx]);
+			irq.irq_mask, mdata->mdp_irq_mask[irq.reg_idx]);
 		ret = -EBUSY;
 	} else {
 		pr_debug("MDP IRQ mask old=%x new=%x\n",
@@ -1182,7 +1181,8 @@
 		if (IS_ERR_VALUE(clk_rate)) {
 			pr_err("unable to round rate err=%ld\n", clk_rate);
 		} else if (clk_rate != clk_get_rate(clk)) {
-			if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
+			if (IS_ERR_VALUE((unsigned long)
+					 clk_set_rate(clk, clk_rate)))
 				pr_err("clk_set_rate failed\n");
 			else
 				pr_debug("mdp clk rate=%lu\n", clk_rate);
@@ -1374,7 +1374,7 @@
 	}
 	mutex_unlock(&mdp_iommu_ref_cnt_lock);
 
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		return rc;
 	else
 		return mdata->iommu_ref_cnt;
@@ -1431,7 +1431,7 @@
 
 	pr_debug("called from %pS\n", __builtin_return_address(0));
 	rc = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		pr_err("mdss iommu attach failed rc=%d\n", rc);
 		goto end;
 	}
@@ -1546,7 +1546,7 @@
 				VOTE_INDEX_LOW);
 
 			rc = mdss_iommu_ctrl(1);
-			if (IS_ERR_VALUE(rc))
+			if (IS_ERR_VALUE((unsigned long)rc))
 				pr_err("IOMMU attach failed\n");
 
 			/* Active+Sleep */
@@ -1665,7 +1665,7 @@
 	pr_debug("max mdp clk rate=%d\n", mdata->max_mdp_clk_rate);
 
 	ret = devm_request_irq(&mdata->pdev->dev, mdss_mdp_hw.irq_info->irq,
-				mdss_irq_handler, IRQF_DISABLED, "MDSS", mdata);
+				mdss_irq_handler, 0, "MDSS", mdata);
 	if (ret) {
 		pr_err("mdp request_irq() failed!\n");
 		return ret;
@@ -2124,6 +2124,7 @@
 			return -EINVAL;
 	}
 
+	mutex_init(&mdata->scaler_off->scaler_lock);
 	return 0;
 }
 
@@ -2630,13 +2631,7 @@
 	mdss_res->mdss_util->panel_intf_type = mdss_panel_intf_type;
 	mdss_res->mdss_util->panel_intf_status = mdss_panel_get_intf_status;
 
-	if (mdss_res->mdss_util->param_check(mdss_mdp_panel)) {
-		mdss_res->mdss_util->display_disabled = true;
-		mdss_res->mdss_util->mdp_probe_done = true;
-		return 0;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");
 	if (rc) {
 		pr_err("unable to map MDP base\n");
 		goto probe_done;
@@ -2645,7 +2640,7 @@
 		(int) (unsigned long) mdata->mdss_io.base,
 		mdata->mdss_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &mdata->vbif_io, "vbif_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_io, "vbif_phys");
 	if (rc) {
 		pr_err("unable to map MDSS VBIF base\n");
 		goto probe_done;
@@ -2654,7 +2649,8 @@
 		(int) (unsigned long) mdata->vbif_io.base,
 		mdata->vbif_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &mdata->vbif_nrt_io, "vbif_nrt_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_nrt_io,
+				     "vbif_nrt_phys");
 	if (rc)
 		pr_debug("unable to map MDSS VBIF non-realtime base\n");
 	else
@@ -2834,7 +2830,7 @@
 		num_of_display_on, intf_sel);
 
 probe_done:
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		if (!num_of_display_on)
 			mdss_mdp_footswitch_ctrl_splash(false);
 
@@ -2850,8 +2846,8 @@
 	return rc;
 }
 
-static void mdss_mdp_parse_dt_regs_array(const u32 *arr, struct dss_io_data *io,
-	struct mdss_hw_settings *hws, int count)
+static void mdss_mdp_parse_dt_regs_array(const u32 *arr,
+	struct mdss_io_data *io, struct mdss_hw_settings *hws, int count)
 {
 	u32 len, reg;
 	int i;
@@ -3261,28 +3257,28 @@
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_VIG, "vig",
 			&mdata->vig_pipes, mdata->nvig_pipes, 0);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->nvig_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_RGB, "rgb",
 			&mdata->rgb_pipes, mdata->nrgb_pipes,
 			mdata->nvig_pipes);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->nrgb_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_DMA, "dma",
 			&mdata->dma_pipes, mdata->ndma_pipes,
 			mdata->nvig_pipes + mdata->nrgb_pipes);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->ndma_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_CURSOR,
 			"cursor", &mdata->cursor_pipes, mdata->ncursor_pipes,
 			0);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->ncursor_pipes = rc;
 
@@ -4282,7 +4278,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev)
 {
 	int rc, paths;
@@ -4358,6 +4354,7 @@
 	return rc;
 }
 #else
+__maybe_unused
 static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev)
 {
 	return 0;
@@ -4975,7 +4972,7 @@
 #define mdss_mdp_resume NULL
 #endif
 
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
 static int mdss_mdp_runtime_resume(struct device *dev)
 {
 	struct mdss_data_type *mdata = dev_get_drvdata(dev);
@@ -5033,9 +5030,11 @@
 
 static const struct dev_pm_ops mdss_mdp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(mdss_mdp_pm_suspend, mdss_mdp_pm_resume)
+#ifdef CONFIG_PM
 	SET_RUNTIME_PM_OPS(mdss_mdp_runtime_suspend,
 			mdss_mdp_runtime_resume,
 			mdss_mdp_runtime_idle)
+#endif
 };
 
 static int mdss_mdp_remove(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index eb85ceb..4307119 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -648,7 +648,6 @@
 
 	/* vsync handler for FRC */
 	struct mdss_mdp_vsync_handler frc_vsync_handler;
-	bool commit_in_progress;
 };
 
 struct mdss_mdp_mixer {
@@ -1010,7 +1009,7 @@
 	u32 splash_mem_size;
 	u32 sd_enabled;
 
-	struct sw_sync_timeline *vsync_timeline;
+	struct mdss_timeline *vsync_timeline;
 	struct mdss_mdp_vsync_handler vsync_retire_handler;
 	int retire_cnt;
 	bool kickoff_released;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 6e4a6b3..4f17310 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -942,6 +942,7 @@
 	if (!ctl || !ctl->mdata)
 		return 0;
 
+	mdata = ctl->mdata;
 	mixer = pipe->mixer_left;
 	if (!mixer)
 		return -EINVAL;
@@ -2670,7 +2671,7 @@
 	ktime_t current_time = ktime_get();
 
 	if (!ctl->ops.read_line_cnt_fnc)
-		return -ENOTSUP;
+		return -ENOTSUPP;
 
 	pinfo = &ctl->panel_data->panel_info;
 	if (!pinfo)
@@ -5524,9 +5525,7 @@
 		} else {
 			sctl_flush_bits = sctl->flush_bits;
 		}
-		sctl->commit_in_progress = true;
 	}
-	ctl->commit_in_progress = true;
 	ctl_flush_bits = ctl->flush_bits;
 
 	ATRACE_END("postproc_programming");
@@ -5666,15 +5665,11 @@
 
 	ATRACE_BEGIN("flush_kickoff");
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits);
-	if (sctl) {
-		if (sctl_flush_bits) {
-			mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
-				sctl_flush_bits);
-			sctl->flush_bits = 0;
-		}
-		sctl->commit_in_progress = false;
+	if (sctl && sctl_flush_bits) {
+		mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
+				   sctl_flush_bits);
+		sctl->flush_bits = 0;
 	}
-	ctl->commit_in_progress = false;
 
 	MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits,
 		split_lm_valid);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c
index b641ccb..6024ea1 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_debug.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c
@@ -1414,7 +1414,7 @@
 		seq_printf(s, "vsync: %08u \tunderrun: %08u\n",
 				ctl->vsync_cnt, ctl->underrun_cnt);
 		if (ctl->mfd) {
-			seq_printf(s, "user_bl: %08u \tmod_bl: %08u\n",
+			seq_printf(s, "user_bl: %08llu \tmod_bl: %08u\n",
 				ctl->mfd->bl_level, ctl->mfd->bl_level_scaled);
 		}
 	} else {
@@ -1495,11 +1495,11 @@
 	debugfs_create_file("safe_stat", 0644, mdd->root, mdata,
 			&mdss_debugfs_safe_stats_fops);
 	debugfs_create_bool("serialize_wait4pp", 0644, mdd->root,
-		(u32 *)&mdata->serialize_wait4pp);
+		(bool *)&mdata->serialize_wait4pp);
 	debugfs_create_bool("wait4autorefresh", 0644, mdd->root,
-		(u32 *)&mdata->wait4autorefresh);
+		(bool *)&mdata->wait4autorefresh);
 	debugfs_create_bool("enable_gate", 0644, mdd->root,
-		(u32 *)&mdata->enable_gate);
+		(bool *)&mdata->enable_gate);
 
 	debugfs_create_u32("color0", 0644, mdd->bordercolor,
 		(u32 *)&mdata->bcolor0);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 84218e3..7a0542a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1206,7 +1206,6 @@
 			       atomic_read(&ctx->koff_cnt));
 		if (sync_ppdone) {
 			atomic_inc(&ctx->pp_done_cnt);
-			if (!ctl->commit_in_progress)
 				schedule_work(&ctx->pp_done_work);
 
 			mdss_mdp_resource_control(ctl,
@@ -3080,7 +3079,7 @@
 
 	pr_debug("%s: turn off interface clocks\n", __func__);
 	ret = mdss_mdp_cmd_stop_sub(ctl, panel_power_state);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("%s: unable to stop interface: %d\n",
 				__func__, ret);
 		goto end;
@@ -3088,7 +3087,7 @@
 
 	if (sctl) {
 		mdss_mdp_cmd_stop_sub(sctl, panel_power_state);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("%s: unable to stop slave intf: %d\n",
 					__func__, ret);
 			goto end;
@@ -3127,7 +3126,7 @@
 	ctl->ops.reconfigure = NULL;
 
 end:
-	if (!IS_ERR_VALUE(ret)) {
+	if (!IS_ERR_VALUE((unsigned long)ret)) {
 		struct mdss_mdp_cmd_ctx *sctx = NULL;
 
 		ctx->panel_power_state = panel_power_state;
@@ -3505,7 +3504,7 @@
 	/* Command mode is supported only starting at INTF1 */
 	session = ctl->intf_num - MDSS_MDP_INTF1;
 	ret = mdss_mdp_cmd_intfs_setup(ctl, session);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to set cmd interface: %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 453fe28..7b69aa3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -926,7 +926,7 @@
 
 	intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
 	ret = mdss_mdp_video_intfs_stop(ctl, ctl->panel_data, intfs_num);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to stop video interface: %d\n", ret);
 		return ret;
 	}
@@ -1512,7 +1512,7 @@
 		}
 
 		rc = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("IOMMU attach failed\n");
 			return rc;
 		}
@@ -2166,7 +2166,7 @@
 
 	intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
 	ret = mdss_mdp_video_intfs_setup(ctl, ctl->panel_data, intfs_num);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to set video interface: %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index b155870..46f25dd 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -794,7 +794,7 @@
 	mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("IOMMU attach failed\n");
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 49a7bf4..b1c8041 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -21,8 +21,6 @@
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
 #include <linux/memblock.h>
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/file.h>
 
 #include <soc/qcom/event_timer.h>
@@ -31,6 +29,7 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_wfd.h"
+#include "mdss_sync.h"
 
 #define CHECK_LAYER_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -704,13 +703,13 @@
 	return ret;
 }
 
-static struct sync_fence *__create_fence(struct msm_fb_data_type *mfd,
+static struct mdss_fence *__create_fence(struct msm_fb_data_type *mfd,
 	struct msm_sync_pt_data *sync_pt_data, u32 fence_type,
 	int *fence_fd, int value)
 {
 	struct mdss_overlay_private *mdp5_data;
 	struct mdss_mdp_ctl *ctl;
-	struct sync_fence *sync_fence = NULL;
+	struct mdss_fence *sync_fence = NULL;
 	char fence_name[32];
 
 	mdp5_data = mfd_to_mdp5_data(mfd);
@@ -736,16 +735,23 @@
 	if ((fence_type == MDSS_MDP_RETIRE_FENCE) &&
 		(mfd->panel.type == MIPI_CMD_PANEL)) {
 		if (mdp5_data->vsync_timeline) {
-			value = mdp5_data->vsync_timeline->value + 1 +
-				mdp5_data->retire_cnt++;
+			value = 1 + mdp5_data->retire_cnt++;
 			sync_fence = mdss_fb_sync_get_fence(
-				mdp5_data->vsync_timeline, fence_name, value);
+				mdp5_data->vsync_timeline, fence_name,
+				value);
 		} else {
 			return ERR_PTR(-EPERM);
 		}
 	} else {
-		sync_fence = mdss_fb_sync_get_fence(sync_pt_data->timeline,
-			fence_name, value);
+		if (fence_type == MDSS_MDP_RETIRE_FENCE)
+			sync_fence = mdss_fb_sync_get_fence(
+						sync_pt_data->timeline_retire,
+						fence_name, value);
+		else
+			sync_fence = mdss_fb_sync_get_fence(
+						sync_pt_data->timeline,
+						fence_name, value);
+
 	}
 
 	if (IS_ERR_OR_NULL(sync_fence)) {
@@ -754,14 +760,15 @@
 	}
 
 	/* get fence fd */
-	*fence_fd = get_unused_fd_flags(0);
+	*fence_fd = mdss_get_sync_fence_fd(sync_fence);
 	if (*fence_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed error:0x%x\n",
 			fence_name, *fence_fd);
-		sync_fence_put(sync_fence);
+		mdss_put_sync_fence(sync_fence);
 		sync_fence = NULL;
 		goto end;
 	}
+	pr_debug("%s:val=%d\n", mdss_get_sync_fence_name(sync_fence), value);
 
 end:
 	return sync_fence;
@@ -777,7 +784,7 @@
 static int __handle_buffer_fences(struct msm_fb_data_type *mfd,
 	struct mdp_layer_commit_v1 *commit, struct mdp_input_layer *layer_list)
 {
-	struct sync_fence *fence, *release_fence, *retire_fence;
+	struct mdss_fence *fence, *release_fence, *retire_fence;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
 	struct mdp_input_layer *layer;
 	int value;
@@ -803,7 +810,7 @@
 		if (layer->buffer.fence < 0)
 			continue;
 
-		fence = sync_fence_fdget(layer->buffer.fence);
+		fence = mdss_get_fd_sync_fence(layer->buffer.fence);
 		if (!fence) {
 			pr_err("%s: sync fence get failed! fd=%d\n",
 				sync_pt_data->fence_name, layer->buffer.fence);
@@ -816,7 +823,7 @@
 	if (ret)
 		goto sync_fence_err;
 
-	value = sync_pt_data->timeline_value + sync_pt_data->threshold +
+	value = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
 
 	release_fence = __create_fence(mfd, sync_pt_data,
@@ -835,21 +842,18 @@
 		goto retire_fence_err;
 	}
 
-	sync_fence_install(release_fence, commit->release_fence);
-	sync_fence_install(retire_fence, commit->retire_fence);
-
 	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
 
 retire_fence_err:
 	put_unused_fd(commit->release_fence);
-	sync_fence_put(release_fence);
+	mdss_put_sync_fence(release_fence);
 release_fence_err:
 	commit->retire_fence = -1;
 	commit->release_fence = -1;
 sync_fence_err:
 	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
-		sync_fence_put(sync_pt_data->acq_fen[i]);
+		mdss_put_sync_fence(sync_pt_data->acq_fen[i]);
 	sync_pt_data->acq_fen_cnt = 0;
 
 	mutex_unlock(&sync_pt_data->sync_mutex);
@@ -1522,7 +1526,7 @@
 	int cnt = 1;
 
 	mode = __multirect_layer_flags_to_mode(layer_list[ndx].flags);
-	if (IS_ERR_VALUE(mode))
+	if (IS_ERR_VALUE((unsigned long)mode))
 		return mode;
 
 	pr_debug("layer #%d pipe_ndx=%d multirect mode=%d\n",
@@ -1557,7 +1561,7 @@
 
 			mode = __multirect_layer_flags_to_mode(
 					layer_list[i].flags);
-			if (IS_ERR_VALUE(mode))
+			if (IS_ERR_VALUE((unsigned long)mode))
 				return mode;
 
 			if (mode != vinfo[0]->multirect.mode) {
@@ -1598,7 +1602,7 @@
 
 	cnt = __update_multirect_info(mfd, validate_info_list,
 			layer_list, ndx, layer_cnt);
-	if (IS_ERR_VALUE(cnt))
+	if (IS_ERR_VALUE((unsigned long)cnt))
 		return cnt;
 
 	if (cnt <= 1) {
@@ -1619,7 +1623,7 @@
 	}
 
 	rc = __multirect_validate_mode(mfd, layers, cnt);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		return rc;
 
 	return 0;
@@ -1647,7 +1651,7 @@
 	u32 mixer_mux, dst_x;
 	int layer_count = commit->input_layer_cnt;
 
-	struct mdss_mdp_pipe *pipe, *tmp, *left_blend_pipe;
+	struct mdss_mdp_pipe *pipe = NULL, *tmp, *left_blend_pipe;
 	struct mdss_mdp_pipe *right_plist[MAX_PIPES_PER_LM] = {0};
 	struct mdss_mdp_pipe *left_plist[MAX_PIPES_PER_LM] = {0};
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -1867,7 +1871,7 @@
 			rec_destroy_ndx[rect_num] |= pipe->ndx;
 
 		ret = mdss_mdp_pipe_map(pipe);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Unable to map used pipe%d ndx=%x\n",
 				pipe->num, pipe->ndx);
 			layer->error_code = ret;
@@ -1937,7 +1941,7 @@
 			rec_destroy_ndx[0], rec_destroy_ndx[1], ret);
 	mutex_lock(&mdp5_data->list_lock);
 	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_used, list) {
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			if (((pipe->ndx & rec_release_ndx[0]) &&
 						(pipe->multirect.num == 0)) ||
 					((pipe->ndx & rec_release_ndx[1]) &&
@@ -2062,7 +2066,7 @@
 		if (!validate_info_list[i].layer) {
 			ret = __update_multirect_info(mfd, validate_info_list,
 						   layer_list, i, layer_count);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("error updating multirect config. ret=%d i=%d\n",
 					ret, i);
 				goto end;
@@ -2180,7 +2184,7 @@
 	struct mdss_mdp_wfd *wfd = NULL;
 	struct mdp_output_layer *output_layer = NULL;
 	struct mdss_mdp_wfd_data *data = NULL;
-	struct sync_fence *fence = NULL;
+	struct mdss_fence *fence = NULL;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
 
 	if (!mfd || !commit)
@@ -2208,7 +2212,8 @@
 			return PTR_ERR(data);
 
 		if (output_layer->buffer.fence >= 0) {
-			fence = sync_fence_fdget(output_layer->buffer.fence);
+			fence = mdss_get_fd_sync_fence(
+						output_layer->buffer.fence);
 			if (!fence) {
 				pr_err("fail to get output buffer fence\n");
 				rc = -EINVAL;
@@ -2249,7 +2254,7 @@
 
 input_layer_err:
 	if (fence)
-		sync_fence_put(fence);
+		mdss_put_sync_fence(fence);
 fence_get_err:
 	if (data)
 		mdss_mdp_wfd_remove_data(wfd, data);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index f69f5b3..3ae59a2 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -25,8 +25,8 @@
 #include <linux/msm_mdp.h>
 #include <linux/memblock.h>
 #include <linux/sort.h>
-#include <linux/sw_sync.h>
 #include <linux/kmemleak.h>
+#include <linux/kthread.h>
 #include <asm/div64.h>
 
 #include <soc/qcom/event_timer.h>
@@ -38,6 +38,7 @@
 #include "mdss_smmu.h"
 #include "mdss_mdp_wfd.h"
 #include "mdss_dsi_clk.h"
+#include "mdss_sync.h"
 
 #define VSYNC_PERIOD 16
 #define BORDERFILL_NDX	0x0BF000BF
@@ -760,7 +761,7 @@
 		}
 
 		ret = mdss_mdp_pipe_map(pipe);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Unable to map used pipe%d ndx=%x\n",
 					pipe->num, pipe->ndx);
 			return ret;
@@ -1387,7 +1388,7 @@
 	if (!mdp5_data->mdata->idle_pc_enabled ||
 		(mfd->panel_info->type != MIPI_CMD_PANEL)) {
 		rc = pm_runtime_get_sync(&mfd->pdev->dev);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("unable to resume with pm_runtime_get_sync rc=%d\n",
 				rc);
 			goto end;
@@ -1404,7 +1405,7 @@
 	 */
 	if (!mfd->panel_info->cont_splash_enabled) {
 		rc = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("iommu attach failed rc=%d\n", rc);
 			goto end;
 		}
@@ -1591,10 +1592,10 @@
 		 * if we reach here without errors and buf == NULL
 		 * then solid fill will be set
 		 */
-		if (!IS_ERR_VALUE(ret))
+		if (!IS_ERR_VALUE((unsigned long)ret))
 			ret = mdss_mdp_pipe_queue_data(pipe, buf);
 
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_warn("Unable to queue data for pnum=%d rect=%d\n",
 					pipe->num, pipe->multirect.num);
 
@@ -2014,7 +2015,7 @@
 {
 	int vsync_diff;
 	int round_up = 0;
-	s64 ts_diff = (cur_ts - base_ts) * display_fp1000s;
+	u64 ts_diff = (cur_ts - base_ts) * display_fp1000s;
 
 	do_div(ts_diff, 1000000);
 	vsync_diff = (int)ts_diff;
@@ -2064,7 +2065,7 @@
 	struct mdss_mdp_frc_cadence_calc *calc = &frc_info->calc;
 	struct mdss_mdp_frc_data *first = &calc->samples[0];
 	struct mdss_mdp_frc_data *last = &calc->samples[cnt-1];
-	s64 ts_diff =
+	u64 ts_diff =
 		(last->timestamp - first->timestamp)
 				* frc_info->display_fp1000s;
 	u32 fcnt_diff =
@@ -2231,7 +2232,7 @@
 
 		if (frc_info->video_stat.last_delta) {
 			video_fps_changed =
-				abs64(delta_t - frc_info->video_stat.last_delta)
+				abs(delta_t - frc_info->video_stat.last_delta)
 				> (FRC_VIDEO_FPS_CHANGE_THRESHOLD_US *
 					FRC_VIDEO_FPS_DETECT_WINDOW);
 
@@ -2883,7 +2884,7 @@
 	}
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("iommu attach failed rc=%d\n", ret);
 		mutex_unlock(&mdp5_data->ov_lock);
 		if (ctl->shared_lock)
@@ -2906,7 +2907,7 @@
 	sd_transition_state = mdp5_data->sd_transition_state;
 	if (sd_transition_state != SD_TRANSITION_NONE) {
 		ret = __config_secure_display(mdp5_data);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Secure session config failed\n");
 			goto commit_fail;
 		}
@@ -2963,7 +2964,7 @@
 	if (!mdp5_data->kickoff_released)
 		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_CTX_DONE);
 
-	if (IS_ERR_VALUE(ret))
+	if (IS_ERR_VALUE((unsigned long)ret))
 		goto commit_fail;
 
 	mutex_unlock(&mdp5_data->ov_lock);
@@ -2985,7 +2986,7 @@
 	ret = mdss_mdp_ctl_update_fps(ctl);
 	ATRACE_END("fps_update");
 
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("failed to update fps!\n");
 		goto commit_fail;
 	}
@@ -3166,7 +3167,7 @@
 	}
 
 	ret = mdss_mdp_pipe_map(pipe);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("Unable to map used pipe%d ndx=%x\n",
 				pipe->num, pipe->ndx);
 		return ret;
@@ -3192,7 +3193,7 @@
 		ret = mdss_mdp_data_get_and_validate_size(src_data, &req->data,
 			1, flags, &mfd->pdev->dev, false, DMA_TO_DEVICE,
 			&buffer);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_mdp_overlay_buf_free(mfd, src_data);
 			pr_err("src_data pmem error\n");
 		}
@@ -3435,7 +3436,7 @@
 	}
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("IOMMU attach failed\n");
 		goto clk_disable;
 	}
@@ -5095,7 +5096,7 @@
 static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
 				void __user *argp)
 {
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	struct mdp_histogram_data hist;
 	struct mdp_histogram_start_req hist_req;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -5493,7 +5494,7 @@
 			left_blend_pipe, is_single_layer);
 		req->z_order -= MDSS_MDP_STAGE_0;
 
-		if (IS_ERR_VALUE(ret))
+		if (IS_ERR_VALUE((unsigned long)ret))
 			goto validate_exit;
 
 		pr_debug("pnum:%d id:0x%x flags:0x%x dst_x:%d l_blend_pnum%d\n",
@@ -5533,7 +5534,7 @@
 	else
 		ovlist->processed_overlays = i;
 
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_debug("err=%d total_ovs:%d processed:%d left:%d right:%d\n",
 			ret, num_ovs, ovlist->processed_overlays, left_lm_ovs,
 			right_lm_ovs);
@@ -5586,7 +5587,7 @@
 	}
 
 	ret = __handle_overlay_prepare(mfd, &ovlist, overlays);
-	if (!IS_ERR_VALUE(ret)) {
+	if (!IS_ERR_VALUE((unsigned long)ret)) {
 		for (i = 0; i < ovlist.num_overlays; i++) {
 			if (copy_to_user(req_list[i], overlays + i,
 					sizeof(struct mdp_overlay))) {
@@ -5609,7 +5610,7 @@
 					  u32 cmd, void __user *argp)
 {
 	struct mdp_overlay *req = NULL;
-	int val, ret = -ENOTSUP;
+	int val, ret = -ENOTSUPP;
 	struct msmfb_metadata metadata;
 	struct mdp_pp_feature_version pp_feature_version;
 	struct msmfb_overlay_data data;
@@ -5653,7 +5654,7 @@
 		if (!ret) {
 			ret = mdss_mdp_overlay_get(mfd, req);
 
-			if (!IS_ERR_VALUE(ret))
+			if (!IS_ERR_VALUE((unsigned long)ret))
 				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 
@@ -5669,7 +5670,7 @@
 		if (!ret) {
 			ret = mdss_mdp_overlay_set(mfd, req);
 
-			if (!IS_ERR_VALUE(ret))
+			if (!IS_ERR_VALUE((unsigned long)ret))
 				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 		if (ret)
@@ -5949,7 +5950,7 @@
 	}
 
 panel_on:
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		pr_err("Failed to turn on fb%d\n", mfd->index);
 		mdss_mdp_overlay_off(mfd);
 		goto end;
@@ -6110,7 +6111,7 @@
 		 * retire_signal api checks for retire_cnt with sync_mutex lock.
 		 */
 
-		flush_kthread_work(&mdp5_data->vsync_work);
+		kthread_flush_work(&mdp5_data->vsync_work);
 	}
 
 ctl_stop:
@@ -6316,7 +6317,7 @@
 	}
 
 	mdp5_data = mfd_to_mdp5_data(mfd);
-	queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work);
+	kthread_queue_work(&mdp5_data->worker, &mdp5_data->vsync_work);
 }
 
 static void __vsync_retire_work_handler(struct kthread_work *work)
@@ -6339,11 +6340,11 @@
 
 	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (mdp5_data->retire_cnt > 0) {
-		sw_sync_timeline_inc(mdp5_data->vsync_timeline, val);
+		mdss_inc_timeline(mdp5_data->vsync_timeline, val);
 		mdp5_data->retire_cnt -= min(val, mdp5_data->retire_cnt);
 		pr_debug("Retire signaled! timeline val=%d remaining=%d\n",
-				mdp5_data->vsync_timeline->value,
-				mdp5_data->retire_cnt);
+			mdss_get_timeline_retire_ts(mdp5_data->vsync_timeline),
+			mdp5_data->retire_cnt);
 
 		if (mdp5_data->retire_cnt == 0) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
@@ -6355,7 +6356,7 @@
 	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 }
 
-static struct sync_fence *
+static struct mdss_fence *
 __vsync_retire_get_fence(struct msm_sync_pt_data *sync_pt_data)
 {
 	struct msm_fb_data_type *mfd;
@@ -6378,7 +6379,7 @@
 		return ERR_PTR(-EPERM);
 	}
 
-	value = mdp5_data->vsync_timeline->value + 1 + mdp5_data->retire_cnt;
+	value = 1 + mdp5_data->retire_cnt;
 	mdp5_data->retire_cnt++;
 
 	return mdss_fb_sync_get_fence(mdp5_data->vsync_timeline,
@@ -6419,14 +6420,14 @@
 	struct sched_param param = { .sched_priority = 5 };
 
 	snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
-	mdp5_data->vsync_timeline = sw_sync_timeline_create(name);
+	mdp5_data->vsync_timeline = mdss_create_timeline(name);
 	if (mdp5_data->vsync_timeline == NULL) {
 		pr_err("cannot vsync create time line");
 		return -ENOMEM;
 	}
 
-	init_kthread_worker(&mdp5_data->worker);
-	init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler);
+	kthread_init_worker(&mdp5_data->worker);
+	kthread_init_work(&mdp5_data->vsync_work, __vsync_retire_work_handler);
 
 	mdp5_data->thread = kthread_run(kthread_worker_fn,
 					&mdp5_data->worker,
@@ -6717,7 +6718,7 @@
 	if (mfd->panel_info->mipi.dms_mode ||
 			mfd->panel_info->type == MIPI_CMD_PANEL) {
 		rc = __vsync_retire_setup(mfd);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("unable to create vsync timeline\n");
 			goto init_fail;
 		}
@@ -6791,14 +6792,18 @@
 	if (!mdata->scaler_off)
 		return -EFAULT;
 
+	mutex_lock(&mdata->scaler_off->scaler_lock);
+
 	qseed3_lut_tbl = &mdata->scaler_off->lut_tbl;
 	if ((lut_tbl->dir_lut_size !=
 		DIR_LUT_IDX * DIR_LUT_COEFFS * sizeof(uint32_t)) ||
 		(lut_tbl->cir_lut_size !=
 		 CIR_LUT_IDX * CIR_LUT_COEFFS * sizeof(uint32_t)) ||
 		(lut_tbl->sep_lut_size !=
-		 SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t)))
+		 SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t))) {
+		mutex_unlock(&mdata->scaler_off->scaler_lock);
 		return -EINVAL;
+	}
 
 	if (!qseed3_lut_tbl->dir_lut) {
 		qseed3_lut_tbl->dir_lut = devm_kzalloc(&mdata->pdev->dev,
@@ -6806,7 +6811,7 @@
 				GFP_KERNEL);
 		if (!qseed3_lut_tbl->dir_lut) {
 			ret = -ENOMEM;
-			goto fail;
+			goto err;
 		}
 	}
 
@@ -6816,7 +6821,7 @@
 				GFP_KERNEL);
 		if (!qseed3_lut_tbl->cir_lut) {
 			ret = -ENOMEM;
-			goto fail;
+			goto fail_free_dir_lut;
 		}
 	}
 
@@ -6826,44 +6831,52 @@
 				GFP_KERNEL);
 		if (!qseed3_lut_tbl->sep_lut) {
 			ret = -ENOMEM;
-			goto fail;
+			goto fail_free_cir_lut;
 		}
 	}
 
 	/* Invalidate before updating */
 	qseed3_lut_tbl->valid = false;
 
-
 	if (copy_from_user(qseed3_lut_tbl->dir_lut,
 				(void *)(unsigned long)lut_tbl->dir_lut,
 				lut_tbl->dir_lut_size)) {
 		ret = -EINVAL;
-		goto err;
+		goto fail_free_sep_lut;
 	}
 
 	if (copy_from_user(qseed3_lut_tbl->cir_lut,
 				(void *)(unsigned long)lut_tbl->cir_lut,
 				lut_tbl->cir_lut_size)) {
 		ret = -EINVAL;
-		goto err;
+		goto fail_free_sep_lut;
 	}
 
 	if (copy_from_user(qseed3_lut_tbl->sep_lut,
 				(void *)(unsigned long)lut_tbl->sep_lut,
 				lut_tbl->sep_lut_size)) {
 		ret = -EINVAL;
-		goto err;
+		goto fail_free_sep_lut;
 	}
 
 	qseed3_lut_tbl->valid = true;
+	mutex_unlock(&mdata->scaler_off->scaler_lock);
+
 	return ret;
 
-fail:
-	kfree(qseed3_lut_tbl->dir_lut);
-	kfree(qseed3_lut_tbl->cir_lut);
-	kfree(qseed3_lut_tbl->sep_lut);
+fail_free_sep_lut:
+	devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->sep_lut);
+fail_free_cir_lut:
+	devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->cir_lut);
+fail_free_dir_lut:
+	devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->dir_lut);
 err:
+	qseed3_lut_tbl->dir_lut = NULL;
+	qseed3_lut_tbl->cir_lut = NULL;
+	qseed3_lut_tbl->sep_lut = NULL;
 	qseed3_lut_tbl->valid = false;
+	mutex_unlock(&mdata->scaler_off->scaler_lock);
+
 	return ret;
 }
 
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 6131ed1..13afa46 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1578,11 +1578,16 @@
 	};
 
 	mdata = mdss_mdp_get_mdata();
+
+	mutex_lock(&mdata->scaler_off->scaler_lock);
+
 	lut_tbl = &mdata->scaler_off->lut_tbl;
 	if ((!lut_tbl) || (!lut_tbl->valid)) {
+		mutex_unlock(&mdata->scaler_off->scaler_lock);
 		pr_err("%s:Invalid QSEED3 LUT TABLE\n", __func__);
 		return -EINVAL;
 	}
+
 	if ((scaler->lut_flag & SCALER_LUT_DIR_WR) ||
 		(scaler->lut_flag & SCALER_LUT_Y_CIR_WR) ||
 		(scaler->lut_flag & SCALER_LUT_UV_CIR_WR) ||
@@ -1632,6 +1637,7 @@
 	if (scaler->lut_flag & SCALER_LUT_SWAP)
 		writel_relaxed(BIT(0), MDSS_MDP_REG_SCALER_COEF_LUT_CTRL +
 				offset);
+	mutex_unlock(&mdata->scaler_off->scaler_lock);
 
 	return 0;
 }
@@ -1717,7 +1723,7 @@
 			lut_offset = mdata->scaler_off->dest_base +
 				mdata->scaler_off->dest_scaler_lut_off[id];
 			/*TODO : set pixel fmt to RGB101010 */
-			return -ENOTSUP;
+			return -ENOTSUPP;
 		} else {
 			return -EINVAL;
 		}
@@ -5772,7 +5778,7 @@
 			struct mdss_ad_input *input, int wait) {
 	int ret = 0;
 	struct mdss_ad_info *ad;
-	u32 bl;
+	u64 bl;
 	struct mdss_overlay_private *mdp5_data;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
@@ -7209,6 +7215,13 @@
 		ret = -EINVAL;
 		goto exit_version;
 	}
+	/* PA dither is not supported by driver */
+	if (version->pp_feature == PA_DITHER) {
+		pr_warn("unsupported feature %d\n", version->pp_feature);
+		version->version_info = 0;
+		ret = 0;
+		goto exit_version;
+	}
 	if (version->pp_feature >= PP_FEATURE_MAX) {
 		pr_err("invalid feature passed %d\n", version->pp_feature);
 		ret = -EINVAL;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index f17cf6f..44817c3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2017-2018, 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
@@ -89,7 +88,7 @@
 	}
 	sinfo->size = buf_size;
 
-	dma_buf_begin_cpu_access(sinfo->dma_buf, 0, size, DMA_BIDIRECTIONAL);
+	dma_buf_begin_cpu_access(sinfo->dma_buf, DMA_BIDIRECTIONAL);
 	sinfo->splash_buffer = dma_buf_kmap(sinfo->dma_buf, 0);
 	if (IS_ERR(sinfo->splash_buffer)) {
 		pr_err("ion kernel memory mapping failed\n");
@@ -133,8 +132,7 @@
 	if (!mdata || !mdata->iclient || !sinfo->dma_buf)
 		return;
 
-	dma_buf_end_cpu_access(sinfo->dma_buf, 0, sinfo->size,
-			       DMA_BIDIRECTIONAL);
+	dma_buf_end_cpu_access(sinfo->dma_buf, DMA_BIDIRECTIONAL);
 	dma_buf_kunmap(sinfo->dma_buf, 0, sinfo->splash_buffer);
 
 	mdss_smmu_unmap_dma_buf(sinfo->table, MDSS_IOMMU_DOMAIN_UNSECURE, 0,
@@ -177,7 +175,7 @@
 		pr_debug("iommu memory mapping failed rc=%d\n", rc);
 	} else {
 		ret = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("mdss iommu attach failed\n");
 			mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE,
 					mdp5_data->splash_mem_addr,
@@ -288,7 +286,7 @@
 		 */
 		if (mdp5_data->handoff && ctl && ctl->is_video_mode) {
 			rc = mdss_mdp_display_commit(ctl, NULL, NULL);
-			if (!IS_ERR_VALUE(rc)) {
+			if (!IS_ERR_VALUE((unsigned long)rc)) {
 				mdss_mdp_display_wait4comp(ctl);
 			} else {
 				/*
diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h
index c100e9c..f8a6baf 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_trace.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h
@@ -376,7 +376,7 @@
 			__entry->kickoff_cnt)
 );
 
-TRACE_EVENT(tracing_mark_write,
+TRACE_EVENT(mdss_mark_write,
 	TP_PROTO(int pid, const char *name, bool trace_begin),
 	TP_ARGS(pid, name, trace_begin),
 	TP_STRUCT__entry(
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 6c28fe9..29f6c1a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -420,8 +420,8 @@
 
 	if (fmt->format == MDP_Y_CBCR_H2V2_UBWC ||
 		fmt->format == MDP_Y_CBCR_H2V2_TP10_UBWC) {
-		uint32_t y_stride_alignment, uv_stride_alignment;
-		uint32_t y_height_alignment, uv_height_alignment;
+		uint32_t y_stride_alignment = 0, uv_stride_alignment = 0;
+		uint32_t y_height_alignment = 0, uv_height_alignment = 0;
 		uint32_t y_tile_width = fmt_ubwc->micro.tile_width;
 		uint32_t y_tile_height = fmt_ubwc->micro.tile_height;
 		uint32_t uv_tile_width = y_tile_width / 2;
@@ -1002,8 +1002,8 @@
 		}
 		data->srcp_f = f;
 
-		if (MAJOR(f.file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
-			fb_num = MINOR(f.file->f_dentry->d_inode->i_rdev);
+		if (MAJOR(f.file->f_path.dentry->d_inode->i_rdev) == FB_MAJOR) {
+			fb_num = MINOR(f.file->f_path.dentry->d_inode->i_rdev);
 			ret = mdss_fb_get_phys_info(start, len, fb_num);
 			if (ret)
 				pr_err("mdss_fb_get_phys_info() failed\n");
@@ -1051,7 +1051,7 @@
 			struct sg_table *sg_ptr = NULL;
 
 			do {
-				ihandle = ion_import_dma_buf(iclient,
+				ihandle = ion_import_dma_buf_fd(iclient,
 							     img->memory_id);
 				if (IS_ERR_OR_NULL(ihandle)) {
 					ret = -EINVAL;
@@ -1140,7 +1140,7 @@
 			ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf,
 					data->srcp_table, domain,
 					&data->addr, &data->len, dir);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("smmu map dma buf failed: (%d)\n", ret);
 				goto err_unmap;
 			}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.h b/drivers/video/fbdev/msm/mdss_mdp_wfd.h
index e603c48..b35feb7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_wfd.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.h
@@ -14,8 +14,6 @@
 #ifndef __MDSS_MDP_WFD_H__
 #define __MDSS_MDP_WFD_H__
 
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/msm_mdp_ext.h>
diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c
index 3e0ca75..aa8d783 100644
--- a/drivers/video/fbdev/msm/mdss_qpic.c
+++ b/drivers/video/fbdev/msm/mdss_qpic.c
@@ -649,7 +649,7 @@
 	if (use_irq && (!qpic_res->irq_requested)) {
 		ret = devm_request_irq(&qpic_res->pdev->dev,
 			qpic_res->irq, qpic_irq_handler,
-			IRQF_DISABLED,	"QPIC", qpic_res);
+			IRQF_TRIGGER_NONE, "QPIC", qpic_res);
 		if (ret) {
 			pr_err("qpic request_irq() failed!\n");
 			use_irq = false;
@@ -776,12 +776,15 @@
 	}
 
 	qpic_res->qpic_a_clk = clk_get(&pdev->dev, "core_a_clk");
-	if (IS_ERR(qpic_res->qpic_a_clk))
+	if (IS_ERR(qpic_res->qpic_a_clk)) {
+		qpic_res->qpic_a_clk = NULL;
 		pr_err("%s: Can't find core_a_clk", __func__);
-
+	}
 	qpic_res->qpic_clk = clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(qpic_res->qpic_clk))
+	if (IS_ERR(qpic_res->qpic_clk)) {
+		qpic_res->qpic_clk = NULL;
 		pr_err("%s: Can't find core_clk", __func__);
+	}
 
 	qpic_res->irq = res->start;
 	qpic_res->res_init = true;
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index 73676d0..2dc9a1f 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/sync.h>
 #include <linux/uaccess.h>
 #include <linux/of.h>
 #include <linux/clk.h>
@@ -28,6 +27,7 @@
 #include "mdss_rotator_internal.h"
 #include "mdss_mdp.h"
 #include "mdss_debug.h"
+#include "mdss_sync.h"
 
 /* waiting for hw time out, 3 vsync for 30fps*/
 #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100
@@ -230,7 +230,7 @@
 			pr_err("unable to round rate err=%ld\n", clk_rate);
 		} else if (clk_rate != clk_get_rate(clk)) {
 			ret = clk_set_rate(clk, clk_rate);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("clk_set_rate failed, err:%d\n", ret);
 			} else {
 				pr_debug("rotator clk rate=%lu\n", clk_rate);
@@ -253,7 +253,7 @@
 	}
 
 	pr_debug("%s: rotator regulators", on ? "Enable" : "Disable");
-	ret = msm_dss_enable_vreg(mgr->module_power.vreg_config,
+	ret = msm_mdss_enable_vreg(mgr->module_power.vreg_config,
 		mgr->module_power.num_vreg, on);
 	if (ret) {
 		pr_warn("Rotator regulator failed to %s\n",
@@ -374,21 +374,11 @@
 	return false;
 }
 
-static void mdss_rotator_install_fence_fd(struct mdss_rot_entry_container *req)
-{
-	int i = 0;
-
-	for (i = 0; i < req->count; i++)
-		sync_fence_install(req->entries[i].output_fence,
-				req->entries[i].output_fence_fd);
-}
-
 static int mdss_rotator_create_fence(struct mdss_rot_entry *entry)
 {
 	int ret = 0, fd;
 	u32 val;
-	struct sync_pt *sync_pt;
-	struct sync_fence *fence;
+	struct mdss_fence *fence;
 	struct mdss_rot_timeline *rot_timeline;
 
 	if (!entry->queue)
@@ -397,24 +387,15 @@
 	rot_timeline = &entry->queue->timeline;
 
 	mutex_lock(&rot_timeline->lock);
-	val = rot_timeline->next_value + 1;
+	val = 1;
 
-	sync_pt = sw_sync_pt_create(rot_timeline->timeline, val);
-	if (sync_pt == NULL) {
+	fence = mdss_get_sync_fence(rot_timeline->timeline,
+					rot_timeline->fence_name, NULL, val);
+	if (fence == NULL) {
 		pr_err("cannot create sync point\n");
 		goto sync_pt_create_err;
 	}
-
-	/* create fence */
-	fence = sync_fence_create(rot_timeline->fence_name, sync_pt);
-	if (fence == NULL) {
-		pr_err("%s: cannot create fence\n", rot_timeline->fence_name);
-		sync_pt_free(sync_pt);
-		ret = -ENOMEM;
-		goto sync_pt_create_err;
-	}
-
-	fd = get_unused_fd_flags(0);
+	fd = mdss_get_sync_fence_fd(fence);
 	if (fd < 0) {
 		pr_err("get_unused_fd_flags failed error:0x%x\n", fd);
 		ret = fd;
@@ -426,12 +407,13 @@
 
 	entry->output_fence_fd = fd;
 	entry->output_fence = fence;
-	pr_debug("output sync point created at val=%u\n", val);
+	pr_debug("output sync point created at %s:val=%u\n",
+		mdss_get_sync_fence_name(fence), val);
 
 	return 0;
 
 get_fd_err:
-	sync_fence_put(fence);
+	mdss_put_sync_fence(fence);
 sync_pt_create_err:
 	mutex_unlock(&rot_timeline->lock);
 	return ret;
@@ -442,7 +424,7 @@
 	struct mdss_rot_timeline *rot_timeline;
 
 	if (entry->input_fence) {
-		sync_fence_put(entry->input_fence);
+		mdss_put_sync_fence(entry->input_fence);
 		entry->input_fence = NULL;
 	}
 
@@ -450,7 +432,7 @@
 
 	/* fence failed to copy to user space */
 	if (entry->output_fence) {
-		sync_fence_put(entry->output_fence);
+		mdss_put_sync_fence(entry->output_fence);
 		entry->output_fence = NULL;
 		put_unused_fd(entry->output_fence_fd);
 
@@ -475,7 +457,7 @@
 	}
 
 	mutex_lock(&rot_timeline->lock);
-	sw_sync_timeline_inc(rot_timeline->timeline, 1);
+	mdss_inc_timeline(rot_timeline->timeline, 1);
 	mutex_unlock(&rot_timeline->lock);
 
 	entry->output_signaled = true;
@@ -492,8 +474,8 @@
 		return 0;
 	}
 
-	ret = sync_fence_wait(entry->input_fence, ROT_FENCE_WAIT_TIMEOUT);
-	sync_fence_put(entry->input_fence);
+	ret = mdss_wait_sync_fence(entry->input_fence, ROT_FENCE_WAIT_TIMEOUT);
+	mdss_put_sync_fence(entry->input_fence);
 	entry->input_fence = NULL;
 	return ret;
 }
@@ -545,7 +527,7 @@
 
 	ATRACE_BEGIN(__func__);
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		ATRACE_END(__func__);
 		return ret;
 	}
@@ -697,7 +679,7 @@
 	struct mdss_rot_hw_resource *hw;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	u32 pipe_ndx, offset = mdss_mdp_get_wb_ctl_support(mdata, true);
-	int ret;
+	int ret = 0;
 
 	hw = devm_kzalloc(&mgr->pdev->dev, sizeof(struct mdss_rot_hw_resource),
 		GFP_KERNEL);
@@ -867,7 +849,7 @@
 		snprintf(name, sizeof(name), "rot_timeline_%d", i);
 		pr_debug("timeline name=%s\n", name);
 		mgr->queues[i].timeline.timeline =
-			sw_sync_timeline_create(name);
+			mdss_create_timeline(name);
 		if (!mgr->queues[i].timeline.timeline) {
 			ret = -EPERM;
 			break;
@@ -896,11 +878,11 @@
 			destroy_workqueue(mgr->queues[i].rot_work_queue);
 
 		if (mgr->queues[i].timeline.timeline) {
-			struct sync_timeline *obj;
+			struct mdss_timeline *obj;
 
-			obj = (struct sync_timeline *)
+			obj = (struct mdss_timeline *)
 				mgr->queues[i].timeline.timeline;
-			sync_timeline_destroy(obj);
+			mdss_destroy_timeline(obj);
 		}
 	}
 	devm_kfree(&mgr->pdev->dev, mgr->queues);
@@ -1524,8 +1506,8 @@
 		}
 
 		if (item->input.fence >= 0) {
-			entry->input_fence =
-				sync_fence_fdget(item->input.fence);
+			entry->input_fence = mdss_get_fd_sync_fence(
+							    item->input.fence);
 			if (!entry->input_fence) {
 				pr_err("invalid input fence fd\n");
 				return -EINVAL;
@@ -2263,7 +2245,6 @@
 		goto handle_request_err1;
 	}
 
-	mdss_rotator_install_fence_fd(req);
 	mdss_rotator_queue_request(mgr, private, req);
 
 	mutex_unlock(&mgr->lock);
@@ -2423,7 +2404,6 @@
 		goto handle_request32_err1;
 	}
 
-	mdss_rotator_install_fence_fd(req);
 	mdss_rotator_queue_request(mgr, private, req);
 
 	mutex_unlock(&mgr->lock);
@@ -2677,14 +2657,14 @@
 }
 
 static void mdss_rotator_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp)
+	struct mdss_module_power *mp)
 {
 	if (!mp) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return;
 	}
 
-	msm_dss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 0);
+	msm_mdss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 0);
 	if (mp->vreg_config) {
 		devm_kfree(dev, mp->vreg_config);
 		mp->vreg_config = NULL;
@@ -2693,7 +2673,7 @@
 }
 
 static int mdss_rotator_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp)
+	struct mdss_module_power *mp)
 {
 	const char *st = NULL;
 	struct device_node *of_node = NULL;
@@ -2715,7 +2695,7 @@
 		return 0;
 	}
 	mp->num_vreg = dt_vreg_total;
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		dt_vreg_total, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		DEV_ERR("%s: can't alloc vreg mem\n", __func__);
@@ -2733,7 +2713,7 @@
 		}
 		snprintf(mp->vreg_config[i].vreg_name, 32, "%s", st);
 	}
-	msm_dss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 1);
+	msm_mdss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 1);
 
 	for (i = 0; i < dt_vreg_total; i++) {
 		DEV_DBG("%s: %s min=%d, max=%d, enable=%d disable=%d\n",
diff --git a/drivers/video/fbdev/msm/mdss_rotator_internal.h b/drivers/video/fbdev/msm/mdss_rotator_internal.h
index 8dd400e..88f530a 100644
--- a/drivers/video/fbdev/msm/mdss_rotator_internal.h
+++ b/drivers/video/fbdev/msm/mdss_rotator_internal.h
@@ -15,10 +15,8 @@
 #define MDSS_MDP_ROTATOR_INTERNAL_H
 
 #include <linux/list.h>
-#include <linux/sync.h>
 #include <linux/file.h>
 #include <linux/mdss_rotator.h>
-#include <linux/sw_sync.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/cdev.h>
@@ -52,7 +50,7 @@
 
 struct mdss_rot_timeline {
 	struct mutex lock;
-	struct sw_sync_timeline *timeline;
+	struct mdss_timeline *timeline;
 	u32 next_value;
 	char fence_name[32];
 };
@@ -95,10 +93,10 @@
 	struct mdss_mdp_data src_buf;
 	struct mdss_mdp_data dst_buf;
 
-	struct sync_fence *input_fence;
+	struct mdss_fence *input_fence;
 
 	int output_fence_fd;
-	struct sync_fence *output_fence;
+	struct mdss_fence *output_fence;
 	bool output_signaled;
 
 	u32 dnsc_factor_w;
@@ -174,7 +172,7 @@
 	struct mdss_rot_bus_data_type reg_bus;
 
 	/* Module power is only used for regulator management */
-	struct dss_module_power module_power;
+	struct mdss_module_power module_power;
 	bool regulator_enable;
 
 	struct mutex clk_lock;
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 05353a0..fbbdaf2 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -17,17 +17,15 @@
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/iommu.h>
-#include <linux/qcom_iommu.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/clk/msm-clk.h>
-
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-buf.h>
 #include <linux/of_platform.h>
 #include <linux/msm_dma_iommu_mapping.h>
 
-#include <linux/qcom_iommu.h>
 #include <asm/dma-iommu.h>
 #include "soc/qcom/secure_buffer.h"
 
@@ -38,6 +36,27 @@
 
 #define SZ_4G 0xF0000000
 
+#ifdef CONFIG_QCOM_IOMMU
+#include <linux/qcom_iommu.h>
+static inline struct bus_type *mdss_mmu_get_bus(struct device *dev)
+{
+	return msm_iommu_get_bus(dev);
+}
+static inline struct device *mdss_mmu_get_ctx(const char *name)
+{
+	return msm_iommu_get_ctx(name);
+}
+#else
+static inline struct bus_type *mdss_mmu_get_bus(struct device *dev)
+{
+	return &platform_bus_type;
+}
+static inline struct device *mdss_mmu_get_ctx(const char *name)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
 static DEFINE_MUTEX(mdp_iommu_lock);
 
 void mdss_iommu_lock(void)
@@ -51,7 +70,7 @@
 }
 
 static int mdss_smmu_util_parse_dt_clock(struct platform_device *pdev,
-		struct dss_module_power *mp)
+		struct mdss_module_power *mp)
 {
 	u32 i = 0, rc = 0;
 	const char *clock_name;
@@ -67,7 +86,7 @@
 
 	mp->num_clk = num_clk;
 	mp->clk_config = devm_kzalloc(&pdev->dev,
-			sizeof(struct dss_clk) * mp->num_clk, GFP_KERNEL);
+			sizeof(struct mdss_clk) * mp->num_clk, GFP_KERNEL);
 	if (!mp->clk_config) {
 		rc = -ENOMEM;
 		mp->num_clk = 0;
@@ -95,7 +114,7 @@
 }
 
 static int mdss_smmu_clk_register(struct platform_device *pdev,
-		struct dss_module_power *mp)
+		struct mdss_module_power *mp)
 {
 	int i, ret;
 	struct clk *clk;
@@ -123,7 +142,7 @@
 	bool enable)
 {
 	int rc = 0;
-	struct dss_module_power *mp;
+	struct mdss_module_power *mp;
 
 	if (!mdss_smmu)
 		return -EINVAL;
@@ -134,27 +153,27 @@
 		return 0;
 
 	if (enable) {
-		rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, true);
+		rc = msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, true);
 		if (rc) {
 			pr_err("vreg enable failed - rc:%d\n", rc);
 			goto end;
 		}
 		mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 			VOTE_INDEX_LOW);
-		rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true);
+		rc = msm_mdss_enable_clk(mp->clk_config, mp->num_clk, true);
 		if (rc) {
 			pr_err("clock enable failed - rc:%d\n", rc);
 			mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 				VOTE_INDEX_DISABLE);
-			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+			msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg,
 				false);
 			goto end;
 		}
 	} else {
-		msm_dss_enable_clk(mp->clk_config, mp->num_clk, false);
+		msm_mdss_enable_clk(mp->clk_config, mp->num_clk, false);
 		mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 			VOTE_INDEX_DISABLE);
-		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false);
+		msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, false);
 	}
 end:
 	return rc;
@@ -297,7 +316,7 @@
 	}
 	ATRACE_END("map_buffer");
 	*iova = table->sgl->dma_address;
-	*size = table->sgl->dma_length;
+	*size = sg_dma_len(table->sgl);
 	return 0;
 }
 
@@ -655,7 +674,10 @@
 
 	parent = dev->of_node;
 	for_each_child_of_node(parent, child) {
-		if (is_mdss_smmu_compatible_device(child->name))
+		char name[MDSS_SMMU_COMPAT_STR_LEN] = {};
+
+		strlcpy(name, child->name, sizeof(name));
+		if (is_mdss_smmu_compatible_device(name))
 			of_platform_device_create(child, NULL, dev);
 	}
 }
@@ -704,8 +726,7 @@
 	int rc = 0;
 	struct mdss_smmu_domain smmu_domain;
 	const struct of_device_id *match;
-	struct dss_module_power *mp;
-	int disable_htw = 1;
+	struct mdss_module_power *mp;
 	char name[MAX_CLIENT_NAME_LEN];
 	const __be32 *address = NULL, *size = NULL;
 
@@ -733,7 +754,7 @@
 		 * For old iommu driver we query the context bank device
 		 * rather than getting it from dt.
 		 */
-		dev = msm_iommu_get_ctx(smmu_domain.ctx_name);
+		dev = mdss_mmu_get_ctx(smmu_domain.ctx_name);
 		if (!dev) {
 			pr_err("Invalid SMMU ctx for domain:%d\n",
 				smmu_domain.domain);
@@ -743,13 +764,13 @@
 
 	mdss_smmu = &mdata->mdss_smmu[smmu_domain.domain];
 	mp = &mdss_smmu->mp;
-	memset(mp, 0, sizeof(struct dss_module_power));
+	memset(mp, 0, sizeof(struct mdss_module_power));
 
 	if (of_find_property(pdev->dev.of_node,
 		"gdsc-mmagic-mdss-supply", NULL)) {
 
 		mp->vreg_config = devm_kzalloc(&pdev->dev,
-			sizeof(struct dss_vreg), GFP_KERNEL);
+			sizeof(struct mdss_vreg), GFP_KERNEL);
 		if (!mp->vreg_config)
 			return -ENOMEM;
 
@@ -758,7 +779,7 @@
 		mp->num_vreg = 1;
 	}
 
-	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+	rc = msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 		mp->num_vreg, true);
 	if (rc) {
 		pr_err("vreg config failed rc=%d\n", rc);
@@ -769,7 +790,7 @@
 	if (rc) {
 		pr_err("smmu clk register failed for domain[%d] with err:%d\n",
 			smmu_domain.domain, rc);
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 		return rc;
 	}
@@ -778,7 +799,7 @@
 	mdss_smmu->reg_bus_clt = mdss_reg_bus_vote_client_create(name);
 	if (IS_ERR(mdss_smmu->reg_bus_clt)) {
 		pr_err("mdss bus client register failed\n");
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 		return PTR_ERR(mdss_smmu->reg_bus_clt);
 	}
@@ -791,7 +812,7 @@
 	}
 
 	mdss_smmu->mmu_mapping = arm_iommu_create_mapping(
-		msm_iommu_get_bus(dev), smmu_domain.start, smmu_domain.size);
+		mdss_mmu_get_bus(dev), smmu_domain.start, smmu_domain.size);
 	if (IS_ERR(mdss_smmu->mmu_mapping)) {
 		pr_err("iommu create mapping failed for domain[%d]\n",
 			smmu_domain.domain);
@@ -799,13 +820,6 @@
 		goto disable_power;
 	}
 
-	rc = iommu_domain_set_attr(mdss_smmu->mmu_mapping->domain,
-		DOMAIN_ATTR_COHERENT_HTW_DISABLE, &disable_htw);
-	if (rc) {
-		pr_err("couldn't disable coherent HTW\n");
-		goto release_mapping;
-	}
-
 	if (smmu_domain.domain == MDSS_IOMMU_DOMAIN_SECURE ||
 		smmu_domain.domain == MDSS_IOMMU_DOMAIN_ROT_SECURE) {
 		int secure_vmid = VMID_CP_PIXEL;
@@ -848,7 +862,7 @@
 bus_client_destroy:
 	mdss_reg_bus_vote_client_destroy(mdss_smmu->reg_bus_clt);
 	mdss_smmu->reg_bus_clt = NULL;
-	msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 	return rc;
 }
diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h
index be2a55f..091af3b 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.h
+++ b/drivers/video/fbdev/msm/mdss_smmu.h
@@ -23,6 +23,7 @@
 #include "mdss_debug.h"
 
 #define MDSS_SMMU_COMPATIBLE "qcom,smmu"
+#define MDSS_SMMU_COMPAT_STR_LEN 10
 #define SMMU_CBN_FSYNR1		0x6c
 
 struct mdss_iommu_map_type {
diff --git a/drivers/video/fbdev/msm/mdss_sync.c b/drivers/video/fbdev/msm/mdss_sync.c
new file mode 100644
index 0000000..22fdcf5
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_sync.c
@@ -0,0 +1,497 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/fence.h>
+#include <linux/sync_file.h>
+
+#include "mdss_sync.h"
+
+#define MDSS_SYNC_NAME_SIZE		64
+#define MDSS_SYNC_DRIVER_NAME	"mdss"
+
+/**
+ * struct mdss_fence - sync fence context
+ * @base: base sync fence object
+ * @name: name of this sync fence
+ * @fence_list: linked list of outstanding sync fence
+ */
+struct mdss_fence {
+	struct fence base;
+	char name[MDSS_SYNC_NAME_SIZE];
+	struct list_head fence_list;
+};
+
+/**
+ * struct mdss_timeline - sync timeline context
+ * @kref: reference count of timeline
+ * @lock: serialization lock for timeline and fence update
+ * @name: name of timeline
+ * @fence_name: fence name prefix
+ * @next_value: next commit sequence number
+ * @value: current retired sequence number
+ * @context: fence context identifier
+ * @fence_list_head: linked list of outstanding sync fence
+ */
+struct mdss_timeline {
+	struct kref kref;
+	spinlock_t lock;
+	spinlock_t list_lock;
+	char name[MDSS_SYNC_NAME_SIZE];
+	u32 next_value;
+	u32 value;
+	u64 context;
+	struct list_head fence_list_head;
+};
+
+#if defined(CONFIG_SYNC_FILE)
+/*
+ * to_mdss_fence - get mdss fence from fence base object
+ * @fence: Pointer to fence base object
+ */
+static struct mdss_fence *to_mdss_fence(struct fence *fence)
+{
+	return container_of(fence, struct mdss_fence, base);
+}
+
+/*
+ * to_mdss_timeline - get mdss timeline from fence base object
+ * @fence: Pointer to fence base object
+ */
+static struct mdss_timeline *to_mdss_timeline(struct fence *fence)
+{
+	return container_of(fence->lock, struct mdss_timeline, lock);
+}
+
+/*
+ * mdss_free_timeline - Free the given timeline object
+ * @kref: Pointer to timeline kref object.
+ */
+static void mdss_free_timeline(struct kref *kref)
+{
+	struct mdss_timeline *tl =
+		container_of(kref, struct mdss_timeline, kref);
+
+	kfree(tl);
+}
+
+/*
+ * mdss_put_timeline - Put the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+static void mdss_put_timeline(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	kref_put(&tl->kref, mdss_free_timeline);
+}
+
+/*
+ * mdss_get_timeline - Get the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+static void mdss_get_timeline(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	kref_get(&tl->kref);
+}
+
+static const char *mdss_fence_get_driver_name(struct fence *fence)
+{
+	return MDSS_SYNC_DRIVER_NAME;
+}
+
+static const char *mdss_fence_get_timeline_name(struct fence *fence)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+
+	return tl->name;
+}
+
+static bool mdss_fence_enable_signaling(struct fence *fence)
+{
+	return true;
+}
+
+static bool mdss_fence_signaled(struct fence *fence)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+	bool status;
+
+	status = ((s32) (tl->value - fence->seqno)) >= 0;
+	pr_debug("status:%d fence seq:%d and timeline:%s:%d next %d\n",
+			status, fence->seqno, tl->name,
+			tl->value, tl->next_value);
+	return status;
+}
+
+static void mdss_fence_release(struct fence *fence)
+{
+	struct mdss_fence *f = to_mdss_fence(fence);
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+
+	pr_debug("%s for fence %s\n", __func__, f->name);
+	spin_lock(&tl->list_lock);
+	if (!list_empty(&f->fence_list))
+		list_del(&f->fence_list);
+	spin_unlock(&tl->list_lock);
+	mdss_put_timeline(to_mdss_timeline(fence));
+	kfree_rcu(f, base.rcu);
+}
+
+static void mdss_fence_value_str(struct fence *fence, char *str, int size)
+{
+	snprintf(str, size, "%u", fence->seqno);
+}
+
+static void mdss_fence_timeline_value_str(struct fence *fence, char *str,
+		int size)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+
+	snprintf(str, size, "%u", tl->value);
+}
+
+static struct fence_ops mdss_fence_ops = {
+	.get_driver_name = mdss_fence_get_driver_name,
+	.get_timeline_name = mdss_fence_get_timeline_name,
+	.enable_signaling = mdss_fence_enable_signaling,
+	.signaled = mdss_fence_signaled,
+	.wait = fence_default_wait,
+	.release = mdss_fence_release,
+	.fence_value_str = mdss_fence_value_str,
+	.timeline_value_str = mdss_fence_timeline_value_str,
+};
+
+/*
+ * mdss_create_timeline - Create timeline object with the given name
+ * @name: Pointer to name character string.
+ */
+struct mdss_timeline *mdss_create_timeline(const char *name)
+{
+	struct mdss_timeline *tl;
+
+	if (!name) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	tl = kzalloc(sizeof(struct mdss_timeline), GFP_KERNEL);
+	if (!tl)
+		return NULL;
+
+	kref_init(&tl->kref);
+	snprintf(tl->name, sizeof(tl->name), "%s", name);
+	spin_lock_init(&tl->lock);
+	spin_lock_init(&tl->list_lock);
+	tl->context = fence_context_alloc(1);
+	INIT_LIST_HEAD(&tl->fence_list_head);
+
+	return tl;
+}
+
+/*
+ * mdss_destroy_timeline - Destroy the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+void mdss_destroy_timeline(struct mdss_timeline *tl)
+{
+	mdss_put_timeline(tl);
+}
+
+/*
+ * mdss_inc_timeline_locked - Increment timeline by given amount
+ * @tl: Pointer to timeline object.
+ * @increment: the amount to increase the timeline by.
+ */
+static int mdss_inc_timeline_locked(struct mdss_timeline *tl,
+		int increment)
+{
+	struct mdss_fence *f, *next;
+	s32 val;
+	bool is_signaled = false;
+	struct list_head local_list_head;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&local_list_head);
+
+	spin_lock(&tl->list_lock);
+	if (list_empty(&tl->fence_list_head)) {
+		pr_debug("fence list is empty\n");
+		spin_unlock(&tl->list_lock);
+		return 0;
+	}
+
+	list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list)
+		list_move(&f->fence_list, &local_list_head);
+	spin_unlock(&tl->list_lock);
+
+	spin_lock_irqsave(&tl->lock, flags);
+	val = tl->next_value - tl->value;
+	if (val >= increment)
+		tl->value += increment;
+	spin_unlock_irqrestore(&tl->lock, flags);
+
+	list_for_each_entry_safe(f, next, &local_list_head, fence_list) {
+		spin_lock_irqsave(&tl->lock, flags);
+		is_signaled = fence_is_signaled_locked(&f->base);
+		spin_unlock_irqrestore(&tl->lock, flags);
+		if (is_signaled) {
+			pr_debug("%s signaled\n", f->name);
+			list_del_init(&f->fence_list);
+			fence_put(&f->base);
+		} else {
+			spin_lock(&tl->list_lock);
+			list_move(&f->fence_list, &tl->fence_list_head);
+			spin_unlock(&tl->list_lock);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * mdss_resync_timeline - Resync timeline to last committed value
+ * @tl: Pointer to timeline object.
+ */
+void mdss_resync_timeline(struct mdss_timeline *tl)
+{
+	s32 val;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	val = tl->next_value - tl->value;
+	if (val > 0) {
+		pr_warn("flush %s:%d TL(Nxt %d , Crnt %d)\n", tl->name, val,
+			tl->next_value, tl->value);
+		mdss_inc_timeline_locked(tl, val);
+	}
+}
+
+/*
+ * mdss_get_sync_fence - Create fence object from the given timeline
+ * @tl: Pointer to timeline object
+ * @timestamp: Pointer to timestamp of the returned fence. Null if not required.
+ * Return: pointer fence created on give time line.
+ */
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset)
+{
+	struct mdss_fence *f;
+	u32 val;
+	unsigned long flags;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	f = kzalloc(sizeof(struct mdss_fence), GFP_KERNEL);
+	if (!f)
+		return NULL;
+
+	INIT_LIST_HEAD(&f->fence_list);
+	spin_lock_irqsave(&tl->lock, flags);
+	val = tl->next_value + offset;
+	tl->next_value += 1;
+	fence_init(&f->base, &mdss_fence_ops, &tl->lock, tl->context, val);
+	mdss_get_timeline(tl);
+	spin_unlock_irqrestore(&tl->lock, flags);
+
+	spin_lock(&tl->list_lock);
+	list_add_tail(&f->fence_list, &tl->fence_list_head);
+	spin_unlock(&tl->list_lock);
+	snprintf(f->name, sizeof(f->name), "%s_%u", fence_name, val);
+
+	if (timestamp)
+		*timestamp = val;
+
+	pr_debug("fence created at val=%u tl->name %s next_value %d value %d offset %d\n",
+			val, tl->name, tl->next_value, tl->value, offset);
+
+	return (struct mdss_fence *) &f->base;
+}
+
+/*
+ * mdss_inc_timeline - Increment timeline by given amount
+ * @tl: Pointer to timeline object.
+ * @increment: the amount to increase the timeline by.
+ */
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment)
+{
+	int rc;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_inc_timeline_locked(tl, increment);
+	return rc;
+}
+
+/*
+ * mdss_get_timeline_commit_ts - Return commit tick of given timeline
+ * @tl: Pointer to timeline object.
+ */
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return 0;
+	}
+
+	return tl->next_value;
+}
+
+/*
+ * mdss_get_timeline_retire_ts - Return retire tick of given timeline
+ * @tl: Pointer to timeline object.
+ */
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return 0;
+	}
+
+	return tl->value;
+}
+
+/*
+ * mdss_put_sync_fence - Destroy given fence object
+ * @fence: Pointer to fence object.
+ */
+void mdss_put_sync_fence(struct mdss_fence *fence)
+{
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	fence_put((struct fence *) fence);
+}
+
+/*
+ * mdss_wait_sync_fence - Wait until fence signal or timeout
+ * @fence: Pointer to fence object.
+ * @timeout: maximum wait time, in msec, for fence to signal.
+ */
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout)
+{
+	int rc;
+
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	rc = fence_wait_timeout((struct fence *) fence, false,
+			msecs_to_jiffies(timeout));
+	if (rc > 0) {
+		pr_debug("fence signaled\n");
+		rc = 0;
+	} else if (rc == 0) {
+		struct fence *input_fence = (struct fence *) fence;
+		char timeline_str[MDSS_SYNC_NAME_SIZE];
+
+		if (input_fence->ops->timeline_value_str)
+			input_fence->ops->timeline_value_str(input_fence,
+					timeline_str, MDSS_SYNC_NAME_SIZE);
+		pr_err(
+			"drv:%s timeline:%s seqno:%d timeline:%s status:0x%x\n",
+			input_fence->ops->get_driver_name(input_fence),
+			input_fence->ops->get_timeline_name(input_fence),
+			input_fence->seqno, timeline_str,
+			input_fence->ops->signaled ?
+			input_fence->ops->signaled(input_fence) : 0xffffffff);
+		rc = -ETIMEDOUT;
+	}
+
+	return rc;
+}
+
+/*
+ * mdss_get_fd_sync_fence - Get fence object of given file descriptor
+ * @fd: File description of fence object.
+ */
+struct mdss_fence *mdss_get_fd_sync_fence(int fd)
+{
+	return (struct mdss_fence *) sync_file_get_fence(fd);
+}
+
+/*
+ * mdss_get_sync_fence_fd - Get file descriptor of given fence object
+ * @fence: Pointer to fence object.
+ * Return: File descriptor on success, or error code on error
+ */
+int mdss_get_sync_fence_fd(struct mdss_fence *fence)
+{
+	int fd;
+	struct sync_file *sync_file;
+
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0) {
+		pr_err("fail to get unused fd\n");
+		return fd;
+	}
+
+	sync_file = sync_file_create((struct fence *) fence);
+	if (!sync_file) {
+		put_unused_fd(fd);
+		pr_err("failed to create sync file\n");
+		return -ENOMEM;
+	}
+
+	fd_install(fd, sync_file->file);
+
+	return fd;
+}
+
+/*
+ * mdss_put_sync_fence - Destroy given fence object
+ * @fence: Pointer to fence object.
+ * Return: fence name
+ */
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence)
+{
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	return fence->name;
+}
+#endif
diff --git a/drivers/video/fbdev/msm/mdss_sync.h b/drivers/video/fbdev/msm/mdss_sync.h
new file mode 100644
index 0000000..a2e84d4
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_sync.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_SYNC_H
+#define MDSS_SYNC_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+struct mdss_fence;
+struct mdss_timeline;
+
+#if defined(CONFIG_SYNC_FILE)
+struct mdss_timeline *mdss_create_timeline(const char *name);
+
+void mdss_destroy_timeline(struct mdss_timeline *tl);
+
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset);
+
+void mdss_resync_timeline(struct mdss_timeline *tl);
+
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl);
+
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl);
+
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment);
+
+void mdss_put_sync_fence(struct mdss_fence *fence);
+
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout);
+
+struct mdss_fence *mdss_get_fd_sync_fence(int fd);
+
+int mdss_get_sync_fence_fd(struct mdss_fence *fence);
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence);
+#else
+static inline
+struct mdss_timeline *mdss_create_timeline(const char *name)
+{
+	return NULL;
+}
+
+static inline
+void mdss_destroy_timeline(struct mdss_timeline *tl)
+{
+}
+
+static inline
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset)
+{
+	return NULL;
+}
+
+static inline
+void mdss_resync_timeline(struct mdss_timeline *tl)
+{
+}
+
+static inline
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment)
+{
+	return 0;
+}
+
+static inline
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl)
+{
+	return 0;
+}
+
+static inline
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl)
+{
+	return 0;
+}
+
+static inline
+void mdss_put_sync_fence(struct mdss_fence *fence)
+{
+}
+
+static inline
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout)
+{
+	return 0;
+}
+
+static inline
+struct mdss_fence *mdss_get_fd_sync_fence(int fd)
+{
+	return NULL;
+}
+
+static inline
+int mdss_get_sync_fence_fd(struct mdss_fence *fence)
+{
+	return -EBADF;
+}
+
+static inline
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence)
+{
+	return NULL;
+}
+#endif
+
+#endif /* MDSS_SYNC_H */
diff --git a/drivers/video/fbdev/msm/mdss_wb.c b/drivers/video/fbdev/msm/mdss_wb.c
index 4b509ec..c8c5d47 100644
--- a/drivers/video/fbdev/msm/mdss_wb.c
+++ b/drivers/video/fbdev/msm/mdss_wb.c
@@ -22,7 +22,8 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/version.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
+#include <linux/module.h>
 
 #include "mdss_panel.h"
 #include "mdss_wb.h"
@@ -94,6 +95,11 @@
 	return 0;
 }
 
+static const unsigned int mdss_wb_disp_supported_cable[] = {
+	EXTCON_DISP_HMD + 1, /* For WFD */
+	EXTCON_NONE,
+};
+
 static int mdss_wb_dev_init(struct mdss_wb_ctrl *wb_ctrl)
 {
 	int rc = 0;
@@ -103,8 +109,11 @@
 		return -ENODEV;
 	}
 
+	memset(&wb_ctrl->sdev, 0x0, sizeof(wb_ctrl->sdev));
+	wb_ctrl->sdev.supported_cable = mdss_wb_disp_supported_cable;
+	wb_ctrl->sdev.dev.parent = &wb_ctrl->pdev->dev;
 	wb_ctrl->sdev.name = "wfd";
-	rc = switch_dev_register(&wb_ctrl->sdev);
+	rc = extcon_dev_register(&wb_ctrl->sdev);
 	if (rc) {
 		pr_err("Failed to setup switch dev for writeback panel");
 		return rc;
@@ -120,7 +129,7 @@
 		return -ENODEV;
 	}
 
-	switch_dev_unregister(&wb_ctrl->sdev);
+	extcon_dev_unregister(&wb_ctrl->sdev);
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/msm/mdss_wb.h b/drivers/video/fbdev/msm/mdss_wb.h
index 9cc88b6..010a123 100644
--- a/drivers/video/fbdev/msm/mdss_wb.h
+++ b/drivers/video/fbdev/msm/mdss_wb.h
@@ -14,12 +14,12 @@
 #ifndef MDSS_WB_H
 #define MDSS_WB_H
 
-#include <linux/switch.h>
+#include <linux/extcon.h>
 
 struct mdss_wb_ctrl {
 	struct platform_device *pdev;
 	struct mdss_panel_data pdata;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 };
 
 #endif
diff --git a/drivers/video/fbdev/msm/mhl_sii8334.c b/drivers/video/fbdev/msm/mhl_sii8334.c
index 5d0ac99..cf45eb6 100644
--- a/drivers/video/fbdev/msm/mhl_sii8334.c
+++ b/drivers/video/fbdev/msm/mhl_sii8334.c
@@ -240,7 +240,7 @@
 {
 	int i, rc = 0;
 	struct device_node *of_node = NULL;
-	struct dss_gpio *temp_gpio = NULL;
+	struct mdss_gpio *temp_gpio = NULL;
 	struct platform_device *hdmi_pdev = NULL;
 	struct device_node *hdmi_tx_node = NULL;
 	int dt_gpio;
@@ -262,7 +262,7 @@
 
 	/* GPIOs */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -283,7 +283,7 @@
 
 	/* PWR */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -303,7 +303,7 @@
 
 	/* INTR */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -1716,7 +1716,7 @@
 static int mhl_gpio_config(struct mhl_tx_ctrl *mhl_ctrl, int on)
 {
 	int ret;
-	struct dss_gpio *temp_reset_gpio, *temp_intr_gpio;
+	struct mdss_gpio *temp_reset_gpio, *temp_intr_gpio;
 
 	/* caused too many line spills */
 	temp_reset_gpio = mhl_ctrl->pdata->gpios[MHL_TX_RESET_GPIO];
diff --git a/drivers/video/fbdev/msm/msm_dba/adv7533.c b/drivers/video/fbdev/msm/msm_dba/adv7533.c
index b628e1a..5b44a49 100644
--- a/drivers/video/fbdev/msm/msm_dba/adv7533.c
+++ b/drivers/video/fbdev/msm/msm_dba/adv7533.c
@@ -125,7 +125,7 @@
 	struct pinctrl_state *pinctrl_state_suspend;
 	bool audio;
 	bool disable_gpios;
-	struct dss_module_power power_data;
+	struct mdss_module_power power_data;
 	bool hdcp_enabled;
 	bool cec_enabled;
 	bool is_power_on;
@@ -433,7 +433,7 @@
 }
 
 static void adv7533_parse_vreg_dt(struct device *dev,
-				struct dss_module_power *mp)
+				struct mdss_module_power *mp)
 {
 	int i, rc = 0;
 	int dt_vreg_total = 0;
@@ -449,7 +449,7 @@
 		goto end;
 	}
 	mp->num_vreg = dt_vreg_total;
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 			dt_vreg_total, GFP_KERNEL);
 	if (!mp->vreg_config)
 		goto end;
@@ -1471,7 +1471,7 @@
 static int adv7533_config_vreg(struct adv7533 *pdata, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!pdata) {
 		pr_err("invalid input\n");
@@ -1486,7 +1486,7 @@
 	}
 
 	if (enable) {
-		rc = msm_dss_config_vreg(&pdata->i2c_client->dev,
+		rc = msm_mdss_config_vreg(&pdata->i2c_client->dev,
 					power_data->vreg_config,
 					power_data->num_vreg, 1);
 		if (rc) {
@@ -1495,7 +1495,7 @@
 			goto exit;
 		}
 	} else {
-		rc = msm_dss_config_vreg(&pdata->i2c_client->dev,
+		rc = msm_mdss_config_vreg(&pdata->i2c_client->dev,
 					power_data->vreg_config,
 					power_data->num_vreg, 0);
 		if (rc) {
@@ -1512,7 +1512,7 @@
 static int adv7533_enable_vreg(struct adv7533 *pdata, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!pdata) {
 		pr_err("invalid input\n");
@@ -1527,7 +1527,7 @@
 	}
 
 	if (enable) {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 					power_data->num_vreg, 1);
 		if (rc) {
 			pr_err("%s: Failed to enable vreg. Err=%d\n",
@@ -1535,7 +1535,7 @@
 			goto exit;
 		}
 	} else {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 					power_data->num_vreg, 0);
 		if (rc) {
 			pr_err("%s: Failed to disable vreg. Err=%d\n",
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 05a7fc0..ec1ee60 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -2033,7 +2033,7 @@
 {
 	int rc = 0;
 	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
-	int i, *vote_cnt;
+	int i, *vote_cnt = NULL;
 
 	void *m_clk_handle;
 	bool is_ecg = false;
@@ -2314,7 +2314,7 @@
 			if ((ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE) &&
 				(i != DSI_CORE_PM))
 				continue;
-			rc = msm_dss_enable_vreg(
+			rc = msm_mdss_enable_vreg(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 0);
 			if (rc) {
@@ -2374,7 +2374,7 @@
 				(!pdata->panel_info.cont_splash_enabled) &&
 				(i != DSI_CORE_PM))
 				continue;
-			rc = msm_dss_enable_vreg(
+			rc = msm_mdss_enable_vreg(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 1);
 			if (rc) {
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 4874b0f..518dfa1 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -169,15 +169,21 @@
 	return 0;
 }
 
-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
-				unsigned int new_timeout)
+static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
+				   unsigned int new_timeout)
 {
 	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-	wdog->timeout = new_timeout;
-
 	regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
 			   WDOG_SEC_TO_COUNT(new_timeout));
+}
+
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+				unsigned int new_timeout)
+{
+	__imx2_wdt_set_timeout(wdog, new_timeout);
+
+	wdog->timeout = new_timeout;
 	return 0;
 }
 
@@ -371,7 +377,11 @@
 
 	/* The watchdog IP block is running */
 	if (imx2_wdt_is_running(wdev)) {
-		imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+		/*
+		 * Don't update wdog->timeout, we'll restore the current value
+		 * during resume.
+		 */
+		__imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
 		imx2_wdt_ping(wdog);
 	}
 
diff --git a/fs/block_dev.c b/fs/block_dev.c
index cb936c9..9900693 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -614,6 +614,7 @@
 #ifdef CONFIG_SYSFS
 	INIT_LIST_HEAD(&bdev->bd_holder_disks);
 #endif
+	bdev->bd_bdi = &noop_backing_dev_info;
 	inode_init_once(&ei->vfs_inode);
 	/* Initialize mutex for freeze. */
 	mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -628,6 +629,12 @@
 	spin_lock(&bdev_lock);
 	list_del_init(&bdev->bd_list);
 	spin_unlock(&bdev_lock);
+	/* Detach inode from wb early as bdi_put() may free bdi->wb */
+	inode_detach_wb(inode);
+	if (bdev->bd_bdi != &noop_backing_dev_info) {
+		bdi_put(bdev->bd_bdi);
+		bdev->bd_bdi = &noop_backing_dev_info;
+	}
 }
 
 static const struct super_operations bdev_sops = {
@@ -698,6 +705,21 @@
 
 static LIST_HEAD(all_bdevs);
 
+/*
+ * If there is a bdev inode for this device, unhash it so that it gets evicted
+ * as soon as last inode reference is dropped.
+ */
+void bdev_unhash_inode(dev_t dev)
+{
+	struct inode *inode;
+
+	inode = ilookup5(blockdev_superblock, hash(dev), bdev_test, &dev);
+	if (inode) {
+		remove_inode_hash(inode);
+		iput(inode);
+	}
+}
+
 struct block_device *bdget(dev_t dev)
 {
 	struct block_device *bdev;
@@ -769,13 +791,22 @@
 
 	spin_lock(&bdev_lock);
 	bdev = inode->i_bdev;
-	if (bdev) {
+	if (bdev && !inode_unhashed(bdev->bd_inode)) {
 		bdgrab(bdev);
 		spin_unlock(&bdev_lock);
 		return bdev;
 	}
 	spin_unlock(&bdev_lock);
 
+	/*
+	 * i_bdev references block device inode that was already shut down
+	 * (corresponding device got removed).  Remove the reference and look
+	 * up block device inode again just in case new device got
+	 * reestablished under the same device number.
+	 */
+	if (bdev)
+		bd_forget(inode);
+
 	bdev = bdget(inode->i_rdev);
 	if (bdev) {
 		spin_lock(&bdev_lock);
@@ -1334,6 +1365,9 @@
 			}
 			bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
 		}
+
+		if (bdev->bd_bdi == &noop_backing_dev_info)
+			bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
 	} else {
 		if (bdev->bd_contains == bdev) {
 			ret = 0;
@@ -1586,12 +1620,6 @@
 		kill_bdev(bdev);
 
 		bdev_write_inode(bdev);
-		/*
-		 * Detaching bdev inode from its wb in __destroy_inode()
-		 * is too late: the queue which embeds its bdi (along with
-		 * root wb) can be gone as soon as we put_disk() below.
-		 */
-		inode_detach_wb(bdev->bd_inode);
 	}
 	if (bdev->bd_contains == bdev) {
 		if (disk->fops->release)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1cd3257..c66054c 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1816,7 +1816,7 @@
 	list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) {
 		if (!device->bdev)
 			continue;
-		bdi = blk_get_backing_dev_info(device->bdev);
+		bdi = device->bdev->bd_bdi;
 		if (bdi_congested(bdi, bdi_bits)) {
 			ret = 1;
 			break;
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index e4b48f3..c56253a 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1253,7 +1253,7 @@
 	/* Lock all pages first so we can lock the extent safely. */
 	ret = io_ctl_prepare_pages(io_ctl, inode, 0);
 	if (ret)
-		goto out;
+		goto out_unlock;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
 			 &cached_state);
@@ -1346,6 +1346,7 @@
 out_nospc:
 	cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list);
 
+out_unlock:
 	if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
 		up_write(&block_group->data_rwsem);
 
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 894d563..a8a1fb4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2063,8 +2063,15 @@
 		goto out;
 	 }
 
-	btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state,
-				  0);
+	ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+					&cached_state, 0);
+	if (ret) {
+		mapping_set_error(page->mapping, ret);
+		end_extent_writepage(page, ret, page_start, page_end);
+		ClearPageChecked(page);
+		goto out;
+	}
+
 	ClearPageChecked(page);
 	set_page_dirty(page);
 out:
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 06a77e4..fad7b37 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -366,7 +366,7 @@
 	 */
 	blk_start_plug(&plug);
 
-	bdi = blk_get_backing_dev_info(device->bdev);
+	bdi = device->bdev->bd_bdi;
 	fs_info = device->dev_root->fs_info;
 	limit = btrfs_async_submit_limit(fs_info);
 	limit = limit * 2 / 3;
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 5eb0412..73360df 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -318,9 +318,8 @@
 {
 	int i;
 	int rc;
-	char password_with_pad[CIFS_ENCPWD_SIZE];
+	char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
 
-	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
 	if (password)
 		strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 580b3a4..441d434 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1667,7 +1667,7 @@
 			tmp_end++;
 			if (!(tmp_end < end && tmp_end[1] == delim)) {
 				/* No it is not. Set the password to NULL */
-				kfree(vol->password);
+				kzfree(vol->password);
 				vol->password = NULL;
 				break;
 			}
@@ -1705,7 +1705,7 @@
 					options = end;
 			}
 
-			kfree(vol->password);
+			kzfree(vol->password);
 			/* Now build new password string */
 			temp_len = strlen(value);
 			vol->password = kzalloc(temp_len+1, GFP_KERNEL);
@@ -4159,7 +4159,7 @@
 		reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 out:
 	kfree(vol_info->username);
-	kfree(vol_info->password);
+	kzfree(vol_info->password);
 	kfree(vol_info);
 
 	return tcon;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index cf192f9..02e403a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3285,20 +3285,18 @@
 
 int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	int rc, xid;
+	int xid, rc = 0;
 	struct inode *inode = file_inode(file);
 
 	xid = get_xid();
 
-	if (!CIFS_CACHE_READ(CIFS_I(inode))) {
+	if (!CIFS_CACHE_READ(CIFS_I(inode)))
 		rc = cifs_zap_mapping(inode);
-		if (rc)
-			return rc;
-	}
-
-	rc = generic_file_mmap(file, vma);
-	if (rc == 0)
+	if (!rc)
+		rc = generic_file_mmap(file, vma);
+	if (!rc)
 		vma->vm_ops = &cifs_file_vm_ops;
+
 	free_xid(xid);
 	return rc;
 }
@@ -3308,16 +3306,16 @@
 	int rc, xid;
 
 	xid = get_xid();
+
 	rc = cifs_revalidate_file(file);
-	if (rc) {
+	if (rc)
 		cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
 			 rc);
-		free_xid(xid);
-		return rc;
-	}
-	rc = generic_file_mmap(file, vma);
-	if (rc == 0)
+	if (!rc)
+		rc = generic_file_mmap(file, vma);
+	if (!rc)
 		vma->vm_ops = &cifs_file_vm_ops;
+
 	free_xid(xid);
 	return rc;
 }
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 5419afe..323d8e3 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -99,14 +99,11 @@
 	kfree(buf_to_free->serverOS);
 	kfree(buf_to_free->serverDomain);
 	kfree(buf_to_free->serverNOS);
-	if (buf_to_free->password) {
-		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-		kfree(buf_to_free->password);
-	}
+	kzfree(buf_to_free->password);
 	kfree(buf_to_free->user_name);
 	kfree(buf_to_free->domainName);
-	kfree(buf_to_free->auth_key.response);
-	kfree(buf_to_free);
+	kzfree(buf_to_free->auth_key.response);
+	kzfree(buf_to_free);
 }
 
 struct cifs_tcon *
@@ -137,10 +134,7 @@
 	}
 	atomic_dec(&tconInfoAllocCount);
 	kfree(buf_to_free->nativeFileSystem);
-	if (buf_to_free->password) {
-		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-		kfree(buf_to_free->password);
-	}
+	kzfree(buf_to_free->password);
 	kfree(buf_to_free);
 }
 
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 69b610ad..94c4c19 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -585,8 +585,7 @@
 	}
 
 	/* check validate negotiate info response matches what we got earlier */
-	if (pneg_rsp->Dialect !=
-			cpu_to_le16(tcon->ses->server->vals->protocol_id))
+	if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
 		goto vneg_out;
 
 	if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 1493ceb..ec03cf6 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -114,6 +114,10 @@
 	int who = arg;
 	type = PIDTYPE_PID;
 	if (who < 0) {
+		/* avoid overflow below */
+		if (who == INT_MIN)
+			return;
+
 		type = PIDTYPE_PGID;
 		who = -who;
 	}
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index ff72ac6..77f1e25 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1226,7 +1226,7 @@
 	 * We set the bdi here to the queue backing, file systems can
 	 * overwrite this in ->fill_super()
 	 */
-	s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+	s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
 	return 0;
 }
 
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 78219d5..d6512cd 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -275,7 +275,7 @@
 {
 	struct kernfs_open_file *of = kernfs_of(file);
 	const struct kernfs_ops *ops;
-	size_t len;
+	ssize_t len;
 	char *buf;
 
 	if (of->atomic_write_len) {
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index bd81bcf..1ac1593 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -787,10 +787,8 @@
 
 	spin_lock(&dreq->lock);
 
-	if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
-		dreq->flags = 0;
+	if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
 		dreq->error = hdr->error;
-	}
 	if (dreq->error == 0) {
 		nfs_direct_good_bytes(dreq, hdr);
 		if (nfs_write_need_commit(hdr)) {
diff --git a/fs/nfs/io.c b/fs/nfs/io.c
index 1fc5d1c..d18ccc1 100644
--- a/fs/nfs/io.c
+++ b/fs/nfs/io.c
@@ -98,7 +98,7 @@
 {
 	if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
 		set_bit(NFS_INO_ODIRECT, &nfsi->flags);
-		nfs_wb_all(inode);
+		nfs_sync_mapping(inode->i_mapping);
 	}
 }
 
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index c444285..f1160cd 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -567,9 +567,13 @@
 	struct idmap_msg *im;
 	struct idmap *idmap = (struct idmap *)aux;
 	struct key *key = cons->key;
-	int ret = -ENOMEM;
+	int ret = -ENOKEY;
+
+	if (!aux)
+		goto out1;
 
 	/* msg and im are freed in idmap_pipe_destroy_msg */
+	ret = -ENOMEM;
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		goto out1;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index b7a07ba..b8e4474 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2145,7 +2145,7 @@
 		nfs_pageio_reset_write_mds(desc);
 		mirror->pg_recoalesce = 1;
 	}
-	hdr->release(hdr);
+	hdr->completion_ops->completion(hdr);
 }
 
 static enum pnfs_try_status
@@ -2256,7 +2256,7 @@
 		nfs_pageio_reset_read_mds(desc);
 		mirror->pg_recoalesce = 1;
 	}
-	hdr->release(hdr);
+	hdr->completion_ops->completion(hdr);
 }
 
 /*
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 9905735..9a3b382 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1806,6 +1806,8 @@
 		set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
 	next:
 		nfs_unlock_and_release_request(req);
+		/* Latency breaker */
+		cond_resched();
 	}
 	nfss = NFS_SERVER(data->inode);
 	if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c
index fd8c9a5..77d136a 100644
--- a/fs/nfs_common/grace.c
+++ b/fs/nfs_common/grace.c
@@ -30,7 +30,11 @@
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
 	spin_lock(&grace_lock);
-	list_add(&lm->list, grace_list);
+	if (list_empty(&lm->list))
+		list_add(&lm->list, grace_list);
+	else
+		WARN(1, "double list_add attempt detected in net %x %s\n",
+		     net->ns.inum, (net == &init_net) ? "(init_net)" : "");
 	spin_unlock(&grace_lock);
 }
 EXPORT_SYMBOL_GPL(locks_start_grace);
@@ -104,7 +108,9 @@
 {
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
-	BUG_ON(!list_empty(grace_list));
+	WARN_ONCE(!list_empty(grace_list),
+		  "net %x %s: grace_list is not empty\n",
+		  net->ns.inum, __func__);
 }
 
 static struct pernet_operations grace_net_ops = {
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 75f942a..81c018e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -59,10 +59,10 @@
 				gi->gid[i] = exp->ex_anon_gid;
 			else
 				gi->gid[i] = rqgi->gid[i];
-
-			/* Each thread allocates its own gi, no race */
-			groups_sort(gi);
 		}
+
+		/* Each thread allocates its own gi, no race */
+		groups_sort(gi);
 	} else {
 		gi = get_group_info(rqgi);
 	}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9ebb2d7..f463c4e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -63,12 +63,16 @@
 static const stateid_t currentstateid = {
 	.si_generation = 1,
 };
+static const stateid_t close_stateid = {
+	.si_generation = 0xffffffffU,
+};
 
 static u64 current_sessionid = 1;
 
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
 #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
+#define CLOSE_STATEID(stateid)  (!memcmp((stateid), &close_stateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
@@ -4866,7 +4870,8 @@
 	struct nfs4_stid *s;
 	__be32 status = nfserr_bad_stateid;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return status;
 	/* Client debugging aid. */
 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
@@ -4924,7 +4929,8 @@
 	else if (typemask & NFS4_DELEG_STID)
 		typemask |= NFS4_REVOKED_DELEG_STID;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return nfserr_bad_stateid;
 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
 	if (status == nfserr_stale_clientid) {
@@ -5175,15 +5181,9 @@
 	status = nfsd4_check_seqid(cstate, sop, seqid);
 	if (status)
 		return status;
-	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
-		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
-		/*
-		 * "Closed" stateid's exist *only* to return
-		 * nfserr_replay_me from the previous step, and
-		 * revoked delegations are kept only for free_stateid.
-		 */
-		return nfserr_bad_stateid;
-	mutex_lock(&stp->st_mutex);
+	status = nfsd4_lock_ol_stateid(stp);
+	if (status != nfs_ok)
+		return status;
 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
 	if (status == nfs_ok)
 		status = nfs4_check_fh(current_fh, &stp->st_stid);
@@ -5407,6 +5407,11 @@
 	nfsd4_close_open_stateid(stp);
 	mutex_unlock(&stp->st_mutex);
 
+	/* See RFC5661 sectionm 18.2.4 */
+	if (stp->st_stid.sc_client->cl_minorversion)
+		memcpy(&close->cl_stateid, &close_stateid,
+				sizeof(close->cl_stateid));
+
 	/* put reference from nfs4_preprocess_seqid_op */
 	nfs4_put_stid(&stp->st_stid);
 out:
@@ -7007,6 +7012,10 @@
 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
 	nn->conf_name_tree = RB_ROOT;
 	nn->unconf_name_tree = RB_ROOT;
+	nn->boot_time = get_seconds();
+	nn->grace_ended = false;
+	nn->nfsd4_manager.block_opens = true;
+	INIT_LIST_HEAD(&nn->nfsd4_manager.list);
 	INIT_LIST_HEAD(&nn->client_lru);
 	INIT_LIST_HEAD(&nn->close_lru);
 	INIT_LIST_HEAD(&nn->del_recall_lru);
@@ -7064,9 +7073,6 @@
 	ret = nfs4_state_create_net(net);
 	if (ret)
 		return ret;
-	nn->boot_time = get_seconds();
-	nn->grace_ended = false;
-	nn->nfsd4_manager.block_opens = true;
 	locks_start_grace(net, &nn->nfsd4_manager);
 	nfsd4_client_tracking_init(net);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index c95d369..ff158f0 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1068,7 +1068,7 @@
 	sb->s_time_gran = 1;
 	sb->s_max_links = NILFS_LINK_MAX;
 
-	sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
+	sb->s_bdi = bdev_get_queue(sb->s_bdev)->backing_dev_info;
 
 	err = load_nilfs(nilfs, sb);
 	if (err)
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c
index fe2cbeb..939aa06 100644
--- a/fs/orangefs/devorangefs-req.c
+++ b/fs/orangefs/devorangefs-req.c
@@ -161,7 +161,7 @@
 	struct orangefs_kernel_op_s *op, *temp;
 	__s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION;
 	static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
-	struct orangefs_kernel_op_s *cur_op = NULL;
+	struct orangefs_kernel_op_s *cur_op;
 	unsigned long ret;
 
 	/* We do not support blocking IO. */
@@ -181,6 +181,7 @@
 	}
 
 restart:
+	cur_op = NULL;
 	/* Get next op (if any) from top of list. */
 	spin_lock(&orangefs_request_list_lock);
 	list_for_each_entry_safe(op, temp, &orangefs_request_list, list) {
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 02cc613..5b2cbe5 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -446,7 +446,7 @@
 static ssize_t orangefs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
 	struct file *file = iocb->ki_filp;
-	loff_t pos = *(&iocb->ki_pos);
+	loff_t pos = iocb->ki_pos;
 	ssize_t rc = 0;
 
 	BUG_ON(iocb->private);
@@ -485,9 +485,6 @@
 		}
 	}
 
-	if (file->f_pos > i_size_read(file->f_mapping->host))
-		orangefs_i_size_write(file->f_mapping->host, file->f_pos);
-
 	rc = generic_write_checks(iocb, iter);
 
 	if (rc <= 0) {
@@ -501,7 +498,7 @@
 	 * pos to the end of the file, so we will wait till now to set
 	 * pos...
 	 */
-	pos = *(&iocb->ki_pos);
+	pos = iocb->ki_pos;
 
 	rc = do_readv_writev(ORANGEFS_IO_WRITE,
 			     file,
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index 45dd8f2..f28381a 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -570,17 +570,6 @@
 	sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE;			\
 } while (0)
 
-static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size)
-{
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	inode_lock(inode);
-#endif
-	i_size_write(inode, i_size);
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	inode_unlock(inode);
-#endif
-}
-
 static inline void orangefs_set_timeout(struct dentry *dentry)
 {
 	unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c
index abcfa3f..f61b008 100644
--- a/fs/orangefs/waitqueue.c
+++ b/fs/orangefs/waitqueue.c
@@ -28,10 +28,10 @@
  */
 void purge_waiting_ops(void)
 {
-	struct orangefs_kernel_op_s *op;
+	struct orangefs_kernel_op_s *op, *tmp;
 
 	spin_lock(&orangefs_request_list_lock);
-	list_for_each_entry(op, &orangefs_request_list, list) {
+	list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) {
 		gossip_debug(GOSSIP_WAIT_DEBUG,
 			     "pvfs2-client-core: purging op tag %llu %s\n",
 			     llu(op->tag),
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index f241b4e..a1be6ba 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -434,10 +434,14 @@
 	struct dentry *dentry = file->f_path.dentry;
 	struct file *realfile = od->realfile;
 
+	/* Nothing to sync for lower */
+	if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
+		return 0;
+
 	/*
 	 * Need to check if we started out being a lower dir, but got copied up
 	 */
-	if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
+	if (!od->is_upper) {
 		struct inode *inode = file_inode(file);
 
 		realfile = lockless_dereference(od->upperfile);
diff --git a/fs/pipe.c b/fs/pipe.c
index 8e0d9f2..3434553 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -609,12 +609,17 @@
 
 static bool too_many_pipe_buffers_soft(unsigned long user_bufs)
 {
-	return pipe_user_pages_soft && user_bufs >= pipe_user_pages_soft;
+	return pipe_user_pages_soft && user_bufs > pipe_user_pages_soft;
 }
 
 static bool too_many_pipe_buffers_hard(unsigned long user_bufs)
 {
-	return pipe_user_pages_hard && user_bufs >= pipe_user_pages_hard;
+	return pipe_user_pages_hard && user_bufs > pipe_user_pages_hard;
+}
+
+static bool is_unprivileged_user(void)
+{
+	return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
 }
 
 struct pipe_inode_info *alloc_pipe_info(void)
@@ -633,12 +638,12 @@
 
 	user_bufs = account_pipe_buffers(user, 0, pipe_bufs);
 
-	if (too_many_pipe_buffers_soft(user_bufs)) {
+	if (too_many_pipe_buffers_soft(user_bufs) && is_unprivileged_user()) {
 		user_bufs = account_pipe_buffers(user, pipe_bufs, 1);
 		pipe_bufs = 1;
 	}
 
-	if (too_many_pipe_buffers_hard(user_bufs))
+	if (too_many_pipe_buffers_hard(user_bufs) && is_unprivileged_user())
 		goto out_revert_acct;
 
 	pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer),
@@ -1018,13 +1023,19 @@
 
 /*
  * Currently we rely on the pipe array holding a power-of-2 number
- * of pages.
+ * of pages. Returns 0 on error.
  */
 static inline unsigned int round_pipe_size(unsigned int size)
 {
 	unsigned long nr_pages;
 
+	if (size < pipe_min_size)
+		size = pipe_min_size;
+
 	nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (nr_pages == 0)
+		return 0;
+
 	return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
 }
 
@@ -1040,6 +1051,8 @@
 	long ret = 0;
 
 	size = round_pipe_size(arg);
+	if (size == 0)
+		return -EINVAL;
 	nr_pages = size >> PAGE_SHIFT;
 
 	if (!nr_pages)
@@ -1061,7 +1074,7 @@
 	if (nr_pages > pipe->buffers &&
 			(too_many_pipe_buffers_hard(user_bufs) ||
 			 too_many_pipe_buffers_soft(user_bufs)) &&
-			!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
+			is_unprivileged_user()) {
 		ret = -EPERM;
 		goto out_revert_acct;
 	}
@@ -1123,13 +1136,18 @@
 int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
 		 size_t *lenp, loff_t *ppos)
 {
+	unsigned int rounded_pipe_max_size;
 	int ret;
 
 	ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
 	if (ret < 0 || !write)
 		return ret;
 
-	pipe_max_size = round_pipe_size(pipe_max_size);
+	rounded_pipe_max_size = round_pipe_size(pipe_max_size);
+	if (rounded_pipe_max_size == 0)
+		return -EINVAL;
+
+	pipe_max_size = rounded_pipe_max_size;
 	return ret;
 }
 
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 5c89a07..df7e079 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -507,23 +507,15 @@
 				return -EFAULT;
 		} else {
 			if (kern_addr_valid(start)) {
-				unsigned long n;
-
 				/*
 				 * Using bounce buffer to bypass the
 				 * hardened user copy kernel text checks.
 				 */
-				memcpy(buf, (char *) start, tsz);
-				n = copy_to_user(buffer, buf, tsz);
-				/*
-				 * We cannot distinguish between fault on source
-				 * and fault on destination. When this happens
-				 * we clear too and hope it will trigger the
-				 * EFAULT again.
-				 */
-				if (n) { 
-					if (clear_user(buffer + tsz - n,
-								n))
+				if (probe_kernel_read(buf, (void *) start, tsz)) {
+					if (clear_user(buffer, tsz))
+						return -EFAULT;
+				} else {
+					if (copy_to_user(buffer, buf, tsz))
 						return -EFAULT;
 				}
 			} else {
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 1bfac28..f9246ac 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2985,7 +2985,8 @@
 	pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld,"
 		" %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order));
 
-	register_shrinker(&dqcache_shrinker);
+	if (register_shrinker(&dqcache_shrinker))
+		panic("Cannot register dquot shrinker");
 
 	return 0;
 }
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index dc198bc..edc8ef7 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -513,9 +513,17 @@
 			       "inode has negative prealloc blocks count.");
 #endif
 	while (ei->i_prealloc_count > 0) {
-		reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
-		ei->i_prealloc_block++;
+		b_blocknr_t block_to_free;
+
+		/*
+		 * reiserfs_free_prealloc_block can drop the write lock,
+		 * which could allow another caller to free the same block.
+		 * We can protect against it by modifying the prealloc
+		 * state before calling it.
+		 */
+		block_to_free = ei->i_prealloc_block++;
 		ei->i_prealloc_count--;
+		reiserfs_free_prealloc_block(th, inode, block_to_free);
 		dirty = 1;
 	}
 	if (dirty)
@@ -1128,7 +1136,7 @@
 	hint->prealloc_size = 0;
 
 	if (!hint->formatted_node && hint->preallocate) {
-		if (S_ISREG(hint->inode->i_mode)
+		if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
 		    && hint->inode->i_size >=
 		    REISERFS_SB(hint->th->t_super)->s_alloc_options.
 		    preallocmin * hint->inode->i_sb->s_blocksize)
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 0a6ad4e..e101d70 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -2521,7 +2521,6 @@
 		return err;
 	if (inode->i_size < off + len - towrite)
 		i_size_write(inode, off + len - towrite);
-	inode->i_version++;
 	inode->i_mtime = inode->i_ctime = current_time(inode);
 	mark_inode_dirty(inode);
 	return len - towrite;
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index fffaad4..0b3b223 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -32,23 +32,20 @@
 	ci->data->under_android = pi->data->under_android;
 	ci->data->under_cache = pi->data->under_cache;
 	ci->data->under_obb = pi->data->under_obb;
-	set_top(ci, pi->top_data);
 }
 
 /* helper function for derived state */
 void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
-					uid_t uid, bool under_android,
-					struct sdcardfs_inode_data *top)
+					uid_t uid)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 
 	info->data->perm = perm;
 	info->data->userid = userid;
 	info->data->d_uid = uid;
-	info->data->under_android = under_android;
+	info->data->under_android = false;
 	info->data->under_cache = false;
 	info->data->under_obb = false;
-	set_top(info, top);
 }
 
 /* While renaming, there is a point where we want the path from dentry,
@@ -58,8 +55,8 @@
 				const struct qstr *name)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
-	struct sdcardfs_inode_data *parent_data =
-			SDCARDFS_I(d_inode(parent))->data;
+	struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent));
+	struct sdcardfs_inode_data *parent_data = parent_info->data;
 	appid_t appid;
 	unsigned long user_num;
 	int err;
@@ -80,13 +77,15 @@
 	inherit_derived_state(d_inode(parent), d_inode(dentry));
 
 	/* Files don't get special labels */
-	if (!S_ISDIR(d_inode(dentry)->i_mode))
+	if (!S_ISDIR(d_inode(dentry)->i_mode)) {
+		set_top(info, parent_info);
 		return;
+	}
 	/* Derive custom permissions based on parent and current node */
 	switch (parent_data->perm) {
 	case PERM_INHERIT:
 	case PERM_ANDROID_PACKAGE_CACHE:
-		/* Already inherited above */
+		set_top(info, parent_info);
 		break;
 	case PERM_PRE_ROOT:
 		/* Legacy internal layout places users at top level */
@@ -96,7 +95,6 @@
 			info->data->userid = 0;
 		else
 			info->data->userid = user_num;
-		set_top(info, info->data);
 		break;
 	case PERM_ROOT:
 		/* Assume masked off by default. */
@@ -104,24 +102,24 @@
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID;
 			info->data->under_android = true;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID:
 		if (qstr_case_eq(name, &q_data)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_DATA;
-			set_top(info, info->data);
 		} else if (qstr_case_eq(name, &q_obb)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_OBB;
 			info->data->under_obb = true;
-			set_top(info, info->data);
 			/* Single OBB directory is always shared */
 		} else if (qstr_case_eq(name, &q_media)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_MEDIA;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID_OBB:
@@ -132,13 +130,13 @@
 		if (appid != 0 && !is_excluded(name->name, parent_data->userid))
 			info->data->d_uid =
 				multiuser_get_uid(parent_data->userid, appid);
-		set_top(info, info->data);
 		break;
 	case PERM_ANDROID_PACKAGE:
 		if (qstr_case_eq(name, &q_cache)) {
 			info->data->perm = PERM_ANDROID_PACKAGE_CACHE;
 			info->data->under_cache = true;
 		}
+		set_top(info, parent_info);
 		break;
 	}
 }
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 8ed0ea1..137d876 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -821,8 +821,8 @@
 	return err;
 }
 
-static int sdcardfs_fillattr(struct vfsmount *mnt,
-				struct inode *inode, struct kstat *stat)
+static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode,
+				struct kstat *lower_stat, struct kstat *stat)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 	struct sdcardfs_inode_data *top = top_data_get(info);
@@ -837,12 +837,12 @@
 	stat->uid = make_kuid(&init_user_ns, top->d_uid);
 	stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
 	stat->rdev = inode->i_rdev;
-	stat->size = i_size_read(inode);
-	stat->atime = inode->i_atime;
-	stat->mtime = inode->i_mtime;
-	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
-	stat->blocks = inode->i_blocks;
+	stat->size = lower_stat->size;
+	stat->atime = lower_stat->atime;
+	stat->mtime = lower_stat->mtime;
+	stat->ctime = lower_stat->ctime;
+	stat->blksize = lower_stat->blksize;
+	stat->blocks = lower_stat->blocks;
 	data_put(top);
 	return 0;
 }
@@ -868,8 +868,7 @@
 		goto out;
 	sdcardfs_copy_and_fix_attrs(d_inode(dentry),
 			      d_inode(lower_path.dentry));
-	err = sdcardfs_fillattr(mnt, d_inode(dentry), stat);
-	stat->blocks = lower_stat.blocks;
+	err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat);
 out:
 	sdcardfs_put_lower_path(dentry, &lower_path);
 	return err;
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 0a2b516..37d4864 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -334,13 +334,11 @@
 	mutex_lock(&sdcardfs_super_list_lock);
 	if (sb_info->options.multiuser) {
 		setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
 	} else {
 		setup_derived_state(d_inode(sb->s_root), PERM_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
 	}
 	fixup_tmp_permissions(d_inode(sb->s_root));
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index d1d8bab..eda8e7a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -201,6 +201,7 @@
 	struct sdcardfs_inode_data *data;
 
 	/* top folder for ownership */
+	spinlock_t top_lock;
 	struct sdcardfs_inode_data *top_data;
 
 	struct inode vfs_inode;
@@ -379,7 +380,12 @@
 static inline struct sdcardfs_inode_data *top_data_get(
 		struct sdcardfs_inode_info *info)
 {
-	return data_get(info->top_data);
+	struct sdcardfs_inode_data *top_data;
+
+	spin_lock(&info->top_lock);
+	top_data = data_get(info->top_data);
+	spin_unlock(&info->top_lock);
+	return top_data;
 }
 
 extern void data_release(struct kref *ref);
@@ -401,15 +407,20 @@
 }
 
 static inline void set_top(struct sdcardfs_inode_info *info,
-			struct sdcardfs_inode_data *top)
+			struct sdcardfs_inode_info *top_owner)
 {
-	struct sdcardfs_inode_data *old_top = info->top_data;
+	struct sdcardfs_inode_data *old_top;
+	struct sdcardfs_inode_data *new_top = NULL;
 
-	if (top)
-		data_get(top);
-	info->top_data = top;
+	if (top_owner)
+		new_top = top_data_get(top_owner);
+
+	spin_lock(&info->top_lock);
+	old_top = info->top_data;
+	info->top_data = new_top;
 	if (old_top)
 		data_put(old_top);
+	spin_unlock(&info->top_lock);
 }
 
 static inline int get_gid(struct vfsmount *mnt,
@@ -513,8 +524,7 @@
 };
 
 extern void setup_derived_state(struct inode *inode, perm_t perm,
-		userid_t userid, uid_t uid, bool under_android,
-		struct sdcardfs_inode_data *top);
+			userid_t userid, uid_t uid);
 extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
 extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name);
 extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index b89947d..72d89b9 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -215,6 +215,9 @@
 
 	i->data = d;
 	kref_init(&d->refcount);
+	i->top_data = d;
+	spin_lock_init(&i->top_lock);
+	kref_get(&d->refcount);
 
 	i->vfs_inode.i_version = 1;
 	return &i->vfs_inode;
diff --git a/fs/super.c b/fs/super.c
index 2987fe3..847d82d 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1030,7 +1030,7 @@
 	 * We set the bdi here to the queue backing, file systems can
 	 * overwrite this in ->fill_super()
 	 */
-	s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+	s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
 	return 0;
 }
 
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index d9f9615..3979d76 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -270,7 +270,8 @@
 }
 
 static int __ubifs_setxattr(struct inode *host, const char *name,
-			    const void *value, size_t size, int flags)
+			    const void *value, size_t size, int flags,
+			    bool check_lock)
 {
 	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
@@ -279,7 +280,8 @@
 	union ubifs_key key;
 	int err;
 
-	ubifs_assert(inode_is_locked(host));
+	if (check_lock)
+		ubifs_assert(inode_is_locked(host));
 
 	if (size > UBIFS_MAX_INO_DATA)
 		return -ERANGE;
@@ -548,7 +550,8 @@
 		}
 		strcpy(name, XATTR_SECURITY_PREFIX);
 		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
-		err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0);
+		err = __ubifs_setxattr(inode, name, xattr->value,
+				       xattr->value_len, 0, false);
 		kfree(name);
 		if (err < 0)
 			break;
@@ -594,7 +597,8 @@
 	name = xattr_full_name(handler, name);
 
 	if (value)
-		return __ubifs_setxattr(inode, name, value, size, flags);
+		return __ubifs_setxattr(inode, name, value, size, flags,
+					true);
 	else
 		return __ubifs_removexattr(inode, name);
 }
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index d31cd1e..f3acecf 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -391,7 +391,7 @@
 	       (ip->i_df.if_flags & XFS_IFEXTENTS));
 	ASSERT(offset <= mp->m_super->s_maxbytes);
 
-	if (offset + count > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)offset + count > mp->m_super->s_maxbytes)
 		count = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
@@ -1295,7 +1295,7 @@
 	if (mapping_size > size)
 		mapping_size = size;
 	if (offset < i_size_read(inode) &&
-	    offset + mapping_size >= i_size_read(inode)) {
+	    (xfs_ufsize_t)offset + mapping_size >= i_size_read(inode)) {
 		/* limit mapping to block that spans EOF */
 		mapping_size = roundup_64(i_size_read(inode) - offset,
 					  i_blocksize(inode));
@@ -1347,7 +1347,7 @@
 	lockmode = xfs_ilock_data_map_shared(ip);
 
 	ASSERT(offset <= mp->m_super->s_maxbytes);
-	if (offset + size > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)offset + size > mp->m_super->s_maxbytes)
 		size = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index eca7bae..7a04b03 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -744,7 +744,7 @@
 	int			nmaps,
 	const struct xfs_buf_ops *ops)
 {
-	if (bdi_read_congested(target->bt_bdi))
+	if (bdi_read_congested(target->bt_bdev->bd_bdi))
 		return;
 
 	xfs_buf_read_map(target, map, nmaps,
@@ -1782,25 +1782,29 @@
 	btp->bt_mount = mp;
 	btp->bt_dev =  bdev->bd_dev;
 	btp->bt_bdev = bdev;
-	btp->bt_bdi = blk_get_backing_dev_info(bdev);
 
 	if (xfs_setsize_buftarg_early(btp, bdev))
-		goto error;
+		goto error_free;
 
 	if (list_lru_init(&btp->bt_lru))
-		goto error;
+		goto error_free;
 
 	if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL))
-		goto error;
+		goto error_lru;
 
 	btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count;
 	btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan;
 	btp->bt_shrinker.seeks = DEFAULT_SEEKS;
 	btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE;
-	register_shrinker(&btp->bt_shrinker);
+	if (register_shrinker(&btp->bt_shrinker))
+		goto error_pcpu;
 	return btp;
 
-error:
+error_pcpu:
+	percpu_counter_destroy(&btp->bt_io_count);
+error_lru:
+	list_lru_destroy(&btp->bt_lru);
+error_free:
 	kmem_free(btp);
 	return NULL;
 }
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index f961b19..c26b36a 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -107,7 +107,6 @@
 typedef struct xfs_buftarg {
 	dev_t			bt_dev;
 	struct block_device	*bt_bdev;
-	struct backing_dev_info	*bt_bdi;
 	struct xfs_mount	*bt_mount;
 	unsigned int		bt_meta_sectorsize;
 	size_t			bt_meta_sectormask;
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 9d06cc3..7a7b3cc 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -1004,14 +1004,22 @@
 	 * holding the lock before removing the dquot from the AIL.
 	 */
 	if ((lip->li_flags & XFS_LI_IN_AIL) &&
-	    lip->li_lsn == qip->qli_flush_lsn) {
+	    ((lip->li_lsn == qip->qli_flush_lsn) ||
+	     (lip->li_flags & XFS_LI_FAILED))) {
 
 		/* xfs_trans_ail_delete() drops the AIL lock. */
 		spin_lock(&ailp->xa_lock);
-		if (lip->li_lsn == qip->qli_flush_lsn)
+		if (lip->li_lsn == qip->qli_flush_lsn) {
 			xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
-		else
+		} else {
+			/*
+			 * Clear the failed state since we are about to drop the
+			 * flush lock
+			 */
+			if (lip->li_flags & XFS_LI_FAILED)
+				xfs_clear_li_failed(lip);
 			spin_unlock(&ailp->xa_lock);
+		}
 	}
 
 	/*
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 2c7a162..664dea1 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -137,6 +137,26 @@
 	wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
 }
 
+/*
+ * Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer
+ * have been failed during writeback
+ *
+ * this informs the AIL that the dquot is already flush locked on the next push,
+ * and acquires a hold on the buffer to ensure that it isn't reclaimed before
+ * dirty data makes it to disk.
+ */
+STATIC void
+xfs_dquot_item_error(
+	struct xfs_log_item	*lip,
+	struct xfs_buf		*bp)
+{
+	struct xfs_dquot	*dqp;
+
+	dqp = DQUOT_ITEM(lip)->qli_dquot;
+	ASSERT(!completion_done(&dqp->q_flush));
+	xfs_set_li_failed(lip, bp);
+}
+
 STATIC uint
 xfs_qm_dquot_logitem_push(
 	struct xfs_log_item	*lip,
@@ -144,13 +164,28 @@
 					      __acquires(&lip->li_ailp->xa_lock)
 {
 	struct xfs_dquot	*dqp = DQUOT_ITEM(lip)->qli_dquot;
-	struct xfs_buf		*bp = NULL;
+	struct xfs_buf		*bp = lip->li_buf;
 	uint			rval = XFS_ITEM_SUCCESS;
 	int			error;
 
 	if (atomic_read(&dqp->q_pincount) > 0)
 		return XFS_ITEM_PINNED;
 
+	/*
+	 * The buffer containing this item failed to be written back
+	 * previously. Resubmit the buffer for IO
+	 */
+	if (lip->li_flags & XFS_LI_FAILED) {
+		if (!xfs_buf_trylock(bp))
+			return XFS_ITEM_LOCKED;
+
+		if (!xfs_buf_resubmit_failed_buffers(bp, lip, buffer_list))
+			rval = XFS_ITEM_FLUSHING;
+
+		xfs_buf_unlock(bp);
+		return rval;
+	}
+
 	if (!xfs_dqlock_nowait(dqp))
 		return XFS_ITEM_LOCKED;
 
@@ -242,7 +277,8 @@
 	.iop_unlock	= xfs_qm_dquot_logitem_unlock,
 	.iop_committed	= xfs_qm_dquot_logitem_committed,
 	.iop_push	= xfs_qm_dquot_logitem_push,
-	.iop_committing = xfs_qm_dquot_logitem_committing
+	.iop_committing = xfs_qm_dquot_logitem_committing,
+	.iop_error	= xfs_dquot_item_error
 };
 
 /*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 98ca9f1..c5f2f1e 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2430,6 +2430,24 @@
 }
 
 /*
+ * Free any local-format buffers sitting around before we reset to
+ * extents format.
+ */
+static inline void
+xfs_ifree_local_data(
+	struct xfs_inode	*ip,
+	int			whichfork)
+{
+	struct xfs_ifork	*ifp;
+
+	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
+		return;
+
+	ifp = XFS_IFORK_PTR(ip, whichfork);
+	xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
+}
+
+/*
  * This is called to return an inode to the inode free list.
  * The inode should already be truncated to 0 length and have
  * no pages associated with it.  This routine also assumes that
@@ -2466,6 +2484,9 @@
 	if (error)
 		return error;
 
+	xfs_ifree_local_data(ip, XFS_DATA_FORK);
+	xfs_ifree_local_data(ip, XFS_ATTR_FORK);
+
 	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
 	ip->i_d.di_flags = 0;
 	ip->i_d.di_dmevmask = 0;
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index cac5735..5203560 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -88,6 +88,8 @@
 	return alg->setkey != shash_no_setkey;
 }
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
 			    struct hash_alg_common *alg,
 			    struct crypto_instance *inst);
diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h
index 894df59..d586f74 100644
--- a/include/crypto/poly1305.h
+++ b/include/crypto/poly1305.h
@@ -30,8 +30,6 @@
 };
 
 int crypto_poly1305_init(struct shash_desc *desc);
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-			   const u8 *key, unsigned int keylen);
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
 					const u8 *src, unsigned int srclen);
 int crypto_poly1305_update(struct shash_desc *desc,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6..07b2e96 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -59,6 +59,23 @@
 	void (*detach)(struct drm_bridge *bridge);
 
 	/**
+	 * @connector_init:
+	 *
+	 * This callback is used to init the connector from bridge side. In some
+	 * cases connector and bridge are created in different modules, and the
+	 * connector ops might need extra info from bridge. This callback offers
+	 * the opportunity to overwrite connector's behavior in external bridge.
+	 *
+	 * The connector_init callback is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * Zero on success, error code on failure.
+	 */
+	int (*connector_init)(struct drm_bridge *bridge,
+				struct drm_connector *connector);
+
+	/**
 	 * @mode_fixup:
 	 *
 	 * This callback is used to validate and adjust a mode. The paramater
@@ -214,5 +231,7 @@
 			struct drm_display_mode *adjusted_mode);
 void drm_bridge_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_enable(struct drm_bridge *bridge);
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector);
 
 #endif
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index b28c4a3..9a5114d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -560,6 +560,7 @@
  * @tile_v_loc: vertical location of this tile
  * @tile_h_size: horizontal size of this tile.
  * @tile_v_size: vertical size of this tile.
+ * @private: connector private data.
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -726,6 +727,8 @@
 	uint8_t num_h_tile, num_v_tile;
 	uint8_t tile_h_loc, tile_v_loc;
 	uint16_t tile_h_size, tile_v_size;
+
+	void *private;
 };
 
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 0dbddb3..3c2024d 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -140,6 +140,10 @@
 #define MIPI_DSI_CLOCK_NON_CONTINUOUS	BIT(10)
 /* transmit data in low power */
 #define MIPI_DSI_MODE_LPM		BIT(11)
+/* disable BLLP area */
+#define MIPI_DSI_MODE_VIDEO_BLLP	BIT(12)
+/* disable EOF BLLP area */
+#define MIPI_DSI_MODE_VIDEO_EOF_BLLP	BIT(13)
 
 enum mipi_dsi_pixel_format {
 	MIPI_DSI_FMT_RGB888,
diff --git a/include/dt-bindings/clock/mdm-clocks-9607.h b/include/dt-bindings/clock/mdm-clocks-9607.h
new file mode 100644
index 0000000..c2c5f26
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-9607.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDM_CLOCKS_9607_H
+#define __MDM_CLOCKS_9607_H
+
+/*PLL Sources */
+#define clk_gpll0_clk_src					 0x5933b69f
+#define clk_gpll0_ao_clk_src                                     0x6b2fb034
+#define clk_gpll2_clk_src					 0x7c34503b
+#define clk_gpll1_clk_src					 0x916f8847
+
+#define clk_a7sspll						 0x0b2e5cbd
+
+/*RPM and Voter clocks */
+#define clk_pcnoc_clk						 0xc1296d0f
+#define clk_pcnoc_a_clk						 0x9bcffee4
+#define clk_pcnoc_msmbus_clk					 0x2b53b688
+#define clk_pcnoc_msmbus_a_clk					 0x9753a54f
+#define clk_pcnoc_keepalive_a_clk				 0x9464f720
+#define clk_pcnoc_usb_clk					 0x57adc448
+#define clk_pcnoc_usb_a_clk					 0x11d6a74e
+#define clk_bimc_clk						 0x4b80bf00
+#define clk_bimc_a_clk						 0x4b25668a
+#define clk_bimc_msmbus_clk					 0xd212feea
+#define clk_bimc_msmbus_a_clk					 0x71d1a499
+#define clk_bimc_usb_clk					 0x9bd2b2bf
+#define clk_bimc_usb_a_clk					 0xea410834
+#define clk_qdss_clk						 0x1492202a
+#define clk_qdss_a_clk						 0xdd121669
+#define clk_qpic_clk						 0x3ce6f7bb
+#define clk_qpic_a_clk						 0xd70ccb7c
+#define clk_xo_clk_src						 0x23f5649f
+#define clk_xo_a_clk_src					 0x2fdd2c7c
+#define clk_xo_otg_clk						 0x79bca5cc
+#define clk_xo_lpm_clk						 0x2be48257
+#define clk_xo_pil_mss_clk					 0xe97a8354
+#define clk_bb_clk1						 0xf5304268
+#define clk_bb_clk1_pin						 0x6dd0a779
+
+/* SRCs */
+#define clk_apss_ahb_clk_src					 0x36f8495f
+#define clk_emac_0_125m_clk_src					 0x955db353
+#define clk_blsp1_qup1_i2c_apps_clk_src				 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src				 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src				 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src				 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src				 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src				 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src				 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src				 0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src				 0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src				 0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src				 0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src				 0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src				 0xf8146114
+#define clk_blsp1_uart2_apps_clk_src				 0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src				 0x600497f2
+#define clk_blsp1_uart4_apps_clk_src				 0x56bff15c
+#define clk_blsp1_uart5_apps_clk_src				 0x218ef697
+#define clk_blsp1_uart6_apps_clk_src				 0x8fbdbe4c
+#define clk_crypto_clk_src					 0x37a21414
+#define clk_gp1_clk_src						 0xad85b97a
+#define clk_gp2_clk_src						 0xfb1f0065
+#define clk_gp3_clk_src						 0x63b693d6
+#define clk_pdm2_clk_src					 0x31e494fd
+#define clk_sdcc1_apps_clk_src					 0xd4975db2
+#define clk_sdcc2_apps_clk_src					 0xfc46c821
+#define clk_emac_0_sys_25m_clk_src				 0x92fe3614
+#define clk_emac_0_tx_clk_src					 0x0487ec76
+#define clk_usb_hs_system_clk_src				 0x28385546
+#define clk_usb_hsic_clk_src					 0x141b01df
+#define clk_usb_hsic_io_cal_clk_src				 0xc83584bd
+#define clk_usb_hsic_system_clk_src				 0x52ef7224
+
+/*Branch*/
+#define clk_gcc_apss_ahb_clk					 0x2b0d39ff
+#define clk_gcc_apss_axi_clk					 0x1d47f4ff
+#define clk_gcc_prng_ahb_clk					 0x397e7eaa
+#define clk_gcc_qdss_dap_clk					 0x7fa9aa73
+#define clk_gcc_apss_tcu_clk					 0xaf56a329
+#define clk_gcc_blsp1_ahb_clk					 0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk				 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk				 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk				 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk				 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk				 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk				 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk				 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk				 0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk				 0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk				 0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk				 0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk				 0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk				 0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk				 0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk				 0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk				 0x26be16c0
+#define clk_gcc_blsp1_uart5_apps_clk				 0x28a6bc74
+#define clk_gcc_blsp1_uart6_apps_clk				 0x28fd3466
+#define clk_gcc_boot_rom_ahb_clk				 0xde2adeb1
+#define clk_gcc_crypto_ahb_clk					 0x94de4919
+#define clk_gcc_crypto_axi_clk					 0xd4415c9b
+#define clk_gcc_crypto_clk					 0x00d390d2
+#define clk_gcc_gp1_clk						 0x057f7b69
+#define clk_gcc_gp2_clk						 0x9bf83ffd
+#define clk_gcc_gp3_clk						 0xec6539ee
+#define clk_gcc_mss_cfg_ahb_clk					 0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk				 0x67544d62
+#define clk_gcc_pdm2_clk					 0x99d55711
+#define clk_gcc_pdm_ahb_clk					 0x365664f6
+#define clk_gcc_sdcc1_ahb_clk					 0x691e0caa
+#define clk_gcc_sdcc1_apps_clk					 0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk					 0x23d5727f
+#define clk_gcc_sdcc2_apps_clk					 0x861b20ac
+#define clk_gcc_emac_0_125m_clk					 0xe556de53
+#define clk_gcc_emac_0_ahb_clk					 0x6a741d38
+#define clk_gcc_emac_0_axi_clk					 0xf2b04fb4
+#define clk_gcc_emac_0_rx_clk					 0x869a4e5c
+#define clk_gcc_emac_0_sys_25m_clk				 0x5812832b
+#define clk_gcc_emac_0_sys_clk					 0x34fb62b0
+#define clk_gcc_emac_0_tx_clk					 0x331d3573
+#define clk_gcc_smmu_cfg_clk					 0x75eaefa5
+#define clk_gcc_usb2a_phy_sleep_clk				 0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk				 0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk					 0x72ce8032
+#define clk_gcc_usb_hs_system_clk				 0xa11972e5
+#define clk_gcc_usb_hsic_ahb_clk				 0x3ec2631a
+#define clk_gcc_usb_hsic_clk					 0x8de18b0e
+#define clk_gcc_usb_hsic_io_cal_clk				 0xbc21f776
+#define clk_gcc_usb_hsic_io_cal_sleep_clk			 0x20e09a22
+#define clk_gcc_usb_hsic_system_clk				 0x145e9366
+#define clk_gcc_usb2_hs_phy_only_clk				 0x0047179d
+#define clk_gcc_qusb2_phy_clk					 0x996884d5
+/* DEBUG */
+#define clk_gcc_debug_mux					 0x8121ac15
+#define clk_apss_debug_pri_mux					 0xc691ff55
+#define clk_apc0_m_clk						 0xce1e9473
+#define clk_apc1_m_clk						 0x990fbaf7
+#define clk_apc2_m_clk						 0x252cd4ae
+#define clk_apc3_m_clk						 0x78c64486
+#define clk_l2_m_clk						 0x4bedf4d0
+
+#define clk_wcnss_m_clk						 0x709f430b
+
+#endif
diff --git a/include/dt-bindings/clock/mdm-clocks-9650.h b/include/dt-bindings/clock/mdm-clocks-9650.h
new file mode 100644
index 0000000..d62a806
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-9650.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_9650_H
+#define __MSM_CLOCKS_9650_H
+
+/* RPM controlled clocks */
+#define clk_xo 0xf13dfee3
+#define clk_xo_a_clk 0xd939b99b
+#define clk_ce_clk 0xd8bc64e1
+#define clk_ce_a_clk 0x4dfefd47
+#define clk_pcnoc_clk 0xc1296d0f
+#define clk_pcnoc_a_clk 0x9bcffee4
+#define clk_bimc_clk 0x4b80bf00
+#define clk_bimc_a_clk 0x4b25668a
+#define clk_snoc_clk 0x2c341aa0
+#define clk_snoc_a_clk 0x8fcef2af
+#define clk_ipa_clk 0xfa685cda
+#define clk_ipa_a_clk 0xeeec2919
+#define clk_qpic_clk 0x3ce6f7bb
+#define clk_qpic_a_clk 0xd70ccb7c
+#define clk_qdss_clk 0x1492202a
+#define clk_qdss_a_clk 0xdd121669
+#define clk_bimc_msmbus_clk 0xd212feea
+#define clk_bimc_msmbus_a_clk 0x71d1a499
+#define clk_mcd_ce_clk 0x7ad13979
+#define clk_pcnoc_keepalive_a_clk 0x9464f720
+#define clk_pcnoc_msmbus_clk 0x2b53b688
+#define clk_pcnoc_msmbus_a_clk 0x9753a54f
+#define clk_pcnoc_pm_clk 0x5e636b5d
+#define clk_pcnoc_sps_clk 0x23d3f584
+#define clk_qcedev_ce_clk 0x2e7f9cee
+#define clk_qcrypto_ce_clk 0xd8cd060b
+#define clk_qseecom_ce_clk 0xea036e4b
+#define clk_scm_ce_clk 0xfd35bb87
+#define clk_snoc_msmbus_clk 0xe6900bb6
+#define clk_snoc_msmbus_a_clk 0x5d4683bd
+#define clk_cxo_dwc3_clk 0xf79c19f6
+#define clk_cxo_lpm_clk 0x94adbf3d
+#define clk_cxo_otg_clk 0x4eec0bb9
+#define clk_div_clk1 0xaa1157a6
+#define clk_div_clk1_ao 0x6b943d68
+#define clk_ln_bb_clk 0x3ab0b36d
+#define clk_ln_bb_a_clk 0xc7257ea8
+#define clk_rf_clk1 0xaabeea5a
+#define clk_rf_clk1_ao 0x72a10cb8
+#define clk_rf_clk1_pin 0x8f463562
+#define clk_rf_clk1_pin_ao 0x62549ff6
+#define clk_rf_clk2 0x24a30992
+#define clk_rf_clk2_ao 0x944d8bbd
+#define clk_rf_clk2_pin 0xa7c5602a
+#define clk_rf_clk2_pin_ao 0x2d75eb4d
+#define clk_rf_clk3 0xb673936b
+#define clk_rf_clk3_ao 0x038bb968
+#define clk_rf_clk3_pin 0x726f53f5
+#define clk_rf_clk3_pin_ao 0x76f9240f
+
+/* APSS controlled clocks */
+#define clk_gpll0 0x1ebe3bc4
+#define clk_gpll0_ao 0xa1368304
+#define clk_gpll0_out_msscc 0x7d794829
+#define clk_apss_ahb_clk_src 0x36f8495f
+#define clk_usb30_master_clk_src 0xc6262f89
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_uart1_apps_clk_src 0xf8146114
+#define clk_blsp1_uart2_apps_clk_src 0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src 0x600497f2
+#define clk_blsp1_uart4_apps_clk_src 0x56bff15c
+#define clk_gp1_clk_src 0xad85b97a
+#define clk_gp2_clk_src 0xfb1f0065
+#define clk_gp3_clk_src 0x63b693d6
+#define clk_pcie_aux_clk_src 0xebc50566
+#define clk_pdm2_clk_src 0x31e494fd
+#define clk_sdcc1_apps_clk_src 0xd4975db2
+#define clk_usb30_mock_utmi_clk_src 0xa024a976
+#define clk_usb3_aux_clk_src 0xfde7ae09
+#define clk_gcc_pcie_phy_reset 0x9bc3c959
+#define clk_gcc_qusb2a_phy_reset 0x2a9dfa9f
+#define clk_gcc_usb3phy_phy_reset 0xb1a4f885
+#define clk_gcc_usb3_phy_reset 0x03d559f1
+#define clk_gpll0_out_main_cgc 0xb0298998
+#define clk_gcc_blsp1_ahb_clk 0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_uart1_apps_clk 0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk 0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk 0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk 0x26be16c0
+#define clk_gcc_boot_rom_ahb_clk 0xde2adeb1
+#define clk_gcc_dcc_clk 0xd1000c50
+#define clk_gpll0_out_main_div2_cgc 0xc76ac7ae
+#define clk_gcc_gp1_clk 0x057f7b69
+#define clk_gcc_gp2_clk 0x9bf83ffd
+#define clk_gcc_gp3_clk 0xec6539ee
+#define clk_gcc_mss_q6_bimc_axi_clk 0x67544d62
+#define clk_gcc_pcie_axi_clk 0xb833d9e3
+#define clk_gcc_pcie_axi_mstr_clk 0x54d09178
+#define clk_gcc_pcie_cfg_ahb_clk 0xddc9a515
+#define clk_gcc_pcie_pipe_clk 0x8be62558
+#define clk_gcc_pcie_sleep_clk 0x8b8bfc3b
+#define clk_gcc_pdm2_clk 0x99d55711
+#define clk_gcc_pdm_ahb_clk 0x365664f6
+#define clk_gcc_prng_ahb_clk 0x397e7eaa
+#define clk_gcc_sdcc1_ahb_clk 0x691e0caa
+#define clk_gcc_sdcc1_apps_clk 0x9ad6fb96
+#define clk_gcc_apss_tcu_clk 0xaf56a329
+#define clk_gcc_pcie_axi_tbu_clk 0xab70f06e
+#define clk_gcc_pcie_ref_clk 0x63fca50a
+#define clk_gcc_usb_ss_ref_clk 0xb85dadfa
+#define clk_gcc_qusb_ref_clk 0x16e35a90
+#define clk_gcc_smmu_cfg_clk 0x75eaefa5
+#define clk_gcc_usb3_axi_tbu_clk 0x18779c6e
+#define clk_gcc_sys_noc_usb3_axi_clk 0x94d26800
+#define clk_gcc_usb30_master_clk 0xb3b4e2cb
+#define clk_gcc_usb30_mock_utmi_clk 0xa800b65a
+#define clk_gcc_usb30_sleep_clk 0xd0b65c92
+#define clk_gcc_usb3_aux_clk 0x555d16b2
+#define clk_gcc_usb3_pipe_clk 0x26f8a97a
+#define clk_gcc_usb_phy_cfg_ahb_clk 0xccb7e26f
+#define clk_gcc_mss_cfg_ahb_clk 0x111cde81
+
+/* a7pll */
+#define clk_a7pll_clk		0x3dd5dd94
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux 0x8121ac15
+
+/* Audio External Clocks */
+#define clk_audio_lpass_mclk 0x575ec22b
+
+/* sdx20 */
+#define clk_gcc_pcie_aux_clk 0x06d8e933
+#define clk_pcie_aux_phy_clk_src 0x672e340c
+#define clk_pcie20_phy_aux_clk 0x613dfb19
+#define clk_pcie_aux_mux_clk 0x3e75325b
+
+#endif
diff --git a/include/dt-bindings/clock/mdm-clocks-hwio-9607.h b/include/dt-bindings/clock/mdm-clocks-hwio-9607.h
new file mode 100644
index 0000000..e8bb4e0
--- /dev/null
+++ b/include/dt-bindings/clock/mdm-clocks-hwio-9607.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDM_CLOCKS_9607_HWIO_H
+#define __MDM_CLOCKS_9607_HWIO_H
+
+#define GPLL0_MODE				0x21000
+#define GPLL0_STATUS				0x21024
+#define GPLL1_MODE				0x20000
+#define GPLL1_STATUS				0x2001C
+#define GPLL2_MODE				0x25000
+#define GPLL2_STATUS				0x25024
+#define APCS_GPLL_ENA_VOTE			0x45000
+#define APCS_MODE				0x00018
+#define APSS_AHB_CMD_RCGR			0x46000
+#define PRNG_AHB_CBCR				0x13004
+#define EMAC_0_125M_CMD_RCGR			0x4E028
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR		 0x200C
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR		 0x2024
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR		 0x3000
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR		 0x3014
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR		 0x4000
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR		 0x4024
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR		 0x5000
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR		 0x5024
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR		 0x6000
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR		 0x6024
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR		 0x7000
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR		 0x7024
+#define BLSP1_UART1_APPS_CMD_RCGR		 0x2044
+#define BLSP1_UART2_APPS_CMD_RCGR		 0x3034
+#define BLSP1_UART3_APPS_CMD_RCGR		 0x4044
+#define BLSP1_UART4_APPS_CMD_RCGR		 0x5044
+#define BLSP1_UART5_APPS_CMD_RCGR		 0x6044
+#define BLSP1_UART6_APPS_CMD_RCGR		 0x7044
+#define CRYPTO_CMD_RCGR			0x16004
+#define GP1_CMD_RCGR				 0x8004
+#define GP2_CMD_RCGR				 0x9004
+#define GP3_CMD_RCGR				 0xA004
+#define PDM2_CMD_RCGR				0x44010
+#define QPIC_CMD_RCGR				0x3F004
+#define SDCC1_APPS_CMD_RCGR			0x42004
+#define SDCC2_APPS_CMD_RCGR			0x43004
+#define EMAC_0_SYS_25M_CMD_RCGR		0x4E03C
+#define EMAC_0_TX_CMD_RCGR			0x4E014
+#define USB_HS_SYSTEM_CMD_RCGR			0x41010
+#define USB_HSIC_CMD_RCGR			0x3D018
+#define USB_HSIC_IO_CAL_CMD_RCGR		0x3D030
+#define USB_HSIC_SYSTEM_CMD_RCGR		0x3D000
+#define BIMC_PCNOC_AXI_CBCR			0x31024
+#define BLSP1_AHB_CBCR				 0x1008
+#define APCS_CLOCK_BRANCH_ENA_VOTE		0x45004
+#define BLSP1_QUP1_I2C_APPS_CBCR		 0x2008
+#define BLSP1_QUP1_SPI_APPS_CBCR		 0x2004
+#define BLSP1_QUP2_I2C_APPS_CBCR		 0x3010
+#define BLSP1_QUP2_SPI_APPS_CBCR		 0x300C
+#define BLSP1_QUP3_I2C_APPS_CBCR		 0x4020
+#define BLSP1_QUP3_SPI_APPS_CBCR		 0x401C
+#define BLSP1_QUP4_I2C_APPS_CBCR		 0x5020
+#define BLSP1_QUP4_SPI_APPS_CBCR		 0x501C
+#define BLSP1_QUP5_I2C_APPS_CBCR		 0x6020
+#define BLSP1_QUP5_SPI_APPS_CBCR		 0x601C
+#define BLSP1_QUP6_I2C_APPS_CBCR		 0x7020
+#define BLSP1_QUP6_SPI_APPS_CBCR		 0x701C
+#define BLSP1_UART1_APPS_CBCR			 0x203C
+#define BLSP1_UART2_APPS_CBCR			 0x302C
+#define BLSP1_UART3_APPS_CBCR			 0x403C
+#define BLSP1_UART4_APPS_CBCR			 0x503C
+#define BLSP1_UART5_APPS_CBCR			 0x603C
+#define BLSP1_UART6_APPS_CBCR			 0x703C
+#define APSS_AHB_CBCR				0x4601C
+#define APSS_AXI_CBCR				0x46020
+#define BOOT_ROM_AHB_CBCR			0x1300C
+#define CRYPTO_AHB_CBCR			0x16024
+#define CRYPTO_AXI_CBCR			0x16020
+#define CRYPTO_CBCR				0x1601C
+#define GP1_CBCR				 0x8000
+#define GP2_CBCR				 0x9000
+#define GP3_CBCR				 0xA000
+#define MSS_CFG_AHB_CBCR			0x49000
+#define MSS_Q6_BIMC_AXI_CBCR			0x49004
+#define PCNOC_APSS_AHB_CBCR			0x27030
+#define PDM2_CBCR				0x4400C
+#define PDM_AHB_CBCR				0x44004
+#define QPIC_AHB_CBCR				0x3F01C
+#define QPIC_CBCR				0x3F018
+#define QPIC_SYSTEM_CBCR			0x3F020
+#define SDCC1_AHB_CBCR				0x4201C
+#define SDCC1_APPS_CBCR			0x42018
+#define SDCC2_AHB_CBCR				0x4301C
+#define SDCC2_APPS_CBCR			0x43018
+#define EMAC_0_125M_CBCR			0x4E010
+#define EMAC_0_AHB_CBCR			0x4E000
+#define EMAC_0_AXI_CBCR			0x4E008
+#define EMAC_0_RX_CBCR				0x4E030
+#define EMAC_0_SYS_25M_CBCR			0x4E038
+#define EMAC_0_SYS_CBCR				0x4E034
+#define EMAC_0_TX_CBCR				0x4E00C
+#define APSS_TCU_CBCR				0x12018
+#define SMMU_CFG_CBCR				0x12038
+#define QDSS_DAP_CBCR				0x29084
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE		0x4500C
+#define USB2A_PHY_SLEEP_CBCR			0x4102C
+#define USB_HS_PHY_CFG_AHB_CBCR			0x41030
+#define USB_HS_AHB_CBCR				0x41008
+#define USB_HS_SYSTEM_CBCR			0x41004
+#define USB_HS_BCR				0x41000
+#define USB_HSIC_AHB_CBCR			0x3D04C
+#define USB_HSIC_CBCR				0x3D050
+#define USB_HSIC_IO_CAL_CBCR			0x3D054
+#define USB_HSIC_IO_CAL_SLEEP_CBCR		0x3D058
+#define USB_HSIC_SYSTEM_CBCR			0x3D048
+#define USB_HS_HSIC_BCR				0x3D05C
+#define USB2_HS_PHY_ONLY_BCR			0x41034
+#define QUSB2_PHY_BCR				0x4103C
+#define GCC_DEBUG_CLK_CTL			0x74000
+#define CLOCK_FRQ_MEASURE_CTL			0x74004
+#define CLOCK_FRQ_MEASURE_STATUS		0x74008
+#define PLLTEST_PAD_CFG			0x7400C
+#define GCC_XO_DIV4_CBCR			0x30034
+
+#define xo_source_val				0
+#define xo_a_source_val			0
+#define gpll0_source_val			1
+#define gpll2_source_val			1
+#define emac_0_125m_clk_source_val		1
+#define emac_0_tx_clk_source_val		2
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_EXT(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+		}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+		[VDD_DIG_##l3] = (f3),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOWER,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_LEVEL_NONE,              /* VDD_DIG_NONE */
+	RPM_REGULATOR_LEVEL_SVS,		/* VDD_DIG_LOWER */
+	RPM_REGULATOR_LEVEL_SVS_PLUS,		/*VDD_DIG_LOW*/
+	RPM_REGULATOR_LEVEL_NOM,            /* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_LEVEL_TURBO,		/* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+
+#define VDD_STROMER_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_stromer_pll, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+
+#define RPM_MISC_CLK_TYPE			0x306b6c63
+#define RPM_BUS_CLK_TYPE			0x316b6c63
+#define RPM_MEM_CLK_TYPE			0x326b6c63
+#define RPM_SMD_KEY_ENABLE			0x62616E45
+#define RPM_QPIC_CLK_TYPE			0x63697071
+
+#define XO_ID					0x0
+#define QDSS_ID				0x1
+#define PCNOC_ID				0x0
+#define BIMC_ID				0x0
+#define QPIC_ID				0x0
+
+/* XO clock */
+#define BB_CLK1_ID				1
+#define RF_CLK2_ID				5
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8909.h b/include/dt-bindings/clock/msm-clocks-8909.h
new file mode 100644
index 0000000..b46c724
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8909.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8909_H
+#define __MSM_CLOCKS_8909_H
+
+/* GPLLs */
+#define clk_gpll0_clk_src			0x5933b69f
+#define clk_gpll0_ao_clk_src			0x6b2fb034
+#define clk_gpll1_clk_src			0x916f8847
+#define clk_gpll2_clk_src			0x7c34503b
+
+/* SR2PLL */
+#define clk_a7sspll				0xf761da94
+
+/* SRCs */
+#define clk_apss_ahb_clk_src			0x36f8495f
+#define clk_blsp1_qup1_i2c_apps_clk_src		0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src		0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src		0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src		0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src		0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src		0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src		0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src		0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src		0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src		0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src		0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src		0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src		0xf8146114
+#define clk_blsp1_uart2_apps_clk_src		0xfc9c2f73
+#define clk_byte0_clk_src			0x75cc885b
+#define clk_cci_clk_src				0x822f3d97
+#define clk_cpp_clk_src				0x8382f56d
+#define clk_camss_top_ahb_clk_src		0xf92304fb
+#define clk_camss_gp0_clk_src			0x43b063e9
+#define clk_camss_gp1_clk_src			0xa3315f1b
+#define clk_crypto_clk_src			0x37a21414
+#define clk_csi0_clk_src			0x227e65bc
+#define clk_csi1_clk_src			0x6a2a6c36
+#define clk_csi0phytimer_clk_src		0xc8a309be
+#define clk_csi1phytimer_clk_src		0x7c0fe23a
+#define clk_esc0_clk_src			0xb41d7c38
+#define clk_gfx3d_clk_src			0x917f76ef
+#define clk_gp1_clk_src				0xad85b97a
+#define clk_gp2_clk_src				0xfb1f0065
+#define clk_gp3_clk_src				0x63b693d6
+#define clk_jpeg0_clk_src			0x9a0a0ac3
+#define clk_mdp_clk_src				0x6dc1f8f1
+#define clk_mclk0_clk_src			0x266b3853
+#define clk_mclk1_clk_src			0xa73cad0c
+#define clk_pclk0_clk_src			0xccac1f35
+#define clk_pdm2_clk_src			0x31e494fd
+#define clk_sdcc1_apps_clk_src			0xd4975db2
+#define clk_sdcc2_apps_clk_src			0xfc46c821
+#define clk_usb_hs_system_clk_src		0x28385546
+#define clk_gcc_qusb2_phy_clk			0x996884d5
+#define clk_gcc_usb2_hs_phy_only_clk		0x0047179d
+#define clk_vsync_clk_src			0xecb43940
+#define clk_vfe0_clk_src			0xa0c2bd8f
+#define clk_vcodec0_clk_src			0xbc193019
+
+/* BRANCHEs*/
+#define clk_gcc_apss_ahb_clk			0x2b0d39ff
+#define clk_gcc_blsp1_ahb_clk			0x8caa5b4f
+#define clk_gcc_boot_rom_ahb_clk		0xde2adeb1
+#define clk_gcc_crypto_ahb_clk			0x94de4919
+#define clk_gcc_crypto_axi_clk			0xd4415c9b
+#define clk_gcc_crypto_clk			0x00d390d2
+#define clk_gcc_prng_ahb_clk			0x397e7eaa
+#define clk_gcc_apss_tcu_clk			0xaf56a329
+#define clk_gcc_gfx_tbu_clk			0x18bb9a90
+#define clk_gcc_gtcu_ahb_clk			0xb432168e
+#define clk_gcc_jpeg_tbu_clk			0xcf8fd944
+#define clk_gcc_mdp_tbu_clk			0x82287f76
+#define clk_gcc_smmu_cfg_clk			0x75eaefa5
+#define clk_gcc_venus_tbu_clk			0x7e0b97ce
+#define clk_gcc_vfe_tbu_clk			0x061f2f95
+#define clk_gcc_blsp1_qup1_i2c_apps_clk		0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk		0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk		0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk		0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk		0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk		0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk		0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk		0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk		0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk		0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk		0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk		0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk		0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk		0xf8a61c96
+#define clk_gcc_camss_cci_ahb_clk		0xa81c11ba
+#define clk_gcc_camss_cci_clk			0xb7dd8824
+#define clk_gcc_camss_csi0_ahb_clk		0x175d672a
+#define clk_gcc_camss_csi0_clk			0x6b01b3e1
+#define clk_gcc_camss_csi0phy_clk		0x06a41ff7
+#define clk_gcc_camss_csi0pix_clk		0x61a8a930
+#define clk_gcc_camss_csi0rdi_clk		0x7053c7ae
+#define clk_gcc_camss_csi1_ahb_clk		0x2c2dc261
+#define clk_gcc_camss_csi1_clk			0x1aba4a8c
+#define clk_gcc_camss_csi1phy_clk		0x0fd1d1fa
+#define clk_gcc_camss_csi1pix_clk		0x87fc98d8
+#define clk_gcc_camss_csi1rdi_clk		0x6ac996fe
+#define clk_gcc_camss_csi_vfe0_clk		0xcc73453c
+#define clk_gcc_camss_gp0_clk			0xd2bc3892
+#define clk_gcc_camss_gp1_clk			0xe4c013e1
+#define clk_gcc_camss_ispif_ahb_clk		0x3c0a858f
+#define clk_gcc_camss_jpeg0_clk			0x1ed3f032
+#define clk_gcc_camss_jpeg_ahb_clk		0x3bfa7603
+#define clk_gcc_camss_jpeg_axi_clk		0x3e278896
+#define clk_gcc_camss_mclk0_clk			0x80902deb
+#define clk_gcc_camss_mclk1_clk			0x5002d85f
+#define clk_gcc_camss_micro_ahb_clk		0xfbbee8cf
+#define clk_gcc_camss_csi0phytimer_clk		0xf8897589
+#define clk_gcc_camss_csi1phytimer_clk		0x4d26438f
+#define clk_gcc_camss_ahb_clk			0x9894b414
+#define clk_gcc_camss_top_ahb_clk		0x4e814a78
+#define clk_gcc_camss_cpp_ahb_clk		0x4ac95e14
+#define clk_gcc_camss_cpp_clk			0x7118a0de
+#define clk_gcc_camss_vfe0_clk			0xaaa3cd97
+#define clk_gcc_camss_vfe_ahb_clk		0x4050f47a
+#define clk_gcc_camss_vfe_axi_clk		0x77fe2384
+#define clk_gcc_oxili_gmem_clk			0x5620913a
+#define clk_gcc_gp1_clk				0x057f7b69
+#define clk_gcc_gp2_clk				0x9bf83ffd
+#define clk_gcc_gp3_clk				0xec6539ee
+#define clk_gcc_mdss_ahb_clk			0xbfb92ed3
+#define clk_gcc_mdss_axi_clk			0x668f51de
+#define clk_gcc_mdss_byte0_clk			0x35da7862
+#define clk_gcc_mdss_esc0_clk			0xaec5cb25
+#define clk_gcc_mdss_mdp_clk			0x22f3521f
+#define clk_gcc_mdss_pclk0_clk			0xcc5c5c77
+#define clk_gcc_mdss_vsync_clk			0x32a09f1f
+#define clk_gcc_mss_cfg_ahb_clk			0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk		0x67544d62
+#define clk_gcc_oxili_ahb_clk			0xd15c8a00
+#define clk_gcc_oxili_gfx3d_clk			0x49a51fd9
+#define clk_gcc_pdm2_clk			0x99d55711
+#define clk_gcc_pdm_ahb_clk			0x365664f6
+#define clk_gcc_sdcc1_ahb_clk			0x691e0caa
+#define clk_gcc_sdcc1_apps_clk			0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk			0x23d5727f
+#define clk_gcc_sdcc2_apps_clk			0x861b20ac
+#define clk_gcc_usb2a_phy_sleep_clk		0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk		0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk			0x72ce8032
+#define clk_gcc_usb_hs_system_clk		0xa11972e5
+#define clk_gcc_venus0_ahb_clk			0x08d778c6
+#define clk_gcc_venus0_axi_clk			0xcdf4c8f6
+#define clk_gcc_venus0_vcodec0_clk		0xf76a02bb
+#define clk_gcc_venus0_core0_vcodec0_clk	0x83a7f549
+#define clk_gcc_gfx_tcu_clk			0x59505e55
+#define clk_gcc_gtcu_ahb_bridge_clk		0x19d2c5fe
+#define clk_gcc_bimc_gpu_clk			0x19922503
+#define clk_gcc_bimc_gfx_clk			0x3edd69ad
+#define clk_gcc_snoc_qosgen_clk			0x37d40ce2
+
+#define clk_pixel_clk_src			0x8b6f83d8
+#define clk_byte_clk_src			0x3a911c53
+#define clk_dsi_pll0_byte_clk_src		0x44539836
+#define clk_dsi_pll0_pixel_clk_src		0x5767c287
+
+/* RPM */
+#define clk_pcnoc_clk				0xc1296d0f
+#define clk_pcnoc_a_clk				0x9bcffee4
+#define clk_pcnoc_msmbus_clk			0x2b53b688
+#define clk_pcnoc_msmbus_a_clk			0x9753a54f
+#define clk_pcnoc_keepalive_a_clk		0x9464f720
+#define clk_pcnoc_usb_a_clk			0x11d6a74e
+#define clk_snoc_clk				0x2c341aa0
+#define clk_snoc_a_clk				0x8fcef2af
+#define clk_snoc_msmbus_clk			0xe6900bb6
+#define clk_snoc_msmbus_a_clk			0x5d4683bd
+#define clk_snoc_mmnoc_axi_clk			0xfedd4bd5
+#define clk_snoc_mmnoc_ahb_clk			0xd2149dbb
+#define clk_snoc_usb_a_clk			0x34b7821b
+#define clk_snoc_mm_msmbus_clk			0x5e221ca4
+#define clk_snoc_mm_msmbus_a_clk		0x5950f9ea
+#define clk_bimc_clk				0x4b80bf00
+#define clk_bimc_a_clk				0x4b25668a
+#define clk_bimc_acpu_a_clk			0x4446311b
+#define clk_bimc_msmbus_clk			0xd212feea
+#define clk_bimc_msmbus_a_clk			0x71d1a499
+#define clk_bimc_usb_a_clk			0xea410834
+#define clk_qdss_clk				0x1492202a
+#define clk_qdss_a_clk				0xdd121669
+#define clk_xo_clk_src				0x23f5649f
+#define clk_xo_a_clk_src			0x2fdd2c7c
+#define clk_xo_otg_clk				0x79bca5cc
+#define clk_xo_lpm_clk				0x2be48257
+#define clk_xo_pil_mss_clk			0xe97a8354
+#define clk_xo_pil_pronto_clk			0x89dae6d0
+#define clk_xo_wlan_clk				0x0116b76f
+
+#define clk_qpic_clk				0x3ce6f7bb
+#define clk_qpic_a_clk				0xd70ccb7c
+#define clk_bb_clk1				0xf5304268
+#define clk_bb_clk1_pin				0x6dd0a779
+#define clk_bb_clk2				0xfe15cb87
+#define clk_bb_clk2_pin				0x498938e5
+#define clk_bb_clk3				0x3a9e99a8
+#define clk_bb_clk3_pin				0x3a96c14c
+#define clk_rf_clk1				0xaabeea5a
+#define clk_rf_clk1_pin				0x8f463562
+#define clk_rf_clk2				0x24a30992
+#define clk_rf_clk2_pin				0xa7c5602a
+
+/* DEBUG */
+#define clk_gcc_debug_mux			0x8121ac15
+#define clk_rpm_debug_mux			0x25cd1f3a
+#define clk_wcnss_m_clk				0x709f430b
+#define clk_apss_debug_pri_mux			0xc691ff55
+#define clk_apss_debug_sec_mux			0xc0b680f9
+#define clk_apss_debug_ter_mux			0x32041c48
+#define clk_apc0_m_clk				0xce1e9473
+#define clk_apc1_m_clk				0x990fbaf7
+#define clk_apc2_m_clk				0x252cd4ae
+#define clk_apc3_m_clk				0x78c64486
+#define clk_l2_m_clk                            0x4bedf4d0
+
+#define clk_audio_ap_clk                        0x312ac429
+#define clk_audio_pmi_clk                       0xb7ba2274
+
+#define clk_audio_lpass_mclk			0x575ec22b
+
+/* GCC block resets */
+#define GCC_USB_HS_BCR			0
+#define GCC_USB2_HS_PHY_ONLY_BCR	1
+#define GCC_QUSB2_PHY_BCR		2
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h
new file mode 100644
index 0000000..4547751
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8952.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8952_H
+#define __MSM_CLOCKS_8952_H
+
+/* clock_gcc controlled clocks */
+
+/* GPLLs */
+#define clk_gpll0_clk_src_8952			0x1617c790
+#define clk_gpll0_ao_clk_src_8952		0x9b4db4e8
+#define clk_gpll0_clk_src_8937			0x94350fc4
+#define clk_gpll0_ao_clk_src_8937		0x923c7546
+#define clk_gpll0_clk_src			0x5933b69f
+#define clk_gpll0_ao_clk_src			0x6b2fb034
+#define clk_gpll0_sleep_clk_src			0x4f89fcf0
+#define clk_gpll0_out_main			0x850fecec
+#define clk_gpll0_out_aux			0x64e55d63
+#define clk_gpll0_misc				0xe06ee816
+#define clk_gpll3_clk_src			0x5b1eccd5
+#define clk_gpll3_out_main			0xf5fc71ab
+#define clk_gpll3_out_aux			0xe72bea1a
+#define clk_gpll4_clk_src			0x10525d57
+#define clk_gpll4_out_main                      0xdca8db2a
+#define clk_gpll6_clk_src			0x17dceaad
+#define clk_gpll6_out_main			0x27b8b7be
+#define clk_a53ss_c0_pll			0xf761da94
+#define clk_a53ss_c1_pll			0xfbc57bbd
+#define clk_a53ss_cci_pll			0x17d32f1e
+
+/* SRCs */
+#define clk_apss_ahb_clk_src			0x36f8495f
+#define clk_blsp1_qup1_i2c_apps_clk_src		0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src		0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src		0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src		0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src		0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src		0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src		0xb2ecce68
+#define clk_gcc_blsp2_ahb_clk			0x8f283c1d
+#define clk_gcc_blsp2_sleep_clk			0x429ca5d2
+#define clk_gcc_blsp2_qup1_spi_apps_clk		0xa32604cc
+#define clk_gcc_blsp2_qup1_i2c_apps_clk		0x9ace11dd
+#define clk_blsp2_qup1_spi_apps_clk_src		0xcc1b8365
+#define clk_blsp2_qup1_i2c_apps_clk_src		0xd6d1e95d
+#define clk_gcc_blsp2_uart1_apps_clk		0x8c3512ff
+#define clk_gcc_blsp2_uart1_sim_clk		0x2ea81633
+#define clk_blsp2_uart1_apps_clk_src		0x562c66dc
+#define clk_gcc_blsp2_qup2_spi_apps_clk		0xbf54ca6d
+#define clk_gcc_blsp2_qup2_i2c_apps_clk		0x1bf9a57e
+#define clk_blsp2_qup2_spi_apps_clk_src		0xd577dc44
+#define clk_blsp2_qup2_i2c_apps_clk_src		0x603b5c51
+#define clk_gcc_blsp2_uart2_apps_clk		0x1e1965a3
+#define clk_gcc_blsp2_uart2_sim_clk		0xca05dfe2
+#define clk_blsp2_uart2_apps_clk_src		0xdd448080
+#define clk_gcc_blsp2_qup3_spi_apps_clk		0xc68509d6
+#define clk_gcc_blsp2_qup3_i2c_apps_clk		0x336d4170
+#define clk_blsp2_qup3_spi_apps_clk_src		0xd04b1e92
+#define clk_blsp2_qup3_i2c_apps_clk_src		0xea82959c
+#define clk_gcc_blsp2_qup4_spi_apps_clk		0x01a72b93
+#define clk_gcc_blsp2_qup4_i2c_apps_clk		0xbd22539d
+#define clk_blsp2_qup4_spi_apps_clk_src		0x25d4a2b1
+#define clk_blsp2_qup4_i2c_apps_clk_src		0x73dc968c
+#define clk_blsp1_qup4_spi_apps_clk_src		0xddb5bbdb
+#define clk_blsp1_uart1_apps_clk_src		0xf8146114
+#define clk_blsp1_uart2_apps_clk_src		0xfc9c2f73
+#define clk_byte0_clk_src			0x75cc885b
+#define clk_cci_clk_src				0x822f3d97
+#define clk_camss_top_ahb_clk_src		0xf92304fb
+#define clk_camss_gp0_clk_src			0x43b063e9
+#define clk_camss_gp1_clk_src			0xa3315f1b
+#define clk_crypto_clk_src			0x37a21414
+#define clk_csi0_clk_src			0x227e65bc
+#define clk_csi1_clk_src			0x6a2a6c36
+#define clk_csi2_clk_src                        0x4113589f
+#define clk_csi0phytimer_clk_src		0xc8a309be
+#define clk_csi1phytimer_clk_src		0x7c0fe23a
+#define clk_esc0_clk_src			0xb41d7c38
+#define clk_gfx3d_clk_src			0x917f76ef
+#define clk_gp1_clk_src				0xad85b97a
+#define clk_gp2_clk_src				0xfb1f0065
+#define clk_gp3_clk_src				0x63b693d6
+#define clk_jpeg0_clk_src			0x9a0a0ac3
+#define clk_mdp_clk_src				0x6dc1f8f1
+#define clk_mclk0_clk_src			0x266b3853
+#define clk_mclk1_clk_src			0xa73cad0c
+#define clk_mclk2_clk_src                       0x42545468
+#define clk_pclk0_clk_src			0xccac1f35
+#define clk_pdm2_clk_src			0x31e494fd
+#define clk_sdcc1_apps_clk_src			0xd4975db2
+#define clk_sdcc1_ice_core_clk_src		0xfd6a4301
+#define clk_sdcc2_apps_clk_src			0xfc46c821
+#define clk_usb_hs_system_clk_src		0x28385546
+#define clk_usb_fs_system_clk_src               0x06ee1762
+#define clk_usb_fs_ic_clk_src			0x25d4acc8
+#define clk_usb_fs_ic_clk_src			0x25d4acc8
+#define clk_gcc_qusb2_phy_clk			0x996884d5
+#define clk_gcc_usb2_hs_phy_only_clk		0x0047179d
+#define clk_vsync_clk_src			0xecb43940
+#define clk_vfe0_clk_src			0xa0c2bd8f
+#define clk_vcodec0_clk_src			0xbc193019
+#define clk_gcc_blsp1_ahb_clk			0x8caa5b4f
+#define clk_gcc_boot_rom_ahb_clk		0xde2adeb1
+#define clk_gcc_crypto_ahb_clk			0x94de4919
+#define clk_gcc_crypto_axi_clk			0xd4415c9b
+#define clk_gcc_crypto_clk			0x00d390d2
+#define clk_gcc_prng_ahb_clk			0x397e7eaa
+#define clk_gcc_qdss_dap_clk			0x7fa9aa73
+#define clk_gcc_apss_tcu_clk			0xaf56a329
+#define clk_gcc_ipa_tbu_clk			0x75bbfb5c
+#define clk_gcc_gfx_tbu_clk			0x18bb9a90
+#define clk_gcc_gtcu_ahb_clk			0xb432168e
+#define clk_gcc_jpeg_tbu_clk			0xcf8fd944
+#define clk_gcc_mdp_tbu_clk			0x82287f76
+#define clk_gcc_smmu_cfg_clk			0x75eaefa5
+#define clk_gcc_venus_tbu_clk			0x7e0b97ce
+#define clk_gcc_vfe_tbu_clk			0x061f2f95
+#define clk_gcc_vfe1_tbu_clk			0x4888e70f
+#define clk_gcc_cpp_tbu_clk			0xab6f19ab
+#define clk_gcc_blsp1_qup1_i2c_apps_clk		0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk		0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk		0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk		0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk		0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk		0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk		0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk		0x80f8722f
+#define clk_gcc_blsp1_uart1_apps_clk		0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk		0xf8a61c96
+#define clk_gcc_camss_cci_ahb_clk		0xa81c11ba
+#define clk_gcc_camss_cci_clk			0xb7dd8824
+#define clk_gcc_camss_csi0_ahb_clk		0x175d672a
+#define clk_gcc_camss_csi0_clk			0x6b01b3e1
+#define clk_gcc_camss_csi0phy_clk		0x06a41ff7
+#define clk_gcc_camss_csi0pix_clk		0x61a8a930
+#define clk_gcc_camss_csi0rdi_clk		0x7053c7ae
+#define clk_gcc_camss_csi1_ahb_clk		0x2c2dc261
+#define clk_gcc_camss_csi1_clk			0x1aba4a8c
+#define clk_gcc_camss_csi1phy_clk		0x0fd1d1fa
+#define clk_gcc_camss_csi1pix_clk		0x87fc98d8
+#define clk_gcc_camss_csi1rdi_clk		0x6ac996fe
+#define clk_gcc_camss_csi2_ahb_clk		0xf3f25940
+#define clk_gcc_camss_csi2_clk			0xb6857fa2
+#define clk_gcc_camss_csi2phy_clk		0xbeeffbcd
+#define clk_gcc_camss_csi2pix_clk		0xa619561a
+#define clk_gcc_camss_csi2rdi_clk		0x019fd3f1
+#define clk_vfe1_clk_src			0x4e357366
+#define clk_gcc_camss_vfe1_clk			0xcaf20d99
+#define clk_gcc_camss_vfe1_ahb_clk		0x634a738a
+#define clk_gcc_camss_vfe1_axi_clk		0xaf7463b3
+#define clk_gcc_vfe1_qdss_at_clk		0xfff1e0be
+#define clk_cpp_clk_src				0x8382f56d
+#define clk_gcc_camss_cpp_clk			0x7118a0de
+#define clk_gcc_camss_cpp_ahb_clk		0x4ac95e14
+#define clk_gcc_camss_cpp_axi_clk		0xbbf73861
+#define clk_gcc_cpp_qdss_at_clk			0x05805d0d
+#define clk_gcc_cpp_qdss_tsctr_div8_clk		0xebd2c356
+#define clk_gcc_camss_csi_vfe0_clk		0xcc73453c
+#define clk_gcc_camss_csi_vfe1_clk		0xb1ef6e8b
+#define clk_gcc_camss_gp0_clk			0xd2bc3892
+#define clk_gcc_camss_gp1_clk			0xe4c013e1
+#define clk_gcc_camss_ispif_ahb_clk		0x3c0a858f
+#define clk_gcc_camss_jpeg0_clk			0x1ed3f032
+#define clk_gcc_camss_jpeg_ahb_clk		0x3bfa7603
+#define clk_gcc_camss_jpeg_axi_clk		0x3e278896
+#define clk_gcc_camss_mclk0_clk			0x80902deb
+#define clk_gcc_camss_mclk1_clk			0x5002d85f
+#define clk_gcc_camss_mclk2_clk                 0x222f8fff
+#define clk_gcc_camss_micro_ahb_clk		0xfbbee8cf
+#define clk_gcc_camss_csi0phytimer_clk		0xf8897589
+#define clk_gcc_camss_csi1phytimer_clk		0x4d26438f
+#define clk_gcc_camss_ahb_clk			0x9894b414
+#define clk_gcc_camss_top_ahb_clk		0x4e814a78
+#define clk_gcc_camss_vfe0_clk			0xaaa3cd97
+#define clk_gcc_camss_vfe_ahb_clk		0x4050f47a
+#define clk_gcc_camss_vfe_axi_clk		0x77fe2384
+#define clk_gcc_sys_mm_noc_axi_clk		0xb75a7187
+#define clk_gcc_oxili_gmem_clk			0x5620913a
+#define clk_gcc_gp1_clk				0x057f7b69
+#define clk_gcc_gp2_clk				0x9bf83ffd
+#define clk_gcc_gp3_clk				0xec6539ee
+#define clk_gcc_mdss_ahb_clk			0xbfb92ed3
+#define clk_gcc_mdss_axi_clk			0x668f51de
+#define clk_gcc_mdss_byte0_clk			0x35da7862
+#define clk_gcc_mdss_esc0_clk			0xaec5cb25
+#define clk_gcc_mdss_mdp_clk			0x22f3521f
+#define clk_gcc_mdss_pclk0_clk			0xcc5c5c77
+#define clk_gcc_mdss_vsync_clk			0x32a09f1f
+#define clk_gcc_mss_cfg_ahb_clk			0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk		0x67544d62
+#define clk_gcc_oxili_ahb_clk			0xd15c8a00
+#define clk_gcc_oxili_gfx3d_clk			0x49a51fd9
+#define clk_gcc_oxili_timer_clk			0x1180db06
+#define clk_gcc_oxili_aon_clk			0xae18e54d
+#define clk_gcc_pdm2_clk			0x99d55711
+#define clk_gcc_pdm_ahb_clk			0x365664f6
+#define clk_gcc_sdcc1_ahb_clk			0x691e0caa
+#define clk_gcc_sdcc1_apps_clk			0x9ad6fb96
+#define clk_gcc_sdcc1_ice_core_clk		0x0fd5680a
+#define clk_gcc_sdcc2_ahb_clk			0x23d5727f
+#define clk_gcc_sdcc2_apps_clk			0x861b20ac
+#define clk_gcc_usb2a_phy_sleep_clk		0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk		0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk			0x72ce8032
+#define clk_gcc_usb_fs_ahb_clk                  0x00e31116
+#define clk_gcc_usb_fs_ic_clk			0xbd533d37
+#define clk_gcc_usb_hs_system_clk		0xa11972e5
+#define clk_gcc_usb_fs_system_clk               0xea3b114c
+#define clk_gcc_venus0_ahb_clk			0x08d778c6
+#define clk_gcc_venus0_axi_clk			0xcdf4c8f6
+#define clk_gcc_venus0_vcodec0_clk		0xf76a02bb
+#define clk_gcc_venus0_core0_vcodec0_clk        0x83a7f549
+#define clk_gcc_venus0_core1_vcodec0_clk        0xa0813de6
+#define clk_gcc_gfx_tcu_clk			0x59505e55
+#define clk_gcc_gtcu_ahb_bridge_clk		0x19d2c5fe
+#define clk_gcc_bimc_gpu_clk			0x19922503
+#define clk_gcc_bimc_gfx_clk			0x3edd69ad
+#define clk_ipa_clk				0xfa685cda
+#define clk_ipa_a_clk				0xeeec2919
+#define clk_mdss_mdp_vote_clk			0x588460a4
+#define clk_mdss_rotator_vote_clk		0x5b1f675e
+
+#define clk_pixel_clk_src                       0x8b6f83d8
+#define clk_byte_clk_src                        0x3a911c53
+#define clk_ext_pclk0_clk_src			0x087c1612
+#define clk_ext_byte0_clk_src			0xfb32f31e
+
+#define clk_dsi_pll0_byte_clk_src		0x44539836
+#define clk_dsi_pll0_pixel_clk_src		0x5767c287
+#define clk_dsi_pll1_byte_clk_src		0x73e88d02
+#define clk_dsi_pll1_pixel_clk_src		0xce233fcf
+#define clk_ext_pclk1_clk_src			0x8067c5a3
+#define clk_ext_byte1_clk_src			0x585ef6d4
+#define clk_byte1_clk_src			0x63c2c955
+#define clk_esc1_clk_src			0x3b0afa42
+#define clk_pclk1_clk_src			0x090f68ac
+#define clk_gcc_mdss_pclk1_clk			0x9a9c430d
+#define clk_gcc_mdss_byte1_clk			0x41f97fd8
+#define clk_gcc_mdss_esc1_clk			0x34653cc7
+#define clk_gcc_dcc_clk				0xd1000c50
+#define clk_gcc_debug_mux_8937			0x917968c2
+
+/* clock_rpm controlled clocks */
+#define clk_pnoc_clk				0xc1296d0f
+#define clk_pnoc_a_clk				0x9bcffee4
+#define clk_pnoc_msmbus_clk			0x2b53b688
+#define clk_pnoc_msmbus_a_clk			0x9753a54f
+#define clk_pnoc_keepalive_a_clk		0x9464f720
+#define clk_pnoc_sps_clk			0x23d3f584
+#define clk_pnoc_usb_a_clk			0x11d6a74e
+#define clk_pnoc_usb_clk                        0x266d8376
+#define clk_snoc_clk				0x2c341aa0
+#define clk_snoc_a_clk				0x8fcef2af
+#define clk_snoc_usb_a_clk			0x34b7821b
+#define clk_snoc_wcnss_a_clk			0xd3949ebc
+#define clk_snoc_usb_clk			0x29f9d73d
+#define clk_snoc_msmbus_clk			0xe6900bb6
+#define clk_snoc_msmbus_a_clk			0x5d4683bd
+#define clk_snoc_mmnoc_axi_clk			0xfedd4bd5
+#define clk_snoc_mmnoc_ahb_clk			0xd2149dbb
+#define clk_sysmmnoc_clk			0xebb1df78
+#define clk_sysmmnoc_a_clk			0x6ca682a2
+#define clk_sysmmnoc_msmbus_clk			0xd61e5721
+#define clk_sysmmnoc_msmbus_a_clk		0x50600f1b
+#define clk_bimc_clk				0x4b80bf00
+#define clk_bimc_a_clk				0x4b25668a
+#define clk_bimc_acpu_a_clk			0x4446311b
+#define clk_bimc_msmbus_clk			0xd212feea
+#define clk_bimc_msmbus_a_clk			0x71d1a499
+#define clk_bimc_usb_a_clk			0xea410834
+#define clk_bimc_wcnss_a_clk			0x5a6df715
+#define clk_bimc_usb_clk			0x9bd2b2bf
+#define clk_bimc_gpu_clk			0xd3e0a327
+#define clk_bimc_gpu_a_clk			0x67f0e9a5
+#define clk_qdss_clk				0x1492202a
+#define clk_qdss_a_clk				0xdd121669
+#define clk_xo_clk_src				0x23f5649f
+#define clk_xo_a_clk_src			0x2fdd2c7c
+#define clk_xo_otg_clk				0x79bca5cc
+#define clk_xo_a2				0xeba5a83d
+#define clk_xo_dwc3_clk				0xfad488ce
+#define clk_xo_ehci_host_clk			0xc7c340b1
+#define clk_xo_lpm_clk				0x2be48257
+#define clk_xo_pil_mss_clk			0xe97a8354
+#define clk_xo_pil_pronto_clk			0x89dae6d0
+#define clk_xo_wlan_clk				0x0116b76f
+#define clk_xo_pil_lpass_clk			0xb72aa4c9
+#define clk_bb_clk1				0xf5304268
+#define clk_bb_clk1_a				0xfa113810
+#define clk_bb_clk1_pin				0x6dd0a779
+#define clk_bb_clk1_a_pin			0x9b637772
+#define clk_bb_clk2				0xfe15cb87
+#define clk_bb_clk2_a				0x59682706
+#define clk_bb_clk2_pin				0x498938e5
+#define clk_bb_clk2_a_pin			0x52513787
+#define clk_rf_clk1				0xaabeea5a
+#define clk_rf_clk1_a				0x72a10cb8
+#define clk_rf_clk1_pin				0x8f463562
+#define clk_rf_clk1_a_pin			0x62549ff6
+#define clk_rf_clk2				0x24a30992
+#define clk_rf_clk2_a				0x944d8bbd
+#define clk_rf_clk2_pin				0xa7c5602a
+#define clk_rf_clk2_a_pin			0x2d75eb4d
+#define clk_div_clk1				0xaa1157a6
+#define clk_div_clk1_a				0x6b943d68
+#define clk_div_clk2				0xd454019f
+#define clk_div_clk2_a				0x4bd7bfa8
+#define clk_ln_bb_clk				0x3ab0b36d
+#define clk_ln_bb_a_clk				0xc7257ea8
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux			0x8121ac15
+#define clk_rpm_debug_mux			0x25cd1f3a
+#define clk_wcnss_m_clk				0x709f430b
+#define clk_apss_debug_pri_mux			0xc691ff55
+#define clk_apss_debug_sec_mux			0xc0b680f9
+#define clk_apss_debug_ter_mux			0x32041c48
+#define clk_apc0_m_clk				0xce1e9473
+#define clk_apc1_m_clk				0x990fbaf7
+#define clk_cci_m_clk				0xec7e8afc
+
+#define clk_a53ssmux_lc				0x71a9377b
+#define clk_a53ssmux_bc				0xb5983c42
+#define clk_a53ssmux_cci			0x15560bd5
+
+#define clk_a53_lc_clk				0xc69f0878
+#define clk_a53_bc_clk				0xcf28e63a
+#define clk_cci_clk                             0x96854074
+
+#define clk_audio_ap_clk			0x312ac429
+#define clk_audio_pmi_clk			0xb7ba2274
+#define clk_audio_ap_clk2			0xf0fbaf5b
+#define clk_audio_lpass_mclk			0x575ec22b
+
+/* GCC block resets */
+#define GCC_CAMSS_MICRO_BCR			0
+#define GCC_USB_FS_BCR				1
+#define GCC_USB_HS_BCR				2
+#define GCC_USB2_HS_PHY_ONLY_BCR		3
+#define GCC_QUSB2_PHY_BCR			4
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8953.h b/include/dt-bindings/clock/msm-clocks-8953.h
index 6bfca0b..9550a41 100644
--- a/include/dt-bindings/clock/msm-clocks-8953.h
+++ b/include/dt-bindings/clock/msm-clocks-8953.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -313,6 +313,12 @@
 #define clk_cpu_debug_pri_mux				 0x61a2945f
 #define clk_debug_cpu_clk                                0x0e696b2b
 
+#define clk_apcs_c0_pll					 0xfbc57bbd
+#define clk_apcs_c1_pll					 0x17d32f1e
+#define clk_apcs_cci_pll				 0x09affb3c
+#define clk_a53ssmux_cci				 0x15560bd5
+#define clk_a53_cci_clk					 0x4cdbbe58
+
 #define clk_audio_ap_clk				 0x312ac429
 #define clk_audio_pmi_clk				 0xb7ba2274
 #define clk_audio_ap_clk2				 0xf0fbaf5b
diff --git a/include/dt-bindings/clock/msm-clocks-8996.h b/include/dt-bindings/clock/msm-clocks-8996.h
new file mode 100644
index 0000000..1f515f2
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8996.h
@@ -0,0 +1,548 @@
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8996_H
+#define __MSM_CLOCKS_8996_H
+
+/* clock_gcc controlled clocks */
+#define clk_cxo_clk_src			0x79e95308
+#define clk_pnoc_clk			0x4325d220
+#define clk_pnoc_a_clk			0x2808c12b
+#define clk_bimc_clk			0x4b80bf00
+#define clk_bimc_a_clk			0x4b25668a
+#define clk_cnoc_clk			0xd5ccb7f4
+#define clk_cnoc_a_clk			0xd8fe2ccc
+#define clk_snoc_clk			0x2c341aa0
+#define clk_snoc_a_clk			0x8fcef2af
+#define clk_bb_clk1			0xf5304268
+#define clk_bb_clk1_ao			0xfa113810
+#define clk_bb_clk1_pin			0x6dd0a779
+#define clk_bb_clk1_pin_ao		0x9b637772
+#define clk_bb_clk2			0xfe15cb87
+#define clk_bb_clk2_ao			0x59682706
+#define clk_bb_clk2_pin			0x498938e5
+#define clk_bb_clk2_pin_ao		0x52513787
+#define clk_bimc_msmbus_clk		0xd212feea
+#define clk_bimc_msmbus_a_clk		0x71d1a499
+#define clk_ce1_a_clk			0x44a833fe
+#define clk_cnoc_msmbus_clk		0x62228b5d
+#define clk_cnoc_msmbus_a_clk		0x67442955
+#define clk_cxo_clk_src_ao		0x64eb6004
+#define clk_cxo_dwc3_clk		0xf79c19f6
+#define clk_cxo_lpm_clk			0x94adbf3d
+#define clk_cxo_otg_clk			0x4eec0bb9
+#define clk_cxo_pil_lpass_clk		0xe17f0ff6
+#define clk_cxo_pil_ssc_clk		0x81832015
+#define clk_div_clk1			0xaa1157a6
+#define clk_div_clk1_ao			0x6b943d68
+#define clk_div_clk2			0xd454019f
+#define clk_div_clk2_ao			0x53f9e788
+#define clk_div_clk3			0xa9a55a68
+#define clk_div_clk3_ao			0x3d6725a8
+#define clk_ipa_a_clk			0xeeec2919
+#define clk_ipa_clk			0xfa685cda
+#define clk_ln_bb_clk			0x3ab0b36d
+#define clk_ln_bb_a_clk			0xc7257ea8
+#define clk_ln_bb_clk_pin		0x1b1c476a
+#define clk_ln_bb_a_clk_pin		0x9cbb5411
+#define clk_mcd_ce1_clk			0xbb615d26
+#define clk_pnoc_keepalive_a_clk	0xf8f91f0b
+#define clk_pnoc_msmbus_clk		0x38b95c77
+#define clk_pnoc_msmbus_a_clk		0x8c9b4e93
+#define clk_pnoc_pm_clk			0xd6f7dfb9
+#define clk_pnoc_sps_clk		0xd482ecc7
+#define clk_qdss_a_clk			0xdd121669
+#define clk_qdss_clk			0x1492202a
+#define clk_rf_clk1			0xaabeea5a
+#define clk_rf_clk1_ao			0x72a10cb8
+#define clk_rf_clk1_pin			0x8f463562
+#define clk_rf_clk1_pin_ao		0x62549ff6
+#define clk_rf_clk2			0x24a30992
+#define clk_rf_clk2_ao			0x944d8bbd
+#define clk_rf_clk2_pin			0xa7c5602a
+#define clk_rf_clk2_pin_ao		0x2d75eb4d
+#define clk_snoc_msmbus_clk		0xe6900bb6
+#define clk_snoc_msmbus_a_clk		0x5d4683bd
+#define clk_mcd_ce1_clk			0xbb615d26
+#define clk_qcedev_ce1_clk		0x293f97b0
+#define clk_qcrypto_ce1_clk		0xa6ac14df
+#define clk_qseecom_ce1_clk		0xaa858373
+#define clk_scm_ce1_clk			0xd8ebcc62
+#define clk_ce1_clk			0x42229c55
+#define clk_gcc_ce1_ahb_m_clk		0x2eb28c01
+#define clk_gcc_ce1_axi_m_clk		0xc174dfba
+#define clk_measure_only_bimc_hmss_axi_clk	0xc1cc4f11
+#define clk_aggre1_noc_clk		0x049abba8
+#define clk_aggre1_noc_a_clk		0xc12e4220
+#define clk_aggre2_noc_clk		0xaa681404
+#define clk_aggre2_noc_a_clk		0xcab67089
+#define clk_mmssnoc_axi_rpm_clk		0x4d7f8cdc
+#define clk_mmssnoc_axi_rpm_a_clk	0xfbea899b
+#define clk_mmssnoc_axi_clk		0xdb4b31e6
+#define clk_mmssnoc_axi_a_clk		0xd4970614
+#define clk_mmssnoc_gds_clk		0x06a22afa
+
+#define clk_gpll0			0x1ebe3bc4
+#define clk_gpll0_ao			0xa1368304
+#define clk_gpll0_out_main		0xe9374de7
+#define clk_gpll4			0xb3b5d85b
+#define clk_gpll4_out_main		0xa9a0ab9d
+#define clk_ufs_axi_clk_src		0x297ca380
+#define clk_pcie_aux_clk_src		0xebc50566
+#define clk_usb30_master_clk_src	0xc6262f89
+#define clk_usb20_master_clk_src	0x5680ac83
+#define clk_ufs_ice_core_clk_src	0xda8e7119
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src 0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src 0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src 0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src 0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src	0xf8146114
+#define clk_blsp1_uart2_apps_clk_src	0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src	0x600497f2
+#define clk_blsp1_uart4_apps_clk_src	0x56bff15c
+#define clk_blsp1_uart5_apps_clk_src	0x218ef697
+#define clk_blsp1_uart6_apps_clk_src	0x8fbdbe4c
+#define clk_blsp2_qup1_i2c_apps_clk_src 0xd6d1e95d
+#define clk_blsp2_qup1_spi_apps_clk_src 0xcc1b8365
+#define clk_blsp2_qup2_i2c_apps_clk_src 0x603b5c51
+#define clk_blsp2_qup2_spi_apps_clk_src 0xd577dc44
+#define clk_blsp2_qup3_i2c_apps_clk_src 0xea82959c
+#define clk_blsp2_qup3_spi_apps_clk_src 0xd04b1e92
+#define clk_blsp2_qup4_i2c_apps_clk_src 0x73dc968c
+#define clk_blsp2_qup4_spi_apps_clk_src 0x25d4a2b1
+#define clk_blsp2_qup5_i2c_apps_clk_src 0xcc3698bd
+#define clk_blsp2_qup5_spi_apps_clk_src 0xfa0cf45e
+#define clk_blsp2_qup6_i2c_apps_clk_src 0x2fa53151
+#define clk_blsp2_qup6_spi_apps_clk_src 0x5ca86755
+#define clk_blsp2_uart1_apps_clk_src	0x562c66dc
+#define clk_blsp2_uart2_apps_clk_src	0xdd448080
+#define clk_blsp2_uart3_apps_clk_src	0x46b2e90f
+#define clk_blsp2_uart4_apps_clk_src	0x23a093d2
+#define clk_blsp2_uart5_apps_clk_src	0xe067616a
+#define clk_blsp2_uart6_apps_clk_src	0xe02d2829
+#define clk_gp1_clk_src			0xad85b97a
+#define clk_gp2_clk_src			0xfb1f0065
+#define clk_gp3_clk_src			0x63b693d6
+#define clk_hmss_rbcpr_clk_src		0xedd9a474
+#define clk_pdm2_clk_src		0x31e494fd
+#define clk_sdcc1_apps_clk_src		0xd4975db2
+#define clk_sdcc2_apps_clk_src		0xfc46c821
+#define clk_sdcc3_apps_clk_src		0xea34c7f4
+#define clk_sdcc4_apps_clk_src		0x7aaaaa0c
+#define clk_tsif_ref_clk_src		0x4e9042d1
+#define clk_usb20_mock_utmi_clk_src	0xc3aaeecb
+#define clk_usb30_mock_utmi_clk_src	0xa024a976
+#define clk_usb3_phy_aux_clk_src	0x15eec63c
+#define clk_gcc_qusb2phy_prim_reset	0x07550fa1
+#define clk_gcc_qusb2phy_sec_reset	0x3f3a87d0
+#define clk_gcc_periph_noc_usb20_ahb_clk	0xfb9f26e9
+#define clk_gcc_mmss_gcc_dbg_clk	0xe89d461c
+#define clk_cpu_dbg_clk			0x6550dfa9
+#define clk_gcc_blsp1_ahb_clk		0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk 0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk 0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk 0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk 0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk	0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk	0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk	0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk	0x26be16c0
+#define clk_gcc_blsp1_uart5_apps_clk	0x28a6bc74
+#define clk_gcc_blsp1_uart6_apps_clk	0x28fd3466
+#define clk_gcc_blsp2_ahb_clk		0x8f283c1d
+#define clk_gcc_blsp2_qup1_i2c_apps_clk 0x9ace11dd
+#define clk_gcc_blsp2_qup1_spi_apps_clk 0xa32604cc
+#define clk_gcc_blsp2_qup2_i2c_apps_clk 0x1bf9a57e
+#define clk_gcc_blsp2_qup2_spi_apps_clk 0xbf54ca6d
+#define clk_gcc_blsp2_qup3_i2c_apps_clk 0x336d4170
+#define clk_gcc_blsp2_qup3_spi_apps_clk 0xc68509d6
+#define clk_gcc_blsp2_qup4_i2c_apps_clk 0xbd22539d
+#define clk_gcc_blsp2_qup4_spi_apps_clk 0x01a72b93
+#define clk_gcc_blsp2_qup5_i2c_apps_clk 0xe2b2ce1d
+#define clk_gcc_blsp2_qup5_spi_apps_clk 0xf40999cd
+#define clk_gcc_blsp2_qup6_i2c_apps_clk 0x894bcea4
+#define clk_gcc_blsp2_qup6_spi_apps_clk 0xfe1bd34a
+#define clk_gcc_blsp2_uart1_apps_clk	0x8c3512ff
+#define clk_gcc_blsp2_uart2_apps_clk	0x1e1965a3
+#define clk_gcc_blsp2_uart3_apps_clk	0x382415ab
+#define clk_gcc_blsp2_uart4_apps_clk	0x87a44b42
+#define clk_gcc_blsp2_uart5_apps_clk	0x5cd30649
+#define clk_gcc_blsp2_uart6_apps_clk	0x8feee5ab
+#define clk_gcc_boot_rom_ahb_clk	0xde2adeb1
+#define clk_gcc_gp1_clk			0x057f7b69
+#define clk_gcc_gp2_clk			0x9bf83ffd
+#define clk_gcc_gp3_clk			0xec6539ee
+#define clk_gcc_hmss_rbcpr_clk		0x699183be
+#define clk_gcc_mmss_noc_cfg_ahb_clk	0xb41a9d99
+#define clk_gcc_pcie_0_aux_clk		0x3d2e3ece
+#define clk_gcc_pcie_0_cfg_ahb_clk	0x4dd325c3
+#define clk_gcc_pcie_0_mstr_axi_clk	0x3f85285b
+#define clk_gcc_pcie_0_slv_axi_clk	0xd69638a1
+#define clk_gcc_pcie_0_pipe_clk		0x4f37621e
+#define clk_gcc_pcie_0_phy_reset	0xdc3201c1
+#define clk_gcc_pcie_1_aux_clk		0xc9bb962c
+#define clk_gcc_pcie_1_cfg_ahb_clk	0xb6338658
+#define clk_gcc_pcie_1_mstr_axi_clk	0xc20f6269
+#define clk_gcc_pcie_1_slv_axi_clk	0xd54e40d6
+#define clk_gcc_pcie_1_pipe_clk		0xc1627422
+#define clk_gcc_pcie_1_phy_reset	0x674481bb
+#define clk_gcc_pcie_2_aux_clk		0xa4dc7ae8
+#define clk_gcc_pcie_2_cfg_ahb_clk	0x4f1d3121
+#define clk_gcc_pcie_2_mstr_axi_clk	0x9e81724a
+#define clk_gcc_pcie_2_slv_axi_clk	0x7990d8b2
+#define clk_gcc_pcie_2_pipe_clk		0xa757a834
+#define clk_gcc_pcie_2_phy_reset	0x82634880
+#define clk_gcc_pcie_phy_reset		0x9bc3c959
+#define clk_gcc_pcie_phy_com_reset	0x8bf513e6
+#define clk_gcc_pcie_phy_nocsr_com_phy_reset	0x0c16a2da
+#define clk_gcc_pcie_phy_aux_clk	0x4746e74f
+#define clk_gcc_pcie_phy_cfg_ahb_clk	0x8533671a
+#define clk_gcc_pdm2_clk		0x99d55711
+#define clk_gcc_pdm_ahb_clk		0x365664f6
+#define clk_gcc_prng_ahb_clk		0x397e7eaa
+#define clk_gcc_sdcc1_ahb_clk		0x691e0caa
+#define clk_gcc_sdcc1_apps_clk		0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk		0x23d5727f
+#define clk_gcc_sdcc2_apps_clk		0x861b20ac
+#define clk_gcc_sdcc3_ahb_clk		0x565b2c03
+#define clk_gcc_sdcc3_apps_clk		0x0b27aeac
+#define clk_gcc_sdcc4_ahb_clk		0x64f3e6a8
+#define clk_gcc_sdcc4_apps_clk		0xbf7c4dc8
+#define clk_gcc_tsif_ahb_clk		0x88d2822c
+#define clk_gcc_tsif_ref_clk		0x8f1ed2c2
+#define clk_gcc_ufs_ahb_clk		0x1914bb84
+#define clk_gcc_ufs_axi_clk		0x47c743a7
+#define clk_gcc_ufs_ice_core_clk	0x310b0710
+#define clk_gcc_ufs_rx_cfg_clk		0xa6747786
+#define clk_gcc_ufs_rx_symbol_0_clk	0x7f43251c
+#define clk_gcc_ufs_rx_symbol_1_clk	0x03182fde
+#define clk_gcc_ufs_tx_cfg_clk		0xba2cf8b5
+#define clk_gcc_ufs_tx_symbol_0_clk	0x6a9f747a
+#define clk_gcc_ufs_unipro_core_clk	0x2daf7fd2
+#define clk_gcc_ufs_sys_clk_core_clk	0x360e5ac8
+#define clk_gcc_ufs_tx_symbol_clk_core_clk	0xf6fb0df7
+#define clk_gcc_usb20_master_clk	0x24c3b66a
+#define clk_gcc_usb20_mock_utmi_clk	0xe8db8203
+#define clk_gcc_usb20_sleep_clk		0x6e8cb4b2
+#define clk_gcc_usb30_master_clk	0xb3b4e2cb
+#define clk_gcc_usb30_mock_utmi_clk	0xa800b65a
+#define clk_gcc_usb30_sleep_clk		0xd0b65c92
+#define clk_gcc_usb3_phy_aux_clk	0x0d9a36e0
+#define clk_gcc_usb3_phy_pipe_clk	0xf279aff2
+#define clk_gcc_usb_phy_cfg_ahb2phy_clk	0xd1231a0e
+#define clk_gcc_aggre0_cnoc_ahb_clk	0x53a35559
+#define clk_gcc_aggre0_snoc_axi_clk	0x3c446400
+#define clk_gcc_aggre0_noc_qosgen_extref_clk	0x8c4356ba
+#define clk_hlos1_vote_lpass_core_smmu_clk	0x3aaa1743
+#define clk_hlos1_vote_lpass_adsp_smmu_clk	0xc76f702f
+#define clk_gcc_usb3_phy_reset		0x03d559f1
+#define clk_gcc_usb3phy_phy_reset	0xb1a4f885
+#define clk_gcc_usb3_clkref_clk		0xb6cc8f01
+#define clk_gcc_hdmi_clkref_clk		0x4d4eec04
+#define clk_gcc_edp_clkref_clk		0xa8685c3f
+#define clk_gcc_ufs_clkref_clk		0x92aa126f
+#define clk_gcc_pcie_clkref_clk		0xa2e247fa
+#define clk_gcc_rx2_usb2_clkref_clk	0x27ec24ba
+#define clk_gcc_rx1_usb2_clkref_clk	0x53351d25
+#define clk_gcc_smmu_aggre0_ahb_clk	0x47a06ce4
+#define clk_gcc_smmu_aggre0_axi_clk	0x3cac4a6c
+#define clk_gcc_sys_noc_usb3_axi_clk	0x94d26800
+#define clk_gcc_sys_noc_ufs_axi_clk	0x19d38312
+#define clk_gcc_aggre2_usb3_axi_clk	0xd5822a8e
+#define clk_gcc_aggre2_ufs_axi_clk	0xb31e5191
+#define clk_gcc_mmss_gpll0_div_clk	0xdd06848d
+#define clk_gcc_mmss_bimc_gfx_clk	0xe4f28754
+#define clk_gcc_bimc_gfx_clk		0x3edd69ad
+#define clk_gcc_qspi_ahb_clk		0x96969dc8
+#define clk_gcc_qspi_ser_clk		0xfaf1e266
+#define clk_qspi_ser_clk_src		0x426676ee
+#define clk_sdcc1_ice_core_clk_src	0xfd6a4301
+#define clk_gcc_sdcc1_ice_core_clk	0x0fd5680a
+#define clk_gcc_mss_cfg_ahb_clk		0x111cde81
+#define clk_gcc_mss_snoc_axi_clk	0x0e71de85
+#define clk_gcc_mss_q6_bimc_axi_clk	0x67544d62
+#define clk_gcc_mss_mnoc_bimc_axi_clk	0xf665d03f
+#define clk_gpll0_out_msscc		0x7d794829
+#define clk_gcc_debug_mux_v2		0xf7e749f0
+#define clk_gcc_dcc_ahb_clk		0xfa14a88c
+#define clk_gcc_aggre0_noc_mpu_cfg_ahb_clk	0x5c1bb8e2
+
+/* clock_mmss controlled clocks */
+#define clk_mmsscc_xo			0x05e63704
+#define clk_mmsscc_gpll0		0xe900c515
+#define clk_mmsscc_gpll0_div		0x73892e05
+#define clk_mmsscc_mmssnoc_ahb		0x7b4bd6f7
+#define clk_mmpll0			0xdd83b751
+#define clk_mmpll0_out_main		0x2f996a31
+#define clk_mmpll1			0x6da7fb90
+#define clk_mmpll1_out_main		0xa0d3a7da
+#define clk_mmpll4			0x22c063c1
+#define clk_mmpll4_out_main		0xfb21c2fd
+#define clk_mmpll3			0x18c76899
+#define clk_mmpll3_out_main		0x6eb6328f
+#define clk_ahb_clk_src			0x86f49203
+#define clk_mmpll2			0x1190e4d8
+#define clk_mmpll2_out_main		0x1e9e24a8
+#define clk_mmpll8			0xd06ad45e
+#define clk_mmpll8_out_main		0x75b1f386
+#define clk_mmpll9			0x1c50684c
+#define clk_mmpll9_out_main		0x16b74937
+#define clk_mmpll5			0xa41e1936
+#define clk_mmpll5_out_main		0xcc1897bf
+#define clk_csi0_clk_src		0x227e65bc
+#define clk_vfe0_clk_src		0xa0c2bd8f
+#define clk_vfe1_clk_src		0x4e357366
+#define clk_csi1_clk_src		0x6a2a6c36
+#define clk_csi2_clk_src		0x4113589f
+#define clk_csi3_clk_src		0xfd934012
+#define clk_maxi_clk_src		0x52c09777
+#define clk_cpp_clk_src			0x8382f56d
+#define clk_jpeg0_clk_src		0x9a0a0ac3
+#define clk_jpeg2_clk_src		0x5ad927f3
+#define clk_jpeg_dma_clk_src		0xb68afcea
+#define clk_mdp_clk_src			0x6dc1f8f1
+#define clk_video_core_clk_src		0x8be4c944
+#define clk_fd_core_clk_src		0xe4799ab7
+#define clk_cci_clk_src			0x822f3d97
+#define clk_csiphy0_3p_clk_src		0xd2474b12
+#define clk_csiphy1_3p_clk_src		0x46a02aff
+#define clk_csiphy2_3p_clk_src		0x1447813f
+#define clk_camss_gp0_clk_src		0x6b57cfe6
+#define clk_camss_gp1_clk_src		0xf735368a
+#define clk_jpeg_dma_clk_src		0xb68afcea
+#define clk_mclk0_clk_src		0x266b3853
+#define clk_mclk1_clk_src		0xa73cad0c
+#define clk_mclk2_clk_src		0x42545468
+#define clk_mclk3_clk_src		0x2bfbb714
+#define clk_csi0phytimer_clk_src	0xc8a309be
+#define clk_csi1phytimer_clk_src	0x7c0fe23a
+#define clk_csi2phytimer_clk_src	0x62ffea9c
+#define clk_rbbmtimer_clk_src		0x17649ecc
+#define clk_esc0_clk_src		0xb41d7c38
+#define clk_esc1_clk_src		0x3b0afa42
+#define clk_hdmi_clk_src		0xb40aeea9
+#define clk_vsync_clk_src		0xecb43940
+#define clk_rbcpr_clk_src		0x2c2e9af2
+#define clk_video_subcore0_clk_src	0x88d79636
+#define clk_video_subcore1_clk_src	0x4966930c
+#define clk_mmss_bto_ahb_clk		0xfdf8c361
+#define clk_camss_ahb_clk		0xc4ff91d4
+#define clk_camss_cci_ahb_clk		0x04c4441a
+#define clk_camss_cci_clk		0xd6cb5eb9
+#define clk_camss_cpp_ahb_clk		0x12e9a87b
+#define clk_camss_cpp_clk		0xb82f366b
+#define clk_camss_cpp_axi_clk		0x5598c804
+#define clk_camss_cpp_vbif_ahb_clk	0xb5f31be4
+#define clk_camss_csi0_ahb_clk		0x6e29c972
+#define clk_camss_csi0_clk		0x30862ddb
+#define clk_camss_csi0phy_clk		0x2cecfb84
+#define clk_camss_csi0pix_clk		0x6946f77b
+#define clk_camss_csi0rdi_clk		0x83645ef5
+#define clk_camss_csi1_ahb_clk		0xccc15f06
+#define clk_camss_csi1_clk		0xb150f052
+#define clk_camss_csi1phy_clk		0xb989f06d
+#define clk_camss_csi1pix_clk		0x58d19bf3
+#define clk_camss_csi1rdi_clk		0x4d2f3352
+#define clk_camss_csi2_ahb_clk		0x92d02d75
+#define clk_camss_csi2_clk		0x74fc92e8
+#define clk_camss_csi2phy_clk		0xda05d9d8
+#define clk_camss_csi2pix_clk		0xf8ed0731
+#define clk_camss_csi2rdi_clk		0xdc1b2081
+#define clk_camss_csi3_ahb_clk		0xee5e459c
+#define clk_camss_csi3_clk		0x39488fdd
+#define clk_camss_csi3phy_clk		0x8b6063b9
+#define clk_camss_csi3pix_clk		0xd82bd467
+#define clk_camss_csi3rdi_clk		0xb6750046
+#define clk_camss_csi_vfe0_clk		0x3023937a
+#define clk_camss_csi_vfe1_clk		0xe66fa522
+#define clk_camss_csiphy0_3p_clk	0xf2a54f5a
+#define clk_camss_csiphy1_3p_clk	0x8bf70cb2
+#define clk_camss_csiphy2_3p_clk	0x1c14c939
+#define clk_camss_gp0_clk		0xcee7e51d
+#define clk_camss_gp1_clk		0x41f1c2e3
+#define clk_camss_ispif_ahb_clk		0x9a212c6d
+#define clk_camss_jpeg0_clk		0x0b0e2db7
+#define clk_camss_jpeg2_clk		0xd7291c8d
+#define clk_camss_jpeg_ahb_clk		0x1f47fd28
+#define clk_camss_jpeg_axi_clk		0x9e5545c8
+#define clk_camss_jpeg_dma_clk		0x2336e65d
+#define clk_camss_mclk0_clk		0xcf0c61e0
+#define clk_camss_mclk1_clk		0xd1410ed4
+#define clk_camss_mclk2_clk		0x851286f2
+#define clk_camss_mclk3_clk		0x4db11c45
+#define clk_camss_micro_ahb_clk		0x33a23277
+#define clk_camss_csi0phytimer_clk	0xff93b3c8
+#define clk_camss_csi1phytimer_clk	0x6c399ab6
+#define clk_camss_csi2phytimer_clk	0x24f47f49
+#define clk_camss_top_ahb_clk		0x8f8b2d33
+#define clk_camss_vfe_ahb_clk		0x595197bc
+#define clk_camss_vfe_axi_clk		0x273d4c31
+#define clk_camss_vfe0_ahb_clk		0x4652833c
+#define clk_camss_vfe0_clk		0x1e9bb8c4
+#define clk_camss_vfe0_stream_clk	0x22835fa4
+#define clk_camss_vfe1_ahb_clk		0x6a56abd3
+#define clk_camss_vfe1_clk		0x5bffa69b
+#define clk_camss_vfe1_stream_clk	0x92f849b9
+#define clk_fd_ahb_clk			0x868a2c5c
+#define clk_fd_core_clk			0x3badcae4
+#define clk_fd_core_uar_clk		0x7e624e15
+#define clk_gpu_ahb_clk			0xf97f1d43
+#define clk_gpu_aon_isense_clk		0xa9e9b297
+#define clk_gpu_gx_gfx3d_clk		0xb7ece823
+#define clk_gpu_mx_clk			0xb80ccedf
+#define clk_gpu_gx_rbbmtimer_clk	0xdeba634e
+#define clk_mdss_ahb_clk		0x684ccb41
+#define clk_mdss_axi_clk		0xcc07d687
+#define clk_mdss_esc0_clk		0x28cafbe6
+#define clk_mdss_esc1_clk		0xc22c6883
+#define clk_mdss_hdmi_ahb_clk		0x01cef516
+#define clk_mdss_hdmi_clk		0x097a6de9
+#define clk_mdss_mdp_clk		0x618336ac
+#define clk_mdss_vsync_clk		0x42a022d3
+#define clk_mmss_misc_ahb_clk		0xea30b0e7
+#define clk_mmss_misc_cxo_clk		0xe620cd80
+#define clk_mmagic_bimc_noc_cfg_ahb_clk 0x12d5ba72
+#define clk_mmagic_camss_axi_clk	0xa8b1c16b
+#define clk_mmagic_camss_noc_cfg_ahb_clk 0x5182c819
+#define clk_mmss_mmagic_cfg_ahb_clk	0x5e94a822
+#define clk_mmagic_mdss_axi_clk		0xa0359d10
+#define clk_mmagic_mdss_noc_cfg_ahb_clk 0x9c6d5482
+#define clk_mmagic_video_axi_clk	0x7b9219c3
+#define clk_mmagic_video_noc_cfg_ahb_clk 0x5124d256
+#define clk_mmss_mmagic_ahb_clk		0x3d15f2b0
+#define clk_mmss_mmagic_maxi_clk	0xbdaf5af7
+#define clk_mmss_rbcpr_ahb_clk		0x623ba55f
+#define clk_mmss_rbcpr_clk		0x69a23a6f
+#define clk_mmss_spdm_cpp_clk		0xefe35cd2
+#define clk_mmss_spdm_jpeg_dma_clk	0xcb7bd5a0
+#define clk_smmu_cpp_ahb_clk		0x3ad82d84
+#define clk_smmu_cpp_axi_clk		0xa6bb2f4a
+#define clk_smmu_jpeg_ahb_clk		0x10c436ec
+#define clk_smmu_jpeg_axi_clk		0x41112f37
+#define clk_smmu_mdp_ahb_clk		0x04994cb2
+#define clk_smmu_mdp_axi_clk		0x7fd71687
+#define clk_smmu_rot_ahb_clk		0xa30772c9
+#define clk_smmu_rot_axi_clk		0xfed7c078
+#define clk_smmu_vfe_ahb_clk		0x4dabebe7
+#define clk_smmu_vfe_axi_clk		0xde483725
+#define clk_smmu_video_ahb_clk		0x2d738e2c
+#define clk_smmu_video_axi_clk		0xe2b5b887
+#define clk_video_ahb_clk		0x90775cfb
+#define clk_video_axi_clk		0xe6c16dba
+#define clk_video_core_clk		0x7e876ec3
+#define clk_video_maxi_clk		0x97749db6
+#define clk_video_subcore0_clk		0xb6f63e6c
+#define clk_video_subcore1_clk		0x26c29cb4
+#define clk_vmem_ahb_clk		0xab6223ff
+#define clk_vmem_maxi_clk		0x15ef32db
+#define clk_mmss_debug_mux		0xe646ffda
+#define clk_mmss_gcc_dbg_clk		0xafa4d48a
+#define clk_gfx3d_clk_src		0x917f76ef
+#define clk_extpclk_clk_src		0xb2c31abd
+#define clk_mdss_byte0_clk		0xf5a03f64
+#define clk_mdss_byte1_clk		0xb8c7067d
+#define clk_mdss_extpclk_clk		0xfa5aadb0
+#define clk_mdss_pclk0_clk		0x3487234a
+#define clk_mdss_pclk1_clk		0xd5804246
+#define clk_gpu_gcc_dbg_clk		0x0ccc42cd
+#define clk_mdss_mdp_vote_clk		0x588460a4
+#define clk_mdss_rotator_vote_clk	0x5b1f675e
+#define clk_mmpll2_postdiv_clk		0x4fdeaaba
+#define clk_mmpll8_postdiv_clk		0xedf57882
+#define clk_mmpll9_postdiv_clk		0x3064b618
+#define clk_gfx3d_clk_src_v2		0x4210acb7
+#define clk_byte0_clk_src		0x75cc885b
+#define clk_byte1_clk_src		0x63c2c955
+#define clk_pclk0_clk_src		0xccac1f35
+#define clk_pclk1_clk_src		0x090f68ac
+#define clk_ext_byte0_clk_src		0xfb32f31e
+#define clk_ext_byte1_clk_src		0x585ef6d4
+#define clk_ext_pclk0_clk_src		0x087c1612
+#define clk_ext_pclk1_clk_src		0x8067c5a3
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux		0x8121ac15
+
+/* external multimedia clocks */
+#define clk_dsi0pll_pixel_clk_mux	0x792379e1
+#define clk_dsi0pll_byte_clk_mux	0x60e83f06
+#define clk_dsi0pll_byte_clk_src	0xbbaa30be
+#define clk_dsi0pll_pixel_clk_src	0x45b3260f
+#define clk_dsi0pll_n2_div_clk		0x1474c213
+#define clk_dsi0pll_post_n1_div_clk	0xdab8c389
+#define clk_dsi0pll_vco_clk		0x15940d40
+#define clk_dsi1pll_pixel_clk_mux	0x36458019
+#define clk_dsi1pll_byte_clk_mux	0xb5a42b7b
+#define clk_dsi1pll_byte_clk_src	0x63930a8f
+#define clk_dsi1pll_pixel_clk_src	0x0e4c9b56
+#define clk_dsi1pll_n2_div_clk		0x2c9d4007
+#define clk_dsi1pll_post_n1_div_clk	0x03020041
+#define clk_dsi1pll_vco_clk		0x99797b50
+#define clk_mdss_dsi1_vco_clk_src	0xfcd15658
+#define clk_hdmi_vco_clk		0x66003284
+
+#define clk_dsi0pll_shadow_byte_clk_src	0x177c029c
+#define clk_dsi0pll_shadow_pixel_clk_src	0x98ae3c92
+#define clk_dsi0pll_shadow_n2_div_clk	0xd5f0dad9
+#define clk_dsi0pll_shadow_post_n1_div_clk	0x1f7c8cf8
+#define clk_dsi0pll_shadow_vco_clk	0xb100ca83
+#define clk_dsi1pll_shadow_byte_clk_src	0xfc021ce5
+#define clk_dsi1pll_shadow_pixel_clk_src	0xdcca3ffc
+#define clk_dsi1pll_shadow_n2_div_clk		0x189541bf
+#define clk_dsi1pll_shadow_post_n1_div_clk	0x1637020e
+#define clk_dsi1pll_shadow_vco_clk		0x68d8b6f7
+
+/* CPU clocks */
+#define clk_pwrcl_clk 0xc554130e
+#define clk_pwrcl_pll 0x25454ca1
+#define clk_pwrcl_alt_pll 0xc445471b
+#define clk_pwrcl_pll_main 0x28948e22
+#define clk_pwrcl_alt_pll_main 0x25c8270e
+#define clk_pwrcl_hf_mux 0x77706ae6
+#define clk_pwrcl_lf_mux 0xd99e334d
+#define clk_perfcl_clk 0x58869997
+#define clk_perfcl_pll 0x97dcec1c
+#define clk_perfcl_alt_pll 0xfe2eaea1
+#define clk_perfcl_pll_main 0x0dbf0c0b
+#define clk_perfcl_alt_pll_main 0x0b892aab
+#define clk_perfcl_hf_mux 0x9e8bbe59
+#define clk_perfcl_lf_mux 0x2f9c278d
+#define clk_cbf_pll 0xfe2e96a3
+#define clk_cbf_pll_main 0x2b05cf95
+#define clk_cbf_hf_mux 0x71244f73
+#define clk_cbf_clk 0x48e9e16b
+#define clk_xo_ao 0x428c856d
+#define clk_sys_apcsaux_clk 0x0b0dd513
+#define clk_cpu_debug_mux 0xc7acaa31
+
+/* Audio External Clocks */
+#define clk_audio_ap_clk 0x312ac429
+#define clk_audio_pmi_clk 0xb7ba2274
+#define clk_audio_ap_clk2 0xf0fbaf5b
+#define clk_audio_lpass_mclk2 0x0122abee
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-a7.h b/include/dt-bindings/clock/msm-clocks-a7.h
new file mode 100644
index 0000000..6438b70
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-a7.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_A7_H
+#define __MSM_CLOCKS_A7_H
+
+#define clk_a7ssmux 0x3ea882af
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8952.h b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
new file mode 100644
index 0000000..888c2c7
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8952_HWIO_H
+#define __MSM_CLOCKS_8952_HWIO_H
+
+#define GPLL0_MODE			0x21000
+#define GPLL0_STATUS			0x2101C
+#define GPLL6_STATUS			0x3701C
+#define GPLL3_MODE			0x22000
+#define GPLL4_MODE			0x24000
+#define GPLL4_STATUS			0x24024
+#define GX_DOMAIN_MISC			0x5B00C
+#define SYS_MM_NOC_AXI_CBCR		0x3D008
+#define BIMC_GFX_CBCR			0x59034
+#define MSS_CFG_AHB_CBCR		0x49000
+#define	MSS_Q6_BIMC_AXI_CBCR		0x49004
+#define USB_HS_BCR			0x41000
+#define USB_HS_SYSTEM_CBCR		0x41004
+#define USB_HS_AHB_CBCR			0x41008
+#define USB_HS_PHY_CFG_AHB_CBCR		0x41030
+#define USB_HS_SYSTEM_CMD_RCGR		0x41010
+#define USB2A_PHY_SLEEP_CBCR		0x4102C
+#define USB_FS_SYSTEM_CBCR		0x3F004
+#define USB_FS_AHB_CBCR			0x3F008
+#define USB_FS_IC_CBCR			0x3F030
+#define USB_FS_SYSTEM_CMD_RCGR		0x3F010
+#define USB_FS_IC_CMD_RCGR		0x3F034
+#define USB2_HS_PHY_ONLY_BCR		0x41034
+#define QUSB2_PHY_BCR			0x4103C
+#define SDCC1_APPS_CMD_RCGR		0x42004
+#define SDCC1_APPS_CBCR			0x42018
+#define SDCC1_AHB_CBCR			0x4201C
+#define SDCC1_ICE_CORE_CMD_RCGR		0x5D000
+#define SDCC1_ICE_CORE_CBCR		0x5D014
+#define SDCC2_APPS_CMD_RCGR		0x43004
+#define SDCC2_APPS_CBCR			0x43018
+#define SDCC2_AHB_CBCR			0x4301C
+#define BLSP1_AHB_CBCR			0x01008
+#define BLSP1_QUP1_SPI_APPS_CBCR	0x02004
+#define BLSP1_QUP1_I2C_APPS_CBCR	0x02008
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR	0x0200C
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR	0x03000
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR	0x04000
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR	0x05000
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR	0x02024
+#define BLSP1_UART1_APPS_CBCR		0x0203C
+#define BLSP1_UART1_APPS_CMD_RCGR	0x02044
+#define BLSP1_QUP2_SPI_APPS_CBCR	0x0300C
+#define BLSP1_QUP2_I2C_APPS_CBCR	0x03010
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR	0x03014
+#define BLSP1_UART2_APPS_CBCR		0x0302C
+#define BLSP1_UART2_APPS_CMD_RCGR	0x03034
+#define BLSP1_QUP3_SPI_APPS_CBCR	0x0401C
+#define BLSP1_QUP3_I2C_APPS_CBCR	0x04020
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR	0x04024
+#define BLSP1_QUP4_SPI_APPS_CBCR	0x0501C
+#define BLSP1_QUP4_I2C_APPS_CBCR	0x05020
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR	0x05024
+#define BLSP2_AHB_CBCR			0x0B008
+#define BLSP2_QUP1_SPI_APPS_CBCR	0x0C004
+#define BLSP2_QUP1_I2C_APPS_CBCR	0x0C008
+#define BLSP2_QUP1_I2C_APPS_CMD_RCGR	0x0C00C
+#define BLSP2_QUP2_I2C_APPS_CMD_RCGR	0x0D000
+#define BLSP2_QUP3_I2C_APPS_CMD_RCGR	0x0F000
+#define BLSP2_QUP4_I2C_APPS_CMD_RCGR	0x18000
+#define BLSP2_QUP1_SPI_APPS_CMD_RCGR	0x0C024
+#define BLSP2_UART1_APPS_CBCR		0x0C03C
+#define BLSP2_UART1_APPS_CMD_RCGR	0x0C044
+#define BLSP2_QUP2_SPI_APPS_CBCR	0x0D00C
+#define BLSP2_QUP2_I2C_APPS_CBCR	0x0D010
+#define BLSP2_QUP2_SPI_APPS_CMD_RCGR	0x0D014
+#define BLSP2_UART2_APPS_CBCR		0x0D02C
+#define BLSP2_UART2_APPS_CMD_RCGR	0x0D034
+#define BLSP2_QUP3_SPI_APPS_CBCR	0x0F01C
+#define BLSP2_QUP3_I2C_APPS_CBCR	0x0F020
+#define BLSP2_QUP3_SPI_APPS_CMD_RCGR	0x0F024
+#define BLSP2_QUP4_SPI_APPS_CBCR	0x1801C
+#define BLSP2_QUP4_I2C_APPS_CBCR	0x18020
+#define BLSP2_QUP4_SPI_APPS_CMD_RCGR	0x18024
+#define PDM_AHB_CBCR			0x44004
+#define PDM2_CBCR			0x4400C
+#define PDM2_CMD_RCGR			0x44010
+#define PRNG_AHB_CBCR			0x13004
+#define BOOT_ROM_AHB_CBCR		0x1300C
+#define CRYPTO_CMD_RCGR			0x16004
+#define CRYPTO_CBCR			0x1601C
+#define CRYPTO_AXI_CBCR			0x16020
+#define CRYPTO_AHB_CBCR			0x16024
+#define GCC_XO_DIV4_CBCR		0x30034
+#define APSS_AHB_CMD_RCGR		0x46000
+#define GCC_PLLTEST_PAD_CFG		0x7400C
+#define GFX_TBU_CBCR			0x12010
+#define VENUS_TBU_CBCR			0x12014
+#define APSS_TCU_CBCR			0x12018
+#define MDP_TBU_CBCR			0x1201C
+#define GFX_TCU_CBCR			0x12020
+#define JPEG_TBU_CBCR			0x12034
+#define SMMU_CFG_CBCR			0x12038
+#define QDSS_DAP_CBCR			0x29084
+#define VFE_TBU_CBCR			0x1203C
+#define VFE1_TBU_CBCR			0x12090
+#define CPP_TBU_CBCR			0x12040
+#define APCS_GPLL_ENA_VOTE		0x45000
+#define APCS_CLOCK_BRANCH_ENA_VOTE	0x45004
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE	0x4500C
+#define GCC_DEBUG_CLK_CTL		0x74000
+#define CLOCK_FRQ_MEASURE_CTL		0x74004
+#define CLOCK_FRQ_MEASURE_STATUS	0x74008
+#define GP1_CBCR			0x08000
+#define GP1_CMD_RCGR			0x08004
+#define GP1_CFG_RCGR			0x08008
+#define GP2_CBCR			0x09000
+#define GP2_CMD_RCGR			0x09004
+#define GP3_CBCR			0x0A000
+#define GP3_CMD_RCGR			0x0A004
+#define VCODEC0_CMD_RCGR		0x4C000
+#define VENUS0_VCODEC0_CBCR		0x4C01C
+#define VENUS0_CORE0_VCODEC0_CBCR	0x4C02C
+#define VENUS0_CORE1_VCODEC0_CBCR	0x4C034
+#define VENUS0_AHB_CBCR			0x4C020
+#define VENUS0_AXI_CBCR			0x4C024
+#define PCLK0_CMD_RCGR			0x4D000
+#define MDP_CMD_RCGR			0x4D014
+#define VSYNC_CMD_RCGR			0x4D02C
+#define BYTE0_CMD_RCGR			0x4D044
+#define ESC0_CMD_RCGR			0x4D05C
+#define MDSS_AHB_CBCR			0x4D07C
+#define MDSS_AXI_CBCR			0x4D080
+#define MDSS_PCLK0_CBCR			0x4D084
+#define MDSS_MDP_CBCR			0x4D088
+#define MDSS_VSYNC_CBCR			0x4D090
+#define MDSS_BYTE0_CBCR			0x4D094
+#define MDSS_ESC0_CBCR			0x4D098
+#define CSI0PHYTIMER_CMD_RCGR		0x4E000
+#define CAMSS_CSI0PHYTIMER_CBCR		0x4E01C
+#define CSI0_CMD_RCGR			0x4E020
+#define CAMSS_CSI0_CBCR			0x4E03C
+#define CAMSS_CSI0_AHB_CBCR		0x4E040
+#define CAMSS_CSI0PHY_CBCR		0x4E048
+#define CAMSS_CSI0RDI_CBCR		0x4E050
+#define CAMSS_CSI0PIX_CBCR		0x4E058
+#define CSI1PHYTIMER_CMD_RCGR		0x4F000
+#define CSI1_CMD_RCGR			0x4F020
+#define CAMSS_CSI1_CBCR			0x4F03C
+#define CAMSS_CSI1PHYTIMER_CBCR		0x4F01C
+#define CAMSS_CSI1_AHB_CBCR		0x4F040
+#define CAMSS_CSI1PHY_CBCR		0x4F048
+#define CAMSS_CSI1RDI_CBCR		0x4F050
+#define CAMSS_CSI1PIX_CBCR		0x4F058
+#define CSI2_CMD_RCGR			0x3C020
+#define CAMSS_CSI2_CBCR			0x3C03C
+#define CAMSS_CSI2_AHB_CBCR		0x3C040
+#define CAMSS_CSI2PHY_CBCR		0x3C048
+#define CAMSS_CSI2RDI_CBCR		0x3C050
+#define CAMSS_CSI2PIX_CBCR		0x3C058
+#define CAMSS_ISPIF_AHB_CBCR		0x50004
+#define CCI_CMD_RCGR			0x51000
+#define CAMSS_CCI_CBCR			0x51018
+#define CAMSS_CCI_AHB_CBCR		0x5101C
+#define MCLK0_CMD_RCGR			0x52000
+#define CAMSS_MCLK0_CBCR		0x52018
+#define MCLK1_CMD_RCGR			0x53000
+#define CAMSS_MCLK1_CBCR		0x53018
+#define MCLK2_CMD_RCGR			0x5C000
+#define CAMSS_MCLK2_CBCR		0x5C018
+#define MM_GP0_CMD_RCGR			0x54000
+#define CAMSS_GP0_CBCR			0x54018
+#define MM_GP1_CMD_RCGR			0x55000
+#define CAMSS_GP1_CBCR			0x55018
+#define CAMSS_TOP_AHB_CBCR		0x5A014
+#define CAMSS_AHB_CBCR			0x56004
+#define CAMSS_MICRO_AHB_CBCR		0x5600C
+#define CAMSS_MICRO_BCR			0x56008
+#define JPEG0_CMD_RCGR			0x57000
+#define CAMSS_JPEG0_CBCR		0x57020
+#define CAMSS_JPEG_AHB_CBCR		0x57024
+#define CAMSS_JPEG_AXI_CBCR		0x57028
+#define VFE0_CMD_RCGR			0x58000
+#define CPP_CMD_RCGR			0x58018
+#define CAMSS_VFE0_CBCR			0x58038
+#define CAMSS_CPP_CBCR			0x5803C
+#define CAMSS_CPP_AHB_CBCR		0x58040
+#define CAMSS_VFE_AHB_CBCR		0x58044
+#define CAMSS_VFE_AXI_CBCR		0x58048
+#define CAMSS_CSI_VFE0_CBCR		0x58050
+#define VFE1_CMD_RCGR			0x58054
+#define CAMSS_VFE1_CBCR			0x5805C
+#define CAMSS_VFE1_AHB_CBCR		0x58060
+#define CAMSS_CPP_AXI_CBCR		0x58064
+#define CAMSS_VFE1_AXI_CBCR		0x58068
+#define CAMSS_CSI_VFE1_CBCR		0x58074
+#define GFX3D_CMD_RCGR			0x59000
+#define OXILI_GFX3D_CBCR		0x59020
+#define OXILI_GMEM_CBCR			0x59024
+#define OXILI_AHB_CBCR			0x59028
+#define OXILI_TIMER_CBCR		0x59040
+#define OXILI_AON_CBCR			0x5904C
+#define CAMSS_TOP_AHB_CMD_RCGR		0x5A000
+#define BIMC_GPU_CBCR			0x59030
+#define GTCU_AHB_CBCR			0x12044
+#define IPA_TBU_CBCR			0x120A0
+#define SYSTEM_MM_NOC_CMD_RCGR		0x3D000
+#define USB_FS_BCR			0x3F000
+
+#define APCS_CLOCK_SLEEP_ENA_VOTE	0x45008
+#define BYTE1_CMD_RCGR			0x4D0B0
+#define ESC1_CMD_RCGR			0x4D0A8
+#define PCLK1_CMD_RCGR			0x4D0B8
+#define MDSS_BYTE1_CBCR			0x4D0A0
+#define MDSS_ESC1_CBCR			0x4D09C
+#define MDSS_PCLK1_CBCR			0x4D0A4
+#define DCC_CBCR			0x77004
+
+#define RPM_MISC_CLK_TYPE		0x306b6c63
+#define RPM_BUS_CLK_TYPE		0x316b6c63
+#define RPM_MEM_CLK_TYPE		0x326b6c63
+#define RPM_IPA_CLK_TYPE		0x617069
+#define RPM_SMD_KEY_ENABLE		0x62616E45
+
+#define CXO_CLK_SRC_ID			0x0
+#define QDSS_CLK_ID			0x1
+
+#define PNOC_CLK_ID			0x0
+#define SNOC_CLK_ID			0x1
+#define SYSMMNOC_CLK_ID			0x2
+#define BIMC_CLK_ID			0x0
+#define BIMC_GPU_CLK_ID			0x2
+#define IPA_CLK_ID			0x0
+
+#define BUS_SCALING		0x2
+
+/* XO clock */
+#define BB_CLK1_ID		0x1
+#define BB_CLK2_ID		0x2
+#define RF_CLK2_ID		0x5
+#define LN_BB_CLK_ID		0x8
+#define DIV_CLK1_ID		0xb
+#define DIV_CLK2_ID		0xc
+
+#define APCS_CCI_PLL_MODE		0x00000
+#define APCS_CCI_PLL_L_VAL		0x00004
+#define APCS_CCI_PLL_M_VAL		0x00008
+#define APCS_CCI_PLL_N_VAL		0x0000C
+#define APCS_CCI_PLL_USER_CTL		0x00010
+#define APCS_CCI_PLL_CONFIG_CTL		0x00014
+#define APCS_CCI_PLL_STATUS		0x0001C
+
+#define APCS_C0_PLL_MODE		0x00000
+#define APCS_C0_PLL_L_VAL		0x00004
+#define APCS_C0_PLL_M_VAL		0x00008
+#define APCS_C0_PLL_N_VAL		0x0000C
+#define APCS_C0_PLL_USER_CTL		0x00010
+#define APCS_C0_PLL_CONFIG_CTL		0x00014
+#define APCS_C0_PLL_STATUS		0x0001C
+
+#define APCS_C1_PLL_MODE		0x00000
+#define APCS_C1_PLL_L_VAL		0x00004
+#define APCS_C1_PLL_M_VAL		0x00008
+#define APCS_C1_PLL_N_VAL		0x0000C
+#define APCS_C1_PLL_USER_CTL		0x00010
+#define APCS_C1_PLL_CONFIG_CTL		0x00014
+#define APCS_C1_PLL_STATUS		0x0001C
+
+
+#define CLKFLAG_WAKEUP_CYCLES		0x0
+#define CLKFLAG_SLEEP_CYCLES		0x0
+
+/* Mux source select values */
+#define xo_source_val			0
+#define xo_a_source_val			0
+#define gpll0_source_val		1
+#define gpll3_source_val		2
+#define gpll0_out_main_source_val	1   /* sdcc1_ice_core */
+/* cci_clk_src and usb_fs_system_clk_src */
+#define gpll0_out_aux_source_val	2
+#define gpll4_source_val		2   /* sdcc1_apss_clk_src */
+#define gpll4_out_source_val		3   /* sdcc1_apss_clk_src */
+#define gpll6_source_val		2   /* mclk0_2_clk_src */
+#define gpll6_aux_source_val		3   /* gfx3d_clk_src */
+#define gpll6_out_main_source_val	1   /* usb_fs_ic_clk_src */
+#define dsi0_phypll_source_val		1
+#define dsi0_0phypll_source_val		1   /* byte0_clk & pclk0_clk */
+#define dsi0_1phypll_source_val         3   /* byte1_clk & pclk1_clk */
+#define dsi1_0phypll_source_val         3   /* byte0_clk & pclk0_clk */
+#define dsi1_1phypll_source_val         1   /* byte1_clk & pclk1_clk */
+
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_SLEW(f, s_f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_freq = (s_f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_APCS_PLL(f, l, m, n, pre_div, post_div, vco) \
+	{ \
+		.freq_hz = (f), \
+		.l_val = (l), \
+		.m_val = (m), \
+		.n_val = (n), \
+		.pre_div_val = BVAL(12, 12, (pre_div)), \
+		.post_div_val = BVAL(9, 8, (post_div)), \
+		.vco_val = BVAL(29, 28, (vco)), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+# define OVERRIDE_FMAX1(clkname, l1, f1) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1)
+
+# define OVERRIDE_FMAX2(clkname, l1, f1, l2, f2) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);  \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2)
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+		[VDD_DIG_##l3] = (f3),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+# define OVERRIDE_FMAX3(clkname, l1, f1, l2, f2, l3, f3) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3)
+
+
+# define OVERRIDE_FMAX4(clkname, l1, f1, l2, f2, l3, f3, l4, f4) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4)
+
+#define VDD_DIG_FMAX_MAP5(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),\
+		[VDD_DIG_##l2] = (f2),\
+		[VDD_DIG_##l3] = (f3),\
+		[VDD_DIG_##l4] = (f4),\
+		[VDD_DIG_##l5] = (f5),\
+	},\
+	.num_fmax = VDD_DIG_NUM
+
+#define OVERRIDE_FMAX5(clkname, l1, f1, l2, f2, l3, f3, l4, f4, l5, f5) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l5] = (f5)
+
+#define OVERRIDE_FMAX6(clkname, \
+		l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l5] = (f5);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l6] = (f6)
+
+#define OVERRIDE_FTABLE(clkname, ftable, name) \
+	clkname##_clk_src.freq_tbl = ftable##_##name
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOWER,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_NOM_PLUS,
+	VDD_DIG_HIGH,
+	VDD_DIG_SUPER_TUR,
+	VDD_DIG_NUM
+};
+
+enum vdd_dig_levels_8917 {
+	VDD_DIG_NONE_8917,
+	VDD_DIG_LOWER_8917,
+	VDD_DIG_LOW_8917,
+	VDD_DIG_NOMINAL_8917,
+	VDD_DIG_NOM_PLUS_8917,
+	VDD_DIG_HIGH_8917,
+	VDD_DIG_NUM_8917
+};
+
+enum vdd_hf_pll_levels_8917 {
+	VDD_HF_PLL_OFF_8917,
+	VDD_HF_PLL_SVS_8917,
+	VDD_HF_PLL_NOM_8917,
+	VDD_HF_PLL_TUR_8917,
+	VDD_HF_PLL_NUM_8917,
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_LEVEL_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_LEVEL_SVS,		/* VDD_DIG_SVS */
+	RPM_REGULATOR_LEVEL_SVS_PLUS,		/* VDD_DIG_SVS_PLUS */
+	RPM_REGULATOR_LEVEL_NOM,		/* VDD_DIG_NOM */
+	RPM_REGULATOR_LEVEL_NOM_PLUS,		/* VDD_DIG_NOM_PLUS */
+	RPM_REGULATOR_LEVEL_TURBO,		/* VDD_DIG_TURBO */
+	RPM_REGULATOR_LEVEL_BINNING,		/* VDD_DIG_SUPER_TUR */
+};
+#endif
diff --git a/include/dt-bindings/clock/msm-cpu-clocks-8939.h b/include/dt-bindings/clock/msm-cpu-clocks-8939.h
new file mode 100644
index 0000000..cb16dca
--- /dev/null
+++ b/include/dt-bindings/clock/msm-cpu-clocks-8939.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCK_CPU_8939_H
+#define __MSM_CLOCK_CPU_8939_H
+
+#define clk_a53ssmux_lc				0x71a9377b
+#define clk_a53_lc_clk				0xc69f0878
+#define clk_a53ssmux_bc				0xb5983c42
+#define clk_a53_bc_clk				0xcf28e63a
+#define clk_a53ssmux_cci			0x15560bd5
+#define clk_cci_clk                             0x96854074
+#endif
diff --git a/include/dt-bindings/clock/qcom,cpucc-sdm845.h b/include/dt-bindings/clock/qcom,cpucc-sdm845.h
index f039284..bbfb849 100644
--- a/include/dt-bindings/clock/qcom,cpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,cpucc-sdm845.h
@@ -30,5 +30,6 @@
 #define L3_MISC_VOTE_CLK					13
 #define CPU4_PWRCL_CLK						14
 #define CPU5_PWRCL_CLK						15
+#define L3_GPU_VOTE_CLK						16
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 36d34b1..1018b0e 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -126,4 +126,7 @@
 #define GCC_USB_PHY_CFG_AHB2PHY_BCR				18
 #define GCC_EMAC_BCR						19
 
+/* Dummy clocks for rate measurement */
+#define MEASURE_ONLY_IPA_2X_CLK					0
+
 #endif
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index c357f27..0691068 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -10,6 +10,7 @@
 #include <linux/flex_proportions.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/kref.h>
 
 struct page;
 struct device;
@@ -20,6 +21,7 @@
  */
 enum wb_state {
 	WB_registered,		/* bdi_register() was done */
+	WB_shutting_down,	/* wb_shutdown() in progress */
 	WB_writeback_running,	/* Writeback is in progress */
 	WB_has_dirty_io,	/* Dirty inodes on ->b_{dirty|io|more_io} */
 };
@@ -53,7 +55,9 @@
 	atomic_t refcnt;		/* nr of attached wb's and blkg */
 
 #ifdef CONFIG_CGROUP_WRITEBACK
-	struct backing_dev_info *bdi;	/* the associated bdi */
+	struct backing_dev_info *__bdi;	/* the associated bdi, set to NULL
+					 * on bdi unregistration. For memcg-wb
+					 * internal use only! */
 	int blkcg_id;			/* ID of the associated blkcg */
 	struct rb_node rb_node;		/* on bdi->cgwb_congestion_tree */
 #endif
@@ -142,6 +146,7 @@
 
 	char *name;
 
+	struct kref refcnt;	/* Reference counter for the structure */
 	unsigned int min_ratio;
 	unsigned int max_ratio, max_prop_frac;
 
@@ -156,7 +161,6 @@
 #ifdef CONFIG_CGROUP_WRITEBACK
 	struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */
 	struct rb_root cgwb_congested_tree; /* their congested states */
-	atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */
 #else
 	struct bdi_writeback_congested *wb_congested;
 #endif
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 43b93a9..c52a48c 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -18,7 +18,14 @@
 #include <linux/slab.h>
 
 int __must_check bdi_init(struct backing_dev_info *bdi);
-void bdi_exit(struct backing_dev_info *bdi);
+
+static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
+{
+	kref_get(&bdi->refcnt);
+	return bdi;
+}
+
+void bdi_put(struct backing_dev_info *bdi);
 
 __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
@@ -29,6 +36,7 @@
 
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
 void bdi_destroy(struct backing_dev_info *bdi);
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
 
 void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
 			bool range_cyclic, enum wb_reason reason);
@@ -183,7 +191,7 @@
 	sb = inode->i_sb;
 #ifdef CONFIG_BLOCK
 	if (sb_is_blkdev_sb(sb))
-		return blk_get_backing_dev_info(I_BDEV(inode));
+		return I_BDEV(inode)->bd_bdi;
 #endif
 	return sb->s_bdi;
 }
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0693c3e..46cd13d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -345,7 +345,7 @@
 	 */
 	struct delayed_work	delay_work;
 
-	struct backing_dev_info	backing_dev_info;
+	struct backing_dev_info	*backing_dev_info;
 
 	/*
 	 * The queue owner gets to use this for whatever they like.
@@ -1031,7 +1031,6 @@
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
 extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua);
-extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
 extern int blk_rq_map_sg_no_cluster(struct request_queue *q, struct request *rq,
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 75ffd3b..7995940 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -36,7 +36,10 @@
 };
 
 struct bpf_map {
-	atomic_t refcnt;
+	/* 1st cacheline with read-mostly members of which some
+	 * are also accessed in fast-path (e.g. ops, max_entries).
+	 */
+	const struct bpf_map_ops *ops ____cacheline_aligned;
 	enum bpf_map_type map_type;
 	u32 key_size;
 	u32 value_size;
@@ -44,10 +47,15 @@
 	u32 map_flags;
 	u32 pages;
 	bool unpriv_array;
-	struct user_struct *user;
-	const struct bpf_map_ops *ops;
-	struct work_struct work;
+	/* 7 bytes hole */
+
+	/* 2nd cacheline with misc members to avoid false sharing
+	 * particularly with refcounting.
+	 */
+	struct user_struct *user ____cacheline_aligned;
+	atomic_t refcnt;
 	atomic_t usercnt;
+	struct work_struct work;
 };
 
 struct bpf_map_type_list {
diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h
index 2189935..a951fd1 100644
--- a/include/linux/cacheinfo.h
+++ b/include/linux/cacheinfo.h
@@ -71,6 +71,7 @@
 	struct cacheinfo *info_list;
 	unsigned int num_levels;
 	unsigned int num_leaves;
+	bool cpu_map_populated;
 };
 
 /*
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 793255d..53a061e 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -42,6 +42,8 @@
 					 * to first consumer that enables clk
 					 */
 #define CLK_IS_MEASURE          BIT(14) /* measure clock */
+/* do not call clk_change_rate on the clock's children */
+#define CLK_CHILD_NO_RATE_PROP	BIT(15)
 
 struct clk;
 struct clk_hw;
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 0d442e3..47f5ba6 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -199,7 +199,7 @@
 extern void clockevents_resume(void);
 
 # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-#  ifdef CONFIG_ARCH_HAS_TICK_BROADCAST
+#  if defined(CONFIG_ARCH_HAS_TICK_BROADCAST) && defined(CONFIG_SMP)
 extern void tick_broadcast(const struct cpumask *mask);
 #  else
 #   define tick_broadcast	NULL
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 32c3d42..fabfc0b 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2018, 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
@@ -272,11 +272,16 @@
 				struct device *dev, struct device_node *node);
 extern struct coresight_cti_data *of_get_coresight_cti_data(
 				struct device *dev, struct device_node *node);
+extern int of_get_coresight_csr_name(struct device_node *node,
+				const char **csr_name);
+
 #else
 static inline struct coresight_platform_data *of_get_coresight_platform_data(
 	struct device *dev, struct device_node *node) { return NULL; }
 static inline struct coresight_cti_data *of_get_coresight_cti_data(
 		struct device *dev, struct device_node *node) { return NULL; }
+static inline int of_get_coresight_csr_name(struct device_node *node,
+		const char **csr_name){ return -EINVAL; }
 #endif
 
 #ifdef CONFIG_PID_NS
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a964d07..2b9ece8 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -303,10 +303,18 @@
 	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
 			unsigned long arg);
 
+	/* perform fb specific ioctl v2 (optional) - provides file param */
+	int (*fb_ioctl_v2)(struct fb_info *info, unsigned int cmd,
+					unsigned long arg, struct file *file);
+
 	/* Handle 32bit compat ioctl (optional) */
-	int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
+	int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
 			unsigned long arg);
 
+	/* Handle 32bit compat ioctl (optional) */
+	int (*fb_compat_ioctl_v2)(struct fb_info *info, unsigned int cmd,
+				  unsigned long arg, struct file *file);
+
 	/* perform fb specific mmap */
 	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
 
@@ -475,6 +483,7 @@
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
 	struct fb_videomode *mode;	/* current mode */
+	struct file *file;		/* current file node */
 
 #ifdef CONFIG_FB_BACKLIGHT
 	/* assigned backlight device */
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 6e84b2cae..442b54a 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/nospec.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/fs.h>
@@ -81,8 +82,10 @@
 {
 	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
 
-	if (fd < fdt->max_fds)
+	if (fd < fdt->max_fds) {
+		fd = array_index_nospec(fd, fdt->max_fds);
 		return rcu_dereference_raw(fdt->fd[fd]);
+	}
 	return NULL;
 }
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4f6ec47..7fb621f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -475,6 +475,7 @@
 	int			bd_invalidated;
 	struct gendisk *	bd_disk;
 	struct request_queue *  bd_queue;
+	struct backing_dev_info *bd_bdi;
 	struct list_head	bd_list;
 	/*
 	 * Private data.  You must have bd_claim'ed the block_device
@@ -2398,6 +2399,7 @@
 #ifdef CONFIG_BLOCK
 extern int register_blkdev(unsigned int, const char *);
 extern void unregister_blkdev(unsigned int, const char *);
+extern void bdev_unhash_inode(dev_t dev);
 extern struct block_device *bdget(dev_t);
 extern struct block_device *bdgrab(struct block_device *bdev);
 extern void bd_set_size(struct block_device *, loff_t size);
diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h
index 20f5cba..08f30a46 100644
--- a/include/linux/hdcp_qseecom.h
+++ b/include/linux/hdcp_qseecom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -181,11 +181,9 @@
 /**
  * struct hdcp_client_ops - call back functions to display transport layer
  * @wakeup:            wake up display transport layer with a new command
- * @notify_lvl_change  notify of encryption level changes
  */
 struct hdcp_client_ops {
 	int (*wakeup)(struct hdcp_wakeup_data *data);
-	void (*notify_lvl_change)(void *client_ctx, int min_lvl);
 };
 
 /**
@@ -219,6 +217,4 @@
 bool hdcp1_check_if_supported_load_app(void);
 int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
 int hdcp1_set_enc(bool enable);
-void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
-void hdcp1_notify_topology(void);
 #endif /* __HDCP_QSEECOM_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index e30104c..8e346d1 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -4,6 +4,13 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 
+/* Built-in __init functions needn't be compiled with retpoline */
+#if defined(RETPOLINE) && !defined(MODULE)
+#define __noretpoline __attribute__((indirect_branch("keep")))
+#else
+#define __noretpoline
+#endif
+
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
  * as `initialization' functions. The kernel can take this
@@ -39,7 +46,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init		__section(.init.text) __cold notrace __latent_entropy
+#define __init		__section(.init.text) __cold notrace __latent_entropy __noretpoline
 #define __initdata	__section(.init.data)
 #define __initconst	__section(.init.rodata)
 #define __exitdata	__section(.exit.data)
diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h
index 2b91bc0..52241e5 100644
--- a/include/linux/input/synaptics_dsx_v2_6.h
+++ b/include/linux/input/synaptics_dsx_v2_6.h
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -57,6 +58,7 @@
  * @x_flip: x flip flag
  * @y_flip: y flip flag
  * @swap_axes: swap axes flag
+ * @resume_in_workqueue: defer resume function to workqueue
  * @irq_gpio: attention interrupt GPIO
  * @irq_on_state: attention interrupt active state
  * @power_gpio: power switch GPIO
@@ -84,6 +86,7 @@
 	bool x_flip;
 	bool y_flip;
 	bool swap_axes;
+	bool resume_in_workqueue;
 	int irq_gpio;
 	int irq_on_state;
 	int power_gpio;
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 46ee6da..4951e0b 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -1668,7 +1668,7 @@
 static inline int ipa_cfg_ep_conn_track(u32 clnt_hdl,
 	const struct ipa_ep_cfg_conn_track *ep_conn_track)
 {
-	return -EPERM
+	return -EPERM;
 }
 
 static inline int ipa_cfg_ep_hdr(u32 clnt_hdl,
diff --git a/include/linux/ipa_wdi3.h b/include/linux/ipa_wdi3.h
index aed8c59..6f00711 100644
--- a/include/linux/ipa_wdi3.h
+++ b/include/linux/ipa_wdi3.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,15 +24,49 @@
 	(IPA_HW_WDI3_TCL_DATA_CMD_ER_DESC_SIZE) : \
 	(IPA_HW_WDI3_IPA2FW_ER_DESC_SIZE))
 
+#define IPA_WDI_MAX_SUPPORTED_SYS_PIPE 3
+
+enum ipa_wdi_version {
+	IPA_WDI_1,
+	IPA_WDI_2,
+	IPA_WDI_3
+};
+
 /**
- * struct ipa_wdi3_hdr_info - Header to install on IPA HW
+ * struct ipa_wdi_init_in_params - wdi init input parameters
+ *
+ * @wdi_version: wdi version
+ * @notify: uc ready callback
+ * @priv: uc ready callback cookie
+ */
+struct ipa_wdi_init_in_params {
+	enum ipa_wdi_version wdi_version;
+	ipa_uc_ready_cb notify;
+	void *priv;
+	ipa_wdi_meter_notifier_cb wdi_notify;
+};
+
+/**
+ * struct ipa_wdi_init_out_params - wdi init output parameters
+ *
+ * @is_uC_ready: is uC ready. No API should be called until uC
+    is ready.
+ * @is_smmu_enable: is smmu enabled
+ */
+struct ipa_wdi_init_out_params {
+	bool is_uC_ready;
+	bool is_smmu_enabled;
+};
+
+/**
+ * struct ipa_wdi_hdr_info - Header to install on IPA HW
  *
  * @hdr: header to install on IPA HW
  * @hdr_len: length of header
  * @dst_mac_addr_offset: destination mac address offset
  * @hdr_type: layer two header type
  */
-struct ipa_wdi3_hdr_info {
+struct ipa_wdi_hdr_info {
 	u8 *hdr;
 	u8 hdr_len;
 	u8 dst_mac_addr_offset;
@@ -40,7 +74,7 @@
 };
 
 /**
- * struct ipa_wdi3_reg_intf_in_params - parameters for uC offload
+ * struct ipa_wdi_reg_intf_in_params - parameters for uC offload
  *	interface registration
  *
  * @netdev_name: network interface name
@@ -49,16 +83,17 @@
  * @meta_data: meta data if any
  * @meta_data_mask: meta data mask
  */
-struct ipa_wdi3_reg_intf_in_params {
+struct ipa_wdi_reg_intf_in_params {
 	const char *netdev_name;
-	struct ipa_wdi3_hdr_info hdr_info[IPA_IP_MAX];
+	struct ipa_wdi_hdr_info hdr_info[IPA_IP_MAX];
+	enum ipa_client_type alt_dst_pipe;
 	u8 is_meta_data_valid;
 	u32 meta_data;
 	u32 meta_data_mask;
 };
 
 /**
- * struct  ipa_wdi3_setup_info - WDI3 TX/Rx configuration
+ * struct  ipa_wdi_pipe_setup_info - WDI TX/Rx configuration
  * @ipa_ep_cfg: ipa endpoint configuration
  * @client: type of "client"
  * @transfer_ring_base_pa:  physical address of the base of the transfer ring
@@ -71,20 +106,20 @@
 	will update the headpointer of the event ring
  * @num_pkt_buffers:  Number of pkt buffers allocated. The size of the event
 	ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
- * @pkt_offset: packet offset (wdi3 header length)
+ * @pkt_offset: packet offset (wdi header length)
  * @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]:  Holds a cached
 	template of the desc format
  */
-struct ipa_wdi3_setup_info {
+struct ipa_wdi_pipe_setup_info {
 	struct ipa_ep_cfg ipa_ep_cfg;
 	enum ipa_client_type client;
-	dma_addr_t  transfer_ring_base_pa;
+	phys_addr_t  transfer_ring_base_pa;
 	u32  transfer_ring_size;
-	dma_addr_t  transfer_ring_doorbell_pa;
+	phys_addr_t  transfer_ring_doorbell_pa;
 
-	dma_addr_t  event_ring_base_pa;
+	phys_addr_t  event_ring_base_pa;
 	u32  event_ring_size;
-	dma_addr_t  event_ring_doorbell_pa;
+	phys_addr_t  event_ring_doorbell_pa;
 	u16  num_pkt_buffers;
 
 	u16 pkt_offset;
@@ -93,40 +128,87 @@
 };
 
 /**
- * struct  ipa_wdi3_conn_in_params - information provided by
+ * struct  ipa_wdi_pipe_setup_info_smmu - WDI TX/Rx configuration
+ * @ipa_ep_cfg: ipa endpoint configuration
+ * @client: type of "client"
+ * @transfer_ring_base_pa:  physical address of the base of the transfer ring
+ * @transfer_ring_size:  size of the transfer ring
+ * @transfer_ring_doorbell_pa:  physical address of the doorbell that
+	IPA uC will update the tailpointer of the transfer ring
+ * @event_ring_base_pa:  physical address of the base of the event ring
+ * @event_ring_size:  event ring size
+ * @event_ring_doorbell_pa:  physical address of the doorbell that IPA uC
+	will update the headpointer of the event ring
+ * @num_pkt_buffers:  Number of pkt buffers allocated. The size of the event
+	ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
+ * @pkt_offset: packet offset (wdi header length)
+ * @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]:  Holds a cached
+	template of the desc format
+ */
+struct ipa_wdi_pipe_setup_info_smmu {
+	struct ipa_ep_cfg ipa_ep_cfg;
+	enum ipa_client_type client;
+	struct sg_table  transfer_ring_base;
+	u32  transfer_ring_size;
+	phys_addr_t  transfer_ring_doorbell_pa;
+
+	struct sg_table  event_ring_base;
+	u32  event_ring_size;
+	phys_addr_t  event_ring_doorbell_pa;
+	u16  num_pkt_buffers;
+
+	u16 pkt_offset;
+
+	u32  desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE];
+};
+
+/**
+ * struct  ipa_wdi_conn_in_params - information provided by
  *		uC offload client
  * @notify: client callback function
  * @priv: client cookie
+ * @is_smmu_enabled: if smmu is enabled
+ * @num_sys_pipe_needed: number of sys pipe needed
+ * @sys_in: parameters to setup sys pipe in mcc mode
  * @tx: parameters to connect TX pipe(from IPA to WLAN)
+ * @tx_smmu: smmu parameters to connect TX pipe(from IPA to WLAN)
  * @rx: parameters to connect RX pipe(from WLAN to IPA)
+ * @rx_smmu: smmu parameters to connect RX pipe(from WLAN to IPA)
  */
-struct ipa_wdi3_conn_in_params {
+struct ipa_wdi_conn_in_params {
 	ipa_notify_cb notify;
 	void *priv;
-	struct ipa_wdi3_setup_info tx;
-	struct ipa_wdi3_setup_info rx;
+	bool is_smmu_enabled;
+	u8 num_sys_pipe_needed;
+	struct ipa_sys_connect_params sys_in[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+	union {
+		struct ipa_wdi_pipe_setup_info tx;
+		struct ipa_wdi_pipe_setup_info_smmu tx_smmu;
+	} u_tx;
+	union {
+		struct ipa_wdi_pipe_setup_info rx;
+		struct ipa_wdi_pipe_setup_info_smmu rx_smmu;
+	} u_rx;
 };
 
 /**
- * struct  ipa_wdi3_conn_out_params - information provided
+ * struct  ipa_wdi_conn_out_params - information provided
  *				to WLAN driver
  * @tx_uc_db_pa: physical address of IPA uC doorbell for TX
- * @tx_uc_db_va: virtual address of IPA uC doorbell for TX
  * @rx_uc_db_pa: physical address of IPA uC doorbell for RX
  */
-struct ipa_wdi3_conn_out_params {
-	dma_addr_t tx_uc_db_pa;
-	void __iomem *tx_uc_db_va;
-	dma_addr_t rx_uc_db_pa;
+struct ipa_wdi_conn_out_params {
+	phys_addr_t tx_uc_db_pa;
+	phys_addr_t rx_uc_db_pa;
 };
 
 /**
- * struct  ipa_wdi3_perf_profile - To set BandWidth profile
+ * struct  ipa_wdi_perf_profile - To set BandWidth profile
  *
  * @client: type of client
  * @max_supported_bw_mbps: maximum bandwidth needed (in Mbps)
  */
-struct ipa_wdi3_perf_profile {
+struct ipa_wdi_perf_profile {
 	enum ipa_client_type client;
 	u32 max_supported_bw_mbps;
 };
@@ -134,117 +216,193 @@
 #if defined CONFIG_IPA || defined CONFIG_IPA3
 
 /**
- * ipa_wdi3_reg_intf - Client should call this function to
- * init WDI3 IPA offload data path
+ * ipa_wdi_init - Client should call this function to
+ * init WDI IPA offload data path
  *
  * Note: Should not be called from atomic context and only
  * after checking IPA readiness using ipa_register_ipa_ready_cb()
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_reg_intf(
-	struct ipa_wdi3_reg_intf_in_params *in);
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out);
 
 /**
- * ipa_wdi3_dereg_intf - Client Driver should call this
+ * ipa_wdi_cleanup - Client should call this function to
+ * clean up WDI IPA offload data path
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_cleanup(void);
+
+/**
+ * ipa_wdi_reg_intf - Client should call this function to
+ * register interface
+ *
+ * Note: Should not be called from atomic context
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_reg_intf(
+	struct ipa_wdi_reg_intf_in_params *in);
+
+/**
+ * ipa_wdi_dereg_intf - Client Driver should call this
  * function to deregister before unload and after disconnect
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_dereg_intf(const char *netdev_name);
+int ipa_wdi_dereg_intf(const char *netdev_name);
 
 /**
- * ipa_wdi3_conn_pipes - Client should call this
+ * ipa_wdi_conn_pipes - Client should call this
  * function to connect pipes
  *
  * @in:	[in] input parameters from client
  * @out: [out] output params to client
  *
- * Note: Should not be called from atomic context and only
- * after checking IPA readiness using ipa_register_ipa_ready_cb()
+ * Note: Should not be called from atomic context
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out);
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out);
 
 /**
- * ipa_wdi3_disconn_pipes() - Client should call this
+ * ipa_wdi_disconn_pipes() - Client should call this
  *		function to disconnect pipes
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_disconn_pipes(void);
+int ipa_wdi_disconn_pipes(void);
 
 /**
- * ipa_wdi3_enable_pipes() - Client should call this
+ * ipa_wdi_enable_pipes() - Client should call this
  *		function to enable IPA offload data path
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_enable_pipes(void);
+int ipa_wdi_enable_pipes(void);
 
 /**
- * ipa_wdi3_disable_pipes() - Client should call this
+ * ipa_wdi_disable_pipes() - Client should call this
  *		function to disable IPA offload data path
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_disable_pipes(void);
+int ipa_wdi_disable_pipes(void);
 
 /**
- * ipa_wdi3_set_perf_profile() - Client should call this function to
+ * ipa_wdi_set_perf_profile() - Client should call this function to
  *		set IPA clock bandwidth based on data rates
  *
  * @profile: [in] BandWidth profile to use
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile);
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile);
 
+/**
+ * ipa_wdi_create_smmu_mapping() - Create smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_release_smmu_mapping() - Release smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_get_stats() - Query WDI statistics
+ * @stats:	[inout] stats blob from client populated by driver
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * @note Cannot be called from atomic context
+ *
+ */
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats);
 
 #else /* (CONFIG_IPA || CONFIG_IPA3) */
 
-static inline int ipa_wdi3_reg_intf(
-	struct ipa_wdi3_reg_intf_in_params *in)
+static inline int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_dereg_intf(const char *netdev_name)
+static inline int ipa_wdi_cleanup(void)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out)
+static inline int ipa_wdi_reg_intf(
+	struct ipa_wdi_reg_intf_in_params *in)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_disconn_pipes(void)
+static inline int ipa_wdi_dereg_intf(const char *netdev_name)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_enable_pipes(void)
+static inline int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_disable_pipes(void)
+static inline int ipa_wdi_disconn_pipes(void)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_set_perf_profile(
-	struct ipa_wdi3_perf_profile *profile)
+static inline int ipa_wdi_enable_pipes(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_disable_pipes(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_set_perf_profile(
+	struct ipa_wdi_perf_profile *profile)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
 {
 	return -EPERM;
 }
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 11ff751..c695ae6 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -66,6 +66,7 @@
 	} stable_secret;
 	__s32		use_oif_addrs_only;
 	__s32		keep_addr_on_down;
+	__s32		accept_ra_prefix_route;
 
 	struct ctl_table_header *sysctl_header;
 };
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 74de8b6..5c8b65a 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -108,6 +108,8 @@
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern struct kobject *kobject_get(struct kobject *kobj);
+extern struct kobject * __must_check kobject_get_unless_zero(
+						struct kobject *kobj);
 extern void kobject_put(struct kobject *kobj);
 
 extern const void *kobject_namespace(struct kobject *kobj);
diff --git a/include/linux/mdss_io_util.h b/include/linux/mdss_io_util.h
index 028f3e3..dd0b17c 100644
--- a/include/linux/mdss_io_util.h
+++ b/include/linux/mdss_io_util.h
@@ -28,26 +28,26 @@
 #define DEV_WARN(fmt, args...)  pr_warn(fmt, ##args)
 #define DEV_ERR(fmt, args...)   pr_err(fmt, ##args)
 
-struct dss_io_data {
+struct mdss_io_data {
 	u32 len;
 	void __iomem *base;
 };
 
-void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug);
-u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug);
-void dss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
+void mdss_reg_w(struct mdss_io_data *io, u32 offset, u32 value, u32 debug);
+u32 mdss_reg_r(struct mdss_io_data *io, u32 offset, u32 debug);
+void mdss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
 
-#define DSS_REG_W_ND(io, offset, val)  dss_reg_w(io, offset, val, false)
-#define DSS_REG_W(io, offset, val)     dss_reg_w(io, offset, val, true)
-#define DSS_REG_R_ND(io, offset)       dss_reg_r(io, offset, false)
-#define DSS_REG_R(io, offset)          dss_reg_r(io, offset, true)
+#define DSS_REG_W_ND(io, offset, val)  mdss_reg_w(io, offset, val, false)
+#define DSS_REG_W(io, offset, val)     mdss_reg_w(io, offset, val, true)
+#define DSS_REG_R_ND(io, offset)       mdss_reg_r(io, offset, false)
+#define DSS_REG_R(io, offset)          mdss_reg_r(io, offset, true)
 
-enum dss_vreg_type {
+enum mdss_vreg_type {
 	DSS_REG_LDO,
 	DSS_REG_VS,
 };
 
-enum dss_vreg_mode {
+enum mdss_vreg_mode {
 	DSS_REG_MODE_ENABLE,
 	DSS_REG_MODE_DISABLE,
 	DSS_REG_MODE_LP,
@@ -55,7 +55,7 @@
 	DSS_REG_MODE_MAX,
 };
 
-struct dss_vreg {
+struct mdss_vreg {
 	struct regulator *vreg; /* vreg handle */
 	char vreg_name[32];
 	int min_voltage;
@@ -67,51 +67,52 @@
 	int post_off_sleep;
 };
 
-struct dss_gpio {
+struct mdss_gpio {
 	unsigned int gpio;
 	unsigned int value;
 	char gpio_name[32];
 };
 
-enum dss_clk_type {
+enum mdss_clk_type {
 	DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
 	DSS_CLK_PCLK,
 	DSS_CLK_OTHER,
 };
 
-struct dss_clk {
+struct mdss_clk {
 	struct clk *clk; /* clk handle */
 	char clk_name[32];
-	enum dss_clk_type type;
+	enum mdss_clk_type type;
 	unsigned long rate;
 };
 
-struct dss_module_power {
+struct mdss_module_power {
 	unsigned int num_vreg;
-	struct dss_vreg *vreg_config;
+	struct mdss_vreg *vreg_config;
 	unsigned int num_gpio;
-	struct dss_gpio *gpio_config;
+	struct mdss_gpio *gpio_config;
 	unsigned int num_clk;
-	struct dss_clk *clk_config;
+	struct mdss_clk *clk_config;
 };
 
-int msm_dss_ioremap_byname(struct platform_device *pdev,
-	struct dss_io_data *io_data, const char *name);
-void msm_dss_iounmap(struct dss_io_data *io_data);
+int msm_mdss_ioremap_byname(struct platform_device *pdev,
+	struct mdss_io_data *io_data, const char *name);
+void msm_mdss_iounmap(struct mdss_io_data *io_data);
 
-int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
-int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_mdss_enable_gpio(struct mdss_gpio *in_gpio, int num_gpio, int enable);
+int msm_mdss_gpio_enable(struct mdss_gpio *in_gpio, int num_gpio, int enable);
 
-int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+int msm_mdss_config_vreg(struct device *dev, struct mdss_vreg *in_vreg,
 	int num_vreg, int config);
-int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg,	int enable);
-int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
-	 enum dss_vreg_mode mode);
+int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable);
+int msm_mdss_config_vreg_opt_mode(struct mdss_vreg *in_vreg, int num_vreg,
+	 enum mdss_vreg_mode mode);
 
-int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
-void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
-int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
-int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
+int msm_mdss_get_clk(struct device *dev, struct mdss_clk *clk_arry,
+		     int num_clk);
+void msm_mdss_put_clk(struct mdss_clk *clk_arry, int num_clk);
+int msm_mdss_clk_set_rate(struct mdss_clk *clk_arry, int num_clk);
+int msm_mdss_enable_clk(struct mdss_clk *clk_arry, int num_clk, int enable);
 
 int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
 		       uint8_t reg_offset, uint8_t *read_buf);
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 25ed105..20ee90c 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -737,6 +737,12 @@
 	MLX5_CAP_PORT_TYPE_ETH = 0x1,
 };
 
+enum {
+	MLX5_CAP_UMR_FENCE_STRONG	= 0x0,
+	MLX5_CAP_UMR_FENCE_SMALL	= 0x1,
+	MLX5_CAP_UMR_FENCE_NONE		= 0x2,
+};
+
 struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         reserved_at_0[0x80];
 
@@ -838,7 +844,9 @@
 	u8         striding_rq[0x1];
 	u8         reserved_at_201[0x2];
 	u8         ipoib_basic_offloads[0x1];
-	u8         reserved_at_205[0xa];
+	u8         reserved_at_205[0x5];
+	u8         umr_fence[0x2];
+	u8         reserved_at_20c[0x3];
 	u8         drain_sigerr[0x1];
 	u8         cmdif_checksum[0x2];
 	u8         sigerr_cqe[0x1];
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 16155d0..932e99c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1901,6 +1901,7 @@
 /* page_alloc.c */
 extern int min_free_kbytes;
 extern int watermark_scale_factor;
+extern int extra_free_kbytes;
 
 /* nommu.c */
 extern atomic_long_t mmap_pages_allocated;
diff --git a/include/linux/module.h b/include/linux/module.h
index 0c3207d..d2224a0 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -791,6 +791,15 @@
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif	/* CONFIG_GENERIC_BUG */
 
+#ifdef RETPOLINE
+extern bool retpoline_module_ok(bool has_retpoline);
+#else
+static inline bool retpoline_module_ok(bool has_retpoline)
+{
+	return true;
+}
+#endif
+
 #ifdef CONFIG_MODULE_SIG
 static inline bool module_sig_ok(struct module *module)
 {
diff --git a/include/linux/msm_hdcp.h b/include/linux/msm_hdcp.h
new file mode 100644
index 0000000..e25d242
--- /dev/null
+++ b/include/linux/msm_hdcp.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_HDCP_H
+#define __MSM_HDCP_H
+#include <linux/types.h>
+#include "video/msm_hdmi_hdcp_mgr.h"
+
+void msm_hdcp_notify_topology(struct device *dev);
+void msm_hdcp_cache_repeater_topology(struct device *dev,
+			struct HDCP_V2V1_MSG_TOPOLOGY *tp);
+void msm_hdcp_register_cb(struct device *dev, void *ctx,
+	void (*cb)(void *ctx, int data));
+
+#endif /* __MSM_HDCP_H */
+
+
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
index afaa08a20..d5a5457 100644
--- a/include/linux/msm_hdmi.h
+++ b/include/linux/msm_hdmi.h
@@ -1,10 +1,6 @@
 /* include/linux/msm_hdmi.h
  *
-<<<<<<< HEAD
  * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
-=======
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
->>>>>>> dfa46f9... fbdev: msm: fix compilation error
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 3aa56e3..b5b43f9 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -270,75 +270,67 @@
 #define INVALIDATE_CACHED_RANGE(map, from, size) \
 	do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
 
+#define map_word_equal(map, val1, val2)					\
+({									\
+	int i, ret = 1;							\
+	for (i = 0; i < map_words(map); i++)				\
+		if ((val1).x[i] != (val2).x[i]) {			\
+			ret = 0;					\
+			break;						\
+		}							\
+	ret;								\
+})
 
-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
-{
-	int i;
+#define map_word_and(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] & (val2).x[i];			\
+	r;								\
+})
 
-	for (i = 0; i < map_words(map); i++) {
-		if (val1.x[i] != val2.x[i])
-			return 0;
-	}
+#define map_word_clr(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] & ~(val2).x[i];			\
+	r;								\
+})
 
-	return 1;
-}
+#define map_word_or(map, val1, val2)					\
+({									\
+	map_word r;							\
+	int i;								\
+	for (i = 0; i < map_words(map); i++)				\
+		r.x[i] = (val1).x[i] | (val2).x[i];			\
+	r;								\
+})
 
-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
+#define map_word_andequal(map, val1, val2, val3)			\
+({									\
+	int i, ret = 1;							\
+	for (i = 0; i < map_words(map); i++) {				\
+		if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) {	\
+			ret = 0;					\
+			break;						\
+		}							\
+	}								\
+	ret;								\
+})
 
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] & val2.x[i];
-
-	return r;
-}
-
-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
-
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] & ~val2.x[i];
-
-	return r;
-}
-
-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
-{
-	map_word r;
-	int i;
-
-	for (i = 0; i < map_words(map); i++)
-		r.x[i] = val1.x[i] | val2.x[i];
-
-	return r;
-}
-
-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
-{
-	int i;
-
-	for (i = 0; i < map_words(map); i++) {
-		if ((val1.x[i] & val2.x[i]) != val3.x[i])
-			return 0;
-	}
-
-	return 1;
-}
-
-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
-{
-	int i;
-
-	for (i = 0; i < map_words(map); i++) {
-		if (val1.x[i] & val2.x[i])
-			return 1;
-	}
-
-	return 0;
-}
+#define map_word_bitsset(map, val1, val2)				\
+({									\
+	int i, ret = 0;							\
+	for (i = 0; i < map_words(map); i++) {				\
+		if ((val1).x[i] & (val2).x[i]) {			\
+			ret = 1;					\
+			break;						\
+		}							\
+	}								\
+	ret;								\
+})
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
new file mode 100644
index 0000000..b99bced
--- /dev/null
+++ b/include/linux/nospec.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set.  Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+						    unsigned long size)
+{
+	/*
+	 * Warn developers about inappropriate array_index_nospec() usage.
+	 *
+	 * Even if the CPU speculates past the WARN_ONCE branch, the
+	 * sign bit of @index is taken into account when generating the
+	 * mask.
+	 *
+	 * This warning is compiled out when the compiler can infer that
+	 * @index and @size are less than LONG_MAX.
+	 */
+	if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX,
+			"array_index_nospec() limited to range of [0, LONG_MAX]\n"))
+		return 0;
+
+	/*
+	 * Always calculate and emit the mask even if the compiler
+	 * thinks the mask is not needed. The compiler does not take
+	 * into account the value of @index under speculation.
+	 */
+	OPTIMIZER_HIDE_VAR(index);
+	return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ *     if (index < size) {
+ *         index = array_index_nospec(index, size);
+ *         val = array[index];
+ *     }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size)					\
+({									\
+	typeof(index) _i = (index);					\
+	typeof(size) _s = (size);					\
+	unsigned long _mask = array_index_mask_nospec(_i, _s);		\
+									\
+	BUILD_BUG_ON(sizeof(_i) > sizeof(long));			\
+	BUILD_BUG_ON(sizeof(_s) > sizeof(long));			\
+									\
+	_i &= _mask;							\
+	_i;								\
+})
+#endif /* _LINUX_NOSPEC_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 164abe2..43d801e 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -272,8 +272,12 @@
 	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+	POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_RECHARGE_SOC,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 9a079a6..a083370 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -133,8 +133,11 @@
 	VADC_VCOIN = 0x85,
 	VADC_DIE_TEMP = 6,
 	VADC_CHG_TEMP = 7,
+	VADC_USB_IN_I_PM5 = 7,
 	VADC_USB_IN = 8,
+	VADC_USB_IN_V_DIV_16_PM5 = 8,
 	VADC_IREG_FB = 9,
+	VADC_CHG_TEMP_PM5 = 9,
 	/* External input connection */
 	VADC_BAT_THERM = 0xa,
 	VADC_BAT_ID = 0xb,
@@ -156,6 +159,7 @@
 	VADC_ATEST2 = 0x1b,
 	VADC_ATEST3 = 0x1c,
 	VADC_ATEST4 = 0x1d,
+	VADC_MID_CHG_DIV_6 = 0x1e,
 	VADC_OFF = 0xff,
 	/* PU1 is 30K pull up */
 	VADC_BAT_THERM_PU1 = 0x2a,
@@ -222,6 +226,13 @@
 	VADC_ATEST3_DIV_3 = 0x9c,
 	VADC_ATEST4_DIV_3 = 0x9d,
 	VADC_REFRESH_MAX_NUM = 0xffff,
+	/*Current and synchronous channels*/
+	VADC_ISNS_INT_EXT_PM5 = 0xa1,
+	VADC_ISNS_PAR_PM5 = 0xa5,
+	VADC_V_I_INT_EXT_VDATA_PM5 = 0xb0,
+	VADC_V_I_INT_EXT_IDATA_PM5 = 0xb1,
+	VADC_V_I_PAR_VDATA_PM5 = 0xb4,
+	VADC_V_I_PAR_IDATA_PM5 = 0xb5,
 };
 
 /**
@@ -388,6 +399,9 @@
  * %SCALE_DIE_TEMP: Conversion for die temp.
  * %SCALE_I_DEFAULT: Default scaling to convert raw adc code to current (uA).
  * %SCALE_USBIN_I: Conversion for USB input current.
+ * %SCALE_BATT_THERM_TEMP_QRD: Conversion to temperature(decidegC) based on btm
+ *			parameters for QRD.
+ * %SCALE_SMB1390_DIE_TEMP: Conversion for SMB1390 die temp
  * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
@@ -410,6 +424,8 @@
 	SCALE_DIE_TEMP,
 	SCALE_I_DEFAULT,
 	SCALE_USBIN_I,
+	SCALE_BATT_THERM_TEMP_QRD,
+	SCALE_SMB1390_DIE_TEMP,
 	SCALE_NONE,
 };
 
@@ -1432,6 +1448,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_batt_therm_qrd() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC for QRD.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset. Returns the temperature in decidegC.
@@ -1692,6 +1725,25 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_die_temp_1390() -  Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. The voltage measured by HKADC is related to
+ *		the junction temperature according to
+ *		V_adc = 1.496 – 0.00381*Tj
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_get_vadc() - Clients need to register with the vadc using the
  *		corresponding device instance it wants to read the channels
  *		from. Read the bindings document on how to pass the phandle
@@ -2033,6 +2085,12 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
@@ -2123,6 +2181,12 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_scale_die_temp_1390(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev,
 							const char *name)
 { return ERR_PTR(-ENXIO); }
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 14e8d79..c1206c6 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -162,6 +162,9 @@
 
 #define PM8950_V2P0_REV4	0x02
 
+/* PM8953 */
+#define PM8953_SUBTYPE		0x16
+
 /* PMI8950 */
 #define PMI8950_SUBTYPE		0x11
 
@@ -184,6 +187,11 @@
 /* PMI632 */
 #define PMI632_SUBTYPE	0x25
 
+/* PM855 */
+#define PM855_SUBTYPE		0x1E
+#define PM855L_SUBTYPE		0x1F
+#define PM855B_SUBTYPE		0x20
+
 /* PMI8998 REV_ID */
 #define PMI8998_V1P0_REV1	0x00
 #define PMI8998_V1P0_REV2	0x00
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 62c770d..8933c9f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1777,7 +1777,7 @@
 	u32 init_load_pct;
 	u64 last_wake_ts;
 	u64 last_switch_out_ts;
-	u64 last_cpu_selected_ts;
+	u64 last_enqueued_ts;
 	struct related_thread_group *grp;
 	struct list_head grp_list;
 	u64 cpu_cycles;
@@ -2754,11 +2754,6 @@
 	return 0;
 }
 
-static inline void
-sched_set_cpu_cstate(int cpu, int cstate, int wakeup_energy, int wakeup_latency)
-{
-}
-
 #ifdef CONFIG_SCHED_WALT
 extern int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb);
 extern void sched_set_io_is_busy(int val);
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 2ec3507..0f57407 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -33,6 +33,7 @@
 extern unsigned int sysctl_sched_boost;
 extern unsigned int sysctl_sched_group_upmigrate_pct;
 extern unsigned int sysctl_sched_group_downmigrate_pct;
+extern unsigned int sysctl_sched_walt_rotate_big_tasks;
 
 extern int
 walt_proc_update_handler(struct ctl_table *table, int write,
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 53af941..4b5dc54 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -601,7 +601,7 @@
 	int			(*framer_handover)(struct slim_controller *ctrl,
 				struct slim_framer *new_framer);
 	int			(*port_xfer)(struct slim_controller *ctrl,
-				u8 pn, phys_addr_t iobuf, u32 len,
+				u8 pn, void *buf, u32 len,
 				struct completion *comp);
 	enum slim_port_err	(*port_xfer_status)(struct slim_controller *ctr,
 				u8 pn, phys_addr_t *done_buf, u32 *done_len);
@@ -869,7 +869,7 @@
  * Client will call slim_port_get_xfer_status to get error and/or number of
  * bytes transferred if used asynchronously.
  */
-extern int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf,
+extern int slim_port_xfer(struct slim_device *sb, u32 ph, void *buf,
 				u32 len, struct completion *comp);
 
 /*
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 52bc890..33c1dae 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -393,6 +393,8 @@
  *		   temperature.
  * @set_trip_temp: a pointer to a function that sets the trip temperature on
  *		   hardware.
+ * @get_trip_temp: a pointer to a function that gets the trip temperature on
+ *		   hardware.
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
@@ -400,6 +402,7 @@
 	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
+	int (*get_trip_temp)(void *, int, int *);
 };
 
 /**
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 972dabc..3f3a7e4 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -84,6 +84,8 @@
  * @db_reg_phs_addr_lsb: IPA channel doorbell register's physical address LSB
  * @mapped_db_reg_phs_addr_lsb: doorbell LSB IOVA address mapped with IOMMU
  * @db_reg_phs_addr_msb: IPA channel doorbell register's physical address MSB
+ * @sgt_trb_xfer_ring: USB TRB ring related sgtable entries
+ * @sgt_data_buff: Data buffer related sgtable entries
  */
 struct usb_gsi_request {
 	void *buf_base_addr;
@@ -93,6 +95,8 @@
 	u32 db_reg_phs_addr_lsb;
 	dma_addr_t mapped_db_reg_phs_addr_lsb;
 	u32 db_reg_phs_addr_msb;
+	struct sg_table sgt_trb_xfer_ring;
+	struct sg_table sgt_data_buff;
 };
 
 /*
@@ -474,6 +478,10 @@
  * @deactivated: True if gadget is deactivated - in deactivated state it cannot
  *	be connected.
  * @connected: True if gadget is connected.
+ * @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
+ * @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
+ * boundary access is protected.
+ * @is_chipidea: True if ChipIdea device controller
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -527,6 +535,10 @@
 	unsigned			deactivated:1;
 	unsigned			connected:1;
 	bool				remote_wakeup;
+	bool				bam2bam_func_enabled;
+	u32				extra_buf_alloc;
+	bool				l1_supported;
+	bool				is_chipidea;
 };
 #define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
 
@@ -1123,7 +1135,7 @@
 			const char *ep_name);
 
 #ifdef CONFIG_USB_DWC3_MSM
-int msm_ep_config(struct usb_ep *ep);
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request);
 int msm_ep_unconfig(struct usb_ep *ep);
 void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
 int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size,
@@ -1135,7 +1147,7 @@
 	u32 size, u8 dst_pipe_idx)
 {	return -ENODEV; }
 
-static inline int msm_ep_config(struct usb_ep *ep)
+static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
 { return -ENODEV; }
 
 static inline int msm_ep_unconfig(struct usb_ep *ep)
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d070109..3a28749 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -664,6 +664,7 @@
 
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 
+#ifdef CONFIG_USB
 #ifdef CONFIG_PM
 extern void usb_root_hub_lost_power(struct usb_device *rhdev);
 extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
@@ -675,7 +676,15 @@
 	return;
 }
 #endif /* CONFIG_PM */
-
+#else  /* CONFIG_USB */
+extern int usb_add_hcd(struct usb_hcd *hcd,
+		unsigned int irqnum, unsigned long irqflags)
+{
+	return 0;
+}
+extern void usb_remove_hcd(struct usb_hcd *hcd) {}
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd) {}
+#endif /* CONFIG_USB */
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
new file mode 100644
index 0000000..1c7dc0d
--- /dev/null
+++ b/include/linux/usb/msm_hsusb.h
@@ -0,0 +1,308 @@
+/* include/linux/usb/msm_hsusb.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_HSUSB_H
+#define __ASM_ARCH_MSM_HSUSB_H
+
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/clk.h>
+#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
+#include <linux/power_supply.h>
+#include <linux/cdev.h>
+#include <linux/usb_bam.h>
+#include <linux/extcon.h>
+#include <linux/regulator/driver.h>
+/**
+ * Requested USB votes for NOC frequency
+ *
+ * USB_NOC_NOM_VOTE    Vote for NOM set of NOC frequencies
+ * USB_NOC_SVS_VOTE    Vote for SVS set of NOC frequencies
+ *
+ */
+enum usb_noc_mode {
+	USB_NOC_NOM_VOTE = 0,
+	USB_NOC_SVS_VOTE,
+	USB_NOC_NUM_VOTE,
+};
+
+/**
+ * USB charger types
+ *
+ * USB_INVALID_CHARGER	Invalid USB charger.
+ * USB_SDP_CHARGER	Standard downstream port. Refers to a downstream port
+ *                      on USB2.0 compliant host/hub.
+ * USB_DCP_CHARGER	Dedicated charger port (AC charger/ Wall charger).
+ * USB_CDP_CHARGER	Charging downstream port. Enumeration can happen and
+ *                      IDEV_CHG_MAX can be drawn irrespective of USB state.
+ * USB_NONCOMPLIANT_CHARGER A non-compliant charger pull DP and DM to specific
+ *			    voltages between 2.0-3.3v for identification.
+ *
+ */
+enum usb_chg_type {
+	USB_INVALID_CHARGER = 0,
+	USB_SDP_CHARGER,
+	USB_DCP_CHARGER,
+	USB_CDP_CHARGER,
+	USB_NONCOMPLIANT_CHARGER,
+	USB_FLOATED_CHARGER,
+};
+
+/**
+ * Maintain state for hvdcp external charger status
+ * DEFAULT	This is used when DCP is detected
+ * ACTIVE	This is used when ioctl is called to block LPM
+ * INACTIVE	This is used when ioctl is called to unblock LPM
+ */
+
+enum usb_ext_chg_status {
+	DEFAULT = 1,
+	ACTIVE,
+	INACTIVE,
+};
+
+/**
+ * USB ID state
+ */
+enum usb_id_state {
+	USB_ID_GROUND = 0,
+	USB_ID_FLOAT,
+};
+
+#define USB_NUM_BUS_CLOCKS      3
+
+/**
+ * struct msm_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @pdata: otg device platform data.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
+ * @phy_irq: IRQ number assigned for PHY to notify events like id and line
+		state changes.
+ * @pclk: clock struct of iface_clk.
+ * @core_clk: clock struct of core_bus_clk.
+ * @sleep_clk: clock struct of sleep_clk for USB PHY.
+ * @phy_reset_clk: clock struct of phy_reset_clk for USB PHY. This clock is
+		a reset only clock and resets the PHY, ULPI bridge and
+		CSR wrapper.
+ * @phy_por_clk: clock struct of phy_por_clk for USB PHY. This clock is
+		a reset only clock and resets only the PHY (POR).
+ * @phy_csr_clk: clock struct of phy_csr_clk for USB PHY. This clock is
+		required to access PHY CSR registers via AHB2PHY interface.
+ * @bus_clks: bimc/snoc/pcnoc clock struct.
+ * @core_reset: Reset control for core_clk
+ * @phy_reset: Reset control for phy_reset_clk
+ * @phy_por_reset: Reset control for phy_por_clk
+ * @default_noc_mode: default frequency for NOC clocks - SVS or NOM
+ * @core_clk_rate: core clk max frequency
+ * @regs: ioremapped register base address.
+ * @usb_phy_ctrl_reg: relevant PHY_CTRL_REG register base address.
+ * @inputs: OTG state machine inputs(Id, SessValid etc).
+ * @sm_work: OTG state machine work.
+ * @sm_work_pending: OTG state machine work is pending, queued post pm_resume
+ * @resume_pending: USB h/w lpm_exit pending. Done on next sm_work run
+ * @pm_suspended: OTG device is system(PM) suspended.
+ * @pm_notify: Notifier to receive system wide PM transition events.
+		It is used to defer wakeup events processing until
+		system is RESUMED.
+ * @in_lpm: indicates low power mode (LPM) state.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
+ * @cur_power: The amount of mA available from downstream port.
+ * @otg_wq: Strict order otg workqueue for OTG works (SM/ID/SUSPEND).
+ * @chg_type: The type of charger attached.
+ * @bus_perf_client: Bus performance client handle to request BUS bandwidth
+ * @host_bus_suspend: indicates host bus suspend or not.
+ * @device_bus_suspend: indicates device bus suspend or not.
+ * @bus_clks_enabled: indicates pcnoc/snoc/bimc clocks are on or not.
+ * @is_ext_chg_dcp: To indicate whether charger detected by external entity
+		SMB hardware is DCP charger or not.
+ * @ext_id_irq: IRQ for ID interrupt.
+ * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM.
+ * @id_state: Indicates USBID line status.
+ * @rm_pulldown: Indicates pulldown status on D+ and D- data lines.
+ * @extcon_vbus: Used for VBUS notification registration.
+ * @extcon_id: Used for ID notification registration.
+ * @vbus_nb: Notification callback for VBUS event.
+ * @id_nb: Notification callback for ID event.
+ * @dpdm_desc: Regulator descriptor for D+ and D- voting.
+ * @dpdm_rdev: Regulator class device for dpdm regulator.
+ * @dbg_idx: Dynamic debug buffer Index.
+ * @dbg_lock: Dynamic debug buffer Lock.
+ * @buf: Dynamic Debug Buffer.
+ * @max_nominal_system_clk_rate: max freq at which system clock can run in
+		nominal mode.
+ */
+struct msm_otg {
+	struct usb_phy phy;
+	struct msm_otg_platform_data *pdata;
+	struct platform_device *pdev;
+	int irq;
+	int async_irq;
+	int phy_irq;
+	struct clk *xo_clk;
+	struct clk *pclk;
+	struct clk *core_clk;
+	struct clk *sleep_clk;
+	struct clk *phy_reset_clk;
+	struct clk *phy_por_clk;
+	struct clk *phy_csr_clk;
+	struct clk *bus_clks[USB_NUM_BUS_CLOCKS];
+	struct clk *phy_ref_clk;
+	struct reset_control *core_reset;
+	struct reset_control *phy_reset;
+	struct reset_control *phy_por_reset;
+	long core_clk_rate;
+	long core_clk_svs_rate;
+	long core_clk_nominal_rate;
+	enum usb_noc_mode default_noc_mode;
+	struct resource *io_res;
+	void __iomem *regs;
+	void __iomem *phy_csr_regs;
+	void __iomem *usb_phy_ctrl_reg;
+#define ID		0
+#define B_SESS_VLD	1
+#define A_BUS_SUSPEND	14
+	unsigned long inputs;
+	struct work_struct sm_work;
+	bool sm_work_pending;
+	bool resume_pending;
+	atomic_t pm_suspended;
+	struct notifier_block pm_notify;
+	atomic_t in_lpm;
+	bool err_event_seen;
+	int async_int;
+	unsigned int cur_power;
+	struct workqueue_struct *otg_wq;
+	struct delayed_work id_status_work;
+	enum usb_chg_type chg_type;
+	unsigned int dcd_time;
+	unsigned long caps;
+	uint32_t bus_perf_client;
+	bool host_bus_suspend;
+	bool device_bus_suspend;
+	bool bus_clks_enabled;
+	/*
+	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
+	 * analog regulators while going to low power mode.
+	 * Currently only 28nm PHY has the support to allowing PHY
+	 * power collapse since it doesn't have leakage currents while
+	 * turning off the power rails.
+	 */
+#define ALLOW_PHY_POWER_COLLAPSE	BIT(0)
+	/*
+	 * Allow PHY RETENTION mode before turning off the digital
+	 * voltage regulator(VDDCX).
+	 */
+#define ALLOW_PHY_RETENTION		BIT(1)
+	/*
+	 * Allow putting the core in Low Power mode, when
+	 * USB bus is suspended but cable is connected.
+	 */
+#define ALLOW_LPM_ON_DEV_SUSPEND	BIT(2)
+	/*
+	 * Allowing PHY regulators LPM puts the HSUSB 3.3v and 1.8v
+	 * analog regulators into LPM while going to USB low power mode.
+	 */
+#define ALLOW_PHY_REGULATORS_LPM	BIT(3)
+	/*
+	 * Allow PHY RETENTION mode before turning off the digital
+	 * voltage regulator(VDDCX) during host mode.
+	 */
+#define ALLOW_HOST_PHY_RETENTION	BIT(4)
+	/*
+	 * Allow VDD minimization without putting PHY into retention
+	 * for fixing PHY current leakage issue when LDOs ar turned off.
+	 */
+#define ALLOW_VDD_MIN_WITH_RETENTION_DISABLED BIT(5)
+
+	/*
+	 * PHY can keep D+ pull-up during peripheral bus suspend and
+	 * D+/D- pull-down during host bus suspend without any
+	 * re-work. This is possible only when PHY DVDD is supplied
+	 * by a PMIC LDO (unlike VDDCX/VDDMX).
+	 */
+#define ALLOW_BUS_SUSPEND_WITHOUT_REWORK BIT(6)
+	unsigned long lpm_flags;
+#define PHY_PWR_COLLAPSED		BIT(0)
+#define PHY_RETENTIONED			BIT(1)
+#define XO_SHUTDOWN			BIT(2)
+#define CLOCKS_DOWN			BIT(3)
+#define PHY_REGULATORS_LPM	BIT(4)
+	int reset_counter;
+	unsigned int online;
+
+	dev_t ext_chg_dev;
+	struct pinctrl *phy_pinctrl;
+	bool is_ext_chg_dcp;
+	struct qpnp_vadc_chip	*vadc_dev;
+	int ext_id_irq;
+	bool phy_irq_pending;
+	enum usb_id_state id_state;
+	bool rm_pulldown;
+	struct extcon_dev       *extcon_vbus;
+	struct extcon_dev       *extcon_id;
+	struct notifier_block   vbus_nb;
+	struct notifier_block   id_nb;
+	struct regulator_desc	dpdm_rdesc;
+	struct regulator_dev	*dpdm_rdev;
+/* Maximum debug message length */
+#define DEBUG_MSG_LEN   128UL
+/* Maximum number of messages */
+#define DEBUG_MAX_MSG   256UL
+	unsigned int dbg_idx;
+	rwlock_t dbg_lock;
+
+	char (buf[DEBUG_MAX_MSG])[DEBUG_MSG_LEN];   /* buffer */
+	unsigned int vbus_state;
+	unsigned int usb_irq_count;
+	int pm_qos_latency;
+	struct pm_qos_request pm_qos_req_dma;
+	struct delayed_work perf_vote_work;
+};
+
+struct ci13xxx_platform_data {
+	u8 usb_core_id;
+	/*
+	 * value of 2^(log2_itc-1) will be used as the interrupt threshold
+	 * (ITC), when log2_itc is between 1 to 7.
+	 */
+	int log2_itc;
+	bool l1_supported;
+	bool enable_ahb2ahb_bypass;
+	bool enable_streaming;
+	bool enable_axi_prefetch;
+};
+
+#ifdef CONFIG_USB_BAM
+void msm_bam_set_usb_host_dev(struct device *dev);
+int msm_do_bam_disable_enable(enum usb_ctrl ctrl);
+#else
+static inline void msm_bam_set_usb_host_dev(struct device *dev) {}
+int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; }
+#endif
+#ifdef CONFIG_USB_CI13XXX_MSM
+void msm_hw_soft_reset(void);
+#else
+static inline void msm_hw_soft_reset(void)
+{
+}
+#endif
+
+#endif
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 974c379..2f90ddc 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -21,10 +21,14 @@
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG        (MSM_USB_BASE + 0x009C)
 #define USB_GENCONFIG_2      (MSM_USB_BASE + 0x00a0)
 #define ULPI_TX_PKT_EN_CLR_FIX	BIT(19)
 
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HS_APF_CTRL      (MSM_USB_BASE + 0x0380)
+
+#define APF_CTRL_EN		BIT(0)
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
 #define USB_PORTSC           (MSM_USB_BASE + 0x0184)
@@ -34,15 +38,32 @@
 #define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 
 #define GENCONFIG_2_SESS_VLD_CTRL_EN	BIT(7)
+#define GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN	BIT(12)
+#define GENCONFIG_2_DPSE_DMSE_HV_INTR_EN	BIT(15)
 #define USBCMD_SESS_VLD_CTRL		BIT(25)
 
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 
+#define AHB2AHB_BYPASS          BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK        BIT(31)
+#define AHB2AHB_BYPASS_CLEAR   (0 << 31)
+#define USB_L1_EP_CTRL       (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG        (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN        BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK	BIT(7)
+#define L1_CONFIG_PHY_LPM	BIT(10)
+#define L1_CONFIG_PLL		BIT(11)
+
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK        (3 << 30)
 #define PORTSC_PTS_ULPI        (2 << 30)
 #define PORTSC_PTS_SERIAL      (3 << 30)
+#define PORTSC_LS	       (3 << 10)
+#define PORTSC_LS_DM	       (1 << 10)
+#define PORTSC_CCS	       (1 << 0)
 
 #define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
 #define ULPI_RUN              (1 << 30)
@@ -52,6 +73,10 @@
 #define ULPI_DATA(n)          ((n) & 255)
 #define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
 
+#define GENCONFIG_BAM_DISABLE (1 << 13)
+#define GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE (1 << 4)
+#define GENCONFIG_ULPI_SERIAL_EN (1 << 5)
+
 /* synopsys 28nm phy registers */
 #define ULPI_PWR_CLK_MNG_REG	0x88
 #define OTG_COMP_DISABLE	BIT(0)
@@ -63,10 +88,16 @@
 #define ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
+#define PHY_CLAMP_DPDMSE_EN	(1 << 21) /* PHY mpm DP DM clamp enable */
+#define PHY_POR_BIT_MASK        BIT(0)
 #define PHY_POR_ASSERT		(1 << 0) /* USB2 28nm PHY POR ASSERT */
+#define PHY_POR_DEASSERT        (0 << 0) /* USB2 28nm PHY POR DEASSERT */
 
 /* OTG definitions */
 #define OTGSC_INTSTS_MASK	(0x7f << 16)
+#define OTGSC_IDPU		(1 << 5)
 #define OTGSC_ID		(1 << 8)
 #define OTGSC_BSV		(1 << 11)
 #define OTGSC_IDIS		(1 << 16)
@@ -74,4 +105,29 @@
 #define OTGSC_IDIE		(1 << 24)
 #define OTGSC_BSVIE		(1 << 27)
 
+/* USB PHY CSR registers and bit definitions */
+
+#define USB_PHY_CSR_PHY_CTRL_COMMON0 (MSM_USB_PHY_CSR_BASE + 0x078)
+#define SIDDQ BIT(2)
+
+#define USB_PHY_CSR_PHY_CTRL1 (MSM_USB_PHY_CSR_BASE + 0x08C)
+#define ID_HV_CLAMP_EN_N BIT(1)
+
+#define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094)
+#define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2)
+
+#define USB2_PHY_USB_PHY_IRQ_CMD (MSM_USB_PHY_CSR_BASE + 0x0D0)
+#define USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS (MSM_USB_PHY_CSR_BASE + 0x05C)
+
+#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR0 (MSM_USB_PHY_CSR_BASE + 0x0DC)
+#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR1 (MSM_USB_PHY_CSR_BASE + 0x0E0)
+
+#define USB2_PHY_USB_PHY_INTERRUPT_MASK1 (MSM_USB_PHY_CSR_BASE + 0x0D8)
+
+#define USB_PHY_IDDIG_1_0 BIT(7)
+
+#define USB_PHY_IDDIG_RISE_MASK BIT(0)
+#define USB_PHY_IDDIG_FALL_MASK BIT(1)
+#define USB_PHY_ID_MASK (USB_PHY_IDDIG_RISE_MASK | USB_PHY_IDDIG_FALL_MASK)
+
 #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 64aa52e..d999b3c 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -58,6 +58,7 @@
 	OTG_STATE_B_SRP_INIT,
 	OTG_STATE_B_PERIPHERAL,
 	OTG_STATE_B_SUSPEND,
+	OTG_STATE_B_CHARGER,
 
 	/* extra dual-role default-b states */
 	OTG_STATE_B_WAIT_ACON,
@@ -141,6 +142,10 @@
 
 	/* reset the PHY clocks */
 	int     (*reset)(struct usb_phy *x);
+
+	/* for notification of usb_phy_dbg_events */
+	void    (*dbg_event)(struct usb_phy *x,
+			char *event, int msg1, int msg2);
 	int	(*disable_chirp)(struct usb_phy *x, bool disable);
 };
 
diff --git a/include/linux/usb_bam.h b/include/linux/usb_bam.h
index 84d7549..e5d4c04 100644
--- a/include/linux/usb_bam.h
+++ b/include/linux/usb_bam.h
@@ -426,7 +426,7 @@
  *
  * @return true when producer granted, false when prodcuer is released.
  */
-bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx);
+bool usb_bam_get_prod_granted(enum usb_ctrl bam_type);
 
 /* Allocates memory for data fifo and descriptor fifos. */
 int usb_bam_alloc_fifos(enum usb_ctrl cur_bam, u8 idx);
@@ -519,7 +519,7 @@
 	return -ENODEV;
 }
 
-static inline bool usb_bam_get_prod_granted(enum usb_ctrl bam_type, u8 idx)
+static inline bool usb_bam_get_prod_granted(enum usb_ctrl bam_type)
 {
 	return false;
 }
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 797100e..9a8eb83 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -224,6 +224,7 @@
 static inline void inode_detach_wb(struct inode *inode)
 {
 	if (inode->i_wb) {
+		WARN_ON_ONCE(!(inode->i_state & I_CLEAR));
 		wb_put(inode->i_wb);
 		inode->i_wb = NULL;
 	}
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
new file mode 100644
index 0000000..2c8b651
--- /dev/null
+++ b/include/media/msm_cam_sensor.h
@@ -0,0 +1,294 @@
+#ifndef __LINUX_MSM_CAM_SENSOR_H
+#define __LINUX_MSM_CAM_SENSOR_H
+
+#include <uapi/media/msm_cam_sensor.h>
+#include <uapi/media/msm_camsensor_sdk.h>
+
+#include <linux/compat.h>
+
+#ifdef CONFIG_COMPAT
+
+struct msm_sensor_power_setting32 {
+	enum msm_sensor_power_seq_type_t seq_type;
+	uint16_t seq_val;
+	compat_uint_t config_val;
+	uint16_t delay;
+	compat_uptr_t data[10];
+};
+
+struct msm_sensor_power_setting_array32 {
+	struct msm_sensor_power_setting32 power_setting_a[MAX_POWER_CONFIG];
+	compat_uptr_t power_setting;
+	uint16_t size;
+	struct msm_sensor_power_setting32
+		power_down_setting_a[MAX_POWER_CONFIG];
+	compat_uptr_t power_down_setting;
+	uint16_t size_down;
+};
+
+struct msm_camera_sensor_slave_info32 {
+	char sensor_name[32];
+	char eeprom_name[32];
+	char actuator_name[32];
+	char ois_name[32];
+	char flash_name[32];
+	enum msm_sensor_camera_id_t camera_id;
+	uint16_t slave_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	struct msm_sensor_id_info_t sensor_id_info;
+	struct msm_sensor_power_setting_array32 power_setting_array;
+	uint8_t  is_init_params_valid;
+	struct msm_sensor_init_params sensor_init_params;
+	enum msm_sensor_output_format_t output_format;
+	uint8_t bypass_video_node_creation;
+};
+
+struct msm_camera_csid_lut_params32 {
+	uint8_t num_cid;
+	struct msm_camera_csid_vc_cfg vc_cfg_a[MAX_CID];
+	compat_uptr_t vc_cfg[MAX_CID];
+};
+
+struct msm_camera_csid_params32 {
+	uint8_t lane_cnt;
+	uint16_t lane_assign;
+	uint8_t phy_sel;
+	uint32_t csi_clk;
+	struct msm_camera_csid_lut_params32 lut_params;
+	uint8_t csi_3p_sel;
+};
+
+struct msm_camera_csi2_params32 {
+	struct msm_camera_csid_params32 csid_params;
+	struct msm_camera_csiphy_params csiphy_params;
+	uint8_t csi_clk_scale_enable;
+};
+
+struct csid_cfg_data32 {
+	enum csid_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		compat_uptr_t csid_params;
+		compat_uptr_t csid_testmode_params;
+	} cfg;
+};
+
+struct msm_ir_led_cfg_data_t32 {
+	enum msm_ir_led_cfg_type_t cfg_type;
+	int32_t pwm_duty_on_ns;
+	int32_t pwm_period_ns;
+};
+
+struct msm_ir_cut_cfg_data_t32 {
+	enum msm_ir_cut_cfg_type_t cfg_type;
+};
+
+struct msm_laser_led_cfg_data_t32 {
+	enum msm_laser_led_cfg_type_t cfg_type;
+	compat_uptr_t                 setting;
+	compat_uptr_t                 debug_reg;
+	uint32_t                      debug_reg_size;
+	uint16_t                      i2c_addr;
+	enum i2c_freq_mode_t          i2c_freq_mode;
+};
+
+struct eeprom_read_t32 {
+	compat_uptr_t dbuffer;
+	uint32_t num_bytes;
+};
+
+struct eeprom_write_t32 {
+	compat_uptr_t dbuffer;
+	uint32_t num_bytes;
+};
+
+struct msm_eeprom_info_t32 {
+	compat_uptr_t power_setting_array;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	compat_uptr_t mem_map_array;
+};
+
+struct msm_eeprom_cfg_data32 {
+	enum eeprom_cfg_type_t cfgtype;
+	uint8_t is_supported;
+	union {
+		char eeprom_name[MAX_SENSOR_NAME];
+		struct eeprom_get_t get_data;
+		struct eeprom_read_t32 read_data;
+		struct eeprom_write_t32 write_data;
+		struct msm_eeprom_info_t32 eeprom_info;
+	} cfg;
+};
+
+struct msm_camera_i2c_seq_reg_setting32 {
+	compat_uptr_t reg_setting;
+	uint16_t size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	uint16_t delay;
+};
+
+struct msm_camera_i2c_reg_setting32 {
+	compat_uptr_t reg_setting;
+	uint16_t size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t delay;
+};
+
+struct msm_camera_i2c_array_write_config32 {
+	struct msm_camera_i2c_reg_setting32 conf_array;
+	uint16_t slave_addr;
+};
+
+struct msm_actuator_tuning_params_t32 {
+	int16_t initial_code;
+	uint16_t pwd_step;
+	uint16_t region_size;
+	uint32_t total_steps;
+	compat_uptr_t region_params;
+};
+
+struct msm_actuator_params_t32 {
+	enum actuator_type act_type;
+	uint8_t reg_tbl_size;
+	uint16_t data_size;
+	uint16_t init_setting_size;
+	uint32_t i2c_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type i2c_addr_type;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	compat_uptr_t reg_tbl_params;
+	compat_uptr_t init_settings;
+	struct park_lens_data_t park_lens;
+};
+
+struct msm_actuator_set_info_t32 {
+	struct msm_actuator_params_t32 actuator_params;
+	struct msm_actuator_tuning_params_t32 af_tuning_params;
+};
+
+struct sensor_init_cfg_data32 {
+	enum msm_sensor_init_cfg_type_t cfgtype;
+	struct msm_sensor_info_t        probed_info;
+	char                            entity_name[MAX_SENSOR_NAME];
+	union {
+		compat_uptr_t setting;
+	} cfg;
+};
+
+struct msm_actuator_move_params_t32 {
+	int8_t dir;
+	int8_t sign_dir;
+	int16_t dest_step_pos;
+	int32_t num_steps;
+	uint16_t curr_lens_pos;
+	compat_uptr_t ringing_params;
+};
+
+struct msm_actuator_cfg_data32 {
+	int cfgtype;
+	uint8_t is_af_supported;
+	union {
+		struct msm_actuator_move_params_t32 move;
+		struct msm_actuator_set_info_t32 set_info;
+		struct msm_actuator_get_info_t get_info;
+		struct msm_actuator_set_position_t setpos;
+		enum af_camera_name cam_name;
+	} cfg;
+};
+
+struct csiphy_cfg_data32 {
+	enum csiphy_cfg_type_t cfgtype;
+	union {
+		compat_uptr_t csiphy_params;
+		compat_uptr_t csi_lane_params;
+	} cfg;
+};
+
+struct sensorb_cfg_data32 {
+	int cfgtype;
+	union {
+		struct msm_sensor_info_t      sensor_info;
+		struct msm_sensor_init_params sensor_init_params;
+		compat_uptr_t                 setting;
+		struct msm_sensor_i2c_sync_params sensor_i2c_sync_params;
+	} cfg;
+};
+
+struct msm_ois_params_t32 {
+	uint16_t data_size;
+	uint16_t setting_size;
+	uint32_t i2c_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type i2c_addr_type;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	compat_uptr_t settings;
+};
+
+struct msm_ois_set_info_t32 {
+	struct msm_ois_params_t32 ois_params;
+};
+
+struct msm_ois_cfg_data32 {
+	int cfgtype;
+	union {
+		struct msm_ois_set_info_t32 set_info;
+		compat_uptr_t settings;
+	} cfg;
+};
+
+struct msm_flash_init_info_t32 {
+	enum msm_flash_driver_type flash_driver_type;
+	uint32_t slave_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	compat_uptr_t power_setting_array;
+	compat_uptr_t settings;
+};
+
+struct msm_flash_cfg_data_t32 {
+	enum msm_flash_cfg_type_t cfg_type;
+	int32_t flash_current[MAX_LED_TRIGGERS];
+	int32_t flash_duration[MAX_LED_TRIGGERS];
+	union {
+		compat_uptr_t flash_init_info;
+		compat_uptr_t settings;
+	} cfg;
+};
+
+#define VIDIOC_MSM_ACTUATOR_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data32)
+
+#define VIDIOC_MSM_SENSOR_INIT_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct sensor_init_cfg_data32)
+
+#define VIDIOC_MSM_CSIPHY_IO_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csiphy_cfg_data32)
+
+#define VIDIOC_MSM_SENSOR_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data32)
+
+#define VIDIOC_MSM_EEPROM_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_eeprom_cfg_data32)
+
+#define VIDIOC_MSM_OIS_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_ois_cfg_data32)
+
+#define VIDIOC_MSM_CSID_IO_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csid_cfg_data32)
+
+#define VIDIOC_MSM_FLASH_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_flash_cfg_data_t32)
+
+#define VIDIOC_MSM_IR_LED_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_ir_led_cfg_data_t32)
+
+#define VIDIOC_MSM_IR_CUT_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t32)
+
+#define VIDIOC_MSM_LASER_LED_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t32)
+
+#endif
+
+#endif
diff --git a/include/media/msm_fd.h b/include/media/msm_fd.h
new file mode 100644
index 0000000..81eaee1
--- /dev/null
+++ b/include/media/msm_fd.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_FD__
+#define __MSM_FD__
+
+#include <uapi/media/msm_fd.h>
+#include <linux/compat.h>
+
+#ifdef CONFIG_COMPAT
+/*
+ * struct msm_fd_result32 - Compat structure contain detected faces result.
+ * @frame_id: Frame id of requested result.
+ * @face_cnt: Number of result faces, driver can modify this value (to smaller)
+ * @face_data: Pointer to array of face data structures.
+ *  Array size should not be smaller then face_cnt.
+ */
+struct msm_fd_result32 {
+	__u32 frame_id;
+	__u32 face_cnt;
+	compat_uptr_t face_data;
+};
+
+/* MSM FD compat private ioctl ID */
+#define VIDIOC_MSM_FD_GET_RESULT32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_fd_result32)
+#endif
+
+#endif /* __MSM_FD__ */
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 623b6f0..83904c9 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -72,6 +72,8 @@
 	unsigned long flags;
 	enum hal_buffer buffer_type;
 	struct dma_mapping_info mapping_info;
+	int mem_type;
+	void *smem_priv;
 };
 
 enum smem_cache_ops {
@@ -104,6 +106,8 @@
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
 int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
diff --git a/include/media/msmb_camera.h b/include/media/msmb_camera.h
new file mode 100644
index 0000000..eae2d01
--- /dev/null
+++ b/include/media/msmb_camera.h
@@ -0,0 +1,25 @@
+#ifndef __LINUX_MSMB_CAMERA_H
+#define __LINUX_MSMB_CAMERA_H
+
+#include <uapi/media/msmb_camera.h>
+
+#ifdef CONFIG_COMPAT
+#define MSM_CAM_V4L2_IOCTL_NOTIFY32 \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 30, struct v4l2_event32)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_META32 \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 31, struct v4l2_event32)
+
+#define MSM_CAM_V4L2_IOCTL_CMD_ACK32 \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 32, struct v4l2_event32)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR32 \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 33, struct v4l2_event32)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG32 \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 34, struct v4l2_event32)
+
+#endif
+
+#endif
+
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
new file mode 100644
index 0000000..b3e1a02
--- /dev/null
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MEDIA_MSMB_GENERIC_BUF_MGR_H__
+#define __MEDIA_MSMB_GENERIC_BUF_MGR_H__
+
+#include <uapi/media/msmb_generic_buf_mgr.h>
+#include <linux/compat.h>
+
+struct v4l2_subdev *msm_buf_mngr_get_subdev(void);
+
+#ifdef CONFIG_COMPAT
+
+struct msm_buf_mngr_info32_t {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t frame_id;
+	struct compat_timeval timestamp;
+	uint32_t index;
+	uint32_t reserved;
+	enum msm_camera_buf_mngr_buf_type type;
+	struct msm_camera_user_buf_cont_t user_buf;
+};
+
+#define VIDIOC_MSM_BUF_MNGR_GET_BUF32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 33, struct msm_buf_mngr_info32_t)
+
+#define VIDIOC_MSM_BUF_MNGR_PUT_BUF32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 34, struct msm_buf_mngr_info32_t)
+
+#define VIDIOC_MSM_BUF_MNGR_BUF_DONE32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info32_t)
+
+#define VIDIOC_MSM_BUF_MNGR_FLUSH32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 39, struct msm_buf_mngr_info32_t)
+
+#endif
+
+#endif
+
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
new file mode 100644
index 0000000..95679cb
--- /dev/null
+++ b/include/media/msmb_isp.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSMB_ISP__
+#define __MSMB_ISP__
+
+#include <uapi/media/msmb_isp.h>
+
+#ifdef CONFIG_COMPAT
+struct msm_isp_event_data32 {
+	struct compat_timeval timestamp;
+	struct compat_timeval mono_timestamp;
+	uint32_t frame_id;
+	union {
+		struct msm_isp_stats_event stats;
+		struct msm_isp_buf_event buf_done;
+		struct msm_isp_fetch_eng_event fetch_done;
+		struct msm_isp_error_info error_info;
+		struct msm_isp_output_info output_info;
+		struct msm_isp_sof_info sof_info;
+	} u;
+};
+#endif
+#ifdef CONFIG_MSM_AVTIMER
+struct avtimer_fptr_t {
+	int (*fptr_avtimer_open)(void);
+	int (*fptr_avtimer_enable)(int enable);
+	int (*fptr_avtimer_get_time)(uint64_t *avtimer_tick);
+};
+void msm_isp_set_avtimer_fptr(struct avtimer_fptr_t avtimer_func);
+#endif
+#endif
+
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
new file mode 100644
index 0000000..1e677f9
--- /dev/null
+++ b/include/media/msmb_pproc.h
@@ -0,0 +1,155 @@
+#ifndef __MSMB_PPROC_H
+#define __MSMB_PPROC_H
+
+#include <uapi/media/msmb_pproc.h>
+
+#include <linux/compat.h>
+
+#define MSM_OUTPUT_BUF_CNT 8
+
+#ifdef CONFIG_COMPAT
+struct msm_cpp_frame_info32_t {
+	int32_t frame_id;
+	struct compat_timeval timestamp;
+	uint32_t inst_id;
+	uint32_t identity;
+	uint32_t client_id;
+	enum msm_cpp_frame_type frame_type;
+	uint32_t num_strips;
+	uint32_t msg_len;
+	compat_uint_t cpp_cmd_msg;
+	int src_fd;
+	int dst_fd;
+	struct compat_timeval in_time, out_time;
+	compat_caddr_t cookie;
+	compat_int_t status;
+	int32_t duplicate_output;
+	uint32_t duplicate_identity;
+	uint32_t feature_mask;
+	uint8_t we_disable;
+	struct msm_cpp_buffer_info_t input_buffer_info;
+	struct msm_cpp_buffer_info_t output_buffer_info[MSM_OUTPUT_BUF_CNT];
+	struct msm_cpp_buffer_info_t duplicate_buffer_info;
+	struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2];
+	uint32_t reserved;
+	uint8_t partial_frame_indicator;
+	/* the followings are used only for partial_frame type
+	 * and is only used for offline frame processing and
+	 * only if payload big enough and need to be split into partial_frame
+	 * if first_payload, kernel acquires output buffer
+	 * first payload must have the last stripe
+	 * buffer addresses from 0 to last_stripe_index are updated.
+	 * kernel updates payload with msg_len and stripe_info
+	 * kernel sends top level, plane level, then only stripes
+	 * starting with first_stripe_index and
+	 * ends with last_stripe_index
+	 * kernel then sends trailing flag at frame done,
+	 * if last payload, kernel queues the output buffer to HAL
+	 */
+	uint8_t first_payload;
+	uint8_t last_payload;
+	uint32_t first_stripe_index;
+	uint32_t last_stripe_index;
+	uint32_t stripe_info_offset;
+	uint32_t stripe_info;
+	struct msm_cpp_batch_info_t  batch_info;
+};
+
+struct msm_cpp_clock_settings32_t {
+	compat_long_t clock_rate;
+	uint64_t avg;
+	uint64_t inst;
+};
+
+struct msm_cpp_stream_buff_info32_t {
+	uint32_t identity;
+	uint32_t num_buffs;
+	compat_caddr_t buffer_info;
+};
+
+struct msm_pproc_queue_buf_info32_t {
+	struct msm_buf_mngr_info32_t buff_mgr_info;
+	uint8_t is_buf_dirty;
+};
+
+struct cpp_hw_info_32_t {
+	uint32_t cpp_hw_version;
+	uint32_t cpp_hw_caps;
+	compat_long_t freq_tbl[MAX_FREQ_TBL];
+	uint32_t freq_tbl_count;
+};
+
+
+#define VIDIOC_MSM_CPP_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_GET_INST_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_LOAD_FIRMWARE32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_GET_HW_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_FLUSH_QUEUE32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_CFG32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_TRANSACTION_SETUP32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_GET_INST_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_QUEUE_BUF32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_SET_CLOCK32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_IOMMU_ATTACH32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_IOMMU_DETACH32 \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl32_t)
+
+#define VIDIOC_MSM_CPP_DELETE_STREAM_BUFF32\
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 20, struct msm_camera_v4l2_ioctl32_t)
+
+struct msm_camera_v4l2_ioctl32_t {
+	uint32_t id;
+	uint32_t len;
+	int32_t trans_code;
+	compat_caddr_t ioctl_ptr;
+};
+#endif
+
+#endif
+
diff --git a/include/net/arp.h b/include/net/arp.h
index 5e0f891..1b3f869 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -19,6 +19,9 @@
 
 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
 {
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		key = INADDR_ANY;
+
 	return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
 }
 
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5e79f1..520c4c3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -61,6 +61,9 @@
 /* Indicate backport support for per chain rssi scan */
 #define CFG80211_SCAN_PER_CHAIN_RSSI_SUPPORT 1
 
+/* Indicate backport support for external authentication*/
+#define CFG80211_EXTERNAL_AUTH_SUPPORT 1
+
 /**
  * DOC: Introduction
  *
@@ -1878,11 +1881,16 @@
  * @ASSOC_REQ_DISABLE_HT:  Disable HT (802.11n)
  * @ASSOC_REQ_DISABLE_VHT:  Disable VHT
  * @ASSOC_REQ_USE_RRM: Declare RRM capability in this association
+ * @CONNECT_REQ_EXTERNAL_AUTH_SUPPORT: User space indicates external
+ *	authentication capability. Drivers can offload authentication to
+ *	userspace if this flag is set. Only applicable for cfg80211_connect()
+ *	request (connect callback).
  */
 enum cfg80211_assoc_req_flags {
-	ASSOC_REQ_DISABLE_HT		= BIT(0),
-	ASSOC_REQ_DISABLE_VHT		= BIT(1),
-	ASSOC_REQ_USE_RRM		= BIT(2),
+	ASSOC_REQ_DISABLE_HT			= BIT(0),
+	ASSOC_REQ_DISABLE_VHT			= BIT(1),
+	ASSOC_REQ_USE_RRM			= BIT(2),
+	CONNECT_REQ_EXTERNAL_AUTH_SUPPORT	= BIT(3),
 };
 
 /**
@@ -2554,6 +2562,33 @@
 };
 
 /**
+ * struct cfg80211_external_auth_params - Trigger External authentication.
+ *
+ * Commonly used across the external auth request and event interfaces.
+ *
+ * @action: action type / trigger for external authentication. Only significant
+ *	for the authentication request event interface (driver to user space).
+ * @bssid: BSSID of the peer with which the authentication has
+ *	to happen. Used by both the authentication request event and
+ *	authentication response command interface.
+ * @ssid: SSID of the AP.  Used by both the authentication request event and
+ *	authentication response command interface.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Used by the
+ *	authentication request event interface.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ *	use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space cannot give you
+ *	the real status code for failures. Used only for the authentication
+ *	response command interface (user space to driver).
+ */
+struct cfg80211_external_auth_params {
+	enum nl80211_external_auth_action action;
+	u8 bssid[ETH_ALEN] __aligned(2);
+	struct cfg80211_ssid ssid;
+	unsigned int key_mgmt_suite;
+	u16 status;
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2862,6 +2897,9 @@
  *	All other parameters must be ignored.
  *
  * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
+ * @external_auth: indicates result of offloaded authentication processing from
+ *     user space
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3146,6 +3184,8 @@
 	int	(*set_multicast_to_unicast)(struct wiphy *wiphy,
 					    struct net_device *dev,
 					    const bool enabled);
+	int     (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_external_auth_params *params);
 };
 
 /*
@@ -3937,6 +3977,9 @@
  * @conn: (private) cfg80211 software SME connection state machine data
  * @connect_keys: (private) keys to set after connection is established
  * @conn_bss_type: connecting/connected BSS type
+ * @conn_owner_nlportid: (private) connection owner socket port ID
+ * @disconnect_wk: (private) auto-disconnect work
+ * @disconnect_bssid: (private) the BSSID to use for auto-disconnect
  * @ibss_fixed: (private) IBSS is using fixed BSSID
  * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
  * @event_list: (private) list for internal event processing
@@ -3968,6 +4011,10 @@
 	struct cfg80211_conn *conn;
 	struct cfg80211_cached_keys *connect_keys;
 	enum ieee80211_bss_type conn_bss_type;
+	u32 conn_owner_nlportid;
+
+	struct work_struct disconnect_wk;
+	u8 disconnect_bssid[ETH_ALEN];
 
 	struct list_head event_list;
 	spinlock_t event_lock;
@@ -6078,6 +6125,17 @@
  */
 bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb);
 
+/**
+ * cfg80211_external_auth_request - userspace request for authentication
+ * @netdev: network device
+ * @params: External authentication parameters
+ * @gfp: allocation flags
+ * Returns: 0 on success, < 0 on error
+ */
+int cfg80211_external_auth_request(struct net_device *netdev,
+				   struct cfg80211_external_auth_params *params,
+				   gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/cnss.h b/include/net/cnss.h
new file mode 100644
index 0000000..368d01e
--- /dev/null
+++ b/include/net/cnss.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _NET_CNSS_H_
+#define _NET_CNSS_H_
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_CNSS
+#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+#define CNSS_MAX_FILE_NAME	20
+#define PINCTRL_SLEEP  0
+#define PINCTRL_ACTIVE 1
+
+enum cnss_bus_width_type {
+	CNSS_BUS_WIDTH_NONE,
+	CNSS_BUS_WIDTH_LOW,
+	CNSS_BUS_WIDTH_MEDIUM,
+	CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_cc_src {
+	CNSS_SOURCE_CORE,
+	CNSS_SOURCE_11D,
+	CNSS_SOURCE_USER
+};
+
+/* FW image files */
+struct cnss_fw_files {
+	char image_file[CNSS_MAX_FILE_NAME];
+	char board_data[CNSS_MAX_FILE_NAME];
+	char otp_data[CNSS_MAX_FILE_NAME];
+	char utf_file[CNSS_MAX_FILE_NAME];
+	char utf_board_data[CNSS_MAX_FILE_NAME];
+	char epping_file[CNSS_MAX_FILE_NAME];
+	char evicted_data[CNSS_MAX_FILE_NAME];
+};
+
+struct cnss_wlan_runtime_ops {
+	int (*runtime_suspend)(struct pci_dev *pdev);
+	int (*runtime_resume)(struct pci_dev *pdev);
+};
+
+struct cnss_wlan_driver {
+	char *name;
+	int  (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*remove)(struct pci_dev *pdev);
+	int  (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*shutdown)(struct pci_dev *pdev);
+	void (*crash_shutdown)(struct pci_dev *pdev);
+	int  (*suspend)(struct pci_dev *pdev, pm_message_t state);
+	int  (*resume)(struct pci_dev *pdev);
+	void (*modem_status)(struct pci_dev *, int state);
+	void (*update_status)(struct pci_dev *pdev, uint32_t status);
+	struct cnss_wlan_runtime_ops *runtime_ops;
+	const struct pci_device_id *id_table;
+};
+
+/*
+ * codeseg_total_bytes: Total bytes across all the codesegment blocks
+ * num_codesegs: No of Pages used
+ * codeseg_size: Size of each segment. Should be power of 2 and multiple of 4K
+ * codeseg_size_log2: log2(codeseg_size)
+ * codeseg_busaddr: Physical address of the DMAble memory;4K aligned
+ */
+
+#define CODESWAP_MAX_CODESEGS 16
+struct codeswap_codeseg_info {
+	u32   codeseg_total_bytes;
+	u32   num_codesegs;
+	u32   codeseg_size;
+	u32   codeseg_size_log2;
+	void *codeseg_busaddr[CODESWAP_MAX_CODESEGS];
+};
+
+struct image_desc_info {
+	dma_addr_t fw_addr;
+	u32 fw_size;
+	dma_addr_t bdata_addr;
+	u32 bdata_size;
+};
+
+/* platform capabilities */
+enum cnss_platform_cap_flag {
+	CNSS_HAS_EXTERNAL_SWREG = 0x01,
+	CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+	u32 cap_flag;
+};
+
+/* WLAN driver status */
+enum cnss_driver_status {
+	CNSS_UNINITIALIZED,
+	CNSS_INITIALIZED,
+	CNSS_LOAD_UNLOAD
+};
+
+enum cnss_runtime_request {
+	CNSS_PM_RUNTIME_GET,
+	CNSS_PM_RUNTIME_PUT,
+	CNSS_PM_RUNTIME_MARK_LAST_BUSY,
+	CNSS_PM_RUNTIME_RESUME,
+	CNSS_PM_RUNTIME_PUT_NOIDLE,
+	CNSS_PM_REQUEST_RESUME,
+	CNSS_PM_RUNTIME_PUT_AUTO,
+	CNSS_PM_GET_NORESUME,
+};
+
+extern int cnss_get_fw_image(struct image_desc_info *image_desc_info);
+extern void cnss_runtime_init(struct device *dev, int auto_delay);
+extern void cnss_runtime_exit(struct device *dev);
+extern void cnss_wlan_pci_link_down(void);
+extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable);
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files);
+extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+					u32 target_type, u32 target_version);
+extern void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+					u32 size, u32 tufello_dual_fw);
+
+extern int cnss_request_bus_bandwidth(int bandwidth);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+extern int cnss_get_sha_hash(const u8 *data, u32 data_len,
+					u8 *hash_idx, u8 *out);
+extern void *cnss_get_fw_ptr(void);
+#endif
+
+extern int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg);
+extern int cnss_get_bmi_setup(void);
+
+#ifdef CONFIG_PCI_MSM
+extern int cnss_wlan_pm_control(bool vote);
+#endif
+extern void cnss_lock_pm_sem(void);
+extern void cnss_release_pm_sem(void);
+
+extern void cnss_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_request_pm_qos(u32 qos_val);
+extern void cnss_remove_pm_qos(void);
+
+extern void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_pci_request_pm_qos(u32 qos_val);
+extern void cnss_pci_remove_pm_qos(void);
+
+extern void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_sdio_request_pm_qos(u32 qos_val);
+extern void cnss_sdio_remove_pm_qos(void);
+
+extern int cnss_get_platform_cap(struct cnss_platform_cap *cap);
+extern void cnss_set_driver_status(enum cnss_driver_status driver_status);
+
+#ifndef CONFIG_WCNSS_MEM_PRE_ALLOC
+static inline int wcnss_pre_alloc_reset(void) { return 0; }
+#endif
+
+extern int msm_pcie_enumerate(u32 rc_idx);
+extern int cnss_auto_suspend(void);
+extern int cnss_auto_resume(void);
+extern int cnss_prevent_auto_suspend(const char *caller_func);
+extern int cnss_allow_auto_suspend(const char *caller_func);
+extern int cnss_is_auto_suspend_allowed(const char *caller_func);
+
+extern int cnss_pm_runtime_request(struct device *dev, enum
+		cnss_runtime_request request);
+extern void cnss_set_cc_source(enum cnss_cc_src cc_source);
+extern enum cnss_cc_src cnss_get_cc_source(void);
+#endif
+
+extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name);
+extern void cnss_pm_wake_lock(struct wakeup_source *ws);
+
+extern void cnss_device_crashed(void);
+extern void cnss_device_self_recovery(void);
+extern void *cnss_get_virt_ramdump_mem(unsigned long *size);
+
+extern void cnss_schedule_recovery_work(void);
+extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
+extern u8 *cnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
+
+enum {
+	CNSS_RESET_SOC = 0,
+	CNSS_RESET_SUBSYS_COUPLED,
+	CNSS_RESET_LEVEL_MAX
+};
+extern int cnss_get_restart_level(void);
+
+struct cnss_sdio_wlan_driver {
+	const char *name;
+	const struct sdio_device_id *id_table;
+	int (*probe)(struct sdio_func *, const struct sdio_device_id *);
+	void (*remove)(struct sdio_func *);
+	int (*reinit)(struct sdio_func *, const struct sdio_device_id *);
+	void (*shutdown)(struct sdio_func *);
+	void (*crash_shutdown)(struct sdio_func *);
+	int (*suspend)(struct device *);
+	int (*resume)(struct device *);
+};
+
+extern int cnss_sdio_wlan_register_driver(
+	struct cnss_sdio_wlan_driver *driver);
+extern void cnss_sdio_wlan_unregister_driver(
+	struct cnss_sdio_wlan_driver *driver);
+
+typedef void (*oob_irq_handler_t)(void *dev_para);
+extern int cnss_wlan_query_oob_status(void);
+extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler,
+	    void *pm_oob);
+extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob);
+
+
+extern void cnss_dump_stack(struct task_struct *task);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern void cnss_init_work(struct work_struct *work, work_func_t func);
+extern void cnss_flush_delayed_work(void *dwork);
+extern void cnss_flush_work(void *work);
+extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
+extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
+extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
+extern void cnss_get_monotonic_boottime(struct timespec *ts);
+extern void cnss_get_boottime(struct timespec *ts);
+extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t
+				   func);
+extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
+extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
+extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
+extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
+					u16 buf_len);
+extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
+extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern int cnss_common_request_bus_bandwidth(struct device *dev, int
+					     bandwidth);
+extern void cnss_common_device_crashed(struct device *dev);
+extern void cnss_common_device_self_recovery(struct device *dev);
+extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long
+					      *size);
+extern void cnss_common_schedule_recovery_work(struct device *dev);
+extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in,
+					    uint32_t len);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern int cnss_sdio_configure_spdt(bool state);
+
+extern int cnss_common_register_tsf_captured_handler(struct device *dev,
+						     irq_handler_t handler,
+						     void *ctx);
+extern int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						       void *ctx);
+#endif /* _NET_CNSS_H_ */
diff --git a/include/net/cnss_logger.h b/include/net/cnss_logger.h
new file mode 100644
index 0000000..f06ec9b
--- /dev/null
+++ b/include/net/cnss_logger.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _NET_CNSS_LOGGER_H_
+#define _NET_CNSS_LOGGER_H_
+
+struct sk_buff;
+struct wiphy;
+
+#ifdef CONFIG_CNSS_LOGGER
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb));
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb));
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name);
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy);
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag);
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag);
+#else
+static inline int cnss_logger_event_register(int radio, int event,
+					     int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_event_unregister(int radio, int event,
+					       int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_device_register(struct wiphy *wiphy,
+					      const char *name)
+{
+	return 0;
+}
+static inline int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_ucast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_bcast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+#endif /* CONFIG_CNSS_LOGGER */
+#endif /* _NET_CNSS_H_ */
+
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 615ce0a..e64210c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -290,6 +290,7 @@
 			   int flags);
 int ip6_flowlabel_init(void);
 void ip6_flowlabel_cleanup(void);
+bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np);
 
 static inline void fl6_sock_release(struct ip6_flowlabel *fl)
 {
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 0940598..23102da 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -213,6 +213,11 @@
 	return net1 == net2;
 }
 
+static inline int check_net(const struct net *net)
+{
+	return atomic_read(&net->count) != 0;
+}
+
 void net_drop_ns(void *);
 
 #else
@@ -237,6 +242,11 @@
 	return 1;
 }
 
+static inline int check_net(const struct net *net)
+{
+	return 1;
+}
+
 #define net_drop_ns NULL
 #endif
 
diff --git a/include/net/sock.h b/include/net/sock.h
index badd144..31309b3 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2286,4 +2286,15 @@
 extern __u32 sysctl_wmem_default;
 extern __u32 sysctl_rmem_default;
 
+/* SOCKEV Notifier Events */
+#define SOCKEV_SOCKET   0x00
+#define SOCKEV_BIND     0x01
+#define SOCKEV_LISTEN   0x02
+#define SOCKEV_ACCEPT   0x03
+#define SOCKEV_CONNECT  0x04
+#define SOCKEV_SHUTDOWN 0x05
+
+int sockev_register_notify(struct notifier_block *nb);
+int sockev_unregister_notify(struct notifier_block *nb);
+
 #endif	/* _SOCK_H */
diff --git a/include/soc/qcom/bam_dmux.h b/include/soc/qcom/bam_dmux.h
new file mode 100644
index 0000000..142b8e1
--- /dev/null
+++ b/include/soc/qcom/bam_dmux.h
@@ -0,0 +1,138 @@
+/* Copyright (c) 2011-2012, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifndef _BAM_DMUX_H
+#define _BAM_DMUX_H
+
+#define BAM_DMUX_CH_NAME_MAX_LEN	20
+
+enum {
+	BAM_DMUX_DATA_RMNET_0,
+	BAM_DMUX_DATA_RMNET_1,
+	BAM_DMUX_DATA_RMNET_2,
+	BAM_DMUX_DATA_RMNET_3,
+	BAM_DMUX_DATA_RMNET_4,
+	BAM_DMUX_DATA_RMNET_5,
+	BAM_DMUX_DATA_RMNET_6,
+	BAM_DMUX_DATA_RMNET_7,
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_RESERVED_0, /* 9..11 are reserved*/
+	BAM_DMUX_RESERVED_1,
+	BAM_DMUX_RESERVED_2,
+	BAM_DMUX_DATA_REV_RMNET_0,
+	BAM_DMUX_DATA_REV_RMNET_1,
+	BAM_DMUX_DATA_REV_RMNET_2,
+	BAM_DMUX_DATA_REV_RMNET_3,
+	BAM_DMUX_DATA_REV_RMNET_4,
+	BAM_DMUX_DATA_REV_RMNET_5,
+	BAM_DMUX_DATA_REV_RMNET_6,
+	BAM_DMUX_DATA_REV_RMNET_7,
+	BAM_DMUX_DATA_REV_RMNET_8,
+	BAM_DMUX_USB_DPL,
+	BAM_DMUX_NUM_CHANNELS
+};
+
+/* event type enum */
+enum {
+	BAM_DMUX_RECEIVE, /* data is struct sk_buff */
+	BAM_DMUX_WRITE_DONE, /* data is struct sk_buff */
+	BAM_DMUX_UL_CONNECTED, /* data is null */
+	BAM_DMUX_UL_DISCONNECTED, /*data is null */
+	BAM_DMUX_TRANSMIT_SIZE, /* data is maximum negotiated transmit MTU */
+};
+
+/*
+ * Open a bam_dmux logical channel
+ *     id - the logical channel to open
+ *     priv - private data pointer to be passed to the notify callback
+ *     notify - event callback function
+ *          priv - private data pointer passed to msm_bam_dmux_open()
+ *          event_type - type of event
+ *          data - data relevant to event.  May not be valid. See event_type
+ *                    enum for valid cases.
+ */
+#ifdef CONFIG_MSM_BAM_DMUX
+int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+
+int msm_bam_dmux_close(uint32_t id);
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
+
+int msm_bam_dmux_kickoff_ul_wakeup(void);
+
+int msm_bam_dmux_ul_power_vote(void);
+
+int msm_bam_dmux_ul_power_unvote(void);
+
+int msm_bam_dmux_is_ch_full(uint32_t id);
+
+int msm_bam_dmux_is_ch_low(uint32_t id);
+
+int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+#else
+static inline int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_close(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_vote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_unvote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+#endif
+#endif /* _BAM_DMUX_H */
diff --git a/include/soc/qcom/camera2.h b/include/soc/qcom/camera2.h
new file mode 100644
index 0000000..c529aff
--- /dev/null
+++ b/include/soc/qcom/camera2.h
@@ -0,0 +1,227 @@
+/* Copyright (c) 2011-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __CAMERA2_H__
+#define __CAMERA2_H__
+
+#include <media/msm_cam_sensor.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+
+#define MAX_SPECIAL_SUPPORT_SIZE 10
+
+enum msm_camera_device_type_t {
+	MSM_CAMERA_I2C_DEVICE,
+	MSM_CAMERA_PLATFORM_DEVICE,
+	MSM_CAMERA_SPI_DEVICE,
+};
+
+enum msm_bus_perf_setting {
+	S_INIT,
+	S_PREVIEW,
+	S_VIDEO,
+	S_CAPTURE,
+	S_ZSL,
+	S_STEREO_VIDEO,
+	S_STEREO_CAPTURE,
+	S_DEFAULT,
+	S_LIVESHOT,
+	S_DUAL,
+	S_EXIT
+};
+
+struct msm_camera_slave_info {
+	uint16_t sensor_slave_addr;
+	uint16_t sensor_id_reg_addr;
+	uint16_t sensor_id;
+	uint16_t sensor_id_mask;
+};
+
+struct msm_cam_clk_info {
+	const char *clk_name;
+	long clk_rate;
+	uint32_t delay;
+};
+
+struct msm_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *gpio_state_active;
+	struct pinctrl_state *gpio_state_suspend;
+	bool use_pinctrl;
+};
+
+struct msm_cam_clk_setting {
+	struct msm_cam_clk_info *clk_info;
+	uint16_t num_clk_info;
+	uint8_t enable;
+};
+
+struct v4l2_subdev_info {
+	uint32_t code;
+	enum v4l2_colorspace colorspace;
+	uint16_t fmt;
+	uint16_t order;
+};
+
+struct msm_camera_gpio_num_info {
+	uint16_t gpio_num[SENSOR_GPIO_MAX];
+	uint8_t valid[SENSOR_GPIO_MAX];
+};
+
+struct msm_camera_gpio_conf {
+	void *cam_gpiomux_conf_tbl;
+	uint8_t cam_gpiomux_conf_tbl_size;
+	struct gpio *cam_gpio_common_tbl;
+	uint8_t cam_gpio_common_tbl_size;
+	struct gpio *cam_gpio_req_tbl;
+	uint8_t cam_gpio_req_tbl_size;
+	uint32_t gpio_no_mux;
+	uint32_t *camera_off_table;
+	uint8_t camera_off_table_size;
+	uint32_t *camera_on_table;
+	uint8_t camera_on_table_size;
+	struct msm_camera_gpio_num_info *gpio_num_info;
+};
+
+struct msm_camera_power_ctrl_t {
+	struct device *dev;
+	struct msm_sensor_power_setting *power_setting;
+	uint16_t power_setting_size;
+	struct msm_sensor_power_setting *power_down_setting;
+	uint16_t power_down_setting_size;
+	struct msm_camera_gpio_conf *gpio_conf;
+	struct camera_vreg_t *cam_vreg;
+	int num_vreg;
+	struct msm_camera_i2c_conf *i2c_conf;
+	struct clk **clk_ptr;
+	struct msm_cam_clk_info *clk_info;
+	struct msm_pinctrl_info pinctrl_info;
+	uint8_t cam_pinctrl_status;
+	size_t clk_info_size;
+};
+
+enum msm_camera_actuator_name {
+	MSM_ACTUATOR_MAIN_CAM_0,
+	MSM_ACTUATOR_MAIN_CAM_1,
+	MSM_ACTUATOR_MAIN_CAM_2,
+	MSM_ACTUATOR_MAIN_CAM_3,
+	MSM_ACTUATOR_MAIN_CAM_4,
+	MSM_ACTUATOR_MAIN_CAM_5,
+	MSM_ACTUATOR_WEB_CAM_0,
+	MSM_ACTUATOR_WEB_CAM_1,
+	MSM_ACTUATOR_WEB_CAM_2,
+};
+
+struct msm_actuator_info {
+	struct i2c_board_info const *board_info;
+	enum msm_camera_actuator_name cam_name;
+	int bus_id;
+	int vcm_pwd;
+	int vcm_enable;
+};
+enum msm_camera_i2c_mux_mode {
+	MODE_R,
+	MODE_L,
+	MODE_DUAL
+};
+
+struct msm_camera_i2c_conf {
+	uint8_t use_i2c_mux;
+	struct platform_device *mux_dev;
+	enum msm_camera_i2c_mux_mode i2c_mux_mode;
+};
+
+struct msm_camera_sensor_board_info {
+	const char *sensor_name;
+	const char *eeprom_name;
+	const char *actuator_name;
+	const char *ois_name;
+	const char *flash_name;
+	const char *special_support_sensors[MAX_SPECIAL_SUPPORT_SIZE];
+	int32_t special_support_size;
+	struct msm_camera_slave_info *slave_info;
+	struct msm_camera_csi_lane_params *csi_lane_params;
+	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
+	struct msm_actuator_info *actuator_info;
+	struct msm_sensor_info_t *sensor_info;
+	const char *misc_regulator;
+	struct msm_camera_power_ctrl_t power_info;
+	struct msm_camera_sensor_slave_info *cam_slave_info;
+};
+
+enum msm_camera_i2c_cmd_type {
+	MSM_CAMERA_I2C_CMD_WRITE,
+	MSM_CAMERA_I2C_CMD_POLL,
+};
+
+struct msm_camera_i2c_reg_conf {
+	uint16_t reg_addr;
+	uint16_t reg_data;
+	enum msm_camera_i2c_data_type dt;
+	enum msm_camera_i2c_cmd_type cmd_type;
+	int16_t mask;
+};
+
+struct msm_camera_i2c_conf_array {
+	struct msm_camera_i2c_reg_conf *conf;
+	uint16_t size;
+	uint16_t delay;
+	enum msm_camera_i2c_data_type data_type;
+};
+
+struct eeprom_map_t {
+	uint32_t valid_size;
+	uint32_t addr;
+	uint32_t addr_t;
+	uint32_t data;
+	uint32_t data_t;
+	uint32_t delay;
+};
+
+struct eeprom_slave_add_t {
+	uint32_t addr;
+};
+
+struct msm_eeprom_memory_map_t {
+	struct eeprom_map_t page;
+	struct eeprom_map_t pageen;
+	struct eeprom_map_t poll;
+	struct eeprom_map_t mem;
+	struct eeprom_slave_add_t saddr;
+};
+
+struct msm_eeprom_memory_block_t {
+	struct msm_eeprom_memory_map_t *map;
+	uint32_t num_map;	/* number of map blocks */
+	uint8_t *mapdata;
+	uint32_t num_data;	/* size of total mapdata */
+};
+
+struct msm_eeprom_cmm_t {
+	uint32_t cmm_support;
+	uint32_t cmm_compression;
+	uint32_t cmm_offset;
+	uint32_t cmm_size;
+};
+
+struct msm_eeprom_board_info {
+	const char *eeprom_name;
+	uint16_t i2c_slaveaddr;
+	struct msm_camera_power_ctrl_t power_info;
+	struct msm_eeprom_cmm_t cmm_data;
+	enum i2c_freq_mode_t i2c_freq_mode;
+};
+
+#endif
diff --git a/include/soc/qcom/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h
index f8130f1..20f8a2f 100644
--- a/include/soc/qcom/clock-alpha-pll.h
+++ b/include/soc/qcom/clock-alpha-pll.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -27,6 +27,7 @@
 	u32 alpha_en_mask;	/* alpha_en bit */
 	u32 output_mask;	/* pllout_* bits */
 	u32 post_div_mask;
+	u32 cal_l_val_mask;
 
 	u32 test_ctl_lo_mask;
 	u32 test_ctl_hi_mask;
@@ -61,6 +62,7 @@
 	u32 config_ctl_val;	/* config register init value */
 	u32 test_ctl_lo_val;	/* test control settings */
 	u32 test_ctl_hi_val;
+	u32 cal_l_val;		/* Calibration L value */
 
 	struct alpha_pll_vco_tbl *vco_tbl;
 	u32 num_vco;
diff --git a/include/soc/qcom/cx_ipeak.h b/include/soc/qcom/cx_ipeak.h
new file mode 100644
index 0000000..01fdcb4
--- /dev/null
+++ b/include/soc/qcom/cx_ipeak.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SOC_COM_CX_IPEAK_H
+#define __SOC_COM_CX_IPEAK_H
+
+struct device_node;
+struct cx_ipeak_client;
+
+#ifndef CONFIG_QCOM_CX_IPEAK
+
+static inline struct cx_ipeak_client *cx_ipeak_register(
+		struct device_node *dev_node,
+		const char *client_name)
+{
+	return NULL;
+}
+
+static inline void cx_ipeak_unregister(struct cx_ipeak_client *client)
+{
+}
+
+static inline int cx_ipeak_update(struct cx_ipeak_client *ipeak_client,
+			bool vote)
+{
+	return 0;
+}
+#else
+
+struct cx_ipeak_client *cx_ipeak_register(struct device_node *dev_node,
+		const char *client_name);
+void cx_ipeak_unregister(struct cx_ipeak_client *client);
+int cx_ipeak_update(struct cx_ipeak_client *ipeak_client, bool vote);
+
+#endif
+
+#endif /*__SOC_COM_CX_IPEAK_H*/
diff --git a/include/soc/qcom/lpm_levels.h b/include/soc/qcom/lpm_levels.h
new file mode 100644
index 0000000..3665caf
--- /dev/null
+++ b/include/soc/qcom/lpm_levels.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __SOC_QCOM_LPM_LEVEL_H__
+#define __SOC_QCOM_LPM_LEVEL_H__
+
+struct system_pm_ops {
+	int (*enter)(struct cpumask *mask);
+	void (*exit)(void);
+	int (*update_wakeup)(bool);
+	bool (*sleep_allowed)(void);
+};
+
+uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops);
+#endif
diff --git a/include/soc/qcom/msm_tz_smmu.h b/include/soc/qcom/msm_tz_smmu.h
index 43a3069..1ae1dd9 100644
--- a/include/soc/qcom/msm_tz_smmu.h
+++ b/include/soc/qcom/msm_tz_smmu.h
@@ -102,6 +102,29 @@
 {
 	return -EINVAL;
 }
+
+static inline size_t msm_secure_smmu_unmap(struct iommu_domain *domain,
+					   unsigned long iova,
+					   size_t size)
+{
+	return -EINVAL;
+}
+
+static inline size_t msm_secure_smmu_map_sg(struct iommu_domain *domain,
+					    unsigned long iova,
+					    struct scatterlist *sg,
+					    unsigned int nents, int prot)
+{
+	return -EINVAL;
+}
+
+static inline int msm_secure_smmu_map(struct iommu_domain *domain,
+				      unsigned long iova,
+				      phys_addr_t paddr, size_t size, int prot)
+{
+	return -EINVAL;
+}
+
 #endif /* CONFIG_MSM_TZ_SMMU */
 
 #endif /* __MSM_TZ_SMMU_H__ */
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index 505e82b..a872c9a 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -108,10 +108,16 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda670")
 #define early_machine_is_msm8953()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953")
+#define early_machine_is_msm8937()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8937")
 #define early_machine_is_sdm450()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm450")
 #define early_machine_is_sdm632()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm632")
+#define early_machine_is_sdm439()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm439")
+#define early_machine_is_sdm429()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429")
 #else
 #define of_board_is_sim()		0
 #define of_board_is_rumi()		0
@@ -155,8 +161,11 @@
 #define early_machine_is_qcs605()	0
 #define early_machine_is_sda670()	0
 #define early_machine_is_msm8953()	0
+#define early_machine_is_msm8937()	0
 #define early_machine_is_sdm450()	0
 #define early_machine_is_sdm632()	0
+#define early_machine_is_sdm439()	0
+#define early_machine_is_sdm429()	0
 #endif
 
 #define PLATFORM_SUBTYPE_MDM	1
@@ -225,6 +234,9 @@
 	MSM_CPU_SDM450,
 	MSM_CPU_SDM632,
 	MSM_CPU_SDA632,
+	MSM_CPU_8937,
+	MSM_CPU_SDM439,
+	MSM_CPU_SDM429,
 };
 
 struct msm_soc_info {
diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h
deleted file mode 100644
index 028c729..0000000
--- a/include/soc/qcom/system_pm.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __SOC_QCOM_SYS_PM_H__
-#define __SOC_QCOM_SYS_PM_H__
-
-#ifdef CONFIG_QTI_SYSTEM_PM
-int system_sleep_enter(void);
-
-void system_sleep_exit(void);
-
-bool system_sleep_allowed(void);
-
-int system_sleep_update_wakeup(void);
-#else
-static inline int system_sleep_enter(void)
-{ return -ENODEV; }
-
-static inline void system_sleep_exit(void)
-{ }
-
-static inline bool system_sleep_allowed(void)
-{ return false; }
-
-static inline int system_sleep_update_wakeup(void)
-{ return -ENODEV; }
-
-#endif /* CONFIG_QTI_SYSTEM_PM */
-
-#endif /* __SOC_QCOM_SYS_PM_H__ */
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index f730b91..9e1aa1a 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -78,6 +78,7 @@
 	size_t xruns;		/* over/underruns counter */
 	/* misc */
 	spinlock_t lock;
+	struct mutex realloc_mutex;
 	wait_queue_head_t sleep;
 	/* event handler (new bytes, input only) */
 	void (*event)(struct snd_rawmidi_substream *substream);
diff --git a/include/trace/events/mpm.h b/include/trace/events/mpm.h
new file mode 100644
index 0000000..433fdbf
--- /dev/null
+++ b/include/trace/events/mpm.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mpm
+
+#if !defined(_TRACE_MPM_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MPM_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(mpm_wakeup_enable_irqs,
+
+	TP_PROTO(uint32_t index, uint32_t irqs),
+
+	TP_ARGS(index, irqs),
+
+	TP_STRUCT__entry(
+		__field(uint32_t, index)
+		__field(uint32_t, irqs)
+	),
+
+	TP_fast_assign(
+		__entry->index = index;
+		__entry->irqs = irqs;
+	),
+
+	TP_printk("index:%u  wakeup_capable_irqs:0x%x",
+				__entry->index, __entry->irqs)
+);
+
+TRACE_EVENT(mpm_wakeup_pending_irqs,
+
+	TP_PROTO(uint32_t index, uint32_t irqs),
+
+	TP_ARGS(index, irqs),
+
+	TP_STRUCT__entry(
+		__field(uint32_t, index)
+		__field(uint32_t, irqs)
+	),
+
+	TP_fast_assign(
+		__entry->index = index;
+		__entry->irqs = irqs;
+	),
+
+	TP_printk("index:%u wakeup_irqs:0x%x", __entry->index, __entry->irqs)
+);
+
+#endif
+#define TRACE_INCLUDE_FILE mpm
+#include <trace/define_trace.h>
diff --git a/include/trace/events/msm_cam.h b/include/trace/events/msm_cam.h
new file mode 100644
index 0000000..3fc1a29
--- /dev/null
+++ b/include/trace/events/msm_cam.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msm_cam
+
+#if !defined(_TRACE_MSM_VFE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSM_VFE_H
+
+#include "msm_isp.h"
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#define STRING_LEN 80
+
+
+TRACE_EVENT(msm_cam_string,
+	TP_PROTO(const char *str),
+	TP_ARGS(str),
+	TP_STRUCT__entry(
+		__array(char, str, STRING_LEN)
+	),
+	TP_fast_assign(
+		strlcpy(__entry->str, str, STRING_LEN);
+	),
+	TP_printk("msm_cam: %s", __entry->str)
+);
+
+TRACE_EVENT(msm_cam_tasklet_debug_dump,
+	TP_PROTO(struct msm_vfe_irq_debug_info tasklet_state),
+	TP_ARGS(tasklet_state),
+	TP_STRUCT__entry(
+		__field(unsigned int, vfe_id)
+		__field(unsigned int, core_id)
+		__field(unsigned int, irq_status0)
+		__field(unsigned int, irq_status1)
+		__field(unsigned int, ping_pong_status)
+		__field(long, tv_sec)
+		__field(long, tv_usec)
+	),
+	TP_fast_assign(
+		__entry->vfe_id = tasklet_state.vfe_id;
+		__entry->irq_status0 =
+			tasklet_state.irq_status0[tasklet_state.vfe_id];
+		__entry->irq_status1 =
+			tasklet_state.irq_status1[tasklet_state.vfe_id];
+		__entry->core_id = tasklet_state.core_id;
+		__entry->ping_pong_status =
+			tasklet_state.ping_pong_status[tasklet_state.vfe_id];
+		__entry->tv_sec =
+			tasklet_state.ts.buf_time.tv_sec;
+		__entry->tv_usec =
+			tasklet_state.ts.buf_time.tv_usec;
+	),
+	TP_printk("vfe_id %d, core %d, irq_st0 0x%x, irq_st1 0x%x\n"
+		"pi_po_st 0x%x, time %ld:%ld",
+		__entry->vfe_id,
+		__entry->core_id,
+		__entry->irq_status0,
+		__entry->irq_status1,
+		__entry->ping_pong_status,
+		__entry->tv_sec,
+		__entry->tv_usec
+	)
+);
+
+TRACE_EVENT(msm_cam_ping_pong_debug_dump,
+	TP_PROTO(struct msm_vfe_irq_debug_info ping_pong_state),
+	TP_ARGS(ping_pong_state),
+	TP_STRUCT__entry(
+		__field(unsigned int, curr_vfe_id)
+		__field(unsigned int, curr_irq_status0)
+		__field(unsigned int, curr_irq_status1)
+		__field(unsigned int, curr_ping_pong_status)
+		__field(unsigned int, othr_vfe_id)
+		__field(unsigned int, othr_irq_status0)
+		__field(unsigned int, othr_irq_status1)
+		__field(unsigned int, othr_ping_pong_status)
+		__field(long, othr_tv_sec)
+		__field(long, othr_tv_usec)
+		__field(unsigned int, core_id)
+	),
+	TP_fast_assign(
+		__entry->curr_vfe_id =
+			ping_pong_state.vfe_id;
+		__entry->curr_irq_status0 =
+			ping_pong_state.irq_status0[ping_pong_state.vfe_id];
+		__entry->curr_irq_status1 =
+			ping_pong_state.irq_status1[ping_pong_state.vfe_id];
+		__entry->curr_ping_pong_status =
+			ping_pong_state.
+			ping_pong_status[ping_pong_state.vfe_id];
+		__entry->othr_vfe_id =
+			!ping_pong_state.vfe_id;
+		__entry->othr_irq_status0 =
+			ping_pong_state.irq_status0[!ping_pong_state.vfe_id];
+		__entry->othr_irq_status1 =
+			ping_pong_state.irq_status1[!ping_pong_state.vfe_id];
+		__entry->othr_ping_pong_status =
+			ping_pong_state.
+			ping_pong_status[!ping_pong_state.vfe_id];
+		__entry->othr_tv_sec =
+			ping_pong_state.ts.buf_time.tv_sec;
+		__entry->othr_tv_usec =
+			ping_pong_state.ts.buf_time.tv_usec;
+		__entry->core_id = ping_pong_state.core_id;
+	),
+	TP_printk("vfe_id %d, irq_st0 0x%x, irq_st1 0x%x, pi_po_st 0x%x\n"
+		"other vfe_id %d, irq_st0 0x%x, irq_st1 0x%x\n"
+		"pi_po_st 0x%x, time %ld:%ld core %d",
+		__entry->curr_vfe_id,
+		__entry->curr_irq_status0,
+		__entry->curr_irq_status1,
+		__entry->curr_ping_pong_status,
+		__entry->othr_vfe_id,
+		__entry->othr_irq_status0,
+		__entry->othr_irq_status1,
+		__entry->othr_ping_pong_status,
+		__entry->othr_tv_sec,
+		__entry->othr_tv_usec,
+		__entry->core_id
+	)
+);
+
+#endif /* _MSM_CAM_TRACE_H */
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 8cfb1d7..a29c76f 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -858,322 +858,6 @@
 		      __entry->freq)
 );
 
-DECLARE_EVENT_CLASS(kpm_module,
-
-	TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
-
-	TP_ARGS(managed_cpus, max_cpus),
-
-	TP_STRUCT__entry(
-		__field(u32, managed_cpus)
-		__field(u32, max_cpus)
-	),
-
-	TP_fast_assign(
-		__entry->managed_cpus = managed_cpus;
-		__entry->max_cpus = max_cpus;
-	),
-
-	TP_printk("managed:%x max_cpus=%u", (unsigned int)__entry->managed_cpus,
-					(unsigned int)__entry->max_cpus)
-);
-
-DEFINE_EVENT(kpm_module, set_max_cpus,
-	TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
-	TP_ARGS(managed_cpus, max_cpus)
-);
-
-DEFINE_EVENT(kpm_module, reevaluate_hotplug,
-	TP_PROTO(unsigned int managed_cpus, unsigned int max_cpus),
-	TP_ARGS(managed_cpus, max_cpus)
-);
-
-DECLARE_EVENT_CLASS(kpm_module2,
-
-	TP_PROTO(unsigned int cpu, unsigned int enter_cycle_cnt,
-		unsigned int exit_cycle_cnt,
-		unsigned int io_busy, u64 iowait),
-
-	TP_ARGS(cpu, enter_cycle_cnt, exit_cycle_cnt, io_busy, iowait),
-
-	TP_STRUCT__entry(
-		__field(u32, cpu)
-		__field(u32, enter_cycle_cnt)
-		__field(u32, exit_cycle_cnt)
-		__field(u32, io_busy)
-		__field(u64, iowait)
-	),
-
-	TP_fast_assign(
-		__entry->cpu = cpu;
-		__entry->enter_cycle_cnt = enter_cycle_cnt;
-		__entry->exit_cycle_cnt = exit_cycle_cnt;
-		__entry->io_busy = io_busy;
-		__entry->iowait = iowait;
-	),
-
-	TP_printk("CPU:%u enter_cycles=%u exit_cycles=%u io_busy=%u iowait=%lu",
-		(unsigned int)__entry->cpu,
-		(unsigned int)__entry->enter_cycle_cnt,
-		(unsigned int)__entry->exit_cycle_cnt,
-		(unsigned int)__entry->io_busy,
-		(unsigned long)__entry->iowait)
-);
-
-DEFINE_EVENT(kpm_module2, track_iowait,
-	TP_PROTO(unsigned int cpu, unsigned int enter_cycle_cnt,
-		unsigned int exit_cycle_cnt, unsigned int io_busy, u64 iowait),
-	TP_ARGS(cpu, enter_cycle_cnt, exit_cycle_cnt, io_busy, iowait)
-);
-
-DECLARE_EVENT_CLASS(cpu_modes,
-
-	TP_PROTO(unsigned int cpu, unsigned int max_load,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int total_load, unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycle_cnt,
-		unsigned int perf_cl_peak_enter_cycle_cnt,
-		unsigned int perf_cl_peak_exit_cycle_cnt,
-		unsigned int mode,
-		unsigned int cpu_cnt),
-
-	TP_ARGS(cpu, max_load, single_enter_cycle_cnt, single_exit_cycle_cnt,
-		total_load, multi_enter_cycle_cnt, multi_exit_cycle_cnt,
-		perf_cl_peak_enter_cycle_cnt, perf_cl_peak_exit_cycle_cnt, mode,
-		cpu_cnt),
-
-	TP_STRUCT__entry(
-		__field(u32, cpu)
-		__field(u32, max_load)
-		__field(u32, single_enter_cycle_cnt)
-		__field(u32, single_exit_cycle_cnt)
-		__field(u32, total_load)
-		__field(u32, multi_enter_cycle_cnt)
-		__field(u32, multi_exit_cycle_cnt)
-		__field(u32, perf_cl_peak_enter_cycle_cnt)
-		__field(u32, perf_cl_peak_exit_cycle_cnt)
-		__field(u32, mode)
-		__field(u32, cpu_cnt)
-	),
-
-	TP_fast_assign(
-		__entry->cpu = cpu;
-		__entry->max_load = max_load;
-		__entry->single_enter_cycle_cnt = single_enter_cycle_cnt;
-		__entry->single_exit_cycle_cnt = single_exit_cycle_cnt;
-		__entry->total_load = total_load;
-		__entry->multi_enter_cycle_cnt = multi_enter_cycle_cnt;
-		__entry->multi_exit_cycle_cnt = multi_exit_cycle_cnt;
-		__entry->perf_cl_peak_enter_cycle_cnt =
-				perf_cl_peak_enter_cycle_cnt;
-		__entry->perf_cl_peak_exit_cycle_cnt =
-				perf_cl_peak_exit_cycle_cnt;
-		__entry->mode = mode;
-		__entry->cpu_cnt = cpu_cnt;
-	),
-
-	TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%u",
-		(unsigned int)__entry->cpu, (unsigned int)__entry->max_load,
-		(unsigned int)__entry->single_enter_cycle_cnt,
-		(unsigned int)__entry->single_exit_cycle_cnt,
-		(unsigned int)__entry->total_load,
-		(unsigned int)__entry->multi_enter_cycle_cnt,
-		(unsigned int)__entry->multi_exit_cycle_cnt,
-		(unsigned int)__entry->perf_cl_peak_enter_cycle_cnt,
-		(unsigned int)__entry->perf_cl_peak_exit_cycle_cnt,
-		(unsigned int)__entry->mode,
-		(unsigned int)__entry->cpu_cnt)
-);
-
-DEFINE_EVENT(cpu_modes, cpu_mode_detect,
-	TP_PROTO(unsigned int cpu, unsigned int max_load,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int total_load, unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycle_cnt,
-		unsigned int perf_cl_peak_enter_cycle_cnt,
-		unsigned int perf_cl_peak_exit_cycle_cnt,
-		unsigned int mode,
-		unsigned int cpu_cnt),
-	TP_ARGS(cpu, max_load, single_enter_cycle_cnt, single_exit_cycle_cnt,
-		total_load, multi_enter_cycle_cnt, multi_exit_cycle_cnt,
-		perf_cl_peak_enter_cycle_cnt, perf_cl_peak_exit_cycle_cnt,
-		mode, cpu_cnt)
-);
-
-DECLARE_EVENT_CLASS(timer_status,
-	TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycles,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int multi_enter_cycles,
-		unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycles,
-		unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
-		single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
-		multi_enter_cycle_cnt, multi_exit_cycles,
-		multi_exit_cycle_cnt, timer_rate, mode),
-
-	TP_STRUCT__entry(
-		__field(unsigned int, cpu)
-		__field(unsigned int, single_enter_cycles)
-		__field(unsigned int, single_enter_cycle_cnt)
-		__field(unsigned int, single_exit_cycles)
-		__field(unsigned int, single_exit_cycle_cnt)
-		__field(unsigned int, multi_enter_cycles)
-		__field(unsigned int, multi_enter_cycle_cnt)
-		__field(unsigned int, multi_exit_cycles)
-		__field(unsigned int, multi_exit_cycle_cnt)
-		__field(unsigned int, timer_rate)
-		__field(unsigned int, mode)
-	),
-
-	TP_fast_assign(
-		__entry->cpu = cpu;
-		__entry->single_enter_cycles = single_enter_cycles;
-		__entry->single_enter_cycle_cnt = single_enter_cycle_cnt;
-		__entry->single_exit_cycles = single_exit_cycles;
-		__entry->single_exit_cycle_cnt = single_exit_cycle_cnt;
-		__entry->multi_enter_cycles = multi_enter_cycles;
-		__entry->multi_enter_cycle_cnt = multi_enter_cycle_cnt;
-		__entry->multi_exit_cycles = multi_exit_cycles;
-		__entry->multi_exit_cycle_cnt = multi_exit_cycle_cnt;
-		__entry->timer_rate = timer_rate;
-		__entry->mode = mode;
-	),
-
-	TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u:%4u",
-		(unsigned int) __entry->cpu,
-		(unsigned int) __entry->single_enter_cycles,
-		(unsigned int) __entry->single_enter_cycle_cnt,
-		(unsigned int) __entry->single_exit_cycles,
-		(unsigned int) __entry->single_exit_cycle_cnt,
-		(unsigned int) __entry->multi_enter_cycles,
-		(unsigned int) __entry->multi_enter_cycle_cnt,
-		(unsigned int) __entry->multi_exit_cycles,
-		(unsigned int) __entry->multi_exit_cycle_cnt,
-		(unsigned int) __entry->timer_rate,
-		(unsigned int) __entry->mode)
-);
-
-DEFINE_EVENT(timer_status, single_mode_timeout,
-	TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycles,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int multi_enter_cycles,
-		unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycles,
-		unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
-		single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
-		multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
-		timer_rate, mode)
-);
-
-DEFINE_EVENT(timer_status, single_cycle_exit_timer_start,
-	TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycles,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int multi_enter_cycles,
-		unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycles,
-		unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
-		single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
-		multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
-		timer_rate, mode)
-);
-
-DEFINE_EVENT(timer_status, single_cycle_exit_timer_stop,
-	TP_PROTO(unsigned int cpu, unsigned int single_enter_cycles,
-		unsigned int single_enter_cycle_cnt,
-		unsigned int single_exit_cycles,
-		unsigned int single_exit_cycle_cnt,
-		unsigned int multi_enter_cycles,
-		unsigned int multi_enter_cycle_cnt,
-		unsigned int multi_exit_cycles,
-		unsigned int multi_exit_cycle_cnt, unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, single_enter_cycles, single_enter_cycle_cnt,
-		single_exit_cycles, single_exit_cycle_cnt, multi_enter_cycles,
-		multi_enter_cycle_cnt, multi_exit_cycles, multi_exit_cycle_cnt,
-		timer_rate, mode)
-);
-
-DECLARE_EVENT_CLASS(perf_cl_peak_timer_status,
-	TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
-		unsigned int perf_cl_peak_enter_cycle_cnt,
-		unsigned int perf_cl_peak_exit_cycles,
-		unsigned int perf_cl_peak_exit_cycle_cnt,
-		unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
-		perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
-		timer_rate, mode),
-
-	TP_STRUCT__entry(
-		__field(unsigned int, cpu)
-		__field(unsigned int, perf_cl_peak_enter_cycles)
-		__field(unsigned int, perf_cl_peak_enter_cycle_cnt)
-		__field(unsigned int, perf_cl_peak_exit_cycles)
-		__field(unsigned int, perf_cl_peak_exit_cycle_cnt)
-		__field(unsigned int, timer_rate)
-		__field(unsigned int, mode)
-	),
-
-	TP_fast_assign(
-		__entry->cpu = cpu;
-		__entry->perf_cl_peak_enter_cycles = perf_cl_peak_enter_cycles;
-		__entry->perf_cl_peak_enter_cycle_cnt =
-				perf_cl_peak_enter_cycle_cnt;
-		__entry->perf_cl_peak_exit_cycles = perf_cl_peak_exit_cycles;
-		__entry->perf_cl_peak_exit_cycle_cnt =
-				perf_cl_peak_exit_cycle_cnt;
-		__entry->timer_rate = timer_rate;
-		__entry->mode = mode;
-	),
-
-	TP_printk("%u:%4u:%4u:%4u:%4u:%4u:%4u",
-		(unsigned int) __entry->cpu,
-		(unsigned int) __entry->perf_cl_peak_enter_cycles,
-		(unsigned int) __entry->perf_cl_peak_enter_cycle_cnt,
-		(unsigned int) __entry->perf_cl_peak_exit_cycles,
-		(unsigned int) __entry->perf_cl_peak_exit_cycle_cnt,
-		(unsigned int) __entry->timer_rate,
-		(unsigned int) __entry->mode)
-);
-
-DEFINE_EVENT(perf_cl_peak_timer_status, perf_cl_peak_exit_timer_start,
-	TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
-		unsigned int perf_cl_peak_enter_cycle_cnt,
-		unsigned int perf_cl_peak_exit_cycles,
-		unsigned int perf_cl_peak_exit_cycle_cnt,
-		unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
-		perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
-		timer_rate, mode)
-);
-
-
-DEFINE_EVENT(perf_cl_peak_timer_status, perf_cl_peak_exit_timer_stop,
-	TP_PROTO(unsigned int cpu, unsigned int perf_cl_peak_enter_cycles,
-		unsigned int perf_cl_peak_enter_cycle_cnt,
-		unsigned int perf_cl_peak_exit_cycles,
-		unsigned int perf_cl_peak_exit_cycle_cnt,
-		unsigned int timer_rate,
-		unsigned int mode),
-	TP_ARGS(cpu, perf_cl_peak_enter_cycles, perf_cl_peak_enter_cycle_cnt,
-		perf_cl_peak_exit_cycles, perf_cl_peak_exit_cycle_cnt,
-		timer_rate, mode)
-);
 
 #endif /* _TRACE_POWER_H */
 
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 290bc59..23a3b9a 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -596,8 +596,8 @@
 
 TRACE_EVENT(sched_load_to_gov,
 
-	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy),
-	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy),
+	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy, int big_task_rotation),
+	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy, big_task_rotation),
 
 	TP_STRUCT__entry(
 		__field(	int,	cpu			)
@@ -612,6 +612,7 @@
 		__field(	u64,	grp_nt_ps		)
 		__field(	u64,	pl			)
 		__field(	u64,    load			)
+		__field(	int,    big_task_rotation	)
 	),
 
 	TP_fast_assign(
@@ -627,13 +628,15 @@
 		__entry->grp_nt_ps	= rq->grp_time.nt_prev_runnable_sum;
 		__entry->pl		= rq->walt_stats.pred_demands_sum;
 		__entry->load		= load;
+		__entry->big_task_rotation = big_task_rotation;
 	),
 
-	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu",
+	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu big_task_rotation=%d",
 		__entry->cpu, __entry->policy, __entry->ed_task_pid,
 		__entry->aggr_grp_load, __entry->freq_aggr_thresh,
 		__entry->tt_load, __entry->rq_ps, __entry->grp_rq_ps,
-		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load)
+		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load,
+		__entry->big_task_rotation)
 );
 #endif
 
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index fcf84e3..38f710e 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -421,4 +421,19 @@
 	__u32 matrix[DITHER_MATRIX_SZ];
 };
 
+/**
+ * struct drm_msm_pa_dither - dspp dither feature structure
+ * @flags: for customizing operations
+ * @strength: dither strength
+ * @offset_en: offset enable bit
+ * @matrix: dither data matrix
+ */
+#define DRM_MSM_PA_DITHER
+struct drm_msm_pa_dither {
+	__u64 flags;
+	__u32 strength;
+	__u32 offset_en;
+	__u32 matrix[DITHER_MATRIX_SZ];
+};
+
 #endif /* _MSM_DRM_PP_H_ */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index ea727f2..f8e92fbc 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -367,6 +367,8 @@
 header-y += qbt1000.h
 header-y += qcedev.h
 header-y += qcota.h
+header-y += qg.h
+header-y += qg-profile.h
 header-y += qnx4_fs.h
 header-y += qnxtypes.h
 header-y += qrng.h
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 3b124ff..8bc189f 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -9,6 +9,7 @@
 #define MAX_ROI_SIZE		144
 #define MAX_ACCEL_SIZE		128
 
+#define HBTP_FLAG_ACTIVE_BLOB      0x01
 #define HBTP_EVENT_TYPE_DISPLAY	"EVENT_TYPE=HBTP_DISPLAY"
 
 struct hbtp_input_touch {
@@ -33,6 +34,13 @@
 	struct timeval time_val;
 };
 
+struct hbtp_input_mt_ext {
+	__s32  num_touches;
+	struct hbtp_input_touch touches[HBTP_MAX_FINGER];
+	struct timeval time_val;
+	__u32  flag;
+};
+
 struct hbtp_input_absinfo {
 	bool  active;
 	__u16 code;
@@ -77,6 +85,8 @@
 					enum hbtp_afe_power_ctrl)
 #define HBTP_SET_SENSORDATA	_IOW(HBTP_INPUT_IOCTL_BASE, 207, \
 					struct hbtp_sensor_data)
+#define HBTP_SET_TOUCHDATA_EXT	_IOW(HBTP_INPUT_IOCTL_BASE, 208, \
+					struct hbtp_input_mt_ext)
 
 #endif	/* _UAPI_HBTP_INPUT_H */
 
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 39b041e..c1ea699 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -684,6 +684,14 @@
 #define BTN_TRIGGER_HAPPY39		0x2e6
 #define BTN_TRIGGER_HAPPY40		0x2e7
 
+/* Custom fingerprint gestures keys */
+#define KEY_FP_GESTURE_UP		0x2e8
+#define KEY_FP_GESTURE_DOWN		0x2e9
+#define KEY_FP_GESTURE_LEFT		0x2ea
+#define KEY_FP_GESTURE_RIGHT		0x2eb
+#define KEY_FP_GESTURE_LONG_PRESS	0x2ec
+#define KEY_FP_GESTURE_TAP		0x2ed
+
 /* We avoid low common keys in module aliases so they don't get huge. */
 #define KEY_MIN_INTERESTING	KEY_MUTE
 #define KEY_MAX			0x2ff
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index c462f1d..b55dceb 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -185,6 +185,7 @@
 	DEVCONF_ADDR_GEN_MODE,
 	DEVCONF_DISABLE_POLICY,
 	DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
+	DEVCONF_ACCEPT_RA_PREFIX_ROUTE,
 	DEVCONF_MAX
 };
 
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index 73f4938..8a0e4cf 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -1410,6 +1410,11 @@
 	MDP_CSC_ITU_R_709,
 };
 
+/*
+ * These definitions are a continuation of the mdp_color_space enum above
+ */
+#define MDP_CSC_ITU_R_2020	(MDP_CSC_ITU_R_709 + 1)
+#define MDP_CSC_ITU_R_2020_FR	(MDP_CSC_ITU_R_2020 + 1)
 enum {
 	mdp_igc_v1_7 = 1,
 	mdp_igc_vmax,
diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h
index 05a105b..1a2a7e2c 100644
--- a/include/uapi/linux/msm_mdp_ext.h
+++ b/include/uapi/linux/msm_mdp_ext.h
@@ -34,9 +34,9 @@
  * To allow proper structure padding for 64bit/32bit target
  */
 #ifdef __LP64
-#define MDP_LAYER_COMMIT_V1_PAD 3
+#define MDP_LAYER_COMMIT_V1_PAD 2
 #else
-#define MDP_LAYER_COMMIT_V1_PAD 4
+#define MDP_LAYER_COMMIT_V1_PAD 3
 #endif
 
 /*
@@ -350,8 +350,11 @@
 	/* Buffer attached with output layer. Device uses it for commit call */
 	struct mdp_layer_buffer		buffer;
 
+	/* color space of the destination */
+	enum mdp_color_space            color_space;
+
 	/* 32bits reserved value for future usage. */
-	uint32_t			reserved[6];
+	uint32_t			reserved[5];
 };
 
 /*
@@ -389,6 +392,18 @@
 	uint64_t	__user scale;
 };
 
+/* Enable Deterministic Frame Rate Control (FRC) */
+#define MDP_VIDEO_FRC_ENABLE (1 << 0)
+
+struct mdp_frc_info {
+	/* flags to control FRC feature */
+	uint32_t flags;
+	/* video frame count per frame */
+	uint32_t frame_cnt;
+	/* video timestamp per frame in millisecond unit */
+	int64_t timestamp;
+};
+
 /*
  * Commit structure holds layer stack send by client for validate and commit
  * call. If layers are different between validate and commit call then commit
@@ -467,6 +482,9 @@
 	 */
 	uint32_t		dest_scaler_cnt;
 
+	/* FRC info per device which contains frame count and timestamp */
+	struct mdp_frc_info __user *frc_info;
+
 	/* 32-bits reserved value for future usage. */
 	uint32_t		reserved[MDP_LAYER_COMMIT_V1_PAD];
 };
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 3092188..9399a35 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -944,6 +944,43 @@
  *	does not result in a change for the current association. Currently,
  *	only the %NL80211_ATTR_IE data is used and updated with this command.
  *
+ * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
+ *	for the given authenticator address (specified with &NL80211_ATTR_MAC).
+ *	When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
+ *	PMK-R0, otherwise it specifies the PMK.
+ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
+ *	configured PMK for the authenticator address identified by
+ *	&NL80211_ATTR_MAC.
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
+ *	handshake was completed successfully by the driver. The BSSID is
+ *	specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ *	offload should send this event after indicating 802.11 association with
+ *	&NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
+ *	&NL80211_CMD_DISCONNECT should be indicated instead.
+ *
+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
+ *
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ *	drivers that do not define separate commands for authentication and
+ *	association, but rely on user space for the authentication to happen.
+ *	This interface acts both as the event request (driver to user space)
+ *	to trigger the authentication and command response (userspace to
+ *	driver) to indicate the authentication status.
+ *
+ *	User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ *	trigger a connection. The host driver selects a BSS and further uses
+ *	this interface to offload only the authentication part to the user
+ *	space. Authentication frames are passed between the driver and user
+ *	space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ *	further with the association after getting successful authentication
+ *	status. User space indicates the authentication status through
+ *	%NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ *	command interface.
+ *
+ *	Host driver reports this status on an authentication failure to the
+ *	user space through the connect result as the user space would have
+ *	initiated the connection through the connect request.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1143,6 +1180,15 @@
 
 	NL80211_CMD_UPDATE_CONNECT_PARAMS,
 
+	NL80211_CMD_SET_PMK,
+	NL80211_CMD_DEL_PMK,
+
+	NL80211_CMD_PORT_AUTHORIZED,
+
+	NL80211_CMD_RELOAD_REGDB,
+
+	NL80211_CMD_EXTERNAL_AUTH,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1870,6 +1916,8 @@
  *	and remove functions. NAN notifications will be sent in unicast to that
  *	socket. Without this attribute, any socket can add functions and the
  *	notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ *	If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
+ *	station will deauthenticate when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
@@ -2077,6 +2125,16 @@
  *	the driver or is not needed (because roaming used the Fast Transition
  *	protocol).
  *
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ *     authentication operation (u32 attribute with an
+ *     &enum nl80211_external_auth_action value). This is used with the
+ *     &NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ *     space supports external authentication. This attribute shall be used
+ *     only with %NL80211_CMD_CONNECT request. The driver may offload
+ *     authentication processing to user space if this capability is indicated
+ *     in NL80211_CMD_CONNECT requests from the user space.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2503,6 +2561,9 @@
 	NL80211_ATTR_PMKR0_NAME,
 	NL80211_ATTR_PORT_AUTHORIZED,
 
+	NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+	NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -5401,4 +5462,15 @@
 	NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
 };
 
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ *     authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+	NL80211_EXTERNAL_AUTH_START,
+	NL80211_EXTERNAL_AUTH_ABORT,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/uapi/linux/qbt1000.h b/include/uapi/linux/qbt1000.h
index a4f0dca..0012d23 100644
--- a/include/uapi/linux/qbt1000.h
+++ b/include/uapi/linux/qbt1000.h
@@ -20,6 +20,7 @@
 	QBT1000_SET_FINGER_DETECT_KEY = 103,
 	QBT1000_CONFIGURE_POWER_KEY = 104
 };
+#define QBT1000_ENABLE_GESTURES 105
 
 /*
  * enum qbt1000_fw_event -
@@ -79,6 +80,15 @@
 };
 
 /*
+ * struct qbt1000_enable_gestures -
+ *      used to configure whether gestures detection is enabled or disabled
+ * @enable - if non-zero, gestures detection is enabled
+ */
+struct qbt1000_enable_gestures {
+	unsigned int enable;
+};
+
+/*
  * struct qbt1000_set_finger_detect_key -
  *      used to configure the input key which is sent on finger down/up event
  * @key_code - Key code to send on finger down/up. 0 disables sending key events
diff --git a/include/uapi/linux/qg-profile.h b/include/uapi/linux/qg-profile.h
new file mode 100644
index 0000000..bffddbb
--- /dev/null
+++ b/include/uapi/linux/qg-profile.h
@@ -0,0 +1,66 @@
+#ifndef __QG_PROFILE_H__
+#define __QG_PROFILE_H__
+
+#include <linux/ioctl.h>
+
+/**
+ * enum profile_table - Table index for battery profile data
+ */
+enum profile_table {
+	TABLE_SOC_OCV1,
+	TABLE_SOC_OCV2,
+	TABLE_FCC1,
+	TABLE_FCC2,
+	TABLE_Z1,
+	TABLE_Z2,
+	TABLE_Z3,
+	TABLE_Z4,
+	TABLE_Z5,
+	TABLE_Z6,
+	TABLE_Y1,
+	TABLE_Y2,
+	TABLE_Y3,
+	TABLE_Y4,
+	TABLE_Y5,
+	TABLE_Y6,
+	TABLE_MAX,
+};
+
+/**
+ * struct battery_params - Battery profile data to be exchanged
+ * @soc:	SOC (state of charge) of the battery
+ * @ocv_uv:	OCV (open circuit voltage) of the battery
+ * @batt_temp:	Battery temperature in deci-degree
+ * @var:	'X' axis param for interpolation
+ * @table_index:Table index to be used for interpolation
+ */
+struct battery_params {
+	int soc;
+	int ocv_uv;
+	int fcc_mah;
+	int slope;
+	int var;
+	int batt_temp;
+	int table_index;
+};
+
+/* Profile MIN / MAX values */
+#define QG_MIN_SOC				0
+#define QG_MAX_SOC				10000
+#define QG_MIN_OCV_UV				3000000
+#define QG_MAX_OCV_UV				5000000
+#define QG_MIN_VAR				0
+#define QG_MAX_VAR				65535
+#define QG_MIN_FCC_MAH				100
+#define QG_MAX_FCC_MAH				16000
+#define QG_MIN_SLOPE				1
+#define QG_MAX_SLOPE				50000
+
+/*  IOCTLs to query battery profile data */
+#define BPIOCXSOC	_IOWR('B', 0x01, struct battery_params) /* SOC */
+#define BPIOCXOCV	_IOWR('B', 0x02, struct battery_params) /* OCV */
+#define BPIOCXFCC	_IOWR('B', 0x03, struct battery_params) /* FCC */
+#define BPIOCXSLOPE	_IOWR('B', 0x04, struct battery_params) /* Slope */
+#define BPIOCXVAR	_IOWR('B', 0x05, struct battery_params) /* All-other */
+
+#endif /* __QG_PROFILE_H__ */
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
new file mode 100644
index 0000000..54488ff
--- /dev/null
+++ b/include/uapi/linux/qg.h
@@ -0,0 +1,52 @@
+#ifndef __QG_H__
+#define __QG_H__
+
+#define MAX_FIFO_LENGTH		16
+
+enum qg {
+	QG_SOC,
+	QG_OCV_UV,
+	QG_RBAT_MOHM,
+	QG_PON_OCV_UV,
+	QG_GOOD_OCV_UV,
+	QG_ESR,
+	QG_CHARGE_COUNTER,
+	QG_FIFO_TIME_DELTA,
+	QG_RESERVED_1,
+	QG_RESERVED_2,
+	QG_RESERVED_3,
+	QG_RESERVED_4,
+	QG_RESERVED_5,
+	QG_RESERVED_6,
+	QG_RESERVED_7,
+	QG_RESERVED_8,
+	QG_RESERVED_9,
+	QG_RESERVED_10,
+	QG_MAX,
+};
+
+struct fifo_data {
+	unsigned int			v;
+	unsigned int			i;
+	unsigned int			count;
+	unsigned int			interval;
+};
+
+struct qg_param {
+	unsigned int			data;
+	bool				valid;
+};
+
+struct qg_kernel_data {
+	unsigned int			seq_no;
+	unsigned int			fifo_time;
+	unsigned int			fifo_length;
+	struct fifo_data		fifo[MAX_FIFO_LENGTH];
+	struct qg_param			param[QG_MAX];
+};
+
+struct qg_user_data {
+	struct qg_param			param[QG_MAX];
+};
+
+#endif
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 1df8c41..0b5ff0f 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -371,7 +371,7 @@
 enum v4l2_mpeg_video_header_mode {
 	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
-
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME		= 2,
 };
 #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
 #define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
@@ -382,6 +382,7 @@
 	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+	V4L2_MPEG_VIDEO_MULTI_SLICE_GOB			= 3,
 };
 #define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
 #define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
@@ -662,6 +663,9 @@
 	V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON = 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+1)
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT   (V4L2_CID_MPEG_MSM_VIDC_BASE+2)
 enum v4l2_mpeg_vidc_video_stream_format {
 	V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES         = 0,
@@ -719,6 +723,8 @@
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0,
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1,
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 2,
+	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 3,
+	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 4,
 };
 #define V4L2_CID_MPEG_VIDC_VIDEO_IR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+13)
 
@@ -741,6 +747,8 @@
 	V4L2_MPEG_VIDC_EXTRADATA_NONE = 0,
 	V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1,
 	V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4,
 	V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5,
 	V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6,
 	V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7,
@@ -782,6 +790,9 @@
 #define V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO \
 	V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO
 	V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO = 31,
+#define V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP \
+	V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP
+	V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP = 32,
 };
 
 #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE	\
@@ -835,6 +846,11 @@
 	V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH			= 5,
 };
 
+enum v4l2_mpeg_vidc_video_mvc_layout {
+	V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0,
+	V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1
+};
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 25)
 
@@ -859,6 +875,14 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 30)
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT       \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+enum v4l2_mpeg_vidc_video_alloc_mode_type {
+	V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
+	V4L2_MPEG_VIDC_VIDEO_RING = 1,
+	V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
+};
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 32)
 
@@ -1070,6 +1094,39 @@
 	V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 68)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 69)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 70)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY	\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 71)
+enum v4l2_mpeg_vidc_video_assembly {
+	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
+	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 72)
+enum v4l2_mpeg_vidc_video_h263_profile {
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING	= 1,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8,
+};
+
+#define V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 97)
+#define V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 98)
 #define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 99)
 #define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \
@@ -1165,6 +1222,144 @@
 #define V4L2_CID_MPEG_VIDC_VENC_MAX_FLL \
 	(V4L2_CID_MPEG_MSM_VIDC_BASE + 128)
 
+#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL \
+	(V4L2_CID_MPEG_MSM_VIDC_BASE + 129)
+enum v4l2_mpeg_vidc_perf_level {
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL	= 0,
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE	= 1,
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO	= 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 130)
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE + 131)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 132)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 135)
+
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 136)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 137)
+enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict {
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 138)
+enum v4l2_mpeg_vidc_video_deinterlace {
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 139)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 140)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 141)
+enum v4l2_mpeg_vidc_video_rate_control_timestamp_mode {
+	V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR = 0,
+	V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 142)
+enum vl42_mpeg_vidc_video_enable_initial_qp {
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME = 0x1,
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME = 0x2,
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 143)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 144)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 145)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 146)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE	 \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 147)
+enum v4l2_mpeg_vidc_video_perf_mode {
+	V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1,
+	V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE	\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 148)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 149)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 150)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 151)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 152)
+
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 153)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2 \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 154)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 155)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 156)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 157)
+enum v4l2_mpeg_vidc_video_h263_level {
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 158)
+
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+159)
+
+enum v4l2_mpeg_vidc_video_divx_format_type {
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0,
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1,
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2,
+};
+
+enum v4l2_mpeg_vidc_video_mbi_statistics_mode {
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1 = 1,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2 = 2,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3 = 3,
+};
+
+enum vl42_mpeg_vidc_video_h264_svc_nal {
+	V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED = 1,
+};
+
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
+
 /*  Camera class control IDs */
 
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 71772c3..8a2a315 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -2,7 +2,7 @@
  *  Video for Linux Two header file
  *
  *  Copyright (C) 1999-2012 the contributors
- *  Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -594,6 +594,14 @@
 #define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12  GRGR.. BGBG.. */
 #define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12  RGRG.. GBGB.. */
 #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SBGGR10DPCM6 v4l2_fourcc('b', 'B', 'A', '6')
+#define V4L2_PIX_FMT_SGBRG10DPCM6 v4l2_fourcc('b', 'G', 'A', '6')
+#define V4L2_PIX_FMT_SGRBG10DPCM6 v4l2_fourcc('B', 'D', '1', '6')
+#define V4L2_PIX_FMT_SRGGB10DPCM6 v4l2_fourcc('b', 'R', 'A', '6')
+#define V4L2_PIX_FMT_SBGGRPLAIN16 v4l2_fourcc('B', 'G', '1', '6')
+#define V4L2_PIX_FMT_SGBRGPLAIN16 v4l2_fourcc('G', 'B', '1', '6')
+#define V4L2_PIX_FMT_SGRBGPLAIN16 v4l2_fourcc('G', 'R', '1', '6')
+#define V4L2_PIX_FMT_SRGGBPLAIN16 v4l2_fourcc('R', 'G', '1', '6')
 
 /* compressed formats */
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
@@ -612,7 +620,10 @@
 #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
 #define V4L2_PIX_FMT_VP8      v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
 #define V4L2_PIX_FMT_VP9      v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
+#define V4L2_PIX_FMT_DIVX_311  v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311     */
+#define V4L2_PIX_FMT_DIVX      v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX        */
 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_HEVC_HYBRID v4l2_fourcc('H', 'V', 'C', 'H')
 #define V4L2_PIX_FMT_TME v4l2_fourcc('T', 'M', 'E', '0') /* for TME stream */
 
 /*  Vendor-specific formats   */
@@ -1011,11 +1022,15 @@
 #define V4L2_QCOM_BUF_FLAG_CODECCONFIG		0x00020000
 #define V4L2_QCOM_BUF_FLAG_EOSEQ		0x00040000
 #define V4L2_QCOM_BUF_TIMESTAMP_INVALID		0x00080000
+#define V4L2_MSM_BUF_FLAG_MBAFF			0x00100000
 #define V4L2_QCOM_BUF_FLAG_DECODEONLY		0x00200000
 #define V4L2_QCOM_BUF_DATA_CORRUPT		0x00400000
+#define V4L2_QCOM_BUF_DROP_FRAME		0x00800000
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED		0x01000000
 #define V4L2_QCOM_BUF_FLAG_EOS			0x02000000
 #define V4L2_QCOM_BUF_FLAG_READONLY		0x04000000
+#define V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND	0x08000000
+#define V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP	0x10000000
 #define V4L2_QCOM_BUF_FLAG_PERF_MODE		0x20000000
 #define V4L2_MSM_BUF_FLAG_DEFER			0x40000000
 #define V4L2_QCOM_BUF_FLAG_IDRFRAME		0x80000000
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index 1e087a1..1aa2a19 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -15,3 +15,16 @@
 header-y += radio-iris.h
 header-y += radio-iris-commands.h
 header-y += cam_lrme.h
+header-y += msm_cam_sensor.h
+header-y += msm_camera.h
+header-y += msm_camsensor_sdk.h
+header-y += msm_fd.h
+header-y += msm_isp.h
+header-y += msm_jpeg.h
+header-y += msm_jpeg_dma.h
+header-y += msm_media_info.h
+header-y += msmb_camera.h
+header-y += msmb_generic_buf_mgr.h
+header-y += msmb_isp.h
+header-y += msmb_ispif.h
+header-y += msmb_pproc.h
\ No newline at end of file
diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h
new file mode 100644
index 0000000..bd5b906
--- /dev/null
+++ b/include/uapi/media/msm_cam_sensor.h
@@ -0,0 +1,635 @@
+#ifndef __UAPI_LINUX_MSM_CAM_SENSOR_H
+#define __UAPI_LINUX_MSM_CAM_SENSOR_H
+
+#include <linux/v4l2-mediabus.h>
+#include <media/msm_camsensor_sdk.h>
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+#define I2C_SEQ_REG_SETTING_MAX   5
+
+#define MSM_SENSOR_MCLK_8HZ   8000000
+#define MSM_SENSOR_MCLK_16HZ  16000000
+#define MSM_SENSOR_MCLK_24HZ  24000000
+
+#define MAX_SENSOR_NAME 32
+#define MAX_ACTUATOR_AF_TOTAL_STEPS 1024
+
+#define MAX_OIS_MOD_NAME_SIZE 32
+#define MAX_OIS_NAME_SIZE 32
+#define MAX_OIS_REG_SETTINGS 800
+
+#define MOVE_NEAR 0
+#define MOVE_FAR  1
+
+#define MSM_ACTUATOR_MOVE_SIGNED_FAR -1
+#define MSM_ACTUATOR_MOVE_SIGNED_NEAR  1
+
+#define MAX_ACTUATOR_REGION  5
+
+#define MAX_EEPROM_NAME 32
+
+#define MAX_AF_ITERATIONS 3
+#define MAX_NUMBER_OF_STEPS 47
+#define MAX_REGULATOR 5
+
+/*msm_flash_query_data_t query types*/
+#define FLASH_QUERY_CURRENT 1
+
+#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
+#define MSM_V4L2_PIX_FMT_META10 v4l2_fourcc('M', 'E', '1', '0') /* META10 */
+#define MSM_V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4')
+	/* 14  BGBG.. GRGR.. */
+#define MSM_V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4')
+	/* 14  GBGB.. RGRG.. */
+#define MSM_V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('B', 'A', '1', '4')
+	/* 14  GRGR.. BGBG.. */
+#define MSM_V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4')
+	/* 14  RGRG.. GBGB.. */
+
+enum flash_type {
+	LED_FLASH = 1,
+	STROBE_FLASH,
+	GPIO_FLASH
+};
+
+enum msm_sensor_resolution_t {
+	MSM_SENSOR_RES_FULL,
+	MSM_SENSOR_RES_QTR,
+	MSM_SENSOR_RES_2,
+	MSM_SENSOR_RES_3,
+	MSM_SENSOR_RES_4,
+	MSM_SENSOR_RES_5,
+	MSM_SENSOR_RES_6,
+	MSM_SENSOR_RES_7,
+	MSM_SENSOR_INVALID_RES,
+};
+
+enum msm_camera_stream_type_t {
+	MSM_CAMERA_STREAM_PREVIEW,
+	MSM_CAMERA_STREAM_SNAPSHOT,
+	MSM_CAMERA_STREAM_VIDEO,
+	MSM_CAMERA_STREAM_INVALID,
+};
+
+enum sensor_sub_module_t {
+	SUB_MODULE_SENSOR,
+	SUB_MODULE_CHROMATIX,
+	SUB_MODULE_ACTUATOR,
+	SUB_MODULE_EEPROM,
+	SUB_MODULE_LED_FLASH,
+	SUB_MODULE_STROBE_FLASH,
+	SUB_MODULE_CSID,
+	SUB_MODULE_CSID_3D,
+	SUB_MODULE_CSIPHY,
+	SUB_MODULE_CSIPHY_3D,
+	SUB_MODULE_OIS,
+	SUB_MODULE_EXT,
+	SUB_MODULE_IR_LED,
+	SUB_MODULE_IR_CUT,
+	SUB_MODULE_LASER_LED,
+	SUB_MODULE_MAX,
+};
+
+enum {
+	MSM_CAMERA_EFFECT_MODE_OFF,
+	MSM_CAMERA_EFFECT_MODE_MONO,
+	MSM_CAMERA_EFFECT_MODE_NEGATIVE,
+	MSM_CAMERA_EFFECT_MODE_SOLARIZE,
+	MSM_CAMERA_EFFECT_MODE_SEPIA,
+	MSM_CAMERA_EFFECT_MODE_POSTERIZE,
+	MSM_CAMERA_EFFECT_MODE_WHITEBOARD,
+	MSM_CAMERA_EFFECT_MODE_BLACKBOARD,
+	MSM_CAMERA_EFFECT_MODE_AQUA,
+	MSM_CAMERA_EFFECT_MODE_EMBOSS,
+	MSM_CAMERA_EFFECT_MODE_SKETCH,
+	MSM_CAMERA_EFFECT_MODE_NEON,
+	MSM_CAMERA_EFFECT_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_WB_MODE_AUTO,
+	MSM_CAMERA_WB_MODE_CUSTOM,
+	MSM_CAMERA_WB_MODE_INCANDESCENT,
+	MSM_CAMERA_WB_MODE_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_WARM_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_TWILIGHT,
+	MSM_CAMERA_WB_MODE_SHADE,
+	MSM_CAMERA_WB_MODE_OFF,
+	MSM_CAMERA_WB_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_SCENE_MODE_OFF,
+	MSM_CAMERA_SCENE_MODE_AUTO,
+	MSM_CAMERA_SCENE_MODE_LANDSCAPE,
+	MSM_CAMERA_SCENE_MODE_SNOW,
+	MSM_CAMERA_SCENE_MODE_BEACH,
+	MSM_CAMERA_SCENE_MODE_SUNSET,
+	MSM_CAMERA_SCENE_MODE_NIGHT,
+	MSM_CAMERA_SCENE_MODE_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_BACKLIGHT,
+	MSM_CAMERA_SCENE_MODE_SPORTS,
+	MSM_CAMERA_SCENE_MODE_ANTISHAKE,
+	MSM_CAMERA_SCENE_MODE_FLOWERS,
+	MSM_CAMERA_SCENE_MODE_CANDLELIGHT,
+	MSM_CAMERA_SCENE_MODE_FIREWORKS,
+	MSM_CAMERA_SCENE_MODE_PARTY,
+	MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_THEATRE,
+	MSM_CAMERA_SCENE_MODE_ACTION,
+	MSM_CAMERA_SCENE_MODE_AR,
+	MSM_CAMERA_SCENE_MODE_FACE_PRIORITY,
+	MSM_CAMERA_SCENE_MODE_BARCODE,
+	MSM_CAMERA_SCENE_MODE_HDR,
+	MSM_CAMERA_SCENE_MODE_MAX
+};
+
+enum csid_cfg_type_t {
+	CSID_INIT,
+	CSID_CFG,
+	CSID_TESTMODE_CFG,
+	CSID_RELEASE,
+};
+
+enum csiphy_cfg_type_t {
+	CSIPHY_INIT,
+	CSIPHY_CFG,
+	CSIPHY_RELEASE,
+};
+
+enum camera_vreg_type {
+	VREG_TYPE_DEFAULT,
+	VREG_TYPE_CUSTOM,
+};
+
+enum sensor_af_t {
+	SENSOR_AF_FOCUSSED,
+	SENSOR_AF_NOT_FOCUSSED,
+};
+
+enum cci_i2c_master_t {
+	MASTER_0,
+	MASTER_1,
+	MASTER_MAX,
+};
+
+struct msm_camera_i2c_array_write_config {
+	struct msm_camera_i2c_reg_setting conf_array;
+	uint16_t slave_addr;
+};
+
+struct msm_camera_i2c_read_config {
+	uint16_t slave_addr;
+	uint16_t reg_addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t data;
+};
+
+struct msm_camera_csi2_params {
+	struct msm_camera_csid_params csid_params;
+	struct msm_camera_csiphy_params csiphy_params;
+	uint8_t csi_clk_scale_enable;
+};
+
+struct msm_camera_csi_lane_params {
+	uint16_t csi_lane_assign;
+	uint16_t csi_lane_mask;
+};
+
+struct csi_lane_params_t {
+	uint16_t csi_lane_assign;
+	uint8_t csi_lane_mask;
+	uint8_t csi_if;
+	int8_t csid_core[2];
+	uint8_t csi_phy_sel;
+};
+
+struct msm_sensor_info_t {
+	char     sensor_name[MAX_SENSOR_NAME];
+	uint32_t session_id;
+	int32_t  subdev_id[SUB_MODULE_MAX];
+	int32_t  subdev_intf[SUB_MODULE_MAX];
+	uint8_t  is_mount_angle_valid;
+	uint32_t sensor_mount_angle;
+	int modes_supported;
+	enum camb_position_t position;
+};
+
+struct camera_vreg_t {
+	const char *reg_name;
+	int min_voltage;
+	int max_voltage;
+	int op_mode;
+	uint32_t delay;
+	const char *custom_vreg_name;
+	enum camera_vreg_type type;
+};
+
+struct sensorb_cfg_data {
+	int cfgtype;
+	union {
+		struct msm_sensor_info_t      sensor_info;
+		struct msm_sensor_init_params sensor_init_params;
+		void                         *setting;
+		struct msm_sensor_i2c_sync_params sensor_i2c_sync_params;
+	} cfg;
+};
+
+struct csid_cfg_data {
+	enum csid_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		struct msm_camera_csid_params *csid_params;
+		struct msm_camera_csid_testmode_parms *csid_testmode_params;
+	} cfg;
+};
+
+struct csiphy_cfg_data {
+	enum csiphy_cfg_type_t cfgtype;
+	union {
+		struct msm_camera_csiphy_params __user *csiphy_params;
+		struct msm_camera_csi_lane_params *csi_lane_params;
+	} cfg;
+};
+
+enum eeprom_cfg_type_t {
+	CFG_EEPROM_GET_INFO,
+	CFG_EEPROM_GET_CAL_DATA,
+	CFG_EEPROM_READ_CAL_DATA,
+	CFG_EEPROM_WRITE_DATA,
+	CFG_EEPROM_GET_MM_INFO,
+	CFG_EEPROM_INIT,
+};
+
+struct eeprom_get_t {
+	uint32_t num_bytes;
+};
+
+struct eeprom_read_t {
+	uint8_t *dbuffer;
+	uint32_t num_bytes;
+};
+
+struct eeprom_write_t {
+	uint8_t *dbuffer;
+	uint32_t num_bytes;
+};
+
+struct eeprom_get_cmm_t {
+	uint32_t cmm_support;
+	uint32_t cmm_compression;
+	uint32_t cmm_size;
+};
+
+struct msm_eeprom_info_t {
+	struct msm_sensor_power_setting_array *power_setting_array;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	struct msm_eeprom_memory_map_array *mem_map_array;
+};
+
+struct msm_ir_led_cfg_data_t {
+	enum msm_ir_led_cfg_type_t cfg_type;
+	int32_t pwm_duty_on_ns;
+	int32_t pwm_period_ns;
+};
+
+struct msm_ir_cut_cfg_data_t {
+	enum msm_ir_cut_cfg_type_t cfg_type;
+};
+
+struct msm_laser_led_cfg_data_t {
+	enum msm_laser_led_cfg_type_t cfg_type;
+	void __user                   *setting;
+	void __user                   *debug_reg;
+	uint32_t                      debug_reg_size;
+	uint16_t                      i2c_addr;
+	enum i2c_freq_mode_t          i2c_freq_mode;
+};
+
+struct msm_eeprom_cfg_data {
+	enum eeprom_cfg_type_t cfgtype;
+	uint8_t is_supported;
+	union {
+		char eeprom_name[MAX_EEPROM_NAME];
+		struct eeprom_get_t get_data;
+		struct eeprom_read_t read_data;
+		struct eeprom_write_t write_data;
+		struct eeprom_get_cmm_t get_cmm_data;
+		struct msm_eeprom_info_t eeprom_info;
+	} cfg;
+};
+
+enum msm_sensor_cfg_type_t {
+	CFG_SET_SLAVE_INFO,
+	CFG_SLAVE_READ_I2C,
+	CFG_WRITE_I2C_ARRAY,
+	CFG_SLAVE_WRITE_I2C_ARRAY,
+	CFG_WRITE_I2C_SEQ_ARRAY,
+	CFG_POWER_UP,
+	CFG_POWER_DOWN,
+	CFG_SET_STOP_STREAM_SETTING,
+	CFG_GET_SENSOR_INFO,
+	CFG_GET_SENSOR_INIT_PARAMS,
+	CFG_SET_INIT_SETTING,
+	CFG_SET_RESOLUTION,
+	CFG_SET_STOP_STREAM,
+	CFG_SET_START_STREAM,
+	CFG_SET_SATURATION,
+	CFG_SET_CONTRAST,
+	CFG_SET_SHARPNESS,
+	CFG_SET_ISO,
+	CFG_SET_EXPOSURE_COMPENSATION,
+	CFG_SET_ANTIBANDING,
+	CFG_SET_BESTSHOT_MODE,
+	CFG_SET_EFFECT,
+	CFG_SET_WHITE_BALANCE,
+	CFG_SET_AUTOFOCUS,
+	CFG_CANCEL_AUTOFOCUS,
+	CFG_SET_STREAM_TYPE,
+	CFG_SET_I2C_SYNC_PARAM,
+	CFG_WRITE_I2C_ARRAY_ASYNC,
+	CFG_WRITE_I2C_ARRAY_SYNC,
+	CFG_WRITE_I2C_ARRAY_SYNC_BLOCK,
+};
+
+enum msm_actuator_cfg_type_t {
+	CFG_GET_ACTUATOR_INFO,
+	CFG_SET_ACTUATOR_INFO,
+	CFG_SET_DEFAULT_FOCUS,
+	CFG_MOVE_FOCUS,
+	CFG_SET_POSITION,
+	CFG_ACTUATOR_POWERDOWN,
+	CFG_ACTUATOR_POWERUP,
+	CFG_ACTUATOR_INIT,
+};
+
+struct msm_ois_opcode {
+	uint32_t prog;
+	uint32_t coeff;
+	uint32_t pheripheral;
+	uint32_t memory;
+};
+
+enum msm_ois_cfg_type_t {
+	CFG_OIS_INIT,
+	CFG_OIS_POWERDOWN,
+	CFG_OIS_POWERUP,
+	CFG_OIS_CONTROL,
+	CFG_OIS_I2C_WRITE_SEQ_TABLE,
+};
+
+enum msm_ois_cfg_download_type_t {
+	CFG_OIS_DOWNLOAD,
+	CFG_OIS_DATA_CONFIG,
+};
+
+enum msm_ois_i2c_operation {
+	MSM_OIS_WRITE = 0,
+	MSM_OIS_POLL,
+	MSM_OIS_READ,
+};
+#define MSM_OIS_READ MSM_OIS_READ
+
+struct reg_settings_ois_t {
+	uint16_t reg_addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	uint32_t reg_data;
+	enum msm_camera_i2c_data_type data_type;
+	enum msm_ois_i2c_operation i2c_operation;
+	uint32_t delay;
+};
+
+struct msm_ois_params_t {
+	uint16_t data_size;
+	uint16_t setting_size;
+	uint32_t i2c_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type i2c_addr_type;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	struct reg_settings_ois_t __user *settings;
+};
+
+struct msm_ois_set_info_t {
+	struct msm_ois_params_t ois_params;
+};
+
+struct msm_actuator_move_params_t {
+	int8_t dir;
+	int8_t sign_dir;
+	int16_t dest_step_pos;
+	int32_t num_steps;
+	uint16_t curr_lens_pos;
+	struct damping_params_t __user *ringing_params;
+};
+
+struct msm_actuator_tuning_params_t {
+	int16_t initial_code;
+	uint16_t pwd_step;
+	uint16_t region_size;
+	uint32_t total_steps;
+	struct region_params_t __user *region_params;
+};
+
+struct park_lens_data_t {
+	uint32_t damping_step;
+	uint32_t damping_delay;
+	uint32_t hw_params;
+	uint32_t max_step;
+};
+
+struct msm_actuator_params_t {
+	enum actuator_type act_type;
+	uint8_t reg_tbl_size;
+	uint16_t data_size;
+	uint16_t init_setting_size;
+	uint32_t i2c_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type i2c_addr_type;
+	enum msm_camera_i2c_data_type i2c_data_type;
+	struct msm_actuator_reg_params_t __user *reg_tbl_params;
+	struct reg_settings_t __user *init_settings;
+	struct park_lens_data_t park_lens;
+};
+
+struct msm_actuator_set_info_t {
+	struct msm_actuator_params_t actuator_params;
+	struct msm_actuator_tuning_params_t af_tuning_params;
+};
+
+struct msm_actuator_get_info_t {
+	uint32_t focal_length_num;
+	uint32_t focal_length_den;
+	uint32_t f_number_num;
+	uint32_t f_number_den;
+	uint32_t f_pix_num;
+	uint32_t f_pix_den;
+	uint32_t total_f_dist_num;
+	uint32_t total_f_dist_den;
+	uint32_t hor_view_angle_num;
+	uint32_t hor_view_angle_den;
+	uint32_t ver_view_angle_num;
+	uint32_t ver_view_angle_den;
+};
+
+enum af_camera_name {
+	ACTUATOR_MAIN_CAM_0,
+	ACTUATOR_MAIN_CAM_1,
+	ACTUATOR_MAIN_CAM_2,
+	ACTUATOR_MAIN_CAM_3,
+	ACTUATOR_MAIN_CAM_4,
+	ACTUATOR_MAIN_CAM_5,
+	ACTUATOR_WEB_CAM_0,
+	ACTUATOR_WEB_CAM_1,
+	ACTUATOR_WEB_CAM_2,
+};
+
+struct msm_ois_slave_info {
+	char ois_name[MAX_OIS_NAME_SIZE];
+	uint32_t i2c_addr;
+	struct msm_ois_opcode opcode;
+};
+struct msm_ois_cfg_data {
+	int cfgtype;
+	union {
+		struct msm_ois_set_info_t set_info;
+		struct msm_camera_i2c_seq_reg_setting *settings;
+	} cfg;
+};
+
+struct msm_ois_cfg_download_data {
+	int cfgtype;
+	struct msm_ois_slave_info slave_info;
+};
+
+struct msm_actuator_set_position_t {
+	uint16_t number_of_steps;
+	uint32_t hw_params;
+	uint16_t pos[MAX_NUMBER_OF_STEPS];
+	uint16_t delay[MAX_NUMBER_OF_STEPS];
+};
+
+struct msm_actuator_cfg_data {
+	int cfgtype;
+	uint8_t is_af_supported;
+	union {
+		struct msm_actuator_move_params_t move;
+		struct msm_actuator_set_info_t set_info;
+		struct msm_actuator_get_info_t get_info;
+		struct msm_actuator_set_position_t setpos;
+		enum af_camera_name cam_name;
+	} cfg;
+};
+
+enum msm_camera_led_config_t {
+	MSM_CAMERA_LED_OFF,
+	MSM_CAMERA_LED_LOW,
+	MSM_CAMERA_LED_HIGH,
+	MSM_CAMERA_LED_INIT,
+	MSM_CAMERA_LED_RELEASE,
+};
+
+struct msm_camera_led_cfg_t {
+	enum msm_camera_led_config_t cfgtype;
+	int32_t torch_current[MAX_LED_TRIGGERS];
+	int32_t flash_current[MAX_LED_TRIGGERS];
+	int32_t flash_duration[MAX_LED_TRIGGERS];
+};
+
+struct msm_flash_init_info_t {
+	enum msm_flash_driver_type flash_driver_type;
+	uint32_t slave_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	struct msm_sensor_power_setting_array __user *power_setting_array;
+	struct msm_camera_i2c_reg_setting_array __user *settings;
+};
+
+struct msm_flash_cfg_data_t {
+	enum msm_flash_cfg_type_t cfg_type;
+	int32_t flash_current[MAX_LED_TRIGGERS];
+	int32_t flash_duration[MAX_LED_TRIGGERS];
+	union {
+		struct msm_flash_init_info_t *flash_init_info;
+		struct msm_camera_i2c_reg_setting_array __user *settings;
+	} cfg;
+};
+
+struct msm_flash_query_data_t {
+	int32_t flags;
+	int32_t query_type;
+	int32_t max_avail_curr;
+};
+
+/* sensor init structures and enums */
+enum msm_sensor_init_cfg_type_t {
+	CFG_SINIT_PROBE,
+	CFG_SINIT_PROBE_DONE,
+	CFG_SINIT_PROBE_WAIT_DONE,
+};
+
+struct sensor_init_cfg_data {
+	enum msm_sensor_init_cfg_type_t cfgtype;
+	struct msm_sensor_info_t        probed_info;
+	char                            entity_name[MAX_SENSOR_NAME];
+	union {
+		void *setting;
+	} cfg;
+};
+
+#define VIDIOC_MSM_SENSOR_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data)
+
+#define VIDIOC_MSM_SENSOR_RELEASE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 2)
+
+#define VIDIOC_MSM_SENSOR_GET_SUBDEV_ID \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t)
+
+#define VIDIOC_MSM_CSIPHY_IO_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csiphy_cfg_data)
+
+#define VIDIOC_MSM_CSID_IO_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csid_cfg_data)
+
+#define VIDIOC_MSM_ACTUATOR_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data)
+
+#define VIDIOC_MSM_FLASH_LED_DATA_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_led_cfg_t)
+
+#define VIDIOC_MSM_EEPROM_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_eeprom_cfg_data)
+
+#define VIDIOC_MSM_SENSOR_GET_AF_STATUS \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, uint32_t)
+
+#define VIDIOC_MSM_SENSOR_INIT_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct sensor_init_cfg_data)
+
+#define VIDIOC_MSM_OIS_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_ois_cfg_data)
+
+#define VIDIOC_MSM_FLASH_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_flash_cfg_data_t)
+
+#define VIDIOC_MSM_OIS_CFG_DOWNLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_ois_cfg_download_data)
+
+#define VIDIOC_MSM_FLASH_QUERY_DATA \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_flash_query_data_t)
+
+#define VIDIOC_MSM_IR_LED_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_led_cfg_data_t)
+
+#define VIDIOC_MSM_IR_CUT_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t)
+
+#define VIDIOC_MSM_LASER_LED_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t)
+
+#endif
+
diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h
new file mode 100644
index 0000000..693fd21
--- /dev/null
+++ b/include/uapi/media/msm_camera.h
@@ -0,0 +1,2231 @@
+/* Copyright (c) 2009-2012, 2014-2016, 2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __UAPI_MSM_CAMERA_H
+#define __UAPI_MSM_CAMERA_H
+
+#define CAM_API_V1
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/media.h>
+
+#include <linux/msm_ion.h>
+
+#define BIT(nr)   (1UL << (nr))
+
+#define MSM_CAM_IOCTL_MAGIC 'm'
+
+#define MAX_SERVER_PAYLOAD_LENGTH 8192
+
+#define MSM_CAM_IOCTL_GET_SENSOR_INFO \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *)
+
+#define MSM_CAM_IOCTL_REGISTER_PMEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 2, struct msm_pmem_info *)
+
+#define MSM_CAM_IOCTL_UNREGISTER_PMEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 3, unsigned int)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 4, struct msm_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_VFE  \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 5, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_STATS \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 6, struct msm_camera_stats_event_ctrl *)
+
+#define MSM_CAM_IOCTL_GETFRAME \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 7, struct msm_camera_get_frame *)
+
+#define MSM_CAM_IOCTL_ENABLE_VFE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 8, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_CTRL_CMD_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 9, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_CMD \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 10, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_DISABLE_VFE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 11, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_PAD_REG_RESET2 \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 12, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_VFE_APPS_RESET \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 13, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 14, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_STATS_BUFFER \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 15, struct msm_stats_buf *)
+
+#define MSM_CAM_IOCTL_AXI_CONFIG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 16, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_PICTURE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 17, struct msm_frame *)
+
+#define MSM_CAM_IOCTL_SET_CROP \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *)
+
+#define MSM_CAM_IOCTL_PICT_PP \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *)
+
+#define MSM_CAM_IOCTL_PICT_PP_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *)
+
+#define MSM_CAM_IOCTL_SENSOR_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *)
+
+#define MSM_CAM_IOCTL_FLASH_LED_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 22, unsigned int *)
+
+#define MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME \
+	_IO(MSM_CAM_IOCTL_MAGIC, 23)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND_2 \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_AF_CTRL \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 25, struct msm_ctrl_cmt_t *)
+
+#define MSM_CAM_IOCTL_AF_CTRL_DONE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 26, struct msm_ctrl_cmt_t *)
+
+#define MSM_CAM_IOCTL_CONFIG_VPE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 27, struct msm_camera_vpe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_AXI_VPE_CONFIG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 28, struct msm_camera_vpe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_STROBE_FLASH_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 29, uint32_t *)
+
+#define MSM_CAM_IOCTL_STROBE_FLASH_CHARGE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 30, uint32_t *)
+
+#define MSM_CAM_IOCTL_STROBE_FLASH_RELEASE \
+	_IO(MSM_CAM_IOCTL_MAGIC, 31)
+
+#define MSM_CAM_IOCTL_FLASH_CTRL \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 32, struct flash_ctrl_data *)
+
+#define MSM_CAM_IOCTL_ERROR_CONFIG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 33, uint32_t *)
+
+#define MSM_CAM_IOCTL_ABORT_CAPTURE \
+	_IO(MSM_CAM_IOCTL_MAGIC, 34)
+
+#define MSM_CAM_IOCTL_SET_FD_ROI \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 35, struct fd_roi_info *)
+
+#define MSM_CAM_IOCTL_GET_CAMERA_INFO \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 36, struct msm_camera_info *)
+
+#define MSM_CAM_IOCTL_UNBLOCK_POLL_PIC_FRAME \
+	_IO(MSM_CAM_IOCTL_MAGIC, 37)
+
+#define MSM_CAM_IOCTL_RELEASE_PIC_BUFFER \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 38, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_PUT_ST_FRAME \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *)
+
+#define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event_and_payload)
+
+#define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *)
+
+#define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 42, struct msm_actuator_cfg_data *)
+
+#define MSM_CAM_IOCTL_MCTL_POST_PROC \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_mctl_post_proc_cmd *)
+
+#define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_cam_evt_divert_frame *)
+
+#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *)
+
+#define MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_pp_frame *)
+
+#define MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 47, struct v4l2_control)
+
+#define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_queryctrl)
+
+#define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 49, struct timeval *)
+
+#define MSM_CAM_IOCTL_SET_VFE_OUTPUT_TYPE \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 50, uint32_t *)
+
+#define MSM_CAM_IOCTL_MCTL_DIVERT_DONE \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 51, struct msm_cam_evt_divert_frame *)
+
+#define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *)
+
+#define MSM_CAM_IOCTL_EEPROM_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
+
+#define MSM_CAM_IOCTL_ISPIF_IO_CFG \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
+
+#define MSM_CAM_IOCTL_STATS_REQBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *)
+
+#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *)
+
+#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+
+#define MSM_CAM_IOCTL_SET_MCTL_SDEV \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 58, struct msm_mctl_set_sdev_data *)
+
+#define MSM_CAM_IOCTL_UNSET_MCTL_SDEV \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 59, struct msm_mctl_set_sdev_data *)
+
+#define MSM_CAM_IOCTL_GET_INST_HANDLE \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *)
+
+#define MSM_CAM_IOCTL_STATS_UNREG_BUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *)
+
+#define MSM_CAM_IOCTL_CSIC_IO_CFG \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 62, struct csic_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSID_IO_CFG \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 63, struct csid_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSIPHY_IO_CFG \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 64, struct csiphy_cfg_data *)
+
+#define MSM_CAM_IOCTL_OEM \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 65, struct sensor_cfg_data *)
+
+#define MSM_CAM_IOCTL_AXI_INIT \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 66, uint8_t *)
+
+#define MSM_CAM_IOCTL_AXI_RELEASE \
+	_IO(MSM_CAM_IOCTL_MAGIC, 67)
+
+struct v4l2_event_and_payload {
+	struct v4l2_event evt;
+	uint32_t payload_length;
+	uint32_t transaction_id;
+	void *payload;
+};
+
+struct msm_stats_reqbuf {
+	int num_buf;		/* how many buffers requested */
+	int stats_type;	/* stats type */
+};
+
+struct msm_stats_flush_bufq {
+	int stats_type;	/* enum msm_stats_enum_type */
+};
+
+struct msm_mctl_pp_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+struct msm_mctl_post_proc_cmd {
+	int32_t type;
+	struct msm_mctl_pp_cmd cmd;
+};
+
+#define MSM_CAMERA_LED_OFF  0
+#define MSM_CAMERA_LED_LOW  1
+#define MSM_CAMERA_LED_HIGH 2
+#define MSM_CAMERA_LED_INIT 3
+#define MSM_CAMERA_LED_RELEASE 4
+
+#define MSM_CAMERA_STROBE_FLASH_NONE 0
+#define MSM_CAMERA_STROBE_FLASH_XENON 1
+
+#define MSM_MAX_CAMERA_SENSORS  5
+#define MAX_SENSOR_NAME 32
+#define MAX_CAM_NAME_SIZE 32
+#define MAX_ACT_MOD_NAME_SIZE 32
+#define MAX_ACT_NAME_SIZE 32
+#define NUM_ACTUATOR_DIR 2
+#define MAX_ACTUATOR_SCENARIO 8
+#define MAX_ACTUATOR_REGION 5
+#define MAX_ACTUATOR_INIT_SET 12
+#define MAX_ACTUATOR_TYPE_SIZE 32
+#define MAX_ACTUATOR_REG_TBL_SIZE 8
+
+
+#define MSM_MAX_CAMERA_CONFIGS 2
+
+#define PP_SNAP  0x01
+#define PP_RAW_SNAP ((0x01)<<1)
+#define PP_PREV  ((0x01)<<2)
+#define PP_THUMB ((0x01)<<3)
+#define PP_MASK		(PP_SNAP|PP_RAW_SNAP|PP_PREV|PP_THUMB)
+
+#define MSM_CAM_CTRL_CMD_DONE  0
+#define MSM_CAM_SENSOR_VFE_CMD 1
+
+/* Should be same as VIDEO_MAX_PLANES in videodev2.h */
+#define MAX_PLANES 8
+
+/*****************************************************
+ *  structure
+ *****************************************************/
+
+/* define five type of structures for userspace <==> kernel
+ * space communication:
+ * command 1 - 2 are from userspace ==> kernel
+ * command 3 - 4 are from kernel ==> userspace
+ *
+ * 1. control command: control command(from control thread),
+ *                     control status (from config thread);
+ */
+struct msm_ctrl_cmd {
+	uint16_t type;
+	uint16_t length;
+	void *value;
+	uint16_t status;
+	uint32_t timeout_ms;
+	int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */
+	int vnode_id;  /* video dev id. Can we overload resp_fd? */
+	int queue_idx;
+	uint32_t evt_id;
+	uint32_t stream_type; /* used to pass value to qcamera server */
+	int config_ident; /*used as identifier for config node*/
+};
+
+struct msm_cam_evt_msg {
+	unsigned short type;	/* 1 == event (RPC), 0 == message (adsp) */
+	unsigned short msg_id;
+	unsigned int len;	/* size in, number of bytes out */
+	uint32_t frame_id;
+	void *data;
+	struct timespec timestamp;
+};
+
+struct msm_pp_frame_sp {
+	/* phy addr of the buffer */
+	unsigned long  phy_addr;
+	uint32_t       y_off;
+	uint32_t       cbcr_off;
+	/* buffer length */
+	uint32_t       length;
+	int32_t        fd;
+	uint32_t       addr_offset;
+	/* mapped addr */
+	unsigned long  vaddr;
+};
+
+struct msm_pp_frame_mp {
+	/* phy addr of the plane */
+	unsigned long  phy_addr;
+	/* offset of plane data */
+	uint32_t       data_offset;
+	/* plane length */
+	uint32_t       length;
+	int32_t        fd;
+	uint32_t       addr_offset;
+	/* mapped addr */
+	unsigned long  vaddr;
+};
+
+struct msm_pp_frame {
+	uint32_t       handle; /* stores vb cookie */
+	uint32_t       frame_id;
+	unsigned short buf_idx;
+	int            path;
+	unsigned short image_type;
+	unsigned short num_planes; /* 1 for sp */
+	struct timeval timestamp;
+	union {
+		struct msm_pp_frame_sp sp;
+		struct msm_pp_frame_mp mp[MAX_PLANES];
+	};
+	int node_type;
+	uint32_t inst_handle;
+};
+
+struct msm_pp_crop {
+	uint32_t  src_x;
+	uint32_t  src_y;
+	uint32_t  src_w;
+	uint32_t  src_h;
+	uint32_t  dst_x;
+	uint32_t  dst_y;
+	uint32_t  dst_w;
+	uint32_t  dst_h;
+	uint8_t update_flag;
+};
+
+struct msm_mctl_pp_frame_cmd {
+	uint32_t cookie;
+	uint8_t  vpe_output_action;
+	struct msm_pp_frame src_frame;
+	struct msm_pp_frame dest_frame;
+	struct msm_pp_crop crop;
+	int path;
+};
+
+struct msm_cam_evt_divert_frame {
+	unsigned short image_mode;
+	unsigned short op_mode;
+	unsigned short inst_idx;
+	unsigned short node_idx;
+	struct msm_pp_frame frame;
+	int            do_pp;
+};
+
+struct msm_mctl_pp_cmd_ack_event {
+	uint32_t cmd;        /* VPE_CMD_ZOOM? */
+	int      status;     /* 0 done, < 0 err */
+	uint32_t cookie;     /* daemon's cookie */
+};
+
+struct msm_mctl_pp_event_info {
+	int32_t  event;
+	union {
+		struct msm_mctl_pp_cmd_ack_event ack;
+	};
+};
+
+struct msm_isp_event_ctrl {
+	unsigned short resptype;
+	union {
+		struct msm_cam_evt_msg isp_msg;
+		struct msm_ctrl_cmd ctrl;
+		struct msm_cam_evt_divert_frame div_frame;
+		struct msm_mctl_pp_event_info pp_event_info;
+	} isp_data;
+};
+
+#define MSM_CAM_RESP_CTRL              0
+#define MSM_CAM_RESP_STAT_EVT_MSG      1
+#define MSM_CAM_RESP_STEREO_OP_1       2
+#define MSM_CAM_RESP_STEREO_OP_2       3
+#define MSM_CAM_RESP_V4L2              4
+#define MSM_CAM_RESP_DIV_FRAME_EVT_MSG 5
+#define MSM_CAM_RESP_DONE_EVENT        6
+#define MSM_CAM_RESP_MCTL_PP_EVENT     7
+#define MSM_CAM_RESP_MAX               8
+
+#define MSM_CAM_APP_NOTIFY_EVENT  0
+#define MSM_CAM_APP_NOTIFY_ERROR_EVENT  1
+
+/* this one is used to send ctrl/status up to config thread */
+
+struct msm_stats_event_ctrl {
+	/* 0 - ctrl_cmd from control thread,
+	 * 1 - stats/event kernel,
+	 * 2 - V4L control or read request
+	 */
+	int resptype;
+	int timeout_ms;
+	struct msm_ctrl_cmd ctrl_cmd;
+	/* struct  vfe_event_t  stats_event; */
+	struct msm_cam_evt_msg stats_event;
+};
+
+/* 2. config command: config command(from config thread); */
+struct msm_camera_cfg_cmd {
+	/* what to config:
+	 * 1 - sensor config, 2 - vfe config
+	 */
+	uint16_t cfg_type;
+
+	/* sensor config type */
+	uint16_t cmd_type;
+	uint16_t queue;
+	uint16_t length;
+	void *value;
+};
+
+#define CMD_GENERAL			0
+#define CMD_AXI_CFG_OUT1		1
+#define CMD_AXI_CFG_SNAP_O1_AND_O2	2
+#define CMD_AXI_CFG_OUT2		3
+#define CMD_PICT_T_AXI_CFG		4
+#define CMD_PICT_M_AXI_CFG		5
+#define CMD_RAW_PICT_AXI_CFG		6
+
+#define CMD_FRAME_BUF_RELEASE		7
+#define CMD_PREV_BUF_CFG		8
+#define CMD_SNAP_BUF_RELEASE		9
+#define CMD_SNAP_BUF_CFG		10
+#define CMD_STATS_DISABLE		11
+#define CMD_STATS_AEC_AWB_ENABLE	12
+#define CMD_STATS_AF_ENABLE		13
+#define CMD_STATS_AEC_ENABLE		14
+#define CMD_STATS_AWB_ENABLE		15
+#define CMD_STATS_ENABLE		16
+
+#define CMD_STATS_AXI_CFG		17
+#define CMD_STATS_AEC_AXI_CFG		18
+#define CMD_STATS_AF_AXI_CFG		19
+#define CMD_STATS_AWB_AXI_CFG		20
+#define CMD_STATS_RS_AXI_CFG		21
+#define CMD_STATS_CS_AXI_CFG		22
+#define CMD_STATS_IHIST_AXI_CFG		23
+#define CMD_STATS_SKIN_AXI_CFG		24
+
+#define CMD_STATS_BUF_RELEASE		25
+#define CMD_STATS_AEC_BUF_RELEASE	26
+#define CMD_STATS_AF_BUF_RELEASE	27
+#define CMD_STATS_AWB_BUF_RELEASE	28
+#define CMD_STATS_RS_BUF_RELEASE	29
+#define CMD_STATS_CS_BUF_RELEASE	30
+#define CMD_STATS_IHIST_BUF_RELEASE	31
+#define CMD_STATS_SKIN_BUF_RELEASE	32
+
+#define UPDATE_STATS_INVALID		33
+#define CMD_AXI_CFG_SNAP_GEMINI		34
+#define CMD_AXI_CFG_SNAP		35
+#define CMD_AXI_CFG_PREVIEW		36
+#define CMD_AXI_CFG_VIDEO		37
+
+#define CMD_STATS_IHIST_ENABLE 38
+#define CMD_STATS_RS_ENABLE 39
+#define CMD_STATS_CS_ENABLE 40
+#define CMD_VPE 41
+#define CMD_AXI_CFG_VPE 42
+#define CMD_AXI_CFG_ZSL 43
+#define CMD_AXI_CFG_SNAP_VPE 44
+#define CMD_AXI_CFG_SNAP_THUMB_VPE 45
+
+#define CMD_CONFIG_PING_ADDR 46
+#define CMD_CONFIG_PONG_ADDR 47
+#define CMD_CONFIG_FREE_BUF_ADDR 48
+#define CMD_AXI_CFG_ZSL_ALL_CHNLS 49
+#define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
+#define CMD_VFE_BUFFER_RELEASE 51
+#define CMD_VFE_PROCESS_IRQ 52
+#define CMD_STATS_BG_ENABLE 53
+#define CMD_STATS_BF_ENABLE 54
+#define CMD_STATS_BHIST_ENABLE 55
+#define CMD_STATS_BG_BUF_RELEASE 56
+#define CMD_STATS_BF_BUF_RELEASE 57
+#define CMD_STATS_BHIST_BUF_RELEASE 58
+#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59
+#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
+#define CMD_STATS_BE_ENABLE 61
+#define CMD_STATS_BE_BUF_RELEASE 62
+
+#define CMD_AXI_CFG_PRIM               BIT(8)
+#define CMD_AXI_CFG_PRIM_ALL_CHNLS     BIT(9)
+#define CMD_AXI_CFG_SEC                BIT(10)
+#define CMD_AXI_CFG_SEC_ALL_CHNLS      BIT(11)
+#define CMD_AXI_CFG_TERT1              BIT(12)
+#define CMD_AXI_CFG_TERT2              BIT(13)
+
+#define CMD_AXI_START  0xE1
+#define CMD_AXI_STOP   0xE2
+#define CMD_AXI_RESET  0xE3
+#define CMD_AXI_ABORT  0xE4
+
+
+
+#define AXI_CMD_PREVIEW      BIT(0)
+#define AXI_CMD_CAPTURE      BIT(1)
+#define AXI_CMD_RECORD       BIT(2)
+#define AXI_CMD_ZSL          BIT(3)
+#define AXI_CMD_RAW_CAPTURE  BIT(4)
+#define AXI_CMD_LIVESHOT     BIT(5)
+
+/* vfe config command: config command(from config thread)*/
+struct msm_vfe_cfg_cmd {
+	int cmd_type;
+	uint16_t length;
+	void *value;
+};
+
+struct msm_vpe_cfg_cmd {
+	int cmd_type;
+	uint16_t length;
+	void *value;
+};
+
+#define MAX_CAMERA_ENABLE_NAME_LEN 32
+struct camera_enable_cmd {
+	char name[MAX_CAMERA_ENABLE_NAME_LEN];
+};
+
+#define MSM_PMEM_OUTPUT1		0
+#define MSM_PMEM_OUTPUT2		1
+#define MSM_PMEM_OUTPUT1_OUTPUT2	2
+#define MSM_PMEM_THUMBNAIL		3
+#define MSM_PMEM_MAINIMG		4
+#define MSM_PMEM_RAW_MAINIMG		5
+#define MSM_PMEM_AEC_AWB		6
+#define MSM_PMEM_AF			7
+#define MSM_PMEM_AEC			8
+#define MSM_PMEM_AWB			9
+#define MSM_PMEM_RS			10
+#define MSM_PMEM_CS			11
+#define MSM_PMEM_IHIST			12
+#define MSM_PMEM_SKIN			13
+#define MSM_PMEM_VIDEO			14
+#define MSM_PMEM_PREVIEW		15
+#define MSM_PMEM_VIDEO_VPE		16
+#define MSM_PMEM_C2D			17
+#define MSM_PMEM_MAINIMG_VPE    18
+#define MSM_PMEM_THUMBNAIL_VPE  19
+#define MSM_PMEM_BAYER_GRID		20
+#define MSM_PMEM_BAYER_FOCUS	21
+#define MSM_PMEM_BAYER_HIST		22
+#define MSM_PMEM_BAYER_EXPOSURE 23
+#define MSM_PMEM_MAX            24
+
+#define STAT_AEAW			0
+#define STAT_AEC			1
+#define STAT_AF				2
+#define STAT_AWB			3
+#define STAT_RS				4
+#define STAT_CS				5
+#define STAT_IHIST			6
+#define STAT_SKIN			7
+#define STAT_BG				8
+#define STAT_BF				9
+#define STAT_BE				10
+#define STAT_BHIST			11
+#define STAT_MAX			12
+
+#define FRAME_PREVIEW_OUTPUT1		0
+#define FRAME_PREVIEW_OUTPUT2		1
+#define FRAME_SNAPSHOT			2
+#define FRAME_THUMBNAIL			3
+#define FRAME_RAW_SNAPSHOT		4
+#define FRAME_MAX			5
+
+enum msm_stats_enum_type {
+	MSM_STATS_TYPE_AEC, /* legacy based AEC */
+	MSM_STATS_TYPE_AF,  /* legacy based AF */
+	MSM_STATS_TYPE_AWB, /* legacy based AWB */
+	MSM_STATS_TYPE_RS,  /* legacy based RS */
+	MSM_STATS_TYPE_CS,  /* legacy based CS */
+	MSM_STATS_TYPE_IHIST,   /* legacy based HIST */
+	MSM_STATS_TYPE_SKIN,    /* legacy based SKIN */
+	MSM_STATS_TYPE_BG,  /* Bayer Grids */
+	MSM_STATS_TYPE_BF,  /* Bayer Focus */
+	MSM_STATS_TYPE_BE,  /* Bayer Exposure*/
+	MSM_STATS_TYPE_BHIST,   /* Bayer Hist */
+	MSM_STATS_TYPE_AE_AW,   /* legacy stats for vfe 2.x*/
+	MSM_STATS_TYPE_COMP, /* Composite stats */
+	MSM_STATS_TYPE_MAX  /* MAX */
+};
+
+struct msm_stats_buf_info {
+	int type; /* msm_stats_enum_type */
+	int fd;
+	void *vaddr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint8_t active;
+	int buf_idx;
+};
+
+struct msm_pmem_info {
+	int type;
+	int fd;
+	void *vaddr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint8_t active;
+};
+
+struct outputCfg {
+	uint32_t height;
+	uint32_t width;
+
+	uint32_t window_height_firstline;
+	uint32_t window_height_lastline;
+};
+
+#define VIDEO_NODE 0
+#define MCTL_NODE 1
+
+#define OUTPUT_1	0
+#define OUTPUT_2	1
+#define OUTPUT_1_AND_2            2   /* snapshot only */
+#define OUTPUT_1_AND_3            3   /* video */
+#define CAMIF_TO_AXI_VIA_OUTPUT_2 4
+#define OUTPUT_1_AND_CAMIF_TO_AXI_VIA_OUTPUT_2 5
+#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 6
+#define OUTPUT_1_2_AND_3 7
+#define OUTPUT_ALL_CHNLS 8
+#define OUTPUT_VIDEO_ALL_CHNLS 9
+#define OUTPUT_ZSL_ALL_CHNLS 10
+#define LAST_AXI_OUTPUT_MODE_ENUM OUTPUT_ZSL_ALL_CHNLS
+
+#define OUTPUT_PRIM              BIT(8)
+#define OUTPUT_PRIM_ALL_CHNLS    BIT(9)
+#define OUTPUT_SEC               BIT(10)
+#define OUTPUT_SEC_ALL_CHNLS     BIT(11)
+#define OUTPUT_TERT1             BIT(12)
+#define OUTPUT_TERT2             BIT(13)
+
+
+
+#define MSM_FRAME_PREV_1	0
+#define MSM_FRAME_PREV_2	1
+#define MSM_FRAME_ENC		2
+
+#define OUTPUT_TYPE_P    BIT(0)
+#define OUTPUT_TYPE_T    BIT(1)
+#define OUTPUT_TYPE_S    BIT(2)
+#define OUTPUT_TYPE_V    BIT(3)
+#define OUTPUT_TYPE_L    BIT(4)
+#define OUTPUT_TYPE_ST_L BIT(5)
+#define OUTPUT_TYPE_ST_R BIT(6)
+#define OUTPUT_TYPE_ST_D BIT(7)
+#define OUTPUT_TYPE_R    BIT(8)
+#define OUTPUT_TYPE_R1   BIT(9)
+#define OUTPUT_TYPE_SAEC   BIT(10)
+#define OUTPUT_TYPE_SAFC   BIT(11)
+#define OUTPUT_TYPE_SAWB   BIT(12)
+#define OUTPUT_TYPE_IHST   BIT(13)
+#define OUTPUT_TYPE_CSTA   BIT(14)
+
+struct fd_roi_info {
+	void *info;
+	int info_len;
+};
+
+struct msm_mem_map_info {
+	uint32_t cookie;
+	uint32_t length;
+	uint32_t mem_type;
+};
+
+#define MSM_MEM_MMAP		0
+#define MSM_MEM_USERPTR		1
+#define MSM_PLANE_MAX		8
+#define MSM_PLANE_Y			0
+#define MSM_PLANE_UV		1
+
+struct msm_frame {
+	struct timespec ts;
+	int path;
+	int type;
+	unsigned long buffer;
+	uint32_t phy_offset;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	int fd;
+
+	void *cropinfo;
+	int croplen;
+	uint32_t error_code;
+	struct fd_roi_info roi_info;
+	uint32_t frame_id;
+	int stcam_quality_ind;
+	uint32_t stcam_conv_value;
+
+	struct ion_allocation_data ion_alloc;
+	struct ion_fd_data fd_data;
+	int ion_dev_fd;
+};
+
+enum msm_st_frame_packing {
+	SIDE_BY_SIDE_HALF,
+	SIDE_BY_SIDE_FULL,
+	TOP_DOWN_HALF,
+	TOP_DOWN_FULL,
+};
+
+struct msm_st_crop {
+	uint32_t in_w;
+	uint32_t in_h;
+	uint32_t out_w;
+	uint32_t out_h;
+};
+
+struct msm_st_half {
+	uint32_t buf_p0_off;
+	uint32_t buf_p1_off;
+	uint32_t buf_p0_stride;
+	uint32_t buf_p1_stride;
+	uint32_t pix_x_off;
+	uint32_t pix_y_off;
+	struct msm_st_crop stCropInfo;
+};
+
+struct msm_st_frame {
+	struct msm_frame buf_info;
+	int type;
+	enum msm_st_frame_packing packing;
+	struct msm_st_half L;
+	struct msm_st_half R;
+	int frame_id;
+};
+
+#define MSM_CAMERA_ERR_MASK (0xFFFFFFFF & 1)
+
+struct stats_buff {
+	unsigned long buff;
+	int fd;
+};
+
+struct msm_stats_buf {
+	uint8_t awb_ymin;
+	struct stats_buff aec;
+	struct stats_buff awb;
+	struct stats_buff af;
+	struct stats_buff be;
+	struct stats_buff ihist;
+	struct stats_buff rs;
+	struct stats_buff cs;
+	struct stats_buff skin;
+	int type;
+	uint32_t status_bits;
+	unsigned long buffer;
+	int fd;
+	int length;
+	struct ion_handle *handle;
+	uint32_t frame_id;
+	int buf_idx;
+};
+#define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
+/* video capture mode in VIDIOC_S_PARM */
+#define MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+1)
+/* extendedmode for video recording in VIDIOC_S_PARM */
+#define MSM_V4L2_EXT_CAPTURE_MODE_VIDEO \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+2)
+/* extendedmode for the full size main image in VIDIOC_S_PARM */
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAIN (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+3)
+/* extendedmode for the thumb nail image in VIDIOC_S_PARM */
+#define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4)
+/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5)
+/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6)
+/* raw image type */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7)
+/* RDI dump */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8)
+/* RDI dump 1 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
+/* RDI dump 2 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10)
+#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11)
+#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12)
+#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13)
+#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
+#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
+#define MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+19)
+
+
+#define MSM_V4L2_PID_MOTION_ISO              V4L2_CID_PRIVATE_BASE
+#define MSM_V4L2_PID_EFFECT                 (V4L2_CID_PRIVATE_BASE+1)
+#define MSM_V4L2_PID_HJR                    (V4L2_CID_PRIVATE_BASE+2)
+#define MSM_V4L2_PID_LED_MODE               (V4L2_CID_PRIVATE_BASE+3)
+#define MSM_V4L2_PID_PREP_SNAPSHOT          (V4L2_CID_PRIVATE_BASE+4)
+#define MSM_V4L2_PID_EXP_METERING           (V4L2_CID_PRIVATE_BASE+5)
+#define MSM_V4L2_PID_ISO                    (V4L2_CID_PRIVATE_BASE+6)
+#define MSM_V4L2_PID_CAM_MODE               (V4L2_CID_PRIVATE_BASE+7)
+#define MSM_V4L2_PID_LUMA_ADAPTATION	    (V4L2_CID_PRIVATE_BASE+8)
+#define MSM_V4L2_PID_BEST_SHOT              (V4L2_CID_PRIVATE_BASE+9)
+#define MSM_V4L2_PID_FOCUS_MODE	            (V4L2_CID_PRIVATE_BASE+10)
+#define MSM_V4L2_PID_BL_DETECTION           (V4L2_CID_PRIVATE_BASE+11)
+#define MSM_V4L2_PID_SNOW_DETECTION         (V4L2_CID_PRIVATE_BASE+12)
+#define MSM_V4L2_PID_CTRL_CMD               (V4L2_CID_PRIVATE_BASE+13)
+#define MSM_V4L2_PID_EVT_SUB_INFO           (V4L2_CID_PRIVATE_BASE+14)
+#define MSM_V4L2_PID_STROBE_FLASH           (V4L2_CID_PRIVATE_BASE+15)
+#define MSM_V4L2_PID_INST_HANDLE            (V4L2_CID_PRIVATE_BASE+16)
+#define MSM_V4L2_PID_MMAP_INST              (V4L2_CID_PRIVATE_BASE+17)
+#define MSM_V4L2_PID_PP_PLANE_INFO          (V4L2_CID_PRIVATE_BASE+18)
+#define MSM_V4L2_PID_MAX                    MSM_V4L2_PID_PP_PLANE_INFO
+
+/* camera operation mode for video recording - two frame output queues */
+#define MSM_V4L2_CAM_OP_DEFAULT         0
+/* camera operation mode for video recording - two frame output queues */
+#define MSM_V4L2_CAM_OP_PREVIEW         (MSM_V4L2_CAM_OP_DEFAULT+1)
+/* camera operation mode for video recording - two frame output queues */
+#define MSM_V4L2_CAM_OP_VIDEO           (MSM_V4L2_CAM_OP_DEFAULT+2)
+/* camera operation mode for standard shapshot - two frame output queues */
+#define MSM_V4L2_CAM_OP_CAPTURE         (MSM_V4L2_CAM_OP_DEFAULT+3)
+/* camera operation mode for zsl shapshot - three output queues */
+#define MSM_V4L2_CAM_OP_ZSL             (MSM_V4L2_CAM_OP_DEFAULT+4)
+/* camera operation mode for raw snapshot - one frame output queue */
+#define MSM_V4L2_CAM_OP_RAW             (MSM_V4L2_CAM_OP_DEFAULT+5)
+/* camera operation mode for jpeg snapshot - one frame output queue */
+#define MSM_V4L2_CAM_OP_JPEG_CAPTURE    (MSM_V4L2_CAM_OP_DEFAULT+6)
+
+
+#define MSM_V4L2_VID_CAP_TYPE	0
+#define MSM_V4L2_STREAM_ON		1
+#define MSM_V4L2_STREAM_OFF		2
+#define MSM_V4L2_SNAPSHOT		3
+#define MSM_V4L2_QUERY_CTRL		4
+#define MSM_V4L2_GET_CTRL		5
+#define MSM_V4L2_SET_CTRL		6
+#define MSM_V4L2_QUERY			7
+#define MSM_V4L2_GET_CROP		8
+#define MSM_V4L2_SET_CROP		9
+#define MSM_V4L2_OPEN			10
+#define MSM_V4L2_CLOSE			11
+#define MSM_V4L2_SET_CTRL_CMD	12
+#define MSM_V4L2_EVT_SUB_MASK	13
+#define MSM_V4L2_PRIVATE_CMD    14
+#define MSM_V4L2_MAX			15
+#define V4L2_CAMERA_EXIT		43
+
+struct crop_info {
+	void *info;
+	int len;
+};
+
+struct msm_postproc {
+	int ftnum;
+	struct msm_frame fthumnail;
+	int fmnum;
+	struct msm_frame fmain;
+};
+
+struct msm_snapshot_pp_status {
+	void *status;
+};
+
+#define CFG_SET_MODE			0
+#define CFG_SET_EFFECT			1
+#define CFG_START			2
+#define CFG_PWR_UP			3
+#define CFG_PWR_DOWN			4
+#define CFG_WRITE_EXPOSURE_GAIN		5
+#define CFG_SET_DEFAULT_FOCUS		6
+#define CFG_MOVE_FOCUS			7
+#define CFG_REGISTER_TO_REAL_GAIN	8
+#define CFG_REAL_TO_REGISTER_GAIN	9
+#define CFG_SET_FPS			10
+#define CFG_SET_PICT_FPS		11
+#define CFG_SET_BRIGHTNESS		12
+#define CFG_SET_CONTRAST		13
+#define CFG_SET_ZOOM			14
+#define CFG_SET_EXPOSURE_MODE		15
+#define CFG_SET_WB			16
+#define CFG_SET_ANTIBANDING		17
+#define CFG_SET_EXP_GAIN		18
+#define CFG_SET_PICT_EXP_GAIN		19
+#define CFG_SET_LENS_SHADING		20
+#define CFG_GET_PICT_FPS		21
+#define CFG_GET_PREV_L_PF		22
+#define CFG_GET_PREV_P_PL		23
+#define CFG_GET_PICT_L_PF		24
+#define CFG_GET_PICT_P_PL		25
+#define CFG_GET_AF_MAX_STEPS		26
+#define CFG_GET_PICT_MAX_EXP_LC		27
+#define CFG_SEND_WB_INFO    28
+#define CFG_SENSOR_INIT    29
+#define CFG_GET_3D_CALI_DATA 30
+#define CFG_GET_CALIB_DATA		31
+#define CFG_GET_OUTPUT_INFO		32
+#define CFG_GET_EEPROM_INFO		33
+#define CFG_GET_EEPROM_DATA		34
+#define CFG_SET_ACTUATOR_INFO		35
+#define CFG_GET_ACTUATOR_INFO           36
+/* TBD: QRD */
+#define CFG_SET_SATURATION            37
+#define CFG_SET_SHARPNESS             38
+#define CFG_SET_TOUCHAEC              39
+#define CFG_SET_AUTO_FOCUS            40
+#define CFG_SET_AUTOFLASH             41
+#define CFG_SET_EXPOSURE_COMPENSATION 42
+#define CFG_SET_ISO                   43
+#define CFG_START_STREAM              44
+#define CFG_STOP_STREAM               45
+#define CFG_GET_CSI_PARAMS            46
+#define CFG_POWER_UP                  47
+#define CFG_POWER_DOWN                48
+#define CFG_WRITE_I2C_ARRAY           49
+#define CFG_READ_I2C_ARRAY            50
+#define CFG_PCLK_CHANGE               51
+#define CFG_CONFIG_VREG_ARRAY         52
+#define CFG_CONFIG_CLK_ARRAY          53
+#define CFG_GPIO_OP                   54
+#define CFG_MAX                       55
+
+
+#define MOVE_NEAR	0
+#define MOVE_FAR	1
+
+#define SENSOR_PREVIEW_MODE		0
+#define SENSOR_SNAPSHOT_MODE		1
+#define SENSOR_RAW_SNAPSHOT_MODE	2
+#define SENSOR_HFR_60FPS_MODE 3
+#define SENSOR_HFR_90FPS_MODE 4
+#define SENSOR_HFR_120FPS_MODE 5
+
+#define SENSOR_QTR_SIZE			0
+#define SENSOR_FULL_SIZE		1
+#define SENSOR_QVGA_SIZE		2
+#define SENSOR_INVALID_SIZE		3
+
+#define CAMERA_EFFECT_OFF		0
+#define CAMERA_EFFECT_MONO		1
+#define CAMERA_EFFECT_NEGATIVE		2
+#define CAMERA_EFFECT_SOLARIZE		3
+#define CAMERA_EFFECT_SEPIA		4
+#define CAMERA_EFFECT_POSTERIZE		5
+#define CAMERA_EFFECT_WHITEBOARD	6
+#define CAMERA_EFFECT_BLACKBOARD	7
+#define CAMERA_EFFECT_AQUA		8
+#define CAMERA_EFFECT_EMBOSS		9
+#define CAMERA_EFFECT_SKETCH		10
+#define CAMERA_EFFECT_NEON		11
+#define CAMERA_EFFECT_FADED		12
+#define CAMERA_EFFECT_VINTAGECOOL	13
+#define CAMERA_EFFECT_VINTAGEWARM	14
+#define CAMERA_EFFECT_ACCENT_BLUE       15
+#define CAMERA_EFFECT_ACCENT_GREEN      16
+#define CAMERA_EFFECT_ACCENT_ORANGE     17
+#define CAMERA_EFFECT_MAX               18
+
+/* QRD */
+#define CAMERA_EFFECT_BW		10
+#define CAMERA_EFFECT_BLUISH	12
+#define CAMERA_EFFECT_REDDISH	13
+#define CAMERA_EFFECT_GREENISH	14
+
+/* QRD */
+#define CAMERA_ANTIBANDING_OFF		0
+#define CAMERA_ANTIBANDING_50HZ		2
+#define CAMERA_ANTIBANDING_60HZ		1
+#define CAMERA_ANTIBANDING_AUTO		3
+
+#define CAMERA_CONTRAST_LV0			0
+#define CAMERA_CONTRAST_LV1			1
+#define CAMERA_CONTRAST_LV2			2
+#define CAMERA_CONTRAST_LV3			3
+#define CAMERA_CONTRAST_LV4			4
+#define CAMERA_CONTRAST_LV5			5
+#define CAMERA_CONTRAST_LV6			6
+#define CAMERA_CONTRAST_LV7			7
+#define CAMERA_CONTRAST_LV8			8
+#define CAMERA_CONTRAST_LV9			9
+
+#define CAMERA_BRIGHTNESS_LV0			0
+#define CAMERA_BRIGHTNESS_LV1			1
+#define CAMERA_BRIGHTNESS_LV2			2
+#define CAMERA_BRIGHTNESS_LV3			3
+#define CAMERA_BRIGHTNESS_LV4			4
+#define CAMERA_BRIGHTNESS_LV5			5
+#define CAMERA_BRIGHTNESS_LV6			6
+#define CAMERA_BRIGHTNESS_LV7			7
+#define CAMERA_BRIGHTNESS_LV8			8
+
+
+#define CAMERA_SATURATION_LV0			0
+#define CAMERA_SATURATION_LV1			1
+#define CAMERA_SATURATION_LV2			2
+#define CAMERA_SATURATION_LV3			3
+#define CAMERA_SATURATION_LV4			4
+#define CAMERA_SATURATION_LV5			5
+#define CAMERA_SATURATION_LV6			6
+#define CAMERA_SATURATION_LV7			7
+#define CAMERA_SATURATION_LV8			8
+
+#define CAMERA_SHARPNESS_LV0		0
+#define CAMERA_SHARPNESS_LV1		3
+#define CAMERA_SHARPNESS_LV2		6
+#define CAMERA_SHARPNESS_LV3		9
+#define CAMERA_SHARPNESS_LV4		12
+#define CAMERA_SHARPNESS_LV5		15
+#define CAMERA_SHARPNESS_LV6		18
+#define CAMERA_SHARPNESS_LV7		21
+#define CAMERA_SHARPNESS_LV8		24
+#define CAMERA_SHARPNESS_LV9		27
+#define CAMERA_SHARPNESS_LV10		30
+
+#define CAMERA_SETAE_AVERAGE		0
+#define CAMERA_SETAE_CENWEIGHT	1
+
+#define  CAMERA_WB_AUTO               1 /* This list must match aeecamera.h */
+#define  CAMERA_WB_CUSTOM             2
+#define  CAMERA_WB_INCANDESCENT       3
+#define  CAMERA_WB_FLUORESCENT        4
+#define  CAMERA_WB_DAYLIGHT           5
+#define  CAMERA_WB_CLOUDY_DAYLIGHT    6
+#define  CAMERA_WB_TWILIGHT           7
+#define  CAMERA_WB_SHADE              8
+
+#define CAMERA_EXPOSURE_COMPENSATION_LV0			12
+#define CAMERA_EXPOSURE_COMPENSATION_LV1			6
+#define CAMERA_EXPOSURE_COMPENSATION_LV2			0
+#define CAMERA_EXPOSURE_COMPENSATION_LV3			-6
+#define CAMERA_EXPOSURE_COMPENSATION_LV4			-12
+
+enum msm_v4l2_saturation_level {
+	MSM_V4L2_SATURATION_L0,
+	MSM_V4L2_SATURATION_L1,
+	MSM_V4L2_SATURATION_L2,
+	MSM_V4L2_SATURATION_L3,
+	MSM_V4L2_SATURATION_L4,
+	MSM_V4L2_SATURATION_L5,
+	MSM_V4L2_SATURATION_L6,
+	MSM_V4L2_SATURATION_L7,
+	MSM_V4L2_SATURATION_L8,
+	MSM_V4L2_SATURATION_L9,
+	MSM_V4L2_SATURATION_L10,
+};
+
+enum msm_v4l2_contrast_level {
+	MSM_V4L2_CONTRAST_L0,
+	MSM_V4L2_CONTRAST_L1,
+	MSM_V4L2_CONTRAST_L2,
+	MSM_V4L2_CONTRAST_L3,
+	MSM_V4L2_CONTRAST_L4,
+	MSM_V4L2_CONTRAST_L5,
+	MSM_V4L2_CONTRAST_L6,
+	MSM_V4L2_CONTRAST_L7,
+	MSM_V4L2_CONTRAST_L8,
+	MSM_V4L2_CONTRAST_L9,
+	MSM_V4L2_CONTRAST_L10,
+};
+
+
+enum msm_v4l2_exposure_level {
+	MSM_V4L2_EXPOSURE_N2,
+	MSM_V4L2_EXPOSURE_N1,
+	MSM_V4L2_EXPOSURE_D,
+	MSM_V4L2_EXPOSURE_P1,
+	MSM_V4L2_EXPOSURE_P2,
+};
+
+enum msm_v4l2_sharpness_level {
+	MSM_V4L2_SHARPNESS_L0,
+	MSM_V4L2_SHARPNESS_L1,
+	MSM_V4L2_SHARPNESS_L2,
+	MSM_V4L2_SHARPNESS_L3,
+	MSM_V4L2_SHARPNESS_L4,
+	MSM_V4L2_SHARPNESS_L5,
+	MSM_V4L2_SHARPNESS_L6,
+};
+
+enum msm_v4l2_expo_metering_mode {
+	MSM_V4L2_EXP_FRAME_AVERAGE,
+	MSM_V4L2_EXP_CENTER_WEIGHTED,
+	MSM_V4L2_EXP_SPOT_METERING,
+};
+
+enum msm_v4l2_iso_mode {
+	MSM_V4L2_ISO_AUTO = 0,
+	MSM_V4L2_ISO_DEBLUR,
+	MSM_V4L2_ISO_100,
+	MSM_V4L2_ISO_200,
+	MSM_V4L2_ISO_400,
+	MSM_V4L2_ISO_800,
+	MSM_V4L2_ISO_1600,
+};
+
+enum msm_v4l2_wb_mode {
+	MSM_V4L2_WB_OFF,
+	MSM_V4L2_WB_AUTO,
+	MSM_V4L2_WB_CUSTOM,
+	MSM_V4L2_WB_INCANDESCENT,
+	MSM_V4L2_WB_FLUORESCENT,
+	MSM_V4L2_WB_DAYLIGHT,
+	MSM_V4L2_WB_CLOUDY_DAYLIGHT,
+};
+
+enum msm_v4l2_special_effect {
+	MSM_V4L2_EFFECT_OFF,
+	MSM_V4L2_EFFECT_MONO,
+	MSM_V4L2_EFFECT_NEGATIVE,
+	MSM_V4L2_EFFECT_SOLARIZE,
+	MSM_V4L2_EFFECT_SEPIA,
+	MSM_V4L2_EFFECT_POSTERAIZE,
+	MSM_V4L2_EFFECT_WHITEBOARD,
+	MSM_V4L2_EFFECT_BLACKBOARD,
+	MSM_V4L2_EFFECT_AQUA,
+	MSM_V4L2_EFFECT_EMBOSS,
+	MSM_V4L2_EFFECT_SKETCH,
+	MSM_V4L2_EFFECT_NEON,
+	MSM_V4L2_EFFECT_MAX,
+};
+
+enum msm_v4l2_power_line_frequency {
+	MSM_V4L2_POWER_LINE_OFF,
+	MSM_V4L2_POWER_LINE_60HZ,
+	MSM_V4L2_POWER_LINE_50HZ,
+	MSM_V4L2_POWER_LINE_AUTO,
+};
+
+#define CAMERA_ISO_TYPE_AUTO           0
+#define CAMEAR_ISO_TYPE_HJR            1
+#define CAMEAR_ISO_TYPE_100            2
+#define CAMERA_ISO_TYPE_200            3
+#define CAMERA_ISO_TYPE_400            4
+#define CAMEAR_ISO_TYPE_800            5
+#define CAMERA_ISO_TYPE_1600           6
+
+struct sensor_pict_fps {
+	uint16_t prevfps;
+	uint16_t pictfps;
+};
+
+struct exp_gain_cfg {
+	uint16_t gain;
+	uint32_t line;
+};
+
+struct focus_cfg {
+	int32_t steps;
+	int dir;
+};
+
+struct fps_cfg {
+	uint16_t f_mult;
+	uint16_t fps_div;
+	uint32_t pict_fps_div;
+};
+struct wb_info_cfg {
+	uint16_t red_gain;
+	uint16_t green_gain;
+	uint16_t blue_gain;
+};
+struct sensor_3d_exp_cfg {
+	uint16_t gain;
+	uint32_t line;
+	uint16_t r_gain;
+	uint16_t b_gain;
+	uint16_t gr_gain;
+	uint16_t gb_gain;
+	uint16_t gain_adjust;
+};
+struct sensor_3d_cali_data_t {
+	unsigned char left_p_matrix[3][4][8];
+	unsigned char right_p_matrix[3][4][8];
+	unsigned char square_len[8];
+	unsigned char focal_len[8];
+	unsigned char pixel_pitch[8];
+	uint16_t left_r;
+	uint16_t left_b;
+	uint16_t left_gb;
+	uint16_t left_af_far;
+	uint16_t left_af_mid;
+	uint16_t left_af_short;
+	uint16_t left_af_5um;
+	uint16_t left_af_50up;
+	uint16_t left_af_50down;
+	uint16_t right_r;
+	uint16_t right_b;
+	uint16_t right_gb;
+	uint16_t right_af_far;
+	uint16_t right_af_mid;
+	uint16_t right_af_short;
+	uint16_t right_af_5um;
+	uint16_t right_af_50up;
+	uint16_t right_af_50down;
+};
+struct sensor_init_cfg {
+	uint8_t prev_res;
+	uint8_t pict_res;
+};
+
+struct sensor_calib_data {
+	/* Color Related Measurements */
+	uint16_t r_over_g;
+	uint16_t b_over_g;
+	uint16_t gr_over_gb;
+
+	/* Lens Related Measurements */
+	uint16_t macro_2_inf;
+	uint16_t inf_2_macro;
+	uint16_t stroke_amt;
+	uint16_t af_pos_1m;
+	uint16_t af_pos_inf;
+};
+
+enum msm_sensor_resolution_t {
+	MSM_SENSOR_RES_FULL,
+	MSM_SENSOR_RES_QTR,
+	MSM_SENSOR_RES_2,
+	MSM_SENSOR_RES_3,
+	MSM_SENSOR_RES_4,
+	MSM_SENSOR_RES_5,
+	MSM_SENSOR_RES_6,
+	MSM_SENSOR_RES_7,
+	MSM_SENSOR_INVALID_RES,
+};
+
+struct msm_sensor_output_info_t {
+	uint16_t x_output;
+	uint16_t y_output;
+	uint16_t line_length_pclk;
+	uint16_t frame_length_lines;
+	uint32_t vt_pixel_clk;
+	uint32_t op_pixel_clk;
+	uint16_t binning_factor;
+};
+
+struct sensor_output_info_t {
+	struct msm_sensor_output_info_t *output_info;
+	uint16_t num_info;
+};
+
+struct msm_sensor_exp_gain_info_t {
+	uint16_t coarse_int_time_addr;
+	uint16_t global_gain_addr;
+	uint16_t vert_offset;
+};
+
+struct msm_sensor_output_reg_addr_t {
+	uint16_t x_output;
+	uint16_t y_output;
+	uint16_t line_length_pclk;
+	uint16_t frame_length_lines;
+};
+
+struct sensor_driver_params_type {
+	struct msm_camera_i2c_reg_setting *init_settings;
+	uint16_t init_settings_size;
+	struct msm_camera_i2c_reg_setting *mode_settings;
+	uint16_t mode_settings_size;
+	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
+	struct msm_camera_i2c_reg_setting *start_settings;
+	struct msm_camera_i2c_reg_setting *stop_settings;
+	struct msm_camera_i2c_reg_setting *groupon_settings;
+	struct msm_camera_i2c_reg_setting *groupoff_settings;
+	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
+	struct msm_sensor_output_info_t *output_info;
+};
+
+struct mirror_flip {
+	int32_t x_mirror;
+	int32_t y_flip;
+};
+
+struct cord {
+	uint32_t x;
+	uint32_t y;
+};
+
+struct msm_eeprom_data_t {
+	void *eeprom_data;
+	uint16_t index;
+};
+
+struct msm_camera_csid_vc_cfg {
+	uint8_t cid;
+	uint8_t dt;
+	uint8_t decode_format;
+};
+
+struct csi_lane_params_t {
+	uint16_t csi_lane_assign;
+	uint8_t csi_lane_mask;
+	uint8_t csi_if;
+	uint8_t csid_core[2];
+	uint8_t csi_phy_sel;
+};
+
+struct msm_camera_csid_lut_params {
+	uint8_t num_cid;
+	struct msm_camera_csid_vc_cfg *vc_cfg;
+};
+
+struct msm_camera_csid_params {
+	uint8_t lane_cnt;
+	uint16_t lane_assign;
+	uint8_t phy_sel;
+	struct msm_camera_csid_lut_params lut_params;
+};
+
+struct msm_camera_csiphy_params {
+	uint8_t lane_cnt;
+	uint8_t settle_cnt;
+	uint16_t lane_mask;
+	uint8_t combo_mode;
+	uint8_t csid_core;
+};
+
+struct msm_camera_csi2_params {
+	struct msm_camera_csid_params csid_params;
+	struct msm_camera_csiphy_params csiphy_params;
+};
+
+enum msm_camera_csi_data_format {
+	CSI_8BIT,
+	CSI_10BIT,
+	CSI_12BIT,
+};
+
+struct msm_camera_csi_params {
+	enum msm_camera_csi_data_format data_format;
+	uint8_t lane_cnt;
+	uint8_t lane_assign;
+	uint8_t settle_cnt;
+	uint8_t dpcm_scheme;
+};
+
+enum csic_cfg_type_t {
+	CSIC_INIT,
+	CSIC_CFG,
+};
+
+struct csic_cfg_data {
+	enum csic_cfg_type_t cfgtype;
+	struct msm_camera_csi_params *csic_params;
+};
+
+enum csid_cfg_type_t {
+	CSID_INIT,
+	CSID_CFG,
+};
+
+struct csid_cfg_data {
+	enum csid_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		struct msm_camera_csid_params *csid_params;
+	} cfg;
+};
+
+enum csiphy_cfg_type_t {
+	CSIPHY_INIT,
+	CSIPHY_CFG,
+};
+
+struct csiphy_cfg_data {
+	enum csiphy_cfg_type_t cfgtype;
+	struct msm_camera_csiphy_params *csiphy_params;
+};
+
+#define CSI_EMBED_DATA 0x12
+#define CSI_RESERVED_DATA_0 0x13
+#define CSI_YUV422_8  0x1E
+#define CSI_RAW8    0x2A
+#define CSI_RAW10   0x2B
+#define CSI_RAW12   0x2C
+
+#define CSI_DECODE_6BIT 0
+#define CSI_DECODE_8BIT 1
+#define CSI_DECODE_10BIT 2
+#define CSI_DECODE_DPCM_10_8_10 5
+
+#define ISPIF_STREAM(intf, action, vfe) (((intf)<<ISPIF_S_STREAM_SHIFT)+\
+	(action)+((vfe)<<ISPIF_VFE_INTF_SHIFT))
+#define ISPIF_ON_FRAME_BOUNDARY   (0x01 << 0)
+#define ISPIF_OFF_FRAME_BOUNDARY  (0x01 << 1)
+#define ISPIF_OFF_IMMEDIATELY     (0x01 << 2)
+#define ISPIF_S_STREAM_SHIFT      4
+#define ISPIF_VFE_INTF_SHIFT      12
+
+#define PIX_0 (0x01 << 0)
+#define RDI_0 (0x01 << 1)
+#define PIX_1 (0x01 << 2)
+#define RDI_1 (0x01 << 3)
+#define RDI_2 (0x01 << 4)
+
+enum msm_ispif_vfe_intf {
+	VFE0,
+	VFE1,
+	VFE_MAX,
+};
+
+enum msm_ispif_intftype {
+	PIX0,
+	RDI0,
+	PIX1,
+	RDI1,
+	RDI2,
+	INTF_MAX,
+};
+
+enum msm_ispif_vc {
+	VC0,
+	VC1,
+	VC2,
+	VC3,
+};
+
+enum msm_ispif_cid {
+	CID0,
+	CID1,
+	CID2,
+	CID3,
+	CID4,
+	CID5,
+	CID6,
+	CID7,
+	CID8,
+	CID9,
+	CID10,
+	CID11,
+	CID12,
+	CID13,
+	CID14,
+	CID15,
+};
+
+struct msm_ispif_params {
+	uint8_t intftype;
+	uint16_t cid_mask;
+	uint8_t csid;
+	uint8_t vfe_intf;
+};
+
+struct msm_ispif_params_list {
+	uint32_t len;
+	struct msm_ispif_params params[4];
+};
+
+enum ispif_cfg_type_t {
+	ISPIF_INIT,
+	ISPIF_SET_CFG,
+	ISPIF_SET_ON_FRAME_BOUNDARY,
+	ISPIF_SET_OFF_FRAME_BOUNDARY,
+	ISPIF_SET_OFF_IMMEDIATELY,
+	ISPIF_RELEASE,
+};
+
+struct ispif_cfg_data {
+	enum ispif_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		int cmd;
+		struct msm_ispif_params_list ispif_params;
+	} cfg;
+};
+
+enum msm_camera_i2c_reg_addr_type {
+	MSM_CAMERA_I2C_BYTE_ADDR = 1,
+	MSM_CAMERA_I2C_WORD_ADDR,
+	MSM_CAMERA_I2C_3B_ADDR,
+	MSM_CAMERA_I2C_DWORD_ADDR,
+};
+#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR
+
+struct msm_camera_i2c_reg_array {
+	uint16_t reg_addr;
+	uint16_t reg_data;
+};
+
+enum msm_camera_i2c_data_type {
+	MSM_CAMERA_I2C_BYTE_DATA = 1,
+	MSM_CAMERA_I2C_WORD_DATA,
+	MSM_CAMERA_I2C_SET_BYTE_MASK,
+	MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+	MSM_CAMERA_I2C_SET_WORD_MASK,
+	MSM_CAMERA_I2C_UNSET_WORD_MASK,
+	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+};
+
+struct msm_camera_i2c_reg_setting {
+	struct msm_camera_i2c_reg_array *reg_setting;
+	uint16_t size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t delay;
+};
+
+enum oem_setting_type {
+	I2C_READ = 1,
+	I2C_WRITE,
+	GPIO_OP,
+	EEPROM_READ,
+	VREG_SET,
+	CLK_SET,
+};
+
+struct sensor_oem_setting {
+	enum oem_setting_type type;
+	void *data;
+};
+
+enum camera_vreg_type {
+	REG_LDO,
+	REG_VS,
+	REG_GPIO,
+};
+
+enum msm_camera_vreg_name_t {
+	CAM_VDIG,
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VAF,
+	CAM_VREG_MAX,
+};
+
+struct msm_camera_csi_lane_params {
+	uint16_t csi_lane_assign;
+	uint16_t csi_lane_mask;
+};
+
+struct camera_vreg_t {
+	const char *reg_name;
+	int min_voltage;
+	int max_voltage;
+	int op_mode;
+	uint32_t delay;
+};
+
+struct msm_camera_vreg_setting {
+	struct camera_vreg_t *cam_vreg;
+	uint16_t num_vreg;
+	uint8_t enable;
+};
+
+struct msm_cam_clk_info {
+	const char *clk_name;
+	long clk_rate;
+	uint32_t delay;
+};
+
+struct msm_cam_clk_setting {
+	struct msm_cam_clk_info *clk_info;
+	uint16_t num_clk_info;
+	uint8_t enable;
+};
+
+struct sensor_cfg_data {
+	int cfgtype;
+	int mode;
+	int rs;
+	uint8_t max_steps;
+
+	union {
+		int8_t effect;
+		uint8_t lens_shading;
+		uint16_t prevl_pf;
+		uint16_t prevp_pl;
+		uint16_t pictl_pf;
+		uint16_t pictp_pl;
+		uint32_t pict_max_exp_lc;
+		uint16_t p_fps;
+		uint8_t iso_type;
+		struct sensor_init_cfg init_info;
+		struct sensor_pict_fps gfps;
+		struct exp_gain_cfg exp_gain;
+		struct focus_cfg focus;
+		struct fps_cfg fps;
+		struct wb_info_cfg wb_info;
+		struct sensor_3d_exp_cfg sensor_3d_exp;
+		struct sensor_calib_data calib_info;
+		struct sensor_output_info_t output_info;
+		struct msm_eeprom_data_t eeprom_data;
+		struct csi_lane_params_t csi_lane_params;
+		/* QRD */
+		uint16_t antibanding;
+		uint8_t contrast;
+		uint8_t saturation;
+		uint8_t sharpness;
+		int8_t brightness;
+		int ae_mode;
+		uint8_t wb_val;
+		int8_t exp_compensation;
+		uint32_t pclk;
+		struct cord aec_cord;
+		int is_autoflash;
+		struct mirror_flip mirror_flip;
+		void *setting;
+	} cfg;
+};
+
+enum gpio_operation_type {
+	GPIO_REQUEST,
+	GPIO_FREE,
+	GPIO_SET_DIRECTION_OUTPUT,
+	GPIO_SET_DIRECTION_INPUT,
+	GPIO_GET_VALUE,
+	GPIO_SET_VALUE,
+};
+
+struct msm_cam_gpio_operation {
+	enum gpio_operation_type op_type;
+	unsigned int address;
+	int value;
+	const char *tag;
+};
+
+struct damping_params_t {
+	uint32_t damping_step;
+	uint32_t damping_delay;
+	uint32_t hw_params;
+};
+
+enum actuator_type {
+	ACTUATOR_VCM,
+	ACTUATOR_PIEZO,
+	ACTUATOR_HVCM,
+	ACTUATOR_BIVCM,
+};
+
+enum msm_actuator_data_type {
+	MSM_ACTUATOR_BYTE_DATA = 1,
+	MSM_ACTUATOR_WORD_DATA,
+};
+
+enum msm_actuator_addr_type {
+	MSM_ACTUATOR_BYTE_ADDR = 1,
+	MSM_ACTUATOR_WORD_ADDR,
+};
+
+enum msm_actuator_write_type {
+	MSM_ACTUATOR_WRITE_HW_DAMP,
+	MSM_ACTUATOR_WRITE_DAC,
+	MSM_ACTUATOR_WRITE,
+	MSM_ACTUATOR_WRITE_DIR_REG,
+	MSM_ACTUATOR_POLL,
+	MSM_ACTUATOR_READ_WRITE,
+};
+
+struct msm_actuator_reg_params_t {
+	enum msm_actuator_write_type reg_write_type;
+	uint32_t hw_mask;
+	uint16_t reg_addr;
+	uint16_t hw_shift;
+	uint16_t data_type;
+	uint16_t addr_type;
+	uint16_t reg_data;
+	uint16_t delay;
+};
+
+struct reg_settings_t {
+	uint16_t reg_addr;
+	uint16_t reg_data;
+};
+
+struct region_params_t {
+	/* [0] = ForwardDirection Macro boundary
+	 *  [1] = ReverseDirection Inf boundary
+	 */
+	uint16_t step_bound[2];
+	uint16_t code_per_step;
+};
+
+struct msm_actuator_move_params_t {
+	int8_t dir;
+	int8_t sign_dir;
+	int16_t dest_step_pos;
+	int32_t num_steps;
+	struct damping_params_t __user *ringing_params;
+};
+
+struct msm_actuator_tuning_params_t {
+	int16_t initial_code;
+	uint16_t pwd_step;
+	uint16_t region_size;
+	uint32_t total_steps;
+	struct region_params_t __user *region_params;
+};
+
+struct msm_actuator_params_t {
+	enum actuator_type act_type;
+	uint8_t reg_tbl_size;
+	uint16_t data_size;
+	uint16_t init_setting_size;
+	uint32_t i2c_addr;
+	enum msm_actuator_addr_type i2c_addr_type;
+	enum msm_actuator_data_type i2c_data_type;
+	struct msm_actuator_reg_params_t __user *reg_tbl_params;
+	struct reg_settings_t __user *init_settings;
+};
+
+struct msm_actuator_set_info_t {
+	struct msm_actuator_params_t actuator_params;
+	struct msm_actuator_tuning_params_t af_tuning_params;
+};
+
+struct msm_actuator_get_info_t {
+	uint32_t focal_length_num;
+	uint32_t focal_length_den;
+	uint32_t f_number_num;
+	uint32_t f_number_den;
+	uint32_t f_pix_num;
+	uint32_t f_pix_den;
+	uint32_t total_f_dist_num;
+	uint32_t total_f_dist_den;
+	uint32_t hor_view_angle_num;
+	uint32_t hor_view_angle_den;
+	uint32_t ver_view_angle_num;
+	uint32_t ver_view_angle_den;
+};
+
+enum af_camera_name {
+	ACTUATOR_MAIN_CAM_0,
+	ACTUATOR_MAIN_CAM_1,
+	ACTUATOR_MAIN_CAM_2,
+	ACTUATOR_MAIN_CAM_3,
+	ACTUATOR_MAIN_CAM_4,
+	ACTUATOR_MAIN_CAM_5,
+	ACTUATOR_WEB_CAM_0,
+	ACTUATOR_WEB_CAM_1,
+	ACTUATOR_WEB_CAM_2,
+};
+
+struct msm_actuator_cfg_data {
+	int cfgtype;
+	uint8_t is_af_supported;
+	union {
+		struct msm_actuator_move_params_t move;
+		struct msm_actuator_set_info_t set_info;
+		struct msm_actuator_get_info_t get_info;
+		enum af_camera_name cam_name;
+	} cfg;
+};
+
+struct msm_eeprom_support {
+	uint16_t is_supported;
+	uint16_t size;
+	uint16_t index;
+	uint16_t qvalue;
+};
+
+struct msm_calib_wb {
+	uint16_t r_over_g;
+	uint16_t b_over_g;
+	uint16_t gr_over_gb;
+};
+
+struct msm_calib_af {
+	uint16_t macro_dac;
+	uint16_t inf_dac;
+	uint16_t start_dac;
+};
+
+struct msm_calib_lsc {
+	uint16_t r_gain[221];
+	uint16_t b_gain[221];
+	uint16_t gr_gain[221];
+	uint16_t gb_gain[221];
+};
+
+struct pixel_t {
+	int x;
+	int y;
+};
+
+struct msm_calib_dpc {
+	uint16_t validcount;
+	struct pixel_t snapshot_coord[128];
+	struct pixel_t preview_coord[128];
+	struct pixel_t video_coord[128];
+};
+
+struct msm_calib_raw {
+	uint8_t *data;
+	uint32_t size;
+};
+
+struct msm_camera_eeprom_info_t {
+	struct msm_eeprom_support af;
+	struct msm_eeprom_support wb;
+	struct msm_eeprom_support lsc;
+	struct msm_eeprom_support dpc;
+	struct msm_eeprom_support raw;
+};
+
+struct msm_eeprom_cfg_data {
+	int cfgtype;
+	uint8_t is_eeprom_supported;
+	union {
+		struct msm_eeprom_data_t get_data;
+		struct msm_camera_eeprom_info_t get_info;
+	} cfg;
+};
+
+struct sensor_large_data {
+	int cfgtype;
+	union {
+		struct sensor_3d_cali_data_t sensor_3d_cali_data;
+	} data;
+};
+
+enum sensor_type_t {
+	BAYER,
+	YUV,
+	JPEG_SOC,
+};
+
+enum flash_type {
+	LED_FLASH,
+	STROBE_FLASH,
+};
+
+enum strobe_flash_ctrl_type {
+	STROBE_FLASH_CTRL_INIT,
+	STROBE_FLASH_CTRL_CHARGE,
+	STROBE_FLASH_CTRL_RELEASE
+};
+
+struct strobe_flash_ctrl_data {
+	enum strobe_flash_ctrl_type type;
+	int charge_en;
+};
+
+struct msm_camera_info {
+	int num_cameras;
+	uint8_t has_3d_support[MSM_MAX_CAMERA_SENSORS];
+	uint8_t is_internal_cam[MSM_MAX_CAMERA_SENSORS];
+	uint32_t s_mount_angle[MSM_MAX_CAMERA_SENSORS];
+	const char *video_dev_name[MSM_MAX_CAMERA_SENSORS];
+	enum sensor_type_t sensor_type[MSM_MAX_CAMERA_SENSORS];
+};
+
+struct msm_cam_config_dev_info {
+	int num_config_nodes;
+	const char *config_dev_name[MSM_MAX_CAMERA_CONFIGS];
+	int config_dev_id[MSM_MAX_CAMERA_CONFIGS];
+};
+
+struct msm_mctl_node_info {
+	int num_mctl_nodes;
+	const char *mctl_node_name[MSM_MAX_CAMERA_SENSORS];
+};
+
+struct flash_ctrl_data {
+	int flashtype;
+	union {
+		int led_state;
+		struct strobe_flash_ctrl_data strobe_ctrl;
+	} ctrl_data;
+};
+
+#define GET_NAME			0
+#define GET_PREVIEW_LINE_PER_FRAME	1
+#define GET_PREVIEW_PIXELS_PER_LINE	2
+#define GET_SNAPSHOT_LINE_PER_FRAME	3
+#define GET_SNAPSHOT_PIXELS_PER_LINE	4
+#define GET_SNAPSHOT_FPS		5
+#define GET_SNAPSHOT_MAX_EP_LINE_CNT	6
+
+struct msm_camsensor_info {
+	char name[MAX_SENSOR_NAME];
+	uint8_t flash_enabled;
+	uint8_t strobe_flash_enabled;
+	uint8_t actuator_enabled;
+	uint8_t ispif_supported;
+	int8_t total_steps;
+	uint8_t support_3d;
+	enum flash_type flashtype;
+	enum sensor_type_t sensor_type;
+	uint32_t pxlcode; /* enum v4l2_mbus_pixelcode */
+	uint32_t camera_type; /* msm_camera_type */
+	int mount_angle;
+	uint32_t max_width;
+	uint32_t max_height;
+};
+
+#define V4L2_SINGLE_PLANE	0
+#define V4L2_MULTI_PLANE_Y	0
+#define V4L2_MULTI_PLANE_CBCR	1
+#define V4L2_MULTI_PLANE_CB	1
+#define V4L2_MULTI_PLANE_CR	2
+
+struct plane_data {
+	int plane_id;
+	uint32_t offset;
+	unsigned long size;
+};
+
+struct img_plane_info {
+	uint32_t width;
+	uint32_t height;
+	uint32_t pixelformat;
+	uint8_t buffer_type; /*Single/Multi planar*/
+	uint8_t output_port;
+	uint32_t ext_mode;
+	uint8_t num_planes;
+	struct plane_data plane[MAX_PLANES];
+	uint32_t sp_y_offset;
+	uint32_t inst_handle;
+};
+
+#define QCAMERA_NAME "qcamera"
+#define QCAMERA_SERVER_NAME "qcamera_server"
+#define QCAMERA_VNODE_GROUP_ID MEDIA_ENT_F_IO_V4L
+
+enum msm_cam_subdev_type {
+	CSIPHY_DEV,
+	CSID_DEV,
+	CSIC_DEV,
+	ISPIF_DEV,
+	VFE_DEV,
+	AXI_DEV,
+	VPE_DEV,
+	SENSOR_DEV,
+	ACTUATOR_DEV,
+	EEPROM_DEV,
+	GESTURE_DEV,
+	IRQ_ROUTER_DEV,
+	CPP_DEV,
+	CCI_DEV,
+	FLASH_DEV,
+};
+
+struct msm_mctl_set_sdev_data {
+	uint32_t revision;
+	enum msm_cam_subdev_type sdev_type;
+};
+
+#define MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_IOCTL_SEND_EVENT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
+#define MSM_CAM_V4L2_IOCTL_CFG_VPE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_vpe_cfg_cmd)
+
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_S_CTRL \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_GENERAL \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_INIT \
+	_IO('V', BASE_VIDIOC_PRIVATE + 15)
+
+#define VIDIOC_MSM_VPE_RELEASE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 16)
+
+#define VIDIOC_MSM_VPE_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_mctl_pp_params *)
+
+#define VIDIOC_MSM_AXI_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, uint8_t *)
+
+#define VIDIOC_MSM_AXI_RELEASE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 19)
+
+#define VIDIOC_MSM_AXI_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 20, void *)
+
+#define VIDIOC_MSM_AXI_IRQ \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, void *)
+
+#define VIDIOC_MSM_AXI_BUF_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
+
+#define VIDIOC_MSM_AXI_RDI_COUNT_UPDATE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, void *)
+
+#define VIDIOC_MSM_VFE_INIT \
+	_IO('V', BASE_VIDIOC_PRIVATE + 24)
+
+#define VIDIOC_MSM_VFE_RELEASE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 25)
+
+struct msm_camera_v4l2_ioctl_t {
+	uint32_t id;
+	uint32_t len;
+	uint32_t trans_code;
+	void __user *ioctl_ptr;
+};
+
+struct msm_camera_vfe_params_t {
+	uint32_t operation_mode;
+	uint32_t capture_count;
+	uint8_t  skip_reset;
+	uint8_t  stop_immediately;
+	uint16_t port_info;
+	uint32_t inst_handle;
+	uint16_t cmd_type;
+};
+
+enum msm_camss_irq_idx {
+	CAMERA_SS_IRQ_0,
+	CAMERA_SS_IRQ_1,
+	CAMERA_SS_IRQ_2,
+	CAMERA_SS_IRQ_3,
+	CAMERA_SS_IRQ_4,
+	CAMERA_SS_IRQ_5,
+	CAMERA_SS_IRQ_6,
+	CAMERA_SS_IRQ_7,
+	CAMERA_SS_IRQ_8,
+	CAMERA_SS_IRQ_9,
+	CAMERA_SS_IRQ_10,
+	CAMERA_SS_IRQ_11,
+	CAMERA_SS_IRQ_12,
+	CAMERA_SS_IRQ_MAX
+};
+
+enum msm_cam_hw_idx {
+	MSM_CAM_HW_MICRO,
+	MSM_CAM_HW_CCI,
+	MSM_CAM_HW_CSI0,
+	MSM_CAM_HW_CSI1,
+	MSM_CAM_HW_CSI2,
+	MSM_CAM_HW_CSI3,
+	MSM_CAM_HW_ISPIF,
+	MSM_CAM_HW_CPP,
+	MSM_CAM_HW_VFE0,
+	MSM_CAM_HW_VFE1,
+	MSM_CAM_HW_JPEG0,
+	MSM_CAM_HW_JPEG1,
+	MSM_CAM_HW_JPEG2,
+	MSM_CAM_HW_MAX
+};
+
+struct msm_camera_irq_cfg {
+	/* Bit mask of all the camera hardwares that needs to
+	 * be composited into a single IRQ to the MSM.
+	 * Current usage: (may be updated based on hw changes)
+	 * Bits 31:13 - Reserved.
+	 * Bits 12:0
+	 * 12 - MSM_CAM_HW_JPEG2
+	 * 11 - MSM_CAM_HW_JPEG1
+	 * 10 - MSM_CAM_HW_JPEG0
+	 *  9 - MSM_CAM_HW_VFE1
+	 *  8 - MSM_CAM_HW_VFE0
+	 *  7 - MSM_CAM_HW_CPP
+	 *  6 - MSM_CAM_HW_ISPIF
+	 *  5 - MSM_CAM_HW_CSI3
+	 *  4 - MSM_CAM_HW_CSI2
+	 *  3 - MSM_CAM_HW_CSI1
+	 *  2 - MSM_CAM_HW_CSI0
+	 *  1 - MSM_CAM_HW_CCI
+	 *  0 - MSM_CAM_HW_MICRO
+	 */
+	uint32_t cam_hw_mask;
+	uint8_t  irq_idx;
+	uint8_t  num_hwcore;
+};
+
+#define MSM_IRQROUTER_CFG_COMPIRQ \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, void __user *)
+
+#define MAX_NUM_CPP_STRIPS 8
+
+enum msm_cpp_frame_type {
+	MSM_CPP_OFFLINE_FRAME,
+	MSM_CPP_REALTIME_FRAME,
+};
+
+struct msm_cpp_frame_info_t {
+	int32_t frame_id;
+	uint32_t inst_id;
+	uint32_t client_id;
+	enum msm_cpp_frame_type frame_type;
+	uint32_t num_strips;
+};
+
+struct msm_ver_num_info {
+	uint32_t main;
+	uint32_t minor;
+	uint32_t rev;
+};
+
+#define VIDIOC_MSM_CPP_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_INST_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+
+#define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
+
+/* Instance Handle - inst_handle
+ * Data bundle containing the information about where
+ * to get a buffer for a particular camera instance.
+ * This is a bitmask containing the following data:
+ * Buffer Handle Bitmask:
+ *      ------------------------------------
+ *      Bits    :  Purpose
+ *      ------------------------------------
+ *      31      :  is Dev ID valid?
+ *      30 - 24 :  Dev ID.
+ *      23      :  is Image mode valid?
+ *      22 - 16 :  Image mode.
+ *      15      :  is MCTL PP inst idx valid?
+ *      14 - 8  :  MCTL PP inst idx.
+ *      7       :  is Video inst idx valid?
+ *      6 - 0   :  Video inst idx.
+ */
+#define CLR_DEVID_MODE(handle)	(handle &= 0x00FFFFFF)
+#define SET_DEVID_MODE(handle, data)	\
+	(handle |= ((0x1 << 31) | ((data & 0x7F) << 24)))
+#define GET_DEVID_MODE(handle)	\
+	((handle & 0x80000000) ? ((handle & 0x7F000000) >> 24) : 0xFF)
+
+#define CLR_IMG_MODE(handle)	(handle &= 0xFF00FFFF)
+#define SET_IMG_MODE(handle, data)	\
+	(handle |= ((0x1 << 23) | ((data & 0x7F) << 16)))
+#define GET_IMG_MODE(handle)	\
+	((handle & 0x800000) ? ((handle & 0x7F0000) >> 16) : 0xFF)
+
+#define CLR_MCTLPP_INST_IDX(handle)	(handle &= 0xFFFF00FF)
+#define SET_MCTLPP_INST_IDX(handle, data)	\
+	(handle |= ((0x1 << 15) | ((data & 0x7F) << 8)))
+#define GET_MCTLPP_INST_IDX(handle)	\
+	((handle & 0x8000) ? ((handle & 0x7F00) >> 8) : 0xFF)
+
+#define CLR_VIDEO_INST_IDX(handle)	(handle &= 0xFFFFFF00)
+#define GET_VIDEO_INST_IDX(handle)	\
+	((handle & 0x80) ? (handle & 0x7F) : 0xFF)
+#define SET_VIDEO_INST_IDX(handle, data)	\
+	(handle |= (0x1 << 7) | (data & 0x7F))
+#endif
diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h
new file mode 100644
index 0000000..5266c02
--- /dev/null
+++ b/include/uapi/media/msm_camsensor_sdk.h
@@ -0,0 +1,431 @@
+#ifndef __UAPI_LINUX_MSM_CAMSENSOR_SDK_H
+#define __UAPI_LINUX_MSM_CAMSENSOR_SDK_H
+
+#include <linux/videodev2.h>
+
+#define KVERSION 0x1
+
+#define MAX_POWER_CONFIG      12
+#define GPIO_OUT_LOW          (0 << 1)
+#define GPIO_OUT_HIGH         (1 << 1)
+#define CSI_EMBED_DATA        0x12
+#define CSI_RESERVED_DATA_0   0x13
+#define CSI_YUV422_8          0x1E
+#define CSI_RAW8              0x2A
+#define CSI_RAW10             0x2B
+#define CSI_RAW12             0x2C
+#define CSI_DECODE_6BIT         0
+#define CSI_DECODE_8BIT         1
+#define CSI_DECODE_10BIT        2
+#define CSI_DECODE_12BIT        3
+#define CSI_DECODE_DPCM_10_6_10 4
+#define CSI_DECODE_DPCM_10_8_10 5
+#define MAX_CID                 16
+#define I2C_SEQ_REG_DATA_MAX    1024
+#define I2C_REG_DATA_MAX       (8*1024)
+
+#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
+#define MSM_V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4')
+	/* 14  BGBG.. GRGR.. */
+#define MSM_V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4')
+	/* 14  GBGB.. RGRG.. */
+#define MSM_V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('B', 'A', '1', '4')
+	/* 14  GRGR.. BGBG.. */
+#define MSM_V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4')
+	/* 14  RGRG.. GBGB.. */
+
+#define MAX_ACTUATOR_REG_TBL_SIZE 8
+#define MAX_ACTUATOR_REGION       5
+#define NUM_ACTUATOR_DIR          2
+#define MAX_ACTUATOR_SCENARIO     8
+#define MAX_ACT_MOD_NAME_SIZE     32
+#define MAX_ACT_NAME_SIZE         32
+#define MAX_ACTUATOR_INIT_SET     120
+#define MAX_I2C_REG_SET           12
+
+#define MAX_LED_TRIGGERS          3
+
+#define MSM_EEPROM_MEMORY_MAP_MAX_SIZE  80
+#define MSM_EEPROM_MAX_MEM_MAP_CNT      8
+
+#define MSM_SENSOR_BYPASS_VIDEO_NODE    1
+
+enum msm_sensor_camera_id_t {
+	CAMERA_0,
+	CAMERA_1,
+	CAMERA_2,
+	CAMERA_3,
+	MAX_CAMERAS,
+};
+
+enum i2c_freq_mode_t {
+	I2C_STANDARD_MODE,
+	I2C_FAST_MODE,
+	I2C_CUSTOM_MODE,
+	I2C_FAST_PLUS_MODE,
+	I2C_MAX_MODES,
+};
+
+enum camb_position_t {
+	BACK_CAMERA_B,
+	FRONT_CAMERA_B,
+	AUX_CAMERA_B = 0x100,
+	INVALID_CAMERA_B,
+};
+
+enum msm_sensor_power_seq_type_t {
+	SENSOR_CLK,
+	SENSOR_GPIO,
+	SENSOR_VREG,
+	SENSOR_I2C_MUX,
+	SENSOR_I2C,
+};
+
+enum msm_camera_i2c_reg_addr_type {
+	MSM_CAMERA_I2C_BYTE_ADDR = 1,
+	MSM_CAMERA_I2C_WORD_ADDR,
+	MSM_CAMERA_I2C_3B_ADDR,
+	MSM_CAMERA_I2C_DWORD_ADDR,
+	MSM_CAMERA_I2C_ADDR_TYPE_MAX,
+};
+#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR
+
+enum msm_camera_i2c_data_type {
+	MSM_CAMERA_I2C_BYTE_DATA = 1,
+	MSM_CAMERA_I2C_WORD_DATA,
+	MSM_CAMERA_I2C_DWORD_DATA,
+	MSM_CAMERA_I2C_SET_BYTE_MASK,
+	MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+	MSM_CAMERA_I2C_SET_WORD_MASK,
+	MSM_CAMERA_I2C_UNSET_WORD_MASK,
+	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+	MSM_CAMERA_I2C_DATA_TYPE_MAX,
+};
+
+enum msm_sensor_power_seq_gpio_t {
+	SENSOR_GPIO_RESET,
+	SENSOR_GPIO_STANDBY,
+	SENSOR_GPIO_AF_PWDM,
+	SENSOR_GPIO_VIO,
+	SENSOR_GPIO_VANA,
+	SENSOR_GPIO_VDIG,
+	SENSOR_GPIO_VAF,
+	SENSOR_GPIO_FL_EN,
+	SENSOR_GPIO_FL_NOW,
+	SENSOR_GPIO_FL_RESET,
+	SENSOR_GPIO_CUSTOM1,
+	SENSOR_GPIO_CUSTOM2,
+	SENSOR_GPIO_CUSTOM3,
+	SENSOR_GPIO_MAX,
+};
+#define SENSOR_GPIO_CUSTOM3 SENSOR_GPIO_CUSTOM3
+
+enum msm_ir_cut_filter_gpio_t {
+	IR_CUT_FILTER_GPIO_P = 0,
+	IR_CUT_FILTER_GPIO_M,
+	IR_CUT_FILTER_GPIO_MAX,
+};
+#define IR_CUT_FILTER_GPIO_P IR_CUT_FILTER_GPIO_P
+#define IR_CUT_FILTER_GPIO_M IR_CUT_FILTER_GPIO_M
+#define R_CUT_FILTER_GPIO_MAX IR_CUT_FILTER_GPIO_MAX
+
+enum msm_camera_vreg_name_t {
+	CAM_VDIG,
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VAF,
+	CAM_V_CUSTOM1,
+	CAM_V_CUSTOM2,
+	CAM_VREG_MAX,
+};
+
+enum msm_sensor_clk_type_t {
+	SENSOR_CAM_MCLK,
+	SENSOR_CAM_CLK,
+	SENSOR_CAM_CLK_MAX,
+};
+
+enum camerab_mode_t {
+	CAMERA_MODE_2D_B = (1<<0),
+	CAMERA_MODE_3D_B = (1<<1),
+	CAMERA_MODE_INVALID = (1<<2),
+};
+
+enum msm_actuator_data_type {
+	MSM_ACTUATOR_BYTE_DATA = 1,
+	MSM_ACTUATOR_WORD_DATA,
+};
+
+enum msm_actuator_addr_type {
+	MSM_ACTUATOR_BYTE_ADDR = 1,
+	MSM_ACTUATOR_WORD_ADDR,
+};
+
+enum msm_actuator_write_type {
+	MSM_ACTUATOR_WRITE_HW_DAMP,
+	MSM_ACTUATOR_WRITE_DAC,
+	MSM_ACTUATOR_WRITE,
+	MSM_ACTUATOR_WRITE_DIR_REG,
+	MSM_ACTUATOR_POLL,
+	MSM_ACTUATOR_READ_WRITE,
+};
+
+enum msm_actuator_i2c_operation {
+	MSM_ACT_WRITE = 0,
+	MSM_ACT_POLL,
+};
+
+enum actuator_type {
+	ACTUATOR_VCM,
+	ACTUATOR_PIEZO,
+	ACTUATOR_HVCM,
+	ACTUATOR_BIVCM,
+};
+
+enum msm_flash_driver_type {
+	FLASH_DRIVER_PMIC,
+	FLASH_DRIVER_I2C,
+	FLASH_DRIVER_GPIO,
+	FLASH_DRIVER_DEFAULT
+};
+
+enum msm_flash_cfg_type_t {
+	CFG_FLASH_INIT,
+	CFG_FLASH_RELEASE,
+	CFG_FLASH_OFF,
+	CFG_FLASH_LOW,
+	CFG_FLASH_HIGH,
+};
+
+enum msm_ir_led_cfg_type_t {
+	CFG_IR_LED_INIT = 0,
+	CFG_IR_LED_RELEASE,
+	CFG_IR_LED_OFF,
+	CFG_IR_LED_ON,
+};
+#define CFG_IR_LED_INIT CFG_IR_LED_INIT
+#define CFG_IR_LED_RELEASE CFG_IR_LED_RELEASE
+#define CFG_IR_LED_OFF CFG_IR_LED_OFF
+#define CFG_IR_LED_ON CFG_IR_LED_ON
+
+enum msm_laser_led_cfg_type_t {
+	CFG_LASER_LED_INIT,
+	CFG_LASER_LED_CONTROL,
+};
+#define CFG_LASER_LED_INIT CFG_LASER_LED_INIT
+#define CFG_LASER_LED_CONTROL CFG_LASER_LED_CONTROL
+
+enum msm_ir_cut_cfg_type_t {
+	CFG_IR_CUT_INIT = 0,
+	CFG_IR_CUT_RELEASE,
+	CFG_IR_CUT_OFF,
+	CFG_IR_CUT_ON,
+};
+#define CFG_IR_CUT_INIT CFG_IR_CUT_INIT
+#define CFG_IR_CUT_RELEASE CFG_IR_CUT_RELEASE
+#define CFG_IR_CUT_OFF CFG_IR_CUT_OFF
+#define CFG_IR_CUT_ON CFG_IR_CUT_ON
+
+enum msm_sensor_output_format_t {
+	MSM_SENSOR_BAYER,
+	MSM_SENSOR_YCBCR,
+	MSM_SENSOR_META,
+};
+
+struct msm_sensor_power_setting {
+	enum msm_sensor_power_seq_type_t seq_type;
+	unsigned short seq_val;
+	long config_val;
+	unsigned short delay;
+	void *data[10];
+};
+
+struct msm_sensor_power_setting_array {
+	struct msm_sensor_power_setting  power_setting_a[MAX_POWER_CONFIG];
+	struct msm_sensor_power_setting  *power_setting;
+	unsigned short size;
+	struct msm_sensor_power_setting  power_down_setting_a[MAX_POWER_CONFIG];
+	struct msm_sensor_power_setting  *power_down_setting;
+	unsigned short size_down;
+};
+
+enum msm_camera_i2c_operation {
+	MSM_CAM_WRITE = 0,
+	MSM_CAM_POLL,
+	MSM_CAM_READ,
+};
+
+struct msm_sensor_i2c_sync_params {
+	unsigned int cid;
+	int csid;
+	unsigned short line;
+	unsigned short delay;
+};
+
+struct msm_camera_reg_settings_t {
+	uint16_t reg_addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	uint16_t reg_data;
+	enum msm_camera_i2c_data_type data_type;
+	enum msm_camera_i2c_operation i2c_operation;
+	uint16_t delay;
+};
+
+struct msm_eeprom_mem_map_t {
+	int slave_addr;
+	struct msm_camera_reg_settings_t
+		mem_settings[MSM_EEPROM_MEMORY_MAP_MAX_SIZE];
+	int memory_map_size;
+};
+
+struct msm_eeprom_memory_map_array {
+	struct msm_eeprom_mem_map_t memory_map[MSM_EEPROM_MAX_MEM_MAP_CNT];
+	uint32_t msm_size_of_max_mappings;
+};
+
+struct msm_sensor_init_params {
+	/* mask of modes supported: 2D, 3D */
+	int                 modes_supported;
+	/* sensor position: front, back */
+	enum camb_position_t position;
+	/* sensor mount angle */
+	unsigned int            sensor_mount_angle;
+};
+
+struct msm_sensor_id_info_t {
+	unsigned short sensor_id_reg_addr;
+	unsigned short sensor_id;
+	unsigned short sensor_id_mask;
+};
+
+struct msm_camera_sensor_slave_info {
+	char sensor_name[32];
+	char eeprom_name[32];
+	char actuator_name[32];
+	char ois_name[32];
+	char flash_name[32];
+	enum msm_sensor_camera_id_t camera_id;
+	unsigned short slave_addr;
+	enum i2c_freq_mode_t i2c_freq_mode;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	struct msm_sensor_id_info_t sensor_id_info;
+	struct msm_sensor_power_setting_array power_setting_array;
+	unsigned char  is_init_params_valid;
+	struct msm_sensor_init_params sensor_init_params;
+	enum msm_sensor_output_format_t output_format;
+	uint8_t bypass_video_node_creation;
+};
+
+struct msm_camera_i2c_reg_array {
+	unsigned short reg_addr;
+	unsigned short reg_data;
+	unsigned int delay;
+};
+
+struct msm_camera_i2c_reg_setting {
+	struct msm_camera_i2c_reg_array *reg_setting;
+	unsigned short size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	unsigned short delay;
+};
+
+struct msm_camera_csid_vc_cfg {
+	unsigned char cid;
+	unsigned char dt;
+	unsigned char decode_format;
+};
+
+struct msm_camera_csid_lut_params {
+	unsigned char num_cid;
+	struct msm_camera_csid_vc_cfg vc_cfg_a[MAX_CID];
+	struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID];
+};
+
+struct msm_camera_csid_params {
+	unsigned char lane_cnt;
+	unsigned short lane_assign;
+	unsigned char phy_sel;
+	unsigned int csi_clk;
+	struct msm_camera_csid_lut_params lut_params;
+	unsigned char csi_3p_sel;
+};
+
+struct msm_camera_csid_testmode_parms {
+	unsigned int num_bytes_per_line;
+	unsigned int num_lines;
+	unsigned int h_blanking_count;
+	unsigned int v_blanking_count;
+	unsigned int payload_mode;
+};
+
+struct msm_camera_csiphy_params {
+	unsigned char lane_cnt;
+	unsigned char settle_cnt;
+	unsigned short lane_mask;
+	unsigned char combo_mode;
+	unsigned char csid_core;
+	unsigned int csiphy_clk;
+	unsigned char csi_3phase;
+};
+
+struct msm_camera_i2c_seq_reg_array {
+	unsigned short reg_addr;
+	unsigned char reg_data[I2C_SEQ_REG_DATA_MAX];
+	unsigned short reg_data_size;
+};
+
+struct msm_camera_i2c_seq_reg_setting {
+	struct msm_camera_i2c_seq_reg_array *reg_setting;
+	unsigned short size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	unsigned short delay;
+};
+
+struct msm_actuator_reg_params_t {
+	enum msm_actuator_write_type reg_write_type;
+	unsigned int hw_mask;
+	unsigned short reg_addr;
+	unsigned short hw_shift;
+	unsigned short data_shift;
+	unsigned short data_type;
+	unsigned short addr_type;
+	unsigned short reg_data;
+	unsigned short delay;
+};
+
+
+struct damping_params_t {
+	unsigned int damping_step;
+	unsigned int damping_delay;
+	unsigned int hw_params;
+};
+
+struct region_params_t {
+	/* [0] = ForwardDirection Macro boundary
+	 *  [1] = ReverseDirection Inf boundary
+	 */
+	unsigned short step_bound[2];
+	unsigned short code_per_step;
+	/* qvalue for converting float type numbers to integer format */
+	unsigned int qvalue;
+};
+
+struct reg_settings_t {
+	unsigned short reg_addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	unsigned short reg_data;
+	enum msm_camera_i2c_data_type data_type;
+	enum msm_actuator_i2c_operation i2c_operation;
+	unsigned int delay;
+};
+
+struct msm_camera_i2c_reg_setting_array {
+	struct msm_camera_i2c_reg_array reg_setting_a[MAX_I2C_REG_SET];
+	unsigned short size;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	enum msm_camera_i2c_data_type data_type;
+	unsigned short delay;
+};
+
+#endif
diff --git a/include/uapi/media/msm_fd.h b/include/uapi/media/msm_fd.h
new file mode 100644
index 0000000..eb3bd78
--- /dev/null
+++ b/include/uapi/media/msm_fd.h
@@ -0,0 +1,76 @@
+#ifndef __UAPI_MSM_FD__
+#define __UAPI_MSM_FD__
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+
+/*
+ * struct msm_fd_event - Structure contain event info.
+ * @buf_index: Buffer index.
+ * @frame_id: Frame id.
+ * @face_cnt: Detected faces.
+ */
+struct msm_fd_event {
+	__u32 buf_index;
+	__u32 frame_id;
+	__u32 face_cnt;
+};
+
+/*
+ * enum msm_fd_pose - Face pose.
+ */
+enum msm_fd_pose {
+	MSM_FD_POSE_FRONT,
+	MSM_FD_POSE_RIGHT_DIAGONAL,
+	MSM_FD_POSE_RIGHT,
+	MSM_FD_POSE_LEFT_DIAGONAL,
+	MSM_FD_POSE_LEFT,
+};
+
+/*
+ * struct msm_fd_face_data - Structure contain detected face data.
+ * @pose: refer to enum msm_fd_pose.
+ * @angle: Face angle
+ * @confidence: Face confidence level.
+ * @reserved: Reserved data for future use.
+ * @face: Face rectangle.
+ */
+struct msm_fd_face_data {
+	__u32 pose;
+	__u32 angle;
+	__u32 confidence;
+	__u32 reserved;
+	struct v4l2_rect face;
+};
+
+/*
+ * struct msm_fd_result - Structure contain detected faces result.
+ * @frame_id: Frame id of requested result.
+ * @face_cnt: Number of result faces, driver can modify this value (to smaller)
+ * @face_data: Pointer to array of face data structures.
+ *  Array size should not be smaller then face_cnt.
+ */
+struct msm_fd_result {
+	__u32 frame_id;
+	__u32 face_cnt;
+	struct msm_fd_face_data __user *face_data;
+};
+
+/* MSM FD private ioctl ID */
+#define VIDIOC_MSM_FD_GET_RESULT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_fd_result)
+
+/* MSM FD event ID */
+#define MSM_EVENT_FD (V4L2_EVENT_PRIVATE_START)
+
+/* MSM FD control ID's */
+#define V4L2_CID_FD_SPEED                (V4L2_CID_PRIVATE_BASE)
+#define V4L2_CID_FD_FACE_ANGLE           (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_FD_MIN_FACE_SIZE        (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_FD_FACE_DIRECTION       (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_FD_DETECTION_THRESHOLD  (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_FD_WORK_MEMORY_SIZE     (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_FD_WORK_MEMORY_FD       (V4L2_CID_PRIVATE_BASE + 6)
+
+#endif
+
diff --git a/include/uapi/media/msm_isp.h b/include/uapi/media/msm_isp.h
new file mode 100644
index 0000000..90d87c2
--- /dev/null
+++ b/include/uapi/media/msm_isp.h
@@ -0,0 +1,344 @@
+#ifndef __UAPI_MSM_ISP_H__
+#define __UAPI_MSM_ISP_H__
+
+#define BIT(nr)			(1UL << (nr))
+
+/* ISP message IDs */
+#define MSG_ID_RESET_ACK                0
+#define MSG_ID_START_ACK                1
+#define MSG_ID_STOP_ACK                 2
+#define MSG_ID_UPDATE_ACK               3
+#define MSG_ID_OUTPUT_P                 4
+#define MSG_ID_OUTPUT_T                 5
+#define MSG_ID_OUTPUT_S                 6
+#define MSG_ID_OUTPUT_V                 7
+#define MSG_ID_SNAPSHOT_DONE            8
+#define MSG_ID_STATS_AEC                9
+#define MSG_ID_STATS_AF                 10
+#define MSG_ID_STATS_AWB                11
+#define MSG_ID_STATS_RS                 12
+#define MSG_ID_STATS_CS                 13
+#define MSG_ID_STATS_IHIST              14
+#define MSG_ID_STATS_SKIN               15
+#define MSG_ID_EPOCH1                   16
+#define MSG_ID_EPOCH2                   17
+#define MSG_ID_SYNC_TIMER0_DONE         18
+#define MSG_ID_SYNC_TIMER1_DONE         19
+#define MSG_ID_SYNC_TIMER2_DONE         20
+#define MSG_ID_ASYNC_TIMER0_DONE        21
+#define MSG_ID_ASYNC_TIMER1_DONE        22
+#define MSG_ID_ASYNC_TIMER2_DONE        23
+#define MSG_ID_ASYNC_TIMER3_DONE        24
+#define MSG_ID_AE_OVERFLOW              25
+#define MSG_ID_AF_OVERFLOW              26
+#define MSG_ID_AWB_OVERFLOW             27
+#define MSG_ID_RS_OVERFLOW              28
+#define MSG_ID_CS_OVERFLOW              29
+#define MSG_ID_IHIST_OVERFLOW           30
+#define MSG_ID_SKIN_OVERFLOW            31
+#define MSG_ID_AXI_ERROR                32
+#define MSG_ID_CAMIF_OVERFLOW           33
+#define MSG_ID_VIOLATION                34
+#define MSG_ID_CAMIF_ERROR              35
+#define MSG_ID_BUS_OVERFLOW             36
+#define MSG_ID_SOF_ACK                  37
+#define MSG_ID_STOP_REC_ACK             38
+#define MSG_ID_STATS_AWB_AEC            39
+#define MSG_ID_OUTPUT_PRIMARY           40
+#define MSG_ID_OUTPUT_SECONDARY         41
+#define MSG_ID_STATS_COMPOSITE          42
+#define MSG_ID_OUTPUT_TERTIARY1         43
+#define MSG_ID_STOP_LS_ACK              44
+#define MSG_ID_OUTPUT_TERTIARY2         45
+#define MSG_ID_STATS_BG                 46
+#define MSG_ID_STATS_BF                 47
+#define MSG_ID_STATS_BHIST              48
+#define MSG_ID_RDI0_UPDATE_ACK          49
+#define MSG_ID_RDI1_UPDATE_ACK          50
+#define MSG_ID_RDI2_UPDATE_ACK          51
+#define MSG_ID_PIX0_UPDATE_ACK          52
+#define MSG_ID_PREV_STOP_ACK            53
+#define MSG_ID_STATS_BE                 54
+
+
+/* ISP command IDs */
+#define VFE_CMD_DUMMY_0                                 0
+#define VFE_CMD_SET_CLK                                 1
+#define VFE_CMD_RESET                                   2
+#define VFE_CMD_START                                   3
+#define VFE_CMD_TEST_GEN_START                          4
+#define VFE_CMD_OPERATION_CFG                           5
+#define VFE_CMD_AXI_OUT_CFG                             6
+#define VFE_CMD_CAMIF_CFG                               7
+#define VFE_CMD_AXI_INPUT_CFG                           8
+#define VFE_CMD_BLACK_LEVEL_CFG                         9
+#define VFE_CMD_MESH_ROLL_OFF_CFG                       10
+#define VFE_CMD_DEMUX_CFG                               11
+#define VFE_CMD_FOV_CFG                                 12
+#define VFE_CMD_MAIN_SCALER_CFG                         13
+#define VFE_CMD_WB_CFG                                  14
+#define VFE_CMD_COLOR_COR_CFG                           15
+#define VFE_CMD_RGB_G_CFG                               16
+#define VFE_CMD_LA_CFG                                  17
+#define VFE_CMD_CHROMA_EN_CFG                           18
+#define VFE_CMD_CHROMA_SUP_CFG                          19
+#define VFE_CMD_MCE_CFG                                 20
+#define VFE_CMD_SK_ENHAN_CFG                            21
+#define VFE_CMD_ASF_CFG                                 22
+#define VFE_CMD_S2Y_CFG                                 23
+#define VFE_CMD_S2CbCr_CFG                              24
+#define VFE_CMD_CHROMA_SUBS_CFG                         25
+#define VFE_CMD_OUT_CLAMP_CFG                           26
+#define VFE_CMD_FRAME_SKIP_CFG                          27
+#define VFE_CMD_DUMMY_1                                 28
+#define VFE_CMD_DUMMY_2                                 29
+#define VFE_CMD_DUMMY_3                                 30
+#define VFE_CMD_UPDATE                                  31
+#define VFE_CMD_BL_LVL_UPDATE                           32
+#define VFE_CMD_DEMUX_UPDATE                            33
+#define VFE_CMD_FOV_UPDATE                              34
+#define VFE_CMD_MAIN_SCALER_UPDATE                      35
+#define VFE_CMD_WB_UPDATE                               36
+#define VFE_CMD_COLOR_COR_UPDATE                        37
+#define VFE_CMD_RGB_G_UPDATE                            38
+#define VFE_CMD_LA_UPDATE                               39
+#define VFE_CMD_CHROMA_EN_UPDATE                        40
+#define VFE_CMD_CHROMA_SUP_UPDATE                       41
+#define VFE_CMD_MCE_UPDATE                              42
+#define VFE_CMD_SK_ENHAN_UPDATE                         43
+#define VFE_CMD_S2CbCr_UPDATE                           44
+#define VFE_CMD_S2Y_UPDATE                              45
+#define VFE_CMD_ASF_UPDATE                              46
+#define VFE_CMD_FRAME_SKIP_UPDATE                       47
+#define VFE_CMD_CAMIF_FRAME_UPDATE                      48
+#define VFE_CMD_STATS_AF_UPDATE                         49
+#define VFE_CMD_STATS_AE_UPDATE                         50
+#define VFE_CMD_STATS_AWB_UPDATE                        51
+#define VFE_CMD_STATS_RS_UPDATE                         52
+#define VFE_CMD_STATS_CS_UPDATE                         53
+#define VFE_CMD_STATS_SKIN_UPDATE                       54
+#define VFE_CMD_STATS_IHIST_UPDATE                      55
+#define VFE_CMD_DUMMY_4                                 56
+#define VFE_CMD_EPOCH1_ACK                              57
+#define VFE_CMD_EPOCH2_ACK                              58
+#define VFE_CMD_START_RECORDING                         59
+#define VFE_CMD_STOP_RECORDING                          60
+#define VFE_CMD_DUMMY_5                                 61
+#define VFE_CMD_DUMMY_6                                 62
+#define VFE_CMD_CAPTURE                                 63
+#define VFE_CMD_DUMMY_7                                 64
+#define VFE_CMD_STOP                                    65
+#define VFE_CMD_GET_HW_VERSION                          66
+#define VFE_CMD_GET_FRAME_SKIP_COUNTS                   67
+#define VFE_CMD_OUTPUT1_BUFFER_ENQ                      68
+#define VFE_CMD_OUTPUT2_BUFFER_ENQ                      69
+#define VFE_CMD_OUTPUT3_BUFFER_ENQ                      70
+#define VFE_CMD_JPEG_OUT_BUF_ENQ                        71
+#define VFE_CMD_RAW_OUT_BUF_ENQ                         72
+#define VFE_CMD_RAW_IN_BUF_ENQ                          73
+#define VFE_CMD_STATS_AF_ENQ                            74
+#define VFE_CMD_STATS_AE_ENQ                            75
+#define VFE_CMD_STATS_AWB_ENQ                           76
+#define VFE_CMD_STATS_RS_ENQ                            77
+#define VFE_CMD_STATS_CS_ENQ                            78
+#define VFE_CMD_STATS_SKIN_ENQ                          79
+#define VFE_CMD_STATS_IHIST_ENQ                         80
+#define VFE_CMD_DUMMY_8                                 81
+#define VFE_CMD_JPEG_ENC_CFG                            82
+#define VFE_CMD_DUMMY_9                                 83
+#define VFE_CMD_STATS_AF_START                          84
+#define VFE_CMD_STATS_AF_STOP                           85
+#define VFE_CMD_STATS_AE_START                          86
+#define VFE_CMD_STATS_AE_STOP                           87
+#define VFE_CMD_STATS_AWB_START                         88
+#define VFE_CMD_STATS_AWB_STOP                          89
+#define VFE_CMD_STATS_RS_START                          90
+#define VFE_CMD_STATS_RS_STOP                           91
+#define VFE_CMD_STATS_CS_START                          92
+#define VFE_CMD_STATS_CS_STOP                           93
+#define VFE_CMD_STATS_SKIN_START                        94
+#define VFE_CMD_STATS_SKIN_STOP                         95
+#define VFE_CMD_STATS_IHIST_START                       96
+#define VFE_CMD_STATS_IHIST_STOP                        97
+#define VFE_CMD_DUMMY_10                                98
+#define VFE_CMD_SYNC_TIMER_SETTING                      99
+#define VFE_CMD_ASYNC_TIMER_SETTING                     100
+#define VFE_CMD_LIVESHOT                                101
+#define VFE_CMD_LA_SETUP                                102
+#define VFE_CMD_LINEARIZATION_CFG                       103
+#define VFE_CMD_DEMOSAICV3                              104
+#define VFE_CMD_DEMOSAICV3_ABCC_CFG                     105
+#define VFE_CMD_DEMOSAICV3_DBCC_CFG                     106
+#define VFE_CMD_DEMOSAICV3_DBPC_CFG                     107
+#define VFE_CMD_DEMOSAICV3_ABF_CFG                      108
+#define VFE_CMD_DEMOSAICV3_ABCC_UPDATE                  109
+#define VFE_CMD_DEMOSAICV3_DBCC_UPDATE                  110
+#define VFE_CMD_DEMOSAICV3_DBPC_UPDATE                  111
+#define VFE_CMD_XBAR_CFG                                112
+#define VFE_CMD_MODULE_CFG                              113
+#define VFE_CMD_ZSL                                     114
+#define VFE_CMD_LINEARIZATION_UPDATE                    115
+#define VFE_CMD_DEMOSAICV3_ABF_UPDATE                   116
+#define VFE_CMD_CLF_CFG                                 117
+#define VFE_CMD_CLF_LUMA_UPDATE                         118
+#define VFE_CMD_CLF_CHROMA_UPDATE                       119
+#define VFE_CMD_PCA_ROLL_OFF_CFG                        120
+#define VFE_CMD_PCA_ROLL_OFF_UPDATE                     121
+#define VFE_CMD_GET_REG_DUMP                            122
+#define VFE_CMD_GET_LINEARIZATON_TABLE                  123
+#define VFE_CMD_GET_MESH_ROLLOFF_TABLE                  124
+#define VFE_CMD_GET_PCA_ROLLOFF_TABLE                   125
+#define VFE_CMD_GET_RGB_G_TABLE                         126
+#define VFE_CMD_GET_LA_TABLE                            127
+#define VFE_CMD_DEMOSAICV3_UPDATE                       128
+#define VFE_CMD_ACTIVE_REGION_CFG                       129
+#define VFE_CMD_COLOR_PROCESSING_CONFIG                 130
+#define VFE_CMD_STATS_WB_AEC_CONFIG                     131
+#define VFE_CMD_STATS_WB_AEC_UPDATE                     132
+#define VFE_CMD_Y_GAMMA_CONFIG                          133
+#define VFE_CMD_SCALE_OUTPUT1_CONFIG                    134
+#define VFE_CMD_SCALE_OUTPUT2_CONFIG                    135
+#define VFE_CMD_CAPTURE_RAW                             136
+#define VFE_CMD_STOP_LIVESHOT                           137
+#define VFE_CMD_RECONFIG_VFE                            138
+#define VFE_CMD_STATS_REQBUF                            139
+#define VFE_CMD_STATS_ENQUEUEBUF                        140
+#define VFE_CMD_STATS_FLUSH_BUFQ                        141
+#define VFE_CMD_STATS_UNREGBUF                          142
+#define VFE_CMD_STATS_BG_START                          143
+#define VFE_CMD_STATS_BG_STOP                           144
+#define VFE_CMD_STATS_BF_START                          145
+#define VFE_CMD_STATS_BF_STOP                           146
+#define VFE_CMD_STATS_BHIST_START                       147
+#define VFE_CMD_STATS_BHIST_STOP                        148
+#define VFE_CMD_RESET_2                                 149
+#define VFE_CMD_FOV_ENC_CFG                             150
+#define VFE_CMD_FOV_VIEW_CFG                            151
+#define VFE_CMD_FOV_ENC_UPDATE                          152
+#define VFE_CMD_FOV_VIEW_UPDATE                         153
+#define VFE_CMD_SCALER_ENC_CFG                          154
+#define VFE_CMD_SCALER_VIEW_CFG                         155
+#define VFE_CMD_SCALER_ENC_UPDATE                       156
+#define VFE_CMD_SCALER_VIEW_UPDATE                      157
+#define VFE_CMD_COLORXFORM_ENC_CFG                      158
+#define VFE_CMD_COLORXFORM_VIEW_CFG                     159
+#define VFE_CMD_COLORXFORM_ENC_UPDATE                   160
+#define VFE_CMD_COLORXFORM_VIEW_UPDATE                  161
+#define VFE_CMD_TEST_GEN_CFG                            162
+#define VFE_CMD_STATS_BE_START                          163
+#define VFE_CMD_STATS_BE_STOP                           164
+struct msm_isp_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+#define VPE_CMD_DUMMY_0                                 0
+#define VPE_CMD_INIT                                    1
+#define VPE_CMD_DEINIT                                  2
+#define VPE_CMD_ENABLE                                  3
+#define VPE_CMD_DISABLE                                 4
+#define VPE_CMD_RESET                                   5
+#define VPE_CMD_FLUSH                                   6
+#define VPE_CMD_OPERATION_MODE_CFG                      7
+#define VPE_CMD_INPUT_PLANE_CFG                         8
+#define VPE_CMD_OUTPUT_PLANE_CFG                        9
+#define VPE_CMD_INPUT_PLANE_UPDATE                      10
+#define VPE_CMD_SCALE_CFG_TYPE                          11
+#define VPE_CMD_ZOOM                                    13
+#define VPE_CMD_MAX                                     14
+
+#define MSM_PP_CMD_TYPE_NOT_USED        0  /* not used */
+#define MSM_PP_CMD_TYPE_VPE             1  /* VPE cmd */
+#define MSM_PP_CMD_TYPE_MCTL            2  /* MCTL cmd */
+
+#define MCTL_CMD_DUMMY_0                0  /* not used */
+#define MCTL_CMD_GET_FRAME_BUFFER       1  /* reserve a free frame buffer */
+#define MCTL_CMD_PUT_FRAME_BUFFER       2  /* return the free frame buffer */
+#define MCTL_CMD_DIVERT_FRAME_PP_PATH   3  /* divert frame for pp */
+
+/* event typese sending to MCTL PP module */
+#define MCTL_PP_EVENT_NOTUSED           0
+#define MCTL_PP_EVENT_CMD_ACK           1
+
+#define VPE_OPERATION_MODE_CFG_LEN      4
+#define VPE_INPUT_PLANE_CFG_LEN         24
+#define VPE_OUTPUT_PLANE_CFG_LEN        20
+#define VPE_INPUT_PLANE_UPDATE_LEN      12
+#define VPE_SCALER_CONFIG_LEN           260
+#define VPE_DIS_OFFSET_CFG_LEN          12
+
+
+#define CAPTURE_WIDTH          1280
+#define IMEM_Y_SIZE            (CAPTURE_WIDTH*16)
+#define IMEM_CBCR_SIZE         (CAPTURE_WIDTH*8)
+
+#define IMEM_Y_PING_OFFSET     0x2E000000
+#define IMEM_CBCR_PING_OFFSET  (IMEM_Y_PING_OFFSET + IMEM_Y_SIZE)
+
+#define IMEM_Y_PONG_OFFSET     (IMEM_CBCR_PING_OFFSET + IMEM_CBCR_SIZE)
+#define IMEM_CBCR_PONG_OFFSET  (IMEM_Y_PONG_OFFSET + IMEM_Y_SIZE)
+
+
+struct msm_vpe_op_mode_cfg {
+	uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_cfg {
+	uint8_t input_plane_cfg[VPE_INPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_output_plane_cfg {
+	uint8_t output_plane_cfg[VPE_OUTPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_update_cfg {
+	uint8_t input_plane_update_cfg[VPE_INPUT_PLANE_UPDATE_LEN];
+};
+
+struct msm_vpe_scaler_cfg {
+	uint8_t scaler_cfg[VPE_SCALER_CONFIG_LEN];
+};
+
+struct msm_vpe_flush_frame_buffer {
+	uint32_t src_buf_handle;
+	uint32_t dest_buf_handle;
+	int path;
+};
+
+struct msm_mctl_pp_frame_buffer {
+	uint32_t buf_handle;
+	int path;
+};
+struct msm_mctl_pp_divert_pp {
+	int path;
+	int enable;
+};
+struct msm_vpe_clock_rate {
+	uint32_t rate;
+};
+
+#define MSM_MCTL_PP_VPE_FRAME_ACK    (1<<0)
+#define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1)
+
+#define VFE_OUTPUTS_MAIN_AND_PREVIEW    BIT(0)
+#define VFE_OUTPUTS_MAIN_AND_VIDEO      BIT(1)
+#define VFE_OUTPUTS_MAIN_AND_THUMB      BIT(2)
+#define VFE_OUTPUTS_THUMB_AND_MAIN      BIT(3)
+#define VFE_OUTPUTS_PREVIEW_AND_VIDEO   BIT(4)
+#define VFE_OUTPUTS_VIDEO_AND_PREVIEW   BIT(5)
+#define VFE_OUTPUTS_PREVIEW             BIT(6)
+#define VFE_OUTPUTS_VIDEO               BIT(7)
+#define VFE_OUTPUTS_RAW                 BIT(8)
+#define VFE_OUTPUTS_JPEG_AND_THUMB      BIT(9)
+#define VFE_OUTPUTS_THUMB_AND_JPEG      BIT(10)
+#define VFE_OUTPUTS_RDI0                BIT(11)
+#define VFE_OUTPUTS_RDI1                BIT(12)
+
+struct msm_frame_info {
+	uint32_t inst_handle;
+	uint32_t path;
+};
+
+#endif /*__UAPI_MSM_ISP_H__*/
+
diff --git a/include/uapi/media/msm_jpeg.h b/include/uapi/media/msm_jpeg.h
new file mode 100644
index 0000000..897a180
--- /dev/null
+++ b/include/uapi/media/msm_jpeg.h
@@ -0,0 +1,125 @@
+#ifndef __UAPI_LINUX_MSM_JPEG_H
+#define __UAPI_LINUX_MSM_JPEG_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define OUTPUT_H2V1  0
+#define OUTPUT_H2V2  1
+#define OUTPUT_BYTE  6
+
+#define MSM_JPEG_IOCTL_MAGIC 'g'
+
+#define MSM_JPEG_IOCTL_GET_HW_VERSION \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd)
+
+#define MSM_JPEG_IOCTL_RESET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd)
+
+#define MSM_JPEG_IOCTL_STOP \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds)
+
+#define MSM_JPEG_IOCTL_START \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds)
+
+#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf)
+
+#define MSM_JPEG_IOCTL_INPUT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf)
+
+#define MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 7, int)
+
+#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 10, int)
+
+#define MSM_JPEG_IOCTL_EVT_GET \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd)
+
+#define MSM_JPEG_IOCTL_EVT_GET_UNBLOCK \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 12, int)
+
+#define MSM_JPEG_IOCTL_HW_CMD \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd)
+
+#define MSM_JPEG_IOCTL_HW_CMDS \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds)
+
+#define MSM_JPEG_IOCTL_TEST_DUMP_REGION \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 15, unsigned long)
+
+#define MSM_JPEG_IOCTL_SET_CLK_RATE \
+	_IOW(MSM_JPEG_IOCTL_MAGIC, 16, unsigned int)
+
+#define MSM_JPEG_MODE_REALTIME_ENCODE 0
+#define MSM_JPEG_MODE_OFFLINE_ENCODE 1
+#define MSM_JPEG_MODE_REALTIME_ROTATION 2
+#define MSM_JPEG_MODE_OFFLINE_ROTATION 3
+
+struct msm_jpeg_ctrl_cmd {
+	uint32_t type;
+	uint32_t len;
+	void     *value;
+};
+
+#define MSM_JPEG_EVT_RESET 0
+#define MSM_JPEG_EVT_SESSION_DONE	1
+#define MSM_JPEG_EVT_ERR 2
+
+struct msm_jpeg_buf {
+	uint32_t type;
+	int      fd;
+
+	void     *vaddr;
+
+	uint32_t y_off;
+	uint32_t y_len;
+	uint32_t framedone_len;
+
+	uint32_t cbcr_off;
+	uint32_t cbcr_len;
+
+	uint32_t num_of_mcu_rows;
+	uint32_t offset;
+	uint32_t pln2_off;
+	uint32_t pln2_len;
+};
+
+#define MSM_JPEG_HW_CMD_TYPE_READ      0
+#define MSM_JPEG_HW_CMD_TYPE_WRITE     1
+#define MSM_JPEG_HW_CMD_TYPE_WRITE_OR  2
+#define MSM_JPEG_HW_CMD_TYPE_UWAIT     3
+#define MSM_JPEG_HW_CMD_TYPE_MWAIT     4
+#define MSM_JPEG_HW_CMD_TYPE_MDELAY    5
+#define MSM_JPEG_HW_CMD_TYPE_UDELAY    6
+struct msm_jpeg_hw_cmd {
+
+	uint32_t type:4;
+
+	/* n microseconds of timeout for WAIT */
+	/* n microseconds of time for DELAY */
+	/* repeat n times for READ/WRITE */
+	/* max is 0xFFF, 4095 */
+	uint32_t n:12;
+	uint32_t offset:16;
+	uint32_t mask;
+	union {
+		uint32_t data;   /* for single READ/WRITE/WAIT, n = 1 */
+		uint32_t *pdata;   /* for multiple READ/WRITE/WAIT, n > 1 */
+	};
+};
+
+struct msm_jpeg_hw_cmds {
+	uint32_t m; /* number of elements in the hw_cmd array */
+	struct msm_jpeg_hw_cmd hw_cmd[1];
+};
+
+#endif
+
diff --git a/include/uapi/media/msm_jpeg_dma.h b/include/uapi/media/msm_jpeg_dma.h
new file mode 100644
index 0000000..a3eab9f
--- /dev/null
+++ b/include/uapi/media/msm_jpeg_dma.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __UAPI_MSM_JPEG_DMA__
+#define __UAPI_MSM_JPEG_DMA__
+
+#include <linux/videodev2.h>
+
+/* msm jpeg dma control ID's */
+#define V4L2_CID_JPEG_DMA_SPEED (V4L2_CID_PRIVATE_BASE)
+#define V4L2_CID_JPEG_DMA_MAX_DOWN_SCALE (V4L2_CID_PRIVATE_BASE + 1)
+
+/* msm_jpeg_dma_buf */
+struct msm_jpeg_dma_buff {
+	int32_t fd;
+	uint32_t offset;
+};
+
+#endif /* __UAPI_MSM_JPEG_DMA__ */
diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h
index 63fd555..cac2b32 100644
--- a/include/uapi/media/msm_vidc.h
+++ b/include/uapi/media/msm_vidc.h
@@ -242,6 +242,8 @@
 	MSM_VIDC_EXTRADATA_NONE = 0x00000000,
 	MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001,
 	MSM_VIDC_EXTRADATA_INTERLACE_VIDEO = 0x00000002,
+	MSM_VIDC_EXTRADATA_VC1_FRAMEDISP = 0x00000003,
+	MSM_VIDC_EXTRADATA_VC1_SEQDISP = 0x00000004,
 	MSM_VIDC_EXTRADATA_TIMESTAMP = 0x00000005,
 	MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING = 0x00000006,
 	MSM_VIDC_EXTRADATA_FRAME_RATE = 0x00000007,
@@ -294,6 +296,9 @@
 	MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
 	MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
 	MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+#define MSM_VIDC_INTERLACE_FRAME_MBAFF \
+	MSM_VIDC_INTERLACE_FRAME_MBAFF
+	MSM_VIDC_INTERLACE_FRAME_MBAFF = 0x20,
 };
 
 /* enum msm_vidc_framepack_type */
@@ -411,7 +416,7 @@
 /*enum msm_vidc_pic_struct */
 #define MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED 0x0
 #define MSM_VIDC_PIC_STRUCT_PROGRESSIVE 0x1
-
+#define MSM_VIDC_PIC_STRUCT_UNKNOWN 0XFFFFFFFF
 /*default when layer ID isn't specified*/
 #define MSM_VIDC_ALL_LAYER_ID 0xFF
 
diff --git a/include/uapi/media/msmb_camera.h b/include/uapi/media/msmb_camera.h
new file mode 100644
index 0000000..8bb2f8c
--- /dev/null
+++ b/include/uapi/media/msmb_camera.h
@@ -0,0 +1,234 @@
+#ifndef __UAPI_LINUX_MSMB_CAMERA_H
+#define __UAPI_LINUX_MSMB_CAMERA_H
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/media.h>
+
+#define MSM_CAM_LOGSYNC_FILE_NAME "logsync"
+#define MSM_CAM_LOGSYNC_FILE_BASEDIR "camera"
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 30, struct msm_v4l2_event_data)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_META \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 31, struct msm_v4l2_event_data)
+
+#define MSM_CAM_V4L2_IOCTL_CMD_ACK \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 32, struct msm_v4l2_event_data)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 33, struct msm_v4l2_event_data)
+
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 34, struct msm_v4l2_event_data)
+
+#define MSM_CAM_V4L2_IOCTL_DAEMON_DISABLED \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 35, struct msm_v4l2_event_data)
+
+#define QCAMERA_VNODE_GROUP_ID	MEDIA_ENT_F_IO_V4L
+#define MSM_CAMERA_NAME			"msm_camera"
+#define MSM_CONFIGURATION_NAME	"msm_config"
+
+//#define MSM_CAMERA_SUBDEV_BASE         (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
+#define MSM_CAMERA_SUBDEV_BASE         (MEDIA_ENT_F_OLD_BASE + 0xF00)
+#define MSM_CAMERA_SUBDEV_CSIPHY       (MSM_CAMERA_SUBDEV_BASE + 0)
+//#define MSM_CAMERA_SUBDEV_CSID         (MSM_CAMERA_SUBDEV_BASE + 1)
+#define MSM_CAMERA_SUBDEV_CSID         (MSM_CAMERA_SUBDEV_BASE + 13)
+#define MSM_CAMERA_SUBDEV_ISPIF        (MSM_CAMERA_SUBDEV_BASE + 2)
+#define MSM_CAMERA_SUBDEV_VFE          (MSM_CAMERA_SUBDEV_BASE + 3)
+#define MSM_CAMERA_SUBDEV_AXI          (MSM_CAMERA_SUBDEV_BASE + 4)
+#define MSM_CAMERA_SUBDEV_VPE          (MSM_CAMERA_SUBDEV_BASE + 5)
+#define MSM_CAMERA_SUBDEV_SENSOR       (MSM_CAMERA_SUBDEV_BASE + 6)
+#define MSM_CAMERA_SUBDEV_ACTUATOR     (MSM_CAMERA_SUBDEV_BASE + 7)
+#define MSM_CAMERA_SUBDEV_EEPROM       (MSM_CAMERA_SUBDEV_BASE + 8)
+#define MSM_CAMERA_SUBDEV_CPP          (MSM_CAMERA_SUBDEV_BASE + 9)
+#define MSM_CAMERA_SUBDEV_CCI          (MSM_CAMERA_SUBDEV_BASE + 10)
+#define MSM_CAMERA_SUBDEV_LED_FLASH    (MSM_CAMERA_SUBDEV_BASE + 11)
+#define MSM_CAMERA_SUBDEV_STROBE_FLASH (MSM_CAMERA_SUBDEV_BASE + 12)
+#define MSM_CAMERA_SUBDEV_BUF_MNGR     (MSM_CAMERA_SUBDEV_BASE + 1)
+//#define MSM_CAMERA_SUBDEV_BUF_MNGR     (MSM_CAMERA_SUBDEV_BASE + 13)
+#define MSM_CAMERA_SUBDEV_SENSOR_INIT  (MSM_CAMERA_SUBDEV_BASE + 14)
+#define MSM_CAMERA_SUBDEV_OIS          (MSM_CAMERA_SUBDEV_BASE + 15)
+#define MSM_CAMERA_SUBDEV_FLASH        (MSM_CAMERA_SUBDEV_BASE + 16)
+#define MSM_CAMERA_SUBDEV_IR_LED       (MSM_CAMERA_SUBDEV_BASE + 17)
+#define MSM_CAMERA_SUBDEV_IR_CUT       (MSM_CAMERA_SUBDEV_BASE + 18)
+#define MSM_CAMERA_SUBDEV_EXT          (MSM_CAMERA_SUBDEV_BASE + 19)
+#define MSM_CAMERA_SUBDEV_TOF          (MSM_CAMERA_SUBDEV_BASE + 20)
+#define MSM_CAMERA_SUBDEV_LASER_LED    (MSM_CAMERA_SUBDEV_BASE + 21)
+#define MSM_MAX_CAMERA_SENSORS  5
+
+/* The below macro is defined to put an upper limit on maximum
+ * number of buffer requested per stream. In case of extremely
+ * large value for number of buffer due to data structure corruption
+ * we return error to avoid integer overflow. Group processing
+ * can have max of 9 groups of 8 bufs each. This value may be
+ * configured in future
+ */
+#define MSM_CAMERA_MAX_STREAM_BUF 72
+
+/* Max batch size of processing */
+#define MSM_CAMERA_MAX_USER_BUFF_CNT 16
+
+/* featur base */
+#define MSM_CAMERA_FEATURE_BASE     0x00010000
+#define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1)
+
+#define MSM_CAMERA_STATUS_BASE      0x00020000
+#define MSM_CAMERA_STATUS_FAIL      (MSM_CAMERA_STATUS_BASE + 1)
+#define MSM_CAMERA_STATUS_SUCCESS   (MSM_CAMERA_STATUS_BASE + 2)
+
+/* event type */
+#define MSM_CAMERA_V4L2_EVENT_TYPE (V4L2_EVENT_PRIVATE_START + 0x00002000)
+
+/* event id */
+#define MSM_CAMERA_EVENT_MIN    0
+#define MSM_CAMERA_NEW_SESSION  (MSM_CAMERA_EVENT_MIN + 1)
+#define MSM_CAMERA_DEL_SESSION  (MSM_CAMERA_EVENT_MIN + 2)
+#define MSM_CAMERA_SET_PARM     (MSM_CAMERA_EVENT_MIN + 3)
+#define MSM_CAMERA_GET_PARM     (MSM_CAMERA_EVENT_MIN + 4)
+#define MSM_CAMERA_MAPPING_CFG  (MSM_CAMERA_EVENT_MIN + 5)
+#define MSM_CAMERA_MAPPING_SES  (MSM_CAMERA_EVENT_MIN + 6)
+#define MSM_CAMERA_MSM_NOTIFY   (MSM_CAMERA_EVENT_MIN + 7)
+#define MSM_CAMERA_EVENT_MAX    (MSM_CAMERA_EVENT_MIN + 8)
+
+/* data.command */
+#define MSM_CAMERA_PRIV_S_CROP			(V4L2_CID_PRIVATE_BASE + 1)
+#define MSM_CAMERA_PRIV_G_CROP			(V4L2_CID_PRIVATE_BASE + 2)
+#define MSM_CAMERA_PRIV_G_FMT			(V4L2_CID_PRIVATE_BASE + 3)
+#define MSM_CAMERA_PRIV_S_FMT			(V4L2_CID_PRIVATE_BASE + 4)
+#define MSM_CAMERA_PRIV_TRY_FMT			(V4L2_CID_PRIVATE_BASE + 5)
+#define MSM_CAMERA_PRIV_METADATA		(V4L2_CID_PRIVATE_BASE + 6)
+#define MSM_CAMERA_PRIV_QUERY_CAP		(V4L2_CID_PRIVATE_BASE + 7)
+#define MSM_CAMERA_PRIV_STREAM_ON		(V4L2_CID_PRIVATE_BASE + 8)
+#define MSM_CAMERA_PRIV_STREAM_OFF		(V4L2_CID_PRIVATE_BASE + 9)
+#define MSM_CAMERA_PRIV_NEW_STREAM		(V4L2_CID_PRIVATE_BASE + 10)
+#define MSM_CAMERA_PRIV_DEL_STREAM		(V4L2_CID_PRIVATE_BASE + 11)
+#define MSM_CAMERA_PRIV_SHUTDOWN		(V4L2_CID_PRIVATE_BASE + 12)
+#define MSM_CAMERA_PRIV_STREAM_INFO_SYNC \
+	(V4L2_CID_PRIVATE_BASE + 13)
+#define MSM_CAMERA_PRIV_G_SESSION_ID (V4L2_CID_PRIVATE_BASE + 14)
+#define MSM_CAMERA_PRIV_CMD_MAX  20
+
+/* data.status - success */
+#define MSM_CAMERA_CMD_SUCCESS      0x00000001
+#define MSM_CAMERA_BUF_MAP_SUCCESS  0x00000002
+
+/* data.status - error */
+#define MSM_CAMERA_ERR_EVT_BASE 0x00010000
+#define MSM_CAMERA_ERR_CMD_FAIL		(MSM_CAMERA_ERR_EVT_BASE + 1)
+#define MSM_CAMERA_ERR_MAPPING		(MSM_CAMERA_ERR_EVT_BASE + 2)
+#define MSM_CAMERA_ERR_DEVICE_BUSY	(MSM_CAMERA_ERR_EVT_BASE + 3)
+
+/* The msm_v4l2_event_data structure should match the
+ * v4l2_event.u.data field.
+ * should not exceed 16 elements
+ */
+struct msm_v4l2_event_data {
+	/*word 0*/
+	unsigned int command;
+	/*word 1*/
+	unsigned int status;
+	/*word 2*/
+	unsigned int session_id;
+	/*word 3*/
+	unsigned int stream_id;
+	/*word 4*/
+	unsigned int map_op;
+	/*word 5*/
+	unsigned int map_buf_idx;
+	/*word 6*/
+	unsigned int notify;
+	/*word 7*/
+	unsigned int arg_value;
+	/*word 8*/
+	unsigned int ret_value;
+	/*word 9*/
+	unsigned int v4l2_event_type;
+	/*word 10*/
+	unsigned int v4l2_event_id;
+	/*word 11*/
+	unsigned int handle;
+	/*word 12*/
+	unsigned int nop6;
+	/*word 13*/
+	unsigned int nop7;
+	/*word 14*/
+	unsigned int nop8;
+	/*word 15*/
+	unsigned int nop9;
+};
+
+/* map to v4l2_format.fmt.raw_data */
+struct msm_v4l2_format_data {
+	enum v4l2_buf_type type;
+	unsigned int width;
+	unsigned int height;
+	unsigned int pixelformat; /* FOURCC */
+	unsigned char num_planes;
+	unsigned int plane_sizes[VIDEO_MAX_PLANES];
+};
+
+/*  MSM Four-character-code (FOURCC) */
+#define msm_v4l2_fourcc(a, b, c, d)\
+	((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) |\
+	((__u32)(d) << 24))
+
+/* Composite stats */
+#define MSM_V4L2_PIX_FMT_STATS_COMB v4l2_fourcc('S', 'T', 'C', 'M')
+/* AEC stats */
+#define MSM_V4L2_PIX_FMT_STATS_AE   v4l2_fourcc('S', 'T', 'A', 'E')
+/* AF stats */
+#define MSM_V4L2_PIX_FMT_STATS_AF   v4l2_fourcc('S', 'T', 'A', 'F')
+/* AWB stats */
+#define MSM_V4L2_PIX_FMT_STATS_AWB  v4l2_fourcc('S', 'T', 'W', 'B')
+/* IHIST stats */
+#define MSM_V4L2_PIX_FMT_STATS_IHST v4l2_fourcc('I', 'H', 'S', 'T')
+/* Column count stats */
+#define MSM_V4L2_PIX_FMT_STATS_CS   v4l2_fourcc('S', 'T', 'C', 'S')
+/* Row count stats */
+#define MSM_V4L2_PIX_FMT_STATS_RS   v4l2_fourcc('S', 'T', 'R', 'S')
+/* Bayer Grid stats */
+#define MSM_V4L2_PIX_FMT_STATS_BG   v4l2_fourcc('S', 'T', 'B', 'G')
+/* Bayer focus stats */
+#define MSM_V4L2_PIX_FMT_STATS_BF   v4l2_fourcc('S', 'T', 'B', 'F')
+/* Bayer hist stats */
+#define MSM_V4L2_PIX_FMT_STATS_BHST v4l2_fourcc('B', 'H', 'S', 'T')
+
+enum smmu_attach_mode {
+	NON_SECURE_MODE = 0x01,
+	SECURE_MODE = 0x02,
+	MAX_PROTECTION_MODE = 0x03,
+};
+
+struct msm_camera_smmu_attach_type {
+	enum smmu_attach_mode attach;
+};
+
+struct msm_camera_user_buf_cont_t {
+	unsigned int buf_cnt;
+	unsigned int buf_idx[MSM_CAMERA_MAX_USER_BUFF_CNT];
+};
+
+struct msm_camera_return_buf {
+	__u32 index;
+	__u32 reserved;
+};
+
+#define MSM_CAMERA_PRIV_IOCTL_ID_BASE 0
+#define MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF 1
+
+struct msm_camera_private_ioctl_arg {
+	__u32 id;
+	__u32 size;
+	__u32 result;
+	__u32 reserved;
+	__u64 ioctl_ptr;
+};
+
+#define VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_private_ioctl_arg)
+
+#endif
+
diff --git a/include/uapi/media/msmb_generic_buf_mgr.h b/include/uapi/media/msmb_generic_buf_mgr.h
new file mode 100644
index 0000000..2961cae
--- /dev/null
+++ b/include/uapi/media/msmb_generic_buf_mgr.h
@@ -0,0 +1,66 @@
+#ifndef __UAPI_MEDIA_MSMB_GENERIC_BUF_MGR_H__
+#define __UAPI_MEDIA_MSMB_GENERIC_BUF_MGR_H__
+
+#include <media/msmb_camera.h>
+
+enum msm_camera_buf_mngr_cmd {
+	MSM_CAMERA_BUF_MNGR_CONT_MAP,
+	MSM_CAMERA_BUF_MNGR_CONT_UNMAP,
+	MSM_CAMERA_BUF_MNGR_CONT_MAX,
+};
+
+enum msm_camera_buf_mngr_buf_type {
+	MSM_CAMERA_BUF_MNGR_BUF_PLANAR,
+	MSM_CAMERA_BUF_MNGR_BUF_USER,
+	MSM_CAMERA_BUF_MNGR_BUF_INVALID,
+};
+
+struct msm_buf_mngr_info {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t frame_id;
+	struct timeval timestamp;
+	uint32_t index;
+	uint32_t reserved;
+	enum msm_camera_buf_mngr_buf_type type;
+	struct msm_camera_user_buf_cont_t user_buf;
+};
+
+struct msm_buf_mngr_main_cont_info {
+	uint32_t session_id;
+	uint32_t stream_id;
+	enum msm_camera_buf_mngr_cmd cmd;
+	uint32_t cnt;
+	int32_t cont_fd;
+};
+
+#define MSM_CAMERA_BUF_MNGR_IOCTL_ID_BASE 0
+#define MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX 1
+
+#define VIDIOC_MSM_BUF_MNGR_GET_BUF \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 33, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_PUT_BUF \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 34, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_BUF_DONE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_CONT_CMD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_main_cont_info)
+
+#define VIDIOC_MSM_BUF_MNGR_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_DEINIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 38, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_FLUSH \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 39, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_IOCTL_CMD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 40, \
+	struct msm_camera_private_ioctl_arg)
+
+#endif
+
diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h
new file mode 100644
index 0000000..2b10748
--- /dev/null
+++ b/include/uapi/media/msmb_isp.h
@@ -0,0 +1,1042 @@
+#ifndef __UAPI_MSMB_ISP__
+#define __UAPI_MSMB_ISP__
+
+#include <linux/videodev2.h>
+#include <media/msmb_camera.h>
+
+#define MAX_PLANES_PER_STREAM 3
+#define MAX_NUM_STREAM 7
+
+#define ISP_VERSION_48        48
+#define ISP_VERSION_47        47
+#define ISP_VERSION_46        46
+#define ISP_VERSION_44        44
+#define ISP_VERSION_40        40
+#define ISP_VERSION_32        32
+#define ISP_NATIVE_BUF_BIT    (0x10000 << 0)
+#define ISP0_BIT              (0x10000 << 1)
+#define ISP1_BIT              (0x10000 << 2)
+#define ISP_META_CHANNEL_BIT  (0x10000 << 3)
+#define ISP_SCRATCH_BUF_BIT   (0x10000 << 4)
+#define ISP_OFFLINE_STATS_BIT (0x10000 << 5)
+#define ISP_SVHDR_IN_BIT      (0x10000 << 6) /* RDI hw stream for SVHDR */
+#define ISP_SVHDR_OUT_BIT     (0x10000 << 7) /* SVHDR output bufq stream*/
+
+#define ISP_STATS_STREAM_BIT  0x80000000
+
+#define VFE_HW_LIMIT 1
+
+struct msm_vfe_cfg_cmd_list;
+
+enum ISP_START_PIXEL_PATTERN {
+	ISP_BAYER_RGRGRG,
+	ISP_BAYER_GRGRGR,
+	ISP_BAYER_BGBGBG,
+	ISP_BAYER_GBGBGB,
+	ISP_YUV_YCbYCr,
+	ISP_YUV_YCrYCb,
+	ISP_YUV_CbYCrY,
+	ISP_YUV_CrYCbY,
+	ISP_PIX_PATTERN_MAX
+};
+
+enum msm_vfe_plane_fmt {
+	Y_PLANE,
+	CB_PLANE,
+	CR_PLANE,
+	CRCB_PLANE,
+	CBCR_PLANE,
+	VFE_PLANE_FMT_MAX
+};
+
+enum msm_vfe_input_src {
+	VFE_PIX_0,
+	VFE_RAW_0,
+	VFE_RAW_1,
+	VFE_RAW_2,
+	VFE_SRC_MAX,
+};
+
+enum msm_vfe_axi_stream_src {
+	PIX_ENCODER,
+	PIX_VIEWFINDER,
+	PIX_VIDEO,
+	CAMIF_RAW,
+	IDEAL_RAW,
+	RDI_INTF_0,
+	RDI_INTF_1,
+	RDI_INTF_2,
+	VFE_AXI_SRC_MAX
+};
+
+enum msm_vfe_frame_skip_pattern {
+	NO_SKIP,
+	EVERY_2FRAME,
+	EVERY_3FRAME,
+	EVERY_4FRAME,
+	EVERY_5FRAME,
+	EVERY_6FRAME,
+	EVERY_7FRAME,
+	EVERY_8FRAME,
+	EVERY_16FRAME,
+	EVERY_32FRAME,
+	SKIP_ALL,
+	SKIP_RANGE,
+	MAX_SKIP,
+};
+
+/*
+ * Define an unused period. When this period is set it means that the stream is
+ * stopped(i.e the pattern is 0). We don't track the current pattern, just the
+ * period defines what the pattern is, if period is this then pattern is 0 else
+ * pattern is 1
+ */
+#define MSM_VFE_STREAM_STOP_PERIOD 15
+
+enum msm_isp_stats_type {
+	MSM_ISP_STATS_AEC,   /* legacy based AEC */
+	MSM_ISP_STATS_AF,    /* legacy based AF */
+	MSM_ISP_STATS_AWB,   /* legacy based AWB */
+	MSM_ISP_STATS_RS,    /* legacy based RS */
+	MSM_ISP_STATS_CS,    /* legacy based CS */
+	MSM_ISP_STATS_IHIST, /* legacy based HIST */
+	MSM_ISP_STATS_SKIN,  /* legacy based SKIN */
+	MSM_ISP_STATS_BG,    /* Bayer Grids */
+	MSM_ISP_STATS_BF,    /* Bayer Focus */
+	MSM_ISP_STATS_BE,    /* Bayer Exposure*/
+	MSM_ISP_STATS_BHIST, /* Bayer Hist */
+	MSM_ISP_STATS_BF_SCALE,  /* Bayer Focus scale */
+	MSM_ISP_STATS_HDR_BE,    /* HDR Bayer Exposure */
+	MSM_ISP_STATS_HDR_BHIST, /* HDR Bayer Hist */
+	MSM_ISP_STATS_AEC_BG,   /* AEC BG */
+	MSM_ISP_STATS_MAX    /* MAX */
+};
+
+/*
+ * @stats_type_mask: Stats type mask (enum msm_isp_stats_type).
+ * @stream_src_mask: Stream src mask (enum msm_vfe_axi_stream_src)
+ * @skip_mode: skip pattern, if skip mode is range only then min/max is used
+ * @min_frame_id: minimum frame id (valid only if skip_mode = RANGE)
+ * @max_frame_id: maximum frame id (valid only if skip_mode = RANGE)
+ */
+struct msm_isp_sw_framskip {
+	uint32_t stats_type_mask;
+	uint32_t stream_src_mask;
+	enum msm_vfe_frame_skip_pattern skip_mode;
+	uint32_t min_frame_id;
+	uint32_t max_frame_id;
+};
+
+enum msm_vfe_testgen_color_pattern {
+	COLOR_BAR_8_COLOR,
+	UNICOLOR_WHITE,
+	UNICOLOR_YELLOW,
+	UNICOLOR_CYAN,
+	UNICOLOR_GREEN,
+	UNICOLOR_MAGENTA,
+	UNICOLOR_RED,
+	UNICOLOR_BLUE,
+	UNICOLOR_BLACK,
+	MAX_COLOR,
+};
+
+enum msm_vfe_camif_input {
+	CAMIF_DISABLED,
+	CAMIF_PAD_REG_INPUT,
+	CAMIF_MIDDI_INPUT,
+	CAMIF_MIPI_INPUT,
+};
+
+struct msm_vfe_fetch_engine_cfg {
+	uint32_t input_format;
+	uint32_t buf_width;
+	uint32_t buf_height;
+	uint32_t fetch_width;
+	uint32_t fetch_height;
+	uint32_t x_offset;
+	uint32_t y_offset;
+	uint32_t buf_stride;
+};
+
+enum msm_vfe_camif_output_format {
+	CAMIF_QCOM_RAW,
+	CAMIF_MIPI_RAW,
+	CAMIF_PLAIN_8,
+	CAMIF_PLAIN_16,
+	CAMIF_MAX_FORMAT,
+};
+
+/*
+ * Camif output general configuration
+ */
+struct msm_vfe_camif_subsample_cfg {
+	uint32_t irq_subsample_period;
+	uint32_t irq_subsample_pattern;
+	uint32_t sof_counter_step;
+	uint32_t pixel_skip;
+	uint32_t line_skip;
+	uint32_t first_line;
+	uint32_t last_line;
+	uint32_t first_pixel;
+	uint32_t last_pixel;
+	enum msm_vfe_camif_output_format output_format;
+};
+
+/*
+ * Camif frame and window configuration
+ */
+struct msm_vfe_camif_cfg {
+	uint32_t lines_per_frame;
+	uint32_t pixels_per_line;
+	uint32_t first_pixel;
+	uint32_t last_pixel;
+	uint32_t first_line;
+	uint32_t last_line;
+	uint32_t epoch_line0;
+	uint32_t epoch_line1;
+	uint32_t is_split;
+	enum msm_vfe_camif_input camif_input;
+	struct msm_vfe_camif_subsample_cfg subsample_cfg;
+};
+
+struct msm_vfe_testgen_cfg {
+	uint32_t lines_per_frame;
+	uint32_t pixels_per_line;
+	uint32_t v_blank;
+	uint32_t h_blank;
+	enum ISP_START_PIXEL_PATTERN pixel_bayer_pattern;
+	uint32_t rotate_period;
+	enum msm_vfe_testgen_color_pattern color_bar_pattern;
+	uint32_t burst_num_frame;
+};
+
+enum msm_vfe_inputmux {
+	CAMIF,
+	TESTGEN,
+	EXTERNAL_READ,
+};
+
+enum msm_vfe_stats_composite_group {
+	STATS_COMPOSITE_GRP_NONE,
+	STATS_COMPOSITE_GRP_1,
+	STATS_COMPOSITE_GRP_2,
+	STATS_COMPOSITE_GRP_MAX,
+};
+
+enum msm_vfe_hvx_streaming_cmd {
+	HVX_DISABLE,
+	HVX_ONE_WAY,
+	HVX_ROUND_TRIP
+};
+
+struct msm_vfe_pix_cfg {
+	struct msm_vfe_camif_cfg camif_cfg;
+	struct msm_vfe_testgen_cfg testgen_cfg;
+	struct msm_vfe_fetch_engine_cfg fetch_engine_cfg;
+	enum msm_vfe_inputmux input_mux;
+	enum ISP_START_PIXEL_PATTERN pixel_pattern;
+	uint32_t input_format;
+	enum msm_vfe_hvx_streaming_cmd hvx_cmd;
+	uint32_t is_split;
+};
+
+struct msm_vfe_rdi_cfg {
+	uint8_t cid;
+	uint8_t frame_based;
+};
+
+struct msm_vfe_input_cfg {
+	union {
+		struct msm_vfe_pix_cfg pix_cfg;
+		struct msm_vfe_rdi_cfg rdi_cfg;
+	} d;
+	enum msm_vfe_input_src input_src;
+	uint32_t input_pix_clk;
+};
+
+struct msm_vfe_fetch_eng_start {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t buf_idx;
+	uint8_t  offline_mode;
+	uint32_t fd;
+	uint32_t buf_addr;
+	uint32_t frame_id;
+};
+
+enum msm_vfe_fetch_eng_pass {
+	OFFLINE_FIRST_PASS,
+	OFFLINE_SECOND_PASS,
+	OFFLINE_MAX_PASS,
+};
+
+struct msm_vfe_fetch_eng_multi_pass_start {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t buf_idx;
+	uint8_t  offline_mode;
+	uint32_t fd;
+	uint32_t buf_addr;
+	uint32_t frame_id;
+	uint32_t output_buf_idx;
+	uint32_t input_buf_offset;
+	enum msm_vfe_fetch_eng_pass  offline_pass;
+	uint32_t output_stream_id;
+};
+
+struct msm_vfe_axi_plane_cfg {
+	uint32_t output_width; /*Include padding*/
+	uint32_t output_height;
+	uint32_t output_stride;
+	uint32_t output_scan_lines;
+	uint32_t output_plane_format; /*Y/Cb/Cr/CbCr*/
+	uint32_t plane_addr_offset;
+	uint8_t csid_src; /*RDI 0-2*/
+	uint8_t rdi_cid;/*CID 1-16*/
+};
+
+enum msm_stream_rdi_input_type {
+	MSM_CAMERA_RDI_MIN,
+	MSM_CAMERA_RDI_PDAF,
+	MSM_CAMERA_RDI_MAX,
+};
+
+struct msm_vfe_axi_stream_request_cmd {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t vt_enable;
+	uint32_t output_format;/*Planar/RAW/Misc*/
+	enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/
+	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
+
+	uint32_t burst_count;
+	uint32_t hfr_mode;
+	uint8_t frame_base;
+
+	uint32_t init_frame_drop; /*MAX 31 Frames*/
+	enum msm_vfe_frame_skip_pattern frame_skip_pattern;
+	uint8_t buf_divert; /* if TRUE no vb2 buf done. */
+	/*Return values*/
+	uint32_t axi_stream_handle;
+	uint32_t controllable_output;
+	uint32_t burst_len;
+	/* Flag indicating memory input stream */
+	enum msm_stream_rdi_input_type rdi_input_type;
+};
+
+struct msm_vfe_axi_stream_release_cmd {
+	uint32_t stream_handle;
+};
+
+enum msm_vfe_axi_stream_cmd {
+	STOP_STREAM,
+	START_STREAM,
+	STOP_IMMEDIATELY,
+};
+
+struct msm_vfe_axi_stream_cfg_cmd {
+	uint8_t num_streams;
+	uint32_t stream_handle[VFE_AXI_SRC_MAX];
+	enum msm_vfe_axi_stream_cmd cmd;
+	uint8_t sync_frame_id_src;
+};
+
+enum msm_vfe_axi_stream_update_type {
+	ENABLE_STREAM_BUF_DIVERT,
+	DISABLE_STREAM_BUF_DIVERT,
+	UPDATE_STREAM_FRAMEDROP_PATTERN,
+	UPDATE_STREAM_STATS_FRAMEDROP_PATTERN,
+	UPDATE_STREAM_AXI_CONFIG,
+	UPDATE_STREAM_REQUEST_FRAMES,
+	UPDATE_STREAM_ADD_BUFQ,
+	UPDATE_STREAM_REMOVE_BUFQ,
+	UPDATE_STREAM_SW_FRAME_DROP,
+	UPDATE_STREAM_REQUEST_FRAMES_VER2,
+	UPDATE_STREAM_OFFLINE_AXI_CONFIG,
+};
+#define UPDATE_STREAM_REQUEST_FRAMES_VER2 UPDATE_STREAM_REQUEST_FRAMES_VER2
+
+enum msm_vfe_iommu_type {
+	IOMMU_ATTACH,
+	IOMMU_DETACH,
+};
+
+enum msm_vfe_buff_queue_id {
+	VFE_BUF_QUEUE_DEFAULT,
+	VFE_BUF_QUEUE_SHARED,
+	VFE_BUF_QUEUE_MAX,
+};
+
+struct msm_vfe_axi_stream_cfg_update_info {
+	uint32_t stream_handle;
+	uint32_t output_format;
+	uint32_t user_stream_id;
+	uint32_t frame_id;
+	enum msm_vfe_frame_skip_pattern skip_pattern;
+	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
+	struct msm_isp_sw_framskip sw_skip_info;
+};
+
+struct msm_vfe_axi_stream_cfg_update_info_req_frm {
+	uint32_t stream_handle;
+	uint32_t user_stream_id;
+	uint32_t frame_id;
+	uint32_t buf_index;
+};
+
+struct msm_vfe_axi_halt_cmd {
+	uint32_t stop_camif;
+	uint32_t overflow_detected;
+	uint32_t blocking_halt;
+};
+
+struct msm_vfe_axi_reset_cmd {
+	uint32_t blocking;
+	uint32_t frame_id;
+};
+
+struct msm_vfe_axi_restart_cmd {
+	uint32_t enable_camif;
+};
+
+struct msm_vfe_axi_stream_update_cmd {
+	uint32_t num_streams;
+	enum msm_vfe_axi_stream_update_type update_type;
+	/*
+	 * For backward compatibility, ensure 1st member of any struct
+	 * in union below is uint32_t stream_handle.
+	 */
+	union {
+		struct msm_vfe_axi_stream_cfg_update_info
+					update_info[MSM_ISP_STATS_MAX];
+		struct msm_vfe_axi_stream_cfg_update_info_req_frm req_frm_ver2;
+	};
+};
+
+struct msm_vfe_smmu_attach_cmd {
+	uint32_t security_mode;
+	uint32_t iommu_attach_mode;
+};
+
+struct msm_vfe_stats_stream_request_cmd {
+	uint32_t session_id;
+	uint32_t stream_id;
+	enum msm_isp_stats_type stats_type;
+	uint32_t composite_flag;
+	uint32_t framedrop_pattern;
+	uint32_t init_frame_drop; /*MAX 31 Frames*/
+	uint32_t irq_subsample_pattern;
+	uint32_t buffer_offset;
+	uint32_t stream_handle;
+};
+
+struct msm_vfe_stats_stream_release_cmd {
+	uint32_t stream_handle;
+};
+struct msm_vfe_stats_stream_cfg_cmd {
+	uint8_t num_streams;
+	uint32_t stream_handle[MSM_ISP_STATS_MAX];
+	uint8_t enable;
+	uint32_t stats_burst_len;
+};
+
+enum msm_vfe_reg_cfg_type {
+	VFE_WRITE,
+	VFE_WRITE_MB,
+	VFE_READ,
+	VFE_CFG_MASK,
+	VFE_WRITE_DMI_16BIT,
+	VFE_WRITE_DMI_32BIT,
+	VFE_WRITE_DMI_64BIT,
+	VFE_READ_DMI_16BIT,
+	VFE_READ_DMI_32BIT,
+	VFE_READ_DMI_64BIT,
+	GET_MAX_CLK_RATE,
+	GET_CLK_RATES,
+	GET_ISP_ID,
+	VFE_HW_UPDATE_LOCK,
+	VFE_HW_UPDATE_UNLOCK,
+	SET_WM_UB_SIZE,
+	SET_UB_POLICY,
+	GET_VFE_HW_LIMIT,
+};
+
+struct msm_vfe_cfg_cmd2 {
+	uint16_t num_cfg;
+	uint16_t cmd_len;
+	void __user *cfg_data;
+	void __user *cfg_cmd;
+};
+
+struct msm_vfe_cfg_cmd_list {
+	struct msm_vfe_cfg_cmd2      cfg_cmd;
+	struct msm_vfe_cfg_cmd_list *next;
+	uint32_t                     next_size;
+};
+
+struct msm_vfe_reg_rw_info {
+	uint32_t reg_offset;
+	uint32_t cmd_data_offset;
+	uint32_t len;
+};
+
+struct msm_vfe_reg_mask_info {
+	uint32_t reg_offset;
+	uint32_t mask;
+	uint32_t val;
+};
+
+struct msm_vfe_reg_dmi_info {
+	uint32_t hi_tbl_offset; /*Optional*/
+	uint32_t lo_tbl_offset; /*Required*/
+	uint32_t len;
+};
+
+struct msm_vfe_reg_cfg_cmd {
+	union {
+		struct msm_vfe_reg_rw_info rw_info;
+		struct msm_vfe_reg_mask_info mask_info;
+		struct msm_vfe_reg_dmi_info dmi_info;
+	} u;
+
+	enum msm_vfe_reg_cfg_type cmd_type;
+};
+
+enum vfe_sd_type {
+	VFE_SD_0 = 0,
+	VFE_SD_1,
+	VFE_SD_COMMON,
+	VFE_SD_MAX,
+};
+
+/* When you change the value below, check for the sof event_data size.
+ * V4l2 limits payload to 64 bytes
+ */
+#define MS_NUM_SLAVE_MAX 1
+
+/* Usecases when 2 HW need to be related or synced */
+enum msm_vfe_dual_hw_type {
+	DUAL_NONE = 0,
+	DUAL_HW_VFE_SPLIT = 1,
+	DUAL_HW_MASTER_SLAVE = 2,
+};
+
+/* Type for 2 INTF when used in Master-Slave mode */
+enum msm_vfe_dual_hw_ms_type {
+	MS_TYPE_NONE,
+	MS_TYPE_MASTER,
+	MS_TYPE_SLAVE,
+};
+
+struct msm_isp_set_dual_hw_ms_cmd {
+	uint8_t num_src;
+	/* Each session can be only one type but multiple intf if YUV cam */
+	enum msm_vfe_dual_hw_ms_type dual_hw_ms_type;
+	/* Primary intf is mostly associated with preview.
+	 * This primary intf SOF frame_id and timestamp is tracked
+	 * and used to calculate delta
+	 */
+	enum msm_vfe_input_src primary_intf;
+	/* input_src array indicates other input INTF that may be Master/Slave.
+	 * For these additional intf, frame_id and timestamp are not saved.
+	 * However, if these are slaves then they will still get their
+	 * frame_id from Master
+	 */
+	enum msm_vfe_input_src input_src[VFE_SRC_MAX];
+	uint32_t sof_delta_threshold; /* In milliseconds. Sent for Master */
+};
+
+enum msm_isp_buf_type {
+	ISP_PRIVATE_BUF,
+	ISP_SHARE_BUF,
+	MAX_ISP_BUF_TYPE,
+};
+
+struct msm_isp_unmap_buf_req {
+	uint32_t fd;
+};
+
+struct msm_isp_buf_request {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint8_t num_buf;
+	uint32_t handle;
+	enum msm_isp_buf_type buf_type;
+};
+
+struct msm_isp_buf_request_ver2 {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint8_t num_buf;
+	uint32_t handle;
+	enum msm_isp_buf_type buf_type;
+	enum smmu_attach_mode security_mode;
+	uint32_t reserved[4];
+};
+
+struct msm_isp_qbuf_plane {
+	uint32_t addr;
+	uint32_t offset;
+	uint32_t length;
+};
+
+struct msm_isp_qbuf_buffer {
+	struct msm_isp_qbuf_plane planes[MAX_PLANES_PER_STREAM];
+	uint32_t num_planes;
+};
+
+struct msm_isp_qbuf_info {
+	uint32_t handle;
+	int32_t buf_idx;
+	/*Only used for prepare buffer*/
+	struct msm_isp_qbuf_buffer buffer;
+	/*Only used for diverted buffer*/
+	uint32_t dirty_buf;
+};
+
+struct msm_isp_clk_rates {
+	uint32_t svs_rate;
+	uint32_t nominal_rate;
+	uint32_t high_rate;
+};
+
+struct msm_vfe_axi_src_state {
+	enum msm_vfe_input_src input_src;
+	uint32_t src_active;
+	uint32_t src_frame_id;
+};
+
+enum msm_isp_event_mask_index {
+	ISP_EVENT_MASK_INDEX_STATS_NOTIFY		= 0,
+	ISP_EVENT_MASK_INDEX_ERROR			= 1,
+	ISP_EVENT_MASK_INDEX_IOMMU_P_FAULT		= 2,
+	ISP_EVENT_MASK_INDEX_STREAM_UPDATE_DONE		= 3,
+	ISP_EVENT_MASK_INDEX_REG_UPDATE			= 4,
+	ISP_EVENT_MASK_INDEX_SOF			= 5,
+	ISP_EVENT_MASK_INDEX_BUF_DIVERT			= 6,
+	ISP_EVENT_MASK_INDEX_COMP_STATS_NOTIFY		= 7,
+	ISP_EVENT_MASK_INDEX_MASK_FE_READ_DONE		= 8,
+	ISP_EVENT_MASK_INDEX_BUF_DONE			= 9,
+	ISP_EVENT_MASK_INDEX_REG_UPDATE_MISSING		= 10,
+	ISP_EVENT_MASK_INDEX_PING_PONG_MISMATCH		= 11,
+	ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR		= 12,
+};
+
+
+#define ISP_EVENT_SUBS_MASK_NONE			0
+
+#define ISP_EVENT_SUBS_MASK_STATS_NOTIFY \
+			(1 << ISP_EVENT_MASK_INDEX_STATS_NOTIFY)
+
+#define ISP_EVENT_SUBS_MASK_ERROR \
+			(1 << ISP_EVENT_MASK_INDEX_ERROR)
+
+#define ISP_EVENT_SUBS_MASK_IOMMU_P_FAULT \
+			(1 << ISP_EVENT_MASK_INDEX_IOMMU_P_FAULT)
+
+#define ISP_EVENT_SUBS_MASK_STREAM_UPDATE_DONE \
+			(1 << ISP_EVENT_MASK_INDEX_STREAM_UPDATE_DONE)
+
+#define ISP_EVENT_SUBS_MASK_REG_UPDATE \
+			(1 << ISP_EVENT_MASK_INDEX_REG_UPDATE)
+
+#define ISP_EVENT_SUBS_MASK_SOF \
+			(1 << ISP_EVENT_MASK_INDEX_SOF)
+
+#define ISP_EVENT_SUBS_MASK_BUF_DIVERT \
+			(1 << ISP_EVENT_MASK_INDEX_BUF_DIVERT)
+
+#define ISP_EVENT_SUBS_MASK_COMP_STATS_NOTIFY \
+			(1 << ISP_EVENT_MASK_INDEX_COMP_STATS_NOTIFY)
+
+#define ISP_EVENT_SUBS_MASK_FE_READ_DONE \
+			(1 << ISP_EVENT_MASK_INDEX_MASK_FE_READ_DONE)
+
+#define ISP_EVENT_SUBS_MASK_BUF_DONE \
+			(1 << ISP_EVENT_MASK_INDEX_BUF_DONE)
+
+#define ISP_EVENT_SUBS_MASK_REG_UPDATE_MISSING \
+			(1 << ISP_EVENT_MASK_INDEX_REG_UPDATE_MISSING)
+
+#define ISP_EVENT_SUBS_MASK_PING_PONG_MISMATCH \
+			(1 << ISP_EVENT_MASK_INDEX_PING_PONG_MISMATCH)
+
+#define ISP_EVENT_SUBS_MASK_BUF_FATAL_ERROR \
+			(1 << ISP_EVENT_MASK_INDEX_BUF_FATAL_ERROR)
+
+enum msm_isp_event_idx {
+	ISP_REG_UPDATE        = 0,
+	ISP_EPOCH_0           = 1,
+	ISP_EPOCH_1           = 2,
+	ISP_START_ACK         = 3,
+	ISP_STOP_ACK          = 4,
+	ISP_IRQ_VIOLATION     = 5,
+	ISP_STATS_OVERFLOW    = 6,
+	ISP_BUF_DONE          = 7,
+	ISP_FE_RD_DONE        = 8,
+	ISP_IOMMU_P_FAULT     = 9,
+	ISP_ERROR             = 10,
+	ISP_HW_FATAL_ERROR      = 11,
+	ISP_PING_PONG_MISMATCH = 12,
+	ISP_REG_UPDATE_MISSING = 13,
+	ISP_BUF_FATAL_ERROR = 14,
+	ISP_EVENT_MAX         = 15
+};
+
+#define ISP_EVENT_OFFSET          8
+#define ISP_EVENT_BASE            (V4L2_EVENT_PRIVATE_START)
+#define ISP_BUF_EVENT_BASE        (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
+#define ISP_STATS_EVENT_BASE      (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
+#define ISP_CAMIF_EVENT_BASE      (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET))
+#define ISP_STREAM_EVENT_BASE     (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET))
+#define ISP_EVENT_REG_UPDATE      (ISP_EVENT_BASE + ISP_REG_UPDATE)
+#define ISP_EVENT_EPOCH_0         (ISP_EVENT_BASE + ISP_EPOCH_0)
+#define ISP_EVENT_EPOCH_1         (ISP_EVENT_BASE + ISP_EPOCH_1)
+#define ISP_EVENT_START_ACK       (ISP_EVENT_BASE + ISP_START_ACK)
+#define ISP_EVENT_STOP_ACK        (ISP_EVENT_BASE + ISP_STOP_ACK)
+#define ISP_EVENT_IRQ_VIOLATION   (ISP_EVENT_BASE + ISP_IRQ_VIOLATION)
+#define ISP_EVENT_STATS_OVERFLOW  (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
+#define ISP_EVENT_ERROR           (ISP_EVENT_BASE + ISP_ERROR)
+#define ISP_EVENT_SOF             (ISP_CAMIF_EVENT_BASE)
+#define ISP_EVENT_EOF             (ISP_CAMIF_EVENT_BASE + 1)
+#define ISP_EVENT_BUF_DONE        (ISP_EVENT_BASE + ISP_BUF_DONE)
+#define ISP_EVENT_BUF_DIVERT      (ISP_BUF_EVENT_BASE)
+#define ISP_EVENT_STATS_NOTIFY    (ISP_STATS_EVENT_BASE)
+#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
+#define ISP_EVENT_FE_READ_DONE    (ISP_EVENT_BASE + ISP_FE_RD_DONE)
+#define ISP_EVENT_IOMMU_P_FAULT   (ISP_EVENT_BASE + ISP_IOMMU_P_FAULT)
+#define ISP_EVENT_HW_FATAL_ERROR  (ISP_EVENT_BASE + ISP_HW_FATAL_ERROR)
+#define ISP_EVENT_PING_PONG_MISMATCH (ISP_EVENT_BASE + ISP_PING_PONG_MISMATCH)
+#define ISP_EVENT_REG_UPDATE_MISSING (ISP_EVENT_BASE + ISP_REG_UPDATE_MISSING)
+#define ISP_EVENT_BUF_FATAL_ERROR (ISP_EVENT_BASE + ISP_BUF_FATAL_ERROR)
+#define ISP_EVENT_STREAM_UPDATE_DONE   (ISP_STREAM_EVENT_BASE)
+
+/* The msm_v4l2_event_data structure should match the
+ * v4l2_event.u.data field.
+ * should not exceed 64 bytes
+ */
+
+struct msm_isp_buf_event {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t handle;
+	uint32_t output_format;
+	int8_t buf_idx;
+};
+struct msm_isp_fetch_eng_event {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t handle;
+	uint32_t fd;
+	int8_t buf_idx;
+	int8_t offline_mode;
+};
+struct msm_isp_stats_event {
+	uint32_t stats_mask;                        /* 4 bytes */
+	uint8_t stats_buf_idxs[MSM_ISP_STATS_MAX];  /* 11 bytes */
+	uint8_t pd_stats_idx;
+};
+
+struct msm_isp_stream_ack {
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t handle;
+};
+
+enum msm_vfe_error_type {
+	ISP_ERROR_NONE,
+	ISP_ERROR_CAMIF,
+	ISP_ERROR_BUS_OVERFLOW,
+	ISP_ERROR_RETURN_EMPTY_BUFFER,
+	ISP_ERROR_FRAME_ID_MISMATCH,
+	ISP_ERROR_MAX,
+};
+
+struct msm_isp_error_info {
+	enum msm_vfe_error_type err_type;
+	uint32_t session_id;
+	uint32_t stream_id;
+	uint32_t stream_id_mask;
+};
+
+/* This structure reports delta between master and slave */
+struct msm_isp_ms_delta_info {
+	uint8_t num_delta_info;
+	uint32_t delta[MS_NUM_SLAVE_MAX];
+};
+
+/* This is sent in EPOCH irq */
+struct msm_isp_output_info {
+	uint8_t regs_not_updated;
+	/* mask with bufq_handle for regs not updated or return empty */
+	uint16_t output_err_mask;
+	/* mask with stream_idx for get_buf failed */
+	uint8_t stream_framedrop_mask;
+	/* mask with stats stream_idx for get_buf failed */
+	uint16_t stats_framedrop_mask;
+	/* delta between master and slave */
+};
+
+/* This structure is piggybacked with SOF event */
+struct msm_isp_sof_info {
+	uint8_t regs_not_updated;
+	/* mask with bufq_handle for regs not updated */
+	uint16_t reg_update_fail_mask;
+	/* mask with bufq_handle for get_buf failed */
+	uint32_t stream_get_buf_fail_mask;
+	/* mask with stats stream_idx for get_buf failed */
+	uint16_t stats_get_buf_fail_mask;
+	/* delta between master and slave */
+	struct msm_isp_ms_delta_info ms_delta_info;
+	/*
+	 * mask with AXI_SRC in paused state. In PAUSED
+	 * state there is no Buffer output. So this mask is used
+	 * to report drop.
+	 */
+	uint16_t axi_updating_mask;
+	/* extended mask with bufq_handle for regs not updated */
+	uint32_t reg_update_fail_mask_ext;
+};
+#define AXI_UPDATING_MASK 1
+#define REG_UPDATE_FAIL_MASK_EXT 1
+
+struct msm_isp_event_data {
+	/*Wall clock except for buffer divert events
+	 *which use monotonic clock
+	 */
+	struct timeval timestamp;
+	/* Monotonic timestamp since bootup */
+	struct timeval mono_timestamp;
+	uint32_t frame_id;
+	union {
+		/* Sent for Stats_Done event */
+		struct msm_isp_stats_event stats;
+		/* Sent for Buf_Divert event */
+		struct msm_isp_buf_event buf_done;
+		/* Sent for offline fetch done event */
+		struct msm_isp_fetch_eng_event fetch_done;
+		/* Sent for Error_Event */
+		struct msm_isp_error_info error_info;
+		/*
+		 * This struct needs to be removed once
+		 * userspace switches to sof_info
+		 */
+		struct msm_isp_output_info output_info;
+		/* Sent for SOF event */
+		struct msm_isp_sof_info sof_info;
+	} u; /* union can have max 52 bytes */
+};
+
+enum msm_vfe_ahb_clk_vote {
+	MSM_ISP_CAMERA_AHB_SVS_VOTE = 1,
+	MSM_ISP_CAMERA_AHB_TURBO_VOTE = 2,
+	MSM_ISP_CAMERA_AHB_NOMINAL_VOTE = 3,
+	MSM_ISP_CAMERA_AHB_SUSPEND_VOTE = 4,
+};
+
+struct msm_isp_ahb_clk_cfg {
+	uint32_t vote;
+	uint32_t reserved[2];
+};
+
+enum msm_vfe_dual_cam_sync_mode {
+	MSM_ISP_DUAL_CAM_ASYNC,
+	MSM_ISP_DUAL_CAM_SYNC,
+};
+
+struct msm_isp_dual_hw_master_slave_sync {
+	uint32_t sync_mode;
+	uint32_t reserved[2];
+};
+
+struct msm_vfe_dual_lpm_mode {
+	enum msm_vfe_axi_stream_src stream_src[VFE_AXI_SRC_MAX];
+	uint32_t num_src;
+	uint32_t lpm_mode;
+};
+#define V4L2_PIX_FMT_QBGGR8  v4l2_fourcc('Q', 'B', 'G', '8')
+#define V4L2_PIX_FMT_QGBRG8  v4l2_fourcc('Q', 'G', 'B', '8')
+#define V4L2_PIX_FMT_QGRBG8  v4l2_fourcc('Q', 'G', 'R', '8')
+#define V4L2_PIX_FMT_QRGGB8  v4l2_fourcc('Q', 'R', 'G', '8')
+#define V4L2_PIX_FMT_QBGGR10 v4l2_fourcc('Q', 'B', 'G', '0')
+#define V4L2_PIX_FMT_QGBRG10 v4l2_fourcc('Q', 'G', 'B', '0')
+#define V4L2_PIX_FMT_QGRBG10 v4l2_fourcc('Q', 'G', 'R', '0')
+#define V4L2_PIX_FMT_QRGGB10 v4l2_fourcc('Q', 'R', 'G', '0')
+#define V4L2_PIX_FMT_QBGGR12 v4l2_fourcc('Q', 'B', 'G', '2')
+#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2')
+#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2')
+#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
+#define V4L2_PIX_FMT_QBGGR14 v4l2_fourcc('Q', 'B', 'G', '4')
+#define V4L2_PIX_FMT_QGBRG14 v4l2_fourcc('Q', 'G', 'B', '4')
+#define V4L2_PIX_FMT_QGRBG14 v4l2_fourcc('Q', 'G', 'R', '4')
+#define V4L2_PIX_FMT_QRGGB14 v4l2_fourcc('Q', 'R', 'G', '4')
+#define V4L2_PIX_FMT_P16BGGR10 v4l2_fourcc('P', 'B', 'G', '0')
+#define V4L2_PIX_FMT_P16GBRG10 v4l2_fourcc('P', 'G', 'B', '0')
+#define V4L2_PIX_FMT_P16GRBG10 v4l2_fourcc('P', 'G', 'R', '0')
+#define V4L2_PIX_FMT_P16RGGB10 v4l2_fourcc('P', 'R', 'G', '0')
+#define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4')
+#define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1')
+#define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T')
+#define V4L2_PIX_FMT_META10 v4l2_fourcc('Q', 'M', '1', '0')
+#define V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') /* 14 BGBG.GRGR.*/
+#define V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4') /* 14 GBGB.RGRG.*/
+#define V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('B', 'A', '1', '4') /* 14 GRGR.BGBG.*/
+#define V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4') /* 14 RGRG.GBGB.*/
+
+enum msm_isp_ioctl_cmd_code {
+	MSM_VFE_REG_CFG = BASE_VIDIOC_PRIVATE,
+	MSM_ISP_REQUEST_BUF,
+	MSM_ISP_ENQUEUE_BUF,
+	MSM_ISP_RELEASE_BUF,
+	MSM_ISP_REQUEST_STREAM,
+	MSM_ISP_CFG_STREAM,
+	MSM_ISP_RELEASE_STREAM,
+	MSM_ISP_INPUT_CFG,
+	MSM_ISP_SET_SRC_STATE,
+	MSM_ISP_REQUEST_STATS_STREAM,
+	MSM_ISP_CFG_STATS_STREAM,
+	MSM_ISP_RELEASE_STATS_STREAM,
+	MSM_ISP_REG_UPDATE_CMD,
+	MSM_ISP_UPDATE_STREAM,
+	MSM_VFE_REG_LIST_CFG,
+	MSM_ISP_SMMU_ATTACH,
+	MSM_ISP_UPDATE_STATS_STREAM,
+	MSM_ISP_AXI_HALT,
+	MSM_ISP_AXI_RESET,
+	MSM_ISP_AXI_RESTART,
+	MSM_ISP_FETCH_ENG_START,
+	MSM_ISP_DEQUEUE_BUF,
+	MSM_ISP_SET_DUAL_HW_MASTER_SLAVE,
+	MSM_ISP_MAP_BUF_START_FE,
+	MSM_ISP_UNMAP_BUF,
+	MSM_ISP_AHB_CLK_CFG,
+	MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC,
+	MSM_ISP_FETCH_ENG_MULTI_PASS_START,
+	MSM_ISP_MAP_BUF_START_MULTI_PASS_FE,
+	MSM_ISP_REQUEST_BUF_VER2,
+	MSM_ISP_DUAL_HW_LPM_MODE,
+};
+
+#define VIDIOC_MSM_VFE_REG_CFG \
+	_IOWR('V', MSM_VFE_REG_CFG, \
+		struct msm_vfe_cfg_cmd2)
+
+#define VIDIOC_MSM_ISP_REQUEST_BUF \
+	_IOWR('V', MSM_ISP_REQUEST_BUF, \
+		struct msm_isp_buf_request)
+
+#define VIDIOC_MSM_ISP_ENQUEUE_BUF \
+	_IOWR('V', MSM_ISP_ENQUEUE_BUF, \
+		struct msm_isp_qbuf_info)
+
+#define VIDIOC_MSM_ISP_RELEASE_BUF \
+	_IOWR('V', MSM_ISP_RELEASE_BUF, \
+		struct msm_isp_buf_request)
+
+#define VIDIOC_MSM_ISP_REQUEST_STREAM \
+	_IOWR('V', MSM_ISP_REQUEST_STREAM, \
+		struct msm_vfe_axi_stream_request_cmd)
+
+#define VIDIOC_MSM_ISP_CFG_STREAM \
+	_IOWR('V', MSM_ISP_CFG_STREAM, \
+		struct msm_vfe_axi_stream_cfg_cmd)
+
+#define VIDIOC_MSM_ISP_RELEASE_STREAM \
+	_IOWR('V', MSM_ISP_RELEASE_STREAM, \
+		struct msm_vfe_axi_stream_release_cmd)
+
+#define VIDIOC_MSM_ISP_INPUT_CFG \
+	_IOWR('V', MSM_ISP_INPUT_CFG, \
+		struct msm_vfe_input_cfg)
+
+#define VIDIOC_MSM_ISP_SET_SRC_STATE \
+	_IOWR('V', MSM_ISP_SET_SRC_STATE, \
+		struct msm_vfe_axi_src_state)
+
+#define VIDIOC_MSM_ISP_REQUEST_STATS_STREAM \
+	_IOWR('V', MSM_ISP_REQUEST_STATS_STREAM, \
+		struct msm_vfe_stats_stream_request_cmd)
+
+#define VIDIOC_MSM_ISP_CFG_STATS_STREAM \
+	_IOWR('V', MSM_ISP_CFG_STATS_STREAM, \
+		struct msm_vfe_stats_stream_cfg_cmd)
+
+#define VIDIOC_MSM_ISP_RELEASE_STATS_STREAM \
+	_IOWR('V', MSM_ISP_RELEASE_STATS_STREAM, \
+		struct msm_vfe_stats_stream_release_cmd)
+
+#define VIDIOC_MSM_ISP_REG_UPDATE_CMD \
+	_IOWR('V', MSM_ISP_REG_UPDATE_CMD, \
+		enum msm_vfe_input_src)
+
+#define VIDIOC_MSM_ISP_UPDATE_STREAM \
+	_IOWR('V', MSM_ISP_UPDATE_STREAM, \
+		struct msm_vfe_axi_stream_update_cmd)
+
+#define VIDIOC_MSM_VFE_REG_LIST_CFG \
+	_IOWR('V', MSM_VFE_REG_LIST_CFG, \
+		struct msm_vfe_cfg_cmd_list)
+
+#define VIDIOC_MSM_ISP_SMMU_ATTACH \
+	_IOWR('V', MSM_ISP_SMMU_ATTACH, \
+		struct msm_vfe_smmu_attach_cmd)
+
+#define VIDIOC_MSM_ISP_UPDATE_STATS_STREAM \
+	_IOWR('V', MSM_ISP_UPDATE_STATS_STREAM, \
+		struct msm_vfe_axi_stream_update_cmd)
+
+#define VIDIOC_MSM_ISP_AXI_HALT \
+	_IOWR('V', MSM_ISP_AXI_HALT, \
+		struct msm_vfe_axi_halt_cmd)
+
+#define VIDIOC_MSM_ISP_AXI_RESET \
+	_IOWR('V', MSM_ISP_AXI_RESET, \
+		struct msm_vfe_axi_reset_cmd)
+
+#define VIDIOC_MSM_ISP_AXI_RESTART \
+	_IOWR('V', MSM_ISP_AXI_RESTART, \
+		struct msm_vfe_axi_restart_cmd)
+
+#define VIDIOC_MSM_ISP_FETCH_ENG_START \
+	_IOWR('V', MSM_ISP_FETCH_ENG_START, \
+		struct msm_vfe_fetch_eng_start)
+
+#define VIDIOC_MSM_ISP_DEQUEUE_BUF \
+	_IOWR('V', MSM_ISP_DEQUEUE_BUF, \
+		struct msm_isp_qbuf_info)
+
+#define VIDIOC_MSM_ISP_SET_DUAL_HW_MASTER_SLAVE \
+	_IOWR('V', MSM_ISP_SET_DUAL_HW_MASTER_SLAVE, \
+		struct msm_isp_set_dual_hw_ms_cmd)
+
+#define VIDIOC_MSM_ISP_MAP_BUF_START_FE \
+	_IOWR('V', MSM_ISP_MAP_BUF_START_FE, \
+		struct msm_vfe_fetch_eng_start)
+
+#define VIDIOC_MSM_ISP_UNMAP_BUF \
+	_IOWR('V', MSM_ISP_UNMAP_BUF, \
+		struct msm_isp_unmap_buf_req)
+
+#define VIDIOC_MSM_ISP_AHB_CLK_CFG \
+	_IOWR('V', MSM_ISP_AHB_CLK_CFG, struct msm_isp_ahb_clk_cfg)
+
+#define VIDIOC_MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC \
+	_IOWR('V', MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC, \
+	struct msm_isp_dual_hw_master_slave_sync)
+
+#define VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START \
+	_IOWR('V', MSM_ISP_FETCH_ENG_MULTI_PASS_START, \
+		struct msm_vfe_fetch_eng_multi_pass_start)
+
+#define VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE \
+	_IOWR('V', MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, \
+		struct msm_vfe_fetch_eng_multi_pass_start)
+
+#define VIDIOC_MSM_ISP_REQUEST_BUF_VER2 \
+	_IOWR('V', MSM_ISP_REQUEST_BUF_VER2, struct msm_isp_buf_request_ver2)
+
+#define VIDIOC_MSM_ISP_DUAL_HW_LPM_MODE \
+	_IOWR('V', MSM_ISP_DUAL_HW_LPM_MODE, \
+	struct msm_vfe_dual_lpm_mode)
+
+#endif /* __MSMB_ISP__ */
diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h
new file mode 100644
index 0000000..d532037
--- /dev/null
+++ b/include/uapi/media/msmb_ispif.h
@@ -0,0 +1,179 @@
+#ifndef UAPI_MSMB_ISPIF_H
+#define UAPI_MSMB_ISPIF_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/videodev2.h>
+
+#define CSID_VERSION_V20                      0x02000011
+#define CSID_VERSION_V22                      0x02001000
+#define CSID_VERSION_V30                      0x30000000
+#define CSID_VERSION_V3                      0x30000000
+
+enum msm_ispif_vfe_intf {
+	VFE0,
+	VFE1,
+	VFE_MAX
+};
+#define VFE0_MASK    (1 << VFE0)
+#define VFE1_MASK    (1 << VFE1)
+
+enum msm_ispif_intftype {
+	PIX0,
+	RDI0,
+	PIX1,
+	RDI1,
+	RDI2,
+	INTF_MAX
+};
+#define MAX_PARAM_ENTRIES (INTF_MAX * 2)
+#define MAX_CID_CH	8
+#define MAX_CID_CH_PARAM_ENTRY	3
+
+#define PIX0_MASK (1 << PIX0)
+#define PIX1_MASK (1 << PIX1)
+#define RDI0_MASK (1 << RDI0)
+#define RDI1_MASK (1 << RDI1)
+#define RDI2_MASK (1 << RDI2)
+
+enum msm_ispif_vc {
+	VC0,
+	VC1,
+	VC2,
+	VC3,
+	VC_MAX
+};
+
+enum msm_ispif_cid {
+	CID0,
+	CID1,
+	CID2,
+	CID3,
+	CID4,
+	CID5,
+	CID6,
+	CID7,
+	CID8,
+	CID9,
+	CID10,
+	CID11,
+	CID12,
+	CID13,
+	CID14,
+	CID15,
+	CID_MAX
+};
+
+enum msm_ispif_csid {
+	CSID0,
+	CSID1,
+	CSID2,
+	CSID3,
+	CSID_MAX
+};
+
+enum msm_ispif_pixel_odd_even {
+	PIX_EVEN,
+	PIX_ODD
+};
+
+enum msm_ispif_pixel_pack_mode {
+	PACK_BYTE,
+	PACK_PLAIN_PACK,
+	PACK_NV_P8,
+	PACK_NV_P16
+};
+
+struct msm_ispif_pack_cfg {
+	int pixel_swap_en;
+	enum msm_ispif_pixel_odd_even even_odd_sel;
+	enum msm_ispif_pixel_pack_mode pack_mode;
+};
+
+struct msm_ispif_params_entry {
+	enum msm_ispif_vfe_intf vfe_intf;
+	enum msm_ispif_intftype intftype;
+	int num_cids;
+	enum msm_ispif_cid cids[MAX_CID_CH_PARAM_ENTRY];
+	enum msm_ispif_csid csid;
+	int crop_enable;
+	uint16_t crop_start_pixel;
+	uint16_t crop_end_pixel;
+};
+
+struct msm_ispif_right_param_entry {
+	enum msm_ispif_cid cids[MAX_CID_CH_PARAM_ENTRY];
+	enum msm_ispif_csid csid;
+};
+
+struct msm_ispif_param_data_ext {
+	uint32_t num;
+	struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES];
+	struct msm_ispif_pack_cfg pack_cfg[CID_MAX];
+	struct msm_ispif_right_param_entry right_entries[MAX_PARAM_ENTRIES];
+	uint32_t stereo_enable;
+	uint16_t line_width[VFE_MAX];
+};
+
+struct msm_ispif_param_data {
+	uint32_t num;
+	struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES];
+};
+
+struct msm_isp_info {
+	uint32_t max_resolution;
+	uint32_t id;
+	uint32_t ver;
+};
+
+struct msm_ispif_vfe_info {
+	int num_vfe;
+	struct msm_isp_info info[VFE_MAX];
+};
+
+enum ispif_cfg_type_t {
+	ISPIF_CLK_ENABLE,
+	ISPIF_CLK_DISABLE,
+	ISPIF_INIT,
+	ISPIF_CFG,
+	ISPIF_START_FRAME_BOUNDARY,
+	ISPIF_RESTART_FRAME_BOUNDARY,
+	ISPIF_STOP_FRAME_BOUNDARY,
+	ISPIF_STOP_IMMEDIATELY,
+	ISPIF_RELEASE,
+	ISPIF_ENABLE_REG_DUMP,
+	ISPIF_SET_VFE_INFO,
+	ISPIF_CFG2,
+	ISPIF_CFG_STEREO,
+};
+
+struct ispif_cfg_data {
+	enum ispif_cfg_type_t cfg_type;
+	union {
+		int reg_dump;                        /* ISPIF_ENABLE_REG_DUMP */
+		uint32_t csid_version;               /* ISPIF_INIT */
+		struct msm_ispif_vfe_info vfe_info;  /* ISPIF_SET_VFE_INFO */
+		struct msm_ispif_param_data params;  /* CFG, START, STOP */
+	};
+};
+
+struct ispif_cfg_data_ext {
+	enum ispif_cfg_type_t cfg_type;
+	void __user *data;
+	uint32_t size;
+};
+
+#define ISPIF_RDI_PACK_MODE_SUPPORT 1
+
+#define ISPIF_3D_SUPPORT 1
+
+#define ISPIF_LINE_WIDTH_SUPPORT 1
+
+#define VIDIOC_MSM_ISPIF_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data)
+
+#define VIDIOC_MSM_ISPIF_CFG_EXT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext)
+
+#endif
+
diff --git a/include/uapi/media/msmb_pproc.h b/include/uapi/media/msmb_pproc.h
new file mode 100644
index 0000000..8f45457
--- /dev/null
+++ b/include/uapi/media/msmb_pproc.h
@@ -0,0 +1,255 @@
+#ifndef __UAPI_MSMB_PPROC_H
+#define __UAPI_MSMB_PPROC_H
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+#include <media/msmb_generic_buf_mgr.h>
+
+/* Should be same as VIDEO_MAX_PLANES in videodev2.h */
+#define MAX_PLANES VIDEO_MAX_PLANES
+/* PARTIAL_FRAME_STRIPE_COUNT must be even */
+#define PARTIAL_FRAME_STRIPE_COUNT 4
+
+#define MAX_NUM_CPP_STRIPS 8
+#define MSM_CPP_MAX_NUM_PLANES 3
+#define MSM_CPP_MIN_FRAME_LENGTH 13
+#define MSM_CPP_MAX_FRAME_LENGTH 4096
+#define MSM_CPP_MAX_FW_NAME_LEN 32
+#define MAX_FREQ_TBL 10
+#define MSM_OUTPUT_BUF_CNT 8
+
+enum msm_cpp_frame_type {
+	MSM_CPP_OFFLINE_FRAME,
+	MSM_CPP_REALTIME_FRAME,
+};
+
+enum msm_vpe_frame_type {
+	MSM_VPE_OFFLINE_FRAME,
+	MSM_VPE_REALTIME_FRAME,
+};
+
+struct msm_cpp_buffer_info_t {
+	int32_t fd;
+	uint32_t index;
+	uint32_t offset;
+	uint8_t native_buff;
+	uint8_t processed_divert;
+	uint32_t identity;
+};
+
+struct msm_cpp_stream_buff_info_t {
+	uint32_t identity;
+	uint32_t num_buffs;
+	struct msm_cpp_buffer_info_t *buffer_info;
+};
+
+enum msm_cpp_batch_mode_t {
+	BATCH_MODE_NONE,
+	BATCH_MODE_VIDEO,
+	BATCH_MODE_PREVIEW
+};
+
+struct msm_cpp_batch_info_t {
+	enum msm_cpp_batch_mode_t  batch_mode;
+	uint32_t batch_size;
+	uint32_t intra_plane_offset[MAX_PLANES];
+	uint32_t pick_preview_idx;
+	uint32_t cont_idx;
+};
+
+struct msm_cpp_frame_info_t {
+	int32_t frame_id;
+	struct timeval timestamp;
+	uint32_t inst_id;
+	uint32_t identity;
+	uint32_t client_id;
+	enum msm_cpp_frame_type frame_type;
+	uint32_t num_strips;
+	uint32_t msg_len;
+	uint32_t *cpp_cmd_msg;
+	int src_fd;
+	int dst_fd;
+	struct timeval in_time, out_time;
+	void __user *cookie;
+	int32_t *status;
+	int32_t duplicate_output;
+	uint32_t duplicate_identity;
+	uint32_t feature_mask;
+	uint8_t we_disable;
+	struct msm_cpp_buffer_info_t input_buffer_info;
+	struct msm_cpp_buffer_info_t output_buffer_info[MSM_OUTPUT_BUF_CNT];
+	struct msm_cpp_buffer_info_t duplicate_buffer_info;
+	struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2];
+	uint32_t reserved;
+	uint8_t partial_frame_indicator;
+	/* the followings are used only for partial_frame type
+	 * and is only used for offline frame processing and
+	 * only if payload big enough and need to be split into partial_frame
+	 * if first_payload, kernel acquires output buffer
+	 * first payload must have the last stripe
+	 * buffer addresses from 0 to last_stripe_index are updated.
+	 * kernel updates payload with msg_len and stripe_info
+	 * kernel sends top level, plane level, then only stripes
+	 * starting with first_stripe_index and
+	 * ends with last_stripe_index
+	 * kernel then sends trailing flag at frame done,
+	 * if last payload, kernel queues the output buffer to HAL
+	 */
+	uint8_t first_payload;
+	uint8_t last_payload;
+	uint32_t first_stripe_index;
+	uint32_t last_stripe_index;
+	uint32_t stripe_info_offset;
+	uint32_t stripe_info;
+	struct msm_cpp_batch_info_t  batch_info;
+};
+
+struct msm_cpp_pop_stream_info_t {
+	int32_t frame_id;
+	uint32_t identity;
+};
+
+struct cpp_hw_info {
+	uint32_t cpp_hw_version;
+	uint32_t cpp_hw_caps;
+	unsigned long freq_tbl[MAX_FREQ_TBL];
+	uint32_t freq_tbl_count;
+};
+
+struct msm_vpe_frame_strip_info {
+	uint32_t src_w;
+	uint32_t src_h;
+	uint32_t dst_w;
+	uint32_t dst_h;
+	uint32_t src_x;
+	uint32_t src_y;
+	uint32_t phase_step_x;
+	uint32_t phase_step_y;
+	uint32_t phase_init_x;
+	uint32_t phase_init_y;
+};
+
+struct msm_vpe_buffer_info_t {
+	int32_t fd;
+	uint32_t index;
+	uint32_t offset;
+	uint8_t native_buff;
+	uint8_t processed_divert;
+};
+
+struct msm_vpe_stream_buff_info_t {
+	uint32_t identity;
+	uint32_t num_buffs;
+	struct msm_vpe_buffer_info_t *buffer_info;
+};
+
+struct msm_vpe_frame_info_t {
+	int32_t frame_id;
+	struct timeval timestamp;
+	uint32_t inst_id;
+	uint32_t identity;
+	uint32_t client_id;
+	enum msm_vpe_frame_type frame_type;
+	struct msm_vpe_frame_strip_info strip_info;
+	unsigned long src_fd;
+	unsigned long dst_fd;
+	struct ion_handle *src_ion_handle;
+	struct ion_handle *dest_ion_handle;
+	unsigned long src_phyaddr;
+	unsigned long dest_phyaddr;
+	unsigned long src_chroma_plane_offset;
+	unsigned long dest_chroma_plane_offset;
+	struct timeval in_time, out_time;
+	void *cookie;
+
+	struct msm_vpe_buffer_info_t input_buffer_info;
+	struct msm_vpe_buffer_info_t output_buffer_info;
+};
+
+struct msm_pproc_queue_buf_info {
+	struct msm_buf_mngr_info buff_mgr_info;
+	uint8_t is_buf_dirty;
+};
+
+struct msm_cpp_clock_settings_t {
+	unsigned long clock_rate;
+	uint64_t avg;
+	uint64_t inst;
+};
+
+#define VIDIOC_MSM_CPP_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_INST_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_HW_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_FLUSH_QUEUE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_INST_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_QUEUE_BUF \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_SET_CLOCK \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_IOMMU_ATTACH \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_IOMMU_DETACH \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_DELETE_STREAM_BUFF\
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 20, struct msm_camera_v4l2_ioctl_t)
+
+
+#define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
+#define V4L2_EVENT_VPE_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 1)
+
+struct msm_camera_v4l2_ioctl_t {
+	uint32_t id;
+	size_t len;
+	int32_t trans_code;
+	void __user *ioctl_ptr;
+};
+
+#endif
+
diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h
index 08d3beb..2ce6d73 100644
--- a/include/uapi/scsi/sg.h
+++ b/include/uapi/scsi/sg.h
@@ -198,7 +198,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
diff --git a/include/uapi/video/msm_hdmi_hdcp_mgr.h b/include/uapi/video/msm_hdmi_hdcp_mgr.h
index 85fa918..1c19d4a 100644
--- a/include/uapi/video/msm_hdmi_hdcp_mgr.h
+++ b/include/uapi/video/msm_hdmi_hdcp_mgr.h
@@ -1,4 +1,4 @@
-#ifndef _UAPI__HDMI_HDCP_MGR_H
+#ifndef _UAPI__MSM_HDMI_HDCP_MGR_H
 #define _UAPI__MSM_HDMI_HDCP_MGR_H
 
 enum DS_TYPE {  /* type of downstream device */
diff --git a/init/Kconfig b/init/Kconfig
index d4a2e32..2e57658 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1760,6 +1760,13 @@
 	  Enable the bpf() system call that allows to manipulate eBPF
 	  programs and maps via file descriptors.
 
+config BPF_JIT_ALWAYS_ON
+	bool "Permanently enable BPF JIT and remove BPF interpreter"
+	depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT
+	help
+	  Enables BPF JIT and removes BPF interpreter to avoid
+	  speculative execution of BPF instructions by the interpreter
+
 config SHMEM
 	bool "Use full shmem filesystem" if EXPERT
 	default y
diff --git a/ipc/msg.c b/ipc/msg.c
index e12307d..ff10d43 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -763,7 +763,10 @@
 	if (*msgtyp == 0)
 		return SEARCH_ANY;
 	if (*msgtyp < 0) {
-		*msgtyp = -*msgtyp;
+		if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */
+			*msgtyp = LONG_MAX;
+		else
+			*msgtyp = -*msgtyp;
 		return SEARCH_LESSEQUAL;
 	}
 	if (msgflg & MSG_EXCEPT)
diff --git a/kernel/async.c b/kernel/async.c
index d2edd6e..d84d486 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -84,20 +84,24 @@
 
 static async_cookie_t lowest_in_progress(struct async_domain *domain)
 {
-	struct list_head *pending;
+	struct async_entry *first = NULL;
 	async_cookie_t ret = ASYNC_COOKIE_MAX;
 	unsigned long flags;
 
 	spin_lock_irqsave(&async_lock, flags);
 
-	if (domain)
-		pending = &domain->pending;
-	else
-		pending = &async_global_pending;
+	if (domain) {
+		if (!list_empty(&domain->pending))
+			first = list_first_entry(&domain->pending,
+					struct async_entry, domain_list);
+	} else {
+		if (!list_empty(&async_global_pending))
+			first = list_first_entry(&async_global_pending,
+					struct async_entry, global_list);
+	}
 
-	if (!list_empty(pending))
-		ret = list_first_entry(pending, struct async_entry,
-				       domain_list)->cookie;
+	if (first)
+		ret = first->cookie;
 
 	spin_unlock_irqrestore(&async_lock, flags);
 	return ret;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index aa6d981..879ca84 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -458,6 +458,7 @@
 }
 EXPORT_SYMBOL_GPL(__bpf_call_base);
 
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 /**
  *	__bpf_prog_run - run eBPF program on a given context
  *	@ctx: is the data we are operating on
@@ -641,7 +642,7 @@
 		DST = tmp;
 		CONT;
 	ALU_MOD_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		DST = do_div(tmp, (u32) SRC);
@@ -660,7 +661,7 @@
 		DST = div64_u64(DST, SRC);
 		CONT;
 	ALU_DIV_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		do_div(tmp, (u32) SRC);
@@ -715,7 +716,7 @@
 		struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
 		struct bpf_array *array = container_of(map, struct bpf_array, map);
 		struct bpf_prog *prog;
-		u64 index = BPF_R3;
+		u32 index = BPF_R3;
 
 		if (unlikely(index >= array->map.max_entries))
 			goto out;
@@ -923,6 +924,13 @@
 }
 STACK_FRAME_NON_STANDARD(__bpf_prog_run); /* jump table */
 
+#else
+static unsigned int __bpf_prog_ret0(void *ctx, const struct bpf_insn *insn)
+{
+	return 0;
+}
+#endif
+
 bool bpf_prog_array_compatible(struct bpf_array *array,
 			       const struct bpf_prog *fp)
 {
@@ -970,7 +978,11 @@
  */
 struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
 {
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 	fp->bpf_func = (void *) __bpf_prog_run;
+#else
+	fp->bpf_func = (void *) __bpf_prog_ret0;
+#endif
 
 	/* eBPF JITs can rewrite the program in case constant
 	 * blinding is active. However, in case of error during
@@ -979,6 +991,12 @@
 	 * be JITed, but falls back to the interpreter.
 	 */
 	fp = bpf_int_jit_compile(fp);
+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+	if (!fp->jited) {
+		*err = -ENOTSUPP;
+		return fp;
+	}
+#endif
 	bpf_prog_lock_ro(fp);
 
 	/* The tail call compatibility check can only be done at
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 19c44cf..076e4a0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -702,6 +702,13 @@
 	return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
 }
 
+static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
+{
+	const struct bpf_reg_state *reg = &env->cur_state.regs[regno];
+
+	return reg->type == PTR_TO_CTX;
+}
+
 static int check_ptr_alignment(struct bpf_verifier_env *env,
 			       struct bpf_reg_state *reg, int off, int size)
 {
@@ -896,6 +903,12 @@
 		return -EACCES;
 	}
 
+	if (is_ctx_reg(env, insn->dst_reg)) {
+		verbose("BPF_XADD stores into R%d context is not allowed\n",
+			insn->dst_reg);
+		return -EACCES;
+	}
+
 	/* check whether atomic_add can read the memory */
 	err = check_mem_access(env, insn->dst_reg, insn->off,
 			       BPF_SIZE(insn->code), BPF_READ, -1);
@@ -1843,6 +1856,11 @@
 			return -EINVAL;
 		}
 
+		if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) {
+			verbose("BPF_ARSH not supported for 32 bit ALU\n");
+			return -EINVAL;
+		}
+
 		if ((opcode == BPF_LSH || opcode == BPF_RSH ||
 		     opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
 			int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
@@ -3007,6 +3025,12 @@
 			if (err)
 				return err;
 
+			if (is_ctx_reg(env, insn->dst_reg)) {
+				verbose("BPF_ST stores into R%d context is not allowed\n",
+					insn->dst_reg);
+				return -EACCES;
+			}
+
 			/* check that memory (dst_reg + off) is writeable */
 			err = check_mem_access(env, insn->dst_reg, insn->off,
 					       BPF_SIZE(insn->code), BPF_WRITE,
@@ -3386,6 +3410,24 @@
 
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
+		if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
+		    insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
+			/* due to JIT bugs clear upper 32-bits of src register
+			 * before div/mod operation
+			 */
+			insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg);
+			insn_buf[1] = *insn;
+			cnt = 2;
+			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+			if (!new_prog)
+				return -ENOMEM;
+
+			delta    += cnt - 1;
+			env->prog = prog = new_prog;
+			insn      = new_prog->insnsi + i + delta;
+			continue;
+		}
+
 		if (insn->code != (BPF_JMP | BPF_CALL))
 			continue;
 
diff --git a/kernel/futex.c b/kernel/futex.c
index 88bad86..bb2265a 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1711,6 +1711,9 @@
 	struct futex_q *this, *next;
 	WAKE_Q(wake_q);
 
+	if (nr_wake < 0 || nr_requeue < 0)
+		return -EINVAL;
+
 	if (requeue_pi) {
 		/*
 		 * Requeue PI only works on two distinct uaddrs. This
diff --git a/kernel/module.c b/kernel/module.c
index 0e54d5b..07bfb99 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2817,6 +2817,15 @@
 }
 #endif /* CONFIG_LIVEPATCH */
 
+static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
+{
+	if (retpoline_module_ok(get_modinfo(info, "retpoline")))
+		return;
+
+	pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+		mod->name);
+}
+
 /* Sets info->hdr and info->len. */
 static int copy_module_from_user(const void __user *umod, unsigned long len,
 				  struct load_info *info)
@@ -2969,6 +2978,8 @@
 		add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
 	}
 
+	check_modinfo_retpoline(mod, info);
+
 	if (get_modinfo(info, "staging")) {
 		add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
 		pr_warn("%s: module is from the staging directory, the quality "
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 5183134..0469d80 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -597,12 +597,11 @@
 #ifdef CONFIG_SMP
 	case PM_QOS_REQ_AFFINE_IRQ:
 		if (irq_can_set_affinity(req->irq)) {
-			int ret = 0;
 			struct irq_desc *desc = irq_to_desc(req->irq);
 			struct cpumask *mask;
 
 			if (!desc)
-				break;
+				return;
 
 			mask = desc->irq_data.common->affinity;
 
@@ -612,13 +611,6 @@
 			req->irq_notify.notify = pm_qos_irq_notify;
 			req->irq_notify.release = pm_qos_irq_release;
 
-			ret = irq_set_affinity_notifier(req->irq,
-					&req->irq_notify);
-			if (ret) {
-				WARN(1, KERN_ERR "IRQ affinity notify set failed\n");
-				req->type = PM_QOS_REQ_ALL_CORES;
-				cpumask_setall(&req->cpus_affine);
-			}
 		} else {
 			req->type = PM_QOS_REQ_ALL_CORES;
 			cpumask_setall(&req->cpus_affine);
@@ -640,6 +632,24 @@
 	trace_pm_qos_add_request(pm_qos_class, value);
 	pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
 			     req, PM_QOS_ADD_REQ, value);
+
+#ifdef CONFIG_SMP
+	if (req->type == PM_QOS_REQ_AFFINE_IRQ &&
+			irq_can_set_affinity(req->irq)) {
+		int ret = 0;
+
+		ret = irq_set_affinity_notifier(req->irq,
+					&req->irq_notify);
+		if (ret) {
+			WARN(1, "IRQ affinity notify set failed\n");
+			req->type = PM_QOS_REQ_ALL_CORES;
+			cpumask_setall(&req->cpus_affine);
+			pm_qos_update_target(
+				pm_qos_array[pm_qos_class]->constraints,
+				req, PM_QOS_UPDATE_REQ, value);
+		}
+	}
+#endif
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
diff --git a/kernel/relay.c b/kernel/relay.c
index 8f18d31..2603e04 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -611,7 +611,6 @@
 
 	kref_put(&chan->kref, relay_destroy_channel);
 	mutex_unlock(&relay_channels_mutex);
-	kfree(chan);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(relay_open);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4bd59d9..23a7f9c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -775,6 +775,7 @@
 	if (!(flags & ENQUEUE_RESTORE))
 		sched_info_queued(rq, p);
 	p->sched_class->enqueue_task(rq, p, flags);
+	walt_update_last_enqueue(p);
 	trace_sched_enq_deq_task(p, 1, cpumask_bits(&p->cpus_allowed)[0]);
 }
 
@@ -6381,6 +6382,19 @@
 		call_rcu_sched(&old_rd->rcu, free_rootdomain);
 }
 
+void sched_get_rd(struct root_domain *rd)
+{
+	atomic_inc(&rd->refcount);
+}
+
+void sched_put_rd(struct root_domain *rd)
+{
+	if (!atomic_dec_and_test(&rd->refcount))
+		return;
+
+	call_rcu_sched(&rd->rcu, free_rootdomain);
+}
+
 static int init_rootdomain(struct root_domain *rd)
 {
 	memset(rd, 0, sizeof(*rd));
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index cc5a97c..c0a8a2a 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -482,6 +482,7 @@
 
 	sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg,
 				 &max_nr, &big_max_nr);
+	walt_rotation_checkpoint(big_avg);
 
 	spin_lock_irqsave(&state_lock, flags);
 	for_each_cluster(cluster, index) {
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index da8261d..0a295ac 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -724,6 +724,8 @@
 		if (unlikely(dl_se->dl_boosted || !start_dl_timer(p)))
 			return;
 		dl_se->dl_throttled = 1;
+		if (dl_se->runtime > 0)
+			dl_se->runtime = 0;
 	}
 }
 
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index c091ca4..16065b2 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -784,7 +784,6 @@
 	P(sysctl_sched_child_runs_first);
 	P(sysctl_sched_features);
 #ifdef CONFIG_SCHED_WALT
-	P(sched_init_task_load_windows);
 	P(min_capacity);
 	P(max_capacity);
 	P(sched_ravg_window);
diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c
index 420cb52..77d8361 100644
--- a/kernel/sched/energy.c
+++ b/kernel/sched/energy.c
@@ -150,6 +150,7 @@
 	int cpu;
 	unsigned long *max_frequencies = NULL;
 	int ret;
+	bool is_sge_valid = false;
 
 	if (!sched_is_energy_aware())
 		return 0;
@@ -248,6 +249,7 @@
 					sge_l0->cap_states[i].power);
 			}
 
+			is_sge_valid = true;
 			dev_info(&pdev->dev,
 				"cpu=%d eff=%d [freq=%ld cap=%ld power_d0=%ld] -> [freq=%ld cap=%ld power_d0=%ld]\n",
 				cpu, efficiency,
@@ -271,7 +273,8 @@
 
 	kfree(max_frequencies);
 
-	walt_sched_energy_populated_callback();
+	if (is_sge_valid)
+		walt_sched_energy_populated_callback();
 	dev_info(&pdev->dev, "Sched-energy-costs capacity updated\n");
 	return 0;
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6026b1b..75ea4ff 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -10021,6 +10021,19 @@
 		if (need_active_balance(&env)) {
 			raw_spin_lock_irqsave(&busiest->lock, flags);
 
+			/*
+			 * The CPUs are marked as reserved if tasks
+			 * are pushed/pulled from other CPUs. In that case,
+			 * bail out from the load balancer.
+			 */
+			if (is_reserved(this_cpu) ||
+			    is_reserved(cpu_of(busiest))) {
+				raw_spin_unlock_irqrestore(&busiest->lock,
+							   flags);
+				*continue_balancing = 0;
+				goto out;
+			}
+
 			/* don't kick the active_load_balance_cpu_stop,
 			 * if the curr task on busiest cpu can't be
 			 * moved to this_cpu
@@ -11620,6 +11633,141 @@
 	return rc;
 }
 
+#ifdef CONFIG_SCHED_WALT
+struct walt_rotate_work {
+	struct work_struct w;
+	struct task_struct *src_task;
+	struct task_struct *dst_task;
+	int src_cpu;
+	int dst_cpu;
+};
+
+static DEFINE_PER_CPU(struct walt_rotate_work, walt_rotate_works);
+
+static void walt_rotate_work_func(struct work_struct *work)
+{
+	struct walt_rotate_work *wr = container_of(work,
+				struct walt_rotate_work, w);
+
+	migrate_swap(wr->src_task, wr->dst_task);
+
+	put_task_struct(wr->src_task);
+	put_task_struct(wr->dst_task);
+
+	clear_reserved(wr->src_cpu);
+	clear_reserved(wr->dst_cpu);
+}
+
+void walt_rotate_work_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		struct walt_rotate_work *wr = &per_cpu(walt_rotate_works, i);
+
+		INIT_WORK(&wr->w, walt_rotate_work_func);
+	}
+}
+
+#define WALT_ROTATION_THRESHOLD_NS	16000000
+static void walt_check_for_rotation(struct rq *src_rq)
+{
+	u64 wc, wait, max_wait = 0, run, max_run = 0;
+	int deserved_cpu = nr_cpu_ids, dst_cpu = nr_cpu_ids;
+	int i, src_cpu = cpu_of(src_rq);
+	struct rq *dst_rq;
+	struct walt_rotate_work *wr = NULL;
+
+	if (!walt_rotation_enabled)
+		return;
+
+	if (got_boost_kick())
+		return;
+
+	if (is_max_capacity_cpu(src_cpu))
+		return;
+
+	wc = ktime_get_ns();
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (is_max_capacity_cpu(i))
+			break;
+
+		if (is_reserved(i))
+			continue;
+
+		if (!rq->misfit_task || rq->curr->sched_class !=
+						&fair_sched_class)
+			continue;
+
+		wait = wc - rq->curr->last_enqueued_ts;
+		if (wait > max_wait) {
+			max_wait = wait;
+			deserved_cpu = i;
+		}
+	}
+
+	if (deserved_cpu != src_cpu)
+		return;
+
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (!is_max_capacity_cpu(i))
+			continue;
+
+		if (is_reserved(i))
+			continue;
+
+		if (rq->curr->sched_class != &fair_sched_class)
+			continue;
+
+		if (rq->nr_running > 1)
+			continue;
+
+		run = wc - rq->curr->last_enqueued_ts;
+
+		if (run < WALT_ROTATION_THRESHOLD_NS)
+			continue;
+
+		if (run > max_run) {
+			max_run = run;
+			dst_cpu = i;
+		}
+	}
+
+	if (dst_cpu == nr_cpu_ids)
+		return;
+
+	dst_rq = cpu_rq(dst_cpu);
+
+	double_rq_lock(src_rq, dst_rq);
+	if (dst_rq->curr->sched_class == &fair_sched_class) {
+		get_task_struct(src_rq->curr);
+		get_task_struct(dst_rq->curr);
+
+		mark_reserved(src_cpu);
+		mark_reserved(dst_cpu);
+		wr = &per_cpu(walt_rotate_works, src_cpu);
+
+		wr->src_task = src_rq->curr;
+		wr->dst_task = dst_rq->curr;
+
+		wr->src_cpu = src_cpu;
+		wr->dst_cpu = dst_cpu;
+	}
+	double_rq_unlock(src_rq, dst_rq);
+
+	if (wr)
+		queue_work_on(src_cpu, system_highpri_wq, &wr->w);
+}
+#else
+static inline void walt_check_for_rotation(struct rq *rq)
+{
+}
+#endif
+
 static DEFINE_RAW_SPINLOCK(migration_lock);
 void check_for_migration(struct rq *rq, struct task_struct *p)
 {
@@ -11649,6 +11797,8 @@
 					&rq->active_balance_work);
 				return;
 			}
+		} else {
+			walt_check_for_rotation(rq);
 		}
 		raw_spin_unlock(&migration_lock);
 	}
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 73f11c4..e6abbb4 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2261,8 +2261,11 @@
 
 	rto_start_unlock(&rq->rd->rto_loop_start);
 
-	if (cpu >= 0)
+	if (cpu >= 0) {
+		/* Make sure the rd does not get freed while pushing */
+		sched_get_rd(rq->rd);
 		irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+	}
 }
 
 /* Called from hardirq context */
@@ -2292,8 +2295,10 @@
 
 	raw_spin_unlock(&rd->rto_lock);
 
-	if (cpu < 0)
+	if (cpu < 0) {
+		sched_put_rd(rd);
 		return;
+	}
 
 	/* Try the next RT overloaded CPU */
 	irq_work_queue_on(&rd->rto_push_work, cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0e03653..bac069a 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -679,6 +679,8 @@
 };
 
 extern struct root_domain def_root_domain;
+extern void sched_get_rd(struct root_domain *rd);
+extern void sched_put_rd(struct root_domain *rd);
 
 #ifdef HAVE_RT_PUSH_IPI
 extern void rto_push_irq_work_func(struct irq_work *work);
@@ -943,8 +945,8 @@
 };
 extern void sched_setnuma(struct task_struct *p, int node);
 extern int migrate_task_to(struct task_struct *p, int cpu);
-extern int migrate_swap(struct task_struct *, struct task_struct *);
 #endif /* CONFIG_NUMA_BALANCING */
+extern int migrate_swap(struct task_struct *cur, struct task_struct *p);
 
 #ifdef CONFIG_SMP
 
@@ -2343,7 +2345,6 @@
 extern unsigned int max_possible_capacity;
 extern unsigned int min_max_possible_capacity;
 extern unsigned int max_power_cost;
-extern unsigned int sched_init_task_load_windows;
 extern unsigned int up_down_migrate_scale_factor;
 extern unsigned int sysctl_sched_restrict_cluster_spill;
 extern unsigned int sched_pred_alert_load;
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 83404a7..b4d815c 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -88,6 +88,9 @@
 
 __read_mostly unsigned int sysctl_sched_cpu_high_irqload = (10 * NSEC_PER_MSEC);
 
+unsigned int sysctl_sched_walt_rotate_big_tasks;
+unsigned int walt_rotation_enabled;
+
 /*
  * sched_window_stats_policy and sched_ravg_hist_size have a 'sysctl' copy
  * associated with them. This is required for atomic update of those variables
@@ -116,7 +119,6 @@
 __read_mostly unsigned int walt_cpu_util_freq_divisor;
 
 /* Initial task load. Newly created tasks are assigned this load. */
-unsigned int __read_mostly sched_init_task_load_windows;
 unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15;
 
 /*
@@ -316,7 +318,8 @@
 	struct task_struct *p;
 	int loop_max = 10;
 
-	if (sched_boost_policy() == SCHED_BOOST_NONE || !rq->cfs.h_nr_running)
+	if ((!walt_rotation_enabled && sched_boost_policy() ==
+			SCHED_BOOST_NONE) || !rq->cfs.h_nr_running)
 		return 0;
 
 	rq->ed_task = NULL;
@@ -487,7 +490,7 @@
 
 done:
 	trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, freq_aggr_thresh,
-				load, reporting_policy);
+				load, reporting_policy, walt_rotation_enabled);
 	return load;
 }
 
@@ -1906,12 +1909,16 @@
 	update_task_demand(p, rq, event, wallclock);
 	update_cpu_busy_time(p, rq, event, wallclock, irqtime);
 	update_task_pred_demand(rq, p, event);
-done:
+
+	if (exiting_task(p))
+		goto done;
+
 	trace_sched_update_task_ravg(p, rq, event, wallclock, irqtime,
 				rq->cc.cycles, rq->cc.time, &rq->grp_time);
 	trace_sched_update_task_ravg_mini(p, rq, event, wallclock, irqtime,
 				rq->cc.cycles, rq->cc.time, &rq->grp_time);
 
+done:
 	p->ravg.mark_start = wallclock;
 
 	run_walt_irq_work(old_window_start, rq);
@@ -1935,8 +1942,8 @@
 void init_new_task_load(struct task_struct *p, bool idle_task)
 {
 	int i;
-	u32 init_load_windows = sched_init_task_load_windows;
-	u32 init_load_pct = current->init_load_pct;
+	u32 init_load_windows;
+	u32 init_load_pct;
 
 	p->init_load_pct = 0;
 	rcu_assign_pointer(p->grp, NULL);
@@ -1953,9 +1960,13 @@
 	if (idle_task)
 		return;
 
-	if (init_load_pct)
-		init_load_windows = div64_u64((u64)init_load_pct *
-			  (u64)sched_ravg_window, 100);
+	if (current->init_load_pct)
+		init_load_pct = current->init_load_pct;
+	else
+		init_load_pct = sysctl_sched_init_task_load_pct;
+
+	init_load_windows = div64_u64((u64)init_load_pct *
+				(u64)sched_ravg_window, 100);
 
 	p->ravg.demand = init_load_windows;
 	p->ravg.coloc_demand = init_load_windows;
@@ -2019,7 +2030,7 @@
 
 	wallclock = ktime_get_ns();
 	p->ravg.mark_start = p->last_wake_ts = wallclock;
-	p->last_cpu_selected_ts = wallclock;
+	p->last_enqueued_ts = wallclock;
 	p->last_switch_out_ts = 0;
 	update_task_cpu_cycles(p, cpu_of(rq));
 }
@@ -3144,6 +3155,19 @@
 		core_ctl_check(this_rq()->window_start);
 }
 
+void walt_rotation_checkpoint(int nr_big)
+{
+	if (!hmp_capable())
+		return;
+
+	if (!sysctl_sched_walt_rotate_big_tasks || sched_boost() != NO_BOOST) {
+		walt_rotation_enabled = 0;
+		return;
+	}
+
+	walt_rotation_enabled = nr_big >= num_possible_cpus();
+}
+
 int walt_proc_update_handler(struct ctl_table *table, int write,
 			     void __user *buffer, size_t *lenp,
 			     loff_t *ppos)
@@ -3179,6 +3203,8 @@
 	cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
 	init_irq_work(&walt_migration_irq_work, walt_irq_work);
 	init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
+	walt_rotate_work_init();
+
 	rq->walt_stats.cumulative_runnable_avg = 0;
 	rq->window_start = 0;
 	rq->cum_window_start = 0;
@@ -3224,8 +3250,4 @@
 
 	walt_cpu_util_freq_divisor =
 	    (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100;
-
-	sched_init_task_load_windows =
-		div64_u64((u64)sysctl_sched_init_task_load_pct *
-			  (u64)sched_ravg_window, 100);
 }
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index bb93ee3..414c4ae 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -40,7 +40,6 @@
 extern unsigned int min_possible_efficiency;
 extern unsigned int max_possible_freq;
 extern unsigned int sched_major_task_runtime;
-extern unsigned int __read_mostly sched_init_task_load_windows;
 extern unsigned int __read_mostly sched_load_granule;
 
 extern struct mutex cluster_lock;
@@ -292,9 +291,20 @@
 	return sysctl_sched_is_big_little ? prev_cpu : min_power_cpu;
 }
 
+static inline void walt_update_last_enqueue(struct task_struct *p)
+{
+	p->last_enqueued_ts = ktime_get_ns();
+}
+extern void walt_rotate_work_init(void);
+extern void walt_rotation_checkpoint(int nr_big);
+extern unsigned int walt_rotation_enabled;
+
 #else /* CONFIG_SCHED_WALT */
 
 static inline void walt_sched_init(struct rq *rq) { }
+static inline void walt_rotate_work_init(void) { }
+static inline void walt_rotation_checkpoint(int nr_big) { }
+static inline void walt_update_last_enqueue(struct task_struct *p) { }
 
 static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
 				int event, u64 wallclock, u64 irqtime) { }
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 6833ffa..b593317 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -85,17 +85,6 @@
 }
 
 /*
- * If ksoftirqd is scheduled, we do not want to process pending softirqs
- * right now. Let ksoftirqd handle this at its own rate, to get fairness.
- */
-static bool ksoftirqd_running(void)
-{
-	struct task_struct *tsk = __this_cpu_read(ksoftirqd);
-
-	return tsk && (tsk->state == TASK_RUNNING);
-}
-
-/*
  * preempt_count and SOFTIRQ_OFFSET usage:
  * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
  *   softirq processing.
@@ -245,8 +234,16 @@
 static inline void lockdep_softirq_end(bool in_hardirq) { }
 #endif
 
-#define long_softirq_pending()	(local_softirq_pending() & LONG_SOFTIRQ_MASK)
-#define defer_for_rt()		(long_softirq_pending() && cpupri_check_rt())
+#define softirq_deferred_for_rt(pending)		\
+({							\
+	__u32 deferred = 0;				\
+	if (cpupri_check_rt()) {			\
+		deferred = pending & LONG_SOFTIRQ_MASK; \
+		pending &= ~LONG_SOFTIRQ_MASK;		\
+	}						\
+	deferred;					\
+})
+
 asmlinkage __visible void __softirq_entry __do_softirq(void)
 {
 	unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -254,6 +251,7 @@
 	int max_restart = MAX_SOFTIRQ_RESTART;
 	struct softirq_action *h;
 	bool in_hardirq;
+	__u32 deferred;
 	__u32 pending;
 	int softirq_bit;
 
@@ -265,14 +263,14 @@
 	current->flags &= ~PF_MEMALLOC;
 
 	pending = local_softirq_pending();
+	deferred = softirq_deferred_for_rt(pending);
 	account_irq_enter_time(current);
-
 	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
 	in_hardirq = lockdep_softirq_start();
 
 restart:
 	/* Reset the pending bitmask before enabling irqs */
-	set_softirq_pending(0);
+	set_softirq_pending(deferred);
 	__this_cpu_write(active_softirqs, pending);
 
 	local_irq_enable();
@@ -308,15 +306,16 @@
 	local_irq_disable();
 
 	pending = local_softirq_pending();
+	deferred = softirq_deferred_for_rt(pending);
+
 	if (pending) {
 		if (time_before(jiffies, end) && !need_resched() &&
-		    !defer_for_rt() &&
 		    --max_restart)
 			goto restart;
-
-		wakeup_softirqd();
 	}
 
+	if (pending | deferred)
+		wakeup_softirqd();
 	lockdep_softirq_end(in_hardirq);
 	account_irq_exit_time(current);
 	__local_bh_enable(SOFTIRQ_OFFSET);
@@ -336,7 +335,7 @@
 
 	pending = local_softirq_pending();
 
-	if (pending && !ksoftirqd_running())
+	if (pending)
 		do_softirq_own_stack();
 
 	local_irq_restore(flags);
@@ -363,10 +362,7 @@
 
 static inline void invoke_softirq(void)
 {
-	if (ksoftirqd_running())
-		return;
-
-	if (!force_irqthreads && !defer_for_rt()) {
+	if (!force_irqthreads) {
 #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
 		/*
 		 * We can safely execute softirq on the current stack if
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index dca7f37..6340010 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -127,7 +127,9 @@
 static int __maybe_unused four = 4;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
+#ifdef CONFIG_PERF_EVENTS
 static int one_thousand = 1000;
+#endif
 #ifdef CONFIG_PRINTK
 static int ten_thousand = 10000;
 #endif
@@ -323,6 +325,22 @@
 		.extra1         = &zero,
 		.extra2		= &three,
 	},
+	{
+		.procname	= "sched_walt_rotate_big_tasks",
+		.data		= &sysctl_sched_walt_rotate_big_tasks,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
+	{
+		.procname	= "sched_initial_task_util",
+		.data		= &sysctl_sched_init_task_load_pct,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 #endif
 	{
 		.procname	= "sched_upmigrate",
@@ -1565,8 +1583,16 @@
 		.maxlen		= sizeof(watermark_scale_factor),
 		.mode		= 0644,
 		.proc_handler	= watermark_scale_factor_sysctl_handler,
-		.extra1		= &one,
-		.extra2		= &one_thousand,
+		.extra1		= &zero,
+		.extra2		= &zero,
+	},
+	{
+		.procname	= "extra_free_kbytes",
+		.data		= &extra_free_kbytes,
+		.maxlen		= sizeof(extra_free_kbytes),
+		.mode		= 0644,
+		.proc_handler	= min_free_kbytes_sysctl_handler,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "percpu_pagelist_fraction",
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index d542c09..8f79045 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -527,6 +527,7 @@
 	{ CTL_INT,	NET_IPV6_PROXY_NDP,			"proxy_ndp" },
 	{ CTL_INT,	NET_IPV6_ACCEPT_SOURCE_ROUTE,		"accept_source_route" },
 	{ CTL_INT,	NET_IPV6_ACCEPT_RA_FROM_LOCAL,		"accept_ra_from_local" },
+	{ CTL_INT,	NET_IPV6_ACCEPT_RA_PREFIX_ROUTE,	"accept_ra_prefix_route" },
 	{}
 };
 
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index a01a71f..38b008e 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -652,7 +652,9 @@
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
 {
 	base->expires_next.tv64 = KTIME_MAX;
+	base->hang_detected = 0;
 	base->hres_active = 0;
+	base->next_timer = NULL;
 }
 
 /*
@@ -1582,6 +1584,7 @@
 		timerqueue_init_head(&cpu_base->clock_base[i].active);
 	}
 
+	cpu_base->active_bases = 0;
 	cpu_base->cpu = cpu;
 	hrtimer_init_hres(cpu_base);
 	return 0;
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index f2826c3..fc7c37a 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -507,17 +507,22 @@
 {
 	struct task_struct *rtn = current->group_leader;
 
-	if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
-		(!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
-		 !same_thread_group(rtn, current) ||
-		 (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
+	switch (event->sigev_notify) {
+	case SIGEV_SIGNAL | SIGEV_THREAD_ID:
+		rtn = find_task_by_vpid(event->sigev_notify_thread_id);
+		if (!rtn || !same_thread_group(rtn, current))
+			return NULL;
+		/* FALLTHRU */
+	case SIGEV_SIGNAL:
+	case SIGEV_THREAD:
+		if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
+			return NULL;
+		/* FALLTHRU */
+	case SIGEV_NONE:
+		return task_pid(rtn);
+	default:
 		return NULL;
-
-	if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
-	    ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
-		return NULL;
-
-	return task_pid(rtn);
+	}
 }
 
 void posix_timers_register_clock(const clockid_t clock_id,
@@ -745,8 +750,7 @@
 	/* interval timer ? */
 	if (iv.tv64)
 		cur_setting->it_interval = ktime_to_timespec(iv);
-	else if (!hrtimer_active(timer) &&
-		 (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+	else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE)
 		return;
 
 	now = timer->base->get_time();
@@ -757,7 +761,7 @@
 	 * expiry is > now.
 	 */
 	if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
-	    (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
+			timr->it_sigev_notify == SIGEV_NONE))
 		timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
 
 	remaining = __hrtimer_expires_remaining_adjusted(timer, now);
@@ -767,7 +771,7 @@
 		 * A single shot SIGEV_NONE timer must return 0, when
 		 * it is expired !
 		 */
-		if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+		if (timr->it_sigev_notify != SIGEV_NONE)
 			cur_setting->it_value.tv_nsec = 1;
 	} else
 		cur_setting->it_value = ktime_to_timespec(remaining);
@@ -865,7 +869,7 @@
 	timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
 
 	/* SIGEV_NONE timers are not queued ! See common_timer_get */
-	if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
+	if (timr->it_sigev_notify == SIGEV_NONE) {
 		/* Setup correct expiry time for relative timers */
 		if (mode == HRTIMER_MODE_REL) {
 			hrtimer_add_expires(timer, timer->base->get_time());
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 5b5d016..41481dc 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1709,7 +1709,7 @@
 	hrtimer_run_queues();
 	/* Raise the softirq only if required. */
 	if (time_before(jiffies, base->clk)) {
-		if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active)
+		if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
 			return;
 		/* CPU is awake, so check the deferrable base. */
 		base++;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5b8d718..2884fe0 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3911,7 +3911,6 @@
 		func_g.type = filter_parse_regex(glob, strlen(glob),
 						 &func_g.search, &not);
 		func_g.len = strlen(func_g.search);
-		func_g.search = glob;
 
 		/* we do not support '!' for function probes */
 		if (WARN_ON(not))
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 72687f4..b15316a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2201,6 +2201,7 @@
 {
 	struct trace_event_call *call, *p;
 	const char *last_system = NULL;
+	bool first = false;
 	int last_i;
 	int i;
 
@@ -2208,15 +2209,28 @@
 	list_for_each_entry_safe(call, p, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
+			first = true;
 			last_i = 0;
 			last_system = call->class->system;
 		}
 
+		/*
+		 * Since calls are grouped by systems, the likelyhood that the
+		 * next call in the iteration belongs to the same system as the
+		 * previous call is high. As an optimization, we skip seaching
+		 * for a map[] that matches the call's system if the last call
+		 * was from the same system. That's what last_i is for. If the
+		 * call has the same system as the previous call, then last_i
+		 * will be the index of the first map[] that has a matching
+		 * system.
+		 */
 		for (i = last_i; i < len; i++) {
 			if (call->class->system == map[i]->system) {
 				/* Save the first system if need be */
-				if (!last_i)
+				if (first) {
 					last_i = i;
+					first = false;
+				}
 				update_event_printk(call, map[i]);
 			}
 		}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 9aea3480..5ef61bd 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -50,6 +50,7 @@
 #include <linux/uaccess.h>
 #include <linux/bug.h>
 #include <linux/delay.h>
+#include <linux/nmi.h>
 
 #include "workqueue_internal.h"
 
@@ -4431,6 +4432,12 @@
 			if (pwq->nr_active || !list_empty(&pwq->delayed_works))
 				show_pwq(pwq);
 			spin_unlock_irqrestore(&pwq->pool->lock, flags);
+			/*
+			 * We could be printing a lot from atomic context, e.g.
+			 * sysrq-t -> show_workqueue_state(). Avoid triggering
+			 * hard lockup.
+			 */
+			touch_nmi_watchdog();
 		}
 	}
 
@@ -4458,6 +4465,12 @@
 		pr_cont("\n");
 	next_pool:
 		spin_unlock_irqrestore(&pool->lock, flags);
+		/*
+		 * We could be printing a lot from atomic context, e.g.
+		 * sysrq-t -> show_workqueue_state(). Avoid triggering
+		 * hard lockup.
+		 */
+		touch_nmi_watchdog();
 	}
 
 	rcu_read_unlock_sched();
diff --git a/lib/kobject.c b/lib/kobject.c
index 445dcae..763d70a 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -601,12 +601,15 @@
 }
 EXPORT_SYMBOL(kobject_get);
 
-static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
+struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
 {
+	if (!kobj)
+		return NULL;
 	if (!kref_get_unless_zero(&kobj->kref))
 		kobj = NULL;
 	return kobj;
 }
+EXPORT_SYMBOL(kobject_get_unless_zero);
 
 /*
  * kobject_cleanup - free kobject resources.
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 2e38502..98da752 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -5646,9 +5646,8 @@
 				return NULL;
 			}
 		}
-		/* We don't expect to fail. */
 		if (*err) {
-			pr_cont("FAIL to attach err=%d len=%d\n",
+			pr_cont("FAIL to prog_create err=%d len=%d\n",
 				*err, fprog.len);
 			return NULL;
 		}
@@ -5671,6 +5670,10 @@
 		 * checks.
 		 */
 		fp = bpf_prog_select_runtime(fp, err);
+		if (*err) {
+			pr_cont("FAIL to select_runtime err=%d\n", *err);
+			return NULL;
+		}
 		break;
 	}
 
@@ -5856,8 +5859,8 @@
 				pass_cnt++;
 				continue;
 			}
-
-			return err;
+			err_cnt++;
+			continue;
 		}
 
 		pr_cont("jited:%u ", fp->jited);
diff --git a/lib/ubsan.c b/lib/ubsan.c
index fb0409d..50d1d5c 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -265,14 +265,14 @@
 }
 EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
 
-static void handle_null_ptr_deref(struct type_mismatch_data *data)
+static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
 {
 	unsigned long flags;
 
-	if (suppress_report(&data->location))
+	if (suppress_report(data->location))
 		return;
 
-	ubsan_prologue(&data->location, &flags);
+	ubsan_prologue(data->location, &flags);
 
 	pr_err("%s null pointer of type %s\n",
 		type_check_kinds[data->type_check_kind],
@@ -281,15 +281,15 @@
 	ubsan_epilogue(&flags);
 }
 
-static void handle_missaligned_access(struct type_mismatch_data *data,
+static void handle_misaligned_access(struct type_mismatch_data_common *data,
 				unsigned long ptr)
 {
 	unsigned long flags;
 
-	if (suppress_report(&data->location))
+	if (suppress_report(data->location))
 		return;
 
-	ubsan_prologue(&data->location, &flags);
+	ubsan_prologue(data->location, &flags);
 
 	pr_err("%s misaligned address %p for type %s\n",
 		type_check_kinds[data->type_check_kind],
@@ -299,15 +299,15 @@
 	ubsan_epilogue(&flags);
 }
 
-static void handle_object_size_mismatch(struct type_mismatch_data *data,
+static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
 					unsigned long ptr)
 {
 	unsigned long flags;
 
-	if (suppress_report(&data->location))
+	if (suppress_report(data->location))
 		return;
 
-	ubsan_prologue(&data->location, &flags);
+	ubsan_prologue(data->location, &flags);
 	pr_err("%s address %p with insufficient space\n",
 		type_check_kinds[data->type_check_kind],
 		(void *) ptr);
@@ -315,19 +315,47 @@
 	ubsan_epilogue(&flags);
 }
 
-void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
+static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
 				unsigned long ptr)
 {
 
 	if (!ptr)
 		handle_null_ptr_deref(data);
 	else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
-		handle_missaligned_access(data, ptr);
+		handle_misaligned_access(data, ptr);
 	else
 		handle_object_size_mismatch(data, ptr);
 }
+
+void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
+				unsigned long ptr)
+{
+	struct type_mismatch_data_common common_data = {
+		.location = &data->location,
+		.type = data->type,
+		.alignment = data->alignment,
+		.type_check_kind = data->type_check_kind
+	};
+
+	ubsan_type_mismatch_common(&common_data, ptr);
+}
 EXPORT_SYMBOL(__ubsan_handle_type_mismatch);
 
+void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
+				unsigned long ptr)
+{
+
+	struct type_mismatch_data_common common_data = {
+		.location = &data->location,
+		.type = data->type,
+		.alignment = 1UL << data->log_alignment,
+		.type_check_kind = data->type_check_kind
+	};
+
+	ubsan_type_mismatch_common(&common_data, ptr);
+}
+EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
+
 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
 {
 	unsigned long flags;
diff --git a/lib/ubsan.h b/lib/ubsan.h
index b2d18d4..d8b8085 100644
--- a/lib/ubsan.h
+++ b/lib/ubsan.h
@@ -36,6 +36,20 @@
 	unsigned char type_check_kind;
 };
 
+struct type_mismatch_data_v1 {
+	struct source_location location;
+	struct type_descriptor *type;
+	unsigned char log_alignment;
+	unsigned char type_check_kind;
+};
+
+struct type_mismatch_data_common {
+	struct source_location *location;
+	struct type_descriptor *type;
+	unsigned long alignment;
+	unsigned char type_check_kind;
+};
+
 struct nonnull_arg_data {
 	struct source_location location;
 	struct source_location attr_location;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 6ff2d77..62ca907 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -237,6 +237,7 @@
 
 	bdi_class->dev_groups = bdi_dev_groups;
 	bdi_debug_init();
+
 	return 0;
 }
 postcore_initcall(bdi_class_init);
@@ -293,6 +294,8 @@
 
 	memset(wb, 0, sizeof(*wb));
 
+	if (wb != &bdi->wb)
+		bdi_get(bdi);
 	wb->bdi = bdi;
 	wb->last_old_flush = jiffies;
 	INIT_LIST_HEAD(&wb->b_dirty);
@@ -312,8 +315,10 @@
 	INIT_DELAYED_WORK(&wb->dwork, wb_workfn);
 
 	wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp);
-	if (!wb->congested)
-		return -ENOMEM;
+	if (!wb->congested) {
+		err = -ENOMEM;
+		goto out_put_bdi;
+	}
 
 	err = fprop_local_init_percpu(&wb->completions, gfp);
 	if (err)
@@ -333,9 +338,14 @@
 	fprop_local_destroy_percpu(&wb->completions);
 out_put_cong:
 	wb_congested_put(wb->congested);
+out_put_bdi:
+	if (wb != &bdi->wb)
+		bdi_put(bdi);
 	return err;
 }
 
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb);
+
 /*
  * Remove bdi from the global list and shutdown any threads we have running
  */
@@ -345,10 +355,18 @@
 	spin_lock_bh(&wb->work_lock);
 	if (!test_and_clear_bit(WB_registered, &wb->state)) {
 		spin_unlock_bh(&wb->work_lock);
+		/*
+		 * Wait for wb shutdown to finish if someone else is just
+		 * running wb_shutdown(). Otherwise we could proceed to wb /
+		 * bdi destruction before wb_shutdown() is finished.
+		 */
+		wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE);
 		return;
 	}
+	set_bit(WB_shutting_down, &wb->state);
 	spin_unlock_bh(&wb->work_lock);
 
+	cgwb_remove_from_bdi_list(wb);
 	/*
 	 * Drain work list and shutdown the delayed_work.  !WB_registered
 	 * tells wb_workfn() that @wb is dying and its work_list needs to
@@ -357,6 +375,12 @@
 	mod_delayed_work(bdi_wq, &wb->dwork, 0);
 	flush_delayed_work(&wb->dwork);
 	WARN_ON(!list_empty(&wb->work_list));
+	/*
+	 * Make sure bit gets cleared after shutdown is finished. Matches with
+	 * the barrier provided by test_and_clear_bit() above.
+	 */
+	smp_wmb();
+	clear_bit(WB_shutting_down, &wb->state);
 }
 
 static void wb_exit(struct bdi_writeback *wb)
@@ -370,6 +394,8 @@
 
 	fprop_local_destroy_percpu(&wb->completions);
 	wb_congested_put(wb->congested);
+	if (wb != &wb->bdi->wb)
+		bdi_put(wb->bdi);
 }
 
 #ifdef CONFIG_CGROUP_WRITEBACK
@@ -379,11 +405,9 @@
 /*
  * cgwb_lock protects bdi->cgwb_tree, bdi->cgwb_congested_tree,
  * blkcg->cgwb_list, and memcg->cgwb_list.  bdi->cgwb_tree is also RCU
- * protected.  cgwb_release_wait is used to wait for the completion of cgwb
- * releases from bdi destruction path.
+ * protected.
  */
 static DEFINE_SPINLOCK(cgwb_lock);
-static DECLARE_WAIT_QUEUE_HEAD(cgwb_release_wait);
 
 /**
  * wb_congested_get_create - get or create a wb_congested
@@ -436,7 +460,7 @@
 		return NULL;
 
 	atomic_set(&new_congested->refcnt, 0);
-	new_congested->bdi = bdi;
+	new_congested->__bdi = bdi;
 	new_congested->blkcg_id = blkcg_id;
 	goto retry;
 
@@ -464,10 +488,10 @@
 	}
 
 	/* bdi might already have been destroyed leaving @congested unlinked */
-	if (congested->bdi) {
+	if (congested->__bdi) {
 		rb_erase(&congested->rb_node,
-			 &congested->bdi->cgwb_congested_tree);
-		congested->bdi = NULL;
+			 &congested->__bdi->cgwb_congested_tree);
+		congested->__bdi = NULL;
 	}
 
 	spin_unlock_irqrestore(&cgwb_lock, flags);
@@ -478,11 +502,6 @@
 {
 	struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
 						release_work);
-	struct backing_dev_info *bdi = wb->bdi;
-
-	spin_lock_irq(&cgwb_lock);
-	list_del_rcu(&wb->bdi_node);
-	spin_unlock_irq(&cgwb_lock);
 
 	wb_shutdown(wb);
 
@@ -493,9 +512,6 @@
 	percpu_ref_exit(&wb->refcnt);
 	wb_exit(wb);
 	kfree_rcu(wb, rcu);
-
-	if (atomic_dec_and_test(&bdi->usage_cnt))
-		wake_up_all(&cgwb_release_wait);
 }
 
 static void cgwb_release(struct percpu_ref *refcnt)
@@ -515,6 +531,13 @@
 	percpu_ref_kill(&wb->refcnt);
 }
 
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+	spin_lock_irq(&cgwb_lock);
+	list_del_rcu(&wb->bdi_node);
+	spin_unlock_irq(&cgwb_lock);
+}
+
 static int cgwb_create(struct backing_dev_info *bdi,
 		       struct cgroup_subsys_state *memcg_css, gfp_t gfp)
 {
@@ -578,7 +601,6 @@
 		/* we might have raced another instance of this function */
 		ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb);
 		if (!ret) {
-			atomic_inc(&bdi->usage_cnt);
 			list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
 			list_add(&wb->memcg_node, memcg_cgwb_list);
 			list_add(&wb->blkcg_node, blkcg_cgwb_list);
@@ -668,7 +690,6 @@
 
 	INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
 	bdi->cgwb_congested_tree = RB_ROOT;
-	atomic_set(&bdi->usage_cnt, 1);
 
 	ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
 	if (!ret) {
@@ -678,36 +699,26 @@
 	return ret;
 }
 
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
 {
 	struct radix_tree_iter iter;
-	struct rb_node *rbn;
 	void **slot;
+	struct bdi_writeback *wb;
 
 	WARN_ON(test_bit(WB_registered, &bdi->wb.state));
 
 	spin_lock_irq(&cgwb_lock);
-
 	radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
 		cgwb_kill(*slot);
 
-	while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
-		struct bdi_writeback_congested *congested =
-			rb_entry(rbn, struct bdi_writeback_congested, rb_node);
-
-		rb_erase(rbn, &bdi->cgwb_congested_tree);
-		congested->bdi = NULL;	/* mark @congested unlinked */
+	while (!list_empty(&bdi->wb_list)) {
+		wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
+				      bdi_node);
+		spin_unlock_irq(&cgwb_lock);
+		wb_shutdown(wb);
+		spin_lock_irq(&cgwb_lock);
 	}
-
 	spin_unlock_irq(&cgwb_lock);
-
-	/*
-	 * All cgwb's and their congested states must be shutdown and
-	 * released before returning.  Drain the usage counter to wait for
-	 * all cgwb's and cgwb_congested's ever created on @bdi.
-	 */
-	atomic_dec(&bdi->usage_cnt);
-	wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt));
 }
 
 /**
@@ -747,6 +758,28 @@
 	spin_unlock_irq(&cgwb_lock);
 }
 
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
+{
+	struct rb_node *rbn;
+
+	spin_lock_irq(&cgwb_lock);
+	while ((rbn = rb_first(&bdi->cgwb_congested_tree))) {
+		struct bdi_writeback_congested *congested =
+			rb_entry(rbn, struct bdi_writeback_congested, rb_node);
+
+		rb_erase(rbn, &bdi->cgwb_congested_tree);
+		congested->__bdi = NULL;	/* mark @congested unlinked */
+	}
+	spin_unlock_irq(&cgwb_lock);
+}
+
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+	spin_lock_irq(&cgwb_lock);
+	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+	spin_unlock_irq(&cgwb_lock);
+}
+
 #else	/* CONFIG_CGROUP_WRITEBACK */
 
 static int cgwb_bdi_init(struct backing_dev_info *bdi)
@@ -767,11 +800,23 @@
 	return 0;
 }
 
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+static void cgwb_bdi_unregister(struct backing_dev_info *bdi) { }
+
+static void cgwb_bdi_exit(struct backing_dev_info *bdi)
 {
 	wb_congested_put(bdi->wb_congested);
 }
 
+static void cgwb_bdi_register(struct backing_dev_info *bdi)
+{
+	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
+}
+
+static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
+{
+	list_del_rcu(&wb->bdi_node);
+}
+
 #endif	/* CONFIG_CGROUP_WRITEBACK */
 
 int bdi_init(struct backing_dev_info *bdi)
@@ -780,6 +825,7 @@
 
 	bdi->dev = NULL;
 
+	kref_init(&bdi->refcnt);
 	bdi->min_ratio = 0;
 	bdi->max_ratio = 100;
 	bdi->max_prop_frac = FPROP_FRAC_BASE;
@@ -789,12 +835,26 @@
 
 	ret = cgwb_bdi_init(bdi);
 
-	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list);
-
 	return ret;
 }
 EXPORT_SYMBOL(bdi_init);
 
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
+{
+	struct backing_dev_info *bdi;
+
+	bdi = kmalloc_node(sizeof(struct backing_dev_info),
+			   gfp_mask | __GFP_ZERO, node_id);
+	if (!bdi)
+		return NULL;
+
+	if (bdi_init(bdi)) {
+		kfree(bdi);
+		return NULL;
+	}
+	return bdi;
+}
+
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
 		const char *fmt, ...)
 {
@@ -810,6 +870,7 @@
 	if (IS_ERR(dev))
 		return PTR_ERR(dev);
 
+	cgwb_bdi_register(bdi);
 	bdi->dev = dev;
 
 	bdi_debug_register(bdi, dev_name(dev));
@@ -838,6 +899,8 @@
 			MINOR(owner->devt));
 	if (rc)
 		return rc;
+	/* Leaking owner reference... */
+	WARN_ON(bdi->owner);
 	bdi->owner = owner;
 	get_device(owner);
 	return 0;
@@ -861,7 +924,7 @@
 	/* make sure nobody finds us on the bdi_list anymore */
 	bdi_remove_from_list(bdi);
 	wb_shutdown(&bdi->wb);
-	cgwb_bdi_destroy(bdi);
+	cgwb_bdi_unregister(bdi);
 
 	if (bdi->dev) {
 		bdi_debug_unregister(bdi);
@@ -875,10 +938,25 @@
 	}
 }
 
-void bdi_exit(struct backing_dev_info *bdi)
+static void bdi_exit(struct backing_dev_info *bdi)
 {
 	WARN_ON_ONCE(bdi->dev);
 	wb_exit(&bdi->wb);
+	cgwb_bdi_exit(bdi);
+}
+
+static void release_bdi(struct kref *ref)
+{
+	struct backing_dev_info *bdi =
+			container_of(ref, struct backing_dev_info, refcnt);
+
+	bdi_exit(bdi);
+	kfree(bdi);
+}
+
+void bdi_put(struct backing_dev_info *bdi)
+{
+	kref_put(&bdi->refcnt, release_bdi);
 }
 
 void bdi_destroy(struct backing_dev_info *bdi)
diff --git a/mm/cma.c b/mm/cma.c
index 2984dac..5fc1809 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -61,7 +61,7 @@
 }
 
 static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
-					     int align_order)
+					     unsigned int align_order)
 {
 	if (align_order <= cma->order_per_bit)
 		return 0;
@@ -69,17 +69,14 @@
 }
 
 /*
- * Find a PFN aligned to the specified order and return an offset represented in
- * order_per_bits.
+ * Find the offset of the base PFN from the specified align_order.
+ * The value returned is represented in order_per_bits.
  */
 static unsigned long cma_bitmap_aligned_offset(const struct cma *cma,
-					       int align_order)
+					       unsigned int align_order)
 {
-	if (align_order <= cma->order_per_bit)
-		return 0;
-
-	return (ALIGN(cma->base_pfn, (1UL << align_order))
-		- cma->base_pfn) >> cma->order_per_bit;
+	return (cma->base_pfn & ((1UL << align_order) - 1))
+		>> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_pages_to_bits(const struct cma *cma,
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 9a20a55..9b59170 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1454,6 +1454,8 @@
 			if (page_count(page) == 0)
 				continue;
 			scan_block(page, page + 1, NULL);
+			if (!(pfn % (MAX_SCAN_SIZE / sizeof(*page))))
+				cond_resched();
 		}
 	}
 	put_online_mems();
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 37d63b2..34eec18 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5560,7 +5560,7 @@
 		next = page->lru.next;
 
 		VM_BUG_ON_PAGE(PageLRU(page), page);
-		VM_BUG_ON_PAGE(page_count(page), page);
+		VM_BUG_ON_PAGE(!PageHWPoison(page) && page_count(page), page);
 
 		if (!page->mem_cgroup)
 			continue;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index b335423..43622c6 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -535,6 +535,13 @@
 		 */
 		ClearPageActive(p);
 		ClearPageUnevictable(p);
+
+		/*
+		 * Poisoned page might never drop its ref count to 0 so we have
+		 * to uncharge it manually from its memcg.
+		 */
+		mem_cgroup_uncharge(p);
+
 		/*
 		 * drop the page count elevated by isolate_lru_page()
 		 */
diff --git a/mm/mmap.c b/mm/mmap.c
index 621db7f..5df92da 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2250,7 +2250,8 @@
 		gap_addr = TASK_SIZE;
 
 	next = vma->vm_next;
-	if (next && next->vm_start < gap_addr) {
+	if (next && next->vm_start < gap_addr &&
+			(next->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
 		if (!(next->vm_flags & VM_GROWSUP))
 			return -ENOMEM;
 		/* Check that both stack segments have the same anon_vma? */
@@ -2334,7 +2335,8 @@
 	if (gap_addr > address)
 		return -ENOMEM;
 	prev = vma->vm_prev;
-	if (prev && prev->vm_end > gap_addr) {
+	if (prev && prev->vm_end > gap_addr &&
+			(prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
 		if (!(prev->vm_flags & VM_GROWSDOWN))
 			return -ENOMEM;
 		/* Check that both stack segments have the same anon_vma? */
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index dd7817cd3..e6fbdf4 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1987,11 +1987,11 @@
 	 * We want to write everything out, not just down to the dirty
 	 * threshold
 	 */
-	if (!bdi_has_dirty_io(&q->backing_dev_info))
+	if (!bdi_has_dirty_io(q->backing_dev_info))
 		return;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node)
+	list_for_each_entry_rcu(wb, &q->backing_dev_info->wb_list, bdi_node)
 		if (wb_has_dirty_io(wb))
 			wb_start_writeback(wb, nr_pages, true,
 					   WB_REASON_LAPTOP_TIMER);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 63b19a3..d3ea11f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -254,9 +254,21 @@
 #endif
 };
 
+/*
+ * Try to keep at least this much lowmem free.  Do not allow normal
+ * allocations below this point, only high priority ones. Automatically
+ * tuned according to the amount of memory in the system.
+ */
 int min_free_kbytes = 1024;
 int user_min_free_kbytes = -1;
-int watermark_scale_factor = 10;
+int watermark_scale_factor;
+
+/*
+ * Extra memory for the system to try freeing. Used to temporarily
+ * free memory, to make space for new workloads. Anyone can allocate
+ * down to the min watermarks controlled by min_free_kbytes above.
+ */
+int extra_free_kbytes;
 
 static unsigned long __meminitdata nr_kernel_pages;
 static unsigned long __meminitdata nr_all_pages;
@@ -2887,9 +2899,6 @@
 		if (!area->nr_free)
 			continue;
 
-		if (alloc_harder)
-			return true;
-
 		for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
 #ifdef CONFIG_CMA
 			/*
@@ -2909,6 +2918,9 @@
 			return true;
 		}
 #endif
+		if (alloc_harder &&
+			!list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
+			return true;
 	}
 	return false;
 }
@@ -3276,6 +3288,46 @@
 	return NULL;
 }
 
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	/* Let costly order requests check for compaction progress */
+	if (order > PAGE_ALLOC_COSTLY_ORDER)
+		return false;
+
+	/*
+	 * For (0 < order < PAGE_ALLOC_COSTLY_ORDER) allow the shrinkers
+	 * to run and free up memory. Do not let these allocations fail
+	 * if shrinkers can free up memory. This is similar to
+	 * should_compact_retry implementation for !CONFIG_COMPACTION.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
+				ac->high_zoneidx, ac->nodemask) {
+		unsigned long available;
+
+		available = zone_reclaimable_pages(zone);
+		available +=
+			zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+		if (__zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+			ac_classzone_idx(ac), alloc_flags, available))
+			return true;
+	}
+
+	return false;
+}
+#else
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	return false;
+}
+#endif
+
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 		     enum compact_result compact_result,
@@ -3288,6 +3340,9 @@
 	if (!order)
 		return false;
 
+	if (should_compact_lmk_retry(ac, order, alloc_flags))
+		return true;
+
 	if (compaction_made_progress(compact_result))
 		(*compaction_retries)++;
 
@@ -3525,7 +3580,8 @@
 	 * their order will become available due to high fragmentation so
 	 * always increment the no progress counter for them
 	 */
-	if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+	if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		*no_progress_loops = 0;
 	else
 		(*no_progress_loops)++;
@@ -3803,7 +3859,8 @@
 	 * implementation of the compaction depends on the sufficient amount
 	 * of free memory (see __compaction_suitable)
 	 */
-	if (did_some_progress > 0 &&
+	if ((did_some_progress > 0 ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER)) &&
 			should_compact_retry(ac, order, alloc_flags,
 				compact_result, &compact_priority,
 				&compaction_retries))
@@ -6742,6 +6799,7 @@
 static void __setup_per_zone_wmarks(void)
 {
 	unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
+	unsigned long pages_low = extra_free_kbytes >> (PAGE_SHIFT - 10);
 	unsigned long lowmem_pages = 0;
 	struct zone *zone;
 	unsigned long flags;
@@ -6753,11 +6811,14 @@
 	}
 
 	for_each_zone(zone) {
-		u64 tmp;
+		u64 min, low;
 
 		spin_lock_irqsave(&zone->lock, flags);
-		tmp = (u64)pages_min * zone->managed_pages;
-		do_div(tmp, lowmem_pages);
+		min = (u64)pages_min * zone->managed_pages;
+		do_div(min, lowmem_pages);
+		low = (u64)pages_low * zone->managed_pages;
+		do_div(low, vm_total_pages);
+
 		if (is_highmem(zone)) {
 			/*
 			 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
@@ -6778,7 +6839,7 @@
 			 * If it's a lowmem zone, reserve a number of pages
 			 * proportionate to the zone's size.
 			 */
-			zone->watermark[WMARK_MIN] = tmp;
+			zone->watermark[WMARK_MIN] = min;
 		}
 
 		/*
@@ -6786,12 +6847,13 @@
 		 * scale factor in proportion to available memory, but
 		 * ensure a minimum size on small systems.
 		 */
-		tmp = max_t(u64, tmp >> 2,
+		min = max_t(u64, min >> 2,
 			    mult_frac(zone->managed_pages,
 				      watermark_scale_factor, 10000));
 
-		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + tmp;
-		zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;
+		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + low + min;
+		zone->watermark[WMARK_HIGH] =
+					min_wmark_pages(zone) + low + min * 2;
 
 		spin_unlock_irqrestore(&zone->lock, flags);
 	}
@@ -6872,7 +6934,7 @@
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
  *	that we can call two helper functions whenever min_free_kbytes
- *	changes.
+ *	or extra_free_kbytes changes.
  */
 int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
 	void __user *buffer, size_t *length, loff_t *ppos)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index bb18b47..2740973 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -212,7 +212,8 @@
 
 	nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
 		zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
-	if (get_nr_swap_pages() > 0)
+	if (get_nr_swap_pages() > 0
+			|| IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
 			zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
 
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 5488e4a..ac1552d 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -722,13 +722,12 @@
 	if (unlikely(!net_eq(dev_net(dev), &init_net)))
 		goto drop;
 
-	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-		      skb->len != CAN_MTU ||
-		      cfd->len > CAN_MAX_DLEN,
-		      "PF_CAN: dropped non conform CAN skbuf: "
-		      "dev type %d, len %d, datalen %d\n",
-		      dev->type, skb->len, cfd->len))
+	if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU ||
+		     cfd->len > CAN_MAX_DLEN)) {
+		pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n",
+			     dev->type, skb->len, cfd->len);
 		goto drop;
+	}
 
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
@@ -746,13 +745,12 @@
 	if (unlikely(!net_eq(dev_net(dev), &init_net)))
 		goto drop;
 
-	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-		      skb->len != CANFD_MTU ||
-		      cfd->len > CANFD_MAX_DLEN,
-		      "PF_CAN: dropped non conform CAN FD skbuf: "
-		      "dev type %d, len %d, datalen %d\n",
-		      dev->type, skb->len, cfd->len))
+	if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU ||
+		     cfd->len > CANFD_MAX_DLEN)) {
+		pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n",
+			     dev->type, skb->len, cfd->len);
 		goto drop;
+	}
 
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
diff --git a/net/core/dev.c b/net/core/dev.c
index e0217f8..ca40d8e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3139,10 +3139,21 @@
 		hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
 
 		/* + transport layer */
-		if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
-			hdr_len += tcp_hdrlen(skb);
-		else
-			hdr_len += sizeof(struct udphdr);
+		if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+			const struct tcphdr *th;
+			struct tcphdr _tcphdr;
+
+			th = skb_header_pointer(skb, skb_transport_offset(skb),
+						sizeof(_tcphdr), &_tcphdr);
+			if (likely(th))
+				hdr_len += __tcp_hdrlen(th);
+		} else {
+			struct udphdr _udphdr;
+
+			if (skb_header_pointer(skb, skb_transport_offset(skb),
+					       sizeof(_udphdr), &_udphdr))
+				hdr_len += sizeof(struct udphdr);
+		}
 
 		if (shinfo->gso_type & SKB_GSO_DODGY)
 			gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
diff --git a/net/core/filter.c b/net/core/filter.c
index 5e42e0e..c385c55 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -451,6 +451,10 @@
 			    convert_bpf_extensions(fp, &insn))
 				break;
 
+			if (fp->code == (BPF_ALU | BPF_DIV | BPF_X) ||
+			    fp->code == (BPF_ALU | BPF_MOD | BPF_X))
+				*insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X);
+
 			*insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k);
 			break;
 
@@ -1015,11 +1019,9 @@
 		 */
 		goto out_err_free;
 
-	/* We are guaranteed to never error here with cBPF to eBPF
-	 * transitions, since there's no issue with type compatibility
-	 * checks on program arrays.
-	 */
 	fp = bpf_prog_select_runtime(fp, &err);
+	if (err)
+		goto out_err_free;
 
 	kfree(old_prog);
 	return fp;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 32e4e01..862d63e 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -550,8 +550,8 @@
 out_good:
 	ret = true;
 
-	key_control->thoff = (u16)nhoff;
 out:
+	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
 	key_basic->n_proto = proto;
 	key_basic->ip_proto = ip_proto;
 
@@ -559,7 +559,6 @@
 
 out_bad:
 	ret = false;
-	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
 	goto out;
 }
 EXPORT_SYMBOL(__skb_flow_dissect);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index b91cecc..7d07d6b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -497,7 +497,7 @@
 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
 
-	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
+	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
 
 	if (n->parms->dead) {
 		rc = ERR_PTR(-EINVAL);
@@ -509,7 +509,7 @@
 	     n1 != NULL;
 	     n1 = rcu_dereference_protected(n1->next,
 			lockdep_is_held(&tbl->lock))) {
-		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
+		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
 			if (want_ref)
 				neigh_hold(n1);
 			rc = n1;
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index 77f396b..5dce429 100644
--- a/net/core/sock_reuseport.c
+++ b/net/core/sock_reuseport.c
@@ -93,6 +93,16 @@
 	return more_reuse;
 }
 
+static void reuseport_free_rcu(struct rcu_head *head)
+{
+	struct sock_reuseport *reuse;
+
+	reuse = container_of(head, struct sock_reuseport, rcu);
+	if (reuse->prog)
+		bpf_prog_destroy(reuse->prog);
+	kfree(reuse);
+}
+
 /**
  *  reuseport_add_sock - Add a socket to the reuseport group of another.
  *  @sk:  New socket to add to the group.
@@ -101,7 +111,7 @@
  */
 int reuseport_add_sock(struct sock *sk, struct sock *sk2)
 {
-	struct sock_reuseport *reuse;
+	struct sock_reuseport *old_reuse, *reuse;
 
 	if (!rcu_access_pointer(sk2->sk_reuseport_cb)) {
 		int err = reuseport_alloc(sk2);
@@ -112,10 +122,13 @@
 
 	spin_lock_bh(&reuseport_lock);
 	reuse = rcu_dereference_protected(sk2->sk_reuseport_cb,
-					  lockdep_is_held(&reuseport_lock)),
-	WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb,
-					    lockdep_is_held(&reuseport_lock)),
-		  "socket already in reuseport group");
+					  lockdep_is_held(&reuseport_lock));
+	old_reuse = rcu_dereference_protected(sk->sk_reuseport_cb,
+					     lockdep_is_held(&reuseport_lock));
+	if (old_reuse && old_reuse->num_socks != 1) {
+		spin_unlock_bh(&reuseport_lock);
+		return -EBUSY;
+	}
 
 	if (reuse->num_socks == reuse->max_socks) {
 		reuse = reuseport_grow(reuse);
@@ -133,19 +146,11 @@
 
 	spin_unlock_bh(&reuseport_lock);
 
+	if (old_reuse)
+		call_rcu(&old_reuse->rcu, reuseport_free_rcu);
 	return 0;
 }
 
-static void reuseport_free_rcu(struct rcu_head *head)
-{
-	struct sock_reuseport *reuse;
-
-	reuse = container_of(head, struct sock_reuseport, rcu);
-	if (reuse->prog)
-		bpf_prog_destroy(reuse->prog);
-	kfree(reuse);
-}
-
 void reuseport_detach_sock(struct sock *sk)
 {
 	struct sock_reuseport *reuse;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index a7f05f0..1b46190 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -292,7 +292,13 @@
 		.data		= &bpf_jit_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 		.proc_handler	= proc_dointvec
+#else
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &one,
+		.extra2		= &one,
+#endif
 	},
 # ifdef CONFIG_HAVE_EBPF_JIT
 	{
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 5e3a730..7753681 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -140,6 +140,9 @@
 
 	ccid2_pr_debug("RTO_EXPIRE\n");
 
+	if (sk->sk_state == DCCP_CLOSED)
+		goto out;
+
 	/* back-off timer */
 	hc->tx_rto <<= 1;
 	if (hc->tx_rto > DCCP_RTO_MAX)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b68168f..9d43c1f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -259,6 +259,7 @@
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct inet_sock *inet = inet_sk(sk);
+	struct dccp_sock *dp = dccp_sk(sk);
 	int err = 0;
 	const int old_state = sk->sk_state;
 
@@ -278,6 +279,10 @@
 		sk->sk_err = ECONNRESET;
 
 	dccp_clear_xmit_timers(sk);
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = NULL;
+	dp->dccps_hc_tx_ccid = NULL;
 
 	__skb_queue_purge(&sk->sk_receive_queue);
 	__skb_queue_purge(&sk->sk_write_queue);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 51b27ae..e60517e 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -223,11 +223,16 @@
 
 static int arp_constructor(struct neighbour *neigh)
 {
-	__be32 addr = *(__be32 *)neigh->primary_key;
+	__be32 addr;
 	struct net_device *dev = neigh->dev;
 	struct in_device *in_dev;
 	struct neigh_parms *parms;
+	u32 inaddr_any = INADDR_ANY;
 
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len);
+
+	addr = *(__be32 *)neigh->primary_key;
 	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(dev);
 	if (!in_dev) {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 7bff0c6..7f5fe07 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -332,7 +332,7 @@
 		return htonl(INADDR_ANY);
 
 	for_ifa(in_dev) {
-		if (inet_ifa_match(fl4->saddr, ifa))
+		if (fl4->saddr == ifa->ifa_local)
 			return fl4->saddr;
 	} endfor_ifa(in_dev);
 
@@ -386,7 +386,11 @@
 	pip->frag_off = htons(IP_DF);
 	pip->ttl      = 1;
 	pip->daddr    = fl4.daddr;
+
+	rcu_read_lock();
 	pip->saddr    = igmpv3_get_srcaddr(dev, &fl4);
+	rcu_read_unlock();
+
 	pip->protocol = IPPROTO_IGMP;
 	pip->tot_len  = 0;	/* filled in later */
 	ip_select_ident(net, skb, NULL);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index bf071f3..6ba9bdc 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2224,6 +2224,9 @@
 			tcp_send_active_reset(sk, GFP_ATOMIC);
 			__NET_INC_STATS(sock_net(sk),
 					LINUX_MIB_TCPABORTONMEMORY);
+		} else if (!check_net(sock_net(sk))) {
+			/* Not possible to send reset; just close */
+			tcp_set_state(sk, TCP_CLOSE);
 		}
 	}
 
@@ -2322,6 +2325,12 @@
 
 	WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
 
+	if (sk->sk_frag.page) {
+		put_page(sk->sk_frag.page);
+		sk->sk_frag.page = NULL;
+		sk->sk_frag.offset = 0;
+	}
+
 	sk->sk_error_report(sk);
 	return err;
 }
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index e86a34f..8ec6053 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -452,7 +452,8 @@
 
 	bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1);
 	bbr->cycle_mstamp = tp->delivered_mstamp;
-	bbr->pacing_gain = bbr_pacing_gain[bbr->cycle_idx];
+	bbr->pacing_gain = bbr->lt_use_bw ? BBR_UNIT :
+					    bbr_pacing_gain[bbr->cycle_idx];
 }
 
 /* Gain cycling: cycle pacing gain to converge to fair share of available bw. */
@@ -461,8 +462,7 @@
 {
 	struct bbr *bbr = inet_csk_ca(sk);
 
-	if ((bbr->mode == BBR_PROBE_BW) && !bbr->lt_use_bw &&
-	    bbr_is_next_cycle_phase(sk, rs))
+	if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs))
 		bbr_advance_cycle_phase(sk);
 }
 
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index bc68da3..366b1be 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -32,6 +32,9 @@
 static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
 					netdev_features_t features)
 {
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4))
+		return ERR_PTR(-EINVAL);
+
 	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
 		return ERR_PTR(-EINVAL);
 
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index d3d3ef6..4be66e4 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -82,11 +82,19 @@
  *  to prevent DoS attacks. It is called when a retransmission timeout
  *  or zero probe timeout occurs on orphaned socket.
  *
+ *  Also close if our net namespace is exiting; in that case there is no
+ *  hope of ever communicating again since all netns interfaces are already
+ *  down (or about to be down), and we need to release our dst references,
+ *  which have been moved to the netns loopback interface, so the namespace
+ *  can finish exiting.  This condition is only possible if we are a kernel
+ *  socket, as those do not hold references to the namespace.
+ *
  *  Criteria is still not confirmed experimentally and may change.
  *  We kill the socket, if:
  *  1. If number of orphaned sockets exceeds an administratively configured
  *     limit.
  *  2. If we have strong memory pressure.
+ *  3. If our net namespace is exiting.
  */
 static int tcp_out_of_resources(struct sock *sk, bool do_reset)
 {
@@ -115,6 +123,13 @@
 		__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY);
 		return 1;
 	}
+
+	if (!check_net(sock_net(sk))) {
+		/* Not possible to send reset; just close */
+		tcp_done(sk);
+		return 1;
+	}
+
 	return 0;
 }
 
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 6401574..f4f616e 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -205,6 +205,9 @@
 		goto out;
 	}
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP))
+		goto out;
+
 	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 		goto out;
 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 140d05f..a5c1ff3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -240,6 +240,7 @@
 	.use_oif_addrs_only	= 0,
 	.ignore_routes_with_linkdown = 0,
 	.keep_addr_on_down	= 0,
+	.accept_ra_prefix_route = 1,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -288,6 +289,7 @@
 	.use_oif_addrs_only	= 0,
 	.ignore_routes_with_linkdown = 0,
 	.keep_addr_on_down	= 0,
+	.accept_ra_prefix_route = 1,
 };
 
 /* Check if link is ready: is it up and is a valid qdisc available */
@@ -2607,8 +2609,11 @@
 				flags |= RTF_EXPIRES;
 				expires = jiffies_to_clock_t(rt_expires);
 			}
-			addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
-					      dev, expires, flags);
+			if (dev->ip6_ptr->cnf.accept_ra_prefix_route) {
+				addrconf_prefix_route(&pinfo->prefix,
+						      pinfo->prefix_len,
+						      dev, expires, flags);
+			}
 		}
 		ip6_rt_put(rt);
 	}
@@ -6125,6 +6130,13 @@
 
 	},
 	{
+		.procname	= "accept_ra_prefix_route",
+		.data		= &ipv6_devconf.accept_ra_prefix_route,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+	{
 		/* sentinel */
 	}
 };
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 55a8f68..1111684 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -290,6 +290,7 @@
 	struct net *net = sock_net(sk);
 	__be32 v4addr = 0;
 	unsigned short snum;
+	bool saved_ipv6only;
 	int addr_type = 0;
 	int err = 0;
 
@@ -394,19 +395,21 @@
 	if (!(addr_type & IPV6_ADDR_MULTICAST))
 		np->saddr = addr->sin6_addr;
 
+	saved_ipv6only = sk->sk_ipv6only;
+	if (addr_type != IPV6_ADDR_ANY && addr_type != IPV6_ADDR_MAPPED)
+		sk->sk_ipv6only = 1;
+
 	/* Make sure we are allowed to bind here. */
 	if ((snum || !inet->bind_address_no_port) &&
 	    sk->sk_prot->get_port(sk, snum)) {
+		sk->sk_ipv6only = saved_ipv6only;
 		inet_reset_saddr(sk);
 		err = -EADDRINUSE;
 		goto out;
 	}
 
-	if (addr_type != IPV6_ADDR_ANY) {
+	if (addr_type != IPV6_ADDR_ANY)
 		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
-		if (addr_type != IPV6_ADDR_MAPPED)
-			sk->sk_ipv6only = 1;
-	}
 	if (snum)
 		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
 	inet->inet_sport = htons(inet->inet_num);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index a7d0c01..21bd54f 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -337,11 +337,12 @@
 
 	nt->dev = dev;
 	nt->net = dev_net(dev);
-	ip6gre_tnl_link_config(nt, 1);
 
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
 
+	ip6gre_tnl_link_config(nt, 1);
+
 	/* Can use a lockless transmit, unless we generate output sequences */
 	if (!(nt->parms.o_flags & TUNNEL_SEQ))
 		dev->features |= NETIF_F_LLTX;
@@ -1267,7 +1268,6 @@
 
 static int ip6gre_tap_init(struct net_device *dev)
 {
-	struct ip6_tnl *tunnel;
 	int ret;
 
 	ret = ip6gre_tunnel_init_common(dev);
@@ -1276,10 +1276,6 @@
 
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
-	tunnel = netdev_priv(dev);
-
-	ip6gre_tnl_link_config(tunnel, 1);
-
 	return 0;
 }
 
@@ -1374,7 +1370,6 @@
 
 	nt->dev = dev;
 	nt->net = dev_net(dev);
-	ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
 
 	dev->features		|= GRE6_FEATURES;
 	dev->hw_features	|= GRE6_FEATURES;
@@ -1400,6 +1395,11 @@
 	if (err)
 		goto out;
 
+	ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
+
+	if (tb[IFLA_MTU])
+		ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
+
 	dev_hold(dev);
 	ip6gre_tunnel_link(ign, nt);
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index dd93836..55ca65c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -165,7 +165,7 @@
 			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }
 
-static bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
+bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
 {
 	if (!np->autoflowlabel_set)
 		return ip6_default_np_autolabel(net);
@@ -1268,14 +1268,16 @@
 	v6_cork->tclass = ipc6->tclass;
 	if (rt->dst.flags & DST_XFRM_TUNNEL)
 		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
 	else
 		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-		      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path);
 	if (np->frag_size < mtu) {
 		if (np->frag_size)
 			mtu = np->frag_size;
 	}
+	if (mtu < IPV6_MIN_MTU)
+		return -EINVAL;
 	cork->base.fragsize = mtu;
 	if (dst_allfrag(rt->dst.path))
 		cork->base.flags |= IPCORK_ALLFRAG;
@@ -1806,6 +1808,7 @@
 	cork.base.flags = 0;
 	cork.base.addr = 0;
 	cork.base.opt = NULL;
+	cork.base.dst = NULL;
 	v6_cork.opt = NULL;
 	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6);
 	if (err) {
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 117405d..a30e7e9 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -495,6 +495,7 @@
 		return ERR_PTR(-ENOENT);
 
 	it->mrt = mrt;
+	it->cache = NULL;
 	return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
 		: SEQ_START_TOKEN;
 }
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 6e3871c..bcea985 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1316,7 +1316,7 @@
 		break;
 
 	case IPV6_AUTOFLOWLABEL:
-		val = np->autoflowlabel;
+		val = ip6_autoflowlabel(sock_net(sk), np);
 		break;
 
 	default:
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 5edfe66..64ec233 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -263,6 +263,7 @@
 			 * this case. -DaveM
 			 */
 			pr_debug("end of fragment not rounded to 8 bytes.\n");
+			inet_frag_kill(&fq->q, &nf_frags);
 			return -EPROTO;
 		}
 		if (end > fq->q.len) {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f7e685f..558d566 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -393,14 +393,11 @@
 	struct net_device *loopback_dev =
 		dev_net(dev)->loopback_dev;
 
-	if (dev != loopback_dev) {
-		if (idev && idev->dev == dev) {
-			struct inet6_dev *loopback_idev =
-				in6_dev_get(loopback_dev);
-			if (loopback_idev) {
-				rt->rt6i_idev = loopback_idev;
-				in6_dev_put(idev);
-			}
+	if (idev && idev->dev != loopback_dev) {
+		struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+		if (loopback_idev) {
+			rt->rt6i_idev = loopback_idev;
+			in6_dev_put(idev);
 		}
 	}
 }
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index d883c92..278e49c 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -46,6 +46,9 @@
 {
 	struct tcphdr *th;
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
+		return ERR_PTR(-EINVAL);
+
 	if (!pskb_may_pull(skb, sizeof(*th)))
 		return ERR_PTR(-EINVAL);
 
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index e7d378c..2bd2087 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -55,6 +55,9 @@
 		const struct ipv6hdr *ipv6h;
 		struct udphdr *uh;
 
+		if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP))
+			goto out;
+
 		if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 			goto out;
 
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 94bf810..6482b00 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -401,6 +401,11 @@
 #endif
 	int len;
 
+	if (sp->sadb_address_len <
+	    DIV_ROUND_UP(sizeof(*sp) + offsetofend(typeof(*addr), sa_family),
+			 sizeof(uint64_t)))
+		return -EINVAL;
+
 	switch (addr->sa_family) {
 	case AF_INET:
 		len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t));
@@ -511,6 +516,9 @@
 		uint16_t ext_type;
 		int ext_len;
 
+		if (len < sizeof(*ehdr))
+			return -EINVAL;
+
 		ext_len  = ehdr->sadb_ext_len;
 		ext_len *= sizeof(uint64_t);
 		ext_type = ehdr->sadb_ext_type;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b747c96..fed598a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -788,7 +788,7 @@
 	struct mesh_path *mpath;
 	u8 ttl, flags, hopcount;
 	const u8 *orig_addr;
-	u32 orig_sn, metric, metric_txsta, interval;
+	u32 orig_sn, new_metric, orig_metric, last_hop_metric, interval;
 	bool root_is_gate;
 
 	ttl = rann->rann_ttl;
@@ -799,7 +799,7 @@
 	interval = le32_to_cpu(rann->rann_interval);
 	hopcount = rann->rann_hopcount;
 	hopcount++;
-	metric = le32_to_cpu(rann->rann_metric);
+	orig_metric = le32_to_cpu(rann->rann_metric);
 
 	/*  Ignore our own RANNs */
 	if (ether_addr_equal(orig_addr, sdata->vif.addr))
@@ -816,7 +816,10 @@
 		return;
 	}
 
-	metric_txsta = airtime_link_metric_get(local, sta);
+	last_hop_metric = airtime_link_metric_get(local, sta);
+	new_metric = orig_metric + last_hop_metric;
+	if (new_metric < orig_metric)
+		new_metric = MAX_METRIC;
 
 	mpath = mesh_path_lookup(sdata, orig_addr);
 	if (!mpath) {
@@ -829,7 +832,7 @@
 	}
 
 	if (!(SN_LT(mpath->sn, orig_sn)) &&
-	    !(mpath->sn == orig_sn && metric < mpath->rann_metric)) {
+	    !(mpath->sn == orig_sn && new_metric < mpath->rann_metric)) {
 		rcu_read_unlock();
 		return;
 	}
@@ -847,7 +850,7 @@
 	}
 
 	mpath->sn = orig_sn;
-	mpath->rann_metric = metric + metric_txsta;
+	mpath->rann_metric = new_metric;
 	mpath->is_root = true;
 	/* Recording RANNs sender address to send individually
 	 * addressed PREQs destined for root mesh STA */
@@ -867,7 +870,7 @@
 		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
 				       orig_sn, 0, NULL, 0, broadcast_addr,
 				       hopcount, ttl, interval,
-				       metric + metric_txsta, 0, sdata);
+				       new_metric, 0, sdata);
 	}
 
 	rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 28d0653..3f49912 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/capability.h>
 #include <net/netlink.h>
 #include <net/sock.h>
 
@@ -392,6 +393,9 @@
 	struct nfnl_cthelper *nlcth;
 	int ret = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
 		return -EINVAL;
 
@@ -595,6 +599,9 @@
 	struct nfnl_cthelper *nlcth;
 	bool tuple_set = false;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
 			.dump = nfnl_cthelper_dump_table,
@@ -661,6 +668,9 @@
 	struct nfnl_cthelper *nlcth, *n;
 	int j = 0, ret;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (tb[NFCTH_NAME])
 		helper_name = nla_data(tb[NFCTH_NAME]);
 
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c
index 2455b69..b589a62 100644
--- a/net/netfilter/xt_osf.c
+++ b/net/netfilter/xt_osf.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 
+#include <linux/capability.h>
 #include <linux/if.h>
 #include <linux/inetdevice.h>
 #include <linux/ip.h>
@@ -69,6 +70,9 @@
 	struct xt_osf_finger *kf = NULL, *sf;
 	int err = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;
 
@@ -113,6 +117,9 @@
 	struct xt_osf_finger *sf;
 	int err = -ENOENT;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;
 
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 822be06..d2141a6 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -519,13 +519,11 @@
 
 	DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
 		 full_tag);
-	spin_lock_bh(&uid_tag_data_tree_lock);
 	tr_entry = lookup_tag_ref(full_tag, &utd_entry);
 	BUG_ON(IS_ERR_OR_NULL(utd_entry));
 	if (!tr_entry)
 		tr_entry = new_tag_ref(full_tag, utd_entry);
 
-	spin_unlock_bh(&uid_tag_data_tree_lock);
 	if (utd_res)
 		*utd_res = utd_entry;
 	DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
@@ -2027,6 +2025,7 @@
 
 	/* Delete socket tags */
 	spin_lock_bh(&sock_tag_list_lock);
+	spin_lock_bh(&uid_tag_data_tree_lock);
 	node = rb_first(&sock_tag_tree);
 	while (node) {
 		st_entry = rb_entry(node, struct sock_tag, sock_node);
@@ -2056,6 +2055,7 @@
 				list_del(&st_entry->list);
 		}
 	}
+	spin_unlock_bh(&uid_tag_data_tree_lock);
 	spin_unlock_bh(&sock_tag_list_lock);
 
 	sock_tag_tree_erase(&st_to_free_tree);
@@ -2265,10 +2265,12 @@
 	full_tag = combine_atag_with_uid(acct_tag, uid_int);
 
 	spin_lock_bh(&sock_tag_list_lock);
+	spin_lock_bh(&uid_tag_data_tree_lock);
 	sock_tag_entry = get_sock_stat_nl(el_socket->sk);
 	tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
 	if (IS_ERR(tag_ref_entry)) {
 		res = PTR_ERR(tag_ref_entry);
+		spin_unlock_bh(&uid_tag_data_tree_lock);
 		spin_unlock_bh(&sock_tag_list_lock);
 		goto err_put;
 	}
@@ -2295,9 +2297,14 @@
 			pr_err("qtaguid: ctrl_tag(%s): "
 			       "socket tag alloc failed\n",
 			       input);
+			BUG_ON(tag_ref_entry->num_sock_tags <= 0);
+			tag_ref_entry->num_sock_tags--;
+			free_tag_ref_from_utd_entry(tag_ref_entry,
+						    uid_tag_data_entry);
+			spin_unlock_bh(&uid_tag_data_tree_lock);
 			spin_unlock_bh(&sock_tag_list_lock);
 			res = -ENOMEM;
-			goto err_tag_unref_put;
+			goto err_put;
 		}
 		/*
 		 * Hold the sk refcount here to make sure the sk pointer cannot
@@ -2307,7 +2314,6 @@
 		sock_tag_entry->sk = el_socket->sk;
 		sock_tag_entry->pid = current->tgid;
 		sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int);
-		spin_lock_bh(&uid_tag_data_tree_lock);
 		pqd_entry = proc_qtu_data_tree_search(
 			&proc_qtu_data_tree, current->tgid);
 		/*
@@ -2325,11 +2331,11 @@
 		else
 			list_add(&sock_tag_entry->list,
 				 &pqd_entry->sock_tag_list);
-		spin_unlock_bh(&uid_tag_data_tree_lock);
 
 		sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
 		atomic64_inc(&qtu_events.sockets_tagged);
 	}
+	spin_unlock_bh(&uid_tag_data_tree_lock);
 	spin_unlock_bh(&sock_tag_list_lock);
 	/* We keep the ref to the sk until it is untagged */
 	CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n",
@@ -2338,10 +2344,6 @@
 	sockfd_put(el_socket);
 	return 0;
 
-err_tag_unref_put:
-	BUG_ON(tag_ref_entry->num_sock_tags <= 0);
-	tag_ref_entry->num_sock_tags--;
-	free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry);
 err_put:
 	CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n",
 		 input, atomic_read(&el_socket->sk->sk_refcnt) - 1);
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index ec87467..313a6dd 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -161,10 +161,13 @@
 #endif
 
 	if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
-		struct udphdr _hdr, *hp;
+		struct udphdr *hp;
+		struct tcphdr _hdr;
 
 		hp = skb_header_pointer(skb, ip_hdrlen(skb),
-					sizeof(_hdr), &_hdr);
+					iph->protocol == IPPROTO_UDP ?
+					sizeof(*hp) : sizeof(_hdr),
+					&_hdr);
 		if (hp == NULL)
 			return NULL;
 
@@ -370,9 +373,11 @@
 	}
 
 	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
-		struct udphdr _hdr, *hp;
+		struct udphdr *hp;
+		struct tcphdr _hdr;
 
-		hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+		hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+					sizeof(*hp) : sizeof(_hdr), &_hdr);
 		if (hp == NULL)
 			return NULL;
 
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 0792541..1668916 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -1789,14 +1789,11 @@
 
 #define MAX_ACTIONS_BUFSIZE	(32 * 1024)
 
-static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log)
+static struct sw_flow_actions *nla_alloc_flow_actions(int size)
 {
 	struct sw_flow_actions *sfa;
 
-	if (size > MAX_ACTIONS_BUFSIZE) {
-		OVS_NLERR(log, "Flow action size %u bytes exceeds max", size);
-		return ERR_PTR(-EINVAL);
-	}
+	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);
 
 	sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
 	if (!sfa)
@@ -1869,12 +1866,15 @@
 	new_acts_size = ksize(*sfa) * 2;
 
 	if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
-		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
+		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) {
+			OVS_NLERR(log, "Flow action size exceeds max %u",
+				  MAX_ACTIONS_BUFSIZE);
 			return ERR_PTR(-EMSGSIZE);
+		}
 		new_acts_size = MAX_ACTIONS_BUFSIZE;
 	}
 
-	acts = nla_alloc_flow_actions(new_acts_size, log);
+	acts = nla_alloc_flow_actions(new_acts_size);
 	if (IS_ERR(acts))
 		return (void *)acts;
 
@@ -2500,7 +2500,7 @@
 {
 	int err;
 
-	*sfa = nla_alloc_flow_actions(nla_len(attr), log);
+	*sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
 	if (IS_ERR(*sfa))
 		return PTR_ERR(*sfa);
 
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 8faf7a7..98b2511 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -356,6 +356,7 @@
 			napi = get_current_napi_context();
 
 			skb_size = skb->len;
+			skb_get_hash(skb);
 			gro_res = napi_gro_receive(napi, skb);
 			trace_rmnet_gro_downlink(gro_res);
 			rmnet_optional_gro_flush(napi, ep, skb_size);
@@ -453,6 +454,13 @@
 	}
 
 	ep = &config->muxed_ep[mux_id];
+	if (!ep->refcount) {
+		LOGD("Packet on %s:%d; has no logical endpoint config",
+		     skb->dev->name, mux_id);
+
+		rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP);
+		return RX_HANDLER_CONSUMED;
+	}
 
 	skb->dev = ep->egress_dev;
 
diff --git a/net/rmnet_data/rmnet_data_stats.h b/net/rmnet_data/rmnet_data_stats.h
index 366e486..75ed434 100644
--- a/net/rmnet_data/rmnet_data_stats.h
+++ b/net/rmnet_data/rmnet_data_stats.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@
 	RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0,
 	RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM,
 	RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED,
+	RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP,
 	RMNET_STATS_SKBFREE_MAX
 };
 
diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c
index cc377bb..771a6b7 100644
--- a/net/rmnet_data/rmnet_map_data.c
+++ b/net/rmnet_data/rmnet_map_data.c
@@ -292,7 +292,7 @@
 		config->agg_count = 1;
 		getnstimeofday(&config->agg_time);
 		trace_rmnet_start_aggregation(skb);
-		rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_CPY_EXPAND);
+		dev_kfree_skb_any(skb);
 		goto schedule;
 	}
 	diff = timespec_sub(config->agg_last, config->agg_time);
@@ -321,7 +321,7 @@
 	dest_buff = skb_put(config->agg_skb, skb->len);
 	memcpy(dest_buff, skb->data, skb->len);
 	config->agg_count++;
-	rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_INTO_BUFF);
+	dev_kfree_skb_any(skb);
 
 schedule:
 	if (config->agg_state != RMNET_MAP_TXFER_SCHEDULED) {
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ae83c3ae..da574a1 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -496,6 +496,7 @@
 static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
 				u32 flags)
 {
+	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
 	struct net_device *dev = tp->q->dev_queue->dev;
 	struct tc_cls_u32_offload u32_offload = {0};
 	struct tc_to_netdev offload;
@@ -520,7 +521,7 @@
 	offload.cls_u32->knode.sel = &n->sel;
 	offload.cls_u32->knode.exts = &n->exts;
 	if (n->ht_down)
-		offload.cls_u32->knode.link_handle = n->ht_down->handle;
+		offload.cls_u32->knode.link_handle = ht->handle;
 
 	err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
 					    tp->protocol, &offload);
@@ -788,8 +789,9 @@
 static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp,
 					 struct tc_u_knode *n)
 {
-	struct tc_u_knode *new;
+	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
 	struct tc_u32_sel *s = &n->sel;
+	struct tc_u_knode *new;
 
 	new = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key),
 		      GFP_KERNEL);
@@ -807,11 +809,11 @@
 	new->fshift = n->fshift;
 	new->res = n->res;
 	new->flags = n->flags;
-	RCU_INIT_POINTER(new->ht_down, n->ht_down);
+	RCU_INIT_POINTER(new->ht_down, ht);
 
 	/* bump reference count as long as we hold pointer to structure */
-	if (new->ht_down)
-		new->ht_down->refcnt++;
+	if (ht)
+		ht->refcnt++;
 
 #ifdef CONFIG_CLS_U32_PERF
 	/* Statistics may be incremented by readers during update
diff --git a/net/sctp/offload.c b/net/sctp/offload.c
index 4f5a2b5..6300f28 100644
--- a/net/sctp/offload.c
+++ b/net/sctp/offload.c
@@ -44,6 +44,9 @@
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
 	struct sctphdr *sh;
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP))
+		goto out;
+
 	sh = sctp_hdr(skb);
 	if (!pskb_may_pull(skb, sizeof(*sh)))
 		goto out;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7181ce6..c472b83 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -83,7 +83,7 @@
 static int sctp_writeable(struct sock *sk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
-				size_t msg_len, struct sock **orig_sk);
+				size_t msg_len);
 static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static int sctp_wait_for_accept(struct sock *sk, long timeo);
@@ -332,16 +332,14 @@
 	if (len < sizeof (struct sockaddr))
 		return NULL;
 
+	if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+		return NULL;
+
 	/* V4 mapped address are really of AF_INET family */
 	if (addr->sa.sa_family == AF_INET6 &&
-	    ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
-		if (!opt->pf->af_supported(AF_INET, opt))
-			return NULL;
-	} else {
-		/* Does this PF support this AF? */
-		if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-			return NULL;
-	}
+	    ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+	    !opt->pf->af_supported(AF_INET, opt))
+		return NULL;
 
 	/* If we get this far, af is valid. */
 	af = sctp_get_af_specific(addr->sa.sa_family);
@@ -1958,7 +1956,7 @@
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 	if (!sctp_wspace(asoc)) {
 		/* sk can be changed by peel off when waiting for buf. */
-		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len, &sk);
+		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
 		if (err) {
 			if (err == -ESRCH) {
 				/* asoc is already dead. */
@@ -7441,12 +7439,12 @@
 
 /* Helper function to wait for space in the sndbuf.  */
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
-				size_t msg_len, struct sock **orig_sk)
+				size_t msg_len)
 {
 	struct sock *sk = asoc->base.sk;
-	int err = 0;
 	long current_timeo = *timeo_p;
 	DEFINE_WAIT(wait);
+	int err = 0;
 
 	pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc,
 		 *timeo_p, msg_len);
@@ -7475,17 +7473,13 @@
 		release_sock(sk);
 		current_timeo = schedule_timeout(current_timeo);
 		lock_sock(sk);
-		if (sk != asoc->base.sk) {
-			release_sock(sk);
-			sk = asoc->base.sk;
-			lock_sock(sk);
-		}
+		if (sk != asoc->base.sk)
+			goto do_error;
 
 		*timeo_p = current_timeo;
 	}
 
 out:
-	*orig_sk = sk;
 	finish_wait(&asoc->wait, &wait);
 
 	/* Release the association's refcnt.  */
diff --git a/net/socket.c b/net/socket.c
index fc0b609..539755b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -117,6 +117,8 @@
 
 static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to);
 static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);
+static BLOCKING_NOTIFIER_HEAD(sockev_notifier_list);
+
 static int sock_mmap(struct file *file, struct vm_area_struct *vma);
 
 static int sock_close(struct inode *inode, struct file *file);
@@ -171,6 +173,14 @@
 static DEFINE_PER_CPU(int, sockets_in_use);
 
 /*
+ * Socket Event framework helpers
+ */
+static void sockev_notify(unsigned long event, struct socket *sk)
+{
+	blocking_notifier_call_chain(&sockev_notifier_list, event, sk);
+}
+
+/**
  * Support routines.
  * Move socket addresses back and forth across the kernel/user
  * divide and look after the messy bits.
@@ -1255,6 +1265,9 @@
 	if (retval < 0)
 		goto out;
 
+	if (retval == 0)
+		sockev_notify(SOCKEV_SOCKET, sock);
+
 	retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
 	if (retval < 0)
 		goto out_release;
@@ -1400,6 +1413,8 @@
 						      &address, addrlen);
 		}
 		fput_light(sock->file, fput_needed);
+		if (!err)
+			sockev_notify(SOCKEV_BIND, sock);
 	}
 	return err;
 }
@@ -1427,6 +1442,8 @@
 			err = sock->ops->listen(sock, backlog);
 
 		fput_light(sock->file, fput_needed);
+		if (!err)
+			sockev_notify(SOCKEV_LISTEN, sock);
 	}
 	return err;
 }
@@ -1513,7 +1530,8 @@
 
 	fd_install(newfd, newfile);
 	err = newfd;
-
+	if (!err)
+		sockev_notify(SOCKEV_ACCEPT, sock);
 out_put:
 	fput_light(sock->file, fput_needed);
 out:
@@ -1563,6 +1581,8 @@
 
 	err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
 				 sock->file->f_flags);
+	if (!err)
+		sockev_notify(SOCKEV_CONNECT, sock);
 out_put:
 	fput_light(sock->file, fput_needed);
 out:
@@ -1823,6 +1843,7 @@
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 	if (sock != NULL) {
+		sockev_notify(SOCKEV_SHUTDOWN, sock);
 		err = security_socket_shutdown(sock, how);
 		if (!err)
 			err = sock->ops->shutdown(sock, how);
@@ -2566,6 +2587,15 @@
 
 core_initcall(sock_init);	/* early initcall */
 
+static int __init jit_init(void)
+{
+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+	bpf_jit_enable = 1;
+#endif
+	return 0;
+}
+pure_initcall(jit_init);
+
 #ifdef CONFIG_PROC_FS
 void socket_seq_show(struct seq_file *seq)
 {
@@ -3331,3 +3361,15 @@
 	return sock->ops->shutdown(sock, how);
 }
 EXPORT_SYMBOL(kernel_sock_shutdown);
+
+int sockev_register_notify(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&sockev_notifier_list, nb);
+}
+EXPORT_SYMBOL(sockev_register_notify);
+
+int sockev_unregister_notify(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&sockev_notifier_list, nb);
+}
+EXPORT_SYMBOL(sockev_unregister_notify);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index e01c825..d24d14e 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2381,6 +2381,7 @@
 	case -ECONNREFUSED:
 	case -ECONNRESET:
 	case -ENETUNREACH:
+	case -EHOSTUNREACH:
 	case -EADDRINUSE:
 	case -ENOBUFS:
 		/* retry with existing socket, after a delay */
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 2775332..5b3e1ea 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1848,36 +1848,38 @@
 
 	if (strcmp(name, tipc_bclink_name) == 0) {
 		err = tipc_nl_add_bc_link(net, &msg);
-		if (err) {
-			nlmsg_free(msg.skb);
-			return err;
-		}
+		if (err)
+			goto err_free;
 	} else {
 		int bearer_id;
 		struct tipc_node *node;
 		struct tipc_link *link;
 
 		node = tipc_node_find_by_name(net, name, &bearer_id);
-		if (!node)
-			return -EINVAL;
+		if (!node) {
+			err = -EINVAL;
+			goto err_free;
+		}
 
 		tipc_node_read_lock(node);
 		link = node->links[bearer_id].link;
 		if (!link) {
 			tipc_node_read_unlock(node);
-			nlmsg_free(msg.skb);
-			return -EINVAL;
+			err = -EINVAL;
+			goto err_free;
 		}
 
 		err = __tipc_nl_add_link(net, &msg, link, 0);
 		tipc_node_read_unlock(node);
-		if (err) {
-			nlmsg_free(msg.skb);
-			return err;
-		}
+		if (err)
+			goto err_free;
 	}
 
 	return genlmsg_reply(msg.skb, info);
+
+err_free:
+	nlmsg_free(msg.skb);
+	return err;
 }
 
 int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8201e6d..95d5088 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1117,6 +1117,8 @@
 		     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
 			dev->priv_flags |= IFF_DONT_BRIDGE;
 
+		INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
+
 		nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
 		break;
 	case NETDEV_GOING_DOWN:
@@ -1205,6 +1207,7 @@
 #ifdef CONFIG_CFG80211_WEXT
 			kzfree(wdev->wext.keys);
 #endif
+			flush_work(&wdev->disconnect_wk);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c40f3de..478e37a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -382,6 +382,7 @@
 		       struct cfg80211_roam_info *info);
 int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
 			      struct wireless_dev *wdev);
+void cfg80211_autodisconnect_wk(struct work_struct *work);
 
 /* SME implementation */
 void cfg80211_conn_work(struct work_struct *work);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index ff9887f..7fe91b1 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -54,7 +54,8 @@
 
 country AR:
 	(2402 - 2482 @ 40), (36)
-	(5170 - 5330 @ 160), (23)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (36), AUTO-BW
 	(5490 - 5590 @ 80), (36)
 	(5650 - 5730 @ 80), (36)
 	(5735 - 5835 @ 80), (36)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 5499e9f..5f85a4e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -350,6 +350,11 @@
 	     !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
 		return 0;
 
+	if (ether_addr_equal(wdev->disconnect_bssid, bssid) ||
+	    (wdev->current_bss &&
+	     ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
+		wdev->conn_owner_nlportid = 0;
+
 	return rdev_deauth(rdev, dev, &req);
 }
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8f9bd38..7cea430 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16,6 +16,7 @@
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
 #include <linux/netlink.h>
+#include <linux/nospec.h>
 #include <linux/etherdevice.h>
 #include <net/net_namespace.h>
 #include <net/genetlink.h>
@@ -433,6 +434,7 @@
 					.len = FILS_ERP_MAX_RRK_LEN },
 	[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
 	[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
+	[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -2039,20 +2041,22 @@
 static int parse_txq_params(struct nlattr *tb[],
 			    struct ieee80211_txq_params *txq_params)
 {
+	u8 ac;
+
 	if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
 	    !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
 	    !tb[NL80211_TXQ_ATTR_AIFS])
 		return -EINVAL;
 
-	txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
+	ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
 	txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
 	txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
 	txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
 	txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
 
-	if (txq_params->ac >= NL80211_NUM_ACS)
+	if (ac >= NL80211_NUM_ACS)
 		return -EINVAL;
-
+	txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
 	return 0;
 }
 
@@ -3784,9 +3788,10 @@
 			return false;
 		return true;
 	case NL80211_CMD_CONNECT:
-		/* SAE not supported yet */
-		if (auth_type == NL80211_AUTHTYPE_SAE)
+		if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
+		    auth_type == NL80211_AUTHTYPE_SAE)
 			return false;
+
 		/* FILS with SK PFS or PK not supported yet */
 		if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 		    auth_type == NL80211_AUTHTYPE_FILS_PK)
@@ -8126,8 +8131,17 @@
 	err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
 	if (!err) {
 		wdev_lock(dev->ieee80211_ptr);
+
 		err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
 					  ssid, ssid_len, &req);
+
+		if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+			dev->ieee80211_ptr->conn_owner_nlportid =
+				info->snd_portid;
+			memcpy(dev->ieee80211_ptr->disconnect_bssid,
+			       bssid, ETH_ALEN);
+		}
+
 		wdev_unlock(dev->ieee80211_ptr);
 	}
 
@@ -8875,12 +8889,32 @@
 		return -EINVAL;
 	}
 
+	if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
+		if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+			return -EINVAL;
+		}
+		connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
+	}
+
 	wdev_lock(dev->ieee80211_ptr);
+
 	err = cfg80211_connect(rdev, dev, &connect, connkeys,
 			       connect.prev_bssid);
-	wdev_unlock(dev->ieee80211_ptr);
 	if (err)
 		kzfree(connkeys);
+
+	if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+		dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+		if (connect.bssid)
+			memcpy(dev->ieee80211_ptr->disconnect_bssid,
+			       connect.bssid, ETH_ALEN);
+		else
+			memset(dev->ieee80211_ptr->disconnect_bssid,
+			       0, ETH_ALEN);
+	}
+
+	wdev_unlock(dev->ieee80211_ptr);
+
 	return err;
 }
 
@@ -12018,6 +12052,41 @@
 	return rdev_set_multicast_to_unicast(rdev, dev, enabled);
 }
 
+static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct cfg80211_external_auth_params params;
+
+	if (rdev->ops->external_auth)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_SSID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_BSSID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_STATUS_CODE])
+		return -EINVAL;
+
+	memset(&params, 0, sizeof(params));
+
+	params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+	if (params.ssid.ssid_len == 0 ||
+	    params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN)
+		return -EINVAL;
+	memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]),
+	       params.ssid.ssid_len);
+
+	memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
+	       ETH_ALEN);
+
+	params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+
+	return rdev_external_auth(rdev, dev, &params);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -12907,6 +12976,14 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_EXTERNAL_AUTH,
+		.doit = nl80211_external_auth,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 /* notification functions */
@@ -14734,6 +14811,8 @@
 
 			if (wdev->owner_nlportid == notify->portid)
 				schedule_destroy_work = true;
+			else if (wdev->conn_owner_nlportid == notify->portid)
+				schedule_work(&wdev->disconnect_wk);
 		}
 
 		spin_lock_bh(&rdev->beacon_registrations_lock);
@@ -14898,6 +14977,47 @@
 	nlmsg_free(msg);
 }
 
+int cfg80211_external_auth_request(struct net_device *dev,
+				   struct cfg80211_external_auth_params *params,
+				   gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+	struct sk_buff *msg;
+	void *hdr;
+
+	if (!wdev->conn_owner_nlportid)
+		return -EINVAL;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
+	if (!hdr)
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+	    nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
+	    nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+			params->action) ||
+	    nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
+	    nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
+		    params->ssid.ssid))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
+			wdev->conn_owner_nlportid);
+	return 0;
+
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+EXPORT_SYMBOL(cfg80211_external_auth_request);
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2f42507..091806d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1153,4 +1153,19 @@
 	trace_rdev_return_int(&rdev->wiphy, ret);
 	return ret;
 }
+
+static inline int
+rdev_external_auth(struct cfg80211_registered_device *rdev,
+		   struct net_device *dev,
+		   struct cfg80211_external_auth_params *params)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_external_auth(&rdev->wiphy, dev, params);
+	if (rdev->ops->external_auth)
+		ret = rdev->ops->external_auth(&rdev->wiphy, dev, params);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d414049..2d64e0f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -763,6 +763,7 @@
 		kzfree(wdev->connect_keys);
 		wdev->connect_keys = NULL;
 		wdev->ssid_len = 0;
+		wdev->conn_owner_nlportid = 0;
 		if (cr->bss) {
 			cfg80211_unhold_bss(bss_from_pub(cr->bss));
 			cfg80211_put_bss(wdev->wiphy, cr->bss);
@@ -1010,6 +1011,7 @@
 
 	wdev->current_bss = NULL;
 	wdev->ssid_len = 0;
+	wdev->conn_owner_nlportid = 0;
 
 	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
@@ -1182,6 +1184,8 @@
 	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
+	wdev->conn_owner_nlportid = 0;
+
 	if (wdev->conn)
 		err = cfg80211_sme_disconnect(wdev, reason);
 	else if (!rdev->ops->disconnect)
@@ -1199,3 +1203,32 @@
 
 	return err;
 }
+
+/*
+ * Used to clean up after the connection / connection attempt owner socket
+ * disconnects
+ */
+void cfg80211_autodisconnect_wk(struct work_struct *work)
+{
+	struct wireless_dev *wdev =
+		container_of(work, struct wireless_dev, disconnect_wk);
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+
+	wdev_lock(wdev);
+
+	if (wdev->conn_owner_nlportid) {
+		/*
+		 * Use disconnect_bssid if still connecting and ops->disconnect
+		 * not implemented.  Otherwise we can use cfg80211_disconnect.
+		 */
+		if (rdev->ops->disconnect || wdev->current_bss)
+			cfg80211_disconnect(rdev, wdev->netdev,
+					    WLAN_REASON_DEAUTH_LEAVING, true);
+		else
+			cfg80211_mlme_deauth(rdev, wdev->netdev,
+					     wdev->disconnect_bssid, NULL, 0,
+					     WLAN_REASON_DEAUTH_LEAVING, false);
+	}
+
+	wdev_unlock(wdev);
+}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ea1b47e..80ea75a 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2230,6 +2230,29 @@
 		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr))
 );
 
+TRACE_EVENT(rdev_external_auth,
+	    TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		     struct cfg80211_external_auth_params *params),
+	    TP_ARGS(wiphy, netdev, params),
+	    TP_STRUCT__entry(WIPHY_ENTRY
+			     NETDEV_ENTRY
+			     MAC_ENTRY(bssid)
+			     __array(u8, ssid, IEEE80211_MAX_SSID_LEN + 1)
+			     __field(u16, status)
+	    ),
+	    TP_fast_assign(WIPHY_ASSIGN;
+			   NETDEV_ASSIGN;
+			   MAC_ASSIGN(bssid, params->bssid);
+			   memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+			   memcpy(__entry->ssid, params->ssid.ssid,
+				  params->ssid.ssid_len);
+			   __entry->status = params->status;
+	    ),
+	    TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+		      ", ssid: %s, status: %u", WIPHY_PR_ARG, NETDEV_PR_ARG,
+		      __entry->bssid, __entry->ssid, __entry->status)
+);
+
 /*************************************************************
  *	     cfg80211 exported functions traces		     *
  *************************************************************/
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index ac5f1267..aab8585 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -9,7 +9,6 @@
 dev_pm_ops
 dma_map_ops
 driver_info
-drm_connector_funcs
 drm_encoder_funcs
 drm_encoder_helper_funcs
 ethtool_ops
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
index 1bf949c..f6ab3cc 100644
--- a/scripts/gdb/linux/tasks.py
+++ b/scripts/gdb/linux/tasks.py
@@ -96,6 +96,8 @@
         thread_info_addr = task.address + ia64_task_size
         thread_info = thread_info_addr.cast(thread_info_ptr_type)
     else:
+        if task.type.fields()[0].type == thread_info_type.get_type():
+            return task['thread_info']
         thread_info = task['stack'].cast(thread_info_ptr_type)
     return thread_info.dereference()
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 845eb9b..238db4f 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -2130,6 +2130,14 @@
 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
 }
 
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+	buf_printf(b, "\n#ifdef RETPOLINE\n");
+	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+	buf_printf(b, "#endif\n");
+}
+
 static void add_staging_flag(struct buffer *b, const char *name)
 {
 	static const char *staging_dir = "drivers/staging";
@@ -2474,6 +2482,7 @@
 
 		add_header(&buf, mod);
 		add_intree_flag(&buf, !external_module);
+		add_retpoline(&buf);
 		add_staging_flag(&buf, mod->name);
 		err |= add_versions(&buf, mod);
 		add_depends(&buf, mod, modules);
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index a871159..ead2fd6 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -141,23 +141,22 @@
  */
 static int valid_master_desc(const char *new_desc, const char *orig_desc)
 {
-	if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
-		if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
-			goto out;
-		if (orig_desc)
-			if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
-				goto out;
-	} else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
-		if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
-			goto out;
-		if (orig_desc)
-			if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
-				goto out;
-	} else
-		goto out;
+	int prefix_len;
+
+	if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
+		prefix_len = KEY_TRUSTED_PREFIX_LEN;
+	else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
+		prefix_len = KEY_USER_PREFIX_LEN;
+	else
+		return -EINVAL;
+
+	if (!new_desc[prefix_len])
+		return -EINVAL;
+
+	if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
+		return -EINVAL;
+
 	return 0;
-out:
-	return -EINVAL;
 }
 
 /*
diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c
index f0bbf9c..16ed516 100644
--- a/security/pfe/pfk_ice.c
+++ b/security/pfe/pfk_ice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -138,6 +138,7 @@
 		if (ret1)
 			pr_err("%s: Invalidate Key Error: %d\n", __func__,
 					ret1);
+		goto out;
 	}
 	ret = qcom_ice_setup_ice_hw((const char *)s_type, false);
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 082b20c..051ee18 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -78,8 +78,7 @@
 
 static struct sidtab sidtab;
 struct policydb policydb;
-int ss_initialized;
-
+int ss_initialized __aligned(0x1000) __attribute__((section(".bss_rtic")));
 /*
  * The largest sequence number that has been used when
  * providing an access decision to the access vector cache.
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 25deca44..9ccf6a5 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -582,7 +582,6 @@
 {
 	u_int64_t n = (u_int64_t) a * b;
 	if (c == 0) {
-		snd_BUG_ON(!n);
 		*r = 0;
 		return UINT_MAX;
 	}
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 16f8124..5143801 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -115,6 +115,7 @@
 		return -ENOMEM;
 	runtime->substream = substream;
 	spin_lock_init(&runtime->lock);
+	mutex_init(&runtime->realloc_mutex);
 	init_waitqueue_head(&runtime->sleep);
 	INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
 	runtime->event = NULL;
@@ -636,8 +637,10 @@
 			      struct snd_rawmidi_params * params)
 {
 	char *newbuf;
+	char *oldbuf;
 	struct snd_rawmidi_runtime *runtime = substream->runtime;
-	
+	unsigned long flags;
+
 	if (substream->append && substream->use_count > 1)
 		return -EBUSY;
 	snd_rawmidi_drain_output(substream);
@@ -648,13 +651,22 @@
 		return -EINVAL;
 	}
 	if (params->buffer_size != runtime->buffer_size) {
-		newbuf = krealloc(runtime->buffer, params->buffer_size,
+		mutex_lock(&runtime->realloc_mutex);
+		newbuf = __krealloc(runtime->buffer, params->buffer_size,
 				  GFP_KERNEL);
-		if (!newbuf)
+		if (!newbuf) {
+			mutex_unlock(&runtime->realloc_mutex);
 			return -ENOMEM;
+		}
+		spin_lock_irqsave(&runtime->lock, flags);
+		oldbuf = runtime->buffer;
 		runtime->buffer = newbuf;
 		runtime->buffer_size = params->buffer_size;
 		runtime->avail = runtime->buffer_size;
+		spin_unlock_irqrestore(&runtime->lock, flags);
+		if (oldbuf != newbuf)
+			kfree(oldbuf);
+		mutex_unlock(&runtime->realloc_mutex);
 	}
 	runtime->avail_min = params->avail_min;
 	substream->active_sensing = !params->no_active_sensing;
@@ -666,7 +678,9 @@
 			     struct snd_rawmidi_params * params)
 {
 	char *newbuf;
+	char *oldbuf;
 	struct snd_rawmidi_runtime *runtime = substream->runtime;
+	unsigned long flags;
 
 	snd_rawmidi_drain_input(substream);
 	if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
@@ -676,12 +690,21 @@
 		return -EINVAL;
 	}
 	if (params->buffer_size != runtime->buffer_size) {
-		newbuf = krealloc(runtime->buffer, params->buffer_size,
+		mutex_lock(&runtime->realloc_mutex);
+		newbuf = __krealloc(runtime->buffer, params->buffer_size,
 				  GFP_KERNEL);
-		if (!newbuf)
+		if (!newbuf) {
+			mutex_unlock(&runtime->realloc_mutex);
 			return -ENOMEM;
+		}
+		spin_lock_irqsave(&runtime->lock, flags);
+		oldbuf = runtime->buffer;
 		runtime->buffer = newbuf;
 		runtime->buffer_size = params->buffer_size;
+		spin_unlock_irqrestore(&runtime->lock, flags);
+		if (oldbuf != newbuf)
+			kfree(oldbuf);
+		mutex_unlock(&runtime->realloc_mutex);
 	}
 	runtime->avail_min = params->avail_min;
 	return 0;
@@ -954,6 +977,8 @@
 	unsigned long appl_ptr;
 
 	spin_lock_irqsave(&runtime->lock, flags);
+	if (userbuf)
+		mutex_lock(&runtime->realloc_mutex);
 	while (count > 0 && runtime->avail) {
 		count1 = runtime->buffer_size - runtime->appl_ptr;
 		if (count1 > count)
@@ -973,6 +998,7 @@
 			spin_unlock_irqrestore(&runtime->lock, flags);
 			if (copy_to_user(userbuf + result,
 					 runtime->buffer + appl_ptr, count1)) {
+				mutex_unlock(&runtime->realloc_mutex);
 				return result > 0 ? result : -EFAULT;
 			}
 			spin_lock_irqsave(&runtime->lock, flags);
@@ -981,6 +1007,8 @@
 		count -= count1;
 	}
 	spin_unlock_irqrestore(&runtime->lock, flags);
+	if (userbuf)
+		mutex_unlock(&runtime->realloc_mutex);
 	return result;
 }
 
@@ -1245,10 +1273,14 @@
 		return -EINVAL;
 
 	result = 0;
+	if (userbuf)
+		mutex_lock(&runtime->realloc_mutex);
 	spin_lock_irqsave(&runtime->lock, flags);
 	if (substream->append) {
 		if ((long)runtime->avail < count) {
 			spin_unlock_irqrestore(&runtime->lock, flags);
+			if (userbuf)
+				mutex_unlock(&runtime->realloc_mutex);
 			return -EAGAIN;
 		}
 	}
@@ -1284,6 +1316,8 @@
       __end:
 	count1 = runtime->avail < runtime->buffer_size;
 	spin_unlock_irqrestore(&runtime->lock, flags);
+	if (userbuf)
+		mutex_unlock(&runtime->realloc_mutex);
 	if (count1)
 		snd_rawmidi_output_trigger(substream, 1);
 	return result;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 45ef591..16580a8 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -221,6 +221,7 @@
 	rwlock_init(&client->ports_lock);
 	mutex_init(&client->ports_mutex);
 	INIT_LIST_HEAD(&client->ports_list_head);
+	mutex_init(&client->ioctl_mutex);
 
 	/* find free slot in the client table */
 	spin_lock_irqsave(&clients_lock, flags);
@@ -2127,7 +2128,9 @@
 			return -EFAULT;
 	}
 
+	mutex_lock(&client->ioctl_mutex);
 	err = handler->func(client, &buf);
+	mutex_unlock(&client->ioctl_mutex);
 	if (err >= 0) {
 		/* Some commands includes a bug in 'dir' field. */
 		if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index c661425..0611e1e 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -61,6 +61,7 @@
 	struct list_head ports_list_head;
 	rwlock_t ports_lock;
 	struct mutex ports_mutex;
+	struct mutex ioctl_mutex;
 	int convert32;		/* convert 32->64bit */
 
 	/* output pool */
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 80bbadc..d6e079f 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -408,6 +408,7 @@
 	/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
 
 	/* codec SSID */
+	SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
 	SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
 	SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
 	SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4ef3b00..71a058f 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5617,6 +5617,7 @@
 	SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
 	SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+	SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 712ed65..ebdf9bd 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -70,3 +70,7 @@
 };
 
 module_spi_driver(pcm512x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f608f8d2..dd88c2c 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -232,13 +232,19 @@
 	snprintf(prop, sizeof(prop), "%scpu", prefix);
 	cpu = of_get_child_by_name(node, prop);
 
+	if (!cpu) {
+		ret = -EINVAL;
+		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+		goto dai_link_of_err;
+	}
+
 	snprintf(prop, sizeof(prop), "%splat", prefix);
 	plat = of_get_child_by_name(node, prop);
 
 	snprintf(prop, sizeof(prop), "%scodec", prefix);
 	codec = of_get_child_by_name(node, prop);
 
-	if (!cpu || !codec) {
+	if (!codec) {
 		ret = -EINVAL;
 		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
 		goto dai_link_of_err;
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 3f8e6f0..dcf0369 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -41,7 +41,8 @@
 	obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
 	if (obj && obj->type == ACPI_TYPE_BUFFER) {
 		nhlt_ptr = (struct nhlt_resource_desc  *)obj->buffer.pointer;
-		nhlt_table = (struct nhlt_acpi_table *)
+		if (nhlt_ptr->length)
+			nhlt_table = (struct nhlt_acpi_table *)
 				memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
 				MEMREMAP_WB);
 		ACPI_FREE(obj);
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 974915c..08bfee4 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -476,6 +476,7 @@
 	case I2S_INTCR:
 	case I2S_XFER:
 	case I2S_CLR:
+	case I2S_TXDR:
 	case I2S_RXDR:
 	case I2S_FIFOLR:
 	case I2S_INTSR:
@@ -490,6 +491,9 @@
 	switch (reg) {
 	case I2S_INTSR:
 	case I2S_CLR:
+	case I2S_FIFOLR:
+	case I2S_TXDR:
+	case I2S_RXDR:
 		return true;
 	default:
 		return false;
@@ -499,6 +503,8 @@
 static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
+	case I2S_RXDR:
+		return true;
 	default:
 		return false;
 	}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 560cf4b..a9a43ac 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -699,9 +699,14 @@
 			       struct rsnd_priv *priv)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	int irq = ssi->irq;
 
+	/* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+	if (pure_ssi_mod != mod)
+		return 0;
+
 	/* PIO will request IRQ again */
 	devm_free_irq(dev, irq, mod);
 
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 7712e2b..4783648 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -122,7 +122,7 @@
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER_PLUS:
 		if (get_endpoint(alts, 0)->bInterval >= 1 &&
-		    get_endpoint(alts, 0)->bInterval <= 4)
+		    get_endpoint(alts, 0)->bInterval <= 16)
 			return get_endpoint(alts, 0)->bInterval - 1;
 		break;
 	default:
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index e2cebf15..1c5b36d 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -173,6 +173,9 @@
 	USB_QMI_PCM_FORMAT_U32_BE,
 };
 
+static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
+	size_t iova_size, size_t mapped_iova_size);
+
 static enum usb_audio_device_speed_enum_v01
 get_speed_info(enum usb_device_speed udev_speed)
 {
@@ -279,11 +282,14 @@
 }
 
 static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
-		size_t size)
+		size_t size, struct sg_table *sgt)
 {
-	unsigned long va = 0;
+	unsigned long va_sg, va = 0;
 	bool map = true;
-	int ret;
+	int i, ret;
+	size_t sg_len, total_len = 0;
+	struct scatterlist *sg;
+	phys_addr_t pa_sg;
 
 	switch (mtype) {
 	case MEM_EVENT_RING:
@@ -306,18 +312,48 @@
 		pr_err("%s: unknown mem type %d\n", __func__, mtype);
 	}
 
-	if (!va)
-		map = false;
-
-	if (!map)
+	if (!va || !map)
 		goto done;
 
-	pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
-		va, mtype);
+	if (!sgt)
+		goto skip_sgt_map;
+
+	va_sg = va;
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		sg_len = PAGE_ALIGN(sg->offset + sg->length);
+		pa_sg = page_to_phys(sg_page(sg));
+		ret = iommu_map(uaudio_qdev->domain, va_sg, pa_sg, sg_len,
+			IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
+		if (ret) {
+			pr_err("%s:mapping failed ret%d\n", __func__, ret);
+			pr_err("memtype:%d, pa:%pK iova:%lu sg_len:%zu\n",
+				mtype, &pa_sg, va_sg, sg_len);
+			uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+			va = 0;
+			goto done;
+		}
+		pr_debug("%s:memtype %d:map pa:%pK to iova:%lu len:%zu\n",
+			__func__, mtype, &pa_sg, va_sg, sg_len);
+		va_sg += sg_len;
+		total_len += sg_len;
+	}
+
+	if (size != total_len) {
+		pr_err("%s: iova size %zu != mapped iova size %zu\n", __func__,
+			size, total_len);
+		uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+		va = 0;
+	}
+	return va;
+
+skip_sgt_map:
+	pr_debug("%s:memtype:%d map pa:%pK to iova %lu size:%zu\n", __func__,
+		mtype, &pa, va, size);
+
 	ret = iommu_map(uaudio_qdev->domain, va, pa, size,
 		IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
 	if (ret)
-		pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
+		pr_err("%s:failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
 			__func__, &pa, va, mtype, ret);
 done:
 	return va;
@@ -361,12 +397,12 @@
 }
 
 static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
-	size_t size)
+	size_t iova_size, size_t mapped_iova_size)
 {
 	size_t umap_size;
 	bool unmap = true;
 
-	if (!va || !size)
+	if (!va || !iova_size)
 		return;
 
 	switch (mtype) {
@@ -378,11 +414,11 @@
 		break;
 
 	case MEM_XFER_RING:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_ring_list,
 		&uaudio_qdev->xfer_ring_iova_size);
 		break;
 	case MEM_XFER_BUF:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_buf_list,
 		&uaudio_qdev->xfer_buf_iova_size);
 		break;
 	default:
@@ -390,15 +426,16 @@
 		unmap = false;
 	}
 
-	if (!unmap)
+	if (!unmap || !mapped_iova_size)
 		return;
 
-	pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
+	pr_debug("%s:memtype %d: unmap iova %lu size %zu\n", __func__, mtype,
+		va, mapped_iova_size);
 
-	umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
-	if (umap_size != size)
-		pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
-		umap_size, va);
+	umap_size = iommu_unmap(uaudio_qdev->domain, va, mapped_iova_size);
+	if (umap_size != mapped_iova_size)
+		pr_err("%s:unmapped size %zu for iova %lu of mapped size %zu\n",
+		__func__, umap_size, va, mapped_iova_size);
 }
 
 static int prepare_qmi_response(struct snd_usb_substream *subs,
@@ -418,12 +455,11 @@
 	void *hdr_ptr;
 	u8 *xfer_buf;
 	unsigned int data_ep_pipe = 0, sync_ep_pipe = 0;
-	u32 len, mult, remainder, xfer_buf_len, sg_len, i, total_len = 0;
-	unsigned long va, va_sg, tr_data_va = 0, tr_sync_va = 0;
+	u32 len, mult, remainder, xfer_buf_len;
+	unsigned long va, tr_data_va = 0, tr_sync_va = 0;
 	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
 	dma_addr_t dma;
 	struct sg_table sgt;
-	struct scatterlist *sg;
 
 	iface = usb_ifnum_to_if(subs->dev, subs->interface);
 	if (!iface) {
@@ -593,7 +629,7 @@
 		goto err;
 	}
 
-	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto err;
 
@@ -610,7 +646,7 @@
 	resp->speed_info_valid = 1;
 
 	/* data transfer ring */
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_er;
 
@@ -624,7 +660,7 @@
 		goto skip_sync;
 
 	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_data;
 
@@ -655,20 +691,9 @@
 
 	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
 			len);
-
-	va = 0;
-	for_each_sg(sgt.sgl, sg, sgt.nents, i) {
-		sg_len = PAGE_ALIGN(sg->offset + sg->length);
-		va_sg = uaudio_iommu_map(MEM_XFER_BUF,
-			page_to_phys(sg_page(sg)), sg_len);
-		if (!va_sg)
-			goto unmap_xfer_buf;
-
-		if (!va)
-			va = va_sg;
-
-		total_len += sg_len;
-	}
+	va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
+	if (!va)
+		goto unmap_sync;
 
 	resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
 	resp->xhci_mem_info.xfer_buff.size = len;
@@ -690,7 +715,7 @@
 			uadev[card_num].num_intf, GFP_KERNEL);
 		if (!uadev[card_num].info) {
 			ret = -ENOMEM;
-			goto unmap_xfer_buf;
+			goto unmap_sync;
 		}
 		uadev[card_num].udev = subs->dev;
 		atomic_set(&uadev[card_num].in_use, 1);
@@ -722,16 +747,13 @@
 
 	return 0;
 
-unmap_xfer_buf:
-	if (va)
-		uaudio_iommu_unmap(MEM_XFER_BUF, va, total_len);
 unmap_sync:
 	usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE, PAGE_SIZE);
 unmap_data:
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE, PAGE_SIZE);
 unmap_er:
-	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, PAGE_SIZE);
 err:
 	return ret;
 }
@@ -760,17 +782,17 @@
 	}
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
-		info->data_xfer_ring_size);
+		info->data_xfer_ring_size, info->data_xfer_ring_size);
 	info->data_xfer_ring_va = 0;
 	info->data_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
-		info->sync_xfer_ring_size);
+		info->sync_xfer_ring_size, info->sync_xfer_ring_size);
 	info->sync_xfer_ring_va = 0;
 	info->sync_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
-		info->xfer_buf_size);
+		info->xfer_buf_size, info->xfer_buf_size);
 	info->xfer_buf_va = 0;
 
 	usb_free_coherent(udev, info->xfer_buf_size,
@@ -805,7 +827,8 @@
 
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}
@@ -881,7 +904,8 @@
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}
 
diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c
index 1c14c25..4b36323 100644
--- a/tools/gpio/gpio-event-mon.c
+++ b/tools/gpio/gpio-event-mon.c
@@ -23,6 +23,7 @@
 #include <getopt.h>
 #include <inttypes.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <linux/gpio.h>
 
 int monitor_device(const char *device_name,
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index d897702..faacf0c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "elf.h"
 #include "warn.h"
@@ -370,7 +371,8 @@
 
 	elf->fd = open(name, O_RDONLY);
 	if (elf->fd == -1) {
-		perror("open");
+		fprintf(stderr, "objtool: Can't open '%s': %s\n",
+			name, strerror(errno));
 		goto err;
 	}
 
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index cffdd9c..ff37531 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -19,18 +19,18 @@
 
 include $(srctree)/tools/scripts/Makefile.arch
 
-$(call detected_var,ARCH)
+$(call detected_var,SRCARCH)
 
 NO_PERF_REGS := 1
 
 # Additional ARCH settings for ppc
-ifeq ($(ARCH),powerpc)
+ifeq ($(SRCARCH),powerpc)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
 endif
 
 # Additional ARCH settings for x86
-ifeq ($(ARCH),x86)
+ifeq ($(SRCARCH),x86)
   $(call detected,CONFIG_X86)
   ifeq (${IS_64_BIT}, 1)
     CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated
@@ -43,12 +43,12 @@
   NO_PERF_REGS := 0
 endif
 
-ifeq ($(ARCH),arm)
+ifeq ($(SRCARCH),arm)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS = -lunwind -lunwind-arm
 endif
 
-ifeq ($(ARCH),arm64)
+ifeq ($(SRCARCH),arm64)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
@@ -61,7 +61,7 @@
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
@@ -115,9 +115,9 @@
 FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
 FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
 
-FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi
+FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi
 # include ARCH specific config
--include $(src-perf)/arch/$(ARCH)/Makefile
+-include $(src-perf)/arch/$(SRCARCH)/Makefile
 
 ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
   CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
@@ -205,12 +205,12 @@
 endif
 
 CFLAGS += -I$(src-perf)/util/include
-CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
+CFLAGS += -I$(src-perf)/arch/$(SRCARCH)/include
 CFLAGS += -I$(srctree)/tools/include/uapi
 CFLAGS += -I$(srctree)/tools/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/
 
 # $(obj-perf)      for generated common-cmds.h
 # $(obj-perf)/util for generated bison/flex headers
@@ -321,7 +321,7 @@
 
   ifndef NO_DWARF
     ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
-      msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
+      msg := $(warning DWARF register mappings have not been defined for architecture $(SRCARCH), DWARF support disabled);
       NO_DWARF := 1
     else
       CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
@@ -346,7 +346,7 @@
         CFLAGS += -DHAVE_BPF_PROLOGUE
         $(call detected,CONFIG_BPF_PROLOGUE)
       else
-        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+        msg := $(warning BPF prologue is not supported by architecture $(SRCARCH), missing regs_query_register_offset());
       endif
     else
       msg := $(warning DWARF support is off, BPF prologue is disabled);
@@ -372,7 +372,7 @@
   endif
 endif
 
-ifeq ($(ARCH),powerpc)
+ifeq ($(SRCARCH),powerpc)
   ifndef NO_DWARF
     CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
   endif
@@ -453,7 +453,7 @@
 endif
 
 ifndef NO_LOCAL_LIBUNWIND
-  ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
+  ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64))
     $(call feature_check,libunwind-debug-frame)
     ifneq ($(feature-libunwind-debug-frame), 1)
       msg := $(warning No debug_frame support found in libunwind);
@@ -717,7 +717,7 @@
       NO_PERF_READ_VDSO32 := 1
     endif
   endif
-  ifneq ($(ARCH), x86)
+  ifneq ($(SRCARCH), x86)
     NO_PERF_READ_VDSOX32 := 1
   endif
   ifndef NO_PERF_READ_VDSOX32
@@ -746,7 +746,7 @@
 endif
 
 ifndef NO_AUXTRACE
-  ifeq ($(ARCH),x86)
+  ifeq ($(SRCARCH),x86)
     ifeq ($(feature-get_cpuid), 0)
       msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc);
       NO_AUXTRACE := 1
@@ -793,7 +793,7 @@
 ETC_PERFCONFIG = etc/perfconfig
 endif
 ifndef lib
-ifeq ($(ARCH)$(IS_64_BIT), x861)
+ifeq ($(SRCARCH)$(IS_64_BIT), x861)
 lib = lib64
 else
 lib = lib
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index ef52d1e..2b92ffe 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -192,7 +192,7 @@
 
 ifeq ($(config),0)
 include $(srctree)/tools/scripts/Makefile.arch
--include arch/$(ARCH)/Makefile
+-include arch/$(SRCARCH)/Makefile
 endif
 
 # The FEATURE_DUMP_EXPORT holds location of the actual
diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
index 109eb75..d9b6af8 100644
--- a/tools/perf/arch/Build
+++ b/tools/perf/arch/Build
@@ -1,2 +1,2 @@
 libperf-y += common.o
-libperf-y += $(ARCH)/
+libperf-y += $(SRCARCH)/
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 9213a12..999a4e8 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -2,7 +2,7 @@
 
 jevents-y	+= json.o jsmn.o jevents.o
 pmu-events-y	+= pmu-events.o
-JDIR		=  pmu-events/arch/$(ARCH)
+JDIR		=  pmu-events/arch/$(SRCARCH)
 JSON		=  $(shell [ -d $(JDIR) ] &&				\
 			find $(JDIR) -name '*.json' -o -name 'mapfile.csv')
 #
@@ -10,4 +10,4 @@
 # directory and create tables in pmu-events.c.
 #
 $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS)
-	$(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
+	$(Q)$(call echo-cmd,gen)$(JEVENTS) $(SRCARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 8a4ce49..546250a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -71,7 +71,7 @@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 
-ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64 powerpc))
+ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 5337f49..28bdb48 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -826,7 +826,7 @@
 
 /*
  * default get_cpuid(): nothing gets recorded
- * actual implementation must be in arch/$(ARCH)/util/header.c
+ * actual implementation must be in arch/$(SRCARCH)/util/header.c
  */
 int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused)
 {
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c
index c25a74a..2bb3eef 100644
--- a/tools/power/cpupower/bench/system.c
+++ b/tools/power/cpupower/bench/system.c
@@ -61,7 +61,7 @@
 
 	dprintf("set %s as cpufreq governor\n", governor);
 
-	if (cpupower_is_cpu_online(cpu) != 0) {
+	if (cpupower_is_cpu_online(cpu) != 1) {
 		perror("cpufreq_cpu_exists");
 		fprintf(stderr, "error: cpu %u does not exist\n", cpu);
 		return -1;
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index 1b5da00..5b3205f 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -130,15 +130,18 @@
 {
 	int num;
 	char *tmp;
+	int this_cpu;
+
+	this_cpu = sched_getcpu();
 
 	/* Assume idle state count is the same for all CPUs */
-	cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0);
+	cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu);
 
 	if (cpuidle_sysfs_monitor.hw_states_num <= 0)
 		return NULL;
 
 	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
-		tmp = cpuidle_state_name(0, num);
+		tmp = cpuidle_state_name(this_cpu, num);
 		if (tmp == NULL)
 			continue;
 
@@ -146,7 +149,7 @@
 		strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
 		free(tmp);
 
-		tmp = cpuidle_state_desc(0, num);
+		tmp = cpuidle_state_desc(this_cpu, num);
 		if (tmp == NULL)
 			continue;
 		strncpy(cpuidle_cstates[num].desc, tmp,	CSTATE_DESC_LEN - 1);
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index ac73710..1517a23 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -215,9 +215,16 @@
 		       struct usbip_usb_interface *uinf)
 {
 	char busid[SYSFS_BUS_ID_SIZE];
+	int size;
 	struct udev_device *sif;
 
-	sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
+	size = snprintf(busid, sizeof(busid), "%s:%d.%d",
+			udev->busid, udev->bConfigurationValue, i);
+	if (size < 0 || (unsigned int)size >= sizeof(busid)) {
+		err("busid length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(busid));
+		return -1;
+	}
 
 	sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
 	if (!sif) {
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c
index 9d41522..6ff7b60 100644
--- a/tools/usb/usbip/libsrc/usbip_host_common.c
+++ b/tools/usb/usbip/libsrc/usbip_host_common.c
@@ -40,13 +40,20 @@
 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
 {
 	char status_attr_path[SYSFS_PATH_MAX];
+	int size;
 	int fd;
 	int length;
 	char status;
 	int value = 0;
 
-	snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
-		 udev->path);
+	size = snprintf(status_attr_path, sizeof(status_attr_path),
+			"%s/usbip_status", udev->path);
+	if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) {
+		err("usbip_status path length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(status_attr_path));
+		return -1;
+	}
+
 
 	fd = open(status_attr_path, O_RDONLY);
 	if (fd < 0) {
@@ -218,6 +225,7 @@
 {
 	char attr_name[] = "usbip_sockfd";
 	char sockfd_attr_path[SYSFS_PATH_MAX];
+	int size;
 	char sockfd_buff[30];
 	int ret;
 
@@ -237,10 +245,20 @@
 	}
 
 	/* only the first interface is true */
-	snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
-		 edev->udev.path, attr_name);
+	size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+			edev->udev.path, attr_name);
+	if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) {
+		err("exported device path length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(sockfd_attr_path));
+		return -1;
+	}
 
-	snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+	size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+	if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) {
+		err("socket length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(sockfd_buff));
+		return -1;
+	}
 
 	ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
 				    strlen(sockfd_buff));
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index ad92047..1274f32 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -55,12 +55,12 @@
 
 	while (*c != '\0') {
 		int port, status, speed, devid;
-		unsigned long socket;
+		int sockfd;
 		char lbusid[SYSFS_BUS_ID_SIZE];
 
-		ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+		ret = sscanf(c, "%d %d %d %x %u %31s\n",
 				&port, &status, &speed,
-				&devid, &socket, lbusid);
+				&devid, &sockfd, lbusid);
 
 		if (ret < 5) {
 			dbg("sscanf failed: %d", ret);
@@ -69,7 +69,7 @@
 
 		dbg("port %d status %d speed %d devid %x",
 				port, status, speed, devid);
-		dbg("socket %lx lbusid %s", socket, lbusid);
+		dbg("sockfd %u lbusid %s", sockfd, lbusid);
 
 
 		/* if a device is connected, look at it */
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
index d7599d9..73d8eee 100644
--- a/tools/usb/usbip/src/usbip.c
+++ b/tools/usb/usbip/src/usbip.c
@@ -176,6 +176,8 @@
 			break;
 		case '?':
 			printf("usbip: invalid option\n");
+			/* Terminate after printing error */
+			/* FALLTHRU */
 		default:
 			usbip_usage();
 			goto out;
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
index fa46141..e121cfb 100644
--- a/tools/usb/usbip/src/usbip_bind.c
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -144,6 +144,7 @@
 	int rc;
 	struct udev *udev;
 	struct udev_device *dev;
+	const char *devpath;
 
 	/* Check whether the device with this bus ID exists. */
 	udev = udev_new();
@@ -152,8 +153,16 @@
 		err("device with the specified bus ID does not exist");
 		return -1;
 	}
+	devpath = udev_device_get_devpath(dev);
 	udev_unref(udev);
 
+	/* If the device is already attached to vhci_hcd - bail out */
+	if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
+		err("bind loop detected: device: %s is attached to %s\n",
+		    devpath, USBIP_VHCI_DRV_NAME);
+		return -1;
+	}
+
 	rc = unbind_other(busid);
 	if (rc == UNBIND_ST_FAILED) {
 		err("could not unbind driver from device on busid %s", busid);
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index f1b38e8..d65a9f4 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -187,6 +187,7 @@
 	const char *busid;
 	char product_name[128];
 	int ret = -1;
+	const char *devpath;
 
 	/* Create libudev context. */
 	udev = udev_new();
@@ -209,6 +210,14 @@
 		path = udev_list_entry_get_name(dev_list_entry);
 		dev = udev_device_new_from_syspath(udev, path);
 
+		/* Ignore devices attached to vhci_hcd */
+		devpath = udev_device_get_devpath(dev);
+		if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
+			dbg("Skip the device %s already attached to %s\n",
+			    devpath, USBIP_VHCI_DRV_NAME);
+			continue;
+		}
+
 		/* Get device information. */
 		idVendor = udev_device_get_sysattr_value(dev, "idVendor");
 		idProduct = udev_device_get_sysattr_value(dev, "idProduct");